Transcoder: Added MediaTranscoder and unit test.
MediaTranscoder is the API for the native transcoding library.
Test: Unit tests.
Bug: 156003955, 152091443, 155918341
Change-Id: I24b52d174db0faecea8f331ef6d8a3dc4e473c4e
diff --git a/media/libmediatranscoding/transcoder/tests/Android.bp b/media/libmediatranscoding/transcoder/tests/Android.bp
index 926110885..4160c30 100644
--- a/media/libmediatranscoding/transcoder/tests/Android.bp
+++ b/media/libmediatranscoding/transcoder/tests/Android.bp
@@ -74,3 +74,10 @@
defaults: ["testdefaults"],
srcs: ["MediaSampleWriterTests.cpp"],
}
+
+// MediaTranscoder unit test
+cc_test {
+ name: "MediaTranscoderTests",
+ defaults: ["testdefaults"],
+ srcs: ["MediaTranscoderTests.cpp"],
+}
diff --git a/media/libmediatranscoding/transcoder/tests/MediaTrackTranscoderTests.cpp b/media/libmediatranscoding/transcoder/tests/MediaTrackTranscoderTests.cpp
index c5b181d..4d9386a 100644
--- a/media/libmediatranscoding/transcoder/tests/MediaTrackTranscoderTests.cpp
+++ b/media/libmediatranscoding/transcoder/tests/MediaTrackTranscoderTests.cpp
@@ -60,6 +60,7 @@
break;
}
ASSERT_NE(mTranscoder, nullptr);
+ mTranscoderOutputQueue = mTranscoder->getOutputQueue();
initSampleReader();
}
@@ -120,7 +121,7 @@
std::shared_ptr<MediaSample> sample;
bool aborted = false;
do {
- aborted = mTranscoder->mOutputQueue.dequeue(&sample);
+ aborted = mTranscoderOutputQueue->dequeue(&sample);
} while (!aborted && !(sample->info.flags & SAMPLE_FLAG_END_OF_STREAM));
mQueueWasAborted = aborted;
mGotEndOfStream =
@@ -142,6 +143,7 @@
protected:
std::shared_ptr<MediaTrackTranscoder> mTranscoder;
+ std::shared_ptr<MediaSampleQueue> mTranscoderOutputQueue;
std::shared_ptr<TestCallback> mCallback;
std::shared_ptr<MediaSampleReader> mMediaSampleReader;
@@ -242,7 +244,7 @@
EXPECT_EQ(mTranscoder->configure(mMediaSampleReader, mTrackIndex, mDestinationFormat),
AMEDIA_OK);
ASSERT_TRUE(mTranscoder->start());
- mTranscoder->mOutputQueue.abort();
+ mTranscoderOutputQueue->abort();
drainOutputSampleQueue();
EXPECT_EQ(mCallback->waitUntilFinished(), AMEDIA_ERROR_IO);
EXPECT_TRUE(mTranscoder->stop());
@@ -259,7 +261,7 @@
ASSERT_TRUE(mTranscoder->start());
std::shared_ptr<MediaSample> sample;
- EXPECT_FALSE(mTranscoder->mOutputQueue.dequeue(&sample));
+ EXPECT_FALSE(mTranscoderOutputQueue->dequeue(&sample));
drainOutputSampleQueue();
EXPECT_EQ(mCallback->waitUntilFinished(), AMEDIA_OK);
@@ -269,6 +271,7 @@
EXPECT_TRUE(mGotEndOfStream);
mTranscoder.reset();
+ mTranscoderOutputQueue.reset();
std::this_thread::sleep_for(std::chrono::milliseconds(20));
sample.reset();
}
@@ -280,7 +283,7 @@
ASSERT_TRUE(mTranscoder->start());
std::shared_ptr<MediaSample> sample;
- EXPECT_FALSE(mTranscoder->mOutputQueue.dequeue(&sample));
+ EXPECT_FALSE(mTranscoderOutputQueue->dequeue(&sample));
EXPECT_TRUE(mTranscoder->stop());
std::this_thread::sleep_for(std::chrono::milliseconds(20));
diff --git a/media/libmediatranscoding/transcoder/tests/MediaTranscoderTests.cpp b/media/libmediatranscoding/transcoder/tests/MediaTranscoderTests.cpp
new file mode 100644
index 0000000..c4a67bb
--- /dev/null
+++ b/media/libmediatranscoding/transcoder/tests/MediaTranscoderTests.cpp
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Unit Test for MediaTranscoder
+
+// #define LOG_NDEBUG 0
+#define LOG_TAG "MediaTranscoderTests"
+
+#include <android-base/logging.h>
+#include <gtest/gtest.h>
+#include <media/MediaTranscoder.h>
+
+namespace android {
+
+class TestCallbacks : public MediaTranscoder::CallbackInterface {
+public:
+ virtual void onFinished(const MediaTranscoder* transcoder __unused) override {
+ std::unique_lock<std::mutex> lock(mMutex);
+ EXPECT_FALSE(mFinished);
+ mFinished = true;
+ mCondition.notify_all();
+ }
+
+ virtual void onError(const MediaTranscoder* transcoder __unused,
+ media_status_t error) override {
+ std::unique_lock<std::mutex> lock(mMutex);
+ EXPECT_NE(error, AMEDIA_OK);
+ EXPECT_FALSE(mFinished);
+ mFinished = true;
+ mStatus = error;
+ mCondition.notify_all();
+ }
+
+ virtual void onProgressUpdate(const MediaTranscoder* transcoder __unused,
+ int32_t progress __unused) override {}
+
+ virtual void onCodecResourceLost(const MediaTranscoder* transcoder __unused,
+ const std::shared_ptr<const Parcelable>& pausedState
+ __unused) override {}
+
+ void waitForTranscodingFinished() {
+ std::unique_lock<std::mutex> lock(mMutex);
+ while (!mFinished) {
+ mCondition.wait(lock);
+ }
+ }
+
+ media_status_t mStatus = AMEDIA_OK;
+
+private:
+ std::mutex mMutex;
+ std::condition_variable mCondition;
+ bool mFinished = false;
+};
+
+static const char* SOURCE_PATH =
+ "/data/local/tmp/TranscoderTestAssets/cubicle_avc_480x240_aac_24KHz.mp4";
+
+class MediaTranscoderTests : public ::testing::Test {
+public:
+ MediaTranscoderTests() { LOG(DEBUG) << "MediaTranscoderTests created"; }
+ ~MediaTranscoderTests() { LOG(DEBUG) << "MediaTranscoderTests destroyed"; }
+
+ void SetUp() override {
+ LOG(DEBUG) << "MediaTranscoderTests set up";
+ mCallbacks = std::make_shared<TestCallbacks>();
+ }
+
+ void TearDown() override {
+ LOG(DEBUG) << "MediaTranscoderTests tear down";
+ mCallbacks.reset();
+ }
+
+ void deleteFile(const char* path) { unlink(path); }
+
+ using FormatConfigurationCallback = std::function<AMediaFormat*(AMediaFormat*)>;
+ media_status_t transcodeHelper(const char* destPath,
+ FormatConfigurationCallback formatCallback) {
+ auto transcoder = MediaTranscoder::create(mCallbacks, nullptr);
+ EXPECT_NE(transcoder, nullptr);
+
+ EXPECT_EQ(transcoder->configureSource(SOURCE_PATH), AMEDIA_OK);
+
+ std::vector<std::shared_ptr<AMediaFormat>> trackFormats = transcoder->getTrackFormats();
+ EXPECT_GT(trackFormats.size(), 0);
+
+ for (int i = 0; i < trackFormats.size(); ++i) {
+ AMediaFormat* format = formatCallback(trackFormats[i].get());
+ EXPECT_EQ(transcoder->configureTrackFormat(i, format), AMEDIA_OK);
+ if (format != nullptr) {
+ AMediaFormat_delete(format);
+ }
+ }
+ deleteFile(destPath);
+ EXPECT_EQ(transcoder->configureDestination(destPath), AMEDIA_OK);
+
+ media_status_t startStatus = transcoder->start();
+ EXPECT_EQ(startStatus, AMEDIA_OK);
+ if (startStatus == AMEDIA_OK) {
+ mCallbacks->waitForTranscodingFinished();
+ }
+
+ return mCallbacks->mStatus;
+ }
+
+ std::shared_ptr<TestCallbacks> mCallbacks;
+};
+
+TEST_F(MediaTranscoderTests, TestPassthrough) {
+ const char* destPath = "/data/local/tmp/MediaTranscoder_Passthrough.MP4";
+
+ EXPECT_EQ(transcodeHelper(destPath, [](AMediaFormat*) { return nullptr; }), AMEDIA_OK);
+
+ // TODO: Validate output file
+}
+
+TEST_F(MediaTranscoderTests, TestBasicVideoTranscode) {
+ const char* destPath = "/data/local/tmp/MediaTranscoder_VideoTranscode.MP4";
+
+ EXPECT_EQ(transcodeHelper(
+ destPath,
+ [](AMediaFormat* sourceFormat) {
+ AMediaFormat* format = nullptr;
+ const char* mime = nullptr;
+ AMediaFormat_getString(sourceFormat, AMEDIAFORMAT_KEY_MIME, &mime);
+
+ if (strncmp(mime, "video/", 6) == 0) {
+ const int32_t kBitRate = 8 * 1000 * 1000; // 8Mbs
+ format = AMediaFormat_new();
+ AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_BIT_RATE, kBitRate);
+ }
+ return format;
+ }),
+ AMEDIA_OK);
+
+ // TODO: Validate output file
+}
+
+} // namespace android
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/media/libmediatranscoding/transcoder/tests/PassthroughTrackTranscoderTests.cpp b/media/libmediatranscoding/transcoder/tests/PassthroughTrackTranscoderTests.cpp
index 7a92a37..316793a 100644
--- a/media/libmediatranscoding/transcoder/tests/PassthroughTrackTranscoderTests.cpp
+++ b/media/libmediatranscoding/transcoder/tests/PassthroughTrackTranscoderTests.cpp
@@ -166,7 +166,8 @@
// Pull transcoder's output samples and compare against input checksums.
uint64_t sampleCount = 0;
std::shared_ptr<MediaSample> sample;
- while (!transcoder.mOutputQueue.dequeue(&sample)) {
+ std::shared_ptr<MediaSampleQueue> outputQueue = transcoder.getOutputQueue();
+ while (!outputQueue->dequeue(&sample)) {
ASSERT_NE(sample, nullptr);
if (sample->info.flags & SAMPLE_FLAG_END_OF_STREAM) {
diff --git a/media/libmediatranscoding/transcoder/tests/TrackTranscoderTestUtils.h b/media/libmediatranscoding/transcoder/tests/TrackTranscoderTestUtils.h
index 6b9131c..79c227b 100644
--- a/media/libmediatranscoding/transcoder/tests/TrackTranscoderTestUtils.h
+++ b/media/libmediatranscoding/transcoder/tests/TrackTranscoderTestUtils.h
@@ -56,13 +56,13 @@
~TestCallback() = default;
// MediaTrackTranscoderCallback
- void onTrackFinished(MediaTrackTranscoder* transcoder __unused) {
+ void onTrackFinished(const MediaTrackTranscoder* transcoder __unused) {
std::unique_lock<std::mutex> lock(mMutex);
mTranscodingFinished = true;
mCv.notify_all();
}
- void onTrackError(MediaTrackTranscoder* transcoder __unused, media_status_t status) {
+ void onTrackError(const MediaTrackTranscoder* transcoder __unused, media_status_t status) {
std::unique_lock<std::mutex> lock(mMutex);
mTranscodingFinished = true;
mStatus = status;
diff --git a/media/libmediatranscoding/transcoder/tests/VideoTrackTranscoderTests.cpp b/media/libmediatranscoding/transcoder/tests/VideoTrackTranscoderTests.cpp
index 3cec1a1..6b1f640 100644
--- a/media/libmediatranscoding/transcoder/tests/VideoTrackTranscoderTests.cpp
+++ b/media/libmediatranscoding/transcoder/tests/VideoTrackTranscoderTests.cpp
@@ -100,10 +100,11 @@
EXPECT_EQ(transcoder.configure(mMediaSampleReader, mTrackIndex, mDestinationFormat), AMEDIA_OK);
ASSERT_TRUE(transcoder.start());
- std::thread sampleConsumerThread{[&transcoder] {
+ std::shared_ptr<MediaSampleQueue> outputQueue = transcoder.getOutputQueue();
+ std::thread sampleConsumerThread{[&outputQueue] {
uint64_t sampleCount = 0;
std::shared_ptr<MediaSample> sample;
- while (!transcoder.mOutputQueue.dequeue(&sample)) {
+ while (!outputQueue->dequeue(&sample)) {
ASSERT_NE(sample, nullptr);
const uint32_t flags = sample->info.flags;
diff --git a/media/libmediatranscoding/transcoder/tests/build_and_run_all_unit_tests.sh b/media/libmediatranscoding/transcoder/tests/build_and_run_all_unit_tests.sh
index 70e2111..01beeee 100755
--- a/media/libmediatranscoding/transcoder/tests/build_and_run_all_unit_tests.sh
+++ b/media/libmediatranscoding/transcoder/tests/build_and_run_all_unit_tests.sh
@@ -39,3 +39,6 @@
echo "testing MediaSampleWriter"
adb shell /data/nativetest64/MediaSampleWriterTests/MediaSampleWriterTests
+
+echo "testing MediaTranscoder"
+adb shell /data/nativetest64/MediaTranscoderTests/MediaTranscoderTests