Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2ec8ac27 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "ExtractorUnitTest: Add support for random seek in SeekTest"

parents 43f0d469 e7b94732
Loading
Loading
Loading
Loading
+96 −8
Original line number Original line Diff line number Diff line
@@ -22,6 +22,7 @@
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaDataUtils.h>
#include <media/stagefright/MetaDataUtils.h>
#include <media/stagefright/foundation/OpusHeader.h>


#include "aac/AACExtractor.h"
#include "aac/AACExtractor.h"
#include "amr/AMRExtractor.h"
#include "amr/AMRExtractor.h"
@@ -43,7 +44,9 @@ using namespace android;
#define OUTPUT_DUMP_FILE "/data/local/tmp/extractorOutput"
#define OUTPUT_DUMP_FILE "/data/local/tmp/extractorOutput"


constexpr int32_t kMaxCount = 10;
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;
static ExtractorUnitTestEnvironment *gEnv = nullptr;


@@ -168,6 +171,47 @@ int32_t ExtractorUnitTest::createExtractor() {
    return 0;
    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) {
void getSeekablePoints(vector<int64_t> &seekablePoints, MediaTrackHelper *track) {
    int32_t status = 0;
    int32_t status = 0;
    if (!seekablePoints.empty()) {
    if (!seekablePoints.empty()) {
@@ -380,11 +424,7 @@ TEST_P(ExtractorUnitTest, MultipleStartStopTest) {
}
}


TEST_P(ExtractorUnitTest, SeekTest) {
TEST_P(ExtractorUnitTest, SeekTest) {
    // Flac, Midi and Wav extractor can give samples from any pts and mark the given sample as
    if (mDisableTest) return;
    // sync frame. So, this seek test is not applicable to these extractors
    if (mDisableTest || mExtractorName == FLAC || mExtractorName == WAV || mExtractorName == MIDI) {
        return;
    }


    ALOGV("Validates %s Extractor behaviour for different seek modes", GetParam().first.c_str());
    ALOGV("Validates %s Extractor behaviour for different seek modes", GetParam().first.c_str());
    string inputFileName = gEnv->getRes() + GetParam().second;
    string inputFileName = gEnv->getRes() + GetParam().second;
@@ -417,6 +457,32 @@ TEST_P(ExtractorUnitTest, SeekTest) {
        MediaBufferGroup *bufferGroup = new MediaBufferGroup();
        MediaBufferGroup *bufferGroup = new MediaBufferGroup();
        status = cTrack->start(track, bufferGroup->wrap());
        status = cTrack->start(track, bufferGroup->wrap());
        ASSERT_EQ(OK, (media_status_t)status) << "Failed to start the track";
        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);
        getSeekablePoints(seekablePoints, track);
        ASSERT_GT(seekablePoints.size(), 0)
        ASSERT_GT(seekablePoints.size(), 0)
                << "Failed to get seekable points for " << GetParam().first << " extractor";
                << "Failed to get seekable points for " << GetParam().first << " extractor";
@@ -427,9 +493,31 @@ TEST_P(ExtractorUnitTest, SeekTest) {
        ASSERT_EQ(OK, (media_status_t)status) << "Failed to get track meta data";
        ASSERT_EQ(OK, (media_status_t)status) << "Failed to get track meta data";


        bool isOpus = false;
        bool isOpus = false;
        int64_t opusSeekPreRollUs = 0;
        const char *mime;
        const char *mime;
        AMediaFormat_getString(trackFormat, AMEDIAFORMAT_KEY_MIME, &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);
        AMediaFormat_delete(trackFormat);


        int32_t seekIdx = 0;
        int32_t seekIdx = 0;
@@ -450,7 +538,7 @@ TEST_P(ExtractorUnitTest, SeekTest) {
                // extractor is calculated based on (seekPts - seekPreRollUs).
                // extractor is calculated based on (seekPts - seekPreRollUs).
                // So we add the preRoll value to the timeStamp we want to seek to.
                // So we add the preRoll value to the timeStamp we want to seek to.
                if (isOpus) {
                if (isOpus) {
                    seekToTimeStamp += kOpusSeekPreRollUs;
                    seekToTimeStamp += opusSeekPreRollUs;
                }
                }


                MediaTrackHelper::ReadOptions *options = new MediaTrackHelper::ReadOptions(
                MediaTrackHelper::ReadOptions *options = new MediaTrackHelper::ReadOptions(