Merge "Transcoder: Add HDR -> SDR unit test using sample plugin." into sc-dev
diff --git a/media/libmediatranscoding/tests/assets/TranscodingTestAssets/video_1280x720_hevc_hdr10_static_3mbps.mp4 b/media/libmediatranscoding/tests/assets/TranscodingTestAssets/video_1280x720_hevc_hdr10_static_3mbps.mp4
new file mode 100644
index 0000000..17150d4
--- /dev/null
+++ b/media/libmediatranscoding/tests/assets/TranscodingTestAssets/video_1280x720_hevc_hdr10_static_3mbps.mp4
Binary files differ
diff --git a/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp b/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
index acf5f6c..ab08d73 100644
--- a/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
+++ b/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
@@ -145,12 +145,12 @@
VideoTrackTranscoder::CodecWrapper* wrapper =
static_cast<VideoTrackTranscoder::CodecWrapper*>(userdata);
if (auto transcoder = wrapper->getTranscoder()) {
- const char* kCodecName = (codec == transcoder->mDecoder ? "Decoder" : "Encoder");
+ const bool isDecoder = codec == transcoder->mDecoder;
+ const char* kCodecName = (isDecoder ? "Decoder" : "Encoder");
LOG(DEBUG) << kCodecName << " format changed: " << AMediaFormat_toString(format);
- if (codec == transcoder->mEncoder->getCodec()) {
- transcoder->mCodecMessageQueue.push(
- [transcoder, format] { transcoder->updateTrackFormat(format); });
- }
+ transcoder->mCodecMessageQueue.push([transcoder, format, isDecoder] {
+ transcoder->updateTrackFormat(format, isDecoder);
+ });
}
}
@@ -507,7 +507,25 @@
}
}
-void VideoTrackTranscoder::updateTrackFormat(AMediaFormat* outputFormat) {
+void VideoTrackTranscoder::updateTrackFormat(AMediaFormat* outputFormat, bool fromDecoder) {
+ if (fromDecoder) {
+ static const AMediaFormatUtils::EntryCopier kValuesToCopy[] = {
+ ENTRY_COPIER(AMEDIAFORMAT_KEY_COLOR_RANGE, Int32),
+ ENTRY_COPIER(AMEDIAFORMAT_KEY_COLOR_STANDARD, Int32),
+ ENTRY_COPIER(AMEDIAFORMAT_KEY_COLOR_TRANSFER, Int32),
+ };
+ AMediaFormat* params = AMediaFormat_new();
+ if (params != nullptr) {
+ AMediaFormatUtils::CopyFormatEntries(outputFormat, params, kValuesToCopy,
+ std::size(kValuesToCopy));
+ if (AMediaCodec_setParameters(mEncoder->getCodec(), params) != AMEDIA_OK) {
+ LOG(WARNING) << "Unable to update encoder with color information";
+ }
+ AMediaFormat_delete(params);
+ }
+ return;
+ }
+
if (mActualOutputFormat != nullptr) {
LOG(WARNING) << "Ignoring duplicate format change.";
return;
@@ -571,6 +589,7 @@
// TODO: transfer other fields as required.
mActualOutputFormat = std::shared_ptr<AMediaFormat>(formatCopy, &AMediaFormat_delete);
+ LOG(DEBUG) << "Actual output format: " << AMediaFormat_toString(formatCopy);
notifyTrackFormatAvailable();
}
diff --git a/media/libmediatranscoding/transcoder/include/media/VideoTrackTranscoder.h b/media/libmediatranscoding/transcoder/include/media/VideoTrackTranscoder.h
index 4413a6c..8a506a0 100644
--- a/media/libmediatranscoding/transcoder/include/media/VideoTrackTranscoder.h
+++ b/media/libmediatranscoding/transcoder/include/media/VideoTrackTranscoder.h
@@ -83,8 +83,8 @@
// Dequeues an encoded buffer from the encoder and adds it to the output queue.
void dequeueOutputSample(int32_t bufferIndex, AMediaCodecBufferInfo bufferInfo);
- // Updates the video track's actual format based on encoder output format.
- void updateTrackFormat(AMediaFormat* outputFormat);
+ // Updates the video track's actual format based on encoder and decoder output format.
+ void updateTrackFormat(AMediaFormat* outputFormat, bool fromDecoder);
AMediaCodec* mDecoder = nullptr;
std::shared_ptr<CodecWrapper> mEncoder;
diff --git a/media/libmediatranscoding/transcoder/setloglevel.sh b/media/libmediatranscoding/transcoder/setloglevel.sh
index 5eb7b67..b0f0a2e 100755
--- a/media/libmediatranscoding/transcoder/setloglevel.sh
+++ b/media/libmediatranscoding/transcoder/setloglevel.sh
@@ -2,19 +2,29 @@
if [ $# -ne 1 ]
then
- echo Usage: $0 loglevel
+ echo "Usage 1: $0 <loglevel>"
+ echo " Set all transcoder log tags to <loglevel>"
+ echo "Usage 2: $0 -l"
+ echo " List all transcoder log tags and exit"
exit 1
fi
-level=$1
-echo Setting transcoder log level to $level
-
# List all log tags
declare -a tags=(
MediaTranscoder MediaTrackTranscoder VideoTrackTranscoder PassthroughTrackTranscoder
MediaSampleWriter MediaSampleReader MediaSampleQueue MediaTranscoderTests
MediaTrackTranscoderTests VideoTrackTranscoderTests PassthroughTrackTranscoderTests
- MediaSampleWriterTests MediaSampleReaderNDKTests MediaSampleQueueTests)
+ MediaSampleWriterTests MediaSampleReaderNDKTests MediaSampleQueueTests HdrTranscodeTests)
+
+if [ "$1" == "-l" ]; then
+ echo "Transcoder log tags:"
+ for tag in "${tags[@]}"; do echo -n "$tag "; done
+ echo
+ exit 0
+fi
+
+level=$1
+echo Setting transcoder log level to $level
# Set log level for all tags
for tag in "${tags[@]}"
diff --git a/media/libmediatranscoding/transcoder/tests/Android.bp b/media/libmediatranscoding/transcoder/tests/Android.bp
index d68c967..11b19c9 100644
--- a/media/libmediatranscoding/transcoder/tests/Android.bp
+++ b/media/libmediatranscoding/transcoder/tests/Android.bp
@@ -89,6 +89,13 @@
srcs: ["MediaSampleWriterTests.cpp"],
}
+// HDR Transcode unit test
+cc_test {
+ name: "HdrTranscodeTests",
+ defaults: ["testdefaults"],
+ srcs: ["HdrTranscodeTests.cpp"],
+}
+
// MediaTranscoder unit test
cc_test {
name: "MediaTranscoderTests",
diff --git a/media/libmediatranscoding/transcoder/tests/HdrTranscodeTests.cpp b/media/libmediatranscoding/transcoder/tests/HdrTranscodeTests.cpp
new file mode 100644
index 0000000..3a2882b
--- /dev/null
+++ b/media/libmediatranscoding/transcoder/tests/HdrTranscodeTests.cpp
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2021 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 HDR to SDR transcoding.
+
+// #define LOG_NDEBUG 0
+#define LOG_TAG "HdrTranscodeTests"
+
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android/binder_process.h>
+#include <fcntl.h>
+#include <gtest/gtest.h>
+#include <media/MediaSampleReaderNDK.h>
+#include <media/MediaTranscoder.h>
+#include <media/NdkCommon.h>
+
+#include "TranscoderTestUtils.h"
+
+namespace android {
+
+// Debug property to load the sample HDR plugin.
+static const std::string kLoadSamplePluginProperty{"debug.codec2.force-sample-plugin"};
+
+// SDR color standard, from MediaFormat.
+static constexpr int COLOR_STANDARD_BT709 = 1;
+
+class HdrTranscodeTests : public ::testing::Test {
+public:
+ HdrTranscodeTests() { LOG(DEBUG) << "HdrTranscodeTests created"; }
+ ~HdrTranscodeTests() { LOG(DEBUG) << "HdrTranscodeTests destroyed"; }
+
+ void SetUp() override {
+ LOG(DEBUG) << "HdrTranscodeTests set up";
+ mCallbacks = std::make_shared<TestTranscoderCallbacks>();
+ ABinderProcess_startThreadPool();
+ }
+
+ void TearDown() override {
+ LOG(DEBUG) << "HdrTranscodeTests tear down";
+ mCallbacks.reset();
+ }
+
+ media_status_t transcode(const char* srcFile, const char* dstFile, const char* dstMime) {
+ std::string srcPath = mSrcDir + srcFile;
+ std::string dstPath = mDstDir + dstFile;
+
+ auto transcoder = MediaTranscoder::create(mCallbacks, -1 /*heartBeatIntervalUs*/);
+ EXPECT_NE(transcoder, nullptr);
+
+ const int srcFd = open(srcPath.c_str(), O_RDONLY);
+ EXPECT_EQ(transcoder->configureSource(srcFd), AMEDIA_OK);
+ close(srcFd);
+
+ std::vector<std::shared_ptr<AMediaFormat>> trackFormats = transcoder->getTrackFormats();
+ EXPECT_GT(trackFormats.size(), 0);
+
+ for (int i = 0; i < trackFormats.size(); ++i) {
+ std::shared_ptr<AMediaFormat> format;
+ const char* mime = nullptr;
+
+ AMediaFormat_getString(trackFormats[i].get(), AMEDIAFORMAT_KEY_MIME, &mime);
+ if (strncmp(mime, "video/", 6) == 0) {
+ format = std::shared_ptr<AMediaFormat>(AMediaFormat_new(), &AMediaFormat_delete);
+ AMediaFormat_setString(format.get(), AMEDIAFORMAT_KEY_MIME, dstMime);
+ }
+
+ media_status_t status = transcoder->configureTrackFormat(i, format.get());
+ if (status != AMEDIA_OK) {
+ return status;
+ }
+ }
+
+ const int dstFd = open(dstPath.c_str(), O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
+ EXPECT_EQ(transcoder->configureDestination(dstFd), AMEDIA_OK);
+ close(dstFd);
+
+ media_status_t startStatus = transcoder->start();
+ EXPECT_EQ(startStatus, AMEDIA_OK);
+ if (startStatus != AMEDIA_OK) {
+ return startStatus;
+ }
+
+ mCallbacks->waitForTranscodingFinished();
+ return mCallbacks->mStatus;
+ }
+
+ media_status_t validateOutput(const char* dstFile __unused) {
+ std::string path = mDstDir + dstFile;
+
+ auto format = TranscoderTestUtils::GetVideoFormat(path);
+ EXPECT_NE(format.get(), nullptr);
+
+ int32_t value;
+ EXPECT_TRUE(AMediaFormat_getInt32(format.get(), AMEDIAFORMAT_KEY_COLOR_STANDARD, &value));
+ EXPECT_EQ(value, COLOR_STANDARD_BT709);
+
+ EXPECT_TRUE(AMediaFormat_getInt32(format.get(), AMEDIAFORMAT_KEY_COLOR_TRANSFER, &value));
+ EXPECT_EQ(value, COLOR_TRANSFER_SDR_VIDEO);
+
+ // TODO(lnilsson): Validate decoded pixels as well. Either by comparing similarity against a
+ // known good "golden master" corresponding SDR video, or by looking at the histogram.
+ return AMEDIA_OK;
+ }
+
+ bool hdrToSdrConversionSupported(const char* hdrFile) {
+ std::string srcPath = mSrcDir + hdrFile;
+
+ std::string mime;
+ auto format = TranscoderTestUtils::GetVideoFormat(srcPath, &mime);
+ EXPECT_NE(format.get(), nullptr);
+
+ AMediaCodec* decoder = AMediaCodec_createDecoderByType(mime.c_str());
+ EXPECT_NE(decoder, nullptr);
+
+ AMediaFormat_setInt32(format.get(), TBD_AMEDIACODEC_PARAMETER_KEY_COLOR_TRANSFER_REQUEST,
+ COLOR_TRANSFER_SDR_VIDEO);
+
+ EXPECT_EQ(AMediaCodec_configure(decoder, format.get(), nullptr /*surface*/,
+ nullptr /*crypto*/, 0 /*flags*/),
+ AMEDIA_OK);
+
+ AMediaFormat* inputFormat = AMediaCodec_getInputFormat(decoder);
+ EXPECT_NE(inputFormat, nullptr);
+
+ int32_t transferFunc;
+ bool conversionSupported =
+ AMediaFormat_getInt32(inputFormat,
+ TBD_AMEDIACODEC_PARAMETER_KEY_COLOR_TRANSFER_REQUEST,
+ &transferFunc) &&
+ transferFunc == COLOR_TRANSFER_SDR_VIDEO;
+
+ AMediaFormat_delete(inputFormat);
+ AMediaCodec_delete(decoder);
+
+ return conversionSupported;
+ }
+
+ std::shared_ptr<TestTranscoderCallbacks> mCallbacks;
+ const std::string mSrcDir{"/data/local/tmp/TranscodingTestAssets/"};
+ const std::string mDstDir{"/data/local/tmp/"};
+};
+
+TEST_F(HdrTranscodeTests, TestHdrSamplePluginTranscode) {
+ const char* hdrFile = "video_1280x720_hevc_hdr10_static_3mbps.mp4";
+ const char* dstFile = "video_1280x720_hevc_hdr10_static_3mbps_transcoded.mp4";
+
+ EXPECT_TRUE(android::base::SetProperty(kLoadSamplePluginProperty, "true"));
+
+ if (hdrToSdrConversionSupported(hdrFile)) {
+ LOG(INFO) << "HDR -> SDR supported, validating output..";
+ EXPECT_EQ(transcode(hdrFile, dstFile, AMEDIA_MIMETYPE_VIDEO_AVC), AMEDIA_OK);
+ EXPECT_EQ(validateOutput(dstFile), AMEDIA_OK);
+ } else {
+ LOG(INFO) << "HDR -> SDR *not* supported";
+ EXPECT_EQ(transcode(hdrFile, dstFile, AMEDIA_MIMETYPE_VIDEO_AVC), AMEDIA_ERROR_UNSUPPORTED);
+ }
+
+ EXPECT_TRUE(android::base::SetProperty(kLoadSamplePluginProperty, "false"));
+}
+} // namespace android
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/media/libmediatranscoding/transcoder/tests/MediaTrackTranscoderTests.cpp b/media/libmediatranscoding/transcoder/tests/MediaTrackTranscoderTests.cpp
index 21f0b86..791e983 100644
--- a/media/libmediatranscoding/transcoder/tests/MediaTrackTranscoderTests.cpp
+++ b/media/libmediatranscoding/transcoder/tests/MediaTrackTranscoderTests.cpp
@@ -28,7 +28,7 @@
#include <media/PassthroughTrackTranscoder.h>
#include <media/VideoTrackTranscoder.h>
-#include "TrackTranscoderTestUtils.h"
+#include "TranscoderTestUtils.h"
namespace android {
@@ -49,7 +49,7 @@
// (b/155663561).
ABinderProcess_startThreadPool();
- mCallback = std::make_shared<TestCallback>();
+ mCallback = std::make_shared<TestTrackTranscoderCallback>();
switch (GetParam()) {
case VIDEO:
@@ -134,7 +134,7 @@
protected:
std::shared_ptr<MediaTrackTranscoder> mTranscoder;
- std::shared_ptr<TestCallback> mCallback;
+ std::shared_ptr<TestTrackTranscoderCallback> mCallback;
std::shared_ptr<MediaSampleReader> mMediaSampleReader;
int mTrackIndex;
diff --git a/media/libmediatranscoding/transcoder/tests/MediaTranscoderTests.cpp b/media/libmediatranscoding/transcoder/tests/MediaTranscoderTests.cpp
index 4e33ec3..b7c7bd8 100644
--- a/media/libmediatranscoding/transcoder/tests/MediaTranscoderTests.cpp
+++ b/media/libmediatranscoding/transcoder/tests/MediaTranscoderTests.cpp
@@ -27,6 +27,8 @@
#include <media/MediaTranscoder.h>
#include <media/NdkCommon.h>
+#include "TranscoderTestUtils.h"
+
namespace android {
#define DEFINE_FORMAT_VALUE_EQUAL_FUNC(_type, _typeName) \
@@ -53,66 +55,6 @@
{AMEDIAFORMAT_KEY_SAR_HEIGHT, equalInt32}, {AMEDIAFORMAT_KEY_ROTATION, equalInt32},
};
-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) override {
- std::unique_lock<std::mutex> lock(mMutex);
- if (progress > 0 && !mProgressMade) {
- mProgressMade = true;
- mCondition.notify_all();
- }
- }
-
- virtual void onHeartBeat(const MediaTranscoder* transcoder __unused) override {
- std::unique_lock<std::mutex> lock(mMutex);
- mHeartBeatCount++;
- }
-
- virtual void onCodecResourceLost(const MediaTranscoder* transcoder __unused,
- const std::shared_ptr<ndk::ScopedAParcel>& pausedState
- __unused) override {}
-
- void waitForTranscodingFinished() {
- std::unique_lock<std::mutex> lock(mMutex);
- while (!mFinished) {
- mCondition.wait(lock);
- }
- }
-
- void waitForProgressMade() {
- std::unique_lock<std::mutex> lock(mMutex);
- while (!mProgressMade && !mFinished) {
- mCondition.wait(lock);
- }
- }
- media_status_t mStatus = AMEDIA_OK;
- bool mFinished = false;
- int32_t mHeartBeatCount = 0;
-
-private:
- std::mutex mMutex;
- std::condition_variable mCondition;
- bool mProgressMade = false;
-};
-
// Write-only, create file if non-existent, don't overwrite existing file.
static constexpr int kOpenFlags = O_WRONLY | O_CREAT | O_EXCL;
// User R+W permission.
@@ -125,7 +67,7 @@
void SetUp() override {
LOG(DEBUG) << "MediaTranscoderTests set up";
- mCallbacks = std::make_shared<TestCallbacks>();
+ mCallbacks = std::make_shared<TestTranscoderCallbacks>();
ABinderProcess_startThreadPool();
}
@@ -325,7 +267,7 @@
close(dstFd);
}
- std::shared_ptr<TestCallbacks> mCallbacks;
+ std::shared_ptr<TestTranscoderCallbacks> mCallbacks;
std::shared_ptr<AMediaFormat> mSourceVideoFormat;
};
@@ -380,7 +322,7 @@
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>();
+ mCallbacks = std::make_shared<TestTranscoderCallbacks>();
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
@@ -410,7 +352,7 @@
EXPECT_EQ(transcodeHelper(srcPath, destPath, getAVCVideoFormat, kCancelAfterProgress),
AMEDIA_OK);
EXPECT_FALSE(mCallbacks->mFinished);
- mCallbacks = std::make_shared<TestCallbacks>();
+ mCallbacks = std::make_shared<TestTranscoderCallbacks>();
}
}
@@ -422,7 +364,7 @@
EXPECT_EQ(transcodeHelper(srcPath, destPath, getAVCVideoFormat, kCancelAfterStart),
AMEDIA_OK);
EXPECT_FALSE(mCallbacks->mFinished);
- mCallbacks = std::make_shared<TestCallbacks>();
+ mCallbacks = std::make_shared<TestTranscoderCallbacks>();
}
}
@@ -434,7 +376,7 @@
EXPECT_EQ(transcodeHelper(srcPath, destPath, getAVCVideoFormat, kPauseAfterProgress),
AMEDIA_OK);
EXPECT_FALSE(mCallbacks->mFinished);
- mCallbacks = std::make_shared<TestCallbacks>();
+ mCallbacks = std::make_shared<TestTranscoderCallbacks>();
}
}
@@ -446,7 +388,7 @@
EXPECT_EQ(transcodeHelper(srcPath, destPath, getAVCVideoFormat, kPauseAfterStart),
AMEDIA_OK);
EXPECT_FALSE(mCallbacks->mFinished);
- mCallbacks = std::make_shared<TestCallbacks>();
+ mCallbacks = std::make_shared<TestTranscoderCallbacks>();
}
}
diff --git a/media/libmediatranscoding/transcoder/tests/PassthroughTrackTranscoderTests.cpp b/media/libmediatranscoding/transcoder/tests/PassthroughTrackTranscoderTests.cpp
index 5071efd..fdbf535 100644
--- a/media/libmediatranscoding/transcoder/tests/PassthroughTrackTranscoderTests.cpp
+++ b/media/libmediatranscoding/transcoder/tests/PassthroughTrackTranscoderTests.cpp
@@ -29,7 +29,7 @@
#include <vector>
-#include "TrackTranscoderTestUtils.h"
+#include "TranscoderTestUtils.h"
namespace android {
@@ -152,7 +152,7 @@
}
// Create and start the transcoder.
- std::shared_ptr<TestCallback> callback = std::make_shared<TestCallback>();
+ auto callback = std::make_shared<TestTrackTranscoderCallback>();
PassthroughTrackTranscoder transcoder{callback};
std::shared_ptr<MediaSampleReader> mediaSampleReader =
diff --git a/media/libmediatranscoding/transcoder/tests/TrackTranscoderTestUtils.h b/media/libmediatranscoding/transcoder/tests/TrackTranscoderTestUtils.h
deleted file mode 100644
index a782f71..0000000
--- a/media/libmediatranscoding/transcoder/tests/TrackTranscoderTestUtils.h
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * 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.
- */
-
-#include <media/MediaTrackTranscoder.h>
-#include <media/MediaTrackTranscoderCallback.h>
-
-#include <condition_variable>
-#include <memory>
-#include <mutex>
-
-namespace android {
-
-//
-// This file contains test utilities used by more than one track transcoder test.
-//
-
-class TrackTranscoderTestUtils {
-public:
- static std::shared_ptr<AMediaFormat> getDefaultVideoDestinationFormat(
- AMediaFormat* sourceFormat, bool includeBitrate = true) {
- // Default video destination format setup.
- static constexpr float kFrameRate = 30.0f;
- static constexpr int32_t kBitRate = 2 * 1000 * 1000;
-
- AMediaFormat* destinationFormat = AMediaFormat_new();
- AMediaFormat_copy(destinationFormat, sourceFormat);
- AMediaFormat_setFloat(destinationFormat, AMEDIAFORMAT_KEY_FRAME_RATE, kFrameRate);
- if (includeBitrate) {
- AMediaFormat_setInt32(destinationFormat, AMEDIAFORMAT_KEY_BIT_RATE, kBitRate);
- }
-
- return std::shared_ptr<AMediaFormat>(destinationFormat, &AMediaFormat_delete);
- }
-};
-
-class TestCallback : public MediaTrackTranscoderCallback {
-public:
- TestCallback() = default;
- ~TestCallback() = default;
-
- // MediaTrackTranscoderCallback
- 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;
- mTranscodingFinishedCondition.notify_all();
- }
-
- virtual void onTrackStopped(const MediaTrackTranscoder* transcoder __unused) override {
- std::unique_lock<std::mutex> lock(mMutex);
- mTranscodingFinished = true;
- mTranscodingStopped = true;
- mTranscodingFinishedCondition.notify_all();
- }
-
- void onTrackError(const MediaTrackTranscoder* transcoder __unused, media_status_t status) {
- std::unique_lock<std::mutex> lock(mMutex);
- mTranscodingFinished = true;
- mStatus = status;
- mTranscodingFinishedCondition.notify_all();
- }
- // ~MediaTrackTranscoderCallback
-
- media_status_t waitUntilFinished() {
- std::unique_lock<std::mutex> lock(mMutex);
- while (!mTranscodingFinished) {
- mTranscodingFinishedCondition.wait(lock);
- }
- return mStatus;
- }
-
- void waitUntilTrackFormatAvailable() {
- std::unique_lock<std::mutex> lock(mMutex);
- while (!mTrackFormatAvailable) {
- mTrackFormatAvailableCondition.wait(lock);
- }
- }
-
- bool transcodingWasStopped() const { return mTranscodingFinished && mTranscodingStopped; }
- bool transcodingFinished() const {
- return mTranscodingFinished && !mTranscodingStopped && mStatus == AMEDIA_OK;
- }
-
-private:
- media_status_t mStatus = AMEDIA_OK;
- std::mutex mMutex;
- std::condition_variable mTranscodingFinishedCondition;
- std::condition_variable mTrackFormatAvailableCondition;
- bool mTranscodingFinished = false;
- bool mTranscodingStopped = false;
- bool mTrackFormatAvailable = false;
-};
-
-class OneShotSemaphore {
-public:
- void wait() {
- std::unique_lock<std::mutex> lock(mMutex);
- while (!mSignaled) {
- mCondition.wait(lock);
- }
- }
-
- void signal() {
- std::unique_lock<std::mutex> lock(mMutex);
- mSignaled = true;
- mCondition.notify_all();
- }
-
-private:
- std::mutex mMutex;
- std::condition_variable mCondition;
- bool mSignaled = false;
-};
-
-}; // namespace android
diff --git a/media/libmediatranscoding/transcoder/tests/TranscoderTestUtils.h b/media/libmediatranscoding/transcoder/tests/TranscoderTestUtils.h
new file mode 100644
index 0000000..35fe25b
--- /dev/null
+++ b/media/libmediatranscoding/transcoder/tests/TranscoderTestUtils.h
@@ -0,0 +1,225 @@
+/*
+ * 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.
+ */
+
+#include <media/MediaTrackTranscoder.h>
+#include <media/MediaTrackTranscoderCallback.h>
+#include <media/MediaTranscoder.h>
+
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+
+namespace android {
+
+//
+// This file contains transcoding test utilities.
+//
+
+namespace TranscoderTestUtils {
+
+std::shared_ptr<AMediaFormat> GetVideoFormat(const std::string& path,
+ std::string* mimeOut = nullptr) {
+ int fd = open(path.c_str(), O_RDONLY);
+ EXPECT_GT(fd, 0);
+ ssize_t fileSize = lseek(fd, 0, SEEK_END);
+ lseek(fd, 0, SEEK_SET);
+
+ auto sampleReader = MediaSampleReaderNDK::createFromFd(fd, 0, fileSize);
+ EXPECT_NE(sampleReader, nullptr);
+
+ for (size_t i = 0; i < sampleReader->getTrackCount(); ++i) {
+ AMediaFormat* format = sampleReader->getTrackFormat(i);
+
+ const char* mime = nullptr;
+ AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime);
+ if (strncmp(mime, "video/", 6) == 0) {
+ if (mimeOut != nullptr) {
+ mimeOut->assign(mime);
+ }
+ return std::shared_ptr<AMediaFormat>(format, &AMediaFormat_delete);
+ }
+
+ AMediaFormat_delete(format);
+ }
+ return nullptr;
+}
+
+}; // namespace TranscoderTestUtils
+
+class TrackTranscoderTestUtils {
+public:
+ static std::shared_ptr<AMediaFormat> getDefaultVideoDestinationFormat(
+ AMediaFormat* sourceFormat, bool includeBitrate = true) {
+ // Default video destination format setup.
+ static constexpr float kFrameRate = 30.0f;
+ static constexpr int32_t kBitRate = 2 * 1000 * 1000;
+
+ AMediaFormat* destinationFormat = AMediaFormat_new();
+ AMediaFormat_copy(destinationFormat, sourceFormat);
+ AMediaFormat_setFloat(destinationFormat, AMEDIAFORMAT_KEY_FRAME_RATE, kFrameRate);
+ if (includeBitrate) {
+ AMediaFormat_setInt32(destinationFormat, AMEDIAFORMAT_KEY_BIT_RATE, kBitRate);
+ }
+
+ return std::shared_ptr<AMediaFormat>(destinationFormat, &AMediaFormat_delete);
+ }
+};
+
+class TestTrackTranscoderCallback : public MediaTrackTranscoderCallback {
+public:
+ TestTrackTranscoderCallback() = default;
+ ~TestTrackTranscoderCallback() = default;
+
+ // MediaTrackTranscoderCallback
+ 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;
+ mTranscodingFinishedCondition.notify_all();
+ }
+
+ virtual void onTrackStopped(const MediaTrackTranscoder* transcoder __unused) override {
+ std::unique_lock<std::mutex> lock(mMutex);
+ mTranscodingFinished = true;
+ mTranscodingStopped = true;
+ mTranscodingFinishedCondition.notify_all();
+ }
+
+ void onTrackError(const MediaTrackTranscoder* transcoder __unused, media_status_t status) {
+ std::unique_lock<std::mutex> lock(mMutex);
+ mTranscodingFinished = true;
+ mStatus = status;
+ mTranscodingFinishedCondition.notify_all();
+ }
+ // ~MediaTrackTranscoderCallback
+
+ media_status_t waitUntilFinished() {
+ std::unique_lock<std::mutex> lock(mMutex);
+ while (!mTranscodingFinished) {
+ mTranscodingFinishedCondition.wait(lock);
+ }
+ return mStatus;
+ }
+
+ void waitUntilTrackFormatAvailable() {
+ std::unique_lock<std::mutex> lock(mMutex);
+ while (!mTrackFormatAvailable) {
+ mTrackFormatAvailableCondition.wait(lock);
+ }
+ }
+
+ bool transcodingWasStopped() const { return mTranscodingFinished && mTranscodingStopped; }
+ bool transcodingFinished() const {
+ return mTranscodingFinished && !mTranscodingStopped && mStatus == AMEDIA_OK;
+ }
+
+private:
+ media_status_t mStatus = AMEDIA_OK;
+ std::mutex mMutex;
+ std::condition_variable mTranscodingFinishedCondition;
+ std::condition_variable mTrackFormatAvailableCondition;
+ bool mTranscodingFinished = false;
+ bool mTranscodingStopped = false;
+ bool mTrackFormatAvailable = false;
+};
+
+class TestTranscoderCallbacks : 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) override {
+ std::unique_lock<std::mutex> lock(mMutex);
+ if (progress > 0 && !mProgressMade) {
+ mProgressMade = true;
+ mCondition.notify_all();
+ }
+ }
+
+ virtual void onHeartBeat(const MediaTranscoder* transcoder __unused) override {
+ std::unique_lock<std::mutex> lock(mMutex);
+ mHeartBeatCount++;
+ }
+
+ virtual void onCodecResourceLost(const MediaTranscoder* transcoder __unused,
+ const std::shared_ptr<ndk::ScopedAParcel>& pausedState
+ __unused) override {}
+
+ void waitForTranscodingFinished() {
+ std::unique_lock<std::mutex> lock(mMutex);
+ while (!mFinished) {
+ mCondition.wait(lock);
+ }
+ }
+
+ void waitForProgressMade() {
+ std::unique_lock<std::mutex> lock(mMutex);
+ while (!mProgressMade && !mFinished) {
+ mCondition.wait(lock);
+ }
+ }
+ media_status_t mStatus = AMEDIA_OK;
+ bool mFinished = false;
+ int32_t mHeartBeatCount = 0;
+
+private:
+ std::mutex mMutex;
+ std::condition_variable mCondition;
+ bool mProgressMade = false;
+};
+
+class OneShotSemaphore {
+public:
+ void wait() {
+ std::unique_lock<std::mutex> lock(mMutex);
+ while (!mSignaled) {
+ mCondition.wait(lock);
+ }
+ }
+
+ void signal() {
+ std::unique_lock<std::mutex> lock(mMutex);
+ mSignaled = true;
+ mCondition.notify_all();
+ }
+
+private:
+ std::mutex mMutex;
+ std::condition_variable mCondition;
+ bool mSignaled = false;
+};
+
+}; // namespace android
diff --git a/media/libmediatranscoding/transcoder/tests/VideoTrackTranscoderTests.cpp b/media/libmediatranscoding/transcoder/tests/VideoTrackTranscoderTests.cpp
index 4ede97f..1f9ec77 100644
--- a/media/libmediatranscoding/transcoder/tests/VideoTrackTranscoderTests.cpp
+++ b/media/libmediatranscoding/transcoder/tests/VideoTrackTranscoderTests.cpp
@@ -27,7 +27,7 @@
#include <media/VideoTrackTranscoder.h>
#include <utils/Timers.h>
-#include "TrackTranscoderTestUtils.h"
+#include "TranscoderTestUtils.h"
namespace android {
@@ -94,7 +94,7 @@
TEST_F(VideoTrackTranscoderTests, SampleSoundness) {
LOG(DEBUG) << "Testing SampleSoundness";
- std::shared_ptr<TestCallback> callback = std::make_shared<TestCallback>();
+ auto callback = std::make_shared<TestTrackTranscoderCallback>();
auto transcoder = VideoTrackTranscoder::create(callback);
EXPECT_EQ(mMediaSampleReader->selectTrack(mTrackIndex), AMEDIA_OK);
@@ -139,7 +139,7 @@
TEST_F(VideoTrackTranscoderTests, PreserveBitrate) {
LOG(DEBUG) << "Testing PreserveBitrate";
- std::shared_ptr<TestCallback> callback = std::make_shared<TestCallback>();
+ auto callback = std::make_shared<TestTrackTranscoderCallback>();
std::shared_ptr<MediaTrackTranscoder> transcoder = VideoTrackTranscoder::create(callback);
auto destFormat = TrackTranscoderTestUtils::getDefaultVideoDestinationFormat(
@@ -171,7 +171,7 @@
// VideoTrackTranscoder needs a valid destination format.
TEST_F(VideoTrackTranscoderTests, NullDestinationFormat) {
LOG(DEBUG) << "Testing NullDestinationFormat";
- std::shared_ptr<TestCallback> callback = std::make_shared<TestCallback>();
+ auto callback = std::make_shared<TestTrackTranscoderCallback>();
std::shared_ptr<AMediaFormat> nullFormat;
auto transcoder = VideoTrackTranscoder::create(callback);
@@ -181,7 +181,7 @@
TEST_F(VideoTrackTranscoderTests, LingeringEncoder) {
OneShotSemaphore semaphore;
- auto callback = std::make_shared<TestCallback>();
+ auto callback = std::make_shared<TestTrackTranscoderCallback>();
auto transcoder = VideoTrackTranscoder::create(callback);
EXPECT_EQ(mMediaSampleReader->selectTrack(mTrackIndex), AMEDIA_OK);