Merge "Transcoder: Preserve source track's bitrate by default."
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 e5c065b..5702627 100644
--- a/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
+++ b/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
@@ -164,6 +164,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) {
@@ -177,6 +179,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 8d12256..b432553 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";