Merge "ExtractorUnitTest: Add support for random seek in SeekTest"
diff --git a/media/extractors/tests/ExtractorUnitTest.cpp b/media/extractors/tests/ExtractorUnitTest.cpp
index 64eda75..fca66a4 100644
--- a/media/extractors/tests/ExtractorUnitTest.cpp
+++ b/media/extractors/tests/ExtractorUnitTest.cpp
@@ -22,6 +22,7 @@
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaDataUtils.h>
+#include <media/stagefright/foundation/OpusHeader.h>
#include "aac/AACExtractor.h"
#include "amr/AMRExtractor.h"
@@ -43,7 +44,9 @@
#define OUTPUT_DUMP_FILE "/data/local/tmp/extractorOutput"
constexpr int32_t kMaxCount = 10;
-constexpr int32_t kOpusSeekPreRollUs = 80000; // 80 ms;
+constexpr int32_t kAudioDefaultSampleDuration = 20000; // 20ms
+constexpr int32_t kRandomSeekToleranceUs = 2 * kAudioDefaultSampleDuration; // 40 ms;
+constexpr int32_t kRandomSeed = 700;
static ExtractorUnitTestEnvironment *gEnv = nullptr;
@@ -168,6 +171,47 @@
return 0;
}
+void randomSeekTest(MediaTrackHelper *track, int64_t clipDuration) {
+ int32_t status = 0;
+ int32_t seekCount = 0;
+ bool hasTimestamp = false;
+ vector<int64_t> seekToTimeStamp;
+ string seekPtsString;
+
+ srand(kRandomSeed);
+ while (seekCount < kMaxCount) {
+ int64_t timeStamp = ((double)rand() / RAND_MAX) * clipDuration;
+ seekToTimeStamp.push_back(timeStamp);
+ seekPtsString.append(to_string(timeStamp));
+ seekPtsString.append(", ");
+ seekCount++;
+ }
+
+ for (int64_t seekPts : seekToTimeStamp) {
+ MediaTrackHelper::ReadOptions *options = new MediaTrackHelper::ReadOptions(
+ CMediaTrackReadOptions::SEEK_CLOSEST | CMediaTrackReadOptions::SEEK, seekPts);
+ ASSERT_NE(options, nullptr) << "Cannot create read option";
+
+ MediaBufferHelper *buffer = nullptr;
+ status = track->read(&buffer, options);
+ if (buffer) {
+ AMediaFormat *metaData = buffer->meta_data();
+ int64_t timeStamp = 0;
+ hasTimestamp = AMediaFormat_getInt64(metaData, AMEDIAFORMAT_KEY_TIME_US, &timeStamp);
+ ASSERT_TRUE(hasTimestamp) << "Extractor didn't set timestamp for the given sample";
+
+ buffer->release();
+ EXPECT_LE(abs(timeStamp - seekPts), kRandomSeekToleranceUs)
+ << "Seek unsuccessful. Expected timestamp range ["
+ << seekPts - kRandomSeekToleranceUs << ", " << seekPts + kRandomSeekToleranceUs
+ << "] "
+ << "received " << timeStamp << ", list of input seek timestamps ["
+ << seekPtsString << "]";
+ }
+ delete options;
+ }
+}
+
void getSeekablePoints(vector<int64_t> &seekablePoints, MediaTrackHelper *track) {
int32_t status = 0;
if (!seekablePoints.empty()) {
@@ -380,11 +424,7 @@
}
TEST_P(ExtractorUnitTest, SeekTest) {
- // Flac, Midi and Wav extractor can give samples from any pts and mark the given sample as
- // sync frame. So, this seek test is not applicable to these extractors
- if (mDisableTest || mExtractorName == FLAC || mExtractorName == WAV || mExtractorName == MIDI) {
- return;
- }
+ if (mDisableTest) return;
ALOGV("Validates %s Extractor behaviour for different seek modes", GetParam().first.c_str());
string inputFileName = gEnv->getRes() + GetParam().second;
@@ -417,6 +457,32 @@
MediaBufferGroup *bufferGroup = new MediaBufferGroup();
status = cTrack->start(track, bufferGroup->wrap());
ASSERT_EQ(OK, (media_status_t)status) << "Failed to start the track";
+
+ // For Flac, Wav and Midi extractor, all samples are seek points.
+ // We cannot create list of all seekable points for these.
+ // This means that if we pass a seekToTimeStamp between two seek points, we may
+ // end up getting the timestamp of next sample as a seekable timestamp.
+ // This timestamp may/may not be a part of the seekable point vector thereby failing the
+ // test. So we test these extractors using random seek test.
+ if (mExtractorName == FLAC || mExtractorName == WAV || mExtractorName == MIDI) {
+ AMediaFormat *trackMeta = AMediaFormat_new();
+ ASSERT_NE(trackMeta, nullptr) << "AMediaFormat_new returned null AMediaformat";
+
+ status = mExtractor->getTrackMetaData(trackMeta, idx, 1);
+ ASSERT_EQ(OK, (media_status_t)status) << "Failed to get trackMetaData";
+
+ int64_t clipDuration = 0;
+ AMediaFormat_getInt64(trackMeta, AMEDIAFORMAT_KEY_DURATION, &clipDuration);
+ ASSERT_GT(clipDuration, 0) << "Invalid clip duration ";
+ randomSeekTest(track, clipDuration);
+ AMediaFormat_delete(trackMeta);
+ continue;
+ }
+ // Request seekable points for remaining extractors which will be used to validate the seek
+ // accuracy for the extractors. Depending on SEEK Mode, we expect the extractors to return
+ // the expected sync frame. We don't prefer random seek test for these extractors because
+ // they aren't expected to seek to random samples. MP4 for instance can seek to
+ // next/previous sync frames but not to samples between two sync frames.
getSeekablePoints(seekablePoints, track);
ASSERT_GT(seekablePoints.size(), 0)
<< "Failed to get seekable points for " << GetParam().first << " extractor";
@@ -427,9 +493,31 @@
ASSERT_EQ(OK, (media_status_t)status) << "Failed to get track meta data";
bool isOpus = false;
+ int64_t opusSeekPreRollUs = 0;
const char *mime;
AMediaFormat_getString(trackFormat, AMEDIAFORMAT_KEY_MIME, &mime);
- if (!strcmp(mime, "audio/opus")) isOpus = true;
+ if (!strcmp(mime, "audio/opus")) {
+ isOpus = true;
+ void *seekPreRollBuf = nullptr;
+ size_t size = 0;
+ if (!AMediaFormat_getBuffer(trackFormat, "csd-2", &seekPreRollBuf, &size)) {
+ size_t opusHeadSize = 0;
+ size_t codecDelayBufSize = 0;
+ size_t seekPreRollBufSize = 0;
+ void *csdBuffer = nullptr;
+ void *opusHeadBuf = nullptr;
+ void *codecDelayBuf = nullptr;
+ AMediaFormat_getBuffer(trackFormat, "csd-0", &csdBuffer, &size);
+ ASSERT_NE(csdBuffer, nullptr);
+
+ GetOpusHeaderBuffers((uint8_t *)csdBuffer, size, &opusHeadBuf, &opusHeadSize,
+ &codecDelayBuf, &codecDelayBufSize, &seekPreRollBuf,
+ &seekPreRollBufSize);
+ }
+ ASSERT_NE(seekPreRollBuf, nullptr)
+ << "Invalid track format. SeekPreRoll info missing for Opus file";
+ opusSeekPreRollUs = *((int64_t *)seekPreRollBuf);
+ }
AMediaFormat_delete(trackFormat);
int32_t seekIdx = 0;
@@ -450,7 +538,7 @@
// extractor is calculated based on (seekPts - seekPreRollUs).
// So we add the preRoll value to the timeStamp we want to seek to.
if (isOpus) {
- seekToTimeStamp += kOpusSeekPreRollUs;
+ seekToTimeStamp += opusSeekPreRollUs;
}
MediaTrackHelper::ReadOptions *options = new MediaTrackHelper::ReadOptions(