blob: a46c2bdb3f092e8ca12a1b4e528e97958de26f00 [file] [log] [blame]
Linus Nilsson0da327a2020-01-31 16:22:18 -08001/*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17// Unit Test for MediaTrackTranscoder
18
19// #define LOG_NDEBUG 0
20#define LOG_TAG "MediaTrackTranscoderTests"
21
22#include <android-base/logging.h>
Linus Nilssonc6221db2020-03-18 14:46:22 -070023#include <android/binder_process.h>
Linus Nilsson0da327a2020-01-31 16:22:18 -080024#include <fcntl.h>
25#include <gtest/gtest.h>
26#include <media/MediaSampleReaderNDK.h>
27#include <media/MediaTrackTranscoder.h>
Linus Nilssonc6221db2020-03-18 14:46:22 -070028#include <media/PassthroughTrackTranscoder.h>
Linus Nilsson0da327a2020-01-31 16:22:18 -080029#include <media/VideoTrackTranscoder.h>
30
31#include "TrackTranscoderTestUtils.h"
32
33namespace android {
34
35/** TrackTranscoder types to test. */
36enum TrackTranscoderType {
37 VIDEO,
Linus Nilssonc6221db2020-03-18 14:46:22 -070038 PASSTHROUGH,
Linus Nilsson0da327a2020-01-31 16:22:18 -080039};
40
41class MediaTrackTranscoderTests : public ::testing::TestWithParam<TrackTranscoderType> {
42public:
43 MediaTrackTranscoderTests() { LOG(DEBUG) << "MediaTrackTranscoderTests created"; }
44
45 void SetUp() override {
46 LOG(DEBUG) << "MediaTrackTranscoderTests set up";
47
Linus Nilssonc6221db2020-03-18 14:46:22 -070048 // Need to start a thread pool to prevent AMediaExtractor binder calls from starving
49 // (b/155663561).
50 ABinderProcess_startThreadPool();
51
Linus Nilsson0da327a2020-01-31 16:22:18 -080052 mCallback = std::make_shared<TestCallback>();
53
54 switch (GetParam()) {
55 case VIDEO:
Linus Nilssone4716f22020-07-10 16:07:57 -070056 mTranscoder = VideoTrackTranscoder::create(mCallback);
Linus Nilssonc6221db2020-03-18 14:46:22 -070057 break;
58 case PASSTHROUGH:
59 mTranscoder = std::make_shared<PassthroughTrackTranscoder>(mCallback);
Linus Nilsson0da327a2020-01-31 16:22:18 -080060 break;
61 }
62 ASSERT_NE(mTranscoder, nullptr);
Linus Nilssoncab39d82020-05-14 16:32:21 -070063 mTranscoderOutputQueue = mTranscoder->getOutputQueue();
Linus Nilsson0da327a2020-01-31 16:22:18 -080064
65 initSampleReader();
66 }
67
68 void initSampleReader() {
69 const char* sourcePath =
Chong Zhangd6e4aec2020-06-22 14:13:07 -070070 "/data/local/tmp/TranscodingTestAssets/cubicle_avc_480x240_aac_24KHz.mp4";
Linus Nilsson0da327a2020-01-31 16:22:18 -080071
72 const int sourceFd = open(sourcePath, O_RDONLY);
73 ASSERT_GT(sourceFd, 0);
74
75 const size_t fileSize = lseek(sourceFd, 0, SEEK_END);
76 lseek(sourceFd, 0, SEEK_SET);
77
78 mMediaSampleReader = MediaSampleReaderNDK::createFromFd(sourceFd, 0 /* offset */, fileSize);
79 ASSERT_NE(mMediaSampleReader, nullptr);
80 close(sourceFd);
81
82 for (size_t trackIndex = 0; trackIndex < mMediaSampleReader->getTrackCount();
83 ++trackIndex) {
84 AMediaFormat* trackFormat = mMediaSampleReader->getTrackFormat(trackIndex);
85 ASSERT_NE(trackFormat, nullptr);
86
87 const char* mime = nullptr;
88 AMediaFormat_getString(trackFormat, AMEDIAFORMAT_KEY_MIME, &mime);
89 ASSERT_NE(mime, nullptr);
90
91 if (GetParam() == VIDEO && strncmp(mime, "video/", 6) == 0) {
92 mTrackIndex = trackIndex;
93
Linus Nilsson800793f2020-07-31 16:16:38 -070094 mSourceFormat = std::shared_ptr<AMediaFormat>(trackFormat, &AMediaFormat_delete);
Linus Nilsson0da327a2020-01-31 16:22:18 -080095 ASSERT_NE(mSourceFormat, nullptr);
96
97 mDestinationFormat =
98 TrackTranscoderTestUtils::getDefaultVideoDestinationFormat(trackFormat);
99 ASSERT_NE(mDestinationFormat, nullptr);
100 break;
Linus Nilssonc6221db2020-03-18 14:46:22 -0700101 } else if (GetParam() == PASSTHROUGH && strncmp(mime, "audio/", 6) == 0) {
102 // TODO(lnilsson): Test metadata track passthrough after hkuang@ provides sample.
103 mTrackIndex = trackIndex;
104
Linus Nilsson800793f2020-07-31 16:16:38 -0700105 mSourceFormat = std::shared_ptr<AMediaFormat>(trackFormat, &AMediaFormat_delete);
Linus Nilssonc6221db2020-03-18 14:46:22 -0700106 ASSERT_NE(mSourceFormat, nullptr);
107 break;
Linus Nilsson0da327a2020-01-31 16:22:18 -0800108 }
109
110 AMediaFormat_delete(trackFormat);
111 }
112
113 ASSERT_NE(mSourceFormat, nullptr);
Linus Nilsson6233fed2020-08-13 15:15:14 -0700114 EXPECT_EQ(mMediaSampleReader->selectTrack(mTrackIndex), AMEDIA_OK);
Linus Nilsson0da327a2020-01-31 16:22:18 -0800115 }
116
117 // Drains the transcoder's output queue in a loop.
118 void drainOutputSampleQueue() {
119 mSampleQueueDrainThread = std::thread{[this] {
120 std::shared_ptr<MediaSample> sample;
121 bool aborted = false;
122 do {
Linus Nilssoncab39d82020-05-14 16:32:21 -0700123 aborted = mTranscoderOutputQueue->dequeue(&sample);
Linus Nilsson0da327a2020-01-31 16:22:18 -0800124 } while (!aborted && !(sample->info.flags & SAMPLE_FLAG_END_OF_STREAM));
125 mQueueWasAborted = aborted;
126 mGotEndOfStream =
127 sample != nullptr && (sample->info.flags & SAMPLE_FLAG_END_OF_STREAM) != 0;
128 }};
129 }
130
131 void joinDrainThread() {
132 if (mSampleQueueDrainThread.joinable()) {
133 mSampleQueueDrainThread.join();
134 }
135 }
136 void TearDown() override {
137 LOG(DEBUG) << "MediaTrackTranscoderTests tear down";
138 joinDrainThread();
139 }
140
141 ~MediaTrackTranscoderTests() { LOG(DEBUG) << "MediaTrackTranscoderTests destroyed"; }
142
143protected:
144 std::shared_ptr<MediaTrackTranscoder> mTranscoder;
Linus Nilssoncab39d82020-05-14 16:32:21 -0700145 std::shared_ptr<MediaSampleQueue> mTranscoderOutputQueue;
Linus Nilsson0da327a2020-01-31 16:22:18 -0800146 std::shared_ptr<TestCallback> mCallback;
147
148 std::shared_ptr<MediaSampleReader> mMediaSampleReader;
149 int mTrackIndex;
150
151 std::shared_ptr<AMediaFormat> mSourceFormat;
152 std::shared_ptr<AMediaFormat> mDestinationFormat;
153
154 std::thread mSampleQueueDrainThread;
155 bool mQueueWasAborted = false;
156 bool mGotEndOfStream = false;
157};
158
159TEST_P(MediaTrackTranscoderTests, WaitNormalOperation) {
160 LOG(DEBUG) << "Testing WaitNormalOperation";
161 EXPECT_EQ(mTranscoder->configure(mMediaSampleReader, mTrackIndex, mDestinationFormat),
162 AMEDIA_OK);
163 ASSERT_TRUE(mTranscoder->start());
164 drainOutputSampleQueue();
165 EXPECT_EQ(mCallback->waitUntilFinished(), AMEDIA_OK);
Linus Nilsson0da327a2020-01-31 16:22:18 -0800166 joinDrainThread();
Linus Nilssone4716f22020-07-10 16:07:57 -0700167 EXPECT_TRUE(mTranscoder->stop());
Linus Nilsson0da327a2020-01-31 16:22:18 -0800168 EXPECT_FALSE(mQueueWasAborted);
169 EXPECT_TRUE(mGotEndOfStream);
170}
171
172TEST_P(MediaTrackTranscoderTests, StopNormalOperation) {
173 LOG(DEBUG) << "Testing StopNormalOperation";
174 EXPECT_EQ(mTranscoder->configure(mMediaSampleReader, mTrackIndex, mDestinationFormat),
175 AMEDIA_OK);
176 EXPECT_TRUE(mTranscoder->start());
177 EXPECT_TRUE(mTranscoder->stop());
178}
179
180TEST_P(MediaTrackTranscoderTests, StartWithoutConfigure) {
181 LOG(DEBUG) << "Testing StartWithoutConfigure";
182 EXPECT_FALSE(mTranscoder->start());
183}
184
185TEST_P(MediaTrackTranscoderTests, StopWithoutStart) {
186 LOG(DEBUG) << "Testing StopWithoutStart";
187 EXPECT_EQ(mTranscoder->configure(mMediaSampleReader, mTrackIndex, mDestinationFormat),
188 AMEDIA_OK);
189 EXPECT_FALSE(mTranscoder->stop());
190}
191
192TEST_P(MediaTrackTranscoderTests, DoubleStartStop) {
193 LOG(DEBUG) << "Testing DoubleStartStop";
194 EXPECT_EQ(mTranscoder->configure(mMediaSampleReader, mTrackIndex, mDestinationFormat),
195 AMEDIA_OK);
196 EXPECT_TRUE(mTranscoder->start());
197 EXPECT_FALSE(mTranscoder->start());
198 EXPECT_TRUE(mTranscoder->stop());
199 EXPECT_FALSE(mTranscoder->stop());
200}
201
202TEST_P(MediaTrackTranscoderTests, DoubleConfigure) {
203 LOG(DEBUG) << "Testing DoubleConfigure";
204 EXPECT_EQ(mTranscoder->configure(mMediaSampleReader, mTrackIndex, mDestinationFormat),
205 AMEDIA_OK);
206 EXPECT_EQ(mTranscoder->configure(mMediaSampleReader, mTrackIndex, mDestinationFormat),
207 AMEDIA_ERROR_UNSUPPORTED);
208}
209
210TEST_P(MediaTrackTranscoderTests, ConfigureAfterFail) {
211 LOG(DEBUG) << "Testing ConfigureAfterFail";
212 EXPECT_EQ(mTranscoder->configure(mMediaSampleReader, -1, mDestinationFormat),
213 AMEDIA_ERROR_INVALID_PARAMETER);
214 EXPECT_EQ(mTranscoder->configure(mMediaSampleReader, mTrackIndex, mDestinationFormat),
215 AMEDIA_OK);
216}
217
218TEST_P(MediaTrackTranscoderTests, RestartAfterStop) {
219 LOG(DEBUG) << "Testing RestartAfterStop";
220 EXPECT_EQ(mTranscoder->configure(mMediaSampleReader, mTrackIndex, mDestinationFormat),
221 AMEDIA_OK);
222 EXPECT_TRUE(mTranscoder->start());
223 EXPECT_TRUE(mTranscoder->stop());
224 EXPECT_FALSE(mTranscoder->start());
225}
226
227TEST_P(MediaTrackTranscoderTests, RestartAfterFinish) {
228 LOG(DEBUG) << "Testing RestartAfterFinish";
229 EXPECT_EQ(mTranscoder->configure(mMediaSampleReader, mTrackIndex, mDestinationFormat),
230 AMEDIA_OK);
231 ASSERT_TRUE(mTranscoder->start());
232 drainOutputSampleQueue();
233 EXPECT_EQ(mCallback->waitUntilFinished(), AMEDIA_OK);
Linus Nilssone4716f22020-07-10 16:07:57 -0700234 joinDrainThread();
Linus Nilsson0da327a2020-01-31 16:22:18 -0800235 EXPECT_TRUE(mTranscoder->stop());
236 EXPECT_FALSE(mTranscoder->start());
Linus Nilsson0da327a2020-01-31 16:22:18 -0800237 EXPECT_FALSE(mQueueWasAborted);
238 EXPECT_TRUE(mGotEndOfStream);
239}
240
241TEST_P(MediaTrackTranscoderTests, AbortOutputQueue) {
242 LOG(DEBUG) << "Testing AbortOutputQueue";
243 EXPECT_EQ(mTranscoder->configure(mMediaSampleReader, mTrackIndex, mDestinationFormat),
244 AMEDIA_OK);
245 ASSERT_TRUE(mTranscoder->start());
Linus Nilssoncab39d82020-05-14 16:32:21 -0700246 mTranscoderOutputQueue->abort();
Linus Nilsson0da327a2020-01-31 16:22:18 -0800247 drainOutputSampleQueue();
248 EXPECT_EQ(mCallback->waitUntilFinished(), AMEDIA_ERROR_IO);
Linus Nilsson0da327a2020-01-31 16:22:18 -0800249 joinDrainThread();
Linus Nilssone4716f22020-07-10 16:07:57 -0700250 EXPECT_TRUE(mTranscoder->stop());
Linus Nilsson0da327a2020-01-31 16:22:18 -0800251 EXPECT_TRUE(mQueueWasAborted);
252 EXPECT_FALSE(mGotEndOfStream);
253}
254
Linus Nilssonc6221db2020-03-18 14:46:22 -0700255TEST_P(MediaTrackTranscoderTests, HoldSampleAfterTranscoderRelease) {
256 LOG(DEBUG) << "Testing HoldSampleAfterTranscoderRelease";
257 EXPECT_EQ(mTranscoder->configure(mMediaSampleReader, mTrackIndex, mDestinationFormat),
258 AMEDIA_OK);
259 ASSERT_TRUE(mTranscoder->start());
260
261 std::shared_ptr<MediaSample> sample;
Linus Nilssoncab39d82020-05-14 16:32:21 -0700262 EXPECT_FALSE(mTranscoderOutputQueue->dequeue(&sample));
Linus Nilssonc6221db2020-03-18 14:46:22 -0700263
264 drainOutputSampleQueue();
265 EXPECT_EQ(mCallback->waitUntilFinished(), AMEDIA_OK);
Linus Nilssonc6221db2020-03-18 14:46:22 -0700266 joinDrainThread();
Linus Nilssone4716f22020-07-10 16:07:57 -0700267 EXPECT_TRUE(mTranscoder->stop());
Linus Nilssonc6221db2020-03-18 14:46:22 -0700268 EXPECT_FALSE(mQueueWasAborted);
269 EXPECT_TRUE(mGotEndOfStream);
270
271 mTranscoder.reset();
Linus Nilssoncab39d82020-05-14 16:32:21 -0700272 mTranscoderOutputQueue.reset();
Linus Nilssonc6221db2020-03-18 14:46:22 -0700273 std::this_thread::sleep_for(std::chrono::milliseconds(20));
274 sample.reset();
275}
276
277TEST_P(MediaTrackTranscoderTests, HoldSampleAfterTranscoderStop) {
278 LOG(DEBUG) << "Testing HoldSampleAfterTranscoderStop";
279 EXPECT_EQ(mTranscoder->configure(mMediaSampleReader, mTrackIndex, mDestinationFormat),
280 AMEDIA_OK);
281 ASSERT_TRUE(mTranscoder->start());
282
283 std::shared_ptr<MediaSample> sample;
Linus Nilssoncab39d82020-05-14 16:32:21 -0700284 EXPECT_FALSE(mTranscoderOutputQueue->dequeue(&sample));
Linus Nilssonc6221db2020-03-18 14:46:22 -0700285 EXPECT_TRUE(mTranscoder->stop());
286
287 std::this_thread::sleep_for(std::chrono::milliseconds(20));
288 sample.reset();
289}
290
Linus Nilsson0da327a2020-01-31 16:22:18 -0800291TEST_P(MediaTrackTranscoderTests, NullSampleReader) {
292 LOG(DEBUG) << "Testing NullSampleReader";
293 std::shared_ptr<MediaSampleReader> nullSampleReader;
294 EXPECT_NE(mTranscoder->configure(nullSampleReader, mTrackIndex, mDestinationFormat), AMEDIA_OK);
Linus Nilssonc6221db2020-03-18 14:46:22 -0700295 ASSERT_FALSE(mTranscoder->start());
Linus Nilsson0da327a2020-01-31 16:22:18 -0800296}
297
298TEST_P(MediaTrackTranscoderTests, InvalidTrackIndex) {
299 LOG(DEBUG) << "Testing InvalidTrackIndex";
300 EXPECT_NE(mTranscoder->configure(mMediaSampleReader, -1, mDestinationFormat), AMEDIA_OK);
301 EXPECT_NE(mTranscoder->configure(mMediaSampleReader, mMediaSampleReader->getTrackCount(),
302 mDestinationFormat),
303 AMEDIA_OK);
304}
305
306}; // namespace android
307
308using namespace android;
309
310INSTANTIATE_TEST_SUITE_P(MediaTrackTranscoderTestsAll, MediaTrackTranscoderTests,
Linus Nilssonc6221db2020-03-18 14:46:22 -0700311 ::testing::Values(VIDEO, PASSTHROUGH));
Linus Nilsson0da327a2020-01-31 16:22:18 -0800312
313int main(int argc, char** argv) {
314 ::testing::InitGoogleTest(&argc, argv);
315 return RUN_ALL_TESTS();
316}