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
diff --git a/media/libmediatranscoding/transcoder/MediaSampleReaderNDK.cpp b/media/libmediatranscoding/transcoder/MediaSampleReaderNDK.cpp
index a0096c7..6a00a10 100644
--- a/media/libmediatranscoding/transcoder/MediaSampleReaderNDK.cpp
+++ b/media/libmediatranscoding/transcoder/MediaSampleReaderNDK.cpp
@@ -21,6 +21,7 @@
#include <media/MediaSampleReaderNDK.h>
#include <algorithm>
+#include <cmath>
#include <vector>
namespace android {
@@ -189,6 +190,78 @@
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);
diff --git a/media/libmediatranscoding/transcoder/MediaTrackTranscoder.cpp b/media/libmediatranscoding/transcoder/MediaTrackTranscoder.cpp
index e3996b0..58e2066 100644
--- a/media/libmediatranscoding/transcoder/MediaTrackTranscoder.cpp
+++ b/media/libmediatranscoding/transcoder/MediaTrackTranscoder.cpp
@@ -45,9 +45,8 @@
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;
diff --git a/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp b/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
index 65dcad3..e192d2a 100644
--- a/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
+++ b/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
@@ -162,6 +162,8 @@
// 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 @@
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,
diff --git a/media/libmediatranscoding/transcoder/include/media/MediaSampleReader.h b/media/libmediatranscoding/transcoder/include/media/MediaSampleReader.h
index acebac2..25df7ab 100644
--- a/media/libmediatranscoding/transcoder/include/media/MediaSampleReader.h
+++ b/media/libmediatranscoding/transcoder/include/media/MediaSampleReader.h
@@ -57,6 +57,16 @@
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).
* @param info Pointer to a MediaSampleInfo object where the sample information is written.
diff --git a/media/libmediatranscoding/transcoder/include/media/MediaSampleReaderNDK.h b/media/libmediatranscoding/transcoder/include/media/MediaSampleReaderNDK.h
index 2dc9029..6c5019d 100644
--- a/media/libmediatranscoding/transcoder/include/media/MediaSampleReaderNDK.h
+++ b/media/libmediatranscoding/transcoder/include/media/MediaSampleReaderNDK.h
@@ -46,6 +46,7 @@
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;
diff --git a/media/libmediatranscoding/transcoder/tests/MediaSampleReaderNDKTests.cpp b/media/libmediatranscoding/transcoder/tests/MediaSampleReaderNDKTests.cpp
index 805095e..323e5ae 100644
--- a/media/libmediatranscoding/transcoder/tests/MediaSampleReaderNDKTests.cpp
+++ b/media/libmediatranscoding/transcoder/tests/MediaSampleReaderNDKTests.cpp
@@ -27,6 +27,8 @@
#include <media/MediaSampleReaderNDK.h>
#include <utils/Timers.h>
+#include <cmath>
+
// TODO(b/153453392): Test more asset types and validate sample data from readSampleDataForTrack.
namespace android {
@@ -70,6 +72,31 @@
mExtractorTimestamps[trackIndex].push_back(sampleTime);
} while (AMediaExtractor_advance(mExtractor));
+
+ AMediaExtractor_seekTo(mExtractor, 0, AMEDIAEXTRACTOR_SEEK_PREVIOUS_SYNC);
+ }
+
+ std::vector<int32_t> getTrackBitrates() {
+ size_t totalSize[mTrackCount];
+ memset(totalSize, 0, sizeof(totalSize));
+
+ do {
+ const int trackIndex = AMediaExtractor_getSampleTrackIndex(mExtractor);
+ totalSize[trackIndex] += AMediaExtractor_getSampleSize(mExtractor);
+ } while (AMediaExtractor_advance(mExtractor));
+
+ AMediaExtractor_seekTo(mExtractor, 0, AMEDIAEXTRACTOR_SEEK_PREVIOUS_SYNC);
+
+ std::vector<int32_t> bitrates;
+ for (int trackIndex = 0; trackIndex < mTrackCount; trackIndex++) {
+ int64_t durationUs;
+ AMediaFormat* trackFormat = AMediaExtractor_getTrackFormat(mExtractor, trackIndex);
+ EXPECT_NE(trackFormat, nullptr);
+ EXPECT_TRUE(AMediaFormat_getInt64(trackFormat, AMEDIAFORMAT_KEY_DURATION, &durationUs));
+ bitrates.push_back(roundf((float)totalSize[trackIndex] * 8 * 1000000 / durationUs));
+ }
+
+ return bitrates;
}
void TearDown() override {
@@ -141,6 +168,28 @@
}
}
+TEST_F(MediaSampleReaderNDKTests, TestEstimatedBitrateAccuracy) {
+ // Just put a somewhat reasonable upper bound on the estimated bitrate expected in our test
+ // assets. This is mostly to make sure the estimation is not way off.
+ static constexpr int32_t kMaxEstimatedBitrate = 100 * 1000 * 1000; // 100 Mbps
+
+ auto sampleReader = MediaSampleReaderNDK::createFromFd(mSourceFd, 0, mFileSize);
+ ASSERT_TRUE(sampleReader);
+
+ std::vector<int32_t> actualTrackBitrates = getTrackBitrates();
+ for (int trackIndex = 0; trackIndex < mTrackCount; ++trackIndex) {
+ int32_t bitrate;
+ EXPECT_EQ(sampleReader->getEstimatedBitrateForTrack(trackIndex, &bitrate), AMEDIA_OK);
+ EXPECT_GT(bitrate, 0);
+ EXPECT_LT(bitrate, kMaxEstimatedBitrate);
+
+ // Note: The test asset currently used in this test is shorter than the sampling duration
+ // used to estimate the bitrate in the sample reader. So for now the estimation should be
+ // exact but if/when a longer asset is used a reasonable delta needs to be defined.
+ EXPECT_EQ(bitrate, actualTrackBitrates[trackIndex]);
+ }
+}
+
TEST_F(MediaSampleReaderNDKTests, TestInvalidFd) {
std::shared_ptr<MediaSampleReader> sampleReader =
MediaSampleReaderNDK::createFromFd(0, 0, mFileSize);
diff --git a/media/libmediatranscoding/transcoder/tests/MediaTrackTranscoderTests.cpp b/media/libmediatranscoding/transcoder/tests/MediaTrackTranscoderTests.cpp
index 502d5aa..804571c 100644
--- a/media/libmediatranscoding/transcoder/tests/MediaTrackTranscoderTests.cpp
+++ b/media/libmediatranscoding/transcoder/tests/MediaTrackTranscoderTests.cpp
@@ -91,8 +91,7 @@
if (GetParam() == VIDEO && strncmp(mime, "video/", 6) == 0) {
mTrackIndex = trackIndex;
- mSourceFormat = std::shared_ptr<AMediaFormat>(
- trackFormat, std::bind(AMediaFormat_delete, std::placeholders::_1));
+ mSourceFormat = std::shared_ptr<AMediaFormat>(trackFormat, &AMediaFormat_delete);
ASSERT_NE(mSourceFormat, nullptr);
mDestinationFormat =
@@ -103,8 +102,7 @@
// TODO(lnilsson): Test metadata track passthrough after hkuang@ provides sample.
mTrackIndex = trackIndex;
- mSourceFormat = std::shared_ptr<AMediaFormat>(
- trackFormat, std::bind(AMediaFormat_delete, std::placeholders::_1));
+ mSourceFormat = std::shared_ptr<AMediaFormat>(trackFormat, &AMediaFormat_delete);
ASSERT_NE(mSourceFormat, nullptr);
break;
}
diff --git a/media/libmediatranscoding/transcoder/tests/MediaTranscoderTests.cpp b/media/libmediatranscoding/transcoder/tests/MediaTranscoderTests.cpp
index e68eaac..53bd2a2 100644
--- a/media/libmediatranscoding/transcoder/tests/MediaTranscoderTests.cpp
+++ b/media/libmediatranscoding/transcoder/tests/MediaTranscoderTests.cpp
@@ -115,6 +115,17 @@
void deleteFile(const char* path) { unlink(path); }
+ float getFileSizeDiffPercent(const char* path1, const char* path2, bool absolute = false) {
+ struct stat s1, s2;
+ EXPECT_EQ(stat(path1, &s1), 0);
+ EXPECT_EQ(stat(path2, &s2), 0);
+
+ int64_t diff = s2.st_size - s1.st_size;
+ if (absolute && diff < 0) diff = -diff;
+
+ return (float)diff * 100.0f / s1.st_size;
+ }
+
using FormatConfigurationCallback = std::function<AMediaFormat*(AMediaFormat*)>;
media_status_t transcodeHelper(const char* srcPath, const char* destPath,
FormatConfigurationCallback formatCallback) {
@@ -157,28 +168,32 @@
return mCallbacks->mStatus;
}
- void testTranscodeVideo(const char* srcPath, const char* destPath, const char* dstMime) {
- const int32_t kBitRate = 8 * 1000 * 1000; // 8Mbs
+ void testTranscodeVideo(const char* srcPath, const char* destPath, const char* dstMime,
+ int32_t bitrate = 0) {
+ EXPECT_EQ(transcodeHelper(srcPath, destPath,
+ [dstMime, bitrate](AMediaFormat* sourceFormat) {
+ AMediaFormat* format = nullptr;
+ const char* mime = nullptr;
+ AMediaFormat_getString(sourceFormat, AMEDIAFORMAT_KEY_MIME,
+ &mime);
- EXPECT_EQ(
- transcodeHelper(
- srcPath, destPath,
- [dstMime](AMediaFormat* sourceFormat) {
- AMediaFormat* format = nullptr;
- const char* mime = nullptr;
- AMediaFormat_getString(sourceFormat, AMEDIAFORMAT_KEY_MIME, &mime);
+ if (strncmp(mime, "video/", 6) == 0 &&
+ (bitrate > 0 || dstMime != nullptr)) {
+ format = AMediaFormat_new();
- if (strncmp(mime, "video/", 6) == 0) {
- format = AMediaFormat_new();
- AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_BIT_RATE, kBitRate);
+ if (bitrate > 0) {
+ AMediaFormat_setInt32(
+ format, AMEDIAFORMAT_KEY_BIT_RATE, bitrate);
+ }
- if (dstMime != nullptr) {
- AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, dstMime);
- }
- }
- return format;
- }),
- AMEDIA_OK);
+ if (dstMime != nullptr) {
+ AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME,
+ dstMime);
+ }
+ }
+ return format;
+ }),
+ AMEDIA_OK);
if (dstMime != nullptr) {
std::vector<FormatVerifierEntry> extraVerifiers = {
@@ -251,16 +266,13 @@
TEST_F(MediaTranscoderTests, TestPassthrough) {
const char* srcPath = "/data/local/tmp/TranscodingTestAssets/cubicle_avc_480x240_aac_24KHz.mp4";
const char* destPath = "/data/local/tmp/MediaTranscoder_Passthrough.MP4";
-
- EXPECT_EQ(transcodeHelper(srcPath, destPath, [](AMediaFormat*) { return nullptr; }), AMEDIA_OK);
-
- verifyOutputFormat(destPath);
+ testTranscodeVideo(srcPath, destPath, nullptr);
}
TEST_F(MediaTranscoderTests, TestVideoTranscode_AvcToAvc_Basic) {
const char* srcPath = "/data/local/tmp/TranscodingTestAssets/cubicle_avc_480x240_aac_24KHz.mp4";
const char* destPath = "/data/local/tmp/MediaTranscoder_VideoTranscode_AvcToAvc_Basic.MP4";
- testTranscodeVideo(srcPath, destPath, nullptr /*dstMime*/);
+ testTranscodeVideo(srcPath, destPath, AMEDIA_MIMETYPE_VIDEO_AVC);
}
TEST_F(MediaTranscoderTests, TestVideoTranscode_HevcToAvc_Basic) {
@@ -276,6 +288,28 @@
testTranscodeVideo(srcPath, destPath, AMEDIA_MIMETYPE_VIDEO_AVC);
}
+TEST_F(MediaTranscoderTests, TestPreserveBitrate) {
+ const char* srcPath = "/data/local/tmp/TranscodingTestAssets/cubicle_avc_480x240_aac_24KHz.mp4";
+ const char* destPath = "/data/local/tmp/MediaTranscoder_PreserveBitrate.MP4";
+ testTranscodeVideo(srcPath, destPath, AMEDIA_MIMETYPE_VIDEO_AVC);
+
+ // Require maximum of 10% difference in file size.
+ EXPECT_LT(getFileSizeDiffPercent(srcPath, destPath, true /* absolute*/), 10);
+}
+
+TEST_F(MediaTranscoderTests, TestCustomBitrate) {
+ const char* srcPath = "/data/local/tmp/TranscodingTestAssets/cubicle_avc_480x240_aac_24KHz.mp4";
+ const char* destPath1 = "/data/local/tmp/MediaTranscoder_CustomBitrate_2Mbps.MP4";
+ const char* destPath2 = "/data/local/tmp/MediaTranscoder_CustomBitrate_8Mbps.MP4";
+ testTranscodeVideo(srcPath, destPath1, AMEDIA_MIMETYPE_VIDEO_AVC, 2 * 1000 * 1000);
+ mCallbacks = std::make_shared<TestCallbacks>();
+ testTranscodeVideo(srcPath, destPath2, AMEDIA_MIMETYPE_VIDEO_AVC, 8 * 1000 * 1000);
+
+ // The source asset is very short and heavily compressed from the beginning so don't expect the
+ // requested bitrate to be exactly matched. However 40% difference seems reasonable.
+ EXPECT_GT(getFileSizeDiffPercent(destPath1, destPath2), 40);
+}
+
} // namespace android
int main(int argc, char** argv) {
diff --git a/media/libmediatranscoding/transcoder/tests/TrackTranscoderTestUtils.h b/media/libmediatranscoding/transcoder/tests/TrackTranscoderTestUtils.h
index 54b42fe..a3ddd71 100644
--- a/media/libmediatranscoding/transcoder/tests/TrackTranscoderTestUtils.h
+++ b/media/libmediatranscoding/transcoder/tests/TrackTranscoderTestUtils.h
@@ -30,7 +30,7 @@
class TrackTranscoderTestUtils {
public:
static std::shared_ptr<AMediaFormat> getDefaultVideoDestinationFormat(
- AMediaFormat* sourceFormat) {
+ AMediaFormat* sourceFormat, bool includeBitrate = true) {
// Default video destination format setup.
static constexpr float kFrameRate = 30.0f;
static constexpr float kIFrameInterval = 30.0f;
@@ -42,12 +42,13 @@
AMediaFormat_setFloat(destinationFormat, AMEDIAFORMAT_KEY_FRAME_RATE, kFrameRate);
AMediaFormat_setFloat(destinationFormat, AMEDIAFORMAT_KEY_I_FRAME_INTERVAL,
kIFrameInterval);
- AMediaFormat_setInt32(destinationFormat, AMEDIAFORMAT_KEY_BIT_RATE, kBitRate);
+ if (includeBitrate) {
+ AMediaFormat_setInt32(destinationFormat, AMEDIAFORMAT_KEY_BIT_RATE, kBitRate);
+ }
AMediaFormat_setInt32(destinationFormat, AMEDIAFORMAT_KEY_COLOR_FORMAT,
kColorFormatSurface);
- return std::shared_ptr<AMediaFormat>(destinationFormat,
- std::bind(AMediaFormat_delete, std::placeholders::_1));
+ return std::shared_ptr<AMediaFormat>(destinationFormat, &AMediaFormat_delete);
}
};
@@ -57,35 +58,48 @@
~TestCallback() = default;
// MediaTrackTranscoderCallback
- void onTrackFormatAvailable(const MediaTrackTranscoder* transcoder __unused) {}
+ void onTrackFormatAvailable(const MediaTrackTranscoder* transcoder __unused) {
+ std::unique_lock<std::mutex> lock(mMutex);
+ mTrackFormatAvailable = true;
+ mTrackFormatAvailableCondition.notify_all();
+ }
void onTrackFinished(const MediaTrackTranscoder* transcoder __unused) {
std::unique_lock<std::mutex> lock(mMutex);
mTranscodingFinished = true;
- mCv.notify_all();
+ mTranscodingFinishedCondition.notify_all();
}
void onTrackError(const MediaTrackTranscoder* transcoder __unused, media_status_t status) {
std::unique_lock<std::mutex> lock(mMutex);
mTranscodingFinished = true;
mStatus = status;
- mCv.notify_all();
+ mTranscodingFinishedCondition.notify_all();
}
// ~MediaTrackTranscoderCallback
media_status_t waitUntilFinished() {
std::unique_lock<std::mutex> lock(mMutex);
while (!mTranscodingFinished) {
- mCv.wait(lock);
+ mTranscodingFinishedCondition.wait(lock);
}
return mStatus;
}
+ void waitUntilTrackFormatAvailable() {
+ std::unique_lock<std::mutex> lock(mMutex);
+ while (!mTrackFormatAvailable) {
+ mTrackFormatAvailableCondition.wait(lock);
+ }
+ }
+
private:
media_status_t mStatus = AMEDIA_OK;
std::mutex mMutex;
- std::condition_variable mCv;
+ std::condition_variable mTranscodingFinishedCondition;
+ std::condition_variable mTrackFormatAvailableCondition;
bool mTranscodingFinished = false;
+ bool mTrackFormatAvailable = false;
};
}; // namespace android
diff --git a/media/libmediatranscoding/transcoder/tests/VideoTrackTranscoderTests.cpp b/media/libmediatranscoding/transcoder/tests/VideoTrackTranscoderTests.cpp
index 5f2cd12..4eecd90 100644
--- a/media/libmediatranscoding/transcoder/tests/VideoTrackTranscoderTests.cpp
+++ b/media/libmediatranscoding/transcoder/tests/VideoTrackTranscoderTests.cpp
@@ -23,6 +23,7 @@
#include <fcntl.h>
#include <gtest/gtest.h>
#include <media/MediaSampleReaderNDK.h>
+#include <media/NdkCommon.h>
#include <media/VideoTrackTranscoder.h>
#include <utils/Timers.h>
@@ -66,8 +67,7 @@
if (strncmp(mime, "video/", 6) == 0) {
mTrackIndex = trackIndex;
- mSourceFormat = std::shared_ptr<AMediaFormat>(
- trackFormat, std::bind(AMediaFormat_delete, std::placeholders::_1));
+ mSourceFormat = std::shared_ptr<AMediaFormat>(trackFormat, &AMediaFormat_delete);
ASSERT_NE(mSourceFormat, nullptr);
mDestinationFormat =
@@ -143,6 +143,35 @@
sampleConsumerThread.join();
}
+TEST_F(VideoTrackTranscoderTests, PreserveBitrate) {
+ LOG(DEBUG) << "Testing PreserveBitrate";
+ std::shared_ptr<TestCallback> callback = std::make_shared<TestCallback>();
+ std::shared_ptr<MediaTrackTranscoder> transcoder = VideoTrackTranscoder::create(callback);
+
+ auto destFormat = TrackTranscoderTestUtils::getDefaultVideoDestinationFormat(
+ mSourceFormat.get(), false /* includeBitrate*/);
+ EXPECT_NE(destFormat, nullptr);
+
+ ASSERT_EQ(transcoder->configure(mMediaSampleReader, mTrackIndex, destFormat), AMEDIA_OK);
+ ASSERT_TRUE(transcoder->start());
+
+ callback->waitUntilTrackFormatAvailable();
+
+ auto outputFormat = transcoder->getOutputFormat();
+ ASSERT_NE(outputFormat, nullptr);
+
+ ASSERT_TRUE(transcoder->stop());
+ transcoder->getOutputQueue()->abort();
+
+ int32_t outBitrate;
+ EXPECT_TRUE(AMediaFormat_getInt32(outputFormat.get(), AMEDIAFORMAT_KEY_BIT_RATE, &outBitrate));
+
+ int32_t srcBitrate;
+ EXPECT_EQ(mMediaSampleReader->getEstimatedBitrateForTrack(mTrackIndex, &srcBitrate), AMEDIA_OK);
+
+ EXPECT_EQ(srcBitrate, outBitrate);
+}
+
// VideoTrackTranscoder needs a valid destination format.
TEST_F(VideoTrackTranscoderTests, NullDestinationFormat) {
LOG(DEBUG) << "Testing NullDestinationFormat";