xref: /aosp_15_r20/frameworks/av/media/module/mpeg2ts/test/Mpeg2tsUnitTest.cpp (revision ec779b8e0859a360c3d303172224686826e6e0e1)
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 "Mpeg2tsUnitTest"
19 
20 #include <utils/Log.h>
21 
22 #include <stdint.h>
23 #include <sys/stat.h>
24 
25 #include <datasource/FileSource.h>
26 #include <media/stagefright/MediaDefs.h>
27 #include <media/stagefright/MetaDataBase.h>
28 #include <media/stagefright/foundation/AUtils.h>
29 #include <mpeg2ts/AnotherPacketSource.h>
30 #include <mpeg2ts/ATSParser.h>
31 
32 #include "Mpeg2tsUnitTestEnvironment.h"
33 
34 constexpr size_t kTSPacketSize = 188;
35 constexpr uint16_t kPIDMask = 0x1FFF;
36 // Max value of PID which is also used for Null packets
37 constexpr uint16_t kPIDMaxValue = 8191;
38 constexpr uint8_t kTSSyncByte = 0x47;
39 constexpr uint8_t kVideoPresent = 0x01;
40 constexpr uint8_t kAudioPresent = 0x02;
41 constexpr uint8_t kMetaDataPresent = 0x04;
42 
43 static Mpeg2tsUnitTestEnvironment *gEnv = nullptr;
44 
45 using namespace android;
46 
47 class Mpeg2tsUnitTest
48     : public ::testing ::TestWithParam<
49               tuple</*fileName*/ string, /*sourceType*/ char, /*numSource*/ uint16_t>> {
50   public:
Mpeg2tsUnitTest()51     Mpeg2tsUnitTest()
52         : mInputBuffer(nullptr), mSource(nullptr), mFpInput(nullptr), mParser(nullptr) {}
53 
~Mpeg2tsUnitTest()54     ~Mpeg2tsUnitTest() {
55         if (mInputBuffer) free(mInputBuffer);
56         if (mFpInput) fclose(mFpInput);
57         mSource.clear();
58     }
59 
SetUp()60     void SetUp() override {
61         mOffset = 0;
62         mNumDataSource = 0;
63         tuple<string, char, uint16_t> params = GetParam();
64         char sourceType = get<1>(params);
65         /* mSourceType = 0b x x x x x M A V
66                                      /  |  \
67                             metaData  audio  video */
68         mMediaType = (sourceType & 0x07);
69         mNumDataSource = get<2>(params);
70         string inputFile = gEnv->getRes() + get<0>(params);
71         mFpInput = fopen(inputFile.c_str(), "rb");
72         ASSERT_NE(mFpInput, nullptr) << "Failed to open file: " << inputFile;
73 
74         struct stat buf;
75         int8_t err = stat(inputFile.c_str(), &buf);
76         ASSERT_EQ(err, 0) << "Failed to get information for file: " << inputFile;
77 
78         long fileSize = buf.st_size;
79         mTotalPackets = fileSize / kTSPacketSize;
80         int32_t fd = fileno(mFpInput);
81         ASSERT_GE(fd, 0) << "Failed to get the integer file descriptor";
82 
83         mSource = new FileSource(dup(fd), 0, buf.st_size);
84         ASSERT_NE(mSource, nullptr) << "Failed to get the data source!";
85 
86         mParser = new ATSParser();
87         ASSERT_NE(mParser, nullptr) << "Unable to create ATS parser!";
88         mInputBuffer = (uint8_t *)malloc(kTSPacketSize);
89         ASSERT_NE(mInputBuffer, nullptr) << "Failed to allocate memory for TS packet!";
90     }
91 
92     uint64_t mOffset;
93     uint64_t mTotalPackets;
94     uint16_t mNumDataSource;
95 
96     int8_t mMediaType;
97 
98     uint8_t *mInputBuffer;
99     string mInputFile;
100     sp<DataSource> mSource;
101     FILE *mFpInput;
102     ATSParser *mParser;
103 };
104 
TEST_P(Mpeg2tsUnitTest,MediaInfoTest)105 TEST_P(Mpeg2tsUnitTest, MediaInfoTest) {
106     bool videoFound = false;
107     bool audioFound = false;
108     bool metaDataFound = false;
109     bool syncPointPresent = false;
110 
111     int16_t totalDataSource = 0;
112     int32_t val32 = 0;
113     uint8_t numDataSource = 0;
114     uint8_t packet[kTSPacketSize];
115     ssize_t numBytesRead = -1;
116 
117     ATSParser::SyncEvent event(mOffset);
118     static const ATSParser::SourceType mediaType[] = {ATSParser::VIDEO, ATSParser::AUDIO,
119                                                       ATSParser::META, ATSParser::NUM_SOURCE_TYPES};
120     const uint32_t nMediaTypes = sizeof(mediaType) / sizeof(mediaType[0]);
121 
122     while ((numBytesRead = mSource->readAt(mOffset, packet, kTSPacketSize)) == kTSPacketSize) {
123         ASSERT_TRUE(packet[0] == kTSSyncByte) << "Sync byte error!";
124 
125         // pid is 13 bits
126         uint16_t pid = (packet[1] + (packet[2] << 8)) & kPIDMask;
127         ASSERT_TRUE(pid <= kPIDMaxValue) << "Invalid PID: " << pid;
128 
129         status_t err = mParser->feedTSPacket(packet, kTSPacketSize, &event);
130         ASSERT_EQ(err, (status_t)OK) << "Unable to feed TS packet!";
131 
132         mOffset += numBytesRead;
133         for (int i = 0; i < nMediaTypes; i++) {
134             if (mParser->hasSource(mediaType[i])) {
135                 switch (mediaType[i]) {
136                     case ATSParser::VIDEO:
137                         videoFound = true;
138                         break;
139                     case ATSParser::AUDIO:
140                         audioFound = true;
141                         break;
142                     case ATSParser::META:
143                         metaDataFound = true;
144                         break;
145                     case ATSParser::NUM_SOURCE_TYPES:
146                         numDataSource = 3;
147                         break;
148                     default:
149                         break;
150                 }
151             }
152         }
153         if (videoFound && audioFound && metaDataFound && (numDataSource == 3)) break;
154     }
155 
156     for (int i = 0; i < nMediaTypes; i++) {
157         ATSParser::SourceType currentMediaType = mediaType[i];
158         if (mParser->hasSource(currentMediaType)) {
159             if (event.hasReturnedData()) {
160                 syncPointPresent = true;
161                 sp<AnotherPacketSource> syncPacketSource = event.getMediaSource();
162                 ASSERT_NE(syncPacketSource, nullptr)
163                         << "Cannot get sync source for media type: " << currentMediaType;
164 
165                 status_t err = syncPacketSource->start();
166                 ASSERT_EQ(err, (status_t)OK) << "Error returned while starting!";
167 
168                 sp<MetaData> format = syncPacketSource->getFormat();
169                 ASSERT_NE(format, nullptr) << "Unable to get the format of the source packet!";
170 
171                 MediaBufferBase *buf;
172                 syncPacketSource->read(&buf, nullptr);
173                 ASSERT_NE(buf, nullptr) << "Failed to read sync packet source data";
174 
175                 MetaDataBase &inMeta = buf->meta_data();
176                 bool status = inMeta.findInt32(kKeyIsSyncFrame, &val32);
177                 ASSERT_EQ(status, true) << "Sync frame key is not set";
178 
179                 status = inMeta.findInt32(kKeyCryptoMode, &val32);
180                 ASSERT_EQ(status, false) << "Invalid packet, found scrambled packets!";
181 
182                 err = syncPacketSource->stop();
183                 ASSERT_EQ(err, (status_t)OK) << "Error returned while stopping!";
184             }
185             sp<AnotherPacketSource> packetSource = mParser->getSource(currentMediaType);
186             ASSERT_NE(packetSource, nullptr)
187                     << "Cannot get source for media type: " << currentMediaType;
188 
189             status_t err = packetSource->start();
190             ASSERT_EQ(err, (status_t)OK) << "Error returned while starting!";
191             sp<MetaData> format = packetSource->getFormat();
192             ASSERT_NE(format, nullptr) << "Unable to get the format of the packet!";
193 
194             err = packetSource->stop();
195             ASSERT_EQ(err, (status_t)OK) << "Error returned while stopping!";
196         }
197     }
198 
199     ASSERT_EQ(videoFound, bool(mMediaType & kVideoPresent)) << "No Video packets found!";
200     ASSERT_EQ(audioFound, bool(mMediaType & kAudioPresent)) << "No Audio packets found!";
201     ASSERT_EQ(metaDataFound, bool(mMediaType & kMetaDataPresent)) << "No meta data found!";
202 
203     if (videoFound || audioFound) {
204         ASSERT_TRUE(syncPointPresent) << "No sync points found for audio/video";
205     }
206 
207     if (videoFound) totalDataSource += 1;
208     if (audioFound) totalDataSource += 1;
209     if (metaDataFound) totalDataSource += 1;
210 
211     ASSERT_TRUE(totalDataSource == mNumDataSource)
212             << "Expected " << mNumDataSource << " data sources, found " << totalDataSource;
213     if (numDataSource == 3) {
214         ASSERT_EQ(numDataSource, mNumDataSource)
215                 << "Expected " << mNumDataSource << " data sources, found " << totalDataSource;
216     }
217 }
218 
219 INSTANTIATE_TEST_SUITE_P(
220         infoTest, Mpeg2tsUnitTest,
221         ::testing::Values(make_tuple("crowd_1920x1080_25fps_6700kbps_h264.ts", 0x01, 1),
222                           make_tuple("segment000001.ts", 0x03, 2),
223                           make_tuple("bbb_44100hz_2ch_128kbps_mp3_5mins.ts", 0x02, 1)));
224 
main(int argc,char ** argv)225 int32_t main(int argc, char **argv) {
226     gEnv = new Mpeg2tsUnitTestEnvironment();
227     ::testing::AddGlobalTestEnvironment(gEnv);
228     ::testing::InitGoogleTest(&argc, argv);
229     uint8_t status = gEnv->initFromOptions(argc, argv);
230     if (status == 0) {
231         status = RUN_ALL_TESTS();
232         ALOGV("Mpeg2tsUnit Test Result = %d\n", status);
233     }
234     return status;
235 }
236