/* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ //#define LOG_NDEBUG 0 #define LOG_TAG "Mpeg2tsUnitTest" #include #include #include #include #include #include #include #include #include #include "Mpeg2tsUnitTestEnvironment.h" constexpr size_t kTSPacketSize = 188; constexpr uint16_t kPIDMask = 0x1FFF; // Max value of PID which is also used for Null packets constexpr uint16_t kPIDMaxValue = 8191; constexpr uint8_t kTSSyncByte = 0x47; constexpr uint8_t kVideoPresent = 0x01; constexpr uint8_t kAudioPresent = 0x02; constexpr uint8_t kMetaDataPresent = 0x04; static Mpeg2tsUnitTestEnvironment *gEnv = nullptr; using namespace android; class Mpeg2tsUnitTest : public ::testing ::TestWithParam< tuple> { public: Mpeg2tsUnitTest() : mInputBuffer(nullptr), mSource(nullptr), mFpInput(nullptr), mParser(nullptr) {} ~Mpeg2tsUnitTest() { if (mInputBuffer) free(mInputBuffer); if (mFpInput) fclose(mFpInput); mSource.clear(); } void SetUp() override { mOffset = 0; mNumDataSource = 0; tuple params = GetParam(); char sourceType = get<1>(params); /* mSourceType = 0b x x x x x M A V / | \ metaData audio video */ mMediaType = (sourceType & 0x07); mNumDataSource = get<2>(params); string inputFile = gEnv->getRes() + get<0>(params); mFpInput = fopen(inputFile.c_str(), "rb"); ASSERT_NE(mFpInput, nullptr) << "Failed to open file: " << inputFile; struct stat buf; int8_t err = stat(inputFile.c_str(), &buf); ASSERT_EQ(err, 0) << "Failed to get information for file: " << inputFile; long fileSize = buf.st_size; mTotalPackets = fileSize / kTSPacketSize; int32_t fd = fileno(mFpInput); ASSERT_GE(fd, 0) << "Failed to get the integer file descriptor"; mSource = new FileSource(dup(fd), 0, buf.st_size); ASSERT_NE(mSource, nullptr) << "Failed to get the data source!"; mParser = new ATSParser(); ASSERT_NE(mParser, nullptr) << "Unable to create ATS parser!"; mInputBuffer = (uint8_t *)malloc(kTSPacketSize); ASSERT_NE(mInputBuffer, nullptr) << "Failed to allocate memory for TS packet!"; } uint64_t mOffset; uint64_t mTotalPackets; uint16_t mNumDataSource; int8_t mMediaType; uint8_t *mInputBuffer; string mInputFile; sp mSource; FILE *mFpInput; ATSParser *mParser; }; TEST_P(Mpeg2tsUnitTest, MediaInfoTest) { bool videoFound = false; bool audioFound = false; bool metaDataFound = false; bool syncPointPresent = false; int16_t totalDataSource = 0; int32_t val32 = 0; uint8_t numDataSource = 0; uint8_t packet[kTSPacketSize]; ssize_t numBytesRead = -1; ATSParser::SyncEvent event(mOffset); static const ATSParser::SourceType mediaType[] = {ATSParser::VIDEO, ATSParser::AUDIO, ATSParser::META, ATSParser::NUM_SOURCE_TYPES}; const uint32_t nMediaTypes = sizeof(mediaType) / sizeof(mediaType[0]); while ((numBytesRead = mSource->readAt(mOffset, packet, kTSPacketSize)) == kTSPacketSize) { ASSERT_TRUE(packet[0] == kTSSyncByte) << "Sync byte error!"; // pid is 13 bits uint16_t pid = (packet[1] + (packet[2] << 8)) & kPIDMask; ASSERT_TRUE(pid <= kPIDMaxValue) << "Invalid PID: " << pid; status_t err = mParser->feedTSPacket(packet, kTSPacketSize, &event); ASSERT_EQ(err, (status_t)OK) << "Unable to feed TS packet!"; mOffset += numBytesRead; for (int i = 0; i < nMediaTypes; i++) { if (mParser->hasSource(mediaType[i])) { switch (mediaType[i]) { case ATSParser::VIDEO: videoFound = true; break; case ATSParser::AUDIO: audioFound = true; break; case ATSParser::META: metaDataFound = true; break; case ATSParser::NUM_SOURCE_TYPES: numDataSource = 3; break; default: break; } } } if (videoFound && audioFound && metaDataFound && (numDataSource == 3)) break; } for (int i = 0; i < nMediaTypes; i++) { ATSParser::SourceType currentMediaType = mediaType[i]; if (mParser->hasSource(currentMediaType)) { if (event.hasReturnedData()) { syncPointPresent = true; sp syncPacketSource = event.getMediaSource(); ASSERT_NE(syncPacketSource, nullptr) << "Cannot get sync source for media type: " << currentMediaType; status_t err = syncPacketSource->start(); ASSERT_EQ(err, (status_t)OK) << "Error returned while starting!"; sp format = syncPacketSource->getFormat(); ASSERT_NE(format, nullptr) << "Unable to get the format of the source packet!"; MediaBufferBase *buf; syncPacketSource->read(&buf, nullptr); ASSERT_NE(buf, nullptr) << "Failed to read sync packet source data"; MetaDataBase &inMeta = buf->meta_data(); bool status = inMeta.findInt32(kKeyIsSyncFrame, &val32); ASSERT_EQ(status, true) << "Sync frame key is not set"; status = inMeta.findInt32(kKeyCryptoMode, &val32); ASSERT_EQ(status, false) << "Invalid packet, found scrambled packets!"; err = syncPacketSource->stop(); ASSERT_EQ(err, (status_t)OK) << "Error returned while stopping!"; } sp packetSource = mParser->getSource(currentMediaType); ASSERT_NE(packetSource, nullptr) << "Cannot get source for media type: " << currentMediaType; status_t err = packetSource->start(); ASSERT_EQ(err, (status_t)OK) << "Error returned while starting!"; sp format = packetSource->getFormat(); ASSERT_NE(format, nullptr) << "Unable to get the format of the packet!"; err = packetSource->stop(); ASSERT_EQ(err, (status_t)OK) << "Error returned while stopping!"; } } ASSERT_EQ(videoFound, bool(mMediaType & kVideoPresent)) << "No Video packets found!"; ASSERT_EQ(audioFound, bool(mMediaType & kAudioPresent)) << "No Audio packets found!"; ASSERT_EQ(metaDataFound, bool(mMediaType & kMetaDataPresent)) << "No meta data found!"; if (videoFound || audioFound) { ASSERT_TRUE(syncPointPresent) << "No sync points found for audio/video"; } if (videoFound) totalDataSource += 1; if (audioFound) totalDataSource += 1; if (metaDataFound) totalDataSource += 1; ASSERT_TRUE(totalDataSource == mNumDataSource) << "Expected " << mNumDataSource << " data sources, found " << totalDataSource; if (numDataSource == 3) { ASSERT_EQ(numDataSource, mNumDataSource) << "Expected " << mNumDataSource << " data sources, found " << totalDataSource; } } INSTANTIATE_TEST_SUITE_P( infoTest, Mpeg2tsUnitTest, ::testing::Values(make_tuple("crowd_1920x1080_25fps_6700kbps_h264.ts", 0x01, 1), make_tuple("segment000001.ts", 0x03, 2), make_tuple("bbb_44100hz_2ch_128kbps_mp3_5mins.ts", 0x02, 1))); int32_t main(int argc, char **argv) { gEnv = new Mpeg2tsUnitTestEnvironment(); ::testing::AddGlobalTestEnvironment(gEnv); ::testing::InitGoogleTest(&argc, argv); uint8_t status = gEnv->initFromOptions(argc, argv); if (status == 0) { status = RUN_ALL_TESTS(); ALOGV("Mpeg2tsUnit Test Result = %d\n", status); } return status; }