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