/* * 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: */ #ifndef _AML_TS_PARSER_H_ #define _AML_TS_PARSER_H_ #include #include #include #include #include #include #include #include #include namespace aml_mp { class AmlDemuxBase; typedef enum { SCRAMBLE_ALGO_CSA, SCRAMBLE_ALGO_AES, SCRAMBLE_ALGO_INVALID, SCRAMBLE_ALGO_NONE } SCRAMBLE_ALGO_t; typedef enum { SCRAMBLE_MODE_ECB, SCRAMBLE_MODE_CBC, SCRAMBLE_MODE_INVALID } SCRAMBLE_MODE_t; typedef enum { SCRAMBLE_ALIGNMENT_LEFT, SCRAMBLE_ALIGNMENT_RIGHT, SCRAMBLE_ALIGNMENT_INVALID } SCRAMBLE_ALIGNMENT_t; typedef enum { TYPE_AUDIO, TYPE_VIDEO, TYPE_SUBTITLE, TYPE_INVALID } STREAM_TYPE_t; typedef struct SCRAMBLE_INFO_s { SCRAMBLE_ALGO_t algo; SCRAMBLE_MODE_t mode; SCRAMBLE_ALIGNMENT_t alignment; uint8_t has_iv_value; uint8_t iv_value_data[16]; } SCRAMBLE_INFO_t; struct StreamInfo { STREAM_TYPE_t type = TYPE_INVALID; int pid = AML_MP_INVALID_PID; Aml_MP_CodecID codecId = AML_MP_CODEC_UNKNOWN; int compositionPageId = -1; int ancillaryPageId = -1; // teletext subtitle params int magazine = -1; int page = -1; }; struct PMTInfo { int programNumber; int pmtPid; }; struct PATSection { //coverity[member_not_init_in_gen_ctor] int version_number; std::vector pmtInfos; }; struct PMTStream { //coverity[member_not_init_in_gen_ctor] int streamPid; //coverity[member_not_init_in_gen_ctor] int streamType; int ecmPid={AML_MP_INVALID_PID}; //es info int descriptorTags[10] = {0}; int descriptorCount = 0; int compositionPageId{}; //dvb subtitle int ancillaryPageId{}; //dvb subtitle int magazine = -1; //teletext subtitle int page = -1; //teletext subtitle bool isAD{false}; }; struct PMTSection { //coverity[member_not_init_in_gen_ctor] int pmtPid; int programNumber; int version_number; int current_next_indicator; int pcrPid = 0x1FFF; bool scrambled = false; int caSystemId = -1; int ecmPid = 0x1FFF; int scrambleAlgorithm = -1; SCRAMBLE_INFO_t scrambleInfo{}; #define PRIVATE_DATA_LENGTH_MAX 256 int privateDataLength = 0; uint8_t privateData[PRIVATE_DATA_LENGTH_MAX] = {0}; int streamCount = 0; std::vector streams; }; struct CATSection { //coverity[member_not_init_in_gen_ctor] int catPid; int caSystemId = -1; int emmPid= 0x1FFF; }; struct ECMSection { int ecmPid; int size; uint8_t* data; }; struct SectionData : public AmlMpRefBase { int pid; int size; uint8_t* data = nullptr; SectionData() { reset(); } SectionData(int pid, int size, uint8_t* data) { init(pid, size, data); } ~SectionData() { reset(); } void init(int pid, int size, uint8_t* data) { this->pid = pid; this->size = size; this->data = new uint8_t[size]; memcpy(this->data, data, size); } void reset() { if (data) { delete[] data; } pid = 0x1FFF; size = 0; data = nullptr; } }; struct ProgramInfo : public AmlMpRefBase { int programNumber = -1; int pmtPid = AML_MP_INVALID_PID; int caSystemId = -1; int emmPid = AML_MP_INVALID_PID; bool scrambled = false; SCRAMBLE_INFO_t scrambleInfo{}; #define PRIVATE_DATA_MAX_LENGTH 256 int privateDataLength; uint8_t privateData[PRIVATE_DATA_MAX_LENGTH]; int serviceIndex = 0; int serviceNum = 0; int ecmPid[3]{AML_MP_INVALID_PID}; #define ECM_INDEX_AUDIO 0 #define ECM_INDEX_VIDEO 1 #define ECM_INDEX_SUB 2 Aml_MP_CodecID audioCodec = AML_MP_CODEC_UNKNOWN; Aml_MP_CodecID videoCodec = AML_MP_CODEC_UNKNOWN; Aml_MP_CodecID subtitleCodec = AML_MP_CODEC_UNKNOWN; Aml_MP_CodecID adCodec = AML_MP_CODEC_UNKNOWN; int audioPid = AML_MP_INVALID_PID; int videoPid = AML_MP_INVALID_PID; int subtitlePid = AML_MP_INVALID_PID; int adPid = AML_MP_INVALID_PID; //coverity[member_not_init_in_gen_ctor] int compositionPageId; int ancillaryPageId; int magazine = -1; int page = -1; std::vector audioStreams; std::vector videoStreams; std::vector subtitleStreams; public: bool isComplete() const { bool hasEcmPid = false; for (size_t i = 0; i < 3; ++i) { if (ecmPid[i] != AML_MP_INVALID_PID) { hasEcmPid = true; break; } } bool hasEmmPid = emmPid != AML_MP_INVALID_PID; return (audioPid != AML_MP_INVALID_PID || videoPid != AML_MP_INVALID_PID) && (!scrambled || (hasEcmPid || hasEmmPid)); } void debugLog() const; }; class Parser : public AmlMpRefBase { public: Parser(Aml_MP_DemuxId demuxId, bool isHardwareSource, Aml_MP_DemuxType demuxType = AML_MP_DEMUX_TYPE_HARDWARE, bool isSecureBuffer = false); ~Parser(); int open(); void selectProgram(int programNumber); void selectProgram(int vPid, int aPid); void parseProgramInfoAsync(); int waitProgramInfoParsed(); int waitCATSectionDataParsed(); sptr parseProgramInfo(); sptr getProgramInfo() const; int addFilter(int pid, Aml_MP_Demux_FilterCb cb, void* userData, const Aml_MP_DemuxFilterParams* params); int removeFilter(int pid); int addSectionFilter(int pid, Aml_MP_Demux_FilterCb cb, void* userData, bool checkCRC = true) { Aml_MP_DemuxFilterParams params; params.type = AML_MP_DEMUX_FILTER_PSI; params.flags = checkCRC; return addFilter(pid, cb, userData, ¶ms); } int removeSectionFilter(int pid) { return removeFilter(pid); } int close(); void signalQuit(); Aml_MP_DemuxId getDemuxId() const { return mDemuxId; } virtual int writeData(const uint8_t* buffer, size_t size); enum ProgramEventType { EVENT_PROGRAM_PARSED, EVENT_PMT_PARSED, EVENT_CAT_PARSED, EVENT_AV_PID_CHANGED, EVENT_ECM_DATA_PARSED }; using ProgramEventCallback = void(ProgramEventType event, int programPid, int param, void* data); void setEventCallback(const std::function& cb); private: struct Section { Section(const uint8_t* buffer_, size_t size_) : buffer(buffer_) , size(size_) { } const uint8_t* data() const { return buffer + bufferIndex; } size_t dataSize() const { return size; } bool empty() const { return size == 0; } const uint8_t* advance(int offset) { bufferIndex += offset; size -= offset; return buffer + bufferIndex; } private: const uint8_t* buffer = nullptr; int size = 0; int bufferIndex = 0; }; struct FilterContext : public AmlMpRefBase { public: FilterContext(int pid) : mPid(pid) { } ~FilterContext() { } int mPid; void* channel = nullptr; void* filter = nullptr; }; void clearAllFilters(); void notifyParseDone_l(); static int patCb(int pid, size_t size, const uint8_t* data, void* userData); static int pmtCb(int pid, size_t size, const uint8_t* data, void* userData); static int catCb(int pid, size_t size, const uint8_t* data, void* userData); static int ecmCb(int pid, size_t size, const uint8_t* data, void* userData); void onPatParsed(const PATSection& results); void onPmtParsed(const SectionData& sectionData, const PMTSection& results); void onCatParsed(const SectionData& sectionData, const CATSection& results); void onEcmParsed(const ECMSection& results); bool checkPidChange(const PMTSection& oldPmt, const PMTSection& newPmt, std::vector *pidChangeInfo); std::function mCb = nullptr; private: int mProgramNumber = -1; int mVPid = AML_MP_INVALID_PID; int mAPid = AML_MP_INVALID_PID; bool mIsHardwareSource = false; Aml_MP_DemuxType mDemuxType = AML_MP_DEMUX_TYPE_HARDWARE; bool mIsSecureBuffer = false; Aml_MP_DemuxId mDemuxId = AML_MP_HW_DEMUX_ID_0; sptr mDemux; sptr mProgramInfo; std::map mPidProgramMap; // map: pid--programNumber std::map mPidPmtMap; // map: pid--pmt std::set mEcmPidSet;// ecmPid mutable std::mutex mLock; std::condition_variable mCond; bool mParseDone = false; bool mCATParseDone = false; //for irdeto , cat seciont is needed std::map> mFilters; //pid, filter std::atomic_bool mRequestQuit{false}; Parser(const Parser&) = delete; Parser& operator=(const Parser&) = delete; }; size_t findEcmPacket(const uint8_t* buffer, size_t size, const std::vector& ecmPids, size_t* ecmSize); } #endif