blob: 21f0b86006ccec7411cbe8fb813d9e9ef3c7c50e [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);
63
Linus Nilssonfdb3e332020-09-18 17:11:41 -070064 initSampleReader("/data/local/tmp/TranscodingTestAssets/cubicle_avc_480x240_aac_24KHz.mp4");
Linus Nilsson0da327a2020-01-31 16:22:18 -080065 }
66
Linus Nilssonfdb3e332020-09-18 17:11:41 -070067 void initSampleReader(const char* sourcePath) {
Linus Nilsson0da327a2020-01-31 16:22:18 -080068 const int sourceFd = open(sourcePath, O_RDONLY);
69 ASSERT_GT(sourceFd, 0);
70
71 const size_t fileSize = lseek(sourceFd, 0, SEEK_END);
72 lseek(sourceFd, 0, SEEK_SET);
73
74 mMediaSampleReader = MediaSampleReaderNDK::createFromFd(sourceFd, 0 /* offset */, fileSize);
75 ASSERT_NE(mMediaSampleReader, nullptr);
76 close(sourceFd);
77
78 for (size_t trackIndex = 0; trackIndex < mMediaSampleReader->getTrackCount();
79 ++trackIndex) {
80 AMediaFormat* trackFormat = mMediaSampleReader->getTrackFormat(trackIndex);
81 ASSERT_NE(trackFormat, nullptr);
82
83 const char* mime = nullptr;
84 AMediaFormat_getString(trackFormat, AMEDIAFORMAT_KEY_MIME, &mime);
85 ASSERT_NE(mime, nullptr);
86
87 if (GetParam() == VIDEO && strncmp(mime, "video/", 6) == 0) {
88 mTrackIndex = trackIndex;
89
Linus Nilsson800793f2020-07-31 16:16:38 -070090 mSourceFormat = std::shared_ptr<AMediaFormat>(trackFormat, &AMediaFormat_delete);
Linus Nilsson0da327a2020-01-31 16:22:18 -080091 ASSERT_NE(mSourceFormat, nullptr);
92
93 mDestinationFormat =
94 TrackTranscoderTestUtils::getDefaultVideoDestinationFormat(trackFormat);
95 ASSERT_NE(mDestinationFormat, nullptr);
96 break;
Linus Nilssonc6221db2020-03-18 14:46:22 -070097 } else if (GetParam() == PASSTHROUGH && strncmp(mime, "audio/", 6) == 0) {
98 // TODO(lnilsson): Test metadata track passthrough after hkuang@ provides sample.
99 mTrackIndex = trackIndex;
100
Linus Nilsson800793f2020-07-31 16:16:38 -0700101 mSourceFormat = std::shared_ptr<AMediaFormat>(trackFormat, &AMediaFormat_delete);
Linus Nilssonc6221db2020-03-18 14:46:22 -0700102 ASSERT_NE(mSourceFormat, nullptr);
103 break;
Linus Nilsson0da327a2020-01-31 16:22:18 -0800104 }
105
106 AMediaFormat_delete(trackFormat);
107 }
108
109 ASSERT_NE(mSourceFormat, nullptr);
Linus Nilsson6233fed2020-08-13 15:15:14 -0700110 EXPECT_EQ(mMediaSampleReader->selectTrack(mTrackIndex), AMEDIA_OK);
Linus Nilsson0da327a2020-01-31 16:22:18 -0800111 }
112
113 // Drains the transcoder's output queue in a loop.
Linus Nilssonc31d2492020-09-23 12:30:00 -0700114 void drainOutputSamples(int numSamplesToSave = 0) {
115 mTranscoder->setSampleConsumer(
116 [this, numSamplesToSave](const std::shared_ptr<MediaSample>& sample) {
117 ASSERT_NE(sample, nullptr);
118
119 mGotEndOfStream = (sample->info.flags & SAMPLE_FLAG_END_OF_STREAM) != 0;
120
121 if (mSavedSamples.size() < numSamplesToSave) {
122 mSavedSamples.push_back(sample);
123 }
124
125 if (mSavedSamples.size() == numSamplesToSave || mGotEndOfStream) {
126 mSamplesSavedSemaphore.signal();
127 }
128 });
Linus Nilsson0da327a2020-01-31 16:22:18 -0800129 }
130
Linus Nilssonc31d2492020-09-23 12:30:00 -0700131 void TearDown() override { LOG(DEBUG) << "MediaTrackTranscoderTests tear down"; }
Linus Nilsson0da327a2020-01-31 16:22:18 -0800132
133 ~MediaTrackTranscoderTests() { LOG(DEBUG) << "MediaTrackTranscoderTests destroyed"; }
134
135protected:
136 std::shared_ptr<MediaTrackTranscoder> mTranscoder;
137 std::shared_ptr<TestCallback> mCallback;
138
139 std::shared_ptr<MediaSampleReader> mMediaSampleReader;
140 int mTrackIndex;
141
142 std::shared_ptr<AMediaFormat> mSourceFormat;
143 std::shared_ptr<AMediaFormat> mDestinationFormat;
144
Linus Nilssonc31d2492020-09-23 12:30:00 -0700145 std::vector<std::shared_ptr<MediaSample>> mSavedSamples;
146 OneShotSemaphore mSamplesSavedSemaphore;
Linus Nilsson0da327a2020-01-31 16:22:18 -0800147 bool mGotEndOfStream = false;
148};
149
150TEST_P(MediaTrackTranscoderTests, WaitNormalOperation) {
151 LOG(DEBUG) << "Testing WaitNormalOperation";
152 EXPECT_EQ(mTranscoder->configure(mMediaSampleReader, mTrackIndex, mDestinationFormat),
153 AMEDIA_OK);
154 ASSERT_TRUE(mTranscoder->start());
Linus Nilssonc31d2492020-09-23 12:30:00 -0700155 drainOutputSamples();
Linus Nilsson0da327a2020-01-31 16:22:18 -0800156 EXPECT_EQ(mCallback->waitUntilFinished(), AMEDIA_OK);
Linus Nilssonfdb3e332020-09-18 17:11:41 -0700157 EXPECT_TRUE(mCallback->transcodingFinished());
Linus Nilsson0da327a2020-01-31 16:22:18 -0800158 EXPECT_TRUE(mGotEndOfStream);
159}
160
161TEST_P(MediaTrackTranscoderTests, StopNormalOperation) {
162 LOG(DEBUG) << "Testing StopNormalOperation";
Linus Nilssonfdb3e332020-09-18 17:11:41 -0700163
164 // Use a longer test asset to make sure that transcoding can be stopped.
165 initSampleReader("/data/local/tmp/TranscodingTestAssets/longtest_15s.mp4");
166
Linus Nilsson0da327a2020-01-31 16:22:18 -0800167 EXPECT_EQ(mTranscoder->configure(mMediaSampleReader, mTrackIndex, mDestinationFormat),
168 AMEDIA_OK);
169 EXPECT_TRUE(mTranscoder->start());
Linus Nilssonfdb3e332020-09-18 17:11:41 -0700170 mCallback->waitUntilTrackFormatAvailable();
171 mTranscoder->stop();
172 EXPECT_EQ(mCallback->waitUntilFinished(), AMEDIA_OK);
173 EXPECT_TRUE(mCallback->transcodingWasStopped());
Linus Nilsson0da327a2020-01-31 16:22:18 -0800174}
175
176TEST_P(MediaTrackTranscoderTests, StartWithoutConfigure) {
177 LOG(DEBUG) << "Testing StartWithoutConfigure";
178 EXPECT_FALSE(mTranscoder->start());
179}
180
181TEST_P(MediaTrackTranscoderTests, StopWithoutStart) {
182 LOG(DEBUG) << "Testing StopWithoutStart";
183 EXPECT_EQ(mTranscoder->configure(mMediaSampleReader, mTrackIndex, mDestinationFormat),
184 AMEDIA_OK);
Linus Nilssonfdb3e332020-09-18 17:11:41 -0700185 mTranscoder->stop();
Linus Nilsson0da327a2020-01-31 16:22:18 -0800186}
187
188TEST_P(MediaTrackTranscoderTests, DoubleStartStop) {
189 LOG(DEBUG) << "Testing DoubleStartStop";
Linus Nilssonfdb3e332020-09-18 17:11:41 -0700190
191 // Use a longer test asset to make sure that transcoding can be stopped.
192 initSampleReader("/data/local/tmp/TranscodingTestAssets/longtest_15s.mp4");
193
Linus Nilsson0da327a2020-01-31 16:22:18 -0800194 EXPECT_EQ(mTranscoder->configure(mMediaSampleReader, mTrackIndex, mDestinationFormat),
195 AMEDIA_OK);
196 EXPECT_TRUE(mTranscoder->start());
197 EXPECT_FALSE(mTranscoder->start());
Linus Nilssonfdb3e332020-09-18 17:11:41 -0700198 mTranscoder->stop();
199 mTranscoder->stop();
200 EXPECT_EQ(mCallback->waitUntilFinished(), AMEDIA_OK);
201 EXPECT_TRUE(mCallback->transcodingWasStopped());
Linus Nilsson0da327a2020-01-31 16:22:18 -0800202}
203
204TEST_P(MediaTrackTranscoderTests, DoubleConfigure) {
205 LOG(DEBUG) << "Testing DoubleConfigure";
206 EXPECT_EQ(mTranscoder->configure(mMediaSampleReader, mTrackIndex, mDestinationFormat),
207 AMEDIA_OK);
208 EXPECT_EQ(mTranscoder->configure(mMediaSampleReader, mTrackIndex, mDestinationFormat),
209 AMEDIA_ERROR_UNSUPPORTED);
210}
211
212TEST_P(MediaTrackTranscoderTests, ConfigureAfterFail) {
213 LOG(DEBUG) << "Testing ConfigureAfterFail";
214 EXPECT_EQ(mTranscoder->configure(mMediaSampleReader, -1, mDestinationFormat),
215 AMEDIA_ERROR_INVALID_PARAMETER);
216 EXPECT_EQ(mTranscoder->configure(mMediaSampleReader, mTrackIndex, mDestinationFormat),
217 AMEDIA_OK);
218}
219
220TEST_P(MediaTrackTranscoderTests, RestartAfterStop) {
221 LOG(DEBUG) << "Testing RestartAfterStop";
222 EXPECT_EQ(mTranscoder->configure(mMediaSampleReader, mTrackIndex, mDestinationFormat),
223 AMEDIA_OK);
224 EXPECT_TRUE(mTranscoder->start());
Linus Nilssonfdb3e332020-09-18 17:11:41 -0700225 mTranscoder->stop();
226 EXPECT_EQ(mCallback->waitUntilFinished(), AMEDIA_OK);
Linus Nilsson0da327a2020-01-31 16:22:18 -0800227 EXPECT_FALSE(mTranscoder->start());
228}
229
230TEST_P(MediaTrackTranscoderTests, RestartAfterFinish) {
231 LOG(DEBUG) << "Testing RestartAfterFinish";
232 EXPECT_EQ(mTranscoder->configure(mMediaSampleReader, mTrackIndex, mDestinationFormat),
233 AMEDIA_OK);
234 ASSERT_TRUE(mTranscoder->start());
Linus Nilssonc31d2492020-09-23 12:30:00 -0700235 drainOutputSamples();
Linus Nilsson0da327a2020-01-31 16:22:18 -0800236 EXPECT_EQ(mCallback->waitUntilFinished(), AMEDIA_OK);
Linus Nilssonfdb3e332020-09-18 17:11:41 -0700237 mTranscoder->stop();
Linus Nilsson0da327a2020-01-31 16:22:18 -0800238 EXPECT_FALSE(mTranscoder->start());
Linus Nilsson0da327a2020-01-31 16:22:18 -0800239 EXPECT_TRUE(mGotEndOfStream);
240}
241
Linus Nilssonc6221db2020-03-18 14:46:22 -0700242TEST_P(MediaTrackTranscoderTests, HoldSampleAfterTranscoderRelease) {
243 LOG(DEBUG) << "Testing HoldSampleAfterTranscoderRelease";
244 EXPECT_EQ(mTranscoder->configure(mMediaSampleReader, mTrackIndex, mDestinationFormat),
245 AMEDIA_OK);
246 ASSERT_TRUE(mTranscoder->start());
Linus Nilssonc31d2492020-09-23 12:30:00 -0700247 drainOutputSamples(1 /* numSamplesToSave */);
Linus Nilssonc6221db2020-03-18 14:46:22 -0700248 EXPECT_EQ(mCallback->waitUntilFinished(), AMEDIA_OK);
Linus Nilssonfdb3e332020-09-18 17:11:41 -0700249 mTranscoder->stop();
Linus Nilssonc6221db2020-03-18 14:46:22 -0700250 EXPECT_TRUE(mGotEndOfStream);
251
252 mTranscoder.reset();
Linus Nilssonc31d2492020-09-23 12:30:00 -0700253
Linus Nilssonc6221db2020-03-18 14:46:22 -0700254 std::this_thread::sleep_for(std::chrono::milliseconds(20));
Linus Nilssonc31d2492020-09-23 12:30:00 -0700255 mSavedSamples.clear();
Linus Nilssonc6221db2020-03-18 14:46:22 -0700256}
257
258TEST_P(MediaTrackTranscoderTests, HoldSampleAfterTranscoderStop) {
259 LOG(DEBUG) << "Testing HoldSampleAfterTranscoderStop";
260 EXPECT_EQ(mTranscoder->configure(mMediaSampleReader, mTrackIndex, mDestinationFormat),
261 AMEDIA_OK);
262 ASSERT_TRUE(mTranscoder->start());
Linus Nilssonc31d2492020-09-23 12:30:00 -0700263 drainOutputSamples(1 /* numSamplesToSave */);
264 mSamplesSavedSemaphore.wait();
Linus Nilssonfdb3e332020-09-18 17:11:41 -0700265 mTranscoder->stop();
266 EXPECT_EQ(mCallback->waitUntilFinished(), AMEDIA_OK);
Linus Nilssonc6221db2020-03-18 14:46:22 -0700267
268 std::this_thread::sleep_for(std::chrono::milliseconds(20));
Linus Nilssonc31d2492020-09-23 12:30:00 -0700269 mSavedSamples.clear();
Linus Nilssonc6221db2020-03-18 14:46:22 -0700270}
271
Linus Nilsson0da327a2020-01-31 16:22:18 -0800272TEST_P(MediaTrackTranscoderTests, NullSampleReader) {
273 LOG(DEBUG) << "Testing NullSampleReader";
274 std::shared_ptr<MediaSampleReader> nullSampleReader;
275 EXPECT_NE(mTranscoder->configure(nullSampleReader, mTrackIndex, mDestinationFormat), AMEDIA_OK);
Linus Nilssonc6221db2020-03-18 14:46:22 -0700276 ASSERT_FALSE(mTranscoder->start());
Linus Nilsson0da327a2020-01-31 16:22:18 -0800277}
278
279TEST_P(MediaTrackTranscoderTests, InvalidTrackIndex) {
280 LOG(DEBUG) << "Testing InvalidTrackIndex";
281 EXPECT_NE(mTranscoder->configure(mMediaSampleReader, -1, mDestinationFormat), AMEDIA_OK);
282 EXPECT_NE(mTranscoder->configure(mMediaSampleReader, mMediaSampleReader->getTrackCount(),
283 mDestinationFormat),
284 AMEDIA_OK);
285}
286
Linus Nilssonfdb3e332020-09-18 17:11:41 -0700287TEST_P(MediaTrackTranscoderTests, StopOnSync) {
288 LOG(DEBUG) << "Testing StopOnSync";
289
290 // Use a longer test asset to make sure there is a GOP to finish.
291 initSampleReader("/data/local/tmp/TranscodingTestAssets/longtest_15s.mp4");
292
293 EXPECT_EQ(mTranscoder->configure(mMediaSampleReader, mTrackIndex, mDestinationFormat),
294 AMEDIA_OK);
295
296 bool lastSampleWasEos = false;
297 bool lastRealSampleWasSync = false;
298 OneShotSemaphore samplesReceivedSemaphore;
299 uint32_t sampleCount = 0;
300
301 mTranscoder->setSampleConsumer([&](const std::shared_ptr<MediaSample>& sample) {
302 ASSERT_NE(sample, nullptr);
303
304 if ((lastSampleWasEos = sample->info.flags & SAMPLE_FLAG_END_OF_STREAM)) {
305 samplesReceivedSemaphore.signal();
306 return;
307 }
308 lastRealSampleWasSync = sample->info.flags & SAMPLE_FLAG_SYNC_SAMPLE;
309
310 if (++sampleCount >= 10) { // Wait for a few samples before stopping.
311 samplesReceivedSemaphore.signal();
312 }
313 });
314
315 ASSERT_TRUE(mTranscoder->start());
316 samplesReceivedSemaphore.wait();
317 mTranscoder->stop(true /* stopOnSync */);
318 EXPECT_EQ(mCallback->waitUntilFinished(), AMEDIA_OK);
319
320 EXPECT_TRUE(lastSampleWasEos);
321 EXPECT_TRUE(lastRealSampleWasSync);
322 EXPECT_TRUE(mCallback->transcodingWasStopped());
323}
324
Linus Nilsson0da327a2020-01-31 16:22:18 -0800325}; // namespace android
326
327using namespace android;
328
329INSTANTIATE_TEST_SUITE_P(MediaTrackTranscoderTestsAll, MediaTrackTranscoderTests,
Linus Nilssonc6221db2020-03-18 14:46:22 -0700330 ::testing::Values(VIDEO, PASSTHROUGH));
Linus Nilsson0da327a2020-01-31 16:22:18 -0800331
332int main(int argc, char** argv) {
333 ::testing::InitGoogleTest(&argc, argv);
334 return RUN_ALL_TESTS();
335}