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