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