1 /*
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 //#define LOG_NDEBUG 0
18 #define LOG_TAG "ESDSTest"
19 #include <utils/Log.h>
20
21 #include <stdio.h>
22 #include <string.h>
23 #include <fstream>
24 #include <memory>
25
26 #include <media/esds/ESDS.h>
27 #include <binder/ProcessState.h>
28 #include <datasource/FileSource.h>
29 #include <media/stagefright/MediaExtractorFactory.h>
30 #include <media/stagefright/MetaData.h>
31
32 #include "ESDSTestEnvironment.h"
33
34 using namespace android;
35
36 static ESDSTestEnvironment *gEnv = nullptr;
37
38 struct ESDSParams {
39 const char *inputFile;
40 int32_t objectTypeIndication;
41 const char *codecSpecificInfoData;
42 int32_t codecSpecificInfoDataSize;
43 int32_t bitrateMax;
44 int32_t bitrateAvg;
45 };
46
47 class ESDSUnitTest : public ::testing::TestWithParam<tuple<
48 /* InputFile */ const char *,
49 /* ObjectTypeIndication */ int32_t,
50 /* CodecSpecificInfoData */ const char *,
51 /* CodecSpecificInfoDataSize */ int32_t,
52 /* BitrateMax */ int32_t,
53 /* BitrateAvg */ int32_t>> {
54 public:
ESDSUnitTest()55 ESDSUnitTest() {
56 mESDSParams.inputFile = get<0>(GetParam());
57 mESDSParams.objectTypeIndication = get<1>(GetParam());
58 mESDSParams.codecSpecificInfoData = get<2>(GetParam());
59 mESDSParams.codecSpecificInfoDataSize = get<3>(GetParam());
60 mESDSParams.bitrateMax = get<4>(GetParam());
61 mESDSParams.bitrateAvg = get<5>(GetParam());
62 };
63
~ESDSUnitTest()64 ~ESDSUnitTest() {
65 if (mESDSData != nullptr) {
66 free(mESDSData);
67 mESDSData = nullptr;
68 }
69 }
70
TearDown()71 virtual void TearDown() override {
72 if (mDataSource) mDataSource.clear();
73 if (mInputFp) {
74 fclose(mInputFp);
75 mInputFp = nullptr;
76 }
77 }
78
SetUp()79 virtual void SetUp() override { ASSERT_NO_FATAL_FAILURE(readESDSData()); }
80 void *mESDSData = nullptr;
81 size_t mESDSSize = 0;
82 ESDSParams mESDSParams;
83
84 private:
readESDSData()85 void readESDSData() {
86 string inputFile = gEnv->getRes() + mESDSParams.inputFile;
87 mInputFp = fopen(inputFile.c_str(), "rb");
88 ASSERT_NE(mInputFp, nullptr) << "File open failed for file: " << inputFile;
89 int32_t fd = fileno(mInputFp);
90 ASSERT_GE(fd, 0) << "File descriptor invalid for file: " << inputFile;
91
92 struct stat buf;
93 status_t status = stat(inputFile.c_str(), &buf);
94 ASSERT_EQ(status, 0) << "Failed to get properties of input file: " << mESDSParams.inputFile;
95 size_t fileSize = buf.st_size;
96
97 mDataSource = new FileSource(dup(fd), 0, fileSize);
98 ASSERT_NE(mDataSource, nullptr) << "Unable to create data source for file: " << inputFile;
99
100 sp<IMediaExtractor> extractor = MediaExtractorFactory::Create(mDataSource);
101 if (extractor == nullptr) {
102 mDataSource.clear();
103 ASSERT_TRUE(false) << "Unable to create extractor for file: " << inputFile;
104 }
105
106 size_t numTracks = extractor->countTracks();
107 ASSERT_GT(numTracks, 0) << "No tracks in file: " << inputFile;
108 ASSERT_TRUE(esdsDataPresent(numTracks, extractor))
109 << "Unable to find esds in any track in file: " << inputFile;
110 }
111
esdsDataPresent(size_t numTracks,sp<IMediaExtractor> extractor)112 bool esdsDataPresent(size_t numTracks, sp<IMediaExtractor> extractor) {
113 bool foundESDS = false;
114 uint32_t type;
115 if (mESDSData != nullptr) {
116 free(mESDSData);
117 mESDSData = nullptr;
118 }
119 for (size_t i = 0; i < numTracks; ++i) {
120 sp<MetaData> trackMeta = extractor->getTrackMetaData(i);
121 const void *esdsData = nullptr;
122 size_t esdsSize = 0;
123 if (trackMeta != nullptr &&
124 trackMeta->findData(kKeyESDS, &type, &esdsData, &esdsSize)) {
125 mESDSData = malloc(esdsSize);
126 mESDSSize = esdsSize;
127 memcpy(mESDSData, esdsData, esdsSize);
128 trackMeta->clear();
129 foundESDS = true;
130 break;
131 }
132 }
133 return foundESDS;
134 }
135
136 FILE *mInputFp;
137 sp<DataSource> mDataSource;
138 };
139
TEST_P(ESDSUnitTest,InvalidDataTest)140 TEST_P(ESDSUnitTest, InvalidDataTest) {
141 std::unique_ptr<char[]> invalidData(new char[mESDSSize]());
142 ASSERT_NE(invalidData, nullptr) << "Unable to allocate memory";
143 ESDS esds((void*)invalidData.get(), mESDSSize);
144 ASSERT_NE(esds.InitCheck(), OK) << "invalid ESDS data accepted";
145 }
146
TEST(ESDSSanityUnitTest,ConstructorSanityTest)147 TEST(ESDSSanityUnitTest, ConstructorSanityTest) {
148 std::unique_ptr<char[]> invalidData(new char[1]());
149 ASSERT_NE(invalidData, nullptr) << "Unable to allocate memory";
150 ESDS esds_zero((void*)invalidData.get(), 0);
151 ASSERT_NE(esds_zero.InitCheck(), OK) << "invalid ESDS data accepted";
152
153 ESDS esds_null(NULL, 0);
154 ASSERT_NE(esds_null.InitCheck(), OK) << "invalid ESDS data accepted";
155 }
156
TEST_P(ESDSUnitTest,CreateAndDestroyTest)157 TEST_P(ESDSUnitTest, CreateAndDestroyTest) {
158 ESDS esds(mESDSData, mESDSSize);
159 ASSERT_EQ(esds.InitCheck(), OK) << "ESDS data invalid";
160 }
161
TEST_P(ESDSUnitTest,ObjectTypeIndicationTest)162 TEST_P(ESDSUnitTest, ObjectTypeIndicationTest) {
163 ESDS esds(mESDSData, mESDSSize);
164 ASSERT_EQ(esds.InitCheck(), OK) << "ESDS data invalid";
165 uint8_t objectTypeIndication;
166 status_t status = esds.getObjectTypeIndication(&objectTypeIndication);
167 ASSERT_EQ(status, OK) << "ESDS objectTypeIndication data invalid";
168 ASSERT_EQ(objectTypeIndication, mESDSParams.objectTypeIndication)
169 << "ESDS objectTypeIndication data doesn't match";
170 }
171
TEST_P(ESDSUnitTest,CodecSpecificInfoTest)172 TEST_P(ESDSUnitTest, CodecSpecificInfoTest) {
173 ESDS esds(mESDSData, mESDSSize);
174 ASSERT_EQ(esds.InitCheck(), OK) << "ESDS data invalid";
175 status_t status;
176 const void *codecSpecificInfo;
177 size_t codecSpecificInfoSize;
178 status = esds.getCodecSpecificInfo(&codecSpecificInfo, &codecSpecificInfoSize);
179 ASSERT_EQ(status, OK) << "ESDS getCodecSpecificInfo data invalid";
180 ASSERT_EQ(mESDSParams.codecSpecificInfoDataSize, codecSpecificInfoSize)
181 << "CodecSpecificInfo data doesn't match";
182 status = memcmp(codecSpecificInfo, mESDSParams.codecSpecificInfoData, codecSpecificInfoSize);
183 ASSERT_EQ(status, 0) << "CodecSpecificInfo data doesn't match";
184 }
185
TEST_P(ESDSUnitTest,GetBitrateTest)186 TEST_P(ESDSUnitTest, GetBitrateTest) {
187 ESDS esds(mESDSData, mESDSSize);
188 ASSERT_EQ(esds.InitCheck(), OK) << "ESDS data invalid";
189 uint32_t bitrateMax;
190 uint32_t bitrateAvg;
191 status_t status = esds.getBitRate(&bitrateMax, &bitrateAvg);
192 ASSERT_EQ(status, OK) << "ESDS bitRate data invalid";
193 ASSERT_EQ(bitrateMax, mESDSParams.bitrateMax) << "ESDS bitrateMax doesn't match";
194 ASSERT_EQ(bitrateAvg, mESDSParams.bitrateAvg) << "ESDS bitrateAvg doesn't match";
195 ASSERT_LE(bitrateAvg, bitrateMax) << "ESDS bitrateMax is less than bitrateAvg";
196 }
197
198 INSTANTIATE_TEST_SUITE_P(
199 ESDSUnitTestAll, ESDSUnitTest,
200 ::testing::Values(
201 // InputFile, ObjectTypeIndication, CodecSpecificInfoData,
202 // CodecSpecificInfoDataSize, BitrateMax, BitrateAvg
203 make_tuple("video_176x144_3gp_h263_56kbps_12fps_aac_stereo_128kbps_22050hz.3gp", 64,
204 "\x13\x90", 2, 131072, 0),
205 make_tuple("video_1280x720_mp4_mpeg2_3000kbps_30fps_aac_stereo_128kbps_48000hz.mp4",
206 97,
207 "\x00\x00\x01\xB3\x50\x02\xD0\x35\xFF\xFF\xE1\xA0\x00\x00\x01\xB5\x15"
208 "\x6A\x00\x01\x00\x00",
209 22, 3415452, 3415452),
210 make_tuple("video_176x144_3gp_h263_56kbps_25fps_aac_mono_24kbps_11025hz.3gp", 64,
211 "\x15\x08", 2, 24576, 0)));
212
main(int argc,char ** argv)213 int main(int argc, char **argv) {
214 // MediaExtractor needs binder thread pool
215 ProcessState::self()->startThreadPool();
216 gEnv = new ESDSTestEnvironment();
217 ::testing::AddGlobalTestEnvironment(gEnv);
218 ::testing::InitGoogleTest(&argc, argv);
219 int status = gEnv->initFromOptions(argc, argv);
220 if (status == 0) {
221 status = RUN_ALL_TESTS();
222 ALOGV("Test result = %d\n", status);
223 }
224 return status;
225 }
226