1 /*
2 * Copyright (C) 2019 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 //#define LOG_NDEBUG 0
18 #define LOG_TAG "C2DecoderTest"
19
20 #include <fstream>
21 #include <iostream>
22 #include <limits>
23 #include <memory>
24
25 #include "BenchmarkTestEnvironment.h"
26 #include "C2Decoder.h"
27 #include "Extractor.h"
28
29 static BenchmarkTestEnvironment *gEnv = nullptr;
30
31 class C2DecoderTest : public ::testing::TestWithParam<pair<string, string>> {
32 public:
C2DecoderTest()33 C2DecoderTest() : mDecoder(nullptr) {}
34
~C2DecoderTest()35 ~C2DecoderTest() {
36 if (!mCodecList.empty()) {
37 mCodecList.clear();
38 }
39 if (mDecoder) {
40 delete mDecoder;
41 mDecoder = nullptr;
42 }
43 }
44
SetUp()45 virtual void SetUp() override { setupC2DecoderTest(); }
46
47 void setupC2DecoderTest();
48
49 vector<string> mCodecList;
50 C2Decoder *mDecoder;
51 };
52
setupC2DecoderTest()53 void C2DecoderTest::setupC2DecoderTest() {
54 mDecoder = new (std::nothrow) C2Decoder();
55 ASSERT_NE(mDecoder, nullptr) << "C2Decoder creation failed";
56
57 int32_t status = mDecoder->setupCodec2();
58 ASSERT_EQ(status, 0) << "Codec2 setup failed";
59
60 mCodecList = mDecoder->getSupportedComponentList(false /* isEncoder*/);
61 ASSERT_GT(mCodecList.size(), 0) << "Codec2 client didn't recognise any component";
62 }
63
TEST_P(C2DecoderTest,Codec2Decode)64 TEST_P(C2DecoderTest, Codec2Decode) {
65 ALOGV("Decode the samples given by extractor using codec2");
66 string inputFile = gEnv->getRes() + GetParam().first;
67 FILE *inputFp = fopen(inputFile.c_str(), "rb");
68 ASSERT_NE(inputFp, nullptr) << "Unable to open " << inputFile << " file for reading";
69
70 std::unique_ptr<Extractor> extractor(new (std::nothrow) Extractor());
71 ASSERT_NE(extractor, nullptr) << "Extractor creation failed";
72
73 // Read file properties
74 struct stat buf;
75 stat(inputFile.c_str(), &buf);
76 size_t fileSize = buf.st_size;
77 int32_t fd = fileno(inputFp);
78
79 ASSERT_LE(fileSize, kMaxBufferSize)
80 << "Input file size is greater than the threshold memory dedicated to the test";
81
82 int32_t trackCount = extractor->initExtractor(fd, fileSize);
83 ASSERT_GT(trackCount, 0) << "initExtractor failed";
84
85 for (int32_t curTrack = 0; curTrack < trackCount; curTrack++) {
86 int32_t status = extractor->setupTrackFormat(curTrack);
87 ASSERT_EQ(status, 0) << "Track Format invalid";
88
89 std::unique_ptr<uint8_t[]> inputBuffer(new (std::nothrow) uint8_t[fileSize]);
90 ASSERT_NE(inputBuffer, nullptr) << "Insufficient memory";
91
92 vector<AMediaCodecBufferInfo> frameInfo;
93 AMediaCodecBufferInfo info;
94 uint32_t inputBufferOffset = 0;
95 int32_t idx = 0;
96
97 // Get CSD data
98 while (1) {
99 void *csdBuffer = extractor->getCSDSample(info, idx);
100 if (!csdBuffer || !info.size) break;
101 // copy the meta data and buffer to be passed to decoder
102 ASSERT_LE(inputBufferOffset + info.size, fileSize) << "Memory allocated not sufficient";
103
104 memcpy(inputBuffer.get() + inputBufferOffset, csdBuffer, info.size);
105 frameInfo.push_back(info);
106 inputBufferOffset += info.size;
107 idx++;
108 }
109
110 // Get frame data
111 while (1) {
112 status = extractor->getFrameSample(info);
113 if (status || !info.size) break;
114 // copy the meta data and buffer to be passed to decoder
115 ASSERT_LE(inputBufferOffset + info.size, fileSize) << "Memory allocated not sufficient";
116
117 memcpy(inputBuffer.get() + inputBufferOffset, extractor->getFrameBuf(), info.size);
118 frameInfo.push_back(info);
119 inputBufferOffset += info.size;
120 }
121
122 AMediaFormat *format = extractor->getFormat();
123 // Decode the given input stream for all C2 codecs supported by device
124 for (string codecName : mCodecList) {
125 if (codecName.find(GetParam().second) != string::npos &&
126 codecName.find("secure") == string::npos) {
127 status = mDecoder->createCodec2Component(codecName, format);
128 ASSERT_EQ(status, 0) << "Create component failed for " << codecName;
129
130 // Send the inputs to C2 Decoder and wait till all buffers are returned.
131 status = mDecoder->decodeFrames(inputBuffer.get(), frameInfo);
132 ASSERT_EQ(status, 0) << "Decoder failed for " << codecName;
133
134 mDecoder->waitOnInputConsumption();
135 ASSERT_TRUE(mDecoder->mEos) << "Test Failed. Didn't receive EOS \n";
136
137 mDecoder->deInitCodec();
138 int64_t durationUs = extractor->getClipDuration();
139 ALOGV("codec : %s", codecName.c_str());
140 mDecoder->dumpStatistics(GetParam().first, durationUs, codecName,
141 gEnv->getStatsFile());
142 mDecoder->resetDecoder();
143 }
144 }
145 fclose(inputFp);
146 extractor->deInitExtractor();
147 delete mDecoder;
148 mDecoder = nullptr;
149 }
150 }
151
152 // TODO: (b/140549596)
153 // Add wav files
154 INSTANTIATE_TEST_SUITE_P(
155 AudioDecoderTest, C2DecoderTest,
156 ::testing::Values(make_pair("bbb_44100hz_2ch_128kbps_aac_30sec.mp4", "aac"),
157 make_pair("bbb_44100hz_2ch_128kbps_mp3_30sec.mp3", "mp3"),
158 make_pair("bbb_8000hz_1ch_8kbps_amrnb_30sec.3gp", "amrnb"),
159 make_pair("bbb_16000hz_1ch_9kbps_amrwb_30sec.3gp", "amrnb"),
160 make_pair("bbb_44100hz_2ch_80kbps_vorbis_30sec.webm", "vorbis"),
161 make_pair("bbb_44100hz_2ch_600kbps_flac_30sec.mp4", "flac"),
162 make_pair("bbb_48000hz_2ch_100kbps_opus_30sec.webm", "opus")));
163
164 INSTANTIATE_TEST_SUITE_P(
165 VideoDecoderTest, C2DecoderTest,
166 ::testing::Values(make_pair("crowd_1920x1080_25fps_4000kbps_vp9.webm", "vp9"),
167 make_pair("crowd_1920x1080_25fps_4000kbps_vp8.webm", "vp8"),
168 make_pair("crowd_1920x1080_25fps_4000kbps_av1.webm", "av1"),
169 make_pair("crowd_1920x1080_25fps_7300kbps_mpeg2.mp4", "mpeg2"),
170 make_pair("crowd_1920x1080_25fps_6000kbps_mpeg4.mp4", "mpeg4"),
171 make_pair("crowd_352x288_25fps_6000kbps_h263.3gp", "h263"),
172 make_pair("crowd_1920x1080_25fps_6700kbps_h264.ts", "avc"),
173 make_pair("crowd_1920x1080_25fps_4000kbps_h265.mkv", "hevc")));
174
main(int argc,char ** argv)175 int main(int argc, char **argv) {
176 gEnv = new (std::nothrow) BenchmarkTestEnvironment();
177 ::testing::AddGlobalTestEnvironment(gEnv);
178 ::testing::InitGoogleTest(&argc, argv);
179 int status = gEnv->initFromOptions(argc, argv);
180 if (status == 0) {
181 gEnv->setStatsFile("C2Decoder.csv");
182 status = gEnv->writeStatsHeader();
183 ALOGV("Stats file = %d\n", status);
184 status = RUN_ALL_TESTS();
185 ALOGV("C2 Decoder Test result = %d\n", status);
186 }
187 return status;
188 }
189