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

Commit 800793f3 authored by Linus Nilsson's avatar Linus Nilsson
Browse files

Transcoder: Preserve source track's bitrate by default.

When no bitrate is passed in the transcoder now preserves the
source track's bitrate. If the bitrate is not available as metadata
the transcoder will sample the source track and estimate the bitrate.

Fixes: 160648740
Test: Unit tests.
Change-Id: I4e0284128aaa1116f5b61d908b52582b2ed3d7e4
parent 41ac4ced
Loading
Loading
Loading
Loading
+73 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#include <media/MediaSampleReaderNDK.h>

#include <algorithm>
#include <cmath>
#include <vector>

namespace android {
@@ -189,6 +190,78 @@ media_status_t MediaSampleReaderNDK::positionExtractorForTrack_l(int trackIndex)
    return AMEDIA_OK;
}

media_status_t MediaSampleReaderNDK::getEstimatedBitrateForTrack(int trackIndex, int32_t* bitrate) {
    std::scoped_lock lock(mExtractorMutex);
    media_status_t status = AMEDIA_OK;

    if (trackIndex < 0 || trackIndex >= mTrackCount) {
        LOG(ERROR) << "Invalid trackIndex " << trackIndex << " for trackCount " << mTrackCount;
        return AMEDIA_ERROR_INVALID_PARAMETER;
    } else if (bitrate == nullptr) {
        LOG(ERROR) << "bitrate pointer is NULL.";
        return AMEDIA_ERROR_INVALID_PARAMETER;
    }

    // Rewind the extractor and sample from the beginning of the file.
    if (mExtractorSampleIndex > 0) {
        status = AMediaExtractor_seekTo(mExtractor, 0, AMEDIAEXTRACTOR_SEEK_PREVIOUS_SYNC);
        if (status != AMEDIA_OK) {
            LOG(ERROR) << "Unable to reset extractor: " << status;
            return status;
        }

        mExtractorTrackIndex = AMediaExtractor_getSampleTrackIndex(mExtractor);
        mExtractorSampleIndex = 0;
    }

    // Sample the track.
    static constexpr int64_t kSamplingDurationUs = 10 * 1000 * 1000;  // 10 seconds
    size_t lastSampleSize = 0;
    size_t totalSampleSize = 0;
    int64_t firstSampleTimeUs = 0;
    int64_t lastSampleTimeUs = 0;

    do {
        if (mExtractorTrackIndex == trackIndex) {
            lastSampleTimeUs = AMediaExtractor_getSampleTime(mExtractor);
            if (totalSampleSize == 0) {
                firstSampleTimeUs = lastSampleTimeUs;
            }

            lastSampleSize = AMediaExtractor_getSampleSize(mExtractor);
            totalSampleSize += lastSampleSize;
        }
    } while ((lastSampleTimeUs - firstSampleTimeUs) < kSamplingDurationUs && advanceExtractor_l());

    int64_t durationUs = 0;
    const int64_t sampledDurationUs = lastSampleTimeUs - firstSampleTimeUs;

    if (sampledDurationUs < kSamplingDurationUs) {
        // Track is shorter than the sampling duration so use the full track duration to get better
        // accuracy (i.e. don't skip the last sample).
        AMediaFormat* trackFormat = getTrackFormat(trackIndex);
        if (!AMediaFormat_getInt64(trackFormat, AMEDIAFORMAT_KEY_DURATION, &durationUs)) {
            durationUs = 0;
        }
        AMediaFormat_delete(trackFormat);
    }

    if (durationUs == 0) {
        // The sampled duration does not account for the last sample's duration so its size should
        // not be included either.
        totalSampleSize -= lastSampleSize;
        durationUs = sampledDurationUs;
    }

    if (totalSampleSize == 0 || durationUs <= 0) {
        LOG(ERROR) << "Unable to estimate track bitrate";
        return AMEDIA_ERROR_MALFORMED;
    }

    *bitrate = roundf((float)totalSampleSize * 8 * 1000000 / durationUs);
    return AMEDIA_OK;
}

media_status_t MediaSampleReaderNDK::getSampleInfoForTrack(int trackIndex, MediaSampleInfo* info) {
    std::scoped_lock lock(mExtractorMutex);

+2 −3
Original line number Diff line number Diff line
@@ -45,9 +45,8 @@ media_status_t MediaTrackTranscoder::configure(
    mMediaSampleReader = mediaSampleReader;
    mTrackIndex = trackIndex;

    mSourceFormat =
            std::shared_ptr<AMediaFormat>(mMediaSampleReader->getTrackFormat(mTrackIndex),
                                          std::bind(AMediaFormat_delete, std::placeholders::_1));
    mSourceFormat = std::shared_ptr<AMediaFormat>(mMediaSampleReader->getTrackFormat(mTrackIndex),
                                                  &AMediaFormat_delete);
    if (mSourceFormat == nullptr) {
        LOG(ERROR) << "Unable to get format for track #" << mTrackIndex;
        return AMEDIA_ERROR_MALFORMED;
+14 −0
Original line number Diff line number Diff line
@@ -162,6 +162,8 @@ VideoTrackTranscoder::~VideoTrackTranscoder() {
// Creates and configures the codecs.
media_status_t VideoTrackTranscoder::configureDestinationFormat(
        const std::shared_ptr<AMediaFormat>& destinationFormat) {
    static constexpr int32_t kDefaultBitrateMbps = 10 * 1000 * 1000;

    media_status_t status = AMEDIA_OK;

    if (destinationFormat == nullptr) {
@@ -175,6 +177,18 @@ media_status_t VideoTrackTranscoder::configureDestinationFormat(
        return AMEDIA_ERROR_INVALID_PARAMETER;
    }

    int32_t bitrate;
    if (!AMediaFormat_getInt32(encoderFormat, AMEDIAFORMAT_KEY_BIT_RATE, &bitrate)) {
        status = mMediaSampleReader->getEstimatedBitrateForTrack(mTrackIndex, &bitrate);
        if (status != AMEDIA_OK) {
            LOG(ERROR) << "Unable to estimate bitrate. Using default " << kDefaultBitrateMbps;
            bitrate = kDefaultBitrateMbps;
        }

        LOG(INFO) << "Configuring bitrate " << bitrate;
        AMediaFormat_setInt32(encoderFormat, AMEDIAFORMAT_KEY_BIT_RATE, bitrate);
    }

    float tmp;
    if (!AMediaFormat_getFloat(encoderFormat, AMEDIAFORMAT_KEY_I_FRAME_INTERVAL, &tmp)) {
        AMediaFormat_setFloat(encoderFormat, AMEDIAFORMAT_KEY_I_FRAME_INTERVAL,
+10 −0
Original line number Diff line number Diff line
@@ -56,6 +56,16 @@ public:
     */
    virtual AMediaFormat* getTrackFormat(int trackIndex) = 0;

    /**
     * Estimates the bitrate of a source track by sampling sample sizes. The bitrate is returned in
     * megabits per second (Mbps). This method will fail if the track only contains a single sample
     * and does not have an associated duration.
     * @param trackIndex The source track index.
     * @param bitrate Output param for the bitrate.
     * @return AMEDIA_OK on success.
     */
    virtual media_status_t getEstimatedBitrateForTrack(int trackIndex, int32_t* bitrate);

    /**
     * Returns the sample information for the current sample in the specified track.
     * @param trackIndex The track index (zero-based).
+1 −0
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ public:
    AMediaFormat* getFileFormat() override;
    size_t getTrackCount() const override;
    AMediaFormat* getTrackFormat(int trackIndex) override;
    media_status_t getEstimatedBitrateForTrack(int trackIndex, int32_t* bitrate) override;
    media_status_t getSampleInfoForTrack(int trackIndex, MediaSampleInfo* info) override;
    media_status_t readSampleDataForTrack(int trackIndex, uint8_t* buffer,
                                          size_t bufferSize) override;
Loading