/* * Copyright (c) 2020 Amlogic, Inc. All rights reserved. * * This source code is subject to the terms and conditions defined in the * file 'LICENSE' which is part of this source code package. * * Description: */ //#define LOG_NDEBUG 0 #define LOG_TAG "AmlMpPlayerDemo_AmlSwDemux" #include #include "AmlSwDemux.h" #include "AmlESQueue.h" #include #include #include #include #include #include #include #include #include #include static const char* mName = LOG_TAG; namespace aml_mp { #define ERROR_SIZE (-1) #define ERROR_CRC (-2) #define MY_LOGV(x, y) \ do { unsigned tmp = y; (void)tmp; MLOGV(x, tmp); } while (0) const size_t kTSPacketSize = 188; class SwTsParser: public AmlDemuxBase::ITsParser { public: enum { // From ISO/IEC 13818-1: 2000 (E), Table 2-29 STREAMTYPE_RESERVED = 0x00, STREAMTYPE_MPEG1_VIDEO = 0x01, STREAMTYPE_MPEG2_VIDEO = 0x02, STREAMTYPE_MPEG1_AUDIO = 0x03, STREAMTYPE_MPEG2_AUDIO = 0x04, STREAMTYPE_PES_PRIVATE_DATA = 0x06, STREAMTYPE_MPEG2_AUDIO_ADTS = 0x0f, STREAMTYPE_MPEG4_VIDEO = 0x10, STREAMTYPE_METADATA = 0x15, STREAMTYPE_H264 = 0x1b, // From ATSC A/53 Part 3:2009, 6.7.1 STREAMTYPE_AC3 = 0x81, // Stream type 0x83 is non-standard, // it could be LPCM or TrueHD AC3 STREAMTYPE_LPCM_AC3 = 0x83, STREAMTYPE_EAC3 = 0x87, //Sample Encrypted types STREAMTYPE_H264_ENCRYPTED = 0xDB, STREAMTYPE_AAC_ENCRYPTED = 0xCF, STREAMTYPE_AC3_ENCRYPTED = 0xC1, }; SwTsParser(const std::function& cb); ~SwTsParser(); int feedTs(const uint8_t* buffer, size_t size) override; void reset() override; int addDemuxFilter(int pid, const Aml_MP_DemuxFilterParams* params) override; void removeDemuxFilter(int pid) override; private: struct PSISection; struct Program; struct Stream; void parseAdaptationField(AmlMpBitReader *br, unsigned PID); int parseTS(AmlMpBitReader *br); void parseProgramAssociationTable(AmlMpBitReader *br); int parsePID(AmlMpBitReader* br, unsigned PID, unsigned continuity_counter, unsigned payload_unit_start_indicator); int programMapPID() const {return mProgramMapPID;} void initCrcTable(); uint32_t crc32(const uint8_t *p_start, size_t length); std::vector > mPrograms; int mPcrPid = 0x1FFF; size_t mNumTSPacketsParsed = 0; uint32_t mCrcTable[256]; std::map > mPSISections; unsigned mProgramMapPID = 0x1FFF; std::map> mStreams; private: SwTsParser(const SwTsParser&); SwTsParser& operator= (const SwTsParser&) = delete; }; struct SwTsParser::PSISection : public AmlMpRefBase { PSISection(int pid, SwTsParser* tsParser); int append(const void *data, size_t size); void clear(); bool isComplete() const; bool isEmpty() const; const uint8_t *data() const; size_t size() const; void setRange(size_t offset, size_t length); size_t sectionLength() const; const sptr rawBuffer() const {return mBuffer;} bool isChanged() const {return mChanged;} bool needCheckVersionChange(); int sectionVersion() const; bool parse(int PID, unsigned continuity_counter, unsigned payload_unit_start_indicator, AmlMpBitReader *br); int parseSection(AmlMpBitReader* br); protected: virtual ~PSISection(); private: sptr mBuffer; int mPid = 0x1FFF; SwTsParser* mTsParser = nullptr; //int32_t mExpectedContinuityCounter = -1; bool mPayloadStarted = false; mutable bool mGuessed = false; std::map mSectionVersions; bool mChanged = false; //DISALLOW_EVIL_CONSTRUCTORS(PSISection); PSISection(const PSISection&) = delete; PSISection& operator=(const PSISection&) = delete; }; struct SwTsParser::Program : public AmlMpRefBase { Program(SwTsParser *parser, unsigned programNumber, unsigned programMapPID) : mParser(parser) , mProgramNumber(programNumber) , mProgramMapPID(programMapPID) { } unsigned number() const { return mProgramNumber; } void updateProgramMapPID(unsigned programMapPID) { mProgramMapPID = programMapPID; } private: SwTsParser *mParser __unused; unsigned mProgramNumber; unsigned mProgramMapPID; private: Program(const Program&) = delete; Program& operator=(const Program&) = delete; }; struct SwTsParser::Stream : public AmlMpRefBase { public: Stream(int pid, const Aml_MP_DemuxFilterParams* params); int parse(unsigned continuity_counter, unsigned payload_unit_start_indicator, AmlMpBitReader* br); sptr dequeueFrame(); private: int flush(); int parsePES(AmlMpBitReader* br); void onPayloadData(unsigned PTS_DTS_flags, uint64_t PTS, uint64_t DTS, const uint8_t* data, size_t size, int32_t payloadOffset); int mPid; Aml_MP_CodecID mCodecType; Aml_MP_DemuxFilterType mType; uint32_t mFlags; int32_t mExpectedContinuityCounter = -1; sptr mBuffer; bool mPayloadStarted = false; sptr mQueue; std::list> mFrames; Stream(const Stream&) = delete; Stream& operator=(const Stream&) = delete; }; /////////////////////////////////////////////////////////////////////////////// AmlSwDemux::AmlSwDemux() : mRemainingBytesBuffer(new AmlMpBuffer(kTSPacketSize)) { mRemainingBytesBuffer->setRange(0, 0); } AmlSwDemux::~AmlSwDemux() { close(); } int AmlSwDemux::open(bool isHardwareSource, Aml_MP_DemuxId demuxId, bool isSecureBuffer) { AML_MP_UNUSED(demuxId); AML_MP_UNUSED(isSecureBuffer); if (isHardwareSource) { MLOGE("swdemux don't support hw source!!!"); return -1; } if (mTsParser == nullptr) { mTsParser = new SwTsParser([this](int pid, const sptr& data, int version) { return notifyData(pid, data, version); }); } return 0; } int AmlSwDemux::close() { flush(); if (mLooper != nullptr) { mLooper->unregisterHandler(mHandler->id()); mLooper->stop(); mLooper.clear(); } if (mDumpFd >= 0) { MLOGI("close dumpfd %d", mDumpFd); ::close(mDumpFd); mDumpFd = -1; } return 0; } int AmlSwDemux::start() { #if 0 if (mDumpFd < 0) { MLOGI("open dump swdemux file!"); mDumpFd = ::open("/data/dump_swdemux.ts", O_CREAT | O_WRONLY | O_TRUNC, 0644); if (mDumpFd < 0) { MLOGE("open dump file filed!"); } } #endif if (mHandler == nullptr) { mHandler = new AmlMpEventHandlerReflector(this); } if (mLooper == nullptr) { mLooper = new AmlMpEventLooper; mLooper->setName("swDemux"); mLooper->registerHandler(mHandler); int ret = mLooper->start(); MLOGI("start swDemux looper, ret = %d", ret); } return 0; } int AmlSwDemux::stop() { if (mStopped) { return 0; } mStopped = true; return 0; } int AmlSwDemux::flush() { ++mBufferGeneration; sptr msg = new AmlMpMessage(kWhatFlush, mHandler); sptr response; msg->postAndAwaitResponse(&response); MLOG(); return 0; } int AmlSwDemux::feedTs(const uint8_t* buffer, size_t size) { if (mStopped) { return -1; } sptr data = new AmlMpBuffer((void*)buffer, size); data->setRange(0, size); sptr msg = new AmlMpMessage(kWhatFeedData, mHandler); msg->setBuffer("buffer", data); msg->setInt32("generation", mBufferGeneration); sptr response; msg->postAndAwaitResponse(&response); if (mDumpFd >= 0) { if (::write(mDumpFd, buffer, size) != (int)size) { MLOGE("write dump file failed!!!"); } } return size; } int AmlSwDemux::addDemuxFilter(int pid, const Aml_MP_DemuxFilterParams* params) { sptr msg = new AmlMpMessage(kWhatAddPid, mHandler); msg->setInt32("pid", pid); msg->setInt32("type", params->type); msg->setInt32("codec-type", params->codecType); msg->setInt32("flags", params->flags); msg->post(); return 0; } int AmlSwDemux::removeDemuxFilter(int pid) { sptr msg = new AmlMpMessage(kWhatRemovePid, mHandler); msg->setInt32("pid", pid); msg->post(); return 0; } bool AmlSwDemux::isStopped() const { return mStopped.load(std::memory_order_relaxed); } void AmlSwDemux::onMessageReceived(const sptr& msg) { switch (msg->what()) { case kWhatFeedData: { sptr data; AML_MP_CHECK(msg->findBuffer("buffer", &data)); sptr replyID; AML_MP_CHECK(msg->senderAwaitsResponse(&replyID)); int32_t generation; AML_MP_CHECK(msg->findInt32("generation", &generation)); sptr response = new AmlMpMessage; if (generation != mBufferGeneration) { MLOGW("kWhatFeedData break, %d %d", generation, mBufferGeneration.load()); } else { onFeedData(data); } response->postReply(replyID); } break; case kWhatAddPid: { int pid = AML_MP_INVALID_PID; Aml_MP_DemuxFilterParams params; msg->findInt32("pid", &pid); msg->findInt32("type", (int32_t*)¶ms.type); msg->findInt32("codec-type", (int32_t*)¶ms.codecType); msg->findInt32("flags", (int32_t*)¶ms.flags); onAddFilterPid(pid, ¶ms); } break; case kWhatRemovePid: { int pid = AML_MP_INVALID_PID; msg->findInt32("pid", &pid); onRemoveFilterPid(pid); } break; case kWhatFlush: { onFlush(); sptr replyID; AML_MP_CHECK(msg->senderAwaitsResponse(&replyID)); sptr response = new AmlMpMessage; response->postReply(replyID); } break; default: AML_MP_TRESPASS(); break; } } void AmlSwDemux::onFeedData(const sptr& entry) { int err = 0; if (mRemainingBytesBuffer->size() > 0) { //CHECK_LE(mRemainingBytesBuffer->size(), kTSPacketSize); size_t paddingSize = kTSPacketSize - mRemainingBytesBuffer->size(); size_t copySize = paddingSize < entry->size() ? paddingSize : entry->size(); memcpy(mRemainingBytesBuffer->data() + mRemainingBytesBuffer->size(), entry->data(), copySize); mRemainingBytesBuffer->setRange(mRemainingBytesBuffer->offset(), mRemainingBytesBuffer->size() + copySize); entry->setRange(entry->offset() + copySize, entry->size() - copySize); if (mRemainingBytesBuffer->size() == kTSPacketSize) { err = mTsParser->feedTs(mRemainingBytesBuffer->data(), kTSPacketSize); if (err != 0) { const uint8_t* p = mRemainingBytesBuffer->data(); MLOGI("%d %" PRId64 ", feedTSPacket err:%d, %#x, %#x, %#x, %#x, %#x", __LINE__, mOutBufferCount.load(), err, p[0], p[1], p[2], p[3], p[4]); } mRemainingBytesBuffer->setRange(0, 0); } } while (entry->size() > 0) { if (entry->size() < kTSPacketSize) { if (*entry->data() == 0x47) { memcpy(mRemainingBytesBuffer->data(), entry->data(), entry->size()); mRemainingBytesBuffer->setRange(mRemainingBytesBuffer->offset(), mRemainingBytesBuffer->size() + entry->size()); } else { MLOGW("left data doesn't start with 0x47, discard it!"); } break; } if (*entry->data() != 0x47) { MLOGI("mOutBufferCount:%" PRId64 ", entry start bytes:%#x, offset:%zu, size:%zu", mOutBufferCount.load(), *entry->data(), entry->offset(), entry->size()); //const uint8_t* p = entry->data(); //MLOGV("entry bytes: %#x %#x %#x %#x %#x", p[0], p[1], p[2], p[3], p[4]); err = resync(entry); if (err < 0) { MLOGE("resync ts buffer failed! %d, size:%zu", err, entry->size()); return; } else { MLOGV("resync add offset:%d", err); continue; } } err = mTsParser->feedTs(entry->data(), kTSPacketSize); if (err != 0) { MLOGE("%d feedTSPacket failed, err:%d", __LINE__, err); } entry->setRange(entry->offset() + kTSPacketSize, entry->size() - kTSPacketSize); } } int AmlSwDemux::resync(const sptr& buffer) { const uint8_t* p = buffer->data(); size_t size = buffer->size(); if (p == nullptr || size < kTSPacketSize) return -1; bool synced = false; size_t offset = 0; while (offset < size) { if (p[offset] != 0x47) { ++offset; continue; } if (offset + kTSPacketSize < size) { if (p[offset + kTSPacketSize] != 0x47) { ++offset; MLOGV("next ts packet header check failed, try sync again..."); continue; } } synced = true; break; } if (synced) { buffer->setRange(buffer->offset() + offset, buffer->size() - offset); return offset; } return -1; } void AmlSwDemux::onFlush() { mOutBufferCount = 0; if (mTsParser != nullptr) { mTsParser->reset(); } mRemainingBytesBuffer->setRange(0, 0); } void AmlSwDemux::onAddFilterPid(int pid, Aml_MP_DemuxFilterParams* params) { if (mTsParser != nullptr) { MLOGI("add filter pid:%d(%#x)", pid, pid); mTsParser->addDemuxFilter(pid, params); } } void AmlSwDemux::onRemoveFilterPid(int pid) { if (mTsParser != nullptr) { MLOGI("remove filter pid:%d(%#x)", pid, pid); mTsParser->removeDemuxFilter(pid); } } /////////////////////////////////////////////////////////////////////////////// SwTsParser::SwTsParser(const std::function& cb) : ITsParser(cb) { MLOG(); mPSISections.emplace(0 /* PID */, new PSISection(0, this)); mPSISections.emplace(1 /* PID */, new PSISection(1, this)); initCrcTable(); } SwTsParser::~SwTsParser() { MLOG(); } void SwTsParser::initCrcTable() { #if 0 uint32_t poly = 0x04C11DB7; for (int i = 0; i < 256; i++) { uint32_t crc = i << 24; for (int j = 0; j < 8; j++) { crc = (crc << 1) ^ ((crc & 0x80000000) ? (poly) : 0); } mCrcTable[i] = crc; } #endif for (uint32_t i = 0; i < 256; i++) { uint32_t k = 0; for (uint32_t j = (i << 24) | 0x800000; j != 0x80000000; j <<= 1) { k = (k << 1) ^ (((k ^ j) & 0x80000000) ? 0x04c11db7 : 0); } mCrcTable[i] = k; } } /** * Compute CRC32 checksum for buffer starting at offset start and for length * bytes. */ uint32_t SwTsParser::crc32(const uint8_t *p_start, size_t length) { #if 0 uint32_t crc = 0xFFFFFFFF; const uint8_t *p; for (p = p_start; p < p_start + length; p++) { crc = (crc << 8) ^ mCrcTable[((crc >> 24) ^ *p) & 0xFF]; } return crc; #endif uint32_t crc32_reg = 0xFFFFFFFF; for (uint32_t i = 0; i < length; i++) { //coverity[overflow_const] crc32_reg = (crc32_reg << 8) ^ mCrcTable[((crc32_reg >> 24) ^ *p_start++) & 0xFF]; } return crc32_reg; } int SwTsParser::feedTs(const uint8_t* buffer, size_t size) { AML_MP_UNUSED(size); //CHECK_EQ(size, kTSPacketSize); AmlMpBitReader br(buffer, kTSPacketSize); return parseTS(&br); } void SwTsParser::reset() { MLOG(); //for (size_t i = 0; i < mPSISections.size(); ++i) { //sptr &p = mPSISections.editValueAt(i); //p->clear(); //} for (auto& p : mPSISections) { p.second->clear(); } } int SwTsParser::addDemuxFilter(int pid, const Aml_MP_DemuxFilterParams* params) { if (pid == 0x1FFF) return -1; if (params->type == AML_MP_DEMUX_FILTER_PSI) { if (mPSISections.find(pid) == mPSISections.end()) { MLOGW("add section pid:%d(%#x)", pid, pid); mPSISections.emplace(pid, new PSISection(pid, this)); } } else { if (mStreams.find(pid) == mStreams.end()) { MLOGW("add pes filter:%d(%#x)", pid, pid); mStreams.emplace(pid, new Stream(pid, params)); } } return 0; } void SwTsParser::removeDemuxFilter(int pid) { if (pid == 0x1FFF) return; if (mPSISections.find(pid) != mPSISections.end()) { MLOGW("remove section pid:%d(%#x)", pid, pid); mPSISections.erase(pid); } else if (mStreams.find(pid) != mStreams.end()) { MLOGW("remove pes pid:%d(%#x)", pid, pid); mStreams.erase(pid); } } void SwTsParser::parseAdaptationField(AmlMpBitReader *br, unsigned PID) { unsigned adaptation_field_length = br->getBits(8); if (adaptation_field_length > 0) { unsigned discontinuity_indicator = br->getBits(1); if (discontinuity_indicator) { MLOGV("PID 0x%04x: discontinuity_indicator = 1 (!!!)", PID); } br->skipBits(2); unsigned PCR_flag = br->getBits(1); size_t numBitsRead = 4; if (PCR_flag && (mPcrPid == 0x1FFF || mPcrPid == (int)PID)) { br->skipBits(4); uint64_t PCR_base = br->getBits(32); //coverity[assigned_value] PCR_base = (PCR_base << 1) | br->getBits(1); //PCR_base = recoverPTS(PCR_base, mLastRecoveredPCR); br->skipBits(6); unsigned PCR_ext = br->getBits(9); (void)PCR_ext; // The number of bytes from the start of the current // MPEG2 transport stream packet up and including // the final byte of this PCR_ext field. //size_t byteOffsetFromStartOfTSPacket = //(188 - br->numBitsLeft() / 8); //int64_t PCR = PCR_base * 300 + PCR_ext; //MLOGV("PID 0x%04x: PCR = 0x%016" PRIx64 " (%.2f)", //PID, PCR, PCR / 27E6); // The number of bytes received by this parser up to and // including the final byte of this PCR_ext field. //size_t byteOffsetFromStart = //mNumTSPacketsParsed * 188 + byteOffsetFromStartOfTSPacket; //for (size_t i = 0; i < mPrograms.size(); ++i) { //updatePCR(PID, PCR, byteOffsetFromStart); //} numBitsRead += 52; } //CHECK_GE(adaptation_field_length * 8, numBitsRead); br->skipBits(adaptation_field_length * 8 - numBitsRead); } } int SwTsParser::parseTS(AmlMpBitReader *br) { MLOGV("---"); unsigned sync_byte = br->getBits(8); if (sync_byte != 0x47u) { MLOGE("[error] parseTS: return error as sync_byte=0x%x", sync_byte); return -EINVAL; } if (br->getBits(1)) { // transport_error_indicator // silently ignore. return 0; } unsigned payload_unit_start_indicator = br->getBits(1); MLOGV("payload_unit_start_indicator = %u", payload_unit_start_indicator); MY_LOGV("transport_priority = %u", br->getBits(1)); unsigned PID = br->getBits(13); MLOGV("PID = 0x%04x", PID); MY_LOGV("transport_scrambling_control = %u", br->getBits(2)); unsigned adaptation_field_control = br->getBits(2); MLOGV("adaptation_field_control = %u", adaptation_field_control); unsigned continuity_counter = br->getBits(4); MLOGV("PID = 0x%04x, continuity_counter = %u", PID, continuity_counter); // MLOGI("PID = 0x%04x, continuity_counter = %u", PID, continuity_counter); if (adaptation_field_control == 2 || adaptation_field_control == 3) { parseAdaptationField(br, PID); } int err = 0; if (adaptation_field_control == 1 || adaptation_field_control == 3) { err = parsePID( br, PID, continuity_counter, payload_unit_start_indicator); } ++mNumTSPacketsParsed; return err; } void SwTsParser::parseProgramAssociationTable(AmlMpBitReader *br) { unsigned table_id = br->getBits(8); MLOGV(" table_id = %u", table_id); if (table_id != 0x00u) { MLOGE("PAT data error!"); return ; } unsigned section_syntax_indictor = br->getBits(1); MY_LOGV(" section_syntax_indictor = %u", section_syntax_indictor); //CHECK_EQ(section_syntax_indictor, 1u); //CHECK_EQ(br->getBits(1), 0u); (br->getBits(1), 0u); MY_LOGV(" reserved = %u", br->getBits(2)); unsigned section_length = br->getBits(12); MLOGV(" section_length = %u", section_length); //CHECK_EQ(section_length & 0xc00, 0u); MY_LOGV(" transport_stream_id = %u", br->getBits(16)); MY_LOGV(" reserved = %u", br->getBits(2)); MY_LOGV(" version_number = %u", br->getBits(5)); MY_LOGV(" current_next_indicator = %u", br->getBits(1)); MY_LOGV(" section_number = %u", br->getBits(8)); MY_LOGV(" last_section_number = %u", br->getBits(8)); // Coverity fix: prevent integer underflow when section_length is too small if (section_length < 9) { // 5 bytes header + 4 bytes CRC MLOGE("Invalid section_length %u, must be at least 9", section_length); return; } size_t numProgramBytes = (section_length - 5 /* header */ - 4 /* crc */); //CHECK_EQ((numProgramBytes % 4), 0u); for (size_t i = 0; i < numProgramBytes / 4; ++i) { unsigned program_number = br->getBits(16); MLOGV(" program_number = %u", program_number); MY_LOGV(" reserved = %u", br->getBits(3)); if (program_number == 0) { MY_LOGV(" network_PID = 0x%04x", br->getBits(13)); } else { unsigned programMapPID = br->getBits(13); MLOGV(" program_map_PID = 0x%04x, %d", programMapPID, programMapPID); if (mProgramMapPID == 0x1FFF) { MLOGE("first update programMapPID:%d", programMapPID); } mProgramMapPID = programMapPID; bool found = false; for (size_t index = 0; index < mPrograms.size(); ++index) { const sptr &program = mPrograms.at(index); if (program->number() == program_number) { program->updateProgramMapPID(programMapPID); found = true; break; } } if (!found) { mPrograms.push_back( new Program(this, program_number, programMapPID)); } if (mPSISections.find(programMapPID) == mPSISections.end()) { mPSISections.emplace(programMapPID, new PSISection(programMapPID, this)); } } } MY_LOGV(" CRC = 0x%08x", br->getBits(32)); } int SwTsParser::parsePID( AmlMpBitReader *br, unsigned PID, unsigned continuity_counter, unsigned payload_unit_start_indicator) { auto sectionIndex = mPSISections.find(PID); if (sectionIndex != mPSISections.end()) { sptr section = mPSISections.at(PID); if (!section->parse(PID, continuity_counter, payload_unit_start_indicator, br)) { MLOGW("pre parse failed!!!! PID = %d", PID); return 0; } AML_MP_CHECK((br->numBitsLeft() % 8) == 0); int err = section->append(br->data(), br->numBitsLeft() / 8); if (err != 0) { MLOGW("section append data %zu size failed!", br->numBitsLeft()/8); return err; } if (!section->isComplete()) { return 0; } AmlMpBitReader sectionBits2(section->data(), section->size()); bool notifyListener = true; err = section->parseSection(§ionBits2); if (err != ERROR_SIZE) { section->setRange(0, section->sectionLength()); } if (err != 0) { notifyListener = false; MLOGE("parse failed:%d, section pid:%d, buffer size:%zu, section length:%zu", err, PID, section->size(), section->sectionLength()); #if 0 // MLOGE("Dump data:"); hexdump(section->data(), std::min(section->size(), (size_t)184)); char path[50]; sprintf(path, "/data/crc_err_%d.bin", PID); int fd = ::open(path, O_RDONLY); if (fd < 0) { MLOGI("dump to %s", path); FILE* fp = fopen(path, "w"); if (fp == NULL) { MLOGE("open %s failed!", path); } else { fwrite(section->data(), 1, section->size(), fp); fclose(fp); } } else { ::close(fd); } // #endif #if 0 if (err == ERROR_CRC) { notifyListener = true; MLOGW("crc error ignored!"); } #endif } else { MLOGV("section pid:%d, set range:%zu", PID, section->sectionLength()); //section->setRange(0, section->sectionLength()); } if (section != NULL) { if (notifyListener) { int version = section->needCheckVersionChange() ? section->sectionVersion() : -1; mFilterCallback(PID, section->rawBuffer(), version); } //section->clear(); } AmlMpBitReader sectionBits(section->data(), section->size()); if (PID == 0) { parseProgramAssociationTable(§ionBits); } else { #if 0 bool handled = false; for (size_t i = 0; i < mPrograms.size(); ++i) { status_t err; if (!mPrograms.editItemAt(i)->parsePSISection( PID, §ionBits, &err)) { continue; } if (err != 0) { return err; } handled = true; break; } if (!handled) { //mPSISections.removeItem(PID); //section.clear(); } #endif } if (section != NULL) { section->clear(); } return 0; } auto streamIndex = mStreams.find(PID); if (streamIndex != mStreams.end()) { sptr stream = streamIndex->second; int err = stream->parse(continuity_counter, payload_unit_start_indicator, br); if (err != 0) { return err; } sptr buffer; while ((buffer = stream->dequeueFrame()) != nullptr) { mFilterCallback(PID, buffer, -1); } } return 0; } //////////////////////////////////////////////////////////////////////////////// static inline uint16_t U16_AT(const uint8_t *ptr) { return ptr[0] << 8 | ptr[1]; } SwTsParser::PSISection::PSISection(int pid, SwTsParser* tsParser) : mPid(pid) , mTsParser(tsParser) { } SwTsParser::PSISection::~PSISection() { } int SwTsParser::PSISection::append(const void *data, size_t size) { if (mBuffer == NULL || mBuffer->size() + size > mBuffer->capacity()) { size_t newCapacity = (mBuffer == NULL) ? size : mBuffer->capacity() + size; newCapacity = (newCapacity + 1023) & ~1023; sptr newBuffer = new AmlMpBuffer(newCapacity); if (mBuffer != NULL) { memcpy(newBuffer->data(), mBuffer->data(), mBuffer->size()); newBuffer->setRange(0, mBuffer->size()); } else { newBuffer->setRange(0, 0); } mBuffer = newBuffer; } memcpy(mBuffer->data() + mBuffer->size(), data, size); mBuffer->setRange(0, mBuffer->size() + size); return 0; } void SwTsParser::PSISection::clear() { if (mBuffer != NULL) { mBuffer->setRange(0, 0); } mChanged = false; } bool SwTsParser::PSISection::isComplete() const { if (mBuffer == NULL || mBuffer->size() < 3) { return false; } unsigned sectionLength = U16_AT(mBuffer->data() + 1) & 0xfff; if (sectionLength > 4093) { MLOGE("section size error:%d", sectionLength); return true; } return mBuffer->size() >= sectionLength + 3; } bool SwTsParser::PSISection::isEmpty() const { return mBuffer == NULL || mBuffer->size() == 0; } const uint8_t *SwTsParser::PSISection::data() const { return mBuffer == NULL ? NULL : mBuffer->data(); } size_t SwTsParser::PSISection::size() const { return mBuffer == NULL ? 0 : mBuffer->size(); } void SwTsParser::PSISection::setRange(size_t offset, size_t length) { if (mBuffer == nullptr || mBuffer->capacity() < length) { MLOGE("section setRange failed! length:%zu", length); return; } mBuffer->setRange(offset, length); } size_t SwTsParser::PSISection::sectionLength() const { if (mBuffer == NULL || mBuffer->size() < 3) { return 0; } unsigned sectionLength = U16_AT(mBuffer->data() + 1) & 0xfff; return sectionLength + 3; } bool SwTsParser::PSISection::needCheckVersionChange() { int pid = mPid; int programMapPID = mTsParser->programMapPID(); return pid == 0 || pid == 1 || (programMapPID!=0x1FFF && programMapPID==pid); } int SwTsParser::PSISection::sectionVersion() const { auto index = mSectionVersions.find(0); if (index == mSectionVersions.end()) return -1; int version = mSectionVersions.at(0); return version; } bool SwTsParser::PSISection::parse(int PID, unsigned continuity_counter, unsigned payload_unit_start_indicator, AmlMpBitReader *br) { (void)PID; (void)continuity_counter; #if 0 if (mExpectedContinuityCounter >= 0 && (unsigned)mExpectedContinuityCounter != continuity_counter) { MLOGW("section discontinuity on stream pid 0x%04x(%d)", PID, PID); mPayloadStarted = false; mBuffer->setRange(0, 0); mExpectedContinuityCounter = -1; if (!payload_unit_start_indicator) { return false; } } mExpectedContinuityCounter = (continuity_counter + 1) & 0x0f; #endif if (payload_unit_start_indicator) { // Otherwise we run the danger of receiving the trailing bytes // of a section packet that we never saw the start of and assuming // we have a a complete section packet. if (!isEmpty()) { MLOGW("parsePID encounters payload_unit_start_indicator when section is not empty"); clear(); } unsigned skip = br->getBits(8); if (skip > 0) { MLOGW("skip %d bytes!", skip); } br->skipBits(skip * 8); mPayloadStarted = true; } if (!mPayloadStarted) { return false; } return true; } int SwTsParser::PSISection::parseSection(AmlMpBitReader* br) { unsigned table_id = br->getBits(8); MY_LOGV(" table_id = %u", table_id); unsigned section_syntax_indicator = br->getBits(1); MY_LOGV(" section_syntax_indicator = %u", section_syntax_indicator); unsigned private_indicator = br->getBits(1); if ((section_syntax_indicator ^ private_indicator) != 1) { if (!mGuessed) { MLOGW("HAVE DSM-CC data!!!"); } mGuessed = true; } MY_LOGV(" reserved = %u", br->getBits(2)); unsigned section_length = br->getBits(12); MLOGV(" section_length = %u", section_length); //CHECK_EQ(section_length & 0xc00, 0u); //CHECK_LE(section_length, 4093u); if (section_length > 4093) { return ERROR_SIZE; } if (section_syntax_indicator) { br->skipBits(18); int versionNumber = br->getBits(5); MY_LOGV(" version_number = %u", versionNumber); //MY_LOGV(" version_number = %u", br->getBits(5)); MY_LOGV(" current_next_indicator = %u", br->getBits(1)); int sectionNumber = br->getBits(8); MY_LOGV(" section_number = %u", sectionNumber); MY_LOGV(" last_section_number = %u", br->getBits(8)); if (needCheckVersionChange()) { auto index = mSectionVersions.find(sectionNumber); if (index == mSectionVersions.end()) { mChanged = true; mSectionVersions.emplace(sectionNumber, versionNumber); MLOGE("section FIRST changed, PID:%d, sectionNumber:%d, versionNumber:%d", mPid, sectionNumber, versionNumber); } else { int &lastVersionNumber = mSectionVersions.at(sectionNumber); if (lastVersionNumber != versionNumber) { MLOGE("section changed, PID:%d, sectionNumber:%d, versionNumber:%d, lastVersionNumber:%d", mPid, sectionNumber, versionNumber, lastVersionNumber); mChanged = true; lastVersionNumber = versionNumber; } } } uint32_t crc = mTsParser->crc32(mBuffer->data(), section_length + 3); if (crc != 0) { MLOGE("crc error: %#x", crc); return ERROR_CRC; } } return 0; } //////////////////////////////////////////////////////////////////////////////// static const size_t kInitialStreamBufferSize = 1 * 1024 * 1024; SwTsParser::Stream::Stream(int pid, const Aml_MP_DemuxFilterParams* params) { mPid = pid; mCodecType = params->codecType; mType = params->type; mFlags = params->flags; ElementaryStreamQueue::Mode mode = ElementaryStreamQueue::INVALID; switch (mCodecType) { case AML_MP_VIDEO_CODEC_H264: mode = ElementaryStreamQueue::H264; break; case AML_MP_VIDEO_CODEC_HEVC: mode = ElementaryStreamQueue::H265; break; case AML_MP_AUDIO_CODEC_AAC: mode = ElementaryStreamQueue::AAC; break; case AML_MP_AUDIO_CODEC_MP2: case AML_MP_AUDIO_CODEC_MP3: mode = ElementaryStreamQueue::MPEG_AUDIO; break; case AML_MP_VIDEO_CODEC_MPEG12: mode = ElementaryStreamQueue::MPEG_VIDEO; break; case AML_MP_VIDEO_CODEC_MPEG4: mode = ElementaryStreamQueue::MPEG4_VIDEO; break; case AML_MP_AUDIO_CODEC_AC3: mode = ElementaryStreamQueue::AC3; break; case AML_MP_AUDIO_CODEC_EAC3: mode = ElementaryStreamQueue::EAC3; break; default: ALOGE("stream PID 0x%02x has invalid codec type %s", mPid, mpCodecId2Str(mCodecType)); return; } mQueue = new ElementaryStreamQueue(mode); mBuffer = new AmlMpBuffer(kInitialStreamBufferSize); mBuffer->setRange(0, 0); } int SwTsParser::Stream::parse(unsigned continuity_counter, unsigned payload_unit_start_indicator, AmlMpBitReader* br) { if (mExpectedContinuityCounter >= 0 && (unsigned)mExpectedContinuityCounter != continuity_counter) { MLOGI("discontinuity on stream pid 0x%04x, continuity_counter:%u", mPid, continuity_counter); mPayloadStarted = false; mBuffer->setRange(0, 0); mExpectedContinuityCounter = -1; if (!payload_unit_start_indicator) { return 0; } } mExpectedContinuityCounter = (continuity_counter + 1) & 0x0f; if (payload_unit_start_indicator) { if (mPayloadStarted) { int err = flush(); if (err != 0) { MLOGW("Error (%08x) happened while flushing; we simply discard " "the PES packet and continue.", err); } } mPayloadStarted = true; } if (!mPayloadStarted) { return 0; } size_t payloadSizeBits = br->numBitsLeft(); if (payloadSizeBits % 8 != 0u) { MLOGE("wrong value!"); return -1; } size_t neededSize = mBuffer->size() + payloadSizeBits/8; if (mBuffer == nullptr || neededSize > mBuffer->capacity()) { neededSize = (neededSize + 65535) & ~65535; sptr newBuffer = new AmlMpBuffer(neededSize); if (mBuffer != nullptr) { memcpy(newBuffer->data(), mBuffer->data(), mBuffer->size()); newBuffer->setRange(0, mBuffer->size()); } else { newBuffer->setRange(0, 0); } mBuffer = newBuffer; } memcpy(mBuffer->data() + mBuffer->size(), br->data(), payloadSizeBits / 8); mBuffer->setRange(0, mBuffer->size() + payloadSizeBits / 8); return 0; } int SwTsParser::Stream::flush() { int err = 0; if (mBuffer == nullptr || mBuffer->size() == 0) { return 0; } #if 0 std::string result; hexdump(mBuffer->data(), std::min(mBuffer->size(), (size_t)16), result); MLOGI("flush:%s", result.c_str()); #endif AmlMpBitReader br(mBuffer->data(), mBuffer->size()); err = parsePES(&br); mBuffer->setRange(0, 0); return err; } int SwTsParser::Stream::parsePES(AmlMpBitReader* br) { const uint8_t* basePtr = br->data(); unsigned packet_startcode_prefix = br->getBits(24); if (packet_startcode_prefix != 1) { MLOGE("Supposedly payload_unit_start=1 unit does not start " "with startcode."); return -1; } unsigned stream_id = br->getBits(8); MLOGV("stream_id = 0x%02x", stream_id); unsigned PES_packet_length = br->getBits(16); MLOGV("PES_packet_length = %u", PES_packet_length); if (stream_id != 0xbc // program_stream_map && stream_id != 0xbe // padding_stream && stream_id != 0xbf // private_stream_2 && stream_id != 0xf0 // ECM && stream_id != 0xf1 // EMM && stream_id != 0xff // program_stream_directory && stream_id != 0xf2 // DSMCC && stream_id != 0xf8) { // H.222.1 type E if (br->getBits(2) != 2u) { return -1; } unsigned PES_scrambling_control = br->getBits(2); MLOGV("PES_scrambling_control = %u", PES_scrambling_control); MY_LOGV("PES_priority = %u", br->getBits(1)); MY_LOGV("data_alignment_indicator = %u", br->getBits(1)); MY_LOGV("copyright = %u", br->getBits(1)); MY_LOGV("original_or_copy = %u", br->getBits(1)); unsigned PTS_DTS_flags = br->getBits(2); ALOGV("PTS_DTS_flags = %u", PTS_DTS_flags); unsigned ESCR_flag = br->getBits(1); ALOGV("ESCR_flag = %u", ESCR_flag); unsigned ES_rate_flag = br->getBits(1); ALOGV("ES_rate_flag = %u", ES_rate_flag); unsigned DSM_trick_mode_flag = br->getBits(1); ALOGV("DSM_trick_mode_flag = %u", DSM_trick_mode_flag); unsigned additional_copy_info_flag = br->getBits(1); ALOGV("additional_copy_info_flag = %u", additional_copy_info_flag); MY_LOGV("PES_CRC_flag = %u", br->getBits(1)); MY_LOGV("PES_extension_flag = %u", br->getBits(1)); unsigned PES_header_data_length = br->getBits(8); ALOGV("PES_header_data_length = %u", PES_header_data_length); unsigned optional_bytes_remaining = PES_header_data_length; uint64_t PTS = 0, DTS = 0; if (PTS_DTS_flags == 2 || PTS_DTS_flags == 3) { if (optional_bytes_remaining < 5u) { return -1; } if (br->getBits(4) != PTS_DTS_flags) { return -1; } PTS = ((uint64_t)br->getBits(3)) << 30; if (br->getBits(1) != 1u) { return -1; } PTS |= ((uint64_t)br->getBits(15)) << 15; if (br->getBits(1) != 1u) { return -1; } PTS |= br->getBits(15); if (br->getBits(1) != 1u) { return -1; } ALOGV("(%d) PTS = 0x%016" PRIx64 " (%.2f)", mPid, PTS, PTS / 90000.0); optional_bytes_remaining -= 5; if (PTS_DTS_flags == 3) { if (optional_bytes_remaining < 5u) { return -1; } if (br->getBits(4) != 1u) { return -1; } DTS = ((uint64_t)br->getBits(3)) << 30; if (br->getBits(1) != 1u) { return -1; } DTS |= ((uint64_t)br->getBits(15)) << 15; if (br->getBits(1) != 1u) { return -1; } DTS |= br->getBits(15); if (br->getBits(1) != 1u) { return -1; } ALOGV("DTS = %" PRIu64, DTS); optional_bytes_remaining -= 5; } } if (ESCR_flag) { if (optional_bytes_remaining < 6u) { return -1; } br->getBits(2); uint64_t ESCR = ((uint64_t)br->getBits(3)) << 30; if (br->getBits(1) != 1u) { return -1; } ESCR |= ((uint64_t)br->getBits(15)) << 15; if (br->getBits(1) != 1u) { return -1; } ESCR |= br->getBits(15); if (br->getBits(1) != 1u) { return -1; } ALOGV("ESCR = %" PRIu64, ESCR); MY_LOGV("ESCR_extension = %u", br->getBits(9)); if (br->getBits(1) != 1u) { return -1; } optional_bytes_remaining -= 6; } if (ES_rate_flag) { if (optional_bytes_remaining < 3u) { return -1; } if (br->getBits(1) != 1u) { return -1; } MY_LOGV("ES_rate = %u", br->getBits(22)); if (br->getBits(1) != 1u) { return -1; } optional_bytes_remaining -= 3; } br->skipBits(optional_bytes_remaining * 8); // ES data follows. int32_t pesOffset = br->data() - basePtr; if (PES_packet_length != 0) { if (PES_packet_length < PES_header_data_length + 3) { return -1; } unsigned dataLength = PES_packet_length - 3 - PES_header_data_length; if (br->numBitsLeft() < dataLength * 8) { ALOGE("PES packet does not carry enough data to contain " "payload. (numBitsLeft = %zu, required = %u)", br->numBitsLeft(), dataLength * 8); return -1; } ALOGV("There's %u bytes of payload, PES_packet_length=%u, offset=%d", dataLength, PES_packet_length, pesOffset); onPayloadData( PTS_DTS_flags, PTS, DTS, br->data(), dataLength, pesOffset); br->skipBits(dataLength * 8); } else { onPayloadData( PTS_DTS_flags, PTS, DTS, br->data(), br->numBitsLeft() / 8, pesOffset); size_t payloadSizeBits = br->numBitsLeft(); if (payloadSizeBits % 8 != 0u) { return -1; } ALOGV("There's %zu bytes of payload, offset=%d", payloadSizeBits / 8, pesOffset); } } else if (stream_id == 0xbe) { // padding_stream if (PES_packet_length == 0u) { return -1; } br->skipBits(PES_packet_length * 8); } else { if (PES_packet_length == 0u) { return -1; } br->skipBits(PES_packet_length * 8); } return 0; } void SwTsParser::Stream::onPayloadData(unsigned PTS_DTS_flags __unused, uint64_t PTS, uint64_t DTS __unused, const uint8_t* data, size_t size, int32_t payloadOffset) { int err = mQueue->appendData(data, size, PTS, payloadOffset); if (err != 0) { MLOGE("append data failed!"); return; } sptr accessUnit; while ((accessUnit = mQueue->dequeueAccessUnit()) != nullptr) { mFrames.push_back(accessUnit); } } sptr SwTsParser::Stream::dequeueFrame() { sptr accessUnit; if (mFrames.empty()) { return nullptr; } accessUnit = *mFrames.begin(); mFrames.pop_front(); return accessUnit; } }