Loading media/libstagefright/webm/tests/Android.bp 0 → 100644 +54 −0 Original line number Original line Diff line number Diff line /* * 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. */ cc_test { name: "WebmFrameThreadUnitTest", gtest: true, srcs: [ "WebmFrameThreadUnitTest.cpp", ], include_dirs: [ "frameworks/av/media/libstagefright", ], static_libs: [ "libdatasource", "libstagefright", "libstagefright_webm", "libstagefright_foundation", ], shared_libs: [ "libbinder", "liblog", "libutils", ], cflags: [ "-Werror", "-Wall", ], sanitize: { cfi: true, misc_undefined: [ "unsigned-integer-overflow", "signed-integer-overflow", ], }, } media/libstagefright/webm/tests/README.md 0 → 100644 +26 −0 Original line number Original line Diff line number Diff line ## Media Testing ## --- #### Webm Writer Utility Tests : The Webm Writer Utility Test Suite validates the APIs being used by the WebmWriter. Run the following steps to build the test suite: ``` mmm frameworks/av/media/libstagefright/webm/tests/ ``` The 32-bit binaries will be created in the following path : ${OUT}/data/nativetest/ The 64-bit binaries will be created in the following path : ${OUT}/data/nativetest64/ #### WebmFrameThread To test 64-bit binary push binaries from nativetest64. adb push ${OUT}/data/nativetest64/WebmFrameThreadUnitTest/WebmFrameThreadUnitTest /data/local/tmp/ To test 32-bit binary push binaries from nativetest. adb push ${OUT}/data/nativetest/WebmFrameThreadUnitTest/WebmFrameThreadUnitTest /data/local/tmp/ ``` adb shell /data/local/tmp/WebmFrameThreadUnitTest ``` media/libstagefright/webm/tests/WebmFrameThreadUnitTest.cpp 0 → 100644 +314 −0 Original line number Original line Diff line number Diff line /* * 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. */ //#define LOG_NDEBUG 0 #define LOG_TAG "WebmFrameThreadUnitTest" #include <utils/Log.h> #include <gtest/gtest.h> #include <media/stagefright/MediaAdapter.h> #include <media/stagefright/MediaDefs.h> #include <media/stagefright/MetaData.h> #include <media/stagefright/Utils.h> #include <media/stagefright/foundation/ABuffer.h> #include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/foundation/AMessage.h> #include <media/stagefright/foundation/OpusHeader.h> #include "webm/EbmlUtil.h" #include "webm/WebmConstants.h" #include "webm/WebmFrameThread.h" using namespace android; using namespace webm; static constexpr int32_t kVideoIdx = 0; static constexpr int32_t kAudioIdx = 1; static constexpr int32_t kMaxStreamCount = 2; static constexpr int32_t kCsdSize = 32; static constexpr int32_t kFrameSize = 128; static constexpr int32_t kMaxLoopCount = 20; static constexpr int32_t kNumFramesToWrite = 32; static constexpr int32_t kSyncFrameInterval = 10; static constexpr uint64_t kDefaultTimeCodeScaleUs = 1000000; /* 1sec */ #define OUTPUT_FILE_NAME "/data/local/tmp/webmFrameThreadOutput.webm" // LookUpTable of clips and metadata for component testing static const struct InputData { const char *mime; int32_t firstParam; int32_t secondParam; bool isAudio; } kInputData[] = { {MEDIA_MIMETYPE_AUDIO_OPUS, 48000, 6, true}, {MEDIA_MIMETYPE_AUDIO_VORBIS, 44100, 1, true}, {MEDIA_MIMETYPE_VIDEO_VP9, 176, 144, false}, {MEDIA_MIMETYPE_VIDEO_VP8, 1920, 1080, false}, }; class WebmFrameThreadUnitTest : public ::testing::TestWithParam<std::pair<int32_t, int32_t>> { public: WebmFrameThreadUnitTest() : mSinkThread(nullptr), mAudioThread(nullptr), mVideoThread(nullptr), mSource{} {} ~WebmFrameThreadUnitTest() { if (mSinkThread) mSinkThread.clear(); if (mAudioThread) mAudioThread.clear(); if (mVideoThread) mVideoThread.clear(); } virtual void SetUp() override { mSegmentDataStart = 0; mFd = open(OUTPUT_FILE_NAME, O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR); ASSERT_GE(mFd, 0) << "Failed to open output file " << OUTPUT_FILE_NAME; } virtual void TearDown() override { if (mFd >= 0) close(mFd); for (int32_t idx = 0; idx < kMaxStreamCount; idx++) { if (mSource[idx] != nullptr) { mSource[idx].clear(); } } mVSink.clear(); mASink.clear(); mCuePoints.clear(); } void addTrack(bool isAudio, int32_t index); void writeFileData(int32_t inputFrameId, int32_t range); void createWebmThreads(std::initializer_list<int32_t> indexList); void startWebmFrameThreads(); void stopWebmFrameThreads(); int32_t mFd; uint64_t mSegmentDataStart; sp<WebmFrameSinkThread> mSinkThread; sp<WebmFrameSourceThread> mAudioThread; sp<WebmFrameSourceThread> mVideoThread; List<sp<WebmElement>> mCuePoints; sp<MediaAdapter> mSource[kMaxStreamCount]; LinkedBlockingQueue<const sp<WebmFrame>> mVSink; LinkedBlockingQueue<const sp<WebmFrame>> mASink; }; void writeAudioHeaderData(const sp<AMessage> &format, const char *mimeType) { if (strncasecmp(mimeType, MEDIA_MIMETYPE_AUDIO_OPUS, strlen(MEDIA_MIMETYPE_AUDIO_OPUS) + 1) && strncasecmp(mimeType, MEDIA_MIMETYPE_AUDIO_VORBIS, strlen(MEDIA_MIMETYPE_AUDIO_VORBIS) + 1)) { ASSERT_TRUE(false) << "Unsupported mime type"; } // Dummy CSD buffers for Opus and Vorbis char csdBuffer[kCsdSize]; memset(csdBuffer, 0xFF, sizeof(csdBuffer)); sp<ABuffer> csdBuffer0 = ABuffer::CreateAsCopy((void *)csdBuffer, kCsdSize); ASSERT_NE(csdBuffer0.get(), nullptr) << "Unable to allocate buffer for CSD0 data"; ASSERT_NE(csdBuffer0->base(), nullptr) << "ABuffer base is null for CSD0"; sp<ABuffer> csdBuffer1 = ABuffer::CreateAsCopy((void *)csdBuffer, kCsdSize); ASSERT_NE(csdBuffer1.get(), nullptr) << "Unable to allocate buffer for CSD1 data"; ASSERT_NE(csdBuffer1->base(), nullptr) << "ABuffer base is null for CSD1"; sp<ABuffer> csdBuffer2 = ABuffer::CreateAsCopy((void *)csdBuffer, kCsdSize); ASSERT_NE(csdBuffer2.get(), nullptr) << "Unable to allocate buffer for CSD2 data"; ASSERT_NE(csdBuffer2->base(), nullptr) << "ABuffer base is null for CSD2"; format->setBuffer("csd-0", csdBuffer0); format->setBuffer("csd-1", csdBuffer1); format->setBuffer("csd-2", csdBuffer2); } void WebmFrameThreadUnitTest::addTrack(bool isAudio, int32_t index) { ASSERT_LT(index, sizeof(kInputData) / sizeof(kInputData[0])) << "Invalid index for loopup table"; sp<AMessage> format = new AMessage; format->setString("mime", kInputData[index].mime); if (!isAudio) { format->setInt32("width", kInputData[index].firstParam); format->setInt32("height", kInputData[index].secondParam); } else { format->setInt32("sample-rate", kInputData[index].firstParam); format->setInt32("channel-count", kInputData[index].secondParam); ASSERT_NO_FATAL_FAILURE(writeAudioHeaderData(format, kInputData[index].mime)); } sp<MetaData> trackMeta = new MetaData; convertMessageToMetaData(format, trackMeta); if (!isAudio) { mSource[kVideoIdx] = new MediaAdapter(trackMeta); ASSERT_NE(mSource[kVideoIdx], nullptr) << "Unable to create source"; } else { mSource[kAudioIdx] = new MediaAdapter(trackMeta); ASSERT_NE(mSource[kAudioIdx], nullptr) << "Unable to create source"; } } void WebmFrameThreadUnitTest::createWebmThreads(std::initializer_list<int32_t> indexList) { mSinkThread = new WebmFrameSinkThread(mFd, mSegmentDataStart, mVSink, mASink, mCuePoints); ASSERT_NE(mSinkThread, nullptr) << "Failed to create Sink Thread"; bool isAudio; // MultiTrack input for (int32_t index : indexList) { isAudio = kInputData[index].isAudio; ASSERT_NO_FATAL_FAILURE(addTrack(isAudio, index)); if (!isAudio) { mVideoThread = new WebmFrameMediaSourceThread(mSource[kVideoIdx], kVideoType, mVSink, kDefaultTimeCodeScaleUs, 0, 0, 1, 0); } else { mAudioThread = new WebmFrameMediaSourceThread(mSource[kAudioIdx], kAudioType, mASink, kDefaultTimeCodeScaleUs, 0, 0, 1, 0); } } // To handle single track file if (!mVideoThread) { mVideoThread = new WebmFrameEmptySourceThread(kVideoType, mVSink); } else if (!mAudioThread) { mAudioThread = new WebmFrameEmptySourceThread(kAudioType, mASink); } ASSERT_NE(mVideoThread, nullptr) << "Failed to create Video Thread"; ASSERT_NE(mAudioThread, nullptr) << "Failed to create Audio Thread"; } void WebmFrameThreadUnitTest::startWebmFrameThreads() { status_t status = mAudioThread->start(); ASSERT_EQ(status, AMEDIA_OK) << "Failed to start Audio Thread"; status = mVideoThread->start(); ASSERT_EQ(status, AMEDIA_OK) << "Failed to start Video Thread"; status = mSinkThread->start(); ASSERT_EQ(status, AMEDIA_OK) << "Failed to start Sink Thread"; } void WebmFrameThreadUnitTest::stopWebmFrameThreads() { status_t status = mAudioThread->stop(); ASSERT_EQ(status, AMEDIA_OK) << "Failed to stop Audio Thread"; status = mVideoThread->stop(); ASSERT_EQ(status, AMEDIA_OK) << "Failed to stop Video Thread"; status = mSinkThread->stop(); ASSERT_EQ(status, AMEDIA_OK) << "Failed to stop Sink Thread"; } // Write dummy data to a file void WebmFrameThreadUnitTest::writeFileData(int32_t inputFrameId, int32_t range) { char data[kFrameSize]; memset(data, 0xFF, sizeof(data)); int32_t status = OK; do { // Queue frames for both A/V tracks for (int32_t idx = kVideoIdx; idx < kMaxStreamCount; idx++) { sp<ABuffer> buffer = new ABuffer((void *)data, kFrameSize); ASSERT_NE(buffer.get(), nullptr) << "ABuffer returned nullptr"; // Released in MediaAdapter::signalBufferReturned(). MediaBuffer *mediaBuffer = new MediaBuffer(buffer); ASSERT_NE(mediaBuffer, nullptr) << "MediaBuffer returned nullptr"; mediaBuffer->add_ref(); mediaBuffer->set_range(buffer->offset(), buffer->size()); MetaDataBase &sampleMetaData = mediaBuffer->meta_data(); sampleMetaData.setInt64(kKeyTime, inputFrameId * kDefaultTimeCodeScaleUs); // For audio codecs, treat all frame as sync frame if ((idx == kAudioIdx) || (inputFrameId % kSyncFrameInterval == 0)) { sampleMetaData.setInt32(kKeyIsSyncFrame, true); } // This pushBuffer will wait until the mediaBuffer is consumed. if (mSource[idx] != nullptr) { status = mSource[idx]->pushBuffer(mediaBuffer); } ASSERT_EQ(status, OK); } inputFrameId++; } while (inputFrameId < range); } TEST_P(WebmFrameThreadUnitTest, WriteTest) { int32_t index1 = GetParam().first; int32_t index2 = GetParam().second; ASSERT_NO_FATAL_FAILURE(createWebmThreads({index1, index2})); ASSERT_NO_FATAL_FAILURE(startWebmFrameThreads()); ASSERT_NO_FATAL_FAILURE(writeFileData(0, kNumFramesToWrite)); if (mSource[kAudioIdx]) mSource[kAudioIdx]->stop(); if (mSource[kVideoIdx]) mSource[kVideoIdx]->stop(); ASSERT_NO_FATAL_FAILURE(stopWebmFrameThreads()); } TEST_P(WebmFrameThreadUnitTest, PauseTest) { int32_t index1 = GetParam().first; int32_t index2 = GetParam().second; ASSERT_NO_FATAL_FAILURE(createWebmThreads({index1, index2})); ASSERT_NO_FATAL_FAILURE(startWebmFrameThreads()); int32_t offset = 0; ASSERT_NO_FATAL_FAILURE(writeFileData(offset, kNumFramesToWrite)); offset += kNumFramesToWrite; for (int idx = 0; idx < kMaxLoopCount; idx++) { // pause the threads status_t status = mAudioThread->pause(); ASSERT_EQ(status, AMEDIA_OK) << "Failed to pause Audio Thread"; status = mVideoThread->pause(); ASSERT_EQ(status, AMEDIA_OK) << "Failed to pause Video Thread"; // Under pause state, no write should happen ASSERT_NO_FATAL_FAILURE(writeFileData(offset, kNumFramesToWrite)); offset += kNumFramesToWrite; status = mAudioThread->resume(); ASSERT_EQ(status, AMEDIA_OK) << "Failed to resume Audio Thread"; status = mVideoThread->resume(); ASSERT_EQ(status, AMEDIA_OK) << "Failed to resume Video Thread"; ASSERT_NO_FATAL_FAILURE(writeFileData(offset, kNumFramesToWrite)); offset += kNumFramesToWrite; } if (mSource[kAudioIdx]) mSource[kAudioIdx]->stop(); if (mSource[kVideoIdx]) mSource[kVideoIdx]->stop(); ASSERT_NO_FATAL_FAILURE(stopWebmFrameThreads()); } INSTANTIATE_TEST_SUITE_P(WebmFrameThreadUnitTestAll, WebmFrameThreadUnitTest, ::testing::Values(std::make_pair(0, 1), std::make_pair(0, 2), std::make_pair(0, 3), std::make_pair(1, 0), std::make_pair(1, 2), std::make_pair(1, 3), std::make_pair(2, 3))); int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); int status = RUN_ALL_TESTS(); ALOGV("Test result = %d\n", status); return status; } Loading
media/libstagefright/webm/tests/Android.bp 0 → 100644 +54 −0 Original line number Original line Diff line number Diff line /* * 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. */ cc_test { name: "WebmFrameThreadUnitTest", gtest: true, srcs: [ "WebmFrameThreadUnitTest.cpp", ], include_dirs: [ "frameworks/av/media/libstagefright", ], static_libs: [ "libdatasource", "libstagefright", "libstagefright_webm", "libstagefright_foundation", ], shared_libs: [ "libbinder", "liblog", "libutils", ], cflags: [ "-Werror", "-Wall", ], sanitize: { cfi: true, misc_undefined: [ "unsigned-integer-overflow", "signed-integer-overflow", ], }, }
media/libstagefright/webm/tests/README.md 0 → 100644 +26 −0 Original line number Original line Diff line number Diff line ## Media Testing ## --- #### Webm Writer Utility Tests : The Webm Writer Utility Test Suite validates the APIs being used by the WebmWriter. Run the following steps to build the test suite: ``` mmm frameworks/av/media/libstagefright/webm/tests/ ``` The 32-bit binaries will be created in the following path : ${OUT}/data/nativetest/ The 64-bit binaries will be created in the following path : ${OUT}/data/nativetest64/ #### WebmFrameThread To test 64-bit binary push binaries from nativetest64. adb push ${OUT}/data/nativetest64/WebmFrameThreadUnitTest/WebmFrameThreadUnitTest /data/local/tmp/ To test 32-bit binary push binaries from nativetest. adb push ${OUT}/data/nativetest/WebmFrameThreadUnitTest/WebmFrameThreadUnitTest /data/local/tmp/ ``` adb shell /data/local/tmp/WebmFrameThreadUnitTest ```
media/libstagefright/webm/tests/WebmFrameThreadUnitTest.cpp 0 → 100644 +314 −0 Original line number Original line Diff line number Diff line /* * 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. */ //#define LOG_NDEBUG 0 #define LOG_TAG "WebmFrameThreadUnitTest" #include <utils/Log.h> #include <gtest/gtest.h> #include <media/stagefright/MediaAdapter.h> #include <media/stagefright/MediaDefs.h> #include <media/stagefright/MetaData.h> #include <media/stagefright/Utils.h> #include <media/stagefright/foundation/ABuffer.h> #include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/foundation/AMessage.h> #include <media/stagefright/foundation/OpusHeader.h> #include "webm/EbmlUtil.h" #include "webm/WebmConstants.h" #include "webm/WebmFrameThread.h" using namespace android; using namespace webm; static constexpr int32_t kVideoIdx = 0; static constexpr int32_t kAudioIdx = 1; static constexpr int32_t kMaxStreamCount = 2; static constexpr int32_t kCsdSize = 32; static constexpr int32_t kFrameSize = 128; static constexpr int32_t kMaxLoopCount = 20; static constexpr int32_t kNumFramesToWrite = 32; static constexpr int32_t kSyncFrameInterval = 10; static constexpr uint64_t kDefaultTimeCodeScaleUs = 1000000; /* 1sec */ #define OUTPUT_FILE_NAME "/data/local/tmp/webmFrameThreadOutput.webm" // LookUpTable of clips and metadata for component testing static const struct InputData { const char *mime; int32_t firstParam; int32_t secondParam; bool isAudio; } kInputData[] = { {MEDIA_MIMETYPE_AUDIO_OPUS, 48000, 6, true}, {MEDIA_MIMETYPE_AUDIO_VORBIS, 44100, 1, true}, {MEDIA_MIMETYPE_VIDEO_VP9, 176, 144, false}, {MEDIA_MIMETYPE_VIDEO_VP8, 1920, 1080, false}, }; class WebmFrameThreadUnitTest : public ::testing::TestWithParam<std::pair<int32_t, int32_t>> { public: WebmFrameThreadUnitTest() : mSinkThread(nullptr), mAudioThread(nullptr), mVideoThread(nullptr), mSource{} {} ~WebmFrameThreadUnitTest() { if (mSinkThread) mSinkThread.clear(); if (mAudioThread) mAudioThread.clear(); if (mVideoThread) mVideoThread.clear(); } virtual void SetUp() override { mSegmentDataStart = 0; mFd = open(OUTPUT_FILE_NAME, O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR); ASSERT_GE(mFd, 0) << "Failed to open output file " << OUTPUT_FILE_NAME; } virtual void TearDown() override { if (mFd >= 0) close(mFd); for (int32_t idx = 0; idx < kMaxStreamCount; idx++) { if (mSource[idx] != nullptr) { mSource[idx].clear(); } } mVSink.clear(); mASink.clear(); mCuePoints.clear(); } void addTrack(bool isAudio, int32_t index); void writeFileData(int32_t inputFrameId, int32_t range); void createWebmThreads(std::initializer_list<int32_t> indexList); void startWebmFrameThreads(); void stopWebmFrameThreads(); int32_t mFd; uint64_t mSegmentDataStart; sp<WebmFrameSinkThread> mSinkThread; sp<WebmFrameSourceThread> mAudioThread; sp<WebmFrameSourceThread> mVideoThread; List<sp<WebmElement>> mCuePoints; sp<MediaAdapter> mSource[kMaxStreamCount]; LinkedBlockingQueue<const sp<WebmFrame>> mVSink; LinkedBlockingQueue<const sp<WebmFrame>> mASink; }; void writeAudioHeaderData(const sp<AMessage> &format, const char *mimeType) { if (strncasecmp(mimeType, MEDIA_MIMETYPE_AUDIO_OPUS, strlen(MEDIA_MIMETYPE_AUDIO_OPUS) + 1) && strncasecmp(mimeType, MEDIA_MIMETYPE_AUDIO_VORBIS, strlen(MEDIA_MIMETYPE_AUDIO_VORBIS) + 1)) { ASSERT_TRUE(false) << "Unsupported mime type"; } // Dummy CSD buffers for Opus and Vorbis char csdBuffer[kCsdSize]; memset(csdBuffer, 0xFF, sizeof(csdBuffer)); sp<ABuffer> csdBuffer0 = ABuffer::CreateAsCopy((void *)csdBuffer, kCsdSize); ASSERT_NE(csdBuffer0.get(), nullptr) << "Unable to allocate buffer for CSD0 data"; ASSERT_NE(csdBuffer0->base(), nullptr) << "ABuffer base is null for CSD0"; sp<ABuffer> csdBuffer1 = ABuffer::CreateAsCopy((void *)csdBuffer, kCsdSize); ASSERT_NE(csdBuffer1.get(), nullptr) << "Unable to allocate buffer for CSD1 data"; ASSERT_NE(csdBuffer1->base(), nullptr) << "ABuffer base is null for CSD1"; sp<ABuffer> csdBuffer2 = ABuffer::CreateAsCopy((void *)csdBuffer, kCsdSize); ASSERT_NE(csdBuffer2.get(), nullptr) << "Unable to allocate buffer for CSD2 data"; ASSERT_NE(csdBuffer2->base(), nullptr) << "ABuffer base is null for CSD2"; format->setBuffer("csd-0", csdBuffer0); format->setBuffer("csd-1", csdBuffer1); format->setBuffer("csd-2", csdBuffer2); } void WebmFrameThreadUnitTest::addTrack(bool isAudio, int32_t index) { ASSERT_LT(index, sizeof(kInputData) / sizeof(kInputData[0])) << "Invalid index for loopup table"; sp<AMessage> format = new AMessage; format->setString("mime", kInputData[index].mime); if (!isAudio) { format->setInt32("width", kInputData[index].firstParam); format->setInt32("height", kInputData[index].secondParam); } else { format->setInt32("sample-rate", kInputData[index].firstParam); format->setInt32("channel-count", kInputData[index].secondParam); ASSERT_NO_FATAL_FAILURE(writeAudioHeaderData(format, kInputData[index].mime)); } sp<MetaData> trackMeta = new MetaData; convertMessageToMetaData(format, trackMeta); if (!isAudio) { mSource[kVideoIdx] = new MediaAdapter(trackMeta); ASSERT_NE(mSource[kVideoIdx], nullptr) << "Unable to create source"; } else { mSource[kAudioIdx] = new MediaAdapter(trackMeta); ASSERT_NE(mSource[kAudioIdx], nullptr) << "Unable to create source"; } } void WebmFrameThreadUnitTest::createWebmThreads(std::initializer_list<int32_t> indexList) { mSinkThread = new WebmFrameSinkThread(mFd, mSegmentDataStart, mVSink, mASink, mCuePoints); ASSERT_NE(mSinkThread, nullptr) << "Failed to create Sink Thread"; bool isAudio; // MultiTrack input for (int32_t index : indexList) { isAudio = kInputData[index].isAudio; ASSERT_NO_FATAL_FAILURE(addTrack(isAudio, index)); if (!isAudio) { mVideoThread = new WebmFrameMediaSourceThread(mSource[kVideoIdx], kVideoType, mVSink, kDefaultTimeCodeScaleUs, 0, 0, 1, 0); } else { mAudioThread = new WebmFrameMediaSourceThread(mSource[kAudioIdx], kAudioType, mASink, kDefaultTimeCodeScaleUs, 0, 0, 1, 0); } } // To handle single track file if (!mVideoThread) { mVideoThread = new WebmFrameEmptySourceThread(kVideoType, mVSink); } else if (!mAudioThread) { mAudioThread = new WebmFrameEmptySourceThread(kAudioType, mASink); } ASSERT_NE(mVideoThread, nullptr) << "Failed to create Video Thread"; ASSERT_NE(mAudioThread, nullptr) << "Failed to create Audio Thread"; } void WebmFrameThreadUnitTest::startWebmFrameThreads() { status_t status = mAudioThread->start(); ASSERT_EQ(status, AMEDIA_OK) << "Failed to start Audio Thread"; status = mVideoThread->start(); ASSERT_EQ(status, AMEDIA_OK) << "Failed to start Video Thread"; status = mSinkThread->start(); ASSERT_EQ(status, AMEDIA_OK) << "Failed to start Sink Thread"; } void WebmFrameThreadUnitTest::stopWebmFrameThreads() { status_t status = mAudioThread->stop(); ASSERT_EQ(status, AMEDIA_OK) << "Failed to stop Audio Thread"; status = mVideoThread->stop(); ASSERT_EQ(status, AMEDIA_OK) << "Failed to stop Video Thread"; status = mSinkThread->stop(); ASSERT_EQ(status, AMEDIA_OK) << "Failed to stop Sink Thread"; } // Write dummy data to a file void WebmFrameThreadUnitTest::writeFileData(int32_t inputFrameId, int32_t range) { char data[kFrameSize]; memset(data, 0xFF, sizeof(data)); int32_t status = OK; do { // Queue frames for both A/V tracks for (int32_t idx = kVideoIdx; idx < kMaxStreamCount; idx++) { sp<ABuffer> buffer = new ABuffer((void *)data, kFrameSize); ASSERT_NE(buffer.get(), nullptr) << "ABuffer returned nullptr"; // Released in MediaAdapter::signalBufferReturned(). MediaBuffer *mediaBuffer = new MediaBuffer(buffer); ASSERT_NE(mediaBuffer, nullptr) << "MediaBuffer returned nullptr"; mediaBuffer->add_ref(); mediaBuffer->set_range(buffer->offset(), buffer->size()); MetaDataBase &sampleMetaData = mediaBuffer->meta_data(); sampleMetaData.setInt64(kKeyTime, inputFrameId * kDefaultTimeCodeScaleUs); // For audio codecs, treat all frame as sync frame if ((idx == kAudioIdx) || (inputFrameId % kSyncFrameInterval == 0)) { sampleMetaData.setInt32(kKeyIsSyncFrame, true); } // This pushBuffer will wait until the mediaBuffer is consumed. if (mSource[idx] != nullptr) { status = mSource[idx]->pushBuffer(mediaBuffer); } ASSERT_EQ(status, OK); } inputFrameId++; } while (inputFrameId < range); } TEST_P(WebmFrameThreadUnitTest, WriteTest) { int32_t index1 = GetParam().first; int32_t index2 = GetParam().second; ASSERT_NO_FATAL_FAILURE(createWebmThreads({index1, index2})); ASSERT_NO_FATAL_FAILURE(startWebmFrameThreads()); ASSERT_NO_FATAL_FAILURE(writeFileData(0, kNumFramesToWrite)); if (mSource[kAudioIdx]) mSource[kAudioIdx]->stop(); if (mSource[kVideoIdx]) mSource[kVideoIdx]->stop(); ASSERT_NO_FATAL_FAILURE(stopWebmFrameThreads()); } TEST_P(WebmFrameThreadUnitTest, PauseTest) { int32_t index1 = GetParam().first; int32_t index2 = GetParam().second; ASSERT_NO_FATAL_FAILURE(createWebmThreads({index1, index2})); ASSERT_NO_FATAL_FAILURE(startWebmFrameThreads()); int32_t offset = 0; ASSERT_NO_FATAL_FAILURE(writeFileData(offset, kNumFramesToWrite)); offset += kNumFramesToWrite; for (int idx = 0; idx < kMaxLoopCount; idx++) { // pause the threads status_t status = mAudioThread->pause(); ASSERT_EQ(status, AMEDIA_OK) << "Failed to pause Audio Thread"; status = mVideoThread->pause(); ASSERT_EQ(status, AMEDIA_OK) << "Failed to pause Video Thread"; // Under pause state, no write should happen ASSERT_NO_FATAL_FAILURE(writeFileData(offset, kNumFramesToWrite)); offset += kNumFramesToWrite; status = mAudioThread->resume(); ASSERT_EQ(status, AMEDIA_OK) << "Failed to resume Audio Thread"; status = mVideoThread->resume(); ASSERT_EQ(status, AMEDIA_OK) << "Failed to resume Video Thread"; ASSERT_NO_FATAL_FAILURE(writeFileData(offset, kNumFramesToWrite)); offset += kNumFramesToWrite; } if (mSource[kAudioIdx]) mSource[kAudioIdx]->stop(); if (mSource[kVideoIdx]) mSource[kVideoIdx]->stop(); ASSERT_NO_FATAL_FAILURE(stopWebmFrameThreads()); } INSTANTIATE_TEST_SUITE_P(WebmFrameThreadUnitTestAll, WebmFrameThreadUnitTest, ::testing::Values(std::make_pair(0, 1), std::make_pair(0, 2), std::make_pair(0, 3), std::make_pair(1, 0), std::make_pair(1, 2), std::make_pair(1, 3), std::make_pair(2, 3))); int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); int status = RUN_ALL_TESTS(); ALOGV("Test result = %d\n", status); return status; }