├── .github └── workflows │ └── c-cpp.yml ├── .gitignore ├── Makefile ├── README.md ├── dantto4k.sln ├── ini └── BonDriver_dantto4k.ini ├── src ├── .gitignore ├── IBonDriver.h ├── IBonDriver2.h ├── acascard.cpp ├── acascard.h ├── accessControlDescriptor.cpp ├── accessControlDescriptor.h ├── adtsConverter.cpp ├── adtsConverter.h ├── applicationMfuDataProcessor.cpp ├── applicationMfuDataProcessor.h ├── aribUtil.cpp ├── aribUtil.h ├── audioMfuDataProcessor.cpp ├── audioMfuDataProcessor.h ├── b24Color.cpp ├── b24Color.h ├── b24ControlSet.h ├── b24SubtitleConvertor.cpp ├── b24SubtitleConvertor.h ├── bonTuner.cpp ├── bonTuner.h ├── caMessage.cpp ├── caMessage.h ├── compressedIPPacket.cpp ├── compressedIPPacket.h ├── config.cpp ├── config.h ├── contentCopyControlDescriptor.cpp ├── contentCopyControlDescriptor.h ├── dantto4k.cpp ├── dantto4k.h ├── dantto4k.vcxproj ├── dantto4k.vcxproj.filters ├── dantto4k_dll.vcxproj ├── dantto4k_dll.vcxproj.filters ├── dataTransmissionMessage.cpp ├── dataTransmissionMessage.h ├── dataUnit.cpp ├── dataUnit.h ├── demuxerHandler.h ├── descriptorConverter.h ├── ecm.cpp ├── ecm.h ├── eventPackageDescriptor.cpp ├── eventPackageDescriptor.h ├── extensionHeaderScrambling.cpp ├── extensionHeaderScrambling.h ├── fragmentAssembler.cpp ├── fragmentAssembler.h ├── hashUtil.h ├── ip.h ├── ipv6.cpp ├── ipv6.h ├── logger.h ├── m2SectionMessage.cpp ├── m2SectionMessage.h ├── m2ShortSectionMessage.cpp ├── m2ShortSectionMessage.h ├── mfuDataProcessorBase.h ├── mfuDataProcessorFactory.cpp ├── mfuDataProcessorFactory.h ├── mhAit.cpp ├── mhAit.h ├── mhApplicationDescriptor.cpp ├── mhApplicationDescriptor.h ├── mhAudioComponentDescriptor.cpp ├── mhAudioComponentDescriptor.h ├── mhBit.cpp ├── mhBit.h ├── mhBroadcasterNameDescriptor.cpp ├── mhBroadcasterNameDescriptor.h ├── mhCaContractInformation.cpp ├── mhCaContractInformation.h ├── mhCdt.cpp ├── mhCdt.h ├── mhContentDescriptor.cpp ├── mhContentDescriptor.h ├── mhDataComponentDescriptor.cpp ├── mhDataComponentDescriptor.h ├── mhEit.cpp ├── mhEit.h ├── mhEventGroupDescriptor.cpp ├── mhEventGroupDescriptor.h ├── mhExtendedEventDescriptor.cpp ├── mhExtendedEventDescriptor.h ├── mhLinkageDescriptor.cpp ├── mhLinkageDescriptor.h ├── mhLogoTransmissionDescriptor.cpp ├── mhLogoTransmissionDescriptor.h ├── mhParentalRatingDescriptor.cpp ├── mhParentalRatingDescriptor.h ├── mhSdt.cpp ├── mhSdt.h ├── mhSeriesDescriptor.cpp ├── mhSeriesDescriptor.h ├── mhServiceDescriptor.cpp ├── mhServiceDescriptor.h ├── mhServiceListDescriptor.cpp ├── mhServiceListDescriptor.h ├── mhShortEventDescriptor.cpp ├── mhShortEventDescriptor.h ├── mhSiParameterDescriptor.cpp ├── mhSiParameterDescriptor.h ├── mhStreamIdentificationDescriptor.cpp ├── mhStreamIdentificationDescriptor.h ├── mhTot.cpp ├── mhTot.h ├── mmt.cpp ├── mmt.h ├── mmtDescriptorBase.h ├── mmtDescriptorFactory.cpp ├── mmtDescriptorFactory.h ├── mmtDescriptors.cpp ├── mmtDescriptors.h ├── mmtFragment.h ├── mmtGeneralLocationInfo.cpp ├── mmtGeneralLocationInfo.h ├── mmtStream.cpp ├── mmtStream.h ├── mmtTableBase.h ├── mmtTableFactory.cpp ├── mmtTableFactory.h ├── mmtTlvDemuxer.cpp ├── mmtTlvDemuxer.h ├── mmtTlvStatistics.h ├── mpt.cpp ├── mpt.h ├── mpu.cpp ├── mpu.h ├── mpuExtendedTimestampDescriptor.cpp ├── mpuExtendedTimestampDescriptor.h ├── mpuTimestampDescriptor.cpp ├── mpuTimestampDescriptor.h ├── multimediaServiceInformationDescriptor.cpp ├── multimediaServiceInformationDescriptor.h ├── networkNameDescriptor.cpp ├── networkNameDescriptor.h ├── nit.cpp ├── nit.h ├── ntp.cpp ├── ntp.h ├── paMessage.cpp ├── paMessage.h ├── pesPacket.cpp ├── pesPacket.h ├── plt.cpp ├── plt.h ├── pugiconfig.hpp ├── pugixml.cpp ├── pugixml.hpp ├── relatedBroadcasterDescriptor.cpp ├── relatedBroadcasterDescriptor.h ├── remoteControlKeyDescriptor.cpp ├── remoteControlKeyDescriptor.h ├── remuxerHandler.cpp ├── remuxerHandler.h ├── serviceListDescriptor.cpp ├── serviceListDescriptor.h ├── signalingMessage.cpp ├── signalingMessage.h ├── smartcard.cpp ├── smartcard.h ├── stream.cpp ├── stream.h ├── subtitleMfuDataProcessor.cpp ├── subtitleMfuDataProcessor.h ├── swap.h ├── systemManagementDescriptor.cpp ├── systemManagementDescriptor.h ├── timeUtil.cpp ├── timeUtil.h ├── timebase.cpp ├── timebase.h ├── tlv.cpp ├── tlv.h ├── tlvDescriptorBase.h ├── tlvDescriptorFactory.cpp ├── tlvDescriptorFactory.h ├── tlvDescriptors.cpp ├── tlvDescriptors.h ├── tlvTableBase.h ├── tlvTableFactory.cpp ├── tlvTableFactory.h ├── transmissionControlSignal.cpp ├── transmissionControlSignal.h ├── tsARIBCharset.cpp ├── tsARIBCharset.h ├── tsARIBCharsetData.cpp ├── tsARIBCharsetEncoding.cpp ├── ttml.cpp ├── ttml.h ├── videoComponentDescriptor.cpp ├── videoComponentDescriptor.h ├── videoMfuDataProcessor.cpp └── videoMfuDataProcessor.h └── thirdparty ├── .gitignore ├── openssl └── .gitkeep └── tsduck └── .gitkeep /.github/workflows/c-cpp.yml: -------------------------------------------------------------------------------- 1 | name: C/C++ CI 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | pull_request: 7 | branches: [ "main" ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v4 16 | - name: Install dependencies 17 | run: | 18 | sudo apt update 19 | sudo apt install -y make g++ libssl-dev libpcsclite-dev pkgconf 20 | - name: Install tsduck 21 | run: | 22 | git clone https://github.com/tsduck/tsduck.git 23 | cd tsduck 24 | scripts/install-prerequisites.sh 25 | make -j10 26 | sudo make install 27 | - name: make 28 | run: make 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vs 2 | x64 3 | BonRecTest 4 | dantto4k_dev.sln -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PROJECT_NAME = dantto4k 2 | 3 | SRC_DIR = src 4 | OBJ_DIR = build 5 | 6 | SRC_FILES = $(filter-out $(SRC_DIR)/bonTuner.cpp, $(wildcard $(SRC_DIR)/*.cpp)) 7 | 8 | OBJ_FILES = $(SRC_FILES:$(SRC_DIR)/%.cpp=$(OBJ_DIR)/%.o) 9 | 10 | OPENSSL_INC = $(shell pkg-config --cflags-only-I openssl) 11 | OPENSSL_LIB = $(shell pkg-config --libs openssl) 12 | 13 | TSDUCK_INC = $(shell pkg-config --cflags-only-I tsduck) 14 | TSDUCK_LIB = $(shell pkg-config --libs tsduck) 15 | 16 | PCSC_INC = $(shell pkg-config --cflags-only-I libpcsclite) 17 | PCSC_LIB = $(shell pkg-config --libs libpcsclite) 18 | 19 | CXX = g++ 20 | CXXFLAGS = -std=c++20 -Wall $(OPENSSL_INC) $(TSDUCK_INC) $(PCSC_INC) 21 | LDFLAGS = $(OPENSSL_LIB) $(TSDUCK_LIB) $(PCSC_LIB) 22 | 23 | EXEC = $(OBJ_DIR)/$(PROJECT_NAME) 24 | 25 | all: $(EXEC) 26 | 27 | $(OBJ_DIR): 28 | mkdir -p $(OBJ_DIR) 29 | 30 | $(EXEC): $(OBJ_FILES) 31 | $(CXX) $(OBJ_FILES) $(LDFLAGS) -o $(EXEC) 32 | 33 | $(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp | $(OBJ_DIR) 34 | $(CXX) $(CXXFLAGS) -c $< -o $@ 35 | 36 | clean: 37 | rm -rf $(OBJ_DIR) 38 | 39 | install: 40 | cp $(EXEC) /usr/local/bin/$(PROJECT_NAME) 41 | 42 | .PHONY: all clean install -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dantto4k 2 | 3 | ## 使用方法 4 | 5 | ### dantto4k.exe 6 | mmtsから復号化およびMPEG-2 TSへの変換を行います。 7 | ``` 8 | dantto4k.exe [options] 9 | '-' can be used instead of a file path to enable piping via stdin or stdout. 10 | options: 11 | --disableADTSConversion: Uses the raw LATM format without converting to ADTS. 12 | --listSmartCardReader: Lists the available smart card readers. 13 | --smartCardReaderName=: Sets the smart card reader to use. 14 | ``` 15 | 16 | ### BonDriver_dantto4k.dll 17 | リアルタイムで復号化とMPEG-2 TSへの変換を行うBonDriverです。 18 | BonDriver_dantto4k.iniで設定されたBonDriverをロードして、復号化とMPEG-2 TSへの変換を行います。 19 | dantto4kは64bitで配布しており、BonRecTestおよびBonDriver_BDAは64bitである必要があります。 20 | 21 | #### mirakurunでの動作 22 | PT4Kで動作する場合、チャンネル再生まで15~20秒かかるため、mirakurunのtimeout(20秒)を超える場合があります。 23 | mirakurunのソースコードを修正してtimeoutを30秒以上に変更する必要があります。 24 | 25 | https://github.com/Chinachu/Mirakurun/blob/master/src/Mirakurun/Tuner.ts#L175C13-L175C55 26 | 27 | ## ビルド 28 | ### Windows 29 | /thirdpartyフォルダにopenssl 3, tsduckを準備します。 30 | 下記のURLからbinaryをダウンロードすることができます。 31 | 32 | - https://slproweb.com/products/Win32OpenSSL.html 33 | - https://github.com/tsduck/tsduck/ 34 | ### Ubuntu 35 | 36 | ```bash 37 | sudo apt install make g++ libssl-dev libpcsclite-dev pscsd pkgconf 38 | git clone https://github.com/tsduck/tsduck.git 39 | cd tsduck 40 | scripts/install-prerequisites.sh 41 | make -j10 42 | make install 43 | 44 | git clone https://github.com/nekohkr/dantto4k.git 45 | cd dantto4k 46 | make 47 | make install 48 | ``` 49 | 50 | ## References 51 | - ARIB STD-B32 52 | - ARIB STD-B60 53 | - [superfashi/FFmpeg](https://github.com/superfashi/FFmpeg) 54 | - b61decoder 55 | -------------------------------------------------------------------------------- /dantto4k.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.11.35222.181 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dantto4k", "src\dantto4k.vcxproj", "{D89922DC-4FE6-4FC1-8D78-BBF73F7A8B6B}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dantto4k_dll", "src\dantto4k_dll.vcxproj", "{55D2B0F2-F627-46E4-B229-FAF59079F9B0}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|x64 = Debug|x64 13 | Debug|x86 = Debug|x86 14 | Release|x64 = Release|x64 15 | Release|x86 = Release|x86 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {D89922DC-4FE6-4FC1-8D78-BBF73F7A8B6B}.Debug|x64.ActiveCfg = Debug|x64 19 | {D89922DC-4FE6-4FC1-8D78-BBF73F7A8B6B}.Debug|x64.Build.0 = Debug|x64 20 | {D89922DC-4FE6-4FC1-8D78-BBF73F7A8B6B}.Debug|x86.ActiveCfg = Debug|Win32 21 | {D89922DC-4FE6-4FC1-8D78-BBF73F7A8B6B}.Debug|x86.Build.0 = Debug|Win32 22 | {D89922DC-4FE6-4FC1-8D78-BBF73F7A8B6B}.Release|x64.ActiveCfg = Release|x64 23 | {D89922DC-4FE6-4FC1-8D78-BBF73F7A8B6B}.Release|x64.Build.0 = Release|x64 24 | {D89922DC-4FE6-4FC1-8D78-BBF73F7A8B6B}.Release|x86.ActiveCfg = Release|Win32 25 | {D89922DC-4FE6-4FC1-8D78-BBF73F7A8B6B}.Release|x86.Build.0 = Release|Win32 26 | {55D2B0F2-F627-46E4-B229-FAF59079F9B0}.Debug|x64.ActiveCfg = Debug|x64 27 | {55D2B0F2-F627-46E4-B229-FAF59079F9B0}.Debug|x64.Build.0 = Debug|x64 28 | {55D2B0F2-F627-46E4-B229-FAF59079F9B0}.Debug|x86.ActiveCfg = Debug|Win32 29 | {55D2B0F2-F627-46E4-B229-FAF59079F9B0}.Debug|x86.Build.0 = Debug|Win32 30 | {55D2B0F2-F627-46E4-B229-FAF59079F9B0}.Release|x64.ActiveCfg = Release|x64 31 | {55D2B0F2-F627-46E4-B229-FAF59079F9B0}.Release|x64.Build.0 = Release|x64 32 | {55D2B0F2-F627-46E4-B229-FAF59079F9B0}.Release|x86.ActiveCfg = Release|Win32 33 | {55D2B0F2-F627-46E4-B229-FAF59079F9B0}.Release|x86.Build.0 = Release|Win32 34 | EndGlobalSection 35 | GlobalSection(SolutionProperties) = preSolution 36 | HideSolutionNode = FALSE 37 | EndGlobalSection 38 | GlobalSection(ExtensibilityGlobals) = postSolution 39 | SolutionGuid = {0653D980-E547-4F79-B538-D30AB4C01FE2} 40 | EndGlobalSection 41 | EndGlobal 42 | -------------------------------------------------------------------------------- /ini/BonDriver_dantto4k.ini: -------------------------------------------------------------------------------- 1 | [bondriver] 2 | bondriverPath=BonDriver_BDA.dll 3 | 4 | ; mmtsDumpPath specifies the path to dump the MMTS for debugging (optional) 5 | mmtsDumpPath= 6 | 7 | [acas] 8 | ; optional 9 | smartCardReaderName= 10 | 11 | [audio] 12 | disableADTSConversion=false 13 | -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | x64 2 | dantto4k.vcxproj.user 3 | dantto4k_dll.vcxproj.user 4 | dantto4k_dev.vcxproj 5 | dantto4k_dll_dev.vcxproj 6 | dantto4k_dev.vcxproj.user 7 | dantto4k_dll_dev.vcxproj.user 8 | dantto4k_dev.vcxproj.filters 9 | dantto4k_dll_dev.vcxproj.filters -------------------------------------------------------------------------------- /src/IBonDriver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class IBonDriver 4 | { 5 | public: 6 | virtual const bool OpenTuner(void) = 0; 7 | virtual void CloseTuner(void) = 0; 8 | 9 | virtual const bool SetChannel(const uint8_t bCh) = 0; 10 | virtual const float GetSignalLevel(void) = 0; 11 | 12 | virtual const uint32_t WaitTsStream(const uint32_t dwTimeOut = 0) = 0; 13 | virtual const uint32_t GetReadyCount(void) = 0; 14 | 15 | virtual const bool GetTsStream(uint8_t* pDst, uint32_t* pdwSize, uint32_t* pdwRemain) = 0; 16 | virtual const bool GetTsStream(uint8_t** ppDst, uint32_t* pdwSize, uint32_t* pdwRemain) = 0; 17 | 18 | virtual void PurgeTsStream(void) = 0; 19 | 20 | virtual void Release(void) = 0; 21 | }; 22 | -------------------------------------------------------------------------------- /src/IBonDriver2.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "IBonDriver.h" 4 | 5 | class IBonDriver2 : public IBonDriver 6 | { 7 | public: 8 | virtual const char* GetTunerName(void) = 0; 9 | 10 | virtual const bool IsTunerOpening(void) = 0; 11 | virtual const char* EnumTuningSpace(const uint32_t dwSpace) = 0; 12 | virtual const char* EnumChannelName(const uint32_t dwSpace, const uint32_t dwChannel) = 0; 13 | 14 | virtual const bool SetChannel(const uint32_t dwSpace, const uint32_t dwChannel) = 0; 15 | 16 | virtual const uint32_t GetCurSpace(void) = 0; 17 | virtual const uint32_t GetCurChannel(void) = 0; 18 | 19 | // IBonDriver 20 | virtual void Release(void) = 0; 21 | }; -------------------------------------------------------------------------------- /src/acascard.cpp: -------------------------------------------------------------------------------- 1 | #include "acascard.h" 2 | #include 3 | #include 4 | 5 | namespace MmtTlv::Acas { 6 | 7 | AcasCard::AcasCard(std::shared_ptr smartCard) 8 | : smartCard(smartCard) 9 | { 10 | } 11 | 12 | void AcasCard::init() 13 | { 14 | ApduCommand apdu(0x90, 0x30, 0x00, 0x01); 15 | smartCard->transmit(apdu.case2short(0x00)); 16 | } 17 | 18 | Common::sha256_t AcasCard::getA0AuthKcl() const 19 | { 20 | std::default_random_engine engine(std::random_device{}()); 21 | std::uniform_int_distribution distrib(0, 255); 22 | 23 | std::vector data = { 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x8A, 0xF7 }; 24 | std::vector a0init(8); 25 | for (size_t i = 0; i < 8; ++i) { 26 | a0init.data()[i] = static_cast(distrib(engine)); 27 | } 28 | 29 | data.insert(data.end(), a0init.begin(), a0init.end()); 30 | 31 | ApduCommand apdu(0x90, 0xA0, 0x00, 0x01); 32 | auto response = smartCard->transmit(apdu.case4short(data, 0x00)); 33 | 34 | if (!response.isSuccess()) { 35 | throw std::runtime_error("A0 auth failed"); 36 | } 37 | 38 | auto a0data = response.getData(); 39 | std::vector a0response(a0data.begin() + 0x06, a0data.begin() + 0x06 + 0x08); 40 | std::vector a0hash(a0data.begin() + 0x0e, a0data.end()); 41 | 42 | std::vector plainKcl; 43 | plainKcl.insert(plainKcl.end(), std::begin(masterKey), std::end(masterKey)); 44 | plainKcl.insert(plainKcl.end(), a0init.begin(), a0init.end()); 45 | plainKcl.insert(plainKcl.end(), a0response.begin(), a0response.end()); 46 | 47 | Common::sha256_t kcl = Common::sha256(plainKcl); 48 | 49 | std::vector plainData; 50 | plainData.insert(plainData.end(), kcl.begin(), kcl.end()); 51 | plainData.insert(plainData.end(), a0init.begin(), a0init.end()); 52 | 53 | Common::sha256_t hash = Common::sha256(plainData); 54 | 55 | if (!std::equal(hash.begin(), hash.end(), a0hash.begin())) { 56 | throw std::runtime_error("A0 hash did not match"); 57 | } 58 | 59 | return kcl; 60 | } 61 | 62 | void AcasCard::addEcmCache(const std::vector& key, const DecryptedEcm& ecm) { 63 | ecmCache.push_back({ key, ecm }); 64 | if (ecmCache.size() > 100) { 65 | ecmCache.pop_front(); 66 | } 67 | } 68 | 69 | AcasCard::EcmCache::iterator AcasCard::findEcmCache(const std::vector& key) { 70 | return std::find_if(ecmCache.begin(), ecmCache.end(), 71 | [&key](const auto& pair) { return pair.first == key; }); 72 | } 73 | 74 | void AcasCard::processEcm(const std::vector& ecm) 75 | { 76 | const auto& cache = findEcmCache(ecm); 77 | if (cache != ecmCache.end()) { 78 | return; 79 | } 80 | 81 | Common::sha256_t kcl = getA0AuthKcl(); 82 | 83 | ApduCommand apdu(0x90, 0x34, 0x00, 0x01); 84 | auto response = smartCard->transmit(apdu.case4short(ecm, 0x00)); 85 | 86 | if (!response.isSuccess()) { 87 | throw std::runtime_error("ECM request failed"); 88 | } 89 | 90 | auto ecmData = response.getData(); 91 | std::vector ecmResponse(ecmData.begin() + 0x06, ecmData.end()); 92 | std::vector ecmInit(ecm.begin() + 0x04, ecm.begin() + 0x04 + 0x17); 93 | 94 | std::vector plainData; 95 | plainData.insert(plainData.end(), kcl.begin(), kcl.end()); 96 | plainData.insert(plainData.end(), ecmInit.begin(), ecmInit.end()); 97 | 98 | Common::sha256_t hash = Common::sha256(plainData); 99 | 100 | for (size_t i = 0; i < hash.size(); i++) { 101 | hash[i] ^= ecmResponse[i]; 102 | } 103 | 104 | DecryptedEcm decryptedEcm{}; 105 | std::copy(hash.begin(), hash.begin() + 0x10, decryptedEcm.odd.begin()); 106 | std::copy(hash.begin() + 0x10, hash.begin() + 0x20, decryptedEcm.even.begin()); 107 | 108 | addEcmCache(ecm, decryptedEcm); 109 | } 110 | 111 | void AcasCard::clear() 112 | { 113 | ecmCache.clear(); 114 | } 115 | 116 | std::optional AcasCard::getLastEcm() const { 117 | if (!ecmCache.empty()) { 118 | return ecmCache.back().second; 119 | } 120 | return std::nullopt; 121 | } 122 | 123 | } -------------------------------------------------------------------------------- /src/acascard.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "smartcard.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "hashUtil.h" 9 | 10 | namespace MmtTlv::Acas { 11 | 12 | static constexpr uint8_t masterKey[] = 13 | { 14 | 0x4F, 0x4C, 0x7C, 0xEB, 0x34, 0xFE, 0xB0, 0xA3, 15 | 0x1E, 0x41, 0x19, 0x51, 0xE1, 0x35, 0x15, 0x12, 16 | 0x87, 0xD3, 0x3D, 0x33, 0xD4, 0x9B, 0x4F, 0x52, 17 | 0x05, 0x77, 0xF9, 0xEF, 0xE5, 0x56, 0x1F, 0x32, 18 | }; 19 | 20 | struct DecryptedEcm { 21 | std::array odd; 22 | std::array even; 23 | }; 24 | 25 | class AcasCard { 26 | public: 27 | AcasCard(std::shared_ptr smartCard); 28 | 29 | void init(); 30 | void clear(); 31 | void processEcm(const std::vector& ecm); 32 | std::optional getLastEcm() const; 33 | 34 | private: 35 | Common::sha256_t getA0AuthKcl() const; 36 | void addEcmCache(const std::vector& key, const DecryptedEcm& ecm); 37 | 38 | using EcmCache = std::list, DecryptedEcm>>; 39 | EcmCache::iterator findEcmCache(const std::vector& key); 40 | EcmCache ecmCache; 41 | std::shared_ptr smartCard; 42 | bool ready{false}; 43 | }; 44 | 45 | } -------------------------------------------------------------------------------- /src/accessControlDescriptor.cpp: -------------------------------------------------------------------------------- 1 | #include "accessControlDescriptor.h" 2 | 3 | namespace MmtTlv { 4 | 5 | bool AccessControlDescriptor::unpack(Common::ReadStream& stream) 6 | { 7 | try { 8 | if (!MmtDescriptorTemplate::unpack(stream)) { 9 | return false; 10 | } 11 | 12 | Common::ReadStream nstream(stream, descriptorLength); 13 | 14 | caSystemId = nstream.getBe16U(); 15 | if (!locationInfo.unpack(nstream)) { 16 | return false; 17 | } 18 | 19 | privateData.resize(nstream.leftBytes()); 20 | nstream.read(privateData.data(), nstream.leftBytes()); 21 | 22 | stream.skip(descriptorLength); 23 | } 24 | catch (const std::out_of_range&) { 25 | return false; 26 | } 27 | 28 | return true; 29 | } 30 | 31 | } -------------------------------------------------------------------------------- /src/accessControlDescriptor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "mmtDescriptorBase.h" 3 | #include "mmtGeneralLocationInfo.h" 4 | #include 5 | 6 | namespace MmtTlv { 7 | 8 | class AccessControlDescriptor 9 | : public MmtDescriptorTemplate<0x8004> { 10 | public: 11 | bool unpack(Common::ReadStream& stream) override; 12 | 13 | uint16_t caSystemId; 14 | MmtGeneralLocationInfo locationInfo; 15 | std::vector privateData; 16 | }; 17 | 18 | } -------------------------------------------------------------------------------- /src/adtsConverter.cpp: -------------------------------------------------------------------------------- 1 | #include "adtsConverter.h" 2 | #include "stream.h" 3 | 4 | static inline int convertAdtsAudioObjectType(int aot) 5 | { 6 | switch (aot) { 7 | case 1: return 0; 8 | case 2: return 1; 9 | case 3: return 2; 10 | default: return 3; 11 | } 12 | } 13 | 14 | bool ADTSConverter::convert(uint8_t* input, size_t size, std::vector& output) 15 | { 16 | if (size < 3) { 17 | return false; 18 | } 19 | 20 | uint16_t syncWord = (input[0] << 3) | (input[1] & 0b11100000) >> 5; 21 | if (syncWord != 0x2b7) { 22 | return false; 23 | } 24 | 25 | uint16_t audioMuxLengthBytes = ((input[1] & 0b00011111) << 8 | input[2]) + 3; 26 | if (size != audioMuxLengthBytes) { 27 | return false; 28 | } 29 | 30 | if (!unpackStreamMuxConfig(input + 3, size - 3)) { 31 | return false; 32 | } 33 | 34 | int tmp; 35 | int slotLength = 0; 36 | int i = 3 + 6; 37 | do { 38 | tmp = (input[i] & 0b00000111) << 5 | (input[i + 1] & 0b11111000) >> 3; 39 | slotLength += tmp; 40 | i++; 41 | } while (tmp == 255); 42 | 43 | int frameLength = slotLength + 7; 44 | int bufferFullness = 0x7FF; 45 | 46 | output.resize(frameLength); 47 | 48 | // ADTS Header 49 | output.data()[0] = (0xFFF >> 4) & 0xFF; 50 | output.data()[1] = ((0xFFF & 0b111100000000) >> 8) << 4 | 51 | 0 << 3 | // mpeg version 52 | 0 << 1 | // layer 53 | 1; // protection absent 54 | output.data()[2] = (convertAdtsAudioObjectType(audioObjectType) & 0b11) << 6 | 55 | sampleRate << 2 | 56 | 1 << 1 | // private bit 57 | (channelConfiguration & 0b100) >> 2; 58 | output.data()[3] = (channelConfiguration & 0b011) << 6 | 59 | 1 << 5 | // original 60 | 1 << 4 | // copy 61 | 1 << 3 | // cib 62 | 1 << 2 | // cis 63 | (frameLength & 0b1100000000000) >> 11; 64 | output.data()[4] = (frameLength & 0b0011111111000) >> 3; 65 | output.data()[5] = (frameLength & 0b0000000000111) << 5 | 66 | (bufferFullness & 0b11111000000) >> 6; 67 | output.data()[6] = (bufferFullness & 0b00000111111) << 2 | 68 | 0/* rdb in frame */; 69 | 70 | for (int i2 = 0; i2 < slotLength; i2++) { 71 | output.data()[7 + i2] = (input[i + i2] & 0b00000111) << 5 | (input[i + i2 + 1] & 0b11111000) >> 3; 72 | } 73 | 74 | return true; 75 | } 76 | 77 | bool ADTSConverter::unpackStreamMuxConfig(uint8_t* input, size_t size) 78 | { 79 | int audioMuxVersion = (input[0] & 0b10000000) >> 7; 80 | 81 | // restricted to 0 82 | if (audioMuxVersion) { 83 | return false; 84 | } 85 | 86 | //int allStreamSameTimeFraming = (input[0] & 0b01000000) >> 5; 87 | // restricted to 0 88 | int numSubFrames = (input[0] & 0b00011111) << 1 | (input[1] & 0b10000000); 89 | // restricted to 0 90 | int numPrograms = input[1] & 0b01111000; 91 | // restricted to 0 92 | int numLayer = input[1] & 0b00000111; 93 | 94 | if (numSubFrames != 0 || numPrograms != 0 || numLayer != 0) { 95 | return false; 96 | } 97 | 98 | if (!unpackAudioSpecificConfig(input, size)) { 99 | return false; 100 | } 101 | 102 | // restricted to 0 103 | int frameLengthType = (input[4] & 0b11100000) >> 5; 104 | if (frameLengthType) { 105 | return false; 106 | } 107 | 108 | //int latmBufferFullness = (input[4] & 0b00011111) << 3 | (input[5] & 0b11100000) >> 5; 109 | int otherDataPresent = (input[5] & 0b00010000) >> 4; 110 | if (otherDataPresent) { 111 | return false; 112 | } 113 | 114 | int crcPresent = (input[5] & 0b00001000) >> 3; 115 | if (!crcPresent) { 116 | return false; 117 | } 118 | 119 | //int crc = (input[5] & 0b00000111) << 3 | (input[6] & 0b11111000) >> 3; 120 | 121 | return true; 122 | } 123 | 124 | bool ADTSConverter::unpackAudioSpecificConfig(uint8_t* input, size_t size) 125 | { 126 | audioObjectType = (input[2] & 0b11111000) >> 3; 127 | if (audioObjectType == 28) { 128 | return false; 129 | } 130 | 131 | sampleRate = (input[2] & 0b00000111) << 1 | (input[3] & 0b10000000) >> 7; 132 | if (sampleRate == 0xf) { 133 | return false; 134 | } 135 | 136 | channelConfiguration = (input[3] & 0b01111000) >> 3; 137 | 138 | bool framelenFlag = (input[3] & 0b00000100) >> 2; 139 | bool dependsOnCoder = (input[3] & 0b00000010) >> 1; 140 | if (framelenFlag || dependsOnCoder) { 141 | return false; 142 | } 143 | 144 | bool extFlag = input[3] & 0b00000001; 145 | if (extFlag) { 146 | return false; 147 | } 148 | 149 | return true; 150 | } -------------------------------------------------------------------------------- /src/adtsConverter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | class ADTSConverter { 6 | public: 7 | bool convert(uint8_t* input, size_t size, std::vector& output); 8 | 9 | private: 10 | bool unpackStreamMuxConfig(uint8_t* input, size_t size); 11 | bool unpackAudioSpecificConfig(uint8_t* input, size_t size); 12 | int audioObjectType{ 0 }; 13 | int sampleRate{ 0 }; 14 | int channelConfiguration{ 0 }; 15 | }; -------------------------------------------------------------------------------- /src/applicationMfuDataProcessor.cpp: -------------------------------------------------------------------------------- 1 | #include "applicationMfuDataProcessor.h" 2 | 3 | namespace MmtTlv { 4 | 5 | std::optional ApplicationMfuDataProcessor::process(const std::shared_ptr& mmtStream, const std::vector& data) 6 | { 7 | Common::ReadStream stream(data); 8 | size_t size = stream.leftBytes(); 9 | if (size == 0) { 10 | return std::nullopt; 11 | } 12 | 13 | MfuData mfuData; 14 | mfuData.data.resize(size); 15 | stream.read(mfuData.data.data(), size); 16 | 17 | mfuData.streamIndex = mmtStream->getStreamIndex(); 18 | 19 | return mfuData; 20 | } 21 | 22 | } -------------------------------------------------------------------------------- /src/applicationMfuDataProcessor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "mfuDataProcessorBase.h" 3 | 4 | namespace MmtTlv { 5 | 6 | class ApplicationMfuDataProcessor : public MfuDataProcessorTemplate { 7 | public: 8 | std::optional process(const std::shared_ptr& mmtStream, const std::vector& data); 9 | 10 | }; 11 | 12 | } -------------------------------------------------------------------------------- /src/aribUtil.cpp: -------------------------------------------------------------------------------- 1 | #include "aribUtil.h" 2 | #include "tsARIBCharset.h" 3 | 4 | struct Gaiji { 5 | const char8_t* find; 6 | const char8_t* replacement; 7 | }; 8 | 9 | constexpr Gaiji GaijiTable[] = { 10 | // ARIB STD-B62 11 | {u8"\U0001F19B", u8"[3D]"}, 12 | {u8"\U0001F19C", u8"[2nd Scr]"}, 13 | {u8"\U0001F19D", u8"[2K]"}, 14 | {u8"\U0001F19E", u8"[4K]"}, 15 | {u8"\U0001F19F", u8"[8K]"}, 16 | {u8"\U0001F1A0", u8"[5.1]"}, 17 | {u8"\U0001F1A1", u8"[7.1]"}, 18 | {u8"\U0001F1A2", u8"[22.2]"}, 19 | {u8"\U0001F1A3", u8"[60P]"}, 20 | {u8"\U0001F1A4", u8"[120P]"}, 21 | {u8"\U0001F1A5", u8"[d]"}, 22 | {u8"\U0001F1A6", u8"[HC]"}, 23 | {u8"\U0001F1A7", u8"[HDR]"}, 24 | {u8"\U0001F1A8", u8"[Hi-Res]"}, 25 | {u8"\U0001F1A9", u8"[Lossless]"}, 26 | {u8"\U0001F1AA", u8"[SHV]"}, 27 | {u8"\U0001F1AB", u8"[UHD]"}, 28 | {u8"\U0001F1AC", u8"[VOD]"}, 29 | {u8"\U0001F23B", u8"[配]"}, 30 | {u8"\U000032FF", u8"令和"}, 31 | 32 | // ARIB STD-B24 (Table 7-11 Addtional Kanji Characters) 33 | {u8"仿", u8"彷"}, 34 | {u8"傜", u8"徭"}, 35 | {u8"恵", u8"恵"}, 36 | {u8"泠", u8"冷"}, 37 | {u8"琢", u8"琢"}, 38 | {u8"畵", u8"畫"}, 39 | {u8"舘", u8"舘"}, 40 | {u8"蟬", u8"蝉"}, 41 | {u8"鷗", u8"鴎"}, 42 | {u8"麴", u8"麹"}, 43 | {u8"麵", u8"麺"}, 44 | {u8"髙", u8"高"}, 45 | {u8"塚", u8"塚"}, 46 | {u8"﨑", u8"埼"}, 47 | {u8"海", u8"海"}, 48 | {u8"渚", u8"渚"}, 49 | {u8"禮", u8"禮"}, 50 | {u8"⾓", u8"角"}, 51 | }; 52 | 53 | namespace { 54 | 55 | void replaceSequence(std::string& str, const std::string& sequence, const char* replacement) { 56 | std::size_t pos = 0; 57 | 58 | while ((pos = str.find(sequence, pos)) != std::string::npos) { 59 | str.replace(pos, sequence.size(), replacement); 60 | pos += 1; 61 | } 62 | } 63 | 64 | void convertGaiji(std::string& str) { 65 | for (const auto& gaiji : GaijiTable) { 66 | replaceSequence(str, reinterpret_cast(gaiji.find), reinterpret_cast(gaiji.replacement)); 67 | } 68 | } 69 | 70 | } 71 | 72 | const ts::ByteBlock aribEncode(const std::string& input) { 73 | std::string converted = input; 74 | convertGaiji(converted); 75 | 76 | ts::UString text = ts::UString::FromUTF8(converted.data(), converted.size()); 77 | return ts::ARIBCharset2::B24.encoded(text); 78 | } 79 | 80 | 81 | const ts::ByteBlock aribEncode(const char* input, size_t size) { 82 | return aribEncode(std::string{ input, size }); 83 | } 84 | -------------------------------------------------------------------------------- /src/aribUtil.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | const ts::ByteBlock aribEncode(const std::string& input); 5 | 6 | const ts::ByteBlock aribEncode(const char* input, size_t size); 7 | -------------------------------------------------------------------------------- /src/audioMfuDataProcessor.cpp: -------------------------------------------------------------------------------- 1 | #include "audioMfuDataProcessor.h" 2 | 3 | namespace MmtTlv { 4 | 5 | std::optional AudioMfuDataProcessor::process(const std::shared_ptr& mmtStream, const std::vector& data) 6 | { 7 | Common::ReadStream stream(data); 8 | size_t size = stream.leftBytes(); 9 | 10 | std::pair ptsDts; 11 | try { 12 | ptsDts = mmtStream->getNextPtsDts(); 13 | } 14 | catch (const std::out_of_range&) { 15 | return std::nullopt; 16 | } 17 | 18 | MfuData mfuData; 19 | mfuData.data.resize(size + 3); 20 | mfuData.data[0] = 0x56; 21 | mfuData.data[1] = ((size >> 8) & 0x1F) | 0xE0; 22 | mfuData.data[2] = size & 0xFF; 23 | stream.read(mfuData.data.data() + 3, size); 24 | 25 | mfuData.pts = ptsDts.first; 26 | mfuData.dts = ptsDts.second; 27 | mfuData.streamIndex = mmtStream->getStreamIndex(); 28 | 29 | return mfuData; 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /src/audioMfuDataProcessor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "mfuDataProcessorBase.h" 3 | 4 | namespace MmtTlv { 5 | 6 | class AudioMfuDataProcessor : public MfuDataProcessorTemplate { 7 | public: 8 | std::optional process(const std::shared_ptr& mmtStream, const std::vector& data); 9 | 10 | private: 11 | std::vector pendingData; 12 | }; 13 | 14 | } -------------------------------------------------------------------------------- /src/b24Color.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | struct ColorRGBA { 6 | constexpr ColorRGBA(uint8_t r, uint8_t g, uint8_t b, uint8_t a) : r(r), g(g), b(b), a(a) {} 7 | 8 | uint8_t r; 9 | uint8_t g; 10 | uint8_t b; 11 | uint8_t a; 12 | }; 13 | 14 | std::pair findClosestColor(const ColorRGBA& color); 15 | -------------------------------------------------------------------------------- /src/b24ControlSet.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace B24ControlSet { 5 | 6 | static constexpr uint8_t NUL = 0x00; 7 | static constexpr uint8_t BEL = 0x07; 8 | static constexpr uint8_t APB = 0x08; 9 | static constexpr uint8_t APF = 0x09; 10 | static constexpr uint8_t APD = 0x0A; 11 | static constexpr uint8_t APU = 0x0B; 12 | static constexpr uint8_t CS = 0x0C; 13 | static constexpr uint8_t APR = 0x0D; 14 | static constexpr uint8_t LS1 = 0x0E; 15 | static constexpr uint8_t LS0 = 0x0F; 16 | static constexpr uint8_t PAPF = 0x16; 17 | static constexpr uint8_t CAN = 0x18; 18 | static constexpr uint8_t SS2 = 0x19; 19 | static constexpr uint8_t ESC = 0x1B; 20 | static constexpr uint8_t APS = 0x1C; 21 | static constexpr uint8_t SS3 = 0x1D; 22 | static constexpr uint8_t RS = 0x1E; 23 | static constexpr uint8_t US = 0x1F; 24 | static constexpr uint8_t SP = 0x20; 25 | static constexpr uint8_t SWF = 0x53; 26 | static constexpr uint8_t SDF = 0x56; 27 | static constexpr uint8_t SSM = 0x57; 28 | static constexpr uint8_t SHS = 0x58; 29 | static constexpr uint8_t SVS = 0x59; 30 | static constexpr uint8_t SDP = 0x5F; 31 | static constexpr uint8_t ORN = 0x63; 32 | static constexpr uint8_t DEL = 0x7F; 33 | static constexpr uint8_t BKF = 0x80; 34 | static constexpr uint8_t RDF = 0x81; 35 | static constexpr uint8_t GRF = 0x82; 36 | static constexpr uint8_t YLF = 0x83; 37 | static constexpr uint8_t BLF = 0x84; 38 | static constexpr uint8_t MGF = 0x85; 39 | static constexpr uint8_t CNF = 0x86; 40 | static constexpr uint8_t WHF = 0x87; 41 | static constexpr uint8_t SSZ = 0x88; 42 | static constexpr uint8_t MSZ = 0x89; 43 | static constexpr uint8_t NSZ = 0x8A; 44 | static constexpr uint8_t SZX = 0x8B; 45 | static constexpr uint8_t COL = 0x90; 46 | static constexpr uint8_t FLC = 0x91; 47 | static constexpr uint8_t CDC = 0x92; 48 | static constexpr uint8_t POL = 0x93; 49 | static constexpr uint8_t WMM = 0x94; 50 | static constexpr uint8_t MACRO = 0x95; 51 | static constexpr uint8_t HLC = 0x97; 52 | static constexpr uint8_t RPC = 0x98; 53 | static constexpr uint8_t SPL = 0x99; 54 | static constexpr uint8_t STL = 0x9A; 55 | static constexpr uint8_t CSI = 0x9B; 56 | static constexpr uint8_t TIME = 0x9D; 57 | 58 | } -------------------------------------------------------------------------------- /src/bonTuner.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include "IBonDriver2.h" 5 | #include "config.h" 6 | 7 | class CBonTuner : public IBonDriver2 8 | { 9 | public: 10 | virtual ~CBonTuner() {}; 11 | 12 | bool init(); 13 | 14 | // IBonDriver 15 | const bool OpenTuner(void); 16 | void CloseTuner(void); 17 | 18 | const bool SetChannel(const uint8_t bCh); 19 | const float GetSignalLevel(void); 20 | 21 | const uint32_t WaitTsStream(const uint32_t dwTimeOut = 0); 22 | const uint32_t GetReadyCount(void); 23 | 24 | const bool GetTsStream(uint8_t* pDst, uint32_t* pdwSize, uint32_t* pdwRemain); 25 | const bool GetTsStream(uint8_t** ppDst, uint32_t* pdwSize, uint32_t* pdwRemain); 26 | 27 | void PurgeTsStream(void); 28 | 29 | // IBonDriver2 30 | const char* GetTunerName(void); 31 | 32 | const bool IsTunerOpening(void); 33 | 34 | const char* EnumTuningSpace(const uint32_t dwSpace); 35 | const char* EnumChannelName(const uint32_t dwSpace, const uint32_t dwChannel); 36 | 37 | const bool SetChannel(const uint32_t dwSpace, const uint32_t dwChannel); 38 | 39 | const uint32_t GetCurSpace(void); 40 | const uint32_t GetCurChannel(void); 41 | 42 | void Release(void); 43 | 44 | protected: 45 | IBonDriver2* pBonDriver2; 46 | std::vector inputBuffer; 47 | std::mutex mutex; 48 | }; -------------------------------------------------------------------------------- /src/caMessage.cpp: -------------------------------------------------------------------------------- 1 | #include "caMessage.h" 2 | 3 | namespace MmtTlv { 4 | 5 | bool CaMessage::unpack(Common::ReadStream& stream) 6 | { 7 | try { 8 | messageId = stream.getBe16U(); 9 | version = stream.get8U(); 10 | length = stream.getBe16U(); 11 | } 12 | catch (const std::out_of_range&) { 13 | return false; 14 | } 15 | 16 | return true; 17 | } 18 | 19 | } -------------------------------------------------------------------------------- /src/caMessage.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "stream.h" 4 | 5 | namespace MmtTlv { 6 | 7 | class CaMessage { 8 | public: 9 | bool unpack(Common::ReadStream& stream); 10 | 11 | uint16_t messageId; 12 | uint8_t version; 13 | uint16_t length; 14 | }; 15 | 16 | } -------------------------------------------------------------------------------- /src/compressedIPPacket.cpp: -------------------------------------------------------------------------------- 1 | #include "compressedIPPacket.h" 2 | #include 3 | #include "stream.h" 4 | 5 | namespace MmtTlv { 6 | 7 | bool CompressedIPPacket::unpack(Common::ReadStream& stream) 8 | { 9 | try { 10 | uint16_t uint16 = stream.getBe16U(); 11 | contextId = (uint16 & 0b1111111111110000) >> 4; 12 | sequenceNumber = uint16 & 0b0000000000001111; 13 | headerType = static_cast(stream.get8U()); 14 | 15 | switch (headerType) { 16 | case ContextHeaderType::ContextIdPartialIpv4AndPartialUdp: 17 | break; 18 | case ContextHeaderType::ContextIdIpv4Identifier: 19 | break; 20 | case ContextHeaderType::ContextIdPartialIpv6AndPartialUdp: 21 | ipv6.assign(38, 0); 22 | stream.read(ipv6.data(), 38); 23 | 24 | udp.assign(4, 0); 25 | stream.read(udp.data(), 4); 26 | break; 27 | case ContextHeaderType::ContextIdNoCompressedHheader: 28 | break; 29 | } 30 | } 31 | catch (const std::out_of_range&) { 32 | return false; 33 | } 34 | 35 | return true; 36 | } 37 | 38 | } -------------------------------------------------------------------------------- /src/compressedIPPacket.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "stream.h" 4 | 5 | namespace MmtTlv { 6 | 7 | enum class ContextHeaderType : uint8_t { 8 | ContextIdPartialIpv4AndPartialUdp = 0x20, 9 | ContextIdIpv4Identifier = 0x21, 10 | ContextIdPartialIpv6AndPartialUdp = 0x60, 11 | ContextIdNoCompressedHheader = 0x61, 12 | }; 13 | 14 | class CompressedIPPacket { 15 | public: 16 | bool unpack(Common::ReadStream& stream); 17 | 18 | std::vector getCompressedHeader() const { 19 | return compressedHeader; 20 | } 21 | 22 | public: 23 | std::vector compressedHeader; 24 | uint16_t contextId; 25 | uint8_t sequenceNumber; 26 | ContextHeaderType headerType; 27 | 28 | // Not implemented 29 | std::vector ipv6; 30 | std::vector udp; 31 | std::vector ipv4; 32 | }; 33 | 34 | } -------------------------------------------------------------------------------- /src/config.cpp: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | #include 3 | 4 | Config config = Config{}; 5 | 6 | static std::string trim(const std::string& str) { 7 | size_t first = str.find_first_not_of(" \t\n\r"); 8 | if (first == std::string::npos) return ""; 9 | size_t last = str.find_last_not_of(" \t\n\r"); 10 | return str.substr(first, last - first + 1); 11 | } 12 | 13 | Config loadConfig(const std::string& filename) 14 | { 15 | Config config; 16 | std::ifstream file(filename); 17 | if (!file.is_open()) { 18 | throw std::runtime_error("Unable to open config file: " + filename); 19 | } 20 | 21 | std::string currentSection; 22 | std::string line; 23 | 24 | while (std::getline(file, line)) { 25 | line = trim(line); 26 | 27 | if (line.empty() || line[0] == '#' || line[0] == ';') { 28 | continue; 29 | } 30 | 31 | if (line.front() == '[' && line.back() == ']') { 32 | currentSection = line.substr(1, line.size() - 2); 33 | currentSection = trim(currentSection); 34 | continue; 35 | } 36 | 37 | if (currentSection == "bondriver") { 38 | size_t equalPos = line.find('='); 39 | if (equalPos != std::string::npos) { 40 | std::string key = trim(line.substr(0, equalPos)); 41 | std::string value = trim(line.substr(equalPos + 1)); 42 | 43 | if (key == "bondriverPath") { 44 | config.bondriverPath = value; 45 | } 46 | if (key == "mmtsDumpPath") { 47 | config.mmtsDumpPath = value; 48 | } 49 | } 50 | } 51 | if (currentSection == "acas") { 52 | size_t equalPos = line.find('='); 53 | if (equalPos != std::string::npos) { 54 | std::string key = trim(line.substr(0, equalPos)); 55 | std::string value = trim(line.substr(equalPos + 1)); 56 | 57 | if (key == "smartCardReaderName") { 58 | config.smartCardReaderName = value; 59 | } 60 | } 61 | } 62 | if (currentSection == "audio") { 63 | size_t equalPos = line.find('='); 64 | if (equalPos != std::string::npos) { 65 | std::string key = trim(line.substr(0, equalPos)); 66 | std::string value = trim(line.substr(equalPos + 1)); 67 | 68 | if (key == "disableADTSConversion") { 69 | if (value == "true") { 70 | config.disableADTSConversion = true; 71 | } 72 | } 73 | } 74 | } 75 | } 76 | 77 | file.close(); 78 | return config; 79 | } 80 | -------------------------------------------------------------------------------- /src/config.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | class Config { 6 | public: 7 | std::string bondriverPath{}; 8 | std::string mmtsDumpPath{}; 9 | std::string smartCardReaderName{}; 10 | bool disableADTSConversion{false}; 11 | }; 12 | 13 | Config loadConfig(const std::string& filename); 14 | 15 | extern Config config; -------------------------------------------------------------------------------- /src/contentCopyControlDescriptor.cpp: -------------------------------------------------------------------------------- 1 | #include "contentCopyControlDescriptor.h" 2 | 3 | namespace MmtTlv { 4 | 5 | bool ContentCopyControlDescriptor::unpack(Common::ReadStream& stream) 6 | { 7 | try { 8 | if (!MmtDescriptorTemplate::unpack(stream)) { 9 | return false; 10 | } 11 | 12 | Common::ReadStream nstream(stream, descriptorLength); 13 | 14 | uint8_t uint8 = nstream.get8U(); 15 | digitalRecordingControlData = (uint8 & 0b11000000) >> 6; 16 | maximumBitrateFlag = (uint8 & 0b00100000) >> 5; 17 | componentControlFlag = (uint8 & 0b00010000) >> 4; 18 | reservedFutureUse1 = uint8 & 0b00001111; 19 | 20 | if (maximumBitrateFlag) { 21 | maximumBitrate = nstream.get8U(); 22 | } 23 | 24 | if (componentControlFlag) { 25 | componentControlLength = nstream.get8U(); 26 | 27 | Common::ReadStream componentStream(nstream, componentControlLength); 28 | while (componentStream.isEof()) { 29 | Component component; 30 | if (!component.unpack(componentStream)) { 31 | return false; 32 | } 33 | components.push_back(component); 34 | } 35 | } 36 | 37 | stream.skip(descriptorLength); 38 | } 39 | catch (const std::out_of_range&) { 40 | return false; 41 | } 42 | 43 | return true; 44 | } 45 | 46 | bool ContentCopyControlDescriptor::Component::unpack(Common::ReadStream& stream) 47 | { 48 | try { 49 | componentTag = stream.getBe16U(); 50 | uint8_t uint8 = stream.get8U(); 51 | digitalRecordingControlData = (uint8 & 0b11000000) >> 6; 52 | maximumBitrateFlag = (uint8 & 0b00100000) >> 5; 53 | reservedFutureUse1 = uint8 & 0b00011111; 54 | reservedFutureUse2 = stream.get8U(); 55 | 56 | if (maximumBitrateFlag) { 57 | maximumBitrate = stream.get8U(); 58 | } 59 | } 60 | catch (const std::out_of_range&) { 61 | return false; 62 | } 63 | 64 | return true; 65 | } 66 | 67 | } -------------------------------------------------------------------------------- /src/contentCopyControlDescriptor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "mmtDescriptorBase.h" 3 | #include 4 | 5 | namespace MmtTlv { 6 | 7 | class ContentCopyControlDescriptor 8 | : public MmtDescriptorTemplate<0x8038> { 9 | public: 10 | bool unpack(Common::ReadStream& stream) override; 11 | 12 | class Component { 13 | public: 14 | bool unpack(Common::ReadStream& stream); 15 | 16 | uint16_t componentTag; 17 | uint8_t digitalRecordingControlData; 18 | uint8_t maximumBitrateFlag; 19 | uint8_t reservedFutureUse1; 20 | uint8_t reservedFutureUse2; 21 | uint8_t maximumBitrate; 22 | 23 | }; 24 | 25 | uint8_t digitalRecordingControlData; 26 | bool maximumBitrateFlag; 27 | bool componentControlFlag; 28 | uint8_t reservedFutureUse1; 29 | uint8_t reservedFutureUse2; 30 | 31 | uint8_t maximumBitrate; 32 | 33 | uint8_t componentControlLength; 34 | 35 | std::list components; 36 | }; 37 | 38 | } -------------------------------------------------------------------------------- /src/dantto4k.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "mmtTlvDemuxer.h" 3 | #include 4 | 5 | extern MmtTlv::MmtTlvDemuxer demuxer; 6 | extern std::vector output; 7 | 8 | #ifdef _WIN32 9 | LONG WINAPI ExceptionHandler(EXCEPTION_POINTERS* exceptionInfo); 10 | #endif -------------------------------------------------------------------------------- /src/dataTransmissionMessage.cpp: -------------------------------------------------------------------------------- 1 | #include "dataTransmissionMessage.h" 2 | 3 | namespace MmtTlv { 4 | 5 | bool DataTransmissionMessage::unpack(Common::ReadStream& stream) 6 | { 7 | try { 8 | messageId = stream.getBe16U(); 9 | version = stream.get8U(); 10 | length = stream.getBe32U(); 11 | } 12 | catch (const std::out_of_range&) { 13 | return false; 14 | } 15 | 16 | return true; 17 | } 18 | 19 | } -------------------------------------------------------------------------------- /src/dataTransmissionMessage.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "stream.h" 4 | 5 | namespace MmtTlv { 6 | 7 | class DataTransmissionMessage { 8 | public: 9 | bool unpack(Common::ReadStream& stream); 10 | 11 | uint16_t messageId; 12 | uint8_t version; 13 | uint32_t length; 14 | }; 15 | 16 | } -------------------------------------------------------------------------------- /src/dataUnit.cpp: -------------------------------------------------------------------------------- 1 | #include "dataUnit.h" 2 | 3 | namespace MmtTlv { 4 | 5 | bool DataUnit::unpack(Common::ReadStream& stream, bool timedFlag, bool aggregateFlag) 6 | { 7 | try { 8 | if (timedFlag) { 9 | if (aggregateFlag == 0) { 10 | movieFragmentSequenceNumber = stream.getBe32U(); 11 | sampleNumber = stream.getBe32U(); 12 | offset = stream.getBe32U(); 13 | priority = stream.get8U(); 14 | dependencyCounter = stream.get8U(); 15 | 16 | data.resize(stream.leftBytes()); 17 | stream.read(data.data(), stream.leftBytes()); 18 | } 19 | else { 20 | dataUnitLength = stream.getBe16U(); 21 | dataUnitLength = std::min(dataUnitLength, static_cast(stream.leftBytes())); 22 | 23 | movieFragmentSequenceNumber = stream.getBe32U(); 24 | sampleNumber = stream.getBe32U(); 25 | offset = stream.getBe32U(); 26 | priority = stream.get8U(); 27 | dependencyCounter = stream.get8U(); 28 | 29 | if (dataUnitLength < 4 * 3 + 2) { 30 | return false; 31 | } 32 | 33 | data.resize(dataUnitLength - 4 * 3 - 2); 34 | stream.read(data.data(), dataUnitLength - 4 * 3 - 2); 35 | } 36 | } 37 | else { 38 | if (aggregateFlag == 0) { 39 | itemId = stream.getBe32U(); 40 | 41 | data.resize(stream.leftBytes()); 42 | stream.read(data.data(), stream.leftBytes()); 43 | } 44 | else { 45 | dataUnitLength = stream.getBe16U(); 46 | 47 | data.resize(dataUnitLength); 48 | stream.read(data.data(), dataUnitLength); 49 | } 50 | } 51 | } 52 | catch (const std::out_of_range&) { 53 | return false; 54 | } 55 | 56 | return true; 57 | } 58 | 59 | } -------------------------------------------------------------------------------- /src/dataUnit.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "stream.h" 4 | 5 | namespace MmtTlv { 6 | 7 | class DataUnit { 8 | public: 9 | bool unpack(Common::ReadStream& stream, bool timedFlag, bool aggregateFlag); 10 | 11 | uint16_t dataUnitLength; 12 | uint32_t movieFragmentSequenceNumber; 13 | uint32_t sampleNumber; 14 | uint32_t offset; 15 | uint8_t priority; 16 | uint8_t dependencyCounter; 17 | uint32_t itemId; 18 | std::vector data; 19 | }; 20 | 21 | } -------------------------------------------------------------------------------- /src/demuxerHandler.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace MmtTlv { 4 | 5 | struct MfuData; 6 | class MmtStream; 7 | class Ecm; 8 | class MhBit; 9 | class MhAit; 10 | class MhCdt; 11 | class MhEit; 12 | class MhSdt; 13 | class MhTot; 14 | class Mpt; 15 | class Plt; 16 | class Nit; 17 | class NTPv4; 18 | 19 | class DemuxerHandler { 20 | public: 21 | virtual ~DemuxerHandler() = default; 22 | 23 | // MPU data 24 | virtual void onVideoData(const std::shared_ptr mmtStream, const std::shared_ptr& mfuData) {} 25 | virtual void onAudioData(const std::shared_ptr mmtStream, const std::shared_ptr& mfuData) {} 26 | virtual void onSubtitleData(const std::shared_ptr mmtStream, const std::shared_ptr& mfuData) {} 27 | virtual void onApplicationData(const std::shared_ptr mmtStream, const std::shared_ptr& mfuData) {} 28 | 29 | // MMT-SI 30 | virtual void onEcm(const std::shared_ptr& ecm) {} 31 | virtual void onMhBit(const std::shared_ptr& mhBit) {} 32 | virtual void onMhAit(const std::shared_ptr& mhBit) {} 33 | virtual void onMhCdt(const std::shared_ptr& mhCdt) {} 34 | virtual void onMhEit(const std::shared_ptr& mhEit) {} 35 | virtual void onMhSdtActual(const std::shared_ptr& mhSdt) {} 36 | virtual void onMhTot(const std::shared_ptr& mhTot) {} 37 | virtual void onMpt(const std::shared_ptr& mpt) {} 38 | virtual void onPlt(const std::shared_ptr& plt) {} 39 | 40 | // TLV-SI 41 | virtual void onNit(const std::shared_ptr& nit) {} 42 | 43 | // IPv6 44 | virtual void onNtp(const std::shared_ptr& ntp) {} 45 | 46 | }; 47 | 48 | } -------------------------------------------------------------------------------- /src/ecm.cpp: -------------------------------------------------------------------------------- 1 | #include "ecm.h" 2 | 3 | namespace MmtTlv { 4 | 5 | bool Ecm::unpack(Common::ReadStream& stream) 6 | { 7 | try { 8 | if (!MmtTableBase::unpack(stream)) { 9 | return false; 10 | } 11 | 12 | uint16_t uint16 = stream.getBe16U(); 13 | sectionSyntaxIndicator = (uint16 & 0b1000000000000000) >> 15; 14 | sectionLength = uint16 & 0b0000111111111111; 15 | 16 | tlvStreamId = stream.getBe16U(); 17 | 18 | uint8_t uint8 = stream.get8U(); 19 | currentNextIndicator = uint8 & 1; 20 | sectionNumber = stream.get8U(); 21 | lastSectionNumber = stream.get8U(); 22 | 23 | ecmData.resize(stream.leftBytes() - 4); 24 | stream.read(ecmData.data(), stream.leftBytes() - 4); 25 | 26 | crc32 = stream.getBe32U(); 27 | } 28 | catch (const std::out_of_range&) { 29 | return false; 30 | } 31 | 32 | return true; 33 | } 34 | 35 | } -------------------------------------------------------------------------------- /src/ecm.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "mmtTableBase.h" 3 | 4 | namespace MmtTlv { 5 | 6 | // Entitlement Control Message 7 | class Ecm : public MmtTableBase { 8 | public: 9 | bool unpack(Common::ReadStream& stream); 10 | 11 | uint16_t sectionSyntaxIndicator; 12 | uint16_t sectionLength; 13 | uint16_t tlvStreamId; 14 | 15 | bool currentNextIndicator; 16 | uint8_t sectionNumber; 17 | uint8_t lastSectionNumber; 18 | 19 | std::vector ecmData; 20 | 21 | uint32_t crc32; 22 | }; 23 | 24 | } -------------------------------------------------------------------------------- /src/eventPackageDescriptor.cpp: -------------------------------------------------------------------------------- 1 | #include "eventPackageDescriptor.h" 2 | 3 | namespace MmtTlv { 4 | 5 | bool EventPackageDescriptor::unpack(Common::ReadStream& stream) 6 | { 7 | try { 8 | if (!MmtDescriptorTemplate::unpack(stream)) { 9 | return false; 10 | } 11 | 12 | Common::ReadStream nstream(stream, descriptorLength); 13 | 14 | mmtPackageIdLength = nstream.get8U(); 15 | 16 | mmtPackageIdByte.resize(mmtPackageIdLength); 17 | nstream.read(mmtPackageIdByte.data(), mmtPackageIdLength); 18 | 19 | stream.skip(descriptorLength); 20 | } 21 | catch (const std::out_of_range&) { 22 | return false; 23 | } 24 | 25 | return true; 26 | } 27 | 28 | } -------------------------------------------------------------------------------- /src/eventPackageDescriptor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "mmtDescriptorBase.h" 3 | 4 | namespace MmtTlv { 5 | 6 | class EventPackageDescriptor 7 | : public MmtDescriptorTemplate<0x8001> { 8 | public: 9 | bool unpack(Common::ReadStream& stream) override; 10 | 11 | uint8_t mmtPackageIdLength; 12 | std::vector mmtPackageIdByte; 13 | }; 14 | 15 | } -------------------------------------------------------------------------------- /src/extensionHeaderScrambling.cpp: -------------------------------------------------------------------------------- 1 | #include "extensionHeaderScrambling.h" 2 | 3 | namespace MmtTlv { 4 | 5 | bool ExtensionHeaderScrambling::unpack(Common::ReadStream& stream, uint16_t extensionHeaderType, uint16_t extensionHeaderLength) 6 | { 7 | try { 8 | if (stream.leftBytes() < 1) { 9 | return false; 10 | } 11 | 12 | uint8_t uint8 = stream.get8U(); 13 | encryptionFlag = static_cast((uint8 & 0b00011000) >> 3); 14 | scramblingSubsystem = (uint8 & 0b00000100) >> 2; 15 | messageAuthenticationControl = (uint8 & 0b00000010) >> 1; 16 | scramblingInitialCounterValue = uint8 & 0b00000001; 17 | } 18 | catch (const std::out_of_range&) { 19 | return false; 20 | } 21 | 22 | return true; 23 | } 24 | 25 | } -------------------------------------------------------------------------------- /src/extensionHeaderScrambling.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "stream.h" 4 | 5 | namespace MmtTlv { 6 | 7 | enum class EncryptionFlag : uint8_t 8 | { 9 | UNSCRAMBLED = 0x00, 10 | RESERVED = 0x01, 11 | EVEN = 0x02, 12 | ODD = 0x03, 13 | }; 14 | 15 | class ExtensionHeaderScrambling { 16 | public: 17 | bool unpack(Common::ReadStream& stream, uint16_t extensionHeaderType, uint16_t extensionHeaderLength); 18 | EncryptionFlag encryptionFlag; 19 | uint8_t scramblingSubsystem; 20 | uint8_t messageAuthenticationControl; 21 | uint8_t scramblingInitialCounterValue; 22 | }; 23 | 24 | } -------------------------------------------------------------------------------- /src/fragmentAssembler.cpp: -------------------------------------------------------------------------------- 1 | #include "fragmentAssembler.h" 2 | #include "mmtFragment.h" 3 | 4 | namespace MmtTlv { 5 | 6 | bool FragmentAssembler::assemble(const std::vector& fragment, FragmentationIndicator fragmentationIndicator, uint32_t packetSequenceNumber) 7 | { 8 | switch (fragmentationIndicator) { 9 | case FragmentationIndicator::NotFragmented: 10 | if (state == State::InFragment) 11 | return false; 12 | 13 | data.insert(data.end(), fragment.begin(), fragment.end()); 14 | state = State::NotStarted; 15 | return true; 16 | case FragmentationIndicator::FirstFragment: 17 | if (state == State::InFragment) { 18 | return false; 19 | } 20 | 21 | state = State::InFragment; 22 | data.insert(data.end(), fragment.begin(), fragment.end()); 23 | break; 24 | case FragmentationIndicator::MiddleFragment: 25 | if (state == State::Skip) { 26 | return false; 27 | } 28 | 29 | if (state != State::InFragment) { 30 | return false; 31 | } 32 | 33 | data.insert(data.end(), fragment.begin(), fragment.end()); 34 | break; 35 | case FragmentationIndicator::LastFragment: 36 | if (state == State::Skip) { 37 | return false; 38 | } 39 | 40 | if (state != State::InFragment) 41 | return false; 42 | 43 | data.insert(data.end(), fragment.begin(), fragment.end()); 44 | state = State::NotStarted; 45 | return true; 46 | } 47 | 48 | return false; 49 | } 50 | 51 | void FragmentAssembler::checkState(uint32_t packetSequenceNumber) 52 | { 53 | if (state == State::Init) { 54 | state = State::Skip; 55 | } 56 | else if (packetSequenceNumber != last_seq + 1) { 57 | if (data.size() != 0) { 58 | data.clear(); 59 | } 60 | 61 | state = State::Skip; 62 | } 63 | last_seq = packetSequenceNumber; 64 | } 65 | 66 | void FragmentAssembler::clear() 67 | { 68 | state = State::NotStarted; 69 | data.clear(); 70 | } 71 | 72 | } -------------------------------------------------------------------------------- /src/fragmentAssembler.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include "mmtFragment.h" 5 | 6 | namespace MmtTlv { 7 | 8 | class FragmentAssembler { 9 | public: 10 | bool assemble(const std::vector& fragment, FragmentationIndicator fragmentationIndicator, uint32_t packetSequenceNumber); 11 | void checkState(uint32_t packetSequenceNumber); 12 | void clear(); 13 | 14 | enum class State 15 | { 16 | Init, 17 | NotStarted, 18 | InFragment, 19 | Skip, 20 | }; 21 | 22 | State state = State::Init; 23 | std::vector data; 24 | uint32_t last_seq = 0; 25 | }; 26 | 27 | } -------------------------------------------------------------------------------- /src/hashUtil.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace MmtTlv { 9 | 10 | namespace Common { 11 | using sha256_t = std::array; 12 | 13 | inline sha256_t sha256(const std::vector& input) 14 | { 15 | std::unique_ptr ctx(EVP_MD_CTX_new(), &EVP_MD_CTX_free); 16 | 17 | EVP_DigestInit_ex(ctx.get(), EVP_sha256(), nullptr); 18 | EVP_DigestUpdate(ctx.get(), input.data(), input.size()); 19 | 20 | sha256_t output; 21 | EVP_DigestFinal_ex(ctx.get(), output.data(), nullptr); 22 | 23 | return output; 24 | } 25 | } 26 | 27 | } -------------------------------------------------------------------------------- /src/ip.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace MmtTlv { 5 | 6 | namespace Common { 7 | 8 | struct in6_addr 9 | { 10 | union 11 | { 12 | uint8_t u6_addr8[16]; 13 | uint16_t u6_addr16[8]; 14 | uint32_t u6_addr32[4]; 15 | } in6_u; 16 | }; 17 | 18 | } 19 | 20 | } -------------------------------------------------------------------------------- /src/ipv6.cpp: -------------------------------------------------------------------------------- 1 | #include "ipv6.h" 2 | 3 | namespace MmtTlv { 4 | 5 | bool IPv6Header::unpack(Common::ReadStream& stream) 6 | { 7 | try { 8 | uint16_t uint16 = stream.getBe16U(); 9 | version = (uint16 & 0b1111000000000000) >> 12; 10 | priority = (uint16 & 0b0000111111110000) >> 4; 11 | flow_lbl = (uint16 & 0b0000000000001111) << 16; 12 | 13 | uint16 = stream.getBe16U(); 14 | flow_lbl |= uint16; 15 | 16 | if (!isCompressed) { 17 | payloadLength = stream.getBe16U(); 18 | } 19 | 20 | nexthdr = stream.get8U(); 21 | hop_limit = stream.get8U(); 22 | 23 | stream.read(saddr.in6_u.u6_addr8, 16); 24 | stream.read(daddr.in6_u.u6_addr8, 16); 25 | } 26 | catch (const std::out_of_range&) { 27 | return false; 28 | } 29 | 30 | return true; 31 | } 32 | 33 | bool IPv6ExtensionHeader::unpack(Common::ReadStream& stream, bool headerLengthOnly) 34 | { 35 | try { 36 | if (!headerLengthOnly) { 37 | next_header = stream.get8U(); 38 | } 39 | header_length = stream.get8U(); 40 | } 41 | catch (const std::out_of_range&) { 42 | return false; 43 | } 44 | 45 | return true; 46 | } 47 | 48 | bool UDPHeader::unpack(Common::ReadStream& stream, bool headerLengthOnly) 49 | { 50 | try { 51 | source_port = stream.getBe16U(); 52 | destination_port = stream.getBe16U(); 53 | length = stream.getBe16U(); 54 | checksum = stream.getBe16U(); 55 | } 56 | catch (const std::out_of_range&) { 57 | return false; 58 | } 59 | 60 | return true; 61 | } 62 | 63 | } -------------------------------------------------------------------------------- /src/ipv6.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "stream.h" 3 | #include "ip.h" 4 | 5 | namespace MmtTlv { 6 | 7 | namespace IPv6 { 8 | constexpr uint8_t PROTOCOL_UDP = 17; 9 | constexpr uint16_t PORT_NTP = 123; 10 | } 11 | 12 | class IPv6Header { 13 | public: 14 | IPv6Header(bool isCompressed = false) : 15 | isCompressed(isCompressed) {} 16 | 17 | bool unpack(Common::ReadStream& stream); 18 | 19 | public: 20 | bool isCompressed{}; 21 | uint8_t version{}; 22 | uint8_t priority{}; 23 | uint32_t flow_lbl{}; 24 | uint8_t nexthdr{}; 25 | uint8_t hop_limit{}; 26 | 27 | 28 | uint16_t payloadLength{}; 29 | uint8_t payloadType{}; 30 | 31 | struct Common::in6_addr saddr; 32 | struct Common::in6_addr daddr; 33 | }; 34 | 35 | class IPv6ExtensionHeader { 36 | public: 37 | bool unpack(Common::ReadStream& stream, bool headerLengthOnly=false); 38 | 39 | public: 40 | uint8_t next_header; 41 | uint8_t header_length; 42 | 43 | }; 44 | 45 | class UDPHeader { 46 | public: 47 | bool unpack(Common::ReadStream& stream, bool headerLengthOnly = false); 48 | 49 | public: 50 | uint16_t source_port; 51 | uint16_t destination_port; 52 | uint16_t length; 53 | uint16_t checksum; 54 | }; 55 | } -------------------------------------------------------------------------------- /src/logger.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | inline void log_debug(const char* format, ...) 11 | { 12 | auto now = std::chrono::system_clock::now(); 13 | auto ms = std::chrono::duration_cast(now.time_since_epoch()) % 1000; 14 | std::time_t t = std::chrono::system_clock::to_time_t(now); 15 | std::tm tm; 16 | localtime_s(&tm, &t); 17 | 18 | va_list args; 19 | va_start(args, format); 20 | 21 | char argsBuffer[1920]; 22 | vsnprintf(argsBuffer, sizeof(argsBuffer), format, args); 23 | 24 | va_end(args); 25 | 26 | std::ostringstream oss; 27 | oss << "[dantto4k] " 28 | << std::setw(2) << std::setfill('0') << tm.tm_hour << ":" 29 | << std::setw(2) << std::setfill('0') << tm.tm_min << ":" 30 | << std::setw(2) << std::setfill('0') << tm.tm_sec << "." 31 | << std::setw(3) << std::setfill('0') << ms.count() << " " 32 | << argsBuffer << "\n"; 33 | 34 | std::string logMessage = oss.str(); 35 | OutputDebugStringA(logMessage.c_str()); 36 | 37 | std::cerr << logMessage; 38 | } -------------------------------------------------------------------------------- /src/m2SectionMessage.cpp: -------------------------------------------------------------------------------- 1 | #include "m2SectionMessage.h" 2 | 3 | namespace MmtTlv { 4 | 5 | bool M2SectionMessage::unpack(Common::ReadStream& stream) 6 | { 7 | try { 8 | messageId = stream.getBe16U(); 9 | version = stream.get8U(); 10 | length = stream.getBe16U(); 11 | } 12 | catch (const std::out_of_range&) { 13 | return false; 14 | } 15 | 16 | return true; 17 | } 18 | 19 | } -------------------------------------------------------------------------------- /src/m2SectionMessage.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "stream.h" 4 | 5 | namespace MmtTlv { 6 | 7 | class M2SectionMessage { 8 | public: 9 | bool unpack(Common::ReadStream& stream); 10 | 11 | uint16_t messageId; 12 | uint8_t version; 13 | uint16_t length; 14 | }; 15 | 16 | } -------------------------------------------------------------------------------- /src/m2ShortSectionMessage.cpp: -------------------------------------------------------------------------------- 1 | #include "m2ShortSectionMessage.h" 2 | 3 | namespace MmtTlv { 4 | 5 | bool M2ShortSectionMessage::unpack(Common::ReadStream& stream) 6 | { 7 | try { 8 | messageId = stream.getBe16U(); 9 | version = stream.get8U(); 10 | length = stream.getBe16U(); 11 | } 12 | catch (const std::out_of_range&) { 13 | return false; 14 | } 15 | 16 | return true; 17 | } 18 | 19 | } -------------------------------------------------------------------------------- /src/m2ShortSectionMessage.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "stream.h" 4 | 5 | namespace MmtTlv { 6 | 7 | class M2ShortSectionMessage { 8 | public: 9 | bool unpack(Common::ReadStream& stream); 10 | 11 | uint16_t messageId; 12 | uint8_t version; 13 | uint16_t length; 14 | }; 15 | 16 | } -------------------------------------------------------------------------------- /src/mfuDataProcessorBase.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include "mmtStream.h" 6 | 7 | namespace MmtTlv { 8 | 9 | constexpr int32_t makeAssetType(uint32_t a, uint32_t b, uint32_t c, uint32_t d) { 10 | return (a << 24) | (b << 16) | (c << 8) | d; 11 | } 12 | 13 | namespace AssetType { 14 | constexpr int32_t hev1 = makeAssetType('h', 'e', 'v', '1'); 15 | constexpr int32_t mp4a = makeAssetType('m', 'p', '4', 'a'); 16 | constexpr int32_t stpp = makeAssetType('s', 't', 'p', 'p'); 17 | constexpr int32_t aapp = makeAssetType('a', 'a', 'p', 'p'); 18 | } 19 | 20 | constexpr uint64_t NOPTS_VALUE = 0x8000000000000000; 21 | 22 | struct MfuData { 23 | std::vector data; 24 | uint64_t pts{NOPTS_VALUE}; 25 | uint64_t dts{NOPTS_VALUE}; 26 | int streamIndex{}; 27 | bool keyframe{false}; 28 | }; 29 | 30 | class MfuDataProcessorBase { 31 | public: 32 | virtual ~MfuDataProcessorBase() = default; 33 | virtual std::optional process(const std::shared_ptr& mmtStream, const std::vector& data) { return std::nullopt; } 34 | 35 | }; 36 | 37 | template 38 | class MfuDataProcessorTemplate : public MfuDataProcessorBase { 39 | public: 40 | virtual ~MfuDataProcessorTemplate() = default; 41 | 42 | static constexpr uint32_t kAssetType = assetType; 43 | 44 | }; 45 | 46 | } -------------------------------------------------------------------------------- /src/mfuDataProcessorFactory.cpp: -------------------------------------------------------------------------------- 1 | #include "mfuDataProcessorFactory.h" 2 | #include "applicationMfuDataProcessor.h" 3 | #include "videoMfuDataProcessor.h" 4 | #include "audioMfuDataProcessor.h" 5 | #include "subtitleMfuDataProcessor.h" 6 | 7 | namespace MmtTlv { 8 | 9 | std::shared_ptr MfuDataProcessorFactory::create(uint32_t tag) 10 | { 11 | switch (tag) { 12 | case VideoMfuDataProcessor::kAssetType: 13 | return std::make_shared(); 14 | case AudioMfuDataProcessor::kAssetType: 15 | return std::make_shared(); 16 | case SubtitleMfuDataProcessor::kAssetType: 17 | return std::make_shared(); 18 | case ApplicationMfuDataProcessor::kAssetType: 19 | return std::make_shared(); 20 | } 21 | 22 | return {}; 23 | } 24 | 25 | } -------------------------------------------------------------------------------- /src/mfuDataProcessorFactory.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "mfuDataProcessorBase.h" 3 | 4 | namespace MmtTlv { 5 | 6 | class MfuDataProcessorBase; 7 | class MfuDataProcessorFactory { 8 | public: 9 | static std::shared_ptr create(uint32_t tag); 10 | 11 | }; 12 | 13 | } -------------------------------------------------------------------------------- /src/mhAit.cpp: -------------------------------------------------------------------------------- 1 | #include "mhAit.h" 2 | 3 | namespace MmtTlv { 4 | 5 | bool MhAit::unpack(Common::ReadStream& stream) 6 | { 7 | try { 8 | if (!MmtTableBase::unpack(stream)) { 9 | return false; 10 | } 11 | 12 | uint16_t uint16 = stream.getBe16U(); 13 | sectionSyntaxIndicator = (uint16 & 0b1000000000000000) >> 15; 14 | sectionLength = uint16 & 0b0000111111111111; 15 | 16 | applicationType = stream.getBe16U(); 17 | 18 | uint8_t uint8 = stream.get8U(); 19 | versionNumber = (uint8 & 0b00111110) >> 1; 20 | currentNextIndicator = uint8 & 1; 21 | sectionNumber = stream.get8U(); 22 | lastSectionNumber = stream.get8U(); 23 | 24 | uint16 = stream.getBe16U(); 25 | commonDescriptorLength = uint16 & 0b0000111111111111; 26 | 27 | Common::ReadStream nstream(stream, commonDescriptorLength); 28 | 29 | if (!descriptors.unpack(nstream)) { 30 | return false; 31 | } 32 | 33 | stream.skip(commonDescriptorLength); 34 | 35 | uint16 = stream.getBe16U(); 36 | applicationLoopLength = uint16 & 0b0000111111111111; 37 | 38 | while (stream.leftBytes() - 4 > 0) { 39 | ApplicationIdentifier applicationIdentifier; 40 | if (!applicationIdentifier.unpack(stream)) { 41 | return false; 42 | } 43 | 44 | applicationIdentifiers.push_back(applicationIdentifier); 45 | } 46 | 47 | crc32 = stream.getBe32U(); 48 | } 49 | catch (const std::out_of_range&) { 50 | return false; 51 | } 52 | 53 | return true; 54 | } 55 | 56 | bool MhAit::ApplicationIdentifier::unpack(Common::ReadStream& stream) 57 | { 58 | try { 59 | applicationControlCode = stream.get8U(); 60 | 61 | uint16_t uint16 = stream.getBe16U(); 62 | applicationDescriptorLoopLength = uint16 & 0b0000111111111111; 63 | 64 | Common::ReadStream nstream(stream, applicationDescriptorLoopLength); 65 | if (!descriptors.unpack(nstream)) { 66 | return false; 67 | } 68 | 69 | stream.skip(applicationDescriptorLoopLength); 70 | } 71 | catch (const std::out_of_range&) { 72 | return false; 73 | } 74 | 75 | return true; 76 | } 77 | 78 | } -------------------------------------------------------------------------------- /src/mhAit.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "mmtTableBase.h" 4 | #include "mmtDescriptors.h" 5 | 6 | namespace MmtTlv { 7 | 8 | // MH-Application Information Table 9 | class MhAit : public MmtTableBase { 10 | public: 11 | bool unpack(Common::ReadStream& stream); 12 | 13 | class ApplicationIdentifier { 14 | public: 15 | bool unpack(Common::ReadStream& stream); 16 | uint8_t applicationControlCode; 17 | uint16_t applicationDescriptorLoopLength; 18 | MmtDescriptors descriptors; 19 | }; 20 | 21 | uint16_t sectionSyntaxIndicator; 22 | uint16_t sectionLength; 23 | 24 | uint16_t applicationType; 25 | uint8_t versionNumber; 26 | bool currentNextIndicator; 27 | uint8_t sectionNumber; 28 | uint8_t lastSectionNumber; 29 | 30 | uint16_t commonDescriptorLength; 31 | MmtDescriptors descriptors; 32 | uint16_t applicationLoopLength; 33 | 34 | std::list applicationIdentifiers; 35 | uint32_t crc32; 36 | }; 37 | 38 | } -------------------------------------------------------------------------------- /src/mhApplicationDescriptor.cpp: -------------------------------------------------------------------------------- 1 | #include "mhApplicationDescriptor.h" 2 | 3 | namespace MmtTlv { 4 | 5 | bool MhApplicationDescriptor::unpack(Common::ReadStream& stream) 6 | { 7 | try { 8 | if (!MmtDescriptorTemplate::unpack(stream)) { 9 | return false; 10 | } 11 | 12 | Common::ReadStream nstream(stream, descriptorLength); 13 | 14 | applicationProfilesLength = nstream.get8U(); 15 | size_t leftBytes = nstream.leftBytes(); 16 | while (nstream.leftBytes() - (leftBytes - applicationProfilesLength) > 0) { 17 | ApplicationProfile applicationProfile; 18 | if (!applicationProfile.unpack(nstream)) { 19 | return false; 20 | } 21 | 22 | applicationProfiles.push_back(applicationProfile); 23 | } 24 | 25 | uint8_t uint8 = nstream.get8U(); 26 | 27 | serviceBoundFlag = (uint8 & 0b10000000) >> 7; 28 | visibility = (uint8 & 0b01100000) >> 5; 29 | presentApplicationPriority = uint8 & 0b00000001; 30 | 31 | applicationPriority = nstream.get8U(); 32 | 33 | transportProtocolLabel.resize(nstream.leftBytes()); 34 | nstream.read(transportProtocolLabel.data(), nstream.leftBytes()); 35 | 36 | stream.skip(descriptorLength); 37 | } 38 | catch (const std::out_of_range&) { 39 | return false; 40 | } 41 | 42 | return true; 43 | } 44 | 45 | bool MhApplicationDescriptor::ApplicationProfile::unpack(Common::ReadStream& stream) 46 | { 47 | try { 48 | applicationProfile = stream.getBe16U(); 49 | versionMajor = stream.get8U(); 50 | versionMinor = stream.get8U(); 51 | versionMicro = stream.get8U(); 52 | } 53 | catch (const std::out_of_range&) { 54 | return false; 55 | } 56 | 57 | return true; 58 | } 59 | 60 | } -------------------------------------------------------------------------------- /src/mhApplicationDescriptor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "mmtDescriptorBase.h" 3 | #include 4 | 5 | namespace MmtTlv { 6 | 7 | class MhApplicationDescriptor 8 | : public MmtDescriptorTemplate<0x8029> { 9 | public: 10 | bool unpack(Common::ReadStream& stream) override; 11 | 12 | class ApplicationProfile { 13 | public: 14 | bool unpack(Common::ReadStream& stream); 15 | 16 | uint16_t applicationProfile; 17 | uint8_t versionMajor; 18 | uint8_t versionMinor; 19 | uint8_t versionMicro; 20 | }; 21 | 22 | uint8_t applicationProfilesLength; 23 | std::list applicationProfiles; 24 | 25 | bool serviceBoundFlag; 26 | uint8_t visibility; 27 | bool presentApplicationPriority; 28 | uint8_t applicationPriority; 29 | std::string transportProtocolLabel; 30 | }; 31 | 32 | } -------------------------------------------------------------------------------- /src/mhAudioComponentDescriptor.cpp: -------------------------------------------------------------------------------- 1 | #include "mhAudioComponentDescriptor.h" 2 | 3 | namespace MmtTlv { 4 | 5 | bool MhAudioComponentDescriptor::unpack(Common::ReadStream& stream) 6 | { 7 | try { 8 | if (!MmtDescriptorTemplate::unpack(stream)) { 9 | return false; 10 | } 11 | 12 | Common::ReadStream nstream(stream, descriptorLength); 13 | 14 | uint8_t uint8 = nstream.get8U(); 15 | streamContent = uint8 & 0b00001111; 16 | componentType = nstream.get8U(); 17 | componentTag = nstream.getBe16U(); 18 | streamType = nstream.get8U(); 19 | simulcastGroupTag = nstream.get8U(); 20 | 21 | uint8 = nstream.get8U(); 22 | esMultiLingualFlag = (uint8 & 0b10000000) >> 7; 23 | mainComponentFlag = (uint8 & 0b01000000) >> 6; 24 | qualityIndicator = (uint8 & 0b00110000) >> 4; 25 | samplingRate = (uint8 & 0b00001110) >> 1; 26 | 27 | nstream.read(language1, 3); 28 | language1[3] = '\0'; 29 | 30 | if (esMultiLingualFlag) { 31 | nstream.read(language2, 3); 32 | language2[3] = '\0'; 33 | } 34 | 35 | size_t textLength = nstream.leftBytes(); 36 | if (textLength) { 37 | text.resize(textLength); 38 | nstream.read(text.data(), textLength); 39 | } 40 | 41 | stream.skip(descriptorLength); 42 | } 43 | catch (const std::out_of_range&) { 44 | return false; 45 | } 46 | 47 | return true; 48 | } 49 | 50 | uint32_t MhAudioComponentDescriptor::getConvertedSamplingRate() const 51 | { 52 | switch (samplingRate) { 53 | case 0b001: 54 | return 16000; 55 | case 0b010: 56 | return 22050; 57 | case 0b011: 58 | return 24000; 59 | case 0b101: 60 | return 32000; 61 | case 0b110: 62 | return 44100; 63 | case 0b111: 64 | return 48000; 65 | } 66 | 67 | return 0; 68 | } 69 | 70 | } -------------------------------------------------------------------------------- /src/mhAudioComponentDescriptor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "mmtDescriptorBase.h" 3 | 4 | namespace MmtTlv { 5 | 6 | class MhAudioComponentDescriptor 7 | : public MmtDescriptorTemplate<0x8014> { 8 | public: 9 | bool unpack(Common::ReadStream& stream) override; 10 | 11 | uint32_t getConvertedSamplingRate() const; 12 | uint8_t getDialogControl() const { return componentType & 0b10000000 >> 7; } 13 | uint8_t getAudioForHandicapped() const { return componentType & 0b01100000 >> 5; } 14 | uint8_t getAudioMode() const { return componentType & 0b00011111; } 15 | 16 | bool Is22_2chAudio() const { return getAudioMode() == 0b10001; } 17 | 18 | uint8_t streamContent; 19 | uint8_t componentType; 20 | uint16_t componentTag; 21 | uint8_t streamType; 22 | uint8_t simulcastGroupTag; 23 | bool esMultiLingualFlag; 24 | bool mainComponentFlag; 25 | uint8_t qualityIndicator; 26 | uint8_t samplingRate; 27 | char language1[4]; 28 | char language2[4]; 29 | std::string text; 30 | }; 31 | 32 | } -------------------------------------------------------------------------------- /src/mhBit.cpp: -------------------------------------------------------------------------------- 1 | #include "mhBit.h" 2 | 3 | namespace MmtTlv { 4 | 5 | bool MhBit::unpack(Common::ReadStream& stream) 6 | { 7 | try { 8 | if (!MmtTableBase::unpack(stream)) { 9 | return false; 10 | } 11 | 12 | uint16_t uint16 = stream.getBe16U(); 13 | sectionSyntaxIndicator = (uint16 & 0b1000000000000000) >> 15; 14 | sectionLength = uint16 & 0b0000111111111111; 15 | 16 | originalNetworkId = stream.getBe16U(); 17 | 18 | uint8_t uint8 = stream.get8U(); 19 | versionNumber = (uint8 & 0b00111110) >> 1; 20 | currentNextIndicator = uint8 & 1; 21 | sectionNumber = stream.get8U(); 22 | lastSectionNumber = stream.get8U(); 23 | 24 | uint16 = stream.getBe16U(); 25 | broadcastViewPropriety = (uint16 & 0b0001000000000000) >> 12; 26 | firstDescriptorsLength = uint16 & 0b0000111111111111; 27 | 28 | Common::ReadStream nstream(stream, firstDescriptorsLength); 29 | 30 | if (!descriptors.unpack(nstream)) { 31 | return false; 32 | } 33 | 34 | stream.skip(firstDescriptorsLength); 35 | 36 | while (stream.leftBytes() - 4 > 0) { 37 | Broadcaster entry; 38 | if (!entry.unpack(stream)) { 39 | return false; 40 | } 41 | 42 | broadcasters.push_back(entry); 43 | } 44 | 45 | crc32 = stream.getBe32U(); 46 | } 47 | catch (const std::out_of_range&) { 48 | return false; 49 | } 50 | 51 | return true; 52 | } 53 | 54 | bool MhBit::Broadcaster::unpack(Common::ReadStream& stream) 55 | { 56 | try { 57 | broadcasterId = stream.get8U(); 58 | 59 | uint16_t uint16 = stream.getBe16U(); 60 | broadcasterDescriptorsLength = uint16 & 0b0000111111111111; 61 | 62 | Common::ReadStream nstream(stream, broadcasterDescriptorsLength); 63 | if (!descriptors.unpack(nstream)) { 64 | return false; 65 | } 66 | 67 | stream.skip(broadcasterDescriptorsLength); 68 | } 69 | catch (const std::out_of_range&) { 70 | return false; 71 | } 72 | 73 | return true; 74 | } 75 | } -------------------------------------------------------------------------------- /src/mhBit.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "mmtTableBase.h" 4 | #include "mmtDescriptors.h" 5 | 6 | namespace MmtTlv { 7 | 8 | // MH-Broadcaster Information Table 9 | class MhBit : public MmtTableBase { 10 | public: 11 | bool unpack(Common::ReadStream& stream); 12 | 13 | class Broadcaster { 14 | public: 15 | bool unpack(Common::ReadStream& stream); 16 | 17 | uint8_t broadcasterId; 18 | uint16_t broadcasterDescriptorsLength; 19 | MmtDescriptors descriptors; 20 | }; 21 | 22 | uint16_t sectionSyntaxIndicator; 23 | uint16_t sectionLength; 24 | 25 | uint16_t originalNetworkId; 26 | uint8_t versionNumber; 27 | bool currentNextIndicator; 28 | uint8_t sectionNumber; 29 | uint8_t lastSectionNumber; 30 | 31 | bool broadcastViewPropriety; 32 | uint16_t firstDescriptorsLength; 33 | 34 | MmtDescriptors descriptors; 35 | 36 | 37 | std::vector broadcasters; 38 | uint32_t crc32; 39 | }; 40 | 41 | } -------------------------------------------------------------------------------- /src/mhBroadcasterNameDescriptor.cpp: -------------------------------------------------------------------------------- 1 | #include "mhBroadcasterNameDescriptor.h" 2 | 3 | namespace MmtTlv { 4 | 5 | bool MhBroadcasterNameDescriptor::unpack(Common::ReadStream& stream) 6 | { 7 | try { 8 | if (!MmtDescriptorTemplate::unpack(stream)) { 9 | return false; 10 | } 11 | 12 | Common::ReadStream nstream(stream, descriptorLength); 13 | 14 | text.resize(nstream.leftBytes()); 15 | nstream.read(text.data(), nstream.leftBytes()); 16 | 17 | stream.skip(descriptorLength); 18 | } 19 | catch (const std::out_of_range&) { 20 | return false; 21 | } 22 | 23 | return true; 24 | } 25 | 26 | } -------------------------------------------------------------------------------- /src/mhBroadcasterNameDescriptor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "mmtDescriptorBase.h" 3 | 4 | namespace MmtTlv { 5 | 6 | class MhBroadcasterNameDescriptor 7 | : public MmtDescriptorTemplate<0x8018> { 8 | public: 9 | bool unpack(Common::ReadStream& stream) override; 10 | 11 | std::string text; 12 | }; 13 | 14 | } -------------------------------------------------------------------------------- /src/mhCaContractInformation.cpp: -------------------------------------------------------------------------------- 1 | #include "mhCaContractInformation.h" 2 | 3 | namespace MmtTlv { 4 | 5 | bool MhCaContractInformation::unpack(Common::ReadStream& stream) 6 | { 7 | try { 8 | if (!MmtDescriptorTemplate::unpack(stream)) { 9 | return false; 10 | } 11 | 12 | Common::ReadStream nstream(stream, descriptorLength); 13 | 14 | caSystemId = nstream.getBe16U(); 15 | 16 | uint8_t uint8 = nstream.get8U(); 17 | caUnitId = (uint8 & 0b11110000) >> 4; 18 | numOfComponent = uint8 & 0b00001111; 19 | 20 | for (int i = 0; i < numOfComponent; i++) { 21 | componentTags.push_back(nstream.getBe16U()); 22 | } 23 | 24 | contractVerificationInfoLength = nstream.get8U(); 25 | contractVerificationInfo.resize(contractVerificationInfoLength); 26 | nstream.read(contractVerificationInfo.data(), contractVerificationInfoLength); 27 | 28 | feeNameLength = nstream.get8U(); 29 | feeName.resize(feeNameLength); 30 | nstream.read(feeName.data(), feeNameLength); 31 | 32 | stream.skip(descriptorLength); 33 | } 34 | catch (const std::out_of_range&) { 35 | return false; 36 | } 37 | 38 | return true; 39 | } 40 | 41 | } -------------------------------------------------------------------------------- /src/mhCaContractInformation.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "mmtDescriptorBase.h" 3 | #include 4 | 5 | namespace MmtTlv { 6 | 7 | class MhCaContractInformation 8 | : public MmtDescriptorTemplate<0x8041> { 9 | public: 10 | bool unpack(Common::ReadStream& stream) override; 11 | 12 | uint16_t caSystemId; 13 | uint8_t caUnitId; 14 | uint8_t numOfComponent; 15 | 16 | std::list componentTags; 17 | 18 | uint8_t contractVerificationInfoLength; 19 | std::vector contractVerificationInfo; 20 | 21 | uint8_t feeNameLength; 22 | std::string feeName; 23 | 24 | }; 25 | 26 | } -------------------------------------------------------------------------------- /src/mhCdt.cpp: -------------------------------------------------------------------------------- 1 | #include "mhCdt.h" 2 | 3 | namespace MmtTlv { 4 | 5 | bool MhCdt::unpack(Common::ReadStream& stream) 6 | { 7 | try { 8 | if (!MmtTableBase::unpack(stream)) { 9 | return false; 10 | } 11 | 12 | uint16_t uint16 = stream.getBe16U(); 13 | sectionSyntaxIndicator = (uint16 & 0b1000000000000000) >> 15; 14 | sectionLength = uint16 & 0b0000111111111111; 15 | 16 | downloadDataId = stream.getBe16U(); 17 | 18 | uint8_t uint8 = stream.get8U(); 19 | versionNumber = (uint8 & 0b00111110) >> 1; 20 | currentNextIndicator = uint8 & 1; 21 | 22 | sectionNumber = stream.get8U(); 23 | lastSectionNumber = stream.get8U(); 24 | originalNetworkId = stream.getBe16U(); 25 | dataType = stream.get8U(); 26 | 27 | uint16 = stream.getBe16U(); 28 | reservedFutureUse = (uint16 & 0b1111000000000000) >> 12; 29 | descriptorsLoopLength = uint16 & 0b0000111111111111; 30 | 31 | if (stream.leftBytes() < descriptorsLoopLength) { 32 | return false; 33 | } 34 | 35 | Common::ReadStream nstream(stream, descriptorsLoopLength); 36 | if (!descriptors.unpack(nstream)) { 37 | return false; 38 | } 39 | stream.skip(descriptorsLoopLength); 40 | 41 | dataModuleByte.resize(stream.leftBytes() - 4); 42 | stream.read(dataModuleByte.data(), stream.leftBytes() - 4); 43 | 44 | if (stream.leftBytes() < 4) { 45 | return false; 46 | } 47 | 48 | crc32 = stream.getBe32U(); 49 | } 50 | catch (const std::out_of_range&) { 51 | return false; 52 | } 53 | 54 | return true; 55 | } 56 | 57 | } -------------------------------------------------------------------------------- /src/mhCdt.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "mmtTableBase.h" 4 | #include "mmtDescriptors.h" 5 | 6 | namespace MmtTlv { 7 | 8 | // Mh-Common Data Table 9 | class MhCdt : public MmtTableBase { 10 | public: 11 | bool unpack(Common::ReadStream& stream); 12 | 13 | uint16_t sectionSyntaxIndicator; 14 | uint16_t sectionLength; 15 | 16 | uint16_t downloadDataId; 17 | uint8_t versionNumber; 18 | bool currentNextIndicator; 19 | uint8_t sectionNumber; 20 | uint8_t lastSectionNumber; 21 | uint16_t originalNetworkId; 22 | 23 | uint8_t dataType; 24 | 25 | uint8_t reservedFutureUse; 26 | uint16_t descriptorsLoopLength; 27 | 28 | MmtDescriptors descriptors; 29 | 30 | std::vector dataModuleByte; 31 | uint32_t crc32; 32 | }; 33 | 34 | } -------------------------------------------------------------------------------- /src/mhContentDescriptor.cpp: -------------------------------------------------------------------------------- 1 | #include "mhContentDescriptor.h" 2 | 3 | namespace MmtTlv { 4 | 5 | bool MhContentDescriptor::unpack(Common::ReadStream& stream) 6 | { 7 | try { 8 | if (!MmtDescriptorTemplate::unpack(stream)) { 9 | return false; 10 | } 11 | 12 | Common::ReadStream nstream(stream, descriptorLength); 13 | 14 | while (!nstream.isEof()) { 15 | Entry entry; 16 | if (!entry.unpack(nstream)) { 17 | return false; 18 | } 19 | entries.push_back(entry); 20 | } 21 | 22 | stream.skip(descriptorLength); 23 | } 24 | catch (const std::out_of_range&) { 25 | return false; 26 | } 27 | 28 | return true; 29 | } 30 | 31 | bool MhContentDescriptor::Entry::unpack(Common::ReadStream& stream) 32 | { 33 | try { 34 | uint8_t uint8 = stream.get8U(); 35 | contentNibbleLevel1 = (uint8 & 0b11110000) >> 4; 36 | contentNibbleLevel2 = uint8 & 0b1111; 37 | 38 | uint8 = stream.get8U(); 39 | userNibble1 = (uint8 & 0b11110000) >> 4; 40 | userNibble2 = uint8 & 0b1111; 41 | } 42 | catch (const std::out_of_range&) { 43 | return false; 44 | } 45 | 46 | return true; 47 | } 48 | 49 | } -------------------------------------------------------------------------------- /src/mhContentDescriptor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "mmtDescriptorBase.h" 3 | #include 4 | 5 | namespace MmtTlv { 6 | 7 | class MhContentDescriptor 8 | : public MmtDescriptorTemplate<0x8012> { 9 | public: 10 | bool unpack(Common::ReadStream& stream) override; 11 | 12 | class Entry { 13 | public: 14 | bool unpack(Common::ReadStream& stream); 15 | 16 | uint8_t contentNibbleLevel1; 17 | uint8_t contentNibbleLevel2; 18 | uint8_t userNibble1; 19 | uint8_t userNibble2; 20 | }; 21 | 22 | std::list entries; 23 | }; 24 | 25 | } -------------------------------------------------------------------------------- /src/mhDataComponentDescriptor.cpp: -------------------------------------------------------------------------------- 1 | #include "mhDataComponentDescriptor.h" 2 | 3 | namespace MmtTlv { 4 | 5 | bool MhDataComponentDescriptor::unpack(Common::ReadStream& stream) 6 | { 7 | try { 8 | if (!MmtDescriptorTemplate::unpack(stream)) { 9 | return false; 10 | } 11 | 12 | Common::ReadStream nstream(stream, descriptorLength); 13 | 14 | dataComponentId = nstream.getBe16U(); 15 | additionalDataComponentInfo.resize(nstream.leftBytes()); 16 | nstream.read(additionalDataComponentInfo.data(), nstream.leftBytes()); 17 | 18 | stream.skip(descriptorLength); 19 | } 20 | catch (const std::out_of_range&) { 21 | return false; 22 | } 23 | 24 | return true; 25 | } 26 | 27 | } -------------------------------------------------------------------------------- /src/mhDataComponentDescriptor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "mmtDescriptorBase.h" 3 | 4 | namespace MmtTlv { 5 | 6 | class MhDataComponentDescriptor 7 | : public MmtDescriptorTemplate<0x8020> { 8 | public: 9 | bool unpack(Common::ReadStream& stream) override; 10 | 11 | uint16_t dataComponentId; 12 | std::vector additionalDataComponentInfo; 13 | }; 14 | 15 | } -------------------------------------------------------------------------------- /src/mhEit.cpp: -------------------------------------------------------------------------------- 1 | #include "mhEit.h" 2 | 3 | namespace MmtTlv { 4 | 5 | bool MhEit::unpack(Common::ReadStream& stream) 6 | { 7 | try { 8 | if (!MmtTableBase::unpack(stream)) { 9 | return false; 10 | } 11 | 12 | uint16_t uint16 = stream.getBe16U(); 13 | sectionSyntaxIndicator = (uint16 & 0b1000000000000000) >> 15; 14 | sectionLength = uint16 & 0b0000111111111111; 15 | 16 | serviceId = stream.getBe16U(); 17 | 18 | uint8_t uint8 = stream.get8U(); 19 | versionNumber = (uint8 & 0b00111110) >> 1; 20 | currentNextIndicator = uint8 & 1; 21 | 22 | sectionNumber = stream.get8U(); 23 | lastSectionNumber = stream.get8U(); 24 | tlvStreamId = stream.getBe16U(); 25 | originalNetworkId = stream.getBe16U(); 26 | segmentLastSectionNumber = stream.get8U(); 27 | lastTableId = stream.get8U(); 28 | 29 | while (stream.leftBytes() - 4 > 0) { 30 | std::shared_ptr event = std::make_shared(); 31 | if (!event->unpack(stream)) { 32 | return false; 33 | } 34 | 35 | events.push_back(event); 36 | } 37 | 38 | if (stream.leftBytes() < 4) { 39 | return false; 40 | } 41 | 42 | crc32 = stream.getBe32U(); 43 | } 44 | catch (const std::out_of_range&) { 45 | return false; 46 | } 47 | 48 | return true; 49 | } 50 | 51 | bool MhEit::Event::unpack(Common::ReadStream& stream) 52 | { 53 | try { 54 | eventId = stream.getBe16U(); 55 | 56 | uint64_t uint64 = stream.getBe64U(); 57 | startTime = (uint64 >> 24) & 0xFFFFFFFFFF; 58 | duration = uint64 & 0xFFFFFF; 59 | 60 | uint16_t uint16 = stream.getBe16U(); 61 | runningStatus = (uint16 & 0b1110000000000000) >> 13; 62 | freeCaMode = (uint16 & 0b0001000000000000) >> 12; 63 | descriptorsLoopLength = uint16 & 0b0000111111111111; 64 | 65 | if (stream.leftBytes() < descriptorsLoopLength) { 66 | return false; 67 | } 68 | 69 | Common::ReadStream nstream(stream, descriptorsLoopLength); 70 | if (!descriptors.unpack(nstream)) { 71 | return false; 72 | } 73 | stream.skip(descriptorsLoopLength); 74 | } 75 | catch (const std::out_of_range&) { 76 | return false; 77 | } 78 | 79 | return true; 80 | } 81 | 82 | } -------------------------------------------------------------------------------- /src/mhEit.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "mmtTableBase.h" 4 | #include "mmtDescriptors.h" 5 | 6 | namespace MmtTlv { 7 | 8 | class MmtDescriptorBase; 9 | 10 | // Mh-Event Information Table 11 | class MhEit : public MmtTableBase { 12 | public: 13 | bool unpack(Common::ReadStream& stream); 14 | 15 | class Event { 16 | public: 17 | bool unpack(Common::ReadStream& stream); 18 | 19 | uint16_t eventId; 20 | int64_t startTime; 21 | uint32_t duration; 22 | uint8_t runningStatus; 23 | uint8_t freeCaMode; 24 | uint16_t descriptorsLoopLength; 25 | 26 | MmtDescriptors descriptors; 27 | }; 28 | 29 | bool isPf() const { 30 | return tableId == MmtTableId::MhEitPf ? true : false; 31 | } 32 | 33 | uint16_t sectionSyntaxIndicator; 34 | uint16_t sectionLength; 35 | 36 | uint16_t serviceId; 37 | 38 | uint8_t versionNumber; 39 | bool currentNextIndicator; 40 | uint8_t sectionNumber; 41 | uint8_t lastSectionNumber; 42 | uint16_t tlvStreamId; 43 | uint16_t originalNetworkId; 44 | uint8_t segmentLastSectionNumber; 45 | uint8_t lastTableId; 46 | uint8_t eventCount; 47 | 48 | std::list> events; 49 | uint32_t crc32; 50 | }; 51 | 52 | } -------------------------------------------------------------------------------- /src/mhEventGroupDescriptor.cpp: -------------------------------------------------------------------------------- 1 | #include "mhEventGroupDescriptor.h" 2 | 3 | namespace MmtTlv { 4 | 5 | bool MhEventGroupDescriptor::unpack(Common::ReadStream& stream) 6 | { 7 | try { 8 | if (!MmtDescriptorTemplate::unpack(stream)) { 9 | return false; 10 | } 11 | 12 | Common::ReadStream nstream(stream, descriptorLength); 13 | 14 | uint8_t uint8 = nstream.get8U(); 15 | groupType = (uint8 & 0b11110000) >> 4; 16 | eventCount = uint8 & 0b00001111; 17 | 18 | for (int i = 0; i < eventCount; i++) { 19 | Event event; 20 | if (!event.unpack(nstream)) { 21 | return false; 22 | } 23 | events.push_back(event); 24 | } 25 | 26 | if (groupType == 4 || groupType == 5) { 27 | while (!nstream.isEof()) { 28 | OtherNetworkEvent otherNetworkEvent; 29 | if (!otherNetworkEvent.unpack(nstream)) { 30 | return false; 31 | } 32 | otherNetworkEvents.push_back(otherNetworkEvent); 33 | } 34 | } 35 | else { 36 | privateDataByte.resize(nstream.leftBytes()); 37 | nstream.read(privateDataByte.data(), nstream.leftBytes()); 38 | } 39 | 40 | stream.skip(descriptorLength); 41 | } 42 | catch (const std::out_of_range&) { 43 | return false; 44 | } 45 | 46 | return true; 47 | } 48 | 49 | bool MhEventGroupDescriptor::Event::unpack(Common::ReadStream& stream) 50 | { 51 | try { 52 | serviceId = stream.getBe16U(); 53 | eventId = stream.getBe16U(); 54 | } 55 | catch (const std::out_of_range&) { 56 | return false; 57 | } 58 | 59 | return true; 60 | } 61 | 62 | bool MhEventGroupDescriptor::OtherNetworkEvent::unpack(Common::ReadStream& stream) 63 | { 64 | try { 65 | originalNetworkId = stream.getBe16U(); 66 | tlvStreamId = stream.getBe16U(); 67 | serviceId = stream.getBe16U(); 68 | eventId = stream.getBe16U(); 69 | } 70 | catch (const std::out_of_range&) { 71 | return false; 72 | } 73 | 74 | return true; 75 | } 76 | 77 | } -------------------------------------------------------------------------------- /src/mhEventGroupDescriptor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "mmtDescriptorBase.h" 3 | #include 4 | 5 | namespace MmtTlv { 6 | 7 | class MhEventGroupDescriptor 8 | : public MmtDescriptorTemplate<0x800C> { 9 | public: 10 | bool unpack(Common::ReadStream& stream) override; 11 | 12 | uint8_t groupType; 13 | uint8_t eventCount; 14 | 15 | class Event { 16 | public: 17 | bool unpack(Common::ReadStream& stream); 18 | uint16_t serviceId; 19 | uint16_t eventId; 20 | }; 21 | 22 | class OtherNetworkEvent { 23 | public: 24 | bool unpack(Common::ReadStream& stream); 25 | uint16_t originalNetworkId; 26 | uint16_t tlvStreamId; 27 | uint16_t serviceId; 28 | uint16_t eventId; 29 | }; 30 | 31 | std::list events; 32 | std::list otherNetworkEvents; 33 | 34 | std::vector privateDataByte; 35 | }; 36 | 37 | } -------------------------------------------------------------------------------- /src/mhExtendedEventDescriptor.cpp: -------------------------------------------------------------------------------- 1 | #include "mhExtendedEventDescriptor.h" 2 | 3 | namespace MmtTlv { 4 | 5 | bool MhExtendedEventDescriptor::unpack(Common::ReadStream& stream) 6 | { 7 | try { 8 | if (!MmtDescriptorTemplate::unpack(stream)) { 9 | return false; 10 | } 11 | 12 | uint8_t uint8 = stream.get8U(); 13 | descriptorNumber = (uint8 & 0b11110000) >> 4; 14 | lastDescriptorNumber = (uint8 & 0b00001111); 15 | stream.read(language, 3); 16 | language[3] = '\0'; 17 | 18 | lengthOfItems = stream.getBe16U(); 19 | Common::ReadStream nstream(stream, lengthOfItems); 20 | while (!nstream.isEof()) { 21 | Entry entry; 22 | if (!entry.unpack(nstream)) { 23 | return false; 24 | } 25 | 26 | entries.push_back(entry); 27 | } 28 | stream.skip(lengthOfItems); 29 | 30 | 31 | textLength = stream.getBe16U(); 32 | if (textLength) { 33 | textChar.resize(textLength); 34 | stream.read(textChar.data(), textLength); 35 | } 36 | } 37 | catch (const std::out_of_range&) { 38 | return false; 39 | } 40 | 41 | return true; 42 | } 43 | 44 | bool MhExtendedEventDescriptor::Entry::unpack(Common::ReadStream& stream) 45 | { 46 | try { 47 | itemDescriptionLength = stream.get8U(); 48 | if (itemDescriptionLength > 0) { 49 | itemDescriptionChar.resize(itemDescriptionLength); 50 | stream.read(itemDescriptionChar.data(), itemDescriptionLength); 51 | } 52 | 53 | itemLength = stream.getBe16U(); 54 | if (itemLength > 0) { 55 | itemChar.resize(itemLength); 56 | stream.read(itemChar.data(), itemLength); 57 | } 58 | } 59 | catch (const std::out_of_range&) { 60 | return false; 61 | } 62 | 63 | return true; 64 | } 65 | 66 | } -------------------------------------------------------------------------------- /src/mhExtendedEventDescriptor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "mmtDescriptorBase.h" 3 | #include 4 | 5 | namespace MmtTlv { 6 | 7 | class MhExtendedEventDescriptor 8 | : public MmtDescriptorTemplate<0xF002, true> { 9 | public: 10 | bool unpack(Common::ReadStream& stream) override; 11 | 12 | class Entry { 13 | public: 14 | bool unpack(Common::ReadStream& stream); 15 | 16 | uint8_t itemDescriptionLength; 17 | std::string itemDescriptionChar; 18 | 19 | uint16_t itemLength; 20 | std::string itemChar; 21 | }; 22 | 23 | uint8_t descriptorNumber; 24 | uint8_t lastDescriptorNumber; 25 | char language[4]; 26 | uint16_t lengthOfItems; 27 | 28 | std::list entries; 29 | 30 | uint16_t textLength; 31 | std::string textChar; 32 | }; 33 | 34 | } -------------------------------------------------------------------------------- /src/mhLinkageDescriptor.cpp: -------------------------------------------------------------------------------- 1 | #include "mhLinkageDescriptor.h" 2 | 3 | namespace MmtTlv { 4 | 5 | bool MhLinkageDescriptor::unpack(Common::ReadStream& stream) 6 | { 7 | try { 8 | if (!MmtDescriptorTemplate::unpack(stream)) { 9 | return false; 10 | } 11 | 12 | Common::ReadStream nstream(stream, descriptorLength); 13 | 14 | tlvStreamId = nstream.getBe16U(); 15 | originalNetworkId = nstream.getBe16U(); 16 | serviceId = nstream.getBe16U(); 17 | linkageType = nstream.get8U(); 18 | 19 | privateDataByte.resize(nstream.leftBytes()); 20 | nstream.read(privateDataByte.data(), nstream.leftBytes()); 21 | 22 | stream.skip(descriptorLength); 23 | } 24 | catch (const std::out_of_range&) { 25 | return false; 26 | } 27 | 28 | return true; 29 | } 30 | 31 | } -------------------------------------------------------------------------------- /src/mhLinkageDescriptor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "mmtDescriptorBase.h" 3 | 4 | namespace MmtTlv { 5 | 6 | class MhLinkageDescriptor 7 | : public MmtDescriptorTemplate<0xF000> { 8 | public: 9 | bool unpack(Common::ReadStream& stream) override; 10 | 11 | uint16_t tlvStreamId; 12 | uint16_t originalNetworkId; 13 | uint16_t serviceId; 14 | uint8_t linkageType; 15 | std::vector privateDataByte; 16 | 17 | }; 18 | 19 | } -------------------------------------------------------------------------------- /src/mhLogoTransmissionDescriptor.cpp: -------------------------------------------------------------------------------- 1 | #include "mhLogoTransmissionDescriptor.h" 2 | 3 | namespace MmtTlv { 4 | 5 | bool MhLogoTransmissionDescriptor::unpack(Common::ReadStream& stream) 6 | { 7 | try { 8 | if (!MmtDescriptorTemplate::unpack(stream)) { 9 | return false; 10 | } 11 | 12 | Common::ReadStream nstream(stream, descriptorLength); 13 | 14 | logoTransmissionType = nstream.get8U(); 15 | if (logoTransmissionType == 0x01) { 16 | uint16_t uint16 = nstream.getBe16U(); 17 | reservedFutureUse1 = (uint16 & 0b1111111000000000) >> 9; 18 | logoId = uint16 & 0b0000000111111111; 19 | 20 | uint16 = nstream.getBe16U(); 21 | reservedFutureUse2 = (uint16 & 0b1111000000000000) >> 12; 22 | logoVersion = uint16 & 0b0000111111111111; 23 | downloadDataId = nstream.getBe16U(); 24 | 25 | while (!nstream.isEof()) { 26 | Entry entry; 27 | if (!entry.unpack(nstream)) { 28 | return false; 29 | } 30 | entries.push_back(entry); 31 | } 32 | } 33 | else if (logoTransmissionType == 0x02) { 34 | uint16_t uint16 = nstream.getBe16U(); 35 | reservedFutureUse1 = (uint16 & 0b1111111000000000) >> 9; 36 | logoId = uint16 & 0b0000000111111111; 37 | } 38 | else if (logoTransmissionType == 0x03) { 39 | logoChar.resize(nstream.leftBytes()); 40 | nstream.read(logoChar.data(), nstream.leftBytes()); 41 | } 42 | 43 | stream.skip(descriptorLength); 44 | } 45 | catch (const std::out_of_range&) { 46 | return false; 47 | } 48 | 49 | return true; 50 | } 51 | 52 | bool MhLogoTransmissionDescriptor::Entry::unpack(Common::ReadStream& stream) 53 | { 54 | try { 55 | logoType = stream.get8U(); 56 | startSectionNumber = stream.get8U(); 57 | numOfSections = stream.get8U(); 58 | } 59 | catch (const std::out_of_range&) { 60 | return false; 61 | } 62 | 63 | return true; 64 | } 65 | 66 | } -------------------------------------------------------------------------------- /src/mhLogoTransmissionDescriptor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "mmtDescriptorBase.h" 3 | #include 4 | 5 | namespace MmtTlv { 6 | 7 | class MhLogoTransmissionDescriptor 8 | : public MmtDescriptorTemplate<0x8025> { 9 | public: 10 | bool unpack(Common::ReadStream& stream) override; 11 | 12 | class Entry { 13 | public: 14 | bool unpack(Common::ReadStream& stream); 15 | uint8_t logoType; 16 | uint8_t startSectionNumber; 17 | uint8_t numOfSections; 18 | }; 19 | 20 | uint8_t logoTransmissionType; 21 | 22 | uint8_t reservedFutureUse1; 23 | uint16_t logoId; 24 | uint8_t reservedFutureUse2; 25 | uint16_t logoVersion; 26 | uint16_t downloadDataId; 27 | 28 | std::list entries; 29 | 30 | std::string logoChar; 31 | }; 32 | 33 | } -------------------------------------------------------------------------------- /src/mhParentalRatingDescriptor.cpp: -------------------------------------------------------------------------------- 1 | #include "mhParentalRatingDescriptor.h" 2 | 3 | namespace MmtTlv { 4 | 5 | bool MhParentalRatingDescriptor::unpack(Common::ReadStream& stream) 6 | { 7 | try { 8 | if (!MmtDescriptorTemplate::unpack(stream)) { 9 | return false; 10 | } 11 | 12 | Common::ReadStream nstream(stream, descriptorLength); 13 | 14 | while (!nstream.isEof()) { 15 | Entry entry; 16 | if (!entry.unpack(nstream)) { 17 | return false; 18 | } 19 | entries.push_back(entry); 20 | } 21 | 22 | stream.skip(descriptorLength); 23 | } 24 | catch (const std::out_of_range&) { 25 | return false; 26 | } 27 | 28 | return true; 29 | } 30 | 31 | bool MhParentalRatingDescriptor::Entry::unpack(Common::ReadStream& stream) { 32 | try { 33 | stream.read(countryCode, 3); 34 | countryCode[3] = '\0'; 35 | 36 | rating = stream.get8U(); 37 | } 38 | catch (const std::out_of_range&) { 39 | return false; 40 | } 41 | 42 | return true; 43 | } 44 | 45 | } -------------------------------------------------------------------------------- /src/mhParentalRatingDescriptor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "mmtDescriptorBase.h" 3 | #include 4 | 5 | namespace MmtTlv { 6 | 7 | class MhParentalRatingDescriptor 8 | : public MmtDescriptorTemplate<0x8013> { 9 | public: 10 | bool unpack(Common::ReadStream& stream) override; 11 | 12 | class Entry { 13 | public: 14 | bool unpack(Common::ReadStream& stream); 15 | 16 | char countryCode[4]; 17 | uint8_t rating; 18 | }; 19 | 20 | std::list entries; 21 | }; 22 | 23 | } -------------------------------------------------------------------------------- /src/mhSdt.cpp: -------------------------------------------------------------------------------- 1 | #include "mhSdt.h" 2 | #include "mhServiceDescriptor.h" 3 | #include 4 | 5 | namespace MmtTlv { 6 | 7 | bool MhSdt::unpack(Common::ReadStream& stream) 8 | { 9 | try { 10 | if (!MmtTableBase::unpack(stream)) { 11 | return false; 12 | } 13 | 14 | uint16_t uint16 = stream.getBe16U(); 15 | sectionSyntaxIndicator = (uint16 & 0b1000000000000000) >> 15; 16 | sectionLength = uint16 & 0b0000111111111111; 17 | 18 | tlvStreamId = stream.getBe16U(); 19 | 20 | uint8_t uint8 = stream.get8U(); 21 | versionNumber = (uint8 & 0b00111110) >> 1; 22 | currentNextIndicator = uint8 & 1; 23 | sectionNumber = stream.get8U(); 24 | lastSectionNumber = stream.get8U(); 25 | originalNetworkId = stream.getBe16U(); 26 | stream.skip(1); 27 | 28 | while (stream.leftBytes() > 4) { 29 | std::shared_ptr service = std::make_shared(); 30 | if (!service->unpack(stream)) { 31 | return false; 32 | } 33 | 34 | services.push_back(service); 35 | } 36 | 37 | if (stream.leftBytes() < 4) { 38 | return false; 39 | } 40 | 41 | crc32 = stream.getBe32U(); 42 | } 43 | catch (const std::out_of_range&) { 44 | return false; 45 | } 46 | 47 | return true; 48 | } 49 | 50 | bool MhSdt::Service::unpack(Common::ReadStream& stream) 51 | { 52 | try { 53 | serviceId = stream.getBe16U(); 54 | 55 | uint8_t uint8 = stream.get8U(); 56 | eitUserDefinedFlags = (uint8 & 0b00011100) >> 2; 57 | eitScheduleFlag = (uint8 & 0b00000010) >> 1; 58 | eitPresentFollowingFlag = (uint8 & 0b00000001) >> 1; 59 | 60 | uint16_t uint16 = stream.getBe16U(); 61 | runningStatus = (uint16 & 0b1110000000000000) >> 13; 62 | freeCaMode = (uint16 & 0b0001000000000000) >> 12; 63 | descriptorsLoopLength = uint16 & 0b0000111111111111; 64 | 65 | Common::ReadStream nstream(stream, descriptorsLoopLength); 66 | if (!descriptors.unpack(nstream)) { 67 | return false; 68 | } 69 | stream.skip(descriptorsLoopLength); 70 | } 71 | catch (const std::out_of_range&) { 72 | return false; 73 | } 74 | 75 | return true; 76 | } 77 | 78 | } -------------------------------------------------------------------------------- /src/mhSdt.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "mmtTableBase.h" 4 | #include "mmtDescriptors.h" 5 | 6 | namespace MmtTlv { 7 | 8 | // Mh-Service Description Table 9 | class MhSdt : public MmtTableBase { 10 | public: 11 | bool unpack(Common::ReadStream& stream); 12 | 13 | class Service { 14 | public: 15 | bool unpack(Common::ReadStream& stream); 16 | 17 | uint16_t serviceId; 18 | int8_t eitUserDefinedFlags; 19 | bool eitScheduleFlag; 20 | bool eitPresentFollowingFlag; 21 | uint8_t runningStatus; 22 | bool freeCaMode; 23 | uint16_t descriptorsLoopLength; 24 | 25 | MmtDescriptors descriptors; 26 | }; 27 | 28 | uint16_t sectionSyntaxIndicator; 29 | uint16_t sectionLength; 30 | 31 | uint16_t tlvStreamId; 32 | 33 | uint8_t versionNumber; 34 | bool currentNextIndicator; 35 | uint8_t sectionNumber; 36 | uint8_t lastSectionNumber; 37 | 38 | uint16_t originalNetworkId; 39 | 40 | std::list> services; 41 | uint32_t crc32; 42 | }; 43 | 44 | } -------------------------------------------------------------------------------- /src/mhSeriesDescriptor.cpp: -------------------------------------------------------------------------------- 1 | #include "mhSeriesDescriptor.h" 2 | 3 | namespace MmtTlv { 4 | 5 | bool MhSeriesDescriptor::unpack(Common::ReadStream& stream) 6 | { 7 | try { 8 | if (!MmtDescriptorTemplate::unpack(stream)) { 9 | return false; 10 | } 11 | 12 | Common::ReadStream nstream(stream, descriptorLength); 13 | 14 | seriesId = nstream.getBe16U(); 15 | 16 | uint8_t uint8 = nstream.get8U(); 17 | 18 | repeatLabel = (uint8 & 0b11110000) >> 4; 19 | programPattern = (uint8 & 0b00001110) >> 1; 20 | expireDateValidFlag = uint8 & 1; 21 | 22 | expireDate = nstream.getBe16U(); 23 | 24 | uint16_t uint16 = nstream.getBe16U(); 25 | episodeNumber = (uint16 & 0b1111111111110000) >> 4; 26 | lastEpisodeNumber = (uint16 & 0b0000000000001111) << 8 | nstream.get8U(); 27 | 28 | seriesNameChar.resize(nstream.leftBytes()); 29 | nstream.read(seriesNameChar.data(), nstream.leftBytes()); 30 | 31 | stream.skip(descriptorLength); 32 | } 33 | catch (const std::out_of_range&) { 34 | return false; 35 | } 36 | 37 | return true; 38 | } 39 | 40 | } -------------------------------------------------------------------------------- /src/mhSeriesDescriptor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "mmtDescriptorBase.h" 3 | 4 | namespace MmtTlv { 5 | 6 | class MhSeriesDescriptor 7 | : public MmtDescriptorTemplate<0x8016> { 8 | public: 9 | bool unpack(Common::ReadStream& stream) override; 10 | 11 | uint16_t seriesId; 12 | 13 | uint8_t repeatLabel; 14 | uint8_t programPattern; 15 | bool expireDateValidFlag; 16 | 17 | uint16_t expireDate; 18 | 19 | uint16_t episodeNumber; 20 | uint16_t lastEpisodeNumber; 21 | 22 | std::string seriesNameChar; 23 | 24 | }; 25 | 26 | } -------------------------------------------------------------------------------- /src/mhServiceDescriptor.cpp: -------------------------------------------------------------------------------- 1 | #include "mhServiceDescriptor.h" 2 | 3 | namespace MmtTlv { 4 | 5 | bool MhServiceDescriptor::unpack(Common::ReadStream& stream) 6 | { 7 | try { 8 | if (!MmtDescriptorTemplate::unpack(stream)) { 9 | return false; 10 | } 11 | 12 | Common::ReadStream nstream(stream, descriptorLength); 13 | 14 | serviceType = nstream.get8U(); 15 | serviceProviderNameLength = nstream.get8U(); 16 | if (serviceProviderNameLength) { 17 | serviceProviderName.resize(serviceProviderNameLength); 18 | nstream.read(serviceProviderName.data(), serviceProviderNameLength); 19 | } 20 | 21 | serviceNameLength = nstream.get8U(); 22 | if (serviceNameLength) { 23 | serviceName.resize(serviceNameLength); 24 | nstream.read(serviceName.data(), serviceNameLength); 25 | } 26 | 27 | stream.skip(descriptorLength); 28 | } 29 | catch (const std::out_of_range&) { 30 | return false; 31 | } 32 | 33 | return true; 34 | } 35 | 36 | } -------------------------------------------------------------------------------- /src/mhServiceDescriptor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "mmtDescriptorBase.h" 3 | 4 | namespace MmtTlv { 5 | 6 | class MhServiceDescriptor 7 | : public MmtDescriptorTemplate<0x8019> { 8 | public: 9 | virtual ~MhServiceDescriptor() {} 10 | bool unpack(Common::ReadStream& stream) override; 11 | 12 | uint8_t serviceType; 13 | uint8_t serviceProviderNameLength; 14 | std::string serviceProviderName; 15 | uint8_t serviceNameLength; 16 | std::string serviceName; 17 | }; 18 | 19 | } -------------------------------------------------------------------------------- /src/mhServiceListDescriptor.cpp: -------------------------------------------------------------------------------- 1 | #include "mhServiceListDescriptor.h" 2 | 3 | namespace MmtTlv { 4 | 5 | bool MhServiceListDescriptor::unpack(Common::ReadStream& stream) 6 | { 7 | try { 8 | if (!MmtDescriptorTemplate::unpack(stream)) { 9 | return false; 10 | } 11 | 12 | Common::ReadStream nstream(stream, descriptorLength); 13 | 14 | while (!nstream.isEof()) { 15 | Entry entry; 16 | if (!entry.unpack(nstream)) { 17 | return false; 18 | } 19 | 20 | entries.push_back(entry); 21 | } 22 | 23 | stream.skip(descriptorLength); 24 | } 25 | catch (const std::out_of_range&) { 26 | return false; 27 | } 28 | 29 | return true; 30 | } 31 | 32 | bool MhServiceListDescriptor::Entry::unpack(Common::ReadStream& stream) 33 | { 34 | try { 35 | serviceId = stream.getBe16U(); 36 | serviceType = stream.get8U(); 37 | } 38 | catch (const std::out_of_range&) { 39 | return false; 40 | } 41 | 42 | return true; 43 | } 44 | } -------------------------------------------------------------------------------- /src/mhServiceListDescriptor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "mmtDescriptorBase.h" 3 | #include 4 | 5 | namespace MmtTlv { 6 | 7 | class MhServiceListDescriptor 8 | : public MmtDescriptorTemplate<0x800D> { 9 | public: 10 | virtual ~MhServiceListDescriptor() {} 11 | bool unpack(Common::ReadStream& stream) override; 12 | 13 | class Entry { 14 | public: 15 | bool unpack(Common::ReadStream& stream); 16 | 17 | uint16_t serviceId; 18 | uint8_t serviceType; 19 | }; 20 | 21 | std::list entries; 22 | }; 23 | 24 | } -------------------------------------------------------------------------------- /src/mhShortEventDescriptor.cpp: -------------------------------------------------------------------------------- 1 | #include "mhShortEventDescriptor.h" 2 | 3 | namespace MmtTlv { 4 | 5 | bool MhShortEventDescriptor::unpack(Common::ReadStream& stream) 6 | { 7 | try { 8 | if (!MmtDescriptorTemplate::unpack(stream)) { 9 | return false; 10 | } 11 | 12 | uint8_t eventNameLength; 13 | uint16_t textLength; 14 | 15 | stream.read(language, 3); 16 | language[3] = '\0'; 17 | 18 | eventNameLength = stream.get8U(); 19 | eventName.resize(eventNameLength); 20 | stream.read(eventName.data(), eventNameLength); 21 | 22 | textLength = stream.getBe16U(); 23 | text.resize(textLength); 24 | stream.read(text.data(), textLength); 25 | } 26 | catch (const std::out_of_range&) { 27 | return false; 28 | } 29 | 30 | return true; 31 | } 32 | 33 | } -------------------------------------------------------------------------------- /src/mhShortEventDescriptor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "mmtDescriptorBase.h" 3 | 4 | namespace MmtTlv { 5 | 6 | class MhShortEventDescriptor 7 | : public MmtDescriptorTemplate<0xF001, true> { 8 | public: 9 | bool unpack(Common::ReadStream& stream) override; 10 | 11 | char language[4]; 12 | std::string eventName; 13 | std::string text; 14 | 15 | }; 16 | 17 | } -------------------------------------------------------------------------------- /src/mhSiParameterDescriptor.cpp: -------------------------------------------------------------------------------- 1 | #include "mhSiParameterDescriptor.h" 2 | 3 | namespace MmtTlv { 4 | 5 | bool MhSiParameterDescriptor::unpack(Common::ReadStream& stream) 6 | { 7 | try { 8 | if (!MmtDescriptorTemplate::unpack(stream)) { 9 | return false; 10 | } 11 | 12 | Common::ReadStream nstream(stream, descriptorLength); 13 | 14 | parameterVersion = nstream.get8U(); 15 | updateTime = nstream.getBe16U(); 16 | 17 | while (!nstream.isEof()) { 18 | Entry entry; 19 | if (!entry.unpack(nstream)) { 20 | return false; 21 | } 22 | 23 | entries.push_back(entry); 24 | } 25 | 26 | stream.skip(descriptorLength); 27 | } 28 | catch (const std::out_of_range&) { 29 | return false; 30 | } 31 | 32 | return true; 33 | } 34 | 35 | bool MhSiParameterDescriptor::Entry::unpack(Common::ReadStream& stream) 36 | { 37 | try { 38 | tableId = stream.get8U(); 39 | tableDescriptionLength = stream.get8U(); 40 | 41 | tableDescriptionByte.resize(tableDescriptionLength); 42 | stream.read(tableDescriptionByte.data(), tableDescriptionLength); 43 | } 44 | catch (const std::out_of_range&) { 45 | return false; 46 | } 47 | 48 | return true; 49 | } 50 | } -------------------------------------------------------------------------------- /src/mhSiParameterDescriptor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "mmtDescriptorBase.h" 3 | #include 4 | 5 | namespace MmtTlv { 6 | 7 | class MhSiParameterDescriptor 8 | : public MmtDescriptorTemplate<0x8017> { 9 | public: 10 | bool unpack(Common::ReadStream& stream) override; 11 | 12 | class Entry { 13 | public: 14 | bool unpack(Common::ReadStream& stream); 15 | 16 | uint8_t tableId; 17 | uint8_t tableDescriptionLength; 18 | std::vector tableDescriptionByte; 19 | }; 20 | 21 | uint8_t parameterVersion; 22 | uint16_t updateTime; 23 | std::list entries; 24 | 25 | }; 26 | 27 | } -------------------------------------------------------------------------------- /src/mhStreamIdentificationDescriptor.cpp: -------------------------------------------------------------------------------- 1 | #include "mhStreamIdentificationDescriptor.h" 2 | 3 | namespace MmtTlv { 4 | 5 | bool MhStreamIdentificationDescriptor::unpack(Common::ReadStream& stream) 6 | { 7 | try { 8 | if (!MmtDescriptorTemplate::unpack(stream)) { 9 | return false; 10 | } 11 | 12 | Common::ReadStream nstream(stream, descriptorLength); 13 | 14 | componentTag = nstream.getBe16U(); 15 | 16 | stream.skip(descriptorLength); 17 | } 18 | catch (const std::out_of_range&) { 19 | return false; 20 | } 21 | 22 | return true; 23 | } 24 | 25 | } -------------------------------------------------------------------------------- /src/mhStreamIdentificationDescriptor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "mmtDescriptorBase.h" 3 | 4 | namespace MmtTlv { 5 | 6 | class MhStreamIdentificationDescriptor 7 | : public MmtDescriptorTemplate<0x8011> { 8 | public: 9 | bool unpack(Common::ReadStream& stream) override; 10 | 11 | uint16_t componentTag; 12 | 13 | }; 14 | 15 | } -------------------------------------------------------------------------------- /src/mhTot.cpp: -------------------------------------------------------------------------------- 1 | #include "mhTot.h" 2 | 3 | namespace MmtTlv { 4 | 5 | bool MhTot::unpack(Common::ReadStream& stream) 6 | { 7 | try { 8 | if (!MmtTableBase::unpack(stream)) { 9 | return false; 10 | } 11 | 12 | uint16_t uint16 = stream.getBe16U(); 13 | sectionSyntaxIndicator = (uint16 & 0b1000000000000000) >> 15; 14 | sectionLength = uint16 & 0b0000111111111111; 15 | 16 | uint64_t uint64 = stream.getBe64U(); 17 | jstTime = (uint64 & 0xFFFFFFFFFF000000) >> 24; 18 | } 19 | catch (const std::out_of_range&) { 20 | return false; 21 | } 22 | return true; 23 | } 24 | 25 | } -------------------------------------------------------------------------------- /src/mhTot.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "mmtTableBase.h" 3 | 4 | namespace MmtTlv { 5 | 6 | // Mh-Time Offset Table 7 | class MhTot : public MmtTableBase { 8 | public: 9 | bool unpack(Common::ReadStream& stream); 10 | 11 | uint16_t sectionSyntaxIndicator; 12 | uint16_t sectionLength; 13 | uint64_t jstTime; 14 | }; 15 | 16 | } -------------------------------------------------------------------------------- /src/mmt.cpp: -------------------------------------------------------------------------------- 1 | #include "mmt.h" 2 | #include "extensionHeaderScrambling.h" 3 | #include "acascard.h" 4 | #include 5 | 6 | namespace MmtTlv { 7 | 8 | bool Mmt::unpack(Common::ReadStream& stream) 9 | { 10 | try { 11 | uint8_t uint8 = stream.get8U(); 12 | version = (uint8 & 0b11000000) >> 6; 13 | packetCounterFlag = (uint8 & 0b00100000) >> 5; 14 | fecType = (uint8 & 0b00011000) >> 3; 15 | reserved1 = (uint8 & 0b00000100) >> 2; 16 | extensionHeaderFlag = (uint8 & 0b00000010) >> 1; 17 | rapFlag = uint8 & 0b00000001; 18 | 19 | uint8 = stream.get8U(); 20 | reserved2 = (uint8 & 0b11000000) >> 6; 21 | payloadType = static_cast(uint8 & 0b00111111); 22 | 23 | packetId = stream.getBe16U(); 24 | deliveryTimestamp = stream.getBe32U(); 25 | packetSequenceNumber = stream.getBe32U(); 26 | 27 | if (packetCounterFlag) { 28 | if (stream.leftBytes() < 4) { 29 | return false; 30 | } 31 | packetCounter = stream.getBe32U(); 32 | } 33 | 34 | if (extensionHeaderFlag) { 35 | if (stream.leftBytes() < 4) { 36 | return false; 37 | } 38 | extensionHeaderType = stream.getBe16U(); 39 | extensionHeaderLength = stream.getBe16U(); 40 | 41 | if (stream.leftBytes() < extensionHeaderLength) { 42 | return false; 43 | } 44 | extensionHeaderField.resize(extensionHeaderLength); 45 | stream.read(extensionHeaderField.data(), extensionHeaderLength); 46 | 47 | if (extensionHeaderField.size() >= 5) { 48 | uint16_t e = Common::swapEndian16(*(uint16_t*)extensionHeaderField.data()); 49 | if ((e & 0x7FFF) == 0x0001) { 50 | Common::ReadStream nstream(extensionHeaderField); 51 | nstream.skip(4); 52 | 53 | ExtensionHeaderScrambling s; 54 | if (s.unpack(nstream, extensionHeaderType, extensionHeaderLength)) { 55 | extensionHeaderScrambling = s; 56 | } 57 | } 58 | } 59 | } 60 | else { 61 | extensionHeaderScrambling = std::nullopt; 62 | } 63 | 64 | payload.resize(stream.leftBytes()); 65 | stream.read(payload.data(), stream.leftBytes()); 66 | } 67 | catch (const std::out_of_range&) { 68 | return false; 69 | } 70 | 71 | return true; 72 | } 73 | 74 | bool Mmt::decryptPayload(const Acas::DecryptedEcm& decryptedEcm) 75 | { 76 | if (!extensionHeaderScrambling) { 77 | return false; 78 | } 79 | 80 | const std::array& key = (extensionHeaderScrambling->encryptionFlag == EncryptionFlag::ODD) 81 | ? decryptedEcm.odd 82 | : decryptedEcm.even; 83 | 84 | std::vector iv(16, 0); 85 | 86 | uint16_t swappedPacketId = Common::swapEndian16(packetId); 87 | uint32_t swappedPacketSequenceNumber = Common::swapEndian32(packetSequenceNumber); 88 | memcpy(iv.data(), &swappedPacketId, 2); 89 | memcpy(iv.data() + 2, &swappedPacketSequenceNumber, 4); 90 | 91 | EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); 92 | EVP_EncryptInit_ex(ctx, EVP_aes_128_ctr(), nullptr, key.data(), iv.data()); 93 | 94 | int outlen; 95 | EVP_EncryptUpdate(ctx, payload.data() + 8, &outlen, payload.data() + 8, static_cast(payload.size() - 8)); 96 | EVP_EncryptFinal_ex(ctx, payload.data() + 8 + outlen, &outlen); 97 | EVP_CIPHER_CTX_free(ctx); 98 | 99 | return true; 100 | } 101 | 102 | } -------------------------------------------------------------------------------- /src/mmt.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include "stream.h" 5 | #include "extensionHeaderScrambling.h" 6 | 7 | namespace MmtTlv { 8 | 9 | namespace Acas { 10 | struct DecryptedEcm; 11 | } 12 | 13 | enum class PayloadType 14 | { 15 | Mpu = 0x00, 16 | Undefined = 0x01, 17 | ContainsOneOrMoreControlMessage = 0x02 18 | }; 19 | 20 | class Mmt { 21 | public: 22 | bool unpack(Common::ReadStream& stream); 23 | bool decryptPayload(const Acas::DecryptedEcm& decryptedEcm); 24 | 25 | public: 26 | uint8_t version; 27 | bool packetCounterFlag; 28 | uint8_t fecType; 29 | bool reserved1; 30 | bool extensionHeaderFlag; 31 | bool rapFlag; 32 | uint8_t reserved2; 33 | PayloadType payloadType; 34 | uint16_t packetId; 35 | uint32_t deliveryTimestamp; 36 | uint32_t packetSequenceNumber; 37 | uint32_t packetCounter; 38 | uint16_t extensionHeaderType; 39 | uint16_t extensionHeaderLength; 40 | std::vector extensionHeaderField; 41 | std::vector payload; 42 | 43 | std::optional extensionHeaderScrambling; 44 | 45 | }; 46 | 47 | } -------------------------------------------------------------------------------- /src/mmtDescriptorBase.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "stream.h" 3 | 4 | namespace MmtTlv { 5 | 6 | class MmtDescriptorBase { 7 | public: 8 | virtual ~MmtDescriptorBase() = default; 9 | 10 | virtual bool unpack(Common::ReadStream& stream) { 11 | try { 12 | descriptorTag = stream.getBe16U(); 13 | descriptorLength = stream.get8U(); 14 | 15 | if (stream.leftBytes() < descriptorLength) { 16 | return false; 17 | } 18 | } 19 | catch (const std::out_of_range&) { 20 | return false; 21 | } 22 | 23 | return true; 24 | } 25 | 26 | uint16_t getDescriptorTag() const { return descriptorTag; }; 27 | uint16_t getDescriptorLength() const { return descriptorLength; }; 28 | 29 | protected: 30 | uint16_t descriptorTag; 31 | uint16_t descriptorLength; 32 | }; 33 | 34 | template 35 | class MmtDescriptorTemplate : public MmtDescriptorBase { 36 | public: 37 | virtual ~MmtDescriptorTemplate() = default; 38 | 39 | static constexpr uint16_t kDescriptorTag = descriptorTagValue; 40 | static constexpr uint16_t kIs16BitLength = is16BitLength; 41 | 42 | virtual bool unpack(Common::ReadStream& stream) { 43 | try { 44 | descriptorTag = stream.getBe16U(); 45 | if (kIs16BitLength) { 46 | descriptorLength = stream.getBe16U(); 47 | } 48 | else { 49 | descriptorLength = stream.get8U(); 50 | } 51 | 52 | if (stream.leftBytes() < descriptorLength) { 53 | return false; 54 | } 55 | } 56 | catch (const std::out_of_range&) { 57 | return false; 58 | } 59 | 60 | return true; 61 | } 62 | }; 63 | 64 | } -------------------------------------------------------------------------------- /src/mmtDescriptorFactory.cpp: -------------------------------------------------------------------------------- 1 | #include "mmtDescriptorFactory.h" 2 | #include 3 | #include 4 | 5 | #include "eventPackageDescriptor.h" 6 | #include "mhAudioComponentDescriptor.h" 7 | #include "mhCaContractInformation.h" 8 | #include "mhContentDescriptor.h" 9 | #include "mhDataComponentDescriptor.h" 10 | #include "mhEventGroupDescriptor.h" 11 | #include "mhExtendedEventDescriptor.h" 12 | #include "mhLinkageDescriptor.h" 13 | #include "mhLogoTransmissionDescriptor.h" 14 | #include "mhParentalRatingDescriptor.h" 15 | #include "mhSeriesDescriptor.h" 16 | #include "mhServiceDescriptor.h" 17 | #include "mhShortEventDescriptor.h" 18 | #include "mhStreamIdentificationDescriptor.h" 19 | #include "mpuExtendedTimestampDescriptor.h" 20 | #include "mpuTimestampDescriptor.h" 21 | #include "videoComponentDescriptor.h" 22 | #include "contentCopyControlDescriptor.h" 23 | #include "multimediaServiceInformationDescriptor.h" 24 | #include "accessControlDescriptor.h" 25 | #include "mhSiParameterDescriptor.h" 26 | #include "relatedBroadcasterDescriptor.h" 27 | #include "mhBroadcasterNameDescriptor.h" 28 | #include "mhServiceListDescriptor.h" 29 | #include 30 | 31 | namespace MmtTlv { 32 | 33 | static const std::unordered_map()>> mapMmtDescriptor = { 34 | { MhAudioComponentDescriptor::kDescriptorTag, [] { return std::make_shared(); } }, 35 | { MhContentDescriptor::kDescriptorTag, [] { return std::make_shared(); } }, 36 | { MhExtendedEventDescriptor::kDescriptorTag, [] { return std::make_shared(); } }, 37 | { MhServiceDescriptor::kDescriptorTag, [] { return std::make_shared(); } }, 38 | { MhShortEventDescriptor::kDescriptorTag, [] { return std::make_shared(); } }, 39 | { MpuExtendedTimestampDescriptor::kDescriptorTag, [] { return std::make_shared(); } }, 40 | { MpuTimestampDescriptor::kDescriptorTag, [] { return std::make_shared(); } }, 41 | { VideoComponentDescriptor::kDescriptorTag, [] { return std::make_shared(); } }, 42 | { EventPackageDescriptor::kDescriptorTag, [] { return std::make_shared(); } }, 43 | { MhCaContractInformation::kDescriptorTag, [] { return std::make_shared(); } }, 44 | { MhLinkageDescriptor::kDescriptorTag, [] { return std::make_shared(); } }, 45 | { MhLogoTransmissionDescriptor::kDescriptorTag, [] { return std::make_shared(); } }, 46 | { MhSeriesDescriptor::kDescriptorTag, [] { return std::make_shared(); } }, 47 | { MhEventGroupDescriptor::kDescriptorTag, [] { return std::make_shared(); } }, 48 | { MhParentalRatingDescriptor::kDescriptorTag, [] { return std::make_shared(); } }, 49 | { MhStreamIdentificationDescriptor::kDescriptorTag, [] { return std::make_shared(); } }, 50 | { MhDataComponentDescriptor::kDescriptorTag, [] { return std::make_shared(); } }, 51 | { ContentCopyControlDescriptor::kDescriptorTag, [] { return std::make_shared(); } }, 52 | { MultimediaServiceInformationDescriptor::kDescriptorTag, [] { return std::make_shared(); } }, 53 | { AccessControlDescriptor::kDescriptorTag, [] { return std::make_shared(); } }, 54 | { MhSiParameterDescriptor::kDescriptorTag, [] { return std::make_shared(); } }, 55 | { RelatedBroadcasterDescriptor::kDescriptorTag, [] { return std::make_shared(); } }, 56 | { MhBroadcasterNameDescriptor::kDescriptorTag, [] { return std::make_shared(); } }, 57 | { MhServiceListDescriptor::kDescriptorTag, [] { return std::make_shared(); } }, 58 | }; 59 | 60 | std::shared_ptr MmtDescriptorFactory::create(uint16_t tag) { 61 | auto it = mapMmtDescriptor.find(tag); 62 | if (it == mapMmtDescriptor.end()) { 63 | return {}; 64 | } 65 | 66 | return it->second(); 67 | } 68 | 69 | bool MmtDescriptorFactory::isValidTag(uint16_t tag) 70 | { 71 | auto it = mapMmtDescriptor.find(tag); 72 | if (it == mapMmtDescriptor.end()) { 73 | return false; 74 | } 75 | 76 | return true; 77 | } 78 | 79 | } -------------------------------------------------------------------------------- /src/mmtDescriptorFactory.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "mmtDescriptorBase.h" 3 | #include 4 | #include 5 | 6 | namespace MmtTlv { 7 | 8 | class MmtDescriptorFactory { 9 | public: 10 | static std::shared_ptr create(uint16_t tag); 11 | static bool isValidTag(uint16_t tag); 12 | 13 | }; 14 | 15 | } -------------------------------------------------------------------------------- /src/mmtDescriptors.cpp: -------------------------------------------------------------------------------- 1 | #include "mmtDescriptors.h" 2 | #include "mmtDescriptorFactory.h" 3 | 4 | namespace MmtTlv { 5 | 6 | bool MmtDescriptors::unpack(Common::ReadStream& stream) 7 | { 8 | list.clear(); 9 | while (!stream.isEof()) { 10 | uint16_t descriptorTag = stream.peekBe16U(); 11 | auto it = MmtDescriptorFactory::create(descriptorTag); 12 | if (it == nullptr) { 13 | MmtDescriptorBase base; 14 | if (!base.unpack(stream)) { 15 | return false; 16 | } 17 | stream.skip(base.getDescriptorLength()); 18 | } 19 | else { 20 | if (!it->unpack(stream)) { 21 | return false; 22 | } 23 | list.push_back(std::move(it)); 24 | } 25 | } 26 | return true; 27 | } 28 | 29 | 30 | } -------------------------------------------------------------------------------- /src/mmtDescriptors.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "mmtDescriptorBase.h" 3 | #include 4 | #include 5 | 6 | namespace MmtTlv { 7 | 8 | class MmtDescriptors { 9 | public: 10 | bool unpack(Common::ReadStream& stream); 11 | std::list> list; 12 | 13 | }; 14 | 15 | } -------------------------------------------------------------------------------- /src/mmtFragment.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace MmtTlv { 4 | 5 | enum class FragmentType 6 | { 7 | MpuMetadata = 0x00, 8 | MovieFragmentMetadata = 0x01, 9 | Mfu = 0x02 10 | }; 11 | 12 | enum FragmentationIndicator { 13 | NotFragmented = 0b00, 14 | FirstFragment = 0b01, 15 | MiddleFragment = 0b10, 16 | LastFragment = 0b11, 17 | }; 18 | 19 | } -------------------------------------------------------------------------------- /src/mmtGeneralLocationInfo.cpp: -------------------------------------------------------------------------------- 1 | #include "mmtGeneralLocationInfo.h" 2 | 3 | namespace MmtTlv { 4 | 5 | bool MmtGeneralLocationInfo::unpack(Common::ReadStream& stream) 6 | { 7 | uint16_t uint16; 8 | 9 | try { 10 | locationType = stream.get8U(); 11 | switch (locationType) { 12 | case 0: 13 | packetId = stream.getBe16U(); 14 | break; 15 | case 1: 16 | stream.read(&ipv4SrcAddr, 4); 17 | stream.read(&ipv4DstAddr, 4); 18 | dstPort = stream.getBe16U(); 19 | packetId = stream.getBe16U(); 20 | break; 21 | case 2: 22 | stream.read(&ipv6SrcAddr, 16); 23 | stream.read(&ipv6DstAddr, 16); 24 | dstPort = stream.getBe16U(); 25 | packetId = stream.getBe16U(); 26 | break; 27 | case 3: 28 | networkId = stream.getBe16U(); 29 | mpeg2TransportStreamId = stream.getBe16U(); 30 | 31 | uint16 = stream.getBe16U(); 32 | reserved = (uint16 & 0b1110000000000000) >> 13; 33 | mpeg2Pid = uint16 & 0x0001111111111111; 34 | break; 35 | case 4: 36 | stream.read(&ipv6SrcAddr, 16); 37 | stream.read(&ipv6DstAddr, 16); 38 | dstPort = stream.getBe16U(); 39 | 40 | uint16 = stream.getBe16U(); 41 | reserved = (uint16 & 0b1110000000000000) >> 13; 42 | mpeg2Pid = uint16 & 0x0001111111111111; 43 | break; 44 | case 5: 45 | urlLength = stream.get8U(); 46 | urlByte.resize(urlLength); 47 | stream.read(urlByte.data(), urlLength); 48 | break; 49 | } 50 | } 51 | catch (const std::out_of_range&) { 52 | return false; 53 | } 54 | 55 | return true; 56 | } 57 | 58 | } -------------------------------------------------------------------------------- /src/mmtGeneralLocationInfo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "stream.h" 4 | #include "ip.h" 5 | 6 | namespace MmtTlv { 7 | 8 | namespace Common { 9 | class Stream; 10 | } 11 | 12 | class MmtGeneralLocationInfo { 13 | public: 14 | bool unpack(Common::ReadStream& stream); 15 | 16 | uint8_t locationType; 17 | uint16_t packetId; 18 | uint32_t ipv4SrcAddr; 19 | uint32_t ipv4DstAddr; 20 | struct Common::in6_addr ipv6SrcAddr; 21 | struct Common::in6_addr ipv6DstAddr; 22 | uint16_t dstPort; 23 | uint16_t networkId; 24 | 25 | uint16_t mpeg2TransportStreamId; 26 | uint8_t reserved; 27 | uint16_t mpeg2Pid; 28 | 29 | uint8_t urlLength; 30 | std::vector urlByte; 31 | }; 32 | 33 | } -------------------------------------------------------------------------------- /src/mmtStream.cpp: -------------------------------------------------------------------------------- 1 | #include "mmtStream.h" 2 | #include "videoComponentDescriptor.h" 3 | #include "mhAudioComponentDescriptor.h" 4 | #include "timebase.h" 5 | #include 6 | 7 | namespace MmtTlv { 8 | 9 | std::pair MmtStream::getNextPtsDts() 10 | { 11 | const auto timestamp = getCurrentTimestamp(); 12 | 13 | int64_t ptime = av_rescale(timestamp.first.mpuPresentationTime, timeBase.den, 14 | 1000000ll * timeBase.num); 15 | 16 | if (auIndex >= timestamp.second.numOfAu) { 17 | throw std::out_of_range("au index out of bounds"); 18 | } 19 | 20 | int64_t dts = ptime - timestamp.second.mpuDecodingTimeOffset; 21 | for (uint32_t j = 0; j < auIndex; ++j) { 22 | dts += timestamp.second.ptsOffsets[j]; 23 | } 24 | 25 | int64_t pts = dts + timestamp.second.dtsPtsOffsets[auIndex]; 26 | 27 | ++auIndex; 28 | 29 | return std::pair(pts, dts); 30 | } 31 | 32 | std::pair MmtStream::getCurrentTimestamp() const 33 | { 34 | auto mpuTimestampIt = std::find_if(mpuTimestamps.begin(), mpuTimestamps.end(), 35 | [this](const auto& entry) { return entry.mpuSequenceNumber == lastMpuSequenceNumber; }); 36 | 37 | auto extendedTimestampIt = std::find_if(mpuExtendedTimestamps.begin(), mpuExtendedTimestamps.end(), 38 | [this](const auto& entry) { return entry.mpuSequenceNumber == lastMpuSequenceNumber; }); 39 | 40 | if (mpuTimestampIt == mpuTimestamps.end() || extendedTimestampIt == mpuExtendedTimestamps.end()) { 41 | return {}; 42 | } 43 | 44 | return { *mpuTimestampIt, *extendedTimestampIt }; 45 | } 46 | 47 | bool MmtStream::Is8KVideo() const 48 | { 49 | if (!videoComponentDescriptor) { 50 | return false; 51 | } 52 | 53 | return videoComponentDescriptor->Is8KVideo(); 54 | } 55 | 56 | bool MmtStream::Is22_2chAudio() const 57 | { 58 | if (!mhAudioComponentDescriptor) { 59 | return false; 60 | } 61 | 62 | return mhAudioComponentDescriptor->Is22_2chAudio(); 63 | } 64 | 65 | uint32_t MmtStream::getSamplingRate() const 66 | { 67 | if (!mhAudioComponentDescriptor) { 68 | return 0; 69 | } 70 | 71 | return mhAudioComponentDescriptor->getConvertedSamplingRate(); 72 | } 73 | 74 | } -------------------------------------------------------------------------------- /src/mmtStream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include "mpuExtendedTimestampDescriptor.h" 5 | #include "mpuTimestampDescriptor.h" 6 | 7 | namespace MmtTlv { 8 | 9 | class MfuDataProcessorBase; 10 | class VideoComponentDescriptor; 11 | class MhAudioComponentDescriptor; 12 | 13 | class MmtStream final { 14 | public: 15 | explicit MmtStream(uint16_t packetId) 16 | : packetId(packetId) {} 17 | 18 | MmtStream(const MmtStream&) = delete; 19 | MmtStream& operator=(const MmtStream&) = delete; 20 | 21 | MmtStream(MmtStream&&) = default; 22 | MmtStream& operator=(MmtStream&&) = default; 23 | 24 | std::pair getNextPtsDts(); 25 | uint32_t getAuIndex() const { return auIndex; } 26 | uint16_t getMpeg2PacketId() const { return componentTag == -1 ? 0x200 + streamIndex : 0x100 + componentTag; } 27 | uint16_t getPacketId() const { return packetId; } 28 | uint32_t getAssetType() const { return assetType; } 29 | uint32_t getStreamIndex() const { return streamIndex; } 30 | int32_t getComponentTag() const { return componentTag; } 31 | bool GetRapFlag() const { return rapFlag; } 32 | bool Is8KVideo() const; 33 | bool Is22_2chAudio() const; 34 | uint32_t getSamplingRate() const; 35 | 36 | const std::shared_ptr& getVideoComponentDescriptor() const { return videoComponentDescriptor; } 37 | const std::shared_ptr& getMhAudioComponentDescriptor() const { return mhAudioComponentDescriptor; } 38 | 39 | struct TimeBase { 40 | int num; 41 | int den; 42 | }; 43 | 44 | struct TimeBase timeBase; 45 | 46 | private: 47 | friend class MmtTlvDemuxer; 48 | 49 | std::pair getCurrentTimestamp() const; 50 | 51 | uint16_t packetId = 0; 52 | uint32_t assetType = 0; 53 | uint32_t lastMpuSequenceNumber = 0; 54 | uint32_t auIndex = 0; 55 | uint32_t streamIndex = 0; 56 | int16_t componentTag = -1; 57 | bool rapFlag = false; 58 | 59 | std::vector mpuTimestamps; 60 | std::vector mpuExtendedTimestamps; 61 | std::shared_ptr mfuDataProcessor; 62 | std::shared_ptr videoComponentDescriptor; 63 | std::shared_ptr mhAudioComponentDescriptor; 64 | }; 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/mmtTableBase.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "stream.h" 3 | 4 | namespace MmtTlv { 5 | 6 | class MmtTableId { 7 | public: 8 | static constexpr uint8_t Pat = 0x00; 9 | static constexpr uint8_t Mpt = 0x20; 10 | static constexpr uint8_t Plt = 0x80; 11 | static constexpr uint8_t Lct = 0x81; 12 | static constexpr uint8_t Ecm_0 = 0x82; 13 | static constexpr uint8_t Ecm_1 = 0x83; 14 | static constexpr uint8_t Emm_0 = 0x84; 15 | static constexpr uint8_t Emm_1 = 0x85; 16 | static constexpr uint8_t Cat = 0x86; 17 | static constexpr uint8_t Dcm = 0x87; 18 | static constexpr uint8_t Dmm = 0x89; 19 | static constexpr uint8_t MhEitPf = 0x8B; // present and next program 20 | static constexpr uint8_t MhEitS_0 = 0x8C; // schedule 21 | static constexpr uint8_t MhEitS_1 = 0x8D; 22 | static constexpr uint8_t MhEitS_2 = 0x8E; 23 | static constexpr uint8_t MhEitS_3 = 0x8F; 24 | static constexpr uint8_t MhEitS_4 = 0x90; 25 | static constexpr uint8_t MhEitS_5 = 0x91; 26 | static constexpr uint8_t MhEitS_6 = 0x92; 27 | static constexpr uint8_t MhEitS_7 = 0x93; 28 | static constexpr uint8_t MhEitS_8 = 0x94; 29 | static constexpr uint8_t MhEitS_9 = 0x95; 30 | static constexpr uint8_t MhEitS_10 = 0x96; 31 | static constexpr uint8_t MhEitS_11 = 0x97; 32 | static constexpr uint8_t MhEitS_12 = 0x98; 33 | static constexpr uint8_t MhEitS_13 = 0x99; 34 | static constexpr uint8_t MhEitS_14 = 0x9A; 35 | static constexpr uint8_t MhEitS_15 = 0x9B; 36 | static constexpr uint8_t MhAit = 0x9C; 37 | static constexpr uint8_t MhBit = 0x9D; 38 | static constexpr uint8_t MhSdtt = 0x9E; 39 | static constexpr uint8_t MhSdtActual = 0x9F; 40 | static constexpr uint8_t MhSdtOther = 0xA0; 41 | static constexpr uint8_t MhTot = 0xA1; 42 | static constexpr uint8_t MhCdt = 0xA2; 43 | 44 | static constexpr uint8_t Ddmt = 0xA3; 45 | static constexpr uint8_t Damt = 0xA4; 46 | static constexpr uint8_t Dcct = 0xA5; 47 | 48 | static constexpr uint8_t Emt = 0xA6; 49 | 50 | }; 51 | 52 | class MmtTableBase { 53 | public: 54 | virtual ~MmtTableBase() = default; 55 | 56 | virtual bool unpack(Common::ReadStream& stream) 57 | { 58 | try { 59 | tableId = stream.get8U(); 60 | } 61 | catch (const std::out_of_range&) { 62 | return false; 63 | } 64 | 65 | return true; 66 | } 67 | uint8_t getTableId() const { return tableId; } 68 | 69 | protected: 70 | uint8_t tableId; 71 | 72 | }; 73 | 74 | } -------------------------------------------------------------------------------- /src/mmtTableFactory.cpp: -------------------------------------------------------------------------------- 1 | #include "mmtTableFactory.h" 2 | #include "ecm.h" 3 | #include "mhCdt.h" 4 | #include "mhEit.h" 5 | #include "mhSdt.h" 6 | #include "mhTot.h" 7 | #include "mpt.h" 8 | #include "plt.h" 9 | #include "mhBit.h" 10 | #include "mhAit.h" 11 | #include 12 | #include 13 | 14 | namespace MmtTlv { 15 | 16 | static const std::unordered_map()>> mapMmtTableFactory = { 17 | { MmtTableId::Ecm_0, [] { return std::make_shared(); } }, 18 | { MmtTableId::MhCdt, [] { return std::make_shared(); } }, 19 | { MmtTableId::MhEitPf, [] { return std::make_shared(); } }, 20 | { MmtTableId::MhEitS_0, [] { return std::make_shared(); } }, 21 | { MmtTableId::MhEitS_1, [] { return std::make_shared(); } }, 22 | { MmtTableId::MhEitS_2, [] { return std::make_shared(); } }, 23 | { MmtTableId::MhEitS_3, [] { return std::make_shared(); } }, 24 | { MmtTableId::MhEitS_4, [] { return std::make_shared(); } }, 25 | { MmtTableId::MhEitS_5, [] { return std::make_shared(); } }, 26 | { MmtTableId::MhEitS_6, [] { return std::make_shared(); } }, 27 | { MmtTableId::MhEitS_7, [] { return std::make_shared(); } }, 28 | { MmtTableId::MhEitS_8, [] { return std::make_shared(); } }, 29 | { MmtTableId::MhEitS_9, [] { return std::make_shared(); } }, 30 | { MmtTableId::MhEitS_10, [] { return std::make_shared(); } }, 31 | { MmtTableId::MhEitS_11, [] { return std::make_shared(); } }, 32 | { MmtTableId::MhEitS_12, [] { return std::make_shared(); } }, 33 | { MmtTableId::MhEitS_13, [] { return std::make_shared(); } }, 34 | { MmtTableId::MhEitS_14, [] { return std::make_shared(); } }, 35 | { MmtTableId::MhEitS_15, [] { return std::make_shared(); } }, 36 | { MmtTableId::MhSdtActual, [] { return std::make_shared(); } }, 37 | { MmtTableId::MhTot, [] { return std::make_shared(); } }, 38 | { MmtTableId::Mpt, [] { return std::make_shared(); } }, 39 | { MmtTableId::Plt, [] { return std::make_shared(); } }, 40 | { MmtTableId::MhBit, [] { return std::make_shared(); } }, 41 | { MmtTableId::MhAit, [] { return std::make_shared(); } }, 42 | }; 43 | 44 | std::shared_ptr MmtTableFactory::create(uint8_t id) { 45 | auto it = mapMmtTableFactory.find(id); 46 | if (it == mapMmtTableFactory.end()) { 47 | return {}; 48 | } 49 | 50 | return it->second(); 51 | } 52 | 53 | bool MmtTableFactory::isValidId(uint8_t id) 54 | { 55 | auto it = mapMmtTableFactory.find(id); 56 | if (it == mapMmtTableFactory.end()) { 57 | return false; 58 | } 59 | 60 | return true; 61 | } 62 | 63 | } -------------------------------------------------------------------------------- /src/mmtTableFactory.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace MmtTlv { 5 | class MmtTableBase; 6 | class MmtTableFactory { 7 | public: 8 | static std::shared_ptr create(uint8_t id); 9 | static bool isValidId(uint8_t id); 10 | 11 | }; 12 | 13 | } -------------------------------------------------------------------------------- /src/mmtTlvDemuxer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include "stream.h" 6 | #include "acascard.h" 7 | #include "mmt.h" 8 | #include "tlv.h" 9 | #include "mpu.h" 10 | #include "mpuExtendedTimestampDescriptor.h" 11 | #include "mpuTimestampDescriptor.h" 12 | #include "mpt.h" 13 | #include "mmtStream.h" 14 | #include "compressedIPPacket.h" 15 | #include "mfuDataProcessorBase.h" 16 | #include "mmtTlvStatistics.h" 17 | 18 | namespace MmtTlv { 19 | 20 | class FragmentAssembler; 21 | class TableBase; 22 | class Plt; 23 | class Ecm; 24 | class TlvTableBase; 25 | class DemuxerHandler; 26 | 27 | enum class MmtMessageId { 28 | PaMessage = 0x0000, 29 | M2SectionMessage = 0x8000, 30 | CaMessage = 0x8001, 31 | M2ShortSectionMessage = 0x8002, 32 | DataTransmissionMessage = 0x8003, 33 | }; 34 | 35 | enum class DemuxStatus { 36 | Ok = 0x0000, 37 | NotEnoughBuffer = 0x1000, 38 | NotValidTlv = 0x1001, 39 | WattingForEcm = 0x1002, 40 | Error = 0x2000, 41 | }; 42 | 43 | class MmtTlvDemuxer { 44 | public: 45 | MmtTlvDemuxer(); 46 | bool init(); 47 | void setDemuxerHandler(DemuxerHandler& demuxerHandler); 48 | void setSmartCardReaderName(const std::string& smartCardReaderName); 49 | DemuxStatus demux(Common::ReadStream& stream); 50 | void clear(); 51 | void release(); 52 | void printStatistics() const; 53 | 54 | private: 55 | bool isVaildTlv(Common::ReadStream& stream) const; 56 | 57 | void processMpu(Common::ReadStream& stream); 58 | void processMfuData(Common::ReadStream& stream); 59 | void processSignalingMessages(Common::ReadStream& stream); 60 | void processSignalingMessage(Common::ReadStream& stream); 61 | void processPaMessage(Common::ReadStream& stream); 62 | void processM2SectionMessage(Common::ReadStream& stream); 63 | void processCaMessage(Common::ReadStream& stream); 64 | void processM2ShortSectionMessage(Common::ReadStream& stream); 65 | void processDataTransmissionMessage(Common::ReadStream& stream); 66 | void processTlvTable(Common::ReadStream& stream); 67 | void processMmtTable(Common::ReadStream& stream); 68 | void processMmtTableStatistics(uint8_t tableId); 69 | void processMmtPackageTable(const std::shared_ptr& mpt); 70 | void processMpuTimestampDescriptor(const std::shared_ptr& descriptor, std::shared_ptr& mmtStream); 71 | void processMpuExtendedTimestampDescriptor(const std::shared_ptr& descriptor, std::shared_ptr& mmtStream); 72 | void processEcm(std::shared_ptr ecm); 73 | 74 | public: 75 | std::shared_ptr getStream(uint16_t pid); 76 | 77 | std::map> mapStream; 78 | std::map> mapStreamByStreamIdx; 79 | 80 | private: 81 | std::shared_ptr getAssembler(uint16_t pid); 82 | 83 | std::shared_ptr smartCard; 84 | std::unique_ptr acasCard; 85 | std::map> mapAssembler; 86 | Tlv tlv; 87 | CompressedIPPacket compressedIPPacket; 88 | Mmt mmt; 89 | Mpu mpu; 90 | std::map> mfuData; 91 | DemuxerHandler* demuxerHandler = nullptr; 92 | mmtTlvStatistics statistics; 93 | }; 94 | } -------------------------------------------------------------------------------- /src/mpt.cpp: -------------------------------------------------------------------------------- 1 | #include "mpt.h" 2 | 3 | namespace MmtTlv { 4 | 5 | bool Mpt::unpack(Common::ReadStream& stream) 6 | { 7 | try { 8 | if (!MmtTableBase::unpack(stream)) { 9 | return false; 10 | } 11 | 12 | version = stream.get8U(); 13 | length = stream.getBe16U(); 14 | uint8_t uint8 = stream.get8U(); 15 | reserved = (uint8 & 0b11111100) >> 2; 16 | mptMode = (uint8 & 0x00000011); 17 | 18 | mmtPackageIdLength = stream.get8U(); 19 | if (stream.leftBytes() < mmtPackageIdLength) { 20 | return false; 21 | } 22 | 23 | mmtPackageIdByte.resize(mmtPackageIdLength); 24 | stream.read(mmtPackageIdByte.data(), mmtPackageIdLength); 25 | 26 | mptDescriptorsLength = stream.getBe16U(); 27 | 28 | Common::ReadStream nstream(stream, mptDescriptorsLength); 29 | if (!descriptors.unpack(nstream)) { 30 | return false; 31 | } 32 | stream.skip(mptDescriptorsLength); 33 | 34 | numberOfAssets = stream.get8U(); 35 | for (int i = 0; i < numberOfAssets; i++) { 36 | Asset asset; 37 | if (!asset.unpack(stream)) { 38 | return false; 39 | } 40 | assets.push_back(asset); 41 | } 42 | } 43 | catch (const std::out_of_range&) { 44 | return false; 45 | } 46 | 47 | return true; 48 | } 49 | 50 | bool Mpt::Asset::unpack(Common::ReadStream& stream) 51 | { 52 | try { 53 | identifierType = stream.get8U(); 54 | assetIdScheme = stream.getBe32U(); 55 | assetIdLength = stream.get8U(); 56 | 57 | assetIdByte.resize(assetIdLength); 58 | stream.read(assetIdByte.data(), assetIdLength); 59 | 60 | assetType = stream.getBe32U(); 61 | uint8_t uint8 = stream.get8U(); 62 | reserved = (uint8 & 0b11111110) >> 2; 63 | assetClockRelationFlag = (uint8 & 0x00000001); 64 | locationCount = stream.get8U(); 65 | for (int i = 0; i < locationCount; i++) { 66 | MmtGeneralLocationInfo locationInfo; 67 | if (!locationInfo.unpack(stream)) { 68 | return false; 69 | } 70 | locationInfos.push_back(locationInfo); 71 | } 72 | 73 | assetDescriptorsLength = stream.getBe16U(); 74 | 75 | Common::ReadStream nstream(stream, assetDescriptorsLength); 76 | if (!descriptors.unpack(nstream)) { 77 | return false; 78 | } 79 | stream.skip(assetDescriptorsLength); 80 | } 81 | catch (const std::out_of_range&) { 82 | return false; 83 | } 84 | 85 | return true; 86 | } 87 | 88 | } -------------------------------------------------------------------------------- /src/mpt.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "mmtTableBase.h" 3 | #include "mmtGeneralLocationInfo.h" 4 | #include "mmtDescriptors.h" 5 | 6 | namespace MmtTlv { 7 | 8 | // MMT Package Table 9 | class Mpt : public MmtTableBase { 10 | public: 11 | bool unpack(Common::ReadStream& stream); 12 | 13 | class Asset { 14 | public: 15 | bool unpack(Common::ReadStream& stream); 16 | 17 | uint8_t identifierType; 18 | uint32_t assetIdScheme; 19 | uint8_t assetIdLength; 20 | std::vector assetIdByte; 21 | uint32_t assetType; 22 | uint8_t reserved; 23 | bool assetClockRelationFlag; 24 | uint8_t locationCount; 25 | std::vector locationInfos; 26 | 27 | uint16_t assetDescriptorsLength; 28 | MmtDescriptors descriptors; 29 | }; 30 | 31 | uint8_t version; 32 | uint16_t length; 33 | uint8_t reserved; 34 | uint8_t mptMode; 35 | uint8_t mmtPackageIdLength; 36 | std::vector mmtPackageIdByte; 37 | uint16_t mptDescriptorsLength; 38 | MmtDescriptors descriptors; 39 | 40 | uint8_t numberOfAssets; 41 | std::list assets; 42 | }; 43 | 44 | } -------------------------------------------------------------------------------- /src/mpu.cpp: -------------------------------------------------------------------------------- 1 | #include "mpu.h" 2 | 3 | namespace MmtTlv { 4 | 5 | bool Mpu::unpack(Common::ReadStream& stream) 6 | { 7 | try { 8 | payloadLength = stream.getBe16U(); 9 | if (payloadLength != stream.leftBytes()) 10 | return false; 11 | 12 | uint8_t byte = stream.get8U(); 13 | fragmentType = static_cast(byte >> 4); 14 | timedFlag = (byte >> 3) & 1; 15 | fragmentationIndicator = static_cast((byte >> 1) & 0b11); 16 | aggregateFlag = byte & 1; 17 | 18 | fragmentCounter = stream.get8U(); 19 | mpuSequenceNumber = stream.getBe32U(); 20 | 21 | payload.resize(payloadLength - 6); 22 | stream.read(payload.data(), payloadLength - 6); 23 | 24 | } 25 | catch (const std::out_of_range&) { 26 | return false; 27 | } 28 | 29 | return true; 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /src/mpu.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "stream.h" 4 | #include "mmtFragment.h" 5 | 6 | namespace MmtTlv { 7 | 8 | class Mpu { 9 | public: 10 | bool unpack(Common::ReadStream& stream); 11 | 12 | uint16_t payloadLength; 13 | FragmentType fragmentType; 14 | bool timedFlag; 15 | FragmentationIndicator fragmentationIndicator; 16 | bool aggregateFlag; 17 | uint8_t fragmentCounter; 18 | uint32_t mpuSequenceNumber; 19 | std::vector payload; 20 | }; 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/mpuExtendedTimestampDescriptor.cpp: -------------------------------------------------------------------------------- 1 | #include "mpuExtendedTimestampDescriptor.h" 2 | 3 | namespace MmtTlv { 4 | 5 | bool MpuExtendedTimestampDescriptor::unpack(Common::ReadStream& stream) 6 | { 7 | try { 8 | if (!MmtDescriptorTemplate::unpack(stream)) { 9 | return false; 10 | } 11 | 12 | uint8_t uint8 = stream.get8U(); 13 | reserved = (uint8 & 0b11111000) >> 3; 14 | ptsOffsetType = (uint8 & 0b00000110) >> 1; 15 | timescaleFlag = uint8 & 0b00000001; 16 | 17 | if (timescaleFlag) { 18 | timescale = stream.getBe32U(); 19 | } 20 | if (ptsOffsetType == 1) { 21 | defaultPtsOffset = stream.getBe16U(); 22 | } 23 | 24 | entries.reserve(15); 25 | while (!stream.isEof()) { 26 | Entry entry; 27 | if (!entry.unpack(stream, ptsOffsetType, defaultPtsOffset)) { 28 | return false; 29 | } 30 | 31 | entries.push_back(entry); 32 | } 33 | } 34 | catch (const std::out_of_range&) { 35 | return false; 36 | } 37 | 38 | return true; 39 | } 40 | 41 | bool MpuExtendedTimestampDescriptor::Entry::unpack(Common::ReadStream& stream, uint8_t ptsOffsetType, uint16_t defaultPtsOffset) 42 | { 43 | try { 44 | mpuSequenceNumber = stream.getBe32U(); 45 | uint8_t uint8 = stream.get8U(); 46 | mpuPresentationTimeLeapIndicator = (uint8 & 0b11000000) >> 6; 47 | reserved = uint8 & 0b00111111; 48 | mpuDecodingTimeOffset = stream.getBe16U(); 49 | numOfAu = stream.get8U(); 50 | 51 | dtsPtsOffsets.reserve(numOfAu); 52 | ptsOffsets.reserve(numOfAu); 53 | for (int i = 0; i < numOfAu; i++) { 54 | dtsPtsOffsets.push_back(stream.getBe16U()); 55 | if (ptsOffsetType == 2) { 56 | ptsOffsets.push_back(stream.getBe16U()); 57 | } 58 | else { 59 | ptsOffsets.push_back(defaultPtsOffset); 60 | } 61 | } 62 | } 63 | catch (const std::out_of_range&) { 64 | return false; 65 | } 66 | 67 | return true; 68 | } 69 | 70 | } -------------------------------------------------------------------------------- /src/mpuExtendedTimestampDescriptor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "mmtDescriptorBase.h" 3 | 4 | namespace MmtTlv { 5 | 6 | class MpuExtendedTimestampDescriptor 7 | : public MmtDescriptorTemplate<0x8026> { 8 | public: 9 | bool unpack(Common::ReadStream& stream) override; 10 | 11 | class Entry { 12 | public: 13 | bool unpack(Common::ReadStream& stream, uint8_t ptsOffsetType, uint16_t defaultPtsOffset); 14 | 15 | uint32_t mpuSequenceNumber; 16 | uint8_t mpuPresentationTimeLeapIndicator; 17 | uint8_t reserved; 18 | uint16_t mpuDecodingTimeOffset; 19 | uint8_t numOfAu; 20 | std::vector dtsPtsOffsets; 21 | std::vector ptsOffsets; 22 | }; 23 | 24 | uint8_t reserved; 25 | uint8_t ptsOffsetType; 26 | bool timescaleFlag; 27 | 28 | uint32_t timescale; 29 | uint16_t defaultPtsOffset; 30 | 31 | std::vector entries; 32 | }; 33 | 34 | } -------------------------------------------------------------------------------- /src/mpuTimestampDescriptor.cpp: -------------------------------------------------------------------------------- 1 | #include "mpuTimestampDescriptor.h" 2 | 3 | namespace MmtTlv { 4 | 5 | namespace { 6 | 7 | #define NTP_OFFSET 2208988800ULL 8 | #define NTP_OFFSET_US (NTP_OFFSET * 1000000ULL) 9 | 10 | uint64_t ff_parse_ntp_time2(uint64_t ntp_ts) 11 | { 12 | uint64_t sec = ntp_ts >> 32; 13 | uint64_t frac_part = ntp_ts & 0xFFFFFFFFULL; 14 | uint64_t usec = (frac_part * 1000000) / 0xFFFFFFFFULL; 15 | 16 | return (sec * 1000000) + usec; 17 | } 18 | 19 | } // anonymous namespace 20 | 21 | bool MpuTimestampDescriptor::unpack(Common::ReadStream& stream) 22 | { 23 | try { 24 | if (!MmtDescriptorTemplate::unpack(stream)) { 25 | return false; 26 | } 27 | 28 | entries.reserve(descriptorLength / 12); 29 | for (int i = 0; i < descriptorLength / 12; i++) { 30 | Entry entry; 31 | entry.mpuSequenceNumber = stream.getBe32U(); 32 | entry.mpuPresentationTime = ff_parse_ntp_time2(stream.getBe64U()) - NTP_OFFSET_US; 33 | entries.push_back(entry); 34 | } 35 | } 36 | catch (const std::out_of_range&) { 37 | return false; 38 | } 39 | 40 | return true; 41 | } 42 | 43 | } -------------------------------------------------------------------------------- /src/mpuTimestampDescriptor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "mmtDescriptorBase.h" 3 | 4 | namespace MmtTlv { 5 | 6 | class MpuTimestampDescriptor 7 | : public MmtDescriptorTemplate<0x0001> { 8 | public: 9 | bool unpack(Common::ReadStream& stream) override; 10 | 11 | class Entry { 12 | public: 13 | uint32_t mpuSequenceNumber; 14 | uint64_t mpuPresentationTime; 15 | }; 16 | 17 | std::vector entries; 18 | }; 19 | 20 | } -------------------------------------------------------------------------------- /src/multimediaServiceInformationDescriptor.cpp: -------------------------------------------------------------------------------- 1 | #include "multimediaServiceInformationDescriptor.h" 2 | 3 | namespace MmtTlv { 4 | 5 | bool MultimediaServiceInformationDescriptor::unpack(Common::ReadStream& stream) 6 | { 7 | try { 8 | if (!MmtDescriptorTemplate::unpack(stream)) { 9 | return false; 10 | } 11 | 12 | Common::ReadStream nstream(stream, descriptorLength); 13 | 14 | dataComponentId = nstream.getBe16U(); 15 | if (dataComponentId == 0x0020) { 16 | componentTag = nstream.getBe16U(); 17 | 18 | nstream.read(language, 3); 19 | language[3] = '\0'; 20 | 21 | textLength = nstream.get8U(); 22 | text.resize(textLength); 23 | nstream.read(text.data(), textLength); 24 | } 25 | 26 | if (dataComponentId == 0x0021) { 27 | uint8_t uint8 = nstream.get8U(); 28 | associatedContentsFlag = (uint8 & 0b10000000) >> 7; 29 | reserved = uint8 & 0b01111111; 30 | } 31 | 32 | selectorLength = nstream.get8U(); 33 | selectorByte.resize(selectorLength); 34 | nstream.read(selectorByte.data(), selectorLength); 35 | 36 | stream.skip(descriptorLength); 37 | } 38 | catch (const std::out_of_range&) { 39 | return false; 40 | } 41 | 42 | return true; 43 | } 44 | 45 | } -------------------------------------------------------------------------------- /src/multimediaServiceInformationDescriptor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "mmtDescriptorBase.h" 3 | 4 | namespace MmtTlv { 5 | 6 | class MultimediaServiceInformationDescriptor 7 | : public MmtDescriptorTemplate<0x803F> { 8 | public: 9 | bool unpack(Common::ReadStream& stream) override; 10 | 11 | uint16_t dataComponentId; 12 | 13 | uint16_t componentTag; 14 | char language[4]; 15 | uint8_t textLength; 16 | std::string text; 17 | 18 | uint8_t associatedContentsFlag; 19 | uint8_t reserved; 20 | 21 | uint8_t selectorLength; 22 | std::vector selectorByte; 23 | 24 | }; 25 | 26 | } -------------------------------------------------------------------------------- /src/networkNameDescriptor.cpp: -------------------------------------------------------------------------------- 1 | #include "networkNameDescriptor.h" 2 | 3 | namespace MmtTlv { 4 | 5 | bool NetworkNameDescriptor::unpack(Common::ReadStream& stream) 6 | { 7 | try { 8 | if (!TlvDescriptorTemplate::unpack(stream)) { 9 | return false; 10 | } 11 | 12 | size_t size = stream.leftBytes(); 13 | networkName.resize(size); 14 | stream.read(networkName.data(), size); 15 | } 16 | catch (const std::out_of_range&) { 17 | return false; 18 | } 19 | 20 | return true; 21 | } 22 | 23 | } -------------------------------------------------------------------------------- /src/networkNameDescriptor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "tlvDescriptorBase.h" 3 | 4 | namespace MmtTlv { 5 | 6 | class NetworkNameDescriptor : public TlvDescriptorTemplate<0x40> { 7 | public: 8 | bool unpack(Common::ReadStream& stream); 9 | std::string networkName; 10 | }; 11 | 12 | } -------------------------------------------------------------------------------- /src/nit.cpp: -------------------------------------------------------------------------------- 1 | #include "nit.h" 2 | 3 | namespace MmtTlv { 4 | 5 | bool Nit::unpack(Common::ReadStream& stream) 6 | { 7 | try { 8 | if (!TlvTableBase::unpack(stream)) { 9 | return false; 10 | } 11 | 12 | uint16_t uint16 = stream.getBe16U(); 13 | sectionSyntaxIndicator = (uint16 & 0b1000000000000000) >> 15; 14 | sectionLength = uint16 & 0b0000111111111111; 15 | 16 | networkId = stream.getBe16U(); 17 | 18 | uint8_t uint8 = stream.get8U(); 19 | versionNumber = (uint8 & 0b00111110) >> 1; 20 | currentNextIndicator = uint8 & 1; 21 | sectionNumber = stream.get8U(); 22 | lastSectionNumber = stream.get8U(); 23 | 24 | uint16 = stream.getBe16U(); 25 | networkDescriptorsLength = uint16 & 0b0000111111111111; 26 | 27 | { 28 | Common::ReadStream nstream(stream, networkDescriptorsLength); 29 | if (!descriptors.unpack(nstream)) { 30 | return false; 31 | } 32 | stream.skip(networkDescriptorsLength); 33 | } 34 | 35 | uint16 = stream.getBe16U(); 36 | tlvStreamLoopLength = uint16 & 0b0000111111111111; 37 | 38 | Common::ReadStream nstream(stream, tlvStreamLoopLength); 39 | while (!nstream.isEof()) { 40 | Entry entry; 41 | if (!entry.unpack(nstream)) { 42 | return false; 43 | } 44 | entries.push_back(entry); 45 | } 46 | stream.skip(tlvStreamLoopLength); 47 | } 48 | catch (const std::out_of_range&) { 49 | return false; 50 | } 51 | 52 | return true; 53 | } 54 | 55 | bool Nit::Entry::unpack(Common::ReadStream& stream) 56 | { 57 | try { 58 | tlvStreamId = stream.getBe16U(); 59 | originalNetworkId = stream.getBe16U(); 60 | 61 | uint16_t uint16 = stream.getBe16U(); 62 | tlvStreamDescriptorsLength = uint16 & 0b0000111111111111; 63 | 64 | Common::ReadStream nstream(stream, tlvStreamDescriptorsLength); 65 | if (!descriptors.unpack(nstream)) { 66 | return false; 67 | } 68 | stream.skip(tlvStreamDescriptorsLength); 69 | } 70 | catch (const std::out_of_range&) { 71 | return false; 72 | } 73 | 74 | return true; 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /src/nit.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "tlvTableBase.h" 4 | #include "tlvDescriptors.h" 5 | #include "stream.h" 6 | 7 | namespace MmtTlv { 8 | 9 | // Network Information Table 10 | class Nit : public TlvTableBase { 11 | public: 12 | bool unpack(Common::ReadStream& stream); 13 | 14 | class Entry { 15 | public: 16 | bool unpack(Common::ReadStream& stream); 17 | 18 | uint16_t tlvStreamId; 19 | uint16_t originalNetworkId; 20 | uint16_t tlvStreamDescriptorsLength; 21 | TlvDescriptors descriptors; 22 | }; 23 | 24 | 25 | uint16_t sectionSyntaxIndicator; 26 | uint16_t sectionLength; 27 | uint16_t networkId; 28 | uint8_t versionNumber; 29 | bool currentNextIndicator; 30 | uint8_t sectionNumber; 31 | uint8_t lastSectionNumber; 32 | 33 | uint16_t networkDescriptorsLength; 34 | TlvDescriptors descriptors; 35 | 36 | uint16_t tlvStreamLoopLength; 37 | std::list entries; 38 | 39 | }; 40 | 41 | } -------------------------------------------------------------------------------- /src/ntp.cpp: -------------------------------------------------------------------------------- 1 | #include "ntp.h" 2 | 3 | bool MmtTlv::NTPv4::unpack(Common::ReadStream& stream) 4 | { 5 | try { 6 | uint8_t uint8 = stream.get8U(); 7 | leap_indicator = uint8 & 0b11000000; 8 | version_number = uint8 & 0b00111000; 9 | mode = uint8 & 0b00000111; 10 | 11 | stratum = stream.get8U(); 12 | poll_interval = stream.get8U(); 13 | precision = stream.get8U(); 14 | 15 | root_delay = stream.getBe32U(); 16 | root_dispersion = stream.getBe32U(); 17 | reference_id = stream.getBe32U(); 18 | 19 | if (!reference_timestamp.unpack(stream)) { 20 | return false; 21 | } 22 | if (!origin_timestamp.unpack(stream)) { 23 | return false; 24 | } 25 | if (!receive_timestamp.unpack(stream)) { 26 | return false; 27 | } 28 | if (!transmit_timestamp.unpack(stream)) { 29 | return false; 30 | } 31 | } 32 | catch (const std::out_of_range&) { 33 | return false; 34 | } 35 | 36 | return true; 37 | } 38 | 39 | 40 | bool MmtTlv::NtpTimestamp::unpack(Common::ReadStream& stream) 41 | { 42 | try { 43 | seconds = stream.getBe32U(); 44 | fraction = stream.getBe32U(); 45 | } 46 | catch (const std::out_of_range&) { 47 | return false; 48 | } 49 | 50 | return true; 51 | } 52 | -------------------------------------------------------------------------------- /src/ntp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "stream.h" 3 | #include "timebase.h" 4 | 5 | namespace MmtTlv { 6 | 7 | class NtpTimestamp { 8 | public: 9 | bool unpack(Common::ReadStream& stream); 10 | int64_t toPcrValue() const { 11 | const uint32_t NTP_1970 = 2208988800U; 12 | int64_t unixTimestamp = static_cast(((seconds - NTP_1970) * 1000.0) + ((fraction / 4294967296.0) * 1000.0)); 13 | 14 | const AVRational ntpTimeBase = { 1, 1000 }; 15 | const AVRational pcrTimeBase = { 1, 27000000 }; 16 | 17 | return av_rescale_q(unixTimestamp, ntpTimeBase, pcrTimeBase); 18 | } 19 | 20 | public: 21 | uint32_t seconds; 22 | uint32_t fraction; 23 | 24 | }; 25 | 26 | class NTPv4 { 27 | public: 28 | bool unpack(Common::ReadStream& stream); 29 | 30 | public: 31 | uint8_t leap_indicator; 32 | uint8_t version_number; 33 | uint8_t mode; 34 | 35 | uint8_t stratum; 36 | uint8_t poll_interval; 37 | uint8_t precision; 38 | 39 | uint32_t root_delay; 40 | uint32_t root_dispersion; 41 | uint32_t reference_id; 42 | 43 | NtpTimestamp reference_timestamp; 44 | NtpTimestamp origin_timestamp; 45 | NtpTimestamp receive_timestamp; 46 | NtpTimestamp transmit_timestamp; 47 | 48 | }; 49 | 50 | } -------------------------------------------------------------------------------- /src/paMessage.cpp: -------------------------------------------------------------------------------- 1 | #include "paMessage.h" 2 | 3 | namespace MmtTlv { 4 | 5 | bool PaMessage::unpack(Common::ReadStream& stream) 6 | { 7 | try { 8 | messageId = stream.getBe16U(); 9 | version = stream.get8U(); 10 | length = stream.getBe32U(); 11 | 12 | numberOfTables = stream.get8U(); 13 | 14 | if (stream.leftBytes() < (8 + 8 + 16) * numberOfTables) { 15 | return false; 16 | } 17 | 18 | for (int i = 0; i < numberOfTables; i++) { 19 | stream.skip(8 + 8 + 16); 20 | } 21 | 22 | table.resize(stream.leftBytes()); 23 | stream.read(table.data(), stream.leftBytes()); 24 | } 25 | catch (const std::out_of_range&) { 26 | return false; 27 | } 28 | 29 | return true; 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /src/paMessage.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "stream.h" 4 | 5 | namespace MmtTlv { 6 | 7 | class PaMessage { 8 | public: 9 | bool unpack(Common::ReadStream& stream); 10 | 11 | uint16_t messageId; 12 | uint8_t version; 13 | uint32_t length; 14 | uint8_t numberOfTables; 15 | std::vector table; 16 | }; 17 | 18 | } -------------------------------------------------------------------------------- /src/pesPacket.cpp: -------------------------------------------------------------------------------- 1 | #include "pesPacket.h" 2 | #include "stream.h" 3 | 4 | namespace { 5 | 6 | void writePts(MmtTlv::Common::WriteStream &stream, int fourbits, int64_t pts) 7 | { 8 | int val; 9 | 10 | val = fourbits << 4 | (((pts >> 30) & 0x07) << 1) | 1; 11 | stream.put8U(val); 12 | val = (((pts >> 15) & 0x7fff) << 1) | 1; 13 | stream.put8U(val >> 8); 14 | stream.put8U(val); 15 | val = (((pts) & 0x7fff) << 1) | 1; 16 | stream.put8U(val >> 8); 17 | stream.put8U(val); 18 | } 19 | 20 | } 21 | 22 | bool PESPacket::pack(std::vector& output) 23 | { 24 | if (!payload) { 25 | return false; 26 | } 27 | 28 | MmtTlv::Common::WriteStream stream; 29 | 30 | // packet_start_code_prefix 31 | stream.write({0x00, 0x00, 0x01}); 32 | stream.put8U(streamId); 33 | 34 | uint8_t flags = 0; 35 | uint8_t headerLength = 0; 36 | 37 | if (pts != NOPTS_VALUE) { 38 | headerLength += 5; 39 | flags |= 0b10000000; 40 | } 41 | 42 | if (dts != NOPTS_VALUE && pts != NOPTS_VALUE && dts != pts) { 43 | headerLength += 5; 44 | flags |= 0b01000000; 45 | } 46 | 47 | size_t length = payload->size() + headerLength + 3; 48 | if (length > 0xffff) { 49 | length = 0; 50 | } 51 | 52 | stream.putBe16U(static_cast(length)); 53 | stream.put8U(2 << 6 /* reserved */ | dataAlignmentIndicator << 2); 54 | stream.put8U(flags); 55 | stream.put8U(headerLength); 56 | 57 | if (pts != NOPTS_VALUE) { 58 | writePts(stream, flags >> 6, pts); 59 | } 60 | if (dts != NOPTS_VALUE && pts != NOPTS_VALUE && dts != pts) { 61 | writePts(stream, 1, dts); 62 | } 63 | 64 | stream.write(std::span{payload->data(), payload->size()}); 65 | 66 | output = stream.getData(); 67 | return true; 68 | } -------------------------------------------------------------------------------- /src/pesPacket.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | constexpr uint8_t STREAM_ID_PROGRAM_STREAM_MAP = 0xbc; 6 | constexpr uint8_t STREAM_ID_PRIVATE_STREAM_1 = 0xbd; 7 | constexpr uint8_t STREAM_ID_PADDING_STREAM = 0xbe; 8 | constexpr uint8_t STREAM_ID_PRIVATE_STREAM_2 = 0xbf; 9 | constexpr uint8_t STREAM_ID_AUDIO_STREAM_0 = 0xc0; 10 | constexpr uint8_t STREAM_ID_VIDEO_STREAM_0 = 0xe0; 11 | constexpr uint8_t STREAM_ID_ECM_STREAM = 0xf0; 12 | constexpr uint8_t STREAM_ID_EMM_STREAM = 0xf1; 13 | constexpr uint8_t STREAM_ID_DSMCC_STREAM = 0xf2; 14 | constexpr uint8_t STREAM_ID_TYPE_E_STREAM = 0xf8; 15 | constexpr uint8_t STREAM_ID_METADATA_STREAM = 0xfc; 16 | constexpr uint8_t STREAM_ID_EXTENDED_STREAM_ID = 0xfd; 17 | constexpr uint8_t STREAM_ID_PROGRAM_STREAM_DIRECTORY = 0xff; 18 | 19 | constexpr uint64_t NOPTS_VALUE = 0x8000000000000000; 20 | 21 | constexpr uint8_t componentTagToStreamId(uint8_t tag) { 22 | if (tag >= 0 && tag <= 0x0F) { 23 | return STREAM_ID_VIDEO_STREAM_0 + tag; 24 | } 25 | 26 | if (tag >= 0x10 && tag <= 0x2F) { 27 | return STREAM_ID_AUDIO_STREAM_0 + (tag - 0x10); 28 | } 29 | 30 | if (tag == 0x30) { 31 | return STREAM_ID_PRIVATE_STREAM_1; 32 | } 33 | 34 | if (tag == 0x38) { 35 | return STREAM_ID_PRIVATE_STREAM_2; 36 | } 37 | 38 | return STREAM_ID_PRIVATE_STREAM_1; 39 | } 40 | 41 | class PESPacket { 42 | public: 43 | bool pack(std::vector& output); 44 | void setPts(uint64_t pts) { this->pts = pts; } 45 | void setDts(uint64_t dts) { this->dts = dts; } 46 | void setStreamId(uint8_t streamId) { this->streamId = streamId; }; 47 | void setDataAlignmentIndicator(bool dataAlignmentIndicator) { this->dataAlignmentIndicator = dataAlignmentIndicator; } 48 | uint64_t getPts() const { return pts; } 49 | uint64_t getDts() const { return dts; } 50 | uint8_t setStreamId() const { return streamId; } 51 | void setPayload(const std::vector* payload) { this->payload = payload; } 52 | bool getDataAlignmentIndicator() const { return dataAlignmentIndicator; } 53 | 54 | 55 | private: 56 | uint8_t streamId{}; 57 | bool dataAlignmentIndicator{}; 58 | const std::vector* payload{nullptr}; 59 | 60 | uint64_t pts{NOPTS_VALUE}; 61 | uint64_t dts{NOPTS_VALUE}; 62 | 63 | }; -------------------------------------------------------------------------------- /src/plt.cpp: -------------------------------------------------------------------------------- 1 | #include "plt.h" 2 | 3 | namespace MmtTlv { 4 | 5 | bool Plt::unpack(Common::ReadStream& stream) 6 | { 7 | try { 8 | if (!MmtTableBase::unpack(stream)) { 9 | return false; 10 | } 11 | 12 | version = stream.get8U(); 13 | length = stream.getBe16U(); 14 | numOfPackage = stream.get8U(); 15 | 16 | for (int i = 0; i < numOfPackage; i++) { 17 | Entry item; 18 | if (!item.unpack(stream)) { 19 | return false; 20 | } 21 | entries.push_back(item); 22 | } 23 | } 24 | catch (const std::out_of_range&) { 25 | return false; 26 | } 27 | return true; 28 | } 29 | 30 | bool Plt::Entry::unpack(Common::ReadStream& stream) 31 | { 32 | try { 33 | mmtPackageIdLength = stream.get8U(); 34 | 35 | if (stream.leftBytes() < mmtPackageIdLength) { 36 | return false; 37 | } 38 | 39 | mmtPackageIdByte.resize(mmtPackageIdLength); 40 | stream.read(mmtPackageIdByte.data(), mmtPackageIdLength); 41 | if (!locationInfos.unpack(stream)) { 42 | return false; 43 | } 44 | } 45 | catch (const std::out_of_range&) { 46 | return false; 47 | } 48 | 49 | return true; 50 | } 51 | 52 | } -------------------------------------------------------------------------------- /src/plt.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "mmtTableBase.h" 4 | #include "mmtGeneralLocationInfo.h" 5 | 6 | namespace MmtTlv { 7 | 8 | // Package List Table 9 | class Plt : public MmtTableBase { 10 | public: 11 | bool unpack(Common::ReadStream& stream); 12 | 13 | class Entry { 14 | public: 15 | bool unpack(Common::ReadStream& stream); 16 | 17 | uint8_t mmtPackageIdLength; 18 | std::vector mmtPackageIdByte; 19 | MmtGeneralLocationInfo locationInfos; 20 | }; 21 | 22 | uint8_t version; 23 | uint16_t length; 24 | uint8_t numOfPackage; 25 | std::list entries; 26 | }; 27 | 28 | } -------------------------------------------------------------------------------- /src/pugiconfig.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * pugixml parser - version 1.15 3 | * -------------------------------------------------------- 4 | * Copyright (C) 2006-2025, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) 5 | * Report bugs and download new versions at https://pugixml.org/ 6 | * 7 | * This library is distributed under the MIT License. See notice at the end 8 | * of this file. 9 | * 10 | * This work is based on the pugxml parser, which is: 11 | * Copyright (C) 2003, by Kristen Wegner (kristen@tima.net) 12 | */ 13 | 14 | #ifndef HEADER_PUGICONFIG_HPP 15 | #define HEADER_PUGICONFIG_HPP 16 | 17 | // Uncomment this to enable wchar_t mode 18 | // #define PUGIXML_WCHAR_MODE 19 | 20 | // Uncomment this to enable compact mode 21 | // #define PUGIXML_COMPACT 22 | 23 | // Uncomment this to disable XPath 24 | // #define PUGIXML_NO_XPATH 25 | 26 | // Uncomment this to disable STL 27 | // #define PUGIXML_NO_STL 28 | 29 | // Uncomment this to disable exceptions 30 | // #define PUGIXML_NO_EXCEPTIONS 31 | 32 | // Set this to control attributes for public classes/functions, i.e.: 33 | // #define PUGIXML_API __declspec(dllexport) // to export all public symbols from DLL 34 | // #define PUGIXML_CLASS __declspec(dllimport) // to import all classes from DLL 35 | // #define PUGIXML_FUNCTION __fastcall // to set calling conventions to all public functions to fastcall 36 | // In absence of PUGIXML_CLASS/PUGIXML_FUNCTION definitions PUGIXML_API is used instead 37 | 38 | // Tune these constants to adjust memory-related behavior 39 | // #define PUGIXML_MEMORY_PAGE_SIZE 32768 40 | // #define PUGIXML_MEMORY_OUTPUT_STACK 10240 41 | // #define PUGIXML_MEMORY_XPATH_PAGE_SIZE 4096 42 | 43 | // Tune this constant to adjust max nesting for XPath queries 44 | // #define PUGIXML_XPATH_DEPTH_LIMIT 1024 45 | 46 | // Uncomment this to switch to header-only version 47 | // #define PUGIXML_HEADER_ONLY 48 | 49 | // Uncomment this to enable long long support (usually enabled automatically) 50 | // #define PUGIXML_HAS_LONG_LONG 51 | 52 | // Uncomment this to enable support for std::string_view (usually enabled automatically) 53 | // #define PUGIXML_HAS_STRING_VIEW 54 | 55 | #endif 56 | 57 | /** 58 | * Copyright (c) 2006-2025 Arseny Kapoulkine 59 | * 60 | * Permission is hereby granted, free of charge, to any person 61 | * obtaining a copy of this software and associated documentation 62 | * files (the "Software"), to deal in the Software without 63 | * restriction, including without limitation the rights to use, 64 | * copy, modify, merge, publish, distribute, sublicense, and/or sell 65 | * copies of the Software, and to permit persons to whom the 66 | * Software is furnished to do so, subject to the following 67 | * conditions: 68 | * 69 | * The above copyright notice and this permission notice shall be 70 | * included in all copies or substantial portions of the Software. 71 | * 72 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 73 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 74 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 75 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 76 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 77 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 78 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 79 | * OTHER DEALINGS IN THE SOFTWARE. 80 | */ 81 | -------------------------------------------------------------------------------- /src/relatedBroadcasterDescriptor.cpp: -------------------------------------------------------------------------------- 1 | #include "relatedBroadcasterDescriptor.h" 2 | 3 | namespace MmtTlv { 4 | 5 | bool RelatedBroadcasterDescriptor::unpack(Common::ReadStream& stream) 6 | { 7 | try { 8 | if (!MmtDescriptorTemplate::unpack(stream)) { 9 | return false; 10 | } 11 | 12 | Common::ReadStream nstream(stream, descriptorLength); 13 | 14 | uint8_t uint8 = nstream.get8U(); 15 | numOfBroadcasterId = (uint8 & 0b11110000) >> 4; 16 | numOfAffiliationId = uint8 & 0b00001111; 17 | 18 | uint8 = nstream.get8U(); 19 | numOfOriginalNetworkId = (uint8 & 0b11110000) >> 4; 20 | 21 | for (int i = 0; i < numOfBroadcasterId; i++) { 22 | BroadcasterId broadcasterId; 23 | if (!broadcasterId.unpack(nstream)) { 24 | return false; 25 | } 26 | broadcasterIds.push_back(broadcasterId); 27 | } 28 | 29 | for (int i = 0; i < numOfAffiliationId; i++) { 30 | affiliationIds.push_back(nstream.get8U()); 31 | } 32 | 33 | for (int i = 0; i < numOfOriginalNetworkId; i++) { 34 | originalNetworkIds.push_back(nstream.getBe16U()); 35 | } 36 | 37 | stream.skip(descriptorLength); 38 | } 39 | catch (const std::out_of_range&) { 40 | return false; 41 | } 42 | 43 | return true; 44 | } 45 | 46 | bool RelatedBroadcasterDescriptor::BroadcasterId::unpack(Common::ReadStream & stream) 47 | { 48 | try { 49 | networkId = stream.getBe16U(); 50 | broadcasterId = stream.get8U(); 51 | } 52 | catch (const std::out_of_range&) { 53 | return false; 54 | } 55 | 56 | return true; 57 | } 58 | 59 | } -------------------------------------------------------------------------------- /src/relatedBroadcasterDescriptor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "mmtDescriptorBase.h" 3 | #include 4 | 5 | namespace MmtTlv { 6 | 7 | class RelatedBroadcasterDescriptor 8 | : public MmtDescriptorTemplate<0x803E> { 9 | public: 10 | bool unpack(Common::ReadStream& stream) override; 11 | 12 | class BroadcasterId { 13 | public: 14 | bool unpack(Common::ReadStream& stream); 15 | 16 | uint16_t networkId; 17 | uint8_t broadcasterId; 18 | }; 19 | 20 | uint8_t numOfBroadcasterId; 21 | uint8_t numOfAffiliationId; 22 | uint8_t numOfOriginalNetworkId; 23 | 24 | std::list broadcasterIds; 25 | std::list affiliationIds; 26 | std::list originalNetworkIds; 27 | 28 | }; 29 | 30 | } -------------------------------------------------------------------------------- /src/remoteControlKeyDescriptor.cpp: -------------------------------------------------------------------------------- 1 | #include "remoteControlKeyDescriptor.h" 2 | 3 | namespace MmtTlv { 4 | 5 | bool RemoteControlKeyDescriptor::unpack(Common::ReadStream& stream) 6 | { 7 | try { 8 | if (!TlvDescriptorTemplate::unpack(stream)) { 9 | return false; 10 | } 11 | 12 | numOfRemoteControlKeyId = stream.get8U(); 13 | for (int i = 0; i < numOfRemoteControlKeyId; i++) { 14 | Entry item; 15 | if (!item.unpack(stream)) { 16 | return false; 17 | } 18 | entries.push_back(item); 19 | } 20 | } 21 | catch (const std::out_of_range&) { 22 | return false; 23 | } 24 | 25 | return true; 26 | } 27 | 28 | bool RemoteControlKeyDescriptor::Entry::unpack(Common::ReadStream& stream) 29 | { 30 | remoteControlKeyId = stream.get8U(); 31 | serviceId = stream.getBe16U(); 32 | return true; 33 | } 34 | 35 | } -------------------------------------------------------------------------------- /src/remoteControlKeyDescriptor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "tlvDescriptorBase.h" 3 | #include 4 | 5 | namespace MmtTlv { 6 | 7 | class RemoteControlKeyDescriptor : public TlvDescriptorTemplate<0xCD> { 8 | public: 9 | bool unpack(Common::ReadStream& stream); 10 | 11 | class Entry { 12 | public: 13 | bool unpack(Common::ReadStream& stream); 14 | uint8_t remoteControlKeyId; 15 | uint16_t serviceId; 16 | 17 | }; 18 | 19 | uint8_t numOfRemoteControlKeyId; 20 | std::list entries; 21 | }; 22 | 23 | } -------------------------------------------------------------------------------- /src/remuxerHandler.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "demuxerHandler.h" 4 | #include "b24SubtitleConvertor.h" 5 | #include 6 | 7 | namespace StreamType { 8 | 9 | constexpr uint8_t VIDEO_MPEG1 = 0x01; 10 | constexpr uint8_t VIDEO_MPEG2 = 0x02; 11 | constexpr uint8_t AUDIO_MPEG1 = 0x03; 12 | constexpr uint8_t AUDIO_MPEG2 = 0x04; 13 | constexpr uint8_t PRIVATE_SECTION = 0x05; 14 | constexpr uint8_t PRIVATE_DATA = 0x06; 15 | constexpr uint8_t ISO_IEC_13818_6_TYPE_D = 0x0d; 16 | constexpr uint8_t AUDIO_AAC = 0x0f; 17 | constexpr uint8_t AUDIO_AAC_LATM = 0x11; 18 | constexpr uint8_t VIDEO_MPEG4 = 0x10; 19 | constexpr uint8_t METADATA = 0x15; 20 | constexpr uint8_t VIDEO_H264 = 0x1b; 21 | constexpr uint8_t VIDEO_HEVC = 0x24; 22 | 23 | } 24 | 25 | namespace MmtTlv { 26 | 27 | class Plt; 28 | class Mpt; 29 | class MhBit; 30 | class MhAit; 31 | class MhCdt; 32 | class MhEit; 33 | class MhSdt; 34 | class MhTot; 35 | class Nit; 36 | class MmtStream; 37 | class MmtTlvDemuxer; 38 | class NTPv4; 39 | 40 | } 41 | 42 | constexpr uint16_t PCR_PID = 0x01FF; 43 | 44 | class RemuxerHandler : public MmtTlv::DemuxerHandler { 45 | public: 46 | RemuxerHandler(MmtTlv::MmtTlvDemuxer& demuxer, std::vector& output) 47 | : demuxer(demuxer), output(output) { 48 | } 49 | 50 | // MPU data 51 | void onVideoData(const std::shared_ptr mmtStream, const std::shared_ptr& mfuData) override; 52 | void onAudioData(const std::shared_ptr mmtStream, const std::shared_ptr& mfuData) override; 53 | void onSubtitleData(const std::shared_ptr mmtStream, const std::shared_ptr& mfuData) override; 54 | void onApplicationData(const std::shared_ptr mmtStream, const std::shared_ptr& mfuData) override; 55 | 56 | // MMT message 57 | void onMhBit(const std::shared_ptr& mhCdt) override; 58 | void onMhAit(const std::shared_ptr& mhBit) override; 59 | void onEcm(const std::shared_ptr& ecm) override {} 60 | void onMhCdt(const std::shared_ptr& mhCdt) override; 61 | void onMhEit(const std::shared_ptr& mhEit) override; 62 | void onMhSdtActual(const std::shared_ptr& mhSdt) override; 63 | void onMhTot(const std::shared_ptr& mhTot) override; 64 | void onMpt(const std::shared_ptr& mpt) override; 65 | void onPlt(const std::shared_ptr& plt) override; 66 | 67 | // TLV message 68 | void onNit(const std::shared_ptr& nit) override; 69 | 70 | // IPv6 71 | void onNtp(const std::shared_ptr& ntp) override; 72 | 73 | void clear(); 74 | 75 | private: 76 | void writeStream(const std::shared_ptr mmtStream, const std::shared_ptr& mfuData, const std::vector& data); 77 | void writeSubtitle(const std::shared_ptr mmtStream, const B24SubtiteOutput& subtitle); 78 | 79 | MmtTlv::MmtTlvDemuxer& demuxer; 80 | std::vector& output; 81 | std::unordered_map mapService2Pid; 82 | std::unordered_map mapCC; 83 | int tsid{-1}; 84 | int streamCount{}; 85 | 86 | uint64_t eitPresentStartTime{}; 87 | uint64_t lastPcr{}; 88 | 89 | ts::DuckContext duck; 90 | }; -------------------------------------------------------------------------------- /src/serviceListDescriptor.cpp: -------------------------------------------------------------------------------- 1 | #include "serviceListDescriptor.h" 2 | 3 | namespace MmtTlv { 4 | 5 | bool ServiceListDescriptor::unpack(Common::ReadStream& stream) 6 | { 7 | try { 8 | if (!TlvDescriptorTemplate::unpack(stream)) { 9 | return false; 10 | } 11 | 12 | Common::ReadStream nstream(stream, descriptorLength); 13 | while (!nstream.isEof()) { 14 | Entry item; 15 | if (!item.unpack(nstream)) { 16 | return false; 17 | } 18 | services.push_back(item); 19 | } 20 | stream.skip(descriptorLength); 21 | } 22 | catch (const std::out_of_range&) { 23 | return false; 24 | } 25 | 26 | return true; 27 | } 28 | 29 | bool ServiceListDescriptor::Entry::unpack(Common::ReadStream& stream) 30 | { 31 | serviceId = stream.getBe16U(); 32 | serviceType = stream.get8U(); 33 | return true; 34 | } 35 | 36 | } -------------------------------------------------------------------------------- /src/serviceListDescriptor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "tlvDescriptorBase.h" 3 | #include 4 | 5 | namespace MmtTlv { 6 | 7 | class ServiceListDescriptor : public TlvDescriptorTemplate<0x41> { 8 | public: 9 | bool unpack(Common::ReadStream& stream); 10 | 11 | class Entry { 12 | public: 13 | bool unpack(Common::ReadStream& stream); 14 | uint16_t serviceId; 15 | uint8_t serviceType; 16 | }; 17 | 18 | std::list services; 19 | }; 20 | 21 | } -------------------------------------------------------------------------------- /src/signalingMessage.cpp: -------------------------------------------------------------------------------- 1 | #include "signalingMessage.h" 2 | 3 | namespace MmtTlv { 4 | 5 | bool SignalingMessage::unpack(Common::ReadStream& stream) 6 | { 7 | try { 8 | uint8_t uint8 = stream.get8U(); 9 | fragmentationIndicator = static_cast((uint8 & 0b11000000) >> 6); 10 | reserved = (uint8 & 0b00111100) >> 2; 11 | lengthExtensionFlag = (uint8 & 0x00000010) >> 2; 12 | aggregationFlag = uint8 & 1; 13 | 14 | fragmentCounter = stream.get8U(); 15 | 16 | payload.resize(stream.leftBytes()); 17 | stream.read(payload.data(), stream.leftBytes()); 18 | } 19 | catch (const std::out_of_range&) { 20 | return false; 21 | } 22 | 23 | return true; 24 | } 25 | 26 | } -------------------------------------------------------------------------------- /src/signalingMessage.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "stream.h" 4 | #include "mmtFragment.h" 5 | 6 | namespace MmtTlv { 7 | 8 | class SignalingMessage { 9 | public: 10 | bool unpack(Common::ReadStream& stream); 11 | 12 | FragmentationIndicator fragmentationIndicator; 13 | uint8_t reserved; 14 | bool lengthExtensionFlag; 15 | bool aggregationFlag; 16 | uint8_t fragmentCounter; 17 | 18 | std::vector payload; 19 | }; 20 | 21 | } -------------------------------------------------------------------------------- /src/smartcard.cpp: -------------------------------------------------------------------------------- 1 | #include "smartcard.h" 2 | 3 | namespace MmtTlv::Acas { 4 | 5 | bool SmartCard::init() { 6 | LONG result = SCardEstablishContext(SCARD_SCOPE_USER, nullptr, nullptr, &hContext); 7 | return result == SCARD_S_SUCCESS; 8 | } 9 | 10 | bool SmartCard::isConnected() const 11 | { 12 | if (hCard) { 13 | return true; 14 | } 15 | 16 | return false; 17 | } 18 | 19 | void SmartCard::connect() { 20 | LONG result; 21 | DWORD readersSize = SCARD_AUTOALLOCATE; 22 | std::string readerName; 23 | disconnect(); 24 | 25 | if(smartCardReaderName == "") { 26 | char* readers = nullptr; 27 | result = SCardListReaders(hContext, nullptr, (LPSTR)&readers, &readersSize); 28 | if (result != SCARD_S_SUCCESS) { 29 | throw std::runtime_error("Failed to list smart card readers. (result: " + std::to_string(result) + ")"); 30 | } 31 | 32 | readerName = readers; 33 | SCardFreeMemory(hContext, readers); 34 | } 35 | else { 36 | readerName = smartCardReaderName; 37 | } 38 | 39 | 40 | result = SCardConnect(hContext, readerName.c_str(), SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &hCard, &dwActiveProtocol); 41 | if (result != SCARD_S_SUCCESS) { 42 | throw std::runtime_error("Failed to connect to smart card. (result: " + std::to_string(result) + ")"); 43 | } 44 | } 45 | 46 | ApduResponse SmartCard::transmit(const std::vector& sendData) { 47 | DWORD recvLength = 256; 48 | std::vector recvBuffer(recvLength); 49 | int retryCount = 0; 50 | 51 | LONG result = SCardTransmit(hCard, SCARD_PCI_T1, sendData.data(), static_cast(sendData.size()), nullptr, recvBuffer.data(), &recvLength); 52 | while (result != SCARD_S_SUCCESS && retryCount < 10) { 53 | retryCount++; 54 | try { 55 | connect(); 56 | } 57 | catch (const std::runtime_error& e) { 58 | std::cerr << e.what() << std::endl; 59 | continue; 60 | } 61 | 62 | result = SCardTransmit(hCard, SCARD_PCI_T1, sendData.data(), static_cast(sendData.size()), nullptr, recvBuffer.data(), &recvLength); 63 | } 64 | 65 | if (result != SCARD_S_SUCCESS) { 66 | throw std::runtime_error("Failed to transmit data to smart card. (result: " + std::to_string(result) + ")"); 67 | } 68 | 69 | uint8_t sw1 = recvBuffer[recvLength - 2]; 70 | uint8_t sw2 = recvBuffer[recvLength - 1]; 71 | 72 | std::vector data(recvBuffer.begin(), recvBuffer.begin() + recvLength - 2); 73 | return ApduResponse(sw1, sw2, data); 74 | } 75 | 76 | void SmartCard::disconnect() { 77 | if (hCard != 0) { 78 | SCardDisconnect(hCard, SCARD_LEAVE_CARD); 79 | hCard = 0; 80 | } 81 | } 82 | 83 | void SmartCard::release() 84 | { 85 | disconnect(); 86 | 87 | if (hContext != 0) { 88 | SCardReleaseContext(hContext); 89 | hContext = 0; 90 | } 91 | } 92 | 93 | } -------------------------------------------------------------------------------- /src/smartcard.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #ifdef _WIN32 7 | #define _WINSOCKAPI_ 8 | #include 9 | #endif 10 | #include 11 | 12 | namespace MmtTlv::Acas { 13 | 14 | class ApduResponse { 15 | public: 16 | ApduResponse(uint8_t sw1, uint8_t sw2, const std::vector& data = {}) 17 | : sw1(sw1), sw2(sw2), data(data) {} 18 | 19 | uint8_t getSw1() const { 20 | return sw1; 21 | } 22 | 23 | uint8_t getSw2() const { 24 | return sw2; 25 | } 26 | 27 | const std::vector& getData() const { 28 | return data; 29 | } 30 | 31 | bool isSuccess() const { 32 | return sw1 == 0x90 && sw2 == 0x00; 33 | } 34 | 35 | private: 36 | uint8_t sw1; 37 | uint8_t sw2; 38 | std::vector data; 39 | }; 40 | 41 | class ApduCommand { 42 | public: 43 | ApduCommand(uint8_t cla, uint8_t ins, uint8_t p1, uint8_t p2) 44 | : cla(cla), ins(ins), p1(p1), p2(p2) {} 45 | 46 | std::vector case1() { 47 | return { cla, ins, p1, p2 }; 48 | } 49 | 50 | std::vector case2short(uint8_t le) { 51 | return { cla, ins, p1, p2, le }; 52 | } 53 | 54 | std::vector case3short(const std::vector& data) { 55 | std::vector apdu = { cla, ins, p1, p2, static_cast(data.size()) }; 56 | apdu.insert(apdu.end(), data.begin(), data.end()); 57 | return apdu; 58 | } 59 | 60 | std::vector case4short(const std::vector& data, uint8_t le) { 61 | std::vector apdu = { cla, ins, p1, p2, static_cast(data.size()) }; 62 | apdu.insert(apdu.end(), data.begin(), data.end()); 63 | apdu.push_back(le); 64 | return apdu; 65 | } 66 | 67 | private: 68 | uint8_t cla; 69 | uint8_t ins; 70 | uint8_t p1; 71 | uint8_t p2; 72 | }; 73 | 74 | class SmartCard { 75 | public: 76 | void setSmartCardReaderName(const std::string& smartCardReaderName) { 77 | this->smartCardReaderName = smartCardReaderName; 78 | } 79 | bool init(); 80 | bool isConnected() const; 81 | void connect(); 82 | ApduResponse transmit(const std::vector& sendData); 83 | void disconnect(); 84 | void release(); 85 | 86 | private: 87 | SCARDCONTEXT hContext = 0; 88 | SCARDHANDLE hCard = 0; 89 | DWORD dwActiveProtocol = 0; 90 | std::string smartCardReaderName; 91 | }; 92 | 93 | } -------------------------------------------------------------------------------- /src/stream.cpp: -------------------------------------------------------------------------------- 1 | #include "stream.h" 2 | 3 | namespace MmtTlv { 4 | 5 | namespace Common { 6 | 7 | ReadStream::ReadStream(const std::vector& buffer) 8 | : buffer(buffer) 9 | { 10 | this->hasSize = true; 11 | this->size = buffer.size(); 12 | } 13 | 14 | ReadStream::ReadStream(const std::vector& buffer, uint32_t size) 15 | : buffer(buffer) 16 | { 17 | if (buffer.size() < size) { 18 | throw std::out_of_range("Access out of bounds"); 19 | } 20 | 21 | this->hasSize = true; 22 | this->size = size; 23 | } 24 | 25 | ReadStream::ReadStream(ReadStream& stream, uint32_t size) 26 | : buffer(stream.buffer) 27 | { 28 | if (stream.buffer.size() < stream.cur + size) { 29 | throw std::out_of_range("Access out of bounds"); 30 | } 31 | 32 | this->cur = stream.cur; 33 | this->hasSize = true; 34 | this->size = stream.cur + size; 35 | } 36 | 37 | ReadStream::ReadStream(ReadStream& stream) 38 | : buffer(stream.buffer) 39 | { 40 | this->hasSize = stream.hasSize; 41 | this->size = stream.size; 42 | this->cur = stream.cur; 43 | } 44 | 45 | } 46 | 47 | } -------------------------------------------------------------------------------- /src/subtitleMfuDataProcessor.cpp: -------------------------------------------------------------------------------- 1 | #include "subtitleMfuDataProcessor.h" 2 | 3 | namespace MmtTlv { 4 | 5 | std::optional SubtitleMfuDataProcessor::process(const std::shared_ptr& mmtStream, const std::vector& data) 6 | { 7 | Common::ReadStream stream(data); 8 | 9 | uint16_t subsampleNumber = stream.getBe16U(); 10 | uint16_t lastSubsampleNumber = stream.getBe16U(); 11 | 12 | uint8_t uint8 = stream.get8U(); 13 | uint8_t dataType = uint8 >> 4; 14 | uint8_t lengthExtFlag = (uint8 >> 3) & 1; 15 | uint8_t subsampleInfoListFlag = (uint8 >> 2) & 1; 16 | 17 | if (dataType != 0) { 18 | return std::nullopt; 19 | } 20 | 21 | uint32_t dataSize; 22 | if (lengthExtFlag) 23 | dataSize = stream.getBe32U(); 24 | else 25 | dataSize = stream.getBe16U(); 26 | 27 | if (subsampleNumber == 0 && lastSubsampleNumber > 0 && subsampleInfoListFlag) { 28 | for (int i = 0; i < lastSubsampleNumber; ++i) { 29 | stream.skip(4 + 4); // subsample_i_data_type 30 | 31 | if (lengthExtFlag) { 32 | stream.skip(4); // subsample_i_data_size 33 | } 34 | else { 35 | stream.skip(2); // subsample_i_data_size 36 | } 37 | } 38 | } 39 | 40 | if (stream.leftBytes() < dataSize) { 41 | return std::nullopt; 42 | } 43 | 44 | MfuData mfuData; 45 | mfuData.data.resize(dataSize); 46 | stream.read(mfuData.data.data(), dataSize); 47 | 48 | mfuData.streamIndex = mmtStream->getStreamIndex(); 49 | 50 | return mfuData; 51 | } 52 | 53 | } -------------------------------------------------------------------------------- /src/subtitleMfuDataProcessor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "mfuDataProcessorBase.h" 3 | 4 | namespace MmtTlv { 5 | 6 | class SubtitleMfuDataProcessor : public MfuDataProcessorTemplate { 7 | public: 8 | std::optional process(const std::shared_ptr& mmtStream, const std::vector& data); 9 | 10 | private: 11 | std::vector pendingData; 12 | }; 13 | 14 | } -------------------------------------------------------------------------------- /src/swap.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace MmtTlv { 5 | 6 | namespace Common { 7 | 8 | inline uint16_t swapEndian16(uint16_t num) { 9 | return (num >> 8) | (num << 8); 10 | } 11 | 12 | inline uint32_t swapEndian32(uint32_t num) { 13 | return ((num >> 24) & 0x000000FF) | 14 | ((num >> 8) & 0x0000FF00) | 15 | ((num << 8) & 0x00FF0000) | 16 | ((num << 24) & 0xFF000000); 17 | } 18 | 19 | inline uint64_t swapEndian64(uint64_t num) { 20 | return ((num >> 56) & 0x00000000000000FFULL) | 21 | ((num >> 40) & 0x000000000000FF00ULL) | 22 | ((num >> 24) & 0x0000000000FF0000ULL) | 23 | ((num >> 8) & 0x00000000FF000000ULL) | 24 | ((num << 8) & 0x000000FF00000000ULL) | 25 | ((num << 24) & 0x0000FF0000000000ULL) | 26 | ((num << 40) & 0x00FF000000000000ULL) | 27 | ((num << 56) & 0xFF00000000000000ULL); 28 | } 29 | } 30 | 31 | } -------------------------------------------------------------------------------- /src/systemManagementDescriptor.cpp: -------------------------------------------------------------------------------- 1 | #include "systemManagementDescriptor.h" 2 | 3 | namespace MmtTlv { 4 | 5 | bool SystemManagementDescriptor::unpack(Common::ReadStream& stream) 6 | { 7 | try { 8 | if (!TlvDescriptorTemplate::unpack(stream)) { 9 | return false; 10 | } 11 | 12 | Common::ReadStream nstream(stream, descriptorLength); 13 | 14 | systemManagementId = nstream.getBe16U(); 15 | 16 | additionalIdentificationInfo.resize(nstream.leftBytes()); 17 | nstream.read(additionalIdentificationInfo.data(), nstream.leftBytes()); 18 | 19 | stream.skip(descriptorLength); 20 | } 21 | catch (const std::out_of_range&) { 22 | return false; 23 | } 24 | 25 | return true; 26 | } 27 | 28 | 29 | } -------------------------------------------------------------------------------- /src/systemManagementDescriptor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "tlvDescriptorBase.h" 3 | #include 4 | 5 | namespace MmtTlv { 6 | 7 | class SystemManagementDescriptor : public TlvDescriptorTemplate<0xFE> { 8 | public: 9 | bool unpack(Common::ReadStream& stream); 10 | 11 | uint16_t systemManagementId; 12 | std::vector additionalIdentificationInfo; 13 | }; 14 | 15 | } -------------------------------------------------------------------------------- /src/timeUtil.cpp: -------------------------------------------------------------------------------- 1 | #include "timeUtil.h" 2 | #include 3 | #include 4 | 5 | namespace { 6 | 7 | constexpr int BASE_YEAR = 1900; 8 | constexpr int MJD_OFFSET = 15078; 9 | constexpr int MJD_OFFSET_2 = 14956; 10 | constexpr uint64_t UNKNOWN_START_TIME = UINT64_C(0xffffffffff); 11 | 12 | inline int convertFromBcd(uint64_t value) { 13 | return ((value >> 4) & 0xf) * 10 + (value & 0xf); 14 | } 15 | 16 | } 17 | 18 | void EITDecodeMjd(int i_mjd, int* p_y, int* p_m, int* p_d) { 19 | const int yp = static_cast((static_cast(i_mjd) - MJD_OFFSET) / 365.25); 20 | const int mp = static_cast((static_cast(i_mjd) - MJD_OFFSET_2 - static_cast(yp * 365.25)) / 30.6001); 21 | const int c = (mp == 14 || mp == 15) ? 1 : 0; 22 | 23 | *p_y = BASE_YEAR + yp + c; 24 | *p_m = mp - 1 - c * 12; 25 | *p_d = i_mjd - MJD_OFFSET_2 - static_cast(yp * 365.25) - static_cast(mp * 30.6001); 26 | } 27 | 28 | struct tm EITConvertStartTime(uint64_t i_date) { 29 | const int i_mjd = static_cast(i_date >> 24); 30 | struct tm tm = {}; 31 | 32 | tm.tm_hour = convertFromBcd(i_date >> 16); 33 | tm.tm_min = convertFromBcd(i_date >> 8); 34 | tm.tm_sec = convertFromBcd(i_date); 35 | 36 | // if all 40 bits are 1, the start is unknown 37 | if (i_date == UNKNOWN_START_TIME) { 38 | return {}; 39 | } 40 | 41 | EITDecodeMjd(i_mjd, &tm.tm_year, &tm.tm_mon, &tm.tm_mday); 42 | tm.tm_year -= BASE_YEAR; 43 | tm.tm_mon--; 44 | tm.tm_isdst = 0; 45 | 46 | return tm; 47 | } 48 | 49 | int EITConvertDuration(uint32_t i_duration) { 50 | return convertFromBcd(i_duration >> 16) * 3600 + 51 | convertFromBcd(i_duration >> 8) * 60 + 52 | convertFromBcd(i_duration); 53 | } -------------------------------------------------------------------------------- /src/timeUtil.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | void EITDecodeMjd(int i_mjd, int* p_y, int* p_m, int* p_d); 6 | struct tm EITConvertStartTime(uint64_t i_date); 7 | int EITConvertDuration(uint32_t i_duration); -------------------------------------------------------------------------------- /src/timebase.cpp: -------------------------------------------------------------------------------- 1 | #include "timebase.h" 2 | #include 3 | #include 4 | 5 | int64_t av_rescale_rnd(int64_t a, int64_t b, int64_t c, enum AVRounding rnd) { 6 | int64_t r = 0; 7 | 8 | if (a < 0 && a != INT64_MIN) return -av_rescale_rnd(-a, b, c, (enum AVRounding)(rnd ^ ((rnd >> 1) & 1))); 9 | 10 | if (rnd == AV_ROUND_NEAR_INF) r = c / 2; 11 | else if (rnd & 1) r = c - 1; 12 | 13 | if (b <= INT_MAX && c <= INT_MAX) { 14 | if (a <= INT_MAX) { 15 | if (c == 0) { 16 | return 0; 17 | } 18 | return (a * b + r) / c; 19 | } 20 | else { 21 | if (c == 0) { 22 | return 0; 23 | } 24 | if (c * b + r == 0) { 25 | return 0; 26 | } 27 | if (c * b + (a % c * b + r) == 0 ) { 28 | return 0; 29 | } 30 | return a / c * b + (a % c * b + r) / c; 31 | } 32 | } 33 | else { 34 | int64_t a0 = a & 0xFFFFFFFF; 35 | int64_t a1 = a >> 32; 36 | int64_t b0 = b & 0xFFFFFFFF; 37 | int64_t b1 = b >> 32; 38 | int64_t t1 = a0 * b1 + a1 * b0; 39 | int64_t t1a = t1 << 32; 40 | int i; 41 | 42 | a0 = a0 * b0 + t1a; 43 | a1 = a1 * b1 + (t1 >> 32) + (a0 < t1a); 44 | a0 += r; 45 | a1 += a0 < r; 46 | 47 | for (i = 63; i >= 0; i--) { 48 | a1 += a1 + ((a0 >> i) & 1); 49 | t1 += t1; 50 | if (c <= a1) { 51 | a1 -= c; 52 | t1++; 53 | } 54 | } 55 | return t1; 56 | } 57 | } 58 | 59 | int64_t av_rescale(int64_t a, int64_t b, int64_t c) { 60 | return av_rescale_rnd(a, b, c, AV_ROUND_NEAR_INF); 61 | } 62 | 63 | int64_t av_rescale_q_rnd(int64_t a, AVRational bq, AVRational cq, 64 | enum AVRounding rnd) 65 | { 66 | int64_t b = bq.num * (int64_t)cq.den; 67 | int64_t c = cq.num * (int64_t)bq.den; 68 | return av_rescale_rnd(a, b, c, rnd); 69 | } 70 | 71 | int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq) 72 | { 73 | return av_rescale_q_rnd(a, bq, cq, AV_ROUND_NEAR_INF); 74 | } 75 | -------------------------------------------------------------------------------- /src/timebase.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | typedef struct AVRational{ 5 | int num{1}; 6 | int den{1}; 7 | } AVRational; 8 | 9 | enum AVRounding { 10 | AV_ROUND_ZERO = 0, 11 | AV_ROUND_INF = 1, 12 | AV_ROUND_DOWN = 2, 13 | AV_ROUND_UP = 3, 14 | AV_ROUND_NEAR_INF = 5, 15 | }; 16 | 17 | int64_t av_rescale_rnd(int64_t a, int64_t b, int64_t c, enum AVRounding rnd); 18 | 19 | int64_t av_rescale(int64_t a, int64_t b, int64_t c); 20 | 21 | int64_t av_rescale_q_rnd(int64_t a, AVRational bq, AVRational cq, enum AVRounding rnd); 22 | 23 | int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq); -------------------------------------------------------------------------------- /src/tlv.cpp: -------------------------------------------------------------------------------- 1 | #include "tlv.h" 2 | #include "stream.h" 3 | #include "mmtTlvDemuxer.h" 4 | 5 | namespace MmtTlv { 6 | 7 | bool Tlv::unpack(Common::ReadStream& stream) 8 | { 9 | if (stream.leftBytes() < 4) { 10 | return false; 11 | } 12 | 13 | uint8_t syncByte = stream.get8U(); 14 | if (syncByte != 0x7F) { 15 | throw std::runtime_error("not valid tlv packet."); 16 | } 17 | 18 | packetType = stream.get8U(); 19 | dataLength = stream.getBe16U(); 20 | 21 | if (stream.leftBytes() < dataLength) { 22 | return false; 23 | } 24 | 25 | data.resize(dataLength); 26 | stream.read(data.data(), dataLength); 27 | return true; 28 | } 29 | 30 | } -------------------------------------------------------------------------------- /src/tlv.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "ip.h" 4 | #include "stream.h" 5 | #include "compressedIPPacket.h" 6 | 7 | namespace MmtTlv { 8 | 9 | enum class TlvPacketType { 10 | Undefined = 0x0, 11 | Ipv4Packet = 0x01, 12 | Ipv6Packet = 0x02, 13 | HeaderCompressedIpPacket = 0x03, 14 | TransmissionControlSignalPacket = 0xFE, 15 | NullPacket = 0xFF 16 | }; 17 | 18 | class Tlv { 19 | public: 20 | bool unpack(Common::ReadStream& stream); 21 | 22 | TlvPacketType getPacketType() const { return static_cast(packetType); } 23 | uint16_t getDataLength() const { return dataLength; } 24 | const CompressedIPPacket& getCompressedIPPacket() const { return compressedIPPacket; } 25 | const std::vector& getData() const { return data; } 26 | 27 | private: 28 | uint8_t packetType; 29 | uint16_t dataLength; 30 | CompressedIPPacket compressedIPPacket; 31 | std::vector data; 32 | }; 33 | 34 | } -------------------------------------------------------------------------------- /src/tlvDescriptorBase.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "stream.h" 3 | 4 | namespace MmtTlv { 5 | 6 | class TlvDescriptorBase { 7 | public: 8 | virtual ~TlvDescriptorBase() = default; 9 | 10 | virtual bool unpack(Common::ReadStream& stream) { 11 | try { 12 | descriptorTag = stream.get8U(); 13 | descriptorLength = stream.get8U(); 14 | 15 | if (stream.leftBytes() < descriptorLength) { 16 | return false; 17 | } 18 | } 19 | catch (const std::out_of_range&) { 20 | return false; 21 | } 22 | 23 | return true; 24 | } 25 | 26 | uint8_t getDescriptorTag() const { return descriptorTag; }; 27 | uint8_t getDescriptorLength() const { return descriptorLength; }; 28 | 29 | protected: 30 | uint8_t descriptorTag; 31 | uint8_t descriptorLength; 32 | }; 33 | 34 | template 35 | class TlvDescriptorTemplate : public TlvDescriptorBase { 36 | public: 37 | virtual ~TlvDescriptorTemplate() = default; 38 | 39 | static constexpr uint8_t kDescriptorTag = descriptorTagValue; 40 | 41 | }; 42 | 43 | } -------------------------------------------------------------------------------- /src/tlvDescriptorFactory.cpp: -------------------------------------------------------------------------------- 1 | #include "tlvDescriptorFactory.h" 2 | #include "serviceListDescriptor.h" 3 | #include "remoteControlKeyDescriptor.h" 4 | #include "networkNameDescriptor.h" 5 | #include "systemManagementDescriptor.h" 6 | #include 7 | #include 8 | #include 9 | 10 | namespace MmtTlv { 11 | 12 | static const std::unordered_map()>> mapTlvDescriptor = { 13 | { ServiceListDescriptor::kDescriptorTag, [] { return std::make_shared(); } }, 14 | { RemoteControlKeyDescriptor::kDescriptorTag, [] { return std::make_shared(); } }, 15 | { NetworkNameDescriptor::kDescriptorTag, [] { return std::make_shared(); } }, 16 | { SystemManagementDescriptor::kDescriptorTag, [] { return std::make_shared(); } }, 17 | }; 18 | 19 | std::shared_ptr TlvDescriptorFactory::create(uint8_t tag) { 20 | auto it = mapTlvDescriptor.find(tag); 21 | if (it == mapTlvDescriptor.end()) { 22 | return {}; 23 | } 24 | 25 | return it->second(); 26 | } 27 | 28 | bool TlvDescriptorFactory::isValidTag(uint8_t tag) 29 | { 30 | auto it = mapTlvDescriptor.find(tag); 31 | if (it == mapTlvDescriptor.end()) { 32 | return false; 33 | } 34 | 35 | return true; 36 | } 37 | 38 | } -------------------------------------------------------------------------------- /src/tlvDescriptorFactory.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "tlvDescriptorBase.h" 3 | #include 4 | 5 | namespace MmtTlv { 6 | 7 | class TlvDescriptorFactory { 8 | public: 9 | static std::shared_ptr create(uint8_t tag); 10 | static bool isValidTag(uint8_t tag); 11 | 12 | }; 13 | 14 | } -------------------------------------------------------------------------------- /src/tlvDescriptors.cpp: -------------------------------------------------------------------------------- 1 | #include "tlvDescriptors.h" 2 | #include "tlvDescriptorFactory.h" 3 | 4 | namespace MmtTlv { 5 | 6 | bool TlvDescriptors::unpack(Common::ReadStream& stream) 7 | { 8 | list.clear(); 9 | while (!stream.isEof()) { 10 | uint8_t descriptorTag = stream.peek8U(); 11 | auto it = TlvDescriptorFactory::create(descriptorTag); 12 | if (it == nullptr) { 13 | TlvDescriptorBase base; 14 | if (!base.unpack(stream)) { 15 | return false; 16 | } 17 | stream.skip(base.getDescriptorLength()); 18 | } 19 | else { 20 | if (!it->unpack(stream)) { 21 | return false; 22 | } 23 | list.push_back(std::move(it)); 24 | } 25 | } 26 | return true; 27 | } 28 | 29 | 30 | } -------------------------------------------------------------------------------- /src/tlvDescriptors.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "tlvDescriptorBase.h" 3 | #include 4 | #include 5 | 6 | namespace MmtTlv { 7 | 8 | class TlvDescriptors { 9 | public: 10 | bool unpack(Common::ReadStream& stream); 11 | 12 | std::list> list; 13 | 14 | }; 15 | 16 | } -------------------------------------------------------------------------------- /src/tlvTableBase.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "stream.h" 3 | 4 | namespace MmtTlv { 5 | 6 | class TlvTableId { 7 | public: 8 | static constexpr uint8_t Nit = 0x40; 9 | }; 10 | 11 | class TlvTableBase { 12 | public: 13 | virtual ~TlvTableBase() = default; 14 | 15 | virtual bool unpack(Common::ReadStream& stream) 16 | { 17 | try { 18 | tableId = stream.get8U(); 19 | } 20 | catch (const std::out_of_range&) { 21 | return false; 22 | } 23 | 24 | return true; 25 | } 26 | 27 | uint8_t getTableId() const { return tableId; } 28 | 29 | protected: 30 | uint8_t tableId; 31 | 32 | }; 33 | 34 | } -------------------------------------------------------------------------------- /src/tlvTableFactory.cpp: -------------------------------------------------------------------------------- 1 | #include "tlvTableFactory.h" 2 | #include "nit.h" 3 | #include 4 | #include 5 | 6 | namespace MmtTlv { 7 | 8 | static const std::unordered_map()>> mapTlvTableFactory = { 9 | { TlvTableId::Nit, [] { return std::make_shared(); } }, 10 | }; 11 | 12 | std::shared_ptr TlvTableFactory::create(uint8_t id) { 13 | auto it = mapTlvTableFactory.find(id); 14 | if (it == mapTlvTableFactory.end()) { 15 | return {}; 16 | } 17 | 18 | return it->second(); 19 | } 20 | 21 | bool TlvTableFactory::isValidId(uint8_t id) 22 | { 23 | auto it = mapTlvTableFactory.find(id); 24 | if (it == mapTlvTableFactory.end()) { 25 | return false; 26 | } 27 | 28 | return true; 29 | } 30 | 31 | } -------------------------------------------------------------------------------- /src/tlvTableFactory.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace MmtTlv { 5 | class TlvTableBase; 6 | class TlvTableFactory { 7 | public: 8 | static std::shared_ptr create(uint8_t id); 9 | static bool isValidId(uint8_t id); 10 | 11 | }; 12 | 13 | } -------------------------------------------------------------------------------- /src/transmissionControlSignal.cpp: -------------------------------------------------------------------------------- 1 | #include "transmissionControlSignal.h" 2 | 3 | namespace MmtTlv { 4 | 5 | bool TransmissionControlSignal::unpack(Common::ReadStream& stream) 6 | { 7 | try { 8 | tableId = stream.get8U(); 9 | } 10 | catch (const std::out_of_range&) { 11 | return false; 12 | } 13 | 14 | return true; 15 | } 16 | 17 | } -------------------------------------------------------------------------------- /src/transmissionControlSignal.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "stream.h" 3 | 4 | namespace MmtTlv { 5 | 6 | class TransmissionControlSignal 7 | { 8 | public: 9 | bool unpack(Common::ReadStream& stream); 10 | 11 | public: 12 | uint8_t tableId; 13 | uint16_t sectionSyntaxIndicator; 14 | uint16_t sectionLength; 15 | uint16_t tableIdExtension; 16 | bool currentNextIndicator; 17 | uint8_t sectionNumber; 18 | uint8_t lastSectionNumber; 19 | }; 20 | } -------------------------------------------------------------------------------- /src/videoComponentDescriptor.cpp: -------------------------------------------------------------------------------- 1 | #include "videoComponentDescriptor.h" 2 | 3 | namespace MmtTlv { 4 | 5 | bool VideoComponentDescriptor::unpack(Common::ReadStream& stream) 6 | { 7 | try { 8 | if (!MmtDescriptorTemplate::unpack(stream)) { 9 | return false; 10 | } 11 | 12 | Common::ReadStream nstream(stream, descriptorLength); 13 | 14 | uint8_t uint8 = nstream.get8U(); 15 | videoResolution = (uint8 & 0b11110000) >> 4; 16 | videoAspectRatio = uint8 & 0b0001111; 17 | 18 | uint8 = nstream.get8U(); 19 | videoScanFlag = (uint8 & 0b10000000) >> 7; 20 | videoFrameRate = uint8 & 0b00011111; 21 | componentTag = nstream.getBe16U(); 22 | 23 | uint8 = nstream.get8U(); 24 | videoTransferCharacteristics = (uint8 & 0b11110000) >> 4; 25 | nstream.read(language, 3); 26 | language[3] = '\0'; 27 | 28 | size_t textLength = nstream.leftBytes(); 29 | if (textLength) { 30 | text.resize(textLength); 31 | nstream.read(text.data(), textLength); 32 | } 33 | 34 | stream.skip(descriptorLength); 35 | } 36 | catch (const std::out_of_range&) { 37 | return false; 38 | } 39 | 40 | return true; 41 | } 42 | 43 | } -------------------------------------------------------------------------------- /src/videoComponentDescriptor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "mmtDescriptorBase.h" 3 | 4 | namespace MmtTlv { 5 | 6 | class VideoComponentDescriptor 7 | : public MmtDescriptorTemplate<0x8010> { 8 | public: 9 | bool unpack(Common::ReadStream& stream) override; 10 | 11 | bool Is8KVideo() const { return videoResolution == 7; } 12 | 13 | uint8_t videoResolution; 14 | uint8_t videoAspectRatio; 15 | bool videoScanFlag; 16 | uint8_t videoFrameRate; 17 | uint16_t componentTag; 18 | uint8_t videoTransferCharacteristics; 19 | char language[4]; 20 | std::string text; 21 | 22 | 23 | }; 24 | 25 | } -------------------------------------------------------------------------------- /src/videoMfuDataProcessor.cpp: -------------------------------------------------------------------------------- 1 | #include "videoMfuDataProcessor.h" 2 | #include "stream.h" 3 | 4 | namespace MmtTlv { 5 | 6 | constexpr uint8_t CRA_NUT = 0x15; 7 | constexpr uint8_t NAL_AUD = 0x23; 8 | 9 | std::optional VideoMfuDataProcessor::process(const std::shared_ptr& mmtStream, const std::vector& data) 10 | { 11 | Common::ReadStream stream(data); 12 | if (stream.leftBytes() < 4) { 13 | return std::nullopt; 14 | } 15 | 16 | uint32_t size = stream.getBe32U(); 17 | if (size != stream.leftBytes()) { 18 | return std::nullopt; 19 | } 20 | 21 | uint8_t uint8 = stream.peek8U(); 22 | int forbiddenZeroBit = uint8 >> 7; 23 | if (forbiddenZeroBit != 0) { 24 | return std::nullopt; 25 | } 26 | 27 | int nalUnitType = ((uint8 >> 1) & 0b111111); 28 | 29 | appendPendingData(stream, size); 30 | 31 | if (nalUnitType < 0x20) { 32 | if (sliceSegmentCount >= (mmtStream->Is8KVideo() ? 3 : 0)) { 33 | std::pair ptsDts; 34 | try { 35 | ptsDts = mmtStream->getNextPtsDts(); 36 | } 37 | catch (const std::out_of_range&) { 38 | pendingData.clear(); 39 | return std::nullopt; 40 | } 41 | 42 | MfuData mfuData; 43 | mfuData.data = std::move(pendingData); 44 | mfuData.pts = ptsDts.first; 45 | mfuData.dts = ptsDts.second; 46 | mfuData.streamIndex = mmtStream->getStreamIndex(); 47 | 48 | if (nalUnitType == CRA_NUT) { 49 | mfuData.keyframe = true; 50 | } 51 | 52 | return mfuData; 53 | } 54 | sliceSegmentCount++; 55 | } 56 | 57 | if (nalUnitType == NAL_AUD){ 58 | sliceSegmentCount = 0; 59 | } 60 | 61 | return std::nullopt; 62 | } 63 | 64 | void VideoMfuDataProcessor::appendPendingData(Common::ReadStream& stream, int size) 65 | { 66 | uint32_t nalStartCode = 0x1000000; 67 | size_t oldSize = pendingData.size(); 68 | 69 | pendingData.resize(oldSize + 4 + size); 70 | 71 | memcpy(pendingData.data() + oldSize, &nalStartCode, 4); 72 | stream.read(pendingData.data() + oldSize + 4, size); 73 | } 74 | 75 | } -------------------------------------------------------------------------------- /src/videoMfuDataProcessor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "mfuDataProcessorBase.h" 3 | 4 | namespace MmtTlv { 5 | 6 | class VideoMfuDataProcessor : public MfuDataProcessorTemplate { 7 | public: 8 | std::optional process(const std::shared_ptr& mmtStream, const std::vector& data); 9 | 10 | private: 11 | void appendPendingData(Common::ReadStream& stream, int size); 12 | 13 | std::vector pendingData; 14 | int sliceSegmentCount = 0; 15 | 16 | }; 17 | 18 | } -------------------------------------------------------------------------------- /thirdparty/.gitignore: -------------------------------------------------------------------------------- 1 | ffmpeg/* 2 | !ffmpeg/.gitkeep 3 | openssl/* 4 | !openssl/.gitkeep 5 | tsduck/* 6 | !tsduck/.gitkeep -------------------------------------------------------------------------------- /thirdparty/openssl/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nekohkr/dantto4k/d30e8a67d596de4014819c682259511d2d3ce75a/thirdparty/openssl/.gitkeep -------------------------------------------------------------------------------- /thirdparty/tsduck/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nekohkr/dantto4k/d30e8a67d596de4014819c682259511d2d3ce75a/thirdparty/tsduck/.gitkeep --------------------------------------------------------------------------------