├── .gitignore ├── .gitmodules ├── LICENSE ├── README.md ├── doc ├── iso13818-1.pdf └── video_file_format_spec_v10.pdf └── mpegts ├── CMakeLists.txt └── mpegts ├── common.cpp ├── common.h ├── crc.cpp ├── crc.h ├── flv_muxer.cpp ├── flv_muxer.h ├── main.cpp ├── mpegts_demuxer.cpp ├── mpegts_demuxer.h ├── mpegts_muxer.cpp ├── mpegts_muxer.h ├── ts_packet.cpp └── ts_packet.h /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | # CMake 3 | cmake-build-*/ 4 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "amf0"] 2 | path = amf0 3 | url = https://github.com/akanchi/amf0 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 akanchi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mpegts 2 | A simple implementation of mpegts(including muxer and demuxer) 3 | 4 | 5 | # Usage 6 | ``` 7 | cd mpegts && cmake . 8 | ``` 9 | -------------------------------------------------------------------------------- /doc/iso13818-1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akanchi/mpegts/8fc9e27faa0307be941d2243ae0ca79dd3b9e49a/doc/iso13818-1.pdf -------------------------------------------------------------------------------- /doc/video_file_format_spec_v10.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akanchi/mpegts/8fc9e27faa0307be941d2243ae0ca79dd3b9e49a/doc/video_file_format_spec_v10.pdf -------------------------------------------------------------------------------- /mpegts/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 2.6) 2 | project (mpegts) 3 | 4 | set(CMAKE_CXX_FLAGS "-g -std=c++11 -Wall") 5 | 6 | set(AMF0_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../amf0/amf0) 7 | set(SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/mpegts) 8 | 9 | set(SRC_FILE_LISTS mpegts/common.cpp mpegts/common.h mpegts/flv_muxer.cpp mpegts/flv_muxer.h ${AMF0_DIR}/amf_core.h ${AMF0_DIR}/amf0.h ${AMF0_DIR}/amf0.cpp ${AMF0_DIR}/amf_errno.h ${AMF0_DIR}/simple_buffer.h ${AMF0_DIR}/simple_buffer.cpp) 10 | include_directories(${SRC_DIR} ${AMF0_DIR}) 11 | aux_source_directory(${SRC_DIR} SRC_FILE_LISTS) 12 | 13 | add_executable(mpegts.out ${SRC_FILE_LISTS} ${SRC_DIR}/main.cpp) 14 | 15 | -------------------------------------------------------------------------------- /mpegts/mpegts/common.cpp: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include "simple_buffer.h" 3 | 4 | void write_pcr(SimpleBuffer *sb, uint64_t pcr) { 5 | sb->write_1byte((int8_t)(pcr >> 25)); 6 | sb->write_1byte((int8_t)(pcr >> 17)); 7 | sb->write_1byte((int8_t)(pcr >> 9)); 8 | sb->write_1byte((int8_t)(pcr >> 1)); 9 | sb->write_1byte((int8_t)(pcr << 7 | 0x7e)); 10 | sb->write_1byte(0); 11 | } 12 | 13 | void write_pts(SimpleBuffer *sb, uint32_t fb, uint64_t pts) { 14 | uint32_t val; 15 | 16 | val = fb << 4 | (((pts >> 30) & 0x07) << 1) | 1; 17 | sb->write_1byte((int8_t)val); 18 | 19 | val = (((pts >> 15) & 0x7fff) << 1) | 1; 20 | sb->write_2bytes((int16_t)val); 21 | 22 | val = (((pts) & 0x7fff) << 1) | 1; 23 | sb->write_2bytes((int16_t)val); 24 | } 25 | 26 | uint64_t read_pts(SimpleBuffer *sb) { 27 | uint64_t pts = 0; 28 | uint32_t val = 0; 29 | val = sb->read_1byte(); 30 | pts |= ((val >> 1) & 0x07) << 30; 31 | 32 | val = sb->read_2bytes(); 33 | pts |= ((val >> 1) & 0x7fff) << 15; 34 | 35 | val = sb->read_2bytes(); 36 | pts |= ((val >> 1) & 0x7fff); 37 | 38 | return pts; 39 | } 40 | 41 | uint64_t read_pcr(SimpleBuffer *sb) { 42 | uint64_t pcr = 0; 43 | uint64_t val = sb->read_1byte(); 44 | pcr |= (val << 25) & 0x1FE000000; 45 | 46 | val = sb->read_1byte(); 47 | pcr |= (val << 17) & 0x1FE0000; 48 | 49 | val = sb->read_1byte(); 50 | pcr |= (val << 9) & 0x1FE00; 51 | 52 | val = sb->read_1byte(); 53 | pcr |= (val << 1) & 0x1FE; 54 | 55 | val = sb->read_1byte(); 56 | pcr |= ((val >> 7) & 0x01); 57 | 58 | sb->read_1byte(); 59 | 60 | return pcr; 61 | } -------------------------------------------------------------------------------- /mpegts/mpegts/common.h: -------------------------------------------------------------------------------- 1 | #ifndef MPEGTS_COMMON_H 2 | #define MPEGTS_COMMON_H 3 | 4 | #include 5 | 6 | class MpegTsAdaptationFieldType 7 | { 8 | public: 9 | // Reserved for future use by ISO/IEC 10 | static const uint8_t reserved = 0x00; 11 | // No adaptation_field, payload only 12 | static const uint8_t payload_only = 0x01; 13 | // Adaptation_field only, no payload 14 | static const uint8_t adaption_only = 0x02; 15 | // Adaptation_field followed by payload 16 | static const uint8_t payload_adaption_both = 0x03; 17 | }; 18 | 19 | class SimpleBuffer; 20 | 21 | extern void write_pcr(SimpleBuffer *sb, uint64_t pcr); 22 | extern void write_pts(SimpleBuffer *sb, uint32_t fb, uint64_t pts); 23 | 24 | extern uint64_t read_pts(SimpleBuffer *sb); 25 | extern uint64_t read_pcr(SimpleBuffer *sb); 26 | 27 | #endif //MPEGTS_COMMON_H 28 | -------------------------------------------------------------------------------- /mpegts/mpegts/crc.cpp: -------------------------------------------------------------------------------- 1 | #include "crc.h" 2 | 3 | // @see http://www.stmc.edu.hk/~vincent/ffmpeg_0.4.9-pre1/libavformat/mpegtsenc.c 4 | uint32_t crc32(const uint8_t *data, int len) 5 | { 6 | int i; 7 | uint32_t crc = 0xffffffff; 8 | 9 | for (i = 0; i> 24) ^ *data++) & 0xff]; 11 | 12 | return crc; 13 | } 14 | -------------------------------------------------------------------------------- /mpegts/mpegts/crc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | static const uint32_t crc_table[256] = { 6 | 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, 7 | 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, 8 | 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, 9 | 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, 10 | 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 11 | 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, 12 | 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef, 13 | 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, 14 | 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 15 | 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 16 | 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, 17 | 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, 18 | 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, 19 | 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, 20 | 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 21 | 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, 22 | 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, 23 | 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, 24 | 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, 25 | 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 26 | 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, 27 | 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, 28 | 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1, 29 | 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, 30 | 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 31 | 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, 32 | 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9, 33 | 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, 34 | 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 35 | 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 36 | 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, 37 | 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, 38 | 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, 39 | 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, 40 | 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, 41 | 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, 42 | 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, 43 | 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, 44 | 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676, 45 | 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 46 | 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, 47 | 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, 48 | 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 49 | }; 50 | 51 | extern uint32_t crc32(const uint8_t *data, int len); 52 | 53 | -------------------------------------------------------------------------------- /mpegts/mpegts/flv_muxer.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by akanchi on 2019-12-31. 3 | // 4 | 5 | #include "flv_muxer.h" 6 | #include "ts_packet.h" 7 | #include "simple_buffer.h" 8 | #include "amf0.h" 9 | 10 | static const int FLV_TAG_HEADER_SIZE = 11; 11 | 12 | class FLVTagType 13 | { 14 | public: 15 | static const uint8_t Audio = 8; 16 | static const uint8_t Video = 9; 17 | static const uint8_t ScriptData = 18; 18 | }; 19 | 20 | class NALU 21 | { 22 | public: 23 | int type; 24 | uint32_t size; 25 | char *data; 26 | }; 27 | 28 | inline int get_nalu(NALU &nalu, char *data, uint32_t size, uint32_t index) 29 | { 30 | nalu.type = 0; 31 | int ret = -1; 32 | uint32_t i = index; 33 | 34 | while (i < size) { 35 | if (data[i++] == 0x00 36 | && data[i++] == 0x00 37 | && data[i++] == 0x00 38 | && data[i++] == 0x01) { 39 | int pos = i; 40 | 41 | while (pos < size) { 42 | if (data[pos++] == 0x00 43 | && data[pos++] == 0x00 44 | && data[pos++] == 0x00 45 | && data[pos++] == 0x01) { 46 | break; 47 | } 48 | } 49 | uint32_t nalu_size = 0; 50 | if (pos == size) { 51 | nalu_size = pos - i; 52 | ret = pos; 53 | } else if (pos > size) { 54 | nalu_size = size - i; 55 | ret = size; 56 | } else { 57 | nalu_size = (pos - 4) - i; 58 | ret = pos - 4; 59 | } 60 | nalu.type = data[i] & 0x1f; 61 | nalu.size = nalu_size; 62 | nalu.data = &data[i]; 63 | 64 | return ret; 65 | } 66 | } 67 | return ret; 68 | } 69 | 70 | FLVMuxer::FLVMuxer() 71 | : has_set_start_pts(false) 72 | , start_pts(0) 73 | , duration(0) 74 | { 75 | 76 | } 77 | 78 | FLVMuxer::~FLVMuxer() 79 | { 80 | 81 | } 82 | 83 | int FLVMuxer::write_header(SimpleBuffer *sb) 84 | { 85 | sb->write_1byte('F'); // Signature 86 | sb->write_1byte('L'); 87 | sb->write_1byte('V'); 88 | sb->write_1byte(0x01); // version 89 | sb->write_1byte(0x05); // Audio and Video tags are present 90 | sb->write_4bytes(0x00000009); // DataOffset, Offset in bytes from start of file to start of body (that is, size of header) 91 | sb->write_4bytes(0x00000000); // PreviousTagSize0, Always 0 92 | return 0; 93 | } 94 | 95 | int FLVMuxer::write_body(TsFrame *frame, SimpleBuffer *sb) 96 | { 97 | if (frame->stream_type == MpegTsStream::AAC) { 98 | write_aac_tag(frame, sb); 99 | } else if (frame->stream_type == MpegTsStream::AVC) { 100 | write_avc_tag(frame, sb); 101 | } 102 | 103 | calc_duration(frame->pts/90); 104 | 105 | return 0; 106 | } 107 | 108 | int FLVMuxer::write_aac_tag(TsFrame *frame, SimpleBuffer *sb) 109 | { 110 | uint32_t bodySize = 2 + frame->_data->size(); 111 | uint32_t pts = frame->pts / 90; 112 | sb->write_1byte(FLVTagType::Audio); 113 | sb->write_3bytes(bodySize); 114 | sb->write_3bytes(pts); 115 | sb->write_1byte((pts >> 24) & 0xff); 116 | sb->write_3bytes(0x00); 117 | sb->write_1byte(0xaf); 118 | sb->write_1byte(0x01); 119 | sb->append(frame->_data->data(), frame->_data->size()); 120 | sb->write_4bytes(bodySize + FLV_TAG_HEADER_SIZE); 121 | 122 | return 0; 123 | } 124 | 125 | int FLVMuxer::write_avc_tag(TsFrame *frame, SimpleBuffer *sb) 126 | { 127 | int index = 0; 128 | uint32_t pts = frame->pts / 90; 129 | uint32_t dts = frame->dts / 90; 130 | uint32_t cts = pts - dts; 131 | uint32_t size = frame->_data->size(); 132 | NALU nalu; 133 | do { 134 | index = get_nalu(nalu, frame->_data->data(), size, index); 135 | if (nalu.type == 7) { 136 | spsData.clear(); 137 | spsData.append(nalu.data, nalu.size); 138 | } else if (nalu.type == 8 && spsData.size() > 0) { 139 | ppsData.clear(); 140 | ppsData.append(nalu.data, nalu.size); 141 | 142 | uint32_t bodySize = 13 + spsData.size() + 3 + ppsData.size(); 143 | sb->write_1byte(FLVTagType::Video); 144 | sb->write_3bytes(bodySize); 145 | sb->write_3bytes(dts); 146 | sb->write_1byte((dts >> 24) & 0xff); 147 | sb->write_3bytes(0x00); 148 | 149 | sb->write_1byte(0x17); 150 | sb->write_4bytes(0x00); 151 | sb->write_1byte(0x01); 152 | sb->append(spsData.data() + 1, 3); 153 | sb->write_1byte(0xff); 154 | sb->write_1byte(0xe1); 155 | sb->write_2bytes(spsData.size()); 156 | sb->append(spsData.data(), spsData.size()); 157 | 158 | sb->write_1byte(0x01); 159 | sb->write_2bytes(ppsData.size()); 160 | sb->append(ppsData.data(), ppsData.size()); 161 | 162 | sb->write_4bytes(FLV_TAG_HEADER_SIZE + bodySize); 163 | } else if ((nalu.type == 1 || nalu.type == 5) && (spsData.size() > 0 && ppsData.size() > 0)) { 164 | bool isKeyFrame = nalu.type == 0x05; 165 | 166 | uint32_t bodySize = 9 + nalu.size; 167 | sb->write_1byte(FLVTagType::Video); 168 | sb->write_3bytes(bodySize); 169 | sb->write_3bytes(dts); 170 | sb->write_1byte((dts >> 24) & 0xff); 171 | sb->write_3bytes(0x00); 172 | 173 | sb->write_1byte(isKeyFrame ? 0x17 : 0x27); 174 | sb->write_1byte(0x01); 175 | sb->write_3bytes(cts); 176 | 177 | sb->write_4bytes(nalu.size); 178 | sb->append(nalu.data, nalu.size); 179 | 180 | sb->write_4bytes(FLV_TAG_HEADER_SIZE + bodySize); 181 | } 182 | } while (index < size && index > 0); 183 | 184 | return 0; 185 | } 186 | 187 | void FLVMuxer::calc_duration(uint32_t pts) 188 | { 189 | if (!has_set_start_pts) { 190 | has_set_start_pts = true; 191 | start_pts = pts; 192 | } 193 | 194 | duration = pts - start_pts; 195 | } 196 | 197 | int FLVMuxer::write_metadata(SimpleBuffer *sb, uint32_t fileSize) 198 | { 199 | SimpleBuffer bodySb; 200 | 201 | Amf0String amfOnMetaData("onMetaData"); 202 | amfOnMetaData.write(&bodySb); 203 | 204 | Amf0EcmaArray amfEcmaArray; 205 | amfEcmaArray.put("duration", new Amf0Number(duration / 1000.)); 206 | amfEcmaArray.put("filesize", new Amf0Number(fileSize)); 207 | amfEcmaArray.write(&bodySb); 208 | 209 | sb->write_1byte(FLVTagType::ScriptData); 210 | sb->write_3bytes(bodySb.size()); 211 | sb->write_3bytes(0); 212 | sb->write_1byte(0); 213 | sb->write_3bytes(0x00); 214 | 215 | sb->append(bodySb.data(), bodySb.size()); 216 | 217 | return 0; 218 | } 219 | 220 | -------------------------------------------------------------------------------- /mpegts/mpegts/flv_muxer.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by akanchi on 2019-12-31. 3 | // 4 | 5 | #ifndef MPEGTS_FLV_MUXER_H 6 | #define MPEGTS_FLV_MUXER_H 7 | 8 | #include "../../amf0/amf0/simple_buffer.h" 9 | 10 | class TsFrame; 11 | 12 | class FLVMuxer 13 | { 14 | public: 15 | FLVMuxer(); 16 | virtual ~FLVMuxer(); 17 | 18 | public: 19 | int write_header(SimpleBuffer *sb); 20 | int write_body(TsFrame *frame, SimpleBuffer *sb); 21 | int write_metadata(SimpleBuffer *sb, uint32_t fileSize); 22 | 23 | private: 24 | int write_aac_tag(TsFrame *frame, SimpleBuffer *sb); 25 | int write_avc_tag(TsFrame *frame, SimpleBuffer *sb); 26 | void calc_duration(uint32_t pts); 27 | 28 | private: 29 | SimpleBuffer ppsData; 30 | SimpleBuffer spsData; 31 | bool has_set_start_pts; 32 | uint32_t start_pts; 33 | uint32_t duration; 34 | }; 35 | 36 | 37 | #endif //MPEGTS_FLV_MUXER_H 38 | -------------------------------------------------------------------------------- /mpegts/mpegts/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "mpegts_muxer.h" 5 | #include "mpegts_demuxer.h" 6 | #include "simple_buffer.h" 7 | #include "ts_packet.h" 8 | #include "flv_muxer.h" 9 | 10 | std::map file_map; 11 | 12 | void write_file(TsFrame *frame) 13 | { 14 | if (!frame) 15 | return; 16 | 17 | if (file_map.find(frame->pid) == file_map.end()) { 18 | std::string ext = ".unknown"; 19 | if (frame->stream_type == 0x0f) { 20 | ext = ".aac"; 21 | } else if (frame->stream_type == 0x1b) { 22 | ext = ".264"; 23 | } 24 | file_map[frame->pid] = new std::ofstream(std::to_string(frame->pid) + ext, std::ios::binary); 25 | } 26 | 27 | file_map[frame->pid]->write(frame->_data->data(), frame->_data->size()); 28 | } 29 | 30 | int main(int argc, char *argv[]) 31 | { 32 | if (argc <= 1) { 33 | std::cout << "usage: ./mpegts.out in.ts" << std::endl; 34 | return 0; 35 | } 36 | 37 | std::string in_file_name = argv[1]; 38 | std::string out_file_name = in_file_name + "out.ts"; 39 | std::string out_flv_fileName = in_file_name + "out.flv"; 40 | if (argc > 2) { 41 | out_file_name = argv[2]; 42 | } 43 | 44 | std::cout << "input ts: " << in_file_name << std::endl; 45 | std::cout << "output ts: " << out_file_name << std::endl; 46 | 47 | std::ifstream ifile(in_file_name, std::ios::binary | std::ios::in); 48 | std::ofstream outts(out_file_name, std::ios::binary); 49 | std::ofstream outflv(out_flv_fileName, std::ios::binary); 50 | 51 | std::shared_ptr muxer(new MpegTsMuxer); 52 | std::shared_ptr flvMuxer(new FLVMuxer); 53 | SimpleBuffer flvOutBuffer; 54 | flvMuxer->write_header(&flvOutBuffer); 55 | flvMuxer->write_metadata(&flvOutBuffer, 0); 56 | 57 | MpegTsDemuxer demuxer; 58 | char packet[188] = { 0 }; 59 | 60 | SimpleBuffer in; 61 | SimpleBuffer out; 62 | 63 | while (!ifile.eof()) { 64 | ifile.read(packet, 188); 65 | in.append(packet, 188); 66 | 67 | TsFrame *frame = nullptr; 68 | demuxer.decode(&in, frame); 69 | 70 | write_file(frame); 71 | if (frame) { 72 | muxer->encode(frame, demuxer.stream_pid_map, demuxer.pmt_id, &out); 73 | flvMuxer->write_body(frame, &flvOutBuffer); 74 | outflv.write(flvOutBuffer.data(), flvOutBuffer.size()); 75 | flvOutBuffer.clear(); 76 | outts.write(out.data(), out.size()); 77 | out.clear(); 78 | } 79 | } 80 | 81 | { 82 | outflv.seekp(0, std::ios::end); 83 | uint32_t fileSize = outflv.tellp(); 84 | flvMuxer->write_metadata(&flvOutBuffer, fileSize); 85 | outflv.seekp(13, std::ios::beg); 86 | outflv.write(flvOutBuffer.data(), flvOutBuffer.size()); 87 | } 88 | 89 | ifile.close(); 90 | for (auto it = file_map.begin(); it != file_map.end(); it++) { 91 | it->second->close(); 92 | } 93 | 94 | return 0; 95 | } 96 | -------------------------------------------------------------------------------- /mpegts/mpegts/mpegts_demuxer.cpp: -------------------------------------------------------------------------------- 1 | #include "mpegts_demuxer.h" 2 | 3 | #include "simple_buffer.h" 4 | #include "ts_packet.h" 5 | #include "common.h" 6 | 7 | MpegTsDemuxer::MpegTsDemuxer() 8 | : pmt_id(0) 9 | , _pcr_id(0) 10 | { 11 | 12 | } 13 | 14 | MpegTsDemuxer::~MpegTsDemuxer() 15 | { 16 | } 17 | 18 | int MpegTsDemuxer::decode(SimpleBuffer *in, TsFrame *&out) 19 | { 20 | while (!in->empty()) { 21 | int pos = in->pos(); 22 | TsHeader ts_header; 23 | ts_header.decode(in); 24 | 25 | // found pat & get pmt pid 26 | if (ts_header.pid == 0 && pmt_id == 0) { 27 | if (ts_header.adaptation_field_control == MpegTsAdaptationFieldType::adaption_only || 28 | ts_header.adaptation_field_control == MpegTsAdaptationFieldType::payload_adaption_both) { 29 | AdaptationFieldHeader adapt_field; 30 | adapt_field.decode(in); 31 | in->skip(adapt_field.adaptation_field_length > 0 ? (adapt_field.adaptation_field_length - 1) : 0); 32 | } 33 | 34 | if (ts_header.adaptation_field_control == MpegTsAdaptationFieldType::payload_only || 35 | ts_header.adaptation_field_control == MpegTsAdaptationFieldType::payload_adaption_both) { 36 | if (ts_header.payload_unit_start_indicator == 0x01) { 37 | uint8_t point_field = in->read_1byte(); 38 | } 39 | PATHeader pat_header; 40 | pat_header.decode(in); 41 | in->read_2bytes(); 42 | pmt_id = in->read_2bytes() & 0x1fff; 43 | pat_header.print(); 44 | } 45 | } 46 | 47 | // found pmt 48 | if (_ts_frames.empty() && pmt_id != 0 && ts_header.pid == pmt_id) { 49 | if (ts_header.adaptation_field_control == MpegTsAdaptationFieldType::adaption_only || 50 | ts_header.adaptation_field_control == MpegTsAdaptationFieldType::payload_adaption_both) { 51 | AdaptationFieldHeader adapt_field; 52 | adapt_field.decode(in); 53 | in->skip(adapt_field.adaptation_field_length > 0 ? (adapt_field.adaptation_field_length - 1) : 0); 54 | } 55 | 56 | if (ts_header.payload_unit_start_indicator == 0x01) { 57 | uint8_t point_field = in->read_1byte(); 58 | PMTHeader pmt_header; 59 | pmt_header.decode(in); 60 | _pcr_id = pmt_header.PCR_PID; 61 | for (size_t i = 0; i < pmt_header.infos.size(); i++) { 62 | _ts_frames[pmt_header.infos[i]->elementary_PID] = std::shared_ptr(new TsFrame(pmt_header.infos[i]->stream_type)); 63 | stream_pid_map[pmt_header.infos[i]->stream_type] = pmt_header.infos[i]->elementary_PID; 64 | } 65 | pmt_header.print(); 66 | } 67 | } 68 | 69 | if (_ts_frames.find(ts_header.pid) != _ts_frames.end()) { 70 | uint8_t pcr_flag = 0; 71 | uint64_t pcr = 0; 72 | if (ts_header.adaptation_field_control == MpegTsAdaptationFieldType::adaption_only || 73 | ts_header.adaptation_field_control == MpegTsAdaptationFieldType::payload_adaption_both) { 74 | AdaptationFieldHeader adapt_field; 75 | adapt_field.decode(in); 76 | int adflength = adapt_field.adaptation_field_length; 77 | pcr_flag = adapt_field.pcr_flag; 78 | if (adapt_field.pcr_flag == 1) { 79 | pcr = read_pcr(in); 80 | // just adjust buffer pos 81 | adflength -= 6; 82 | } 83 | in->skip(adflength > 0 ? (adflength - 1) : 0); 84 | } 85 | 86 | if (ts_header.adaptation_field_control == MpegTsAdaptationFieldType::payload_only || 87 | ts_header.adaptation_field_control == MpegTsAdaptationFieldType::payload_adaption_both) { 88 | PESHeader pes_header; 89 | if (ts_header.payload_unit_start_indicator == 0x01) { 90 | if (_ts_frames[ts_header.pid]->completed) { 91 | _ts_frames[ts_header.pid]->reset(); 92 | } 93 | 94 | if (!_ts_frames[ts_header.pid]->empty()) { 95 | _ts_frames[ts_header.pid]->completed = true; 96 | _ts_frames[ts_header.pid]->pid = ts_header.pid; 97 | out = _ts_frames[ts_header.pid].get(); 98 | // got the frame, reset pos 99 | in->skip(pos - in->pos()); 100 | return _ts_frames[ts_header.pid]->stream_type; 101 | } 102 | 103 | pes_header.decode(in); 104 | _ts_frames[ts_header.pid]->stream_id = pes_header.stream_id; 105 | _ts_frames[ts_header.pid]->expected_pes_packet_length = pes_header.pes_packet_length; 106 | if (pes_header.pts_dts_flags == 0x02) { 107 | _ts_frames[ts_header.pid]->pts = _ts_frames[ts_header.pid]->dts = read_pts(in); 108 | } else if (pes_header.pts_dts_flags == 0x03) { 109 | _ts_frames[ts_header.pid]->pts = read_pts(in); 110 | _ts_frames[ts_header.pid]->dts = read_pts(in); 111 | } 112 | if (pes_header.pes_packet_length != 0) { 113 | int payload_length = pes_header.pes_packet_length - 3 - pes_header.header_data_length; 114 | if (payload_length >= 188 || payload_length < 0) { 115 | _ts_frames[ts_header.pid]->_data->append(in->data() + in->pos(), 188 - (in->pos() - pos)); 116 | } else { 117 | _ts_frames[ts_header.pid]->_data->append(in->data() + in->pos(), payload_length); 118 | } 119 | in->skip(188 - (in->pos() - pos)); 120 | continue; 121 | } 122 | } 123 | 124 | if (_ts_frames[ts_header.pid]->expected_pes_packet_length != 0 && 125 | _ts_frames[ts_header.pid]->_data->size() + 188 - (in->pos() - pos) > _ts_frames[ts_header.pid]->expected_pes_packet_length) { 126 | _ts_frames[ts_header.pid]->_data->append(in->data() + in->pos(), _ts_frames[ts_header.pid]->expected_pes_packet_length - _ts_frames[ts_header.pid]->_data->size()); 127 | } else { 128 | _ts_frames[ts_header.pid]->_data->append(in->data() + in->pos(), 188 - (in->pos() - pos)); 129 | } 130 | } 131 | } else if (_pcr_id != 0 && _pcr_id == ts_header.pid) { 132 | AdaptationFieldHeader adapt_field; 133 | adapt_field.decode(in); 134 | uint64_t pcr = read_pcr(in); 135 | } 136 | 137 | in->skip(188 - (in->pos() - pos)); 138 | } 139 | 140 | in->clear(); 141 | 142 | return 0; 143 | } 144 | -------------------------------------------------------------------------------- /mpegts/mpegts/mpegts_demuxer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | class SimpleBuffer; 8 | class TsFrame; 9 | 10 | class MpegTsDemuxer 11 | { 12 | public: 13 | MpegTsDemuxer(); 14 | virtual ~MpegTsDemuxer(); 15 | 16 | public: 17 | int decode(SimpleBuffer *in, TsFrame *&out); 18 | // stream, pid 19 | std::map stream_pid_map; 20 | int pmt_id; 21 | 22 | private: 23 | // pid, frame 24 | std::map> _ts_frames; 25 | int _pcr_id; 26 | }; 27 | 28 | -------------------------------------------------------------------------------- /mpegts/mpegts/mpegts_muxer.cpp: -------------------------------------------------------------------------------- 1 | #include "mpegts_muxer.h" 2 | #include "simple_buffer.h" 3 | #include "ts_packet.h" 4 | #include "crc.h" 5 | #include 6 | #include "common.h" 7 | 8 | static const uint16_t MPEGTS_NULL_PACKET_PID = 0x1FFF; 9 | static const uint16_t MPEGTS_PAT_PID = 0x00; 10 | static const uint16_t MPEGTS_PMT_PID = 0x100; 11 | static const uint16_t MPEGTS_PCR_PID = 0x110; 12 | 13 | MpegTsMuxer::MpegTsMuxer() 14 | { 15 | } 16 | 17 | MpegTsMuxer::~MpegTsMuxer() 18 | { 19 | } 20 | 21 | void MpegTsMuxer::create_pat(SimpleBuffer *sb, uint16_t pmt_pid, uint8_t cc) 22 | { 23 | SimpleBuffer pat_sb; 24 | TsHeader ts_header; 25 | ts_header.sync_byte = 0x47; 26 | ts_header.transport_error_indicator = 0; 27 | ts_header.payload_unit_start_indicator = 1; 28 | ts_header.transport_priority = 0; 29 | ts_header.pid = MPEGTS_PAT_PID; 30 | ts_header.transport_scrambling_control = 0; 31 | ts_header.adaptation_field_control = MpegTsAdaptationFieldType::payload_only; 32 | ts_header.continuity_counter = cc; 33 | 34 | AdaptationFieldHeader adapt_field; 35 | 36 | PATHeader pat_header; 37 | pat_header.table_id = 0x00; 38 | pat_header.section_syntax_indicator = 1; 39 | pat_header.b0 = 0; 40 | pat_header.reserved0 = 0x3; 41 | pat_header.transport_stream_id = 0; 42 | pat_header.reserved1 = 0x3; 43 | pat_header.version_number = 0; 44 | pat_header.current_next_indicator = 1; 45 | pat_header.section_number = 0x0; 46 | pat_header.last_section_number = 0x0; 47 | 48 | //program_number 49 | uint16_t program_number = 0x0001; 50 | //program_map_PID 51 | uint16_t program_map_PID = 0xe000 | (pmt_pid & 0x1fff); 52 | 53 | unsigned int section_length = 4 + 4 + 5; 54 | pat_header.section_length = section_length & 0x3ff; 55 | 56 | ts_header.encode(&pat_sb); 57 | adapt_field.encode(&pat_sb); 58 | pat_header.encode(&pat_sb); 59 | pat_sb.write_2bytes(program_number); 60 | pat_sb.write_2bytes(program_map_PID); 61 | 62 | // crc32 63 | uint32_t crc_32 = crc32((uint8_t *)pat_sb.data() + 5, pat_sb.size() - 5); 64 | pat_sb.write_4bytes(crc_32); 65 | 66 | std::vector stuff(188 - pat_sb.size(), 0xff); 67 | pat_sb.append((const char *)stuff.data(), stuff.size()); 68 | 69 | sb->append(pat_sb.data(), pat_sb.size()); 70 | } 71 | 72 | void MpegTsMuxer::create_pmt(SimpleBuffer *sb, std::map stream_pid_map, uint16_t pmt_pid, uint8_t cc) 73 | { 74 | SimpleBuffer pmt_sb; 75 | TsHeader ts_header; 76 | ts_header.sync_byte = 0x47; 77 | ts_header.transport_error_indicator = 0; 78 | ts_header.payload_unit_start_indicator = 1; 79 | ts_header.transport_priority = 0; 80 | ts_header.pid = pmt_pid; 81 | ts_header.transport_scrambling_control = 0; 82 | ts_header.adaptation_field_control = MpegTsAdaptationFieldType::payload_only; 83 | ts_header.continuity_counter = cc; 84 | 85 | AdaptationFieldHeader adapt_field; 86 | 87 | PMTHeader pmt_header; 88 | pmt_header.table_id = 0x02; 89 | pmt_header.section_syntax_indicator = 1; 90 | pmt_header.b0 = 0; 91 | pmt_header.reserved0 = 0x3; 92 | pmt_header.section_length = 0; 93 | pmt_header.program_number = 0x0001; 94 | pmt_header.reserved1 = 0x3; 95 | pmt_header.version_number = 0; 96 | pmt_header.current_next_indicator = 1; 97 | pmt_header.section_number = 0x00; 98 | pmt_header.last_section_number = 0x00; 99 | pmt_header.reserved2 = 0x7; 100 | pmt_header.reserved3 = 0xf; 101 | pmt_header.program_info_length = 0; 102 | for (auto it = stream_pid_map.begin(); it != stream_pid_map.end(); it++) { 103 | pmt_header.infos.push_back(std::shared_ptr(new PMTElementInfo(it->first, it->second))); 104 | if (it->first == MpegTsStream::AVC) { 105 | pmt_header.PCR_PID = it->second; 106 | } 107 | } 108 | 109 | uint16_t section_length = pmt_header.size() - 3 + 4; 110 | pmt_header.section_length = section_length & 0x3ff; 111 | 112 | ts_header.encode(&pmt_sb); 113 | adapt_field.encode(&pmt_sb); 114 | pmt_header.encode(&pmt_sb); 115 | 116 | // crc32 117 | uint32_t crc_32 = crc32((uint8_t *)pmt_sb.data() + 5, pmt_sb.size() - 5); 118 | pmt_sb.write_4bytes(crc_32); 119 | 120 | std::vector stuff(188 - pmt_sb.size(), 0xff); 121 | pmt_sb.append((const char *)stuff.data(), stuff.size()); 122 | 123 | sb->append(pmt_sb.data(), pmt_sb.size()); 124 | } 125 | 126 | void MpegTsMuxer::create_pes(TsFrame *frame, SimpleBuffer *sb) 127 | { 128 | bool first = true; 129 | while (!frame->_data->empty()) { 130 | SimpleBuffer packet; 131 | 132 | TsHeader ts_header; 133 | ts_header.pid = frame->pid; 134 | ts_header.adaptation_field_control = MpegTsAdaptationFieldType::payload_only; 135 | ts_header.continuity_counter = get_cc(frame->stream_type); 136 | 137 | if (first) { 138 | ts_header.payload_unit_start_indicator = 0x01; 139 | if (frame->stream_type == MpegTsStream::AVC) { 140 | ts_header.adaptation_field_control |= 0x02; 141 | AdaptationFieldHeader adapt_field_header; 142 | adapt_field_header.adaptation_field_length = 0x07; 143 | adapt_field_header.random_access_indicator = 0x01; 144 | adapt_field_header.pcr_flag = 0x01; 145 | 146 | ts_header.encode(&packet); 147 | adapt_field_header.encode(&packet); 148 | write_pcr(&packet, frame->dts); 149 | } else { 150 | ts_header.encode(&packet); 151 | } 152 | 153 | PESHeader pes_header; 154 | pes_header.packet_start_code = 0x000001; 155 | pes_header.stream_id = frame->stream_id; 156 | pes_header.marker_bits = 0x02; 157 | pes_header.original_or_copy = 0x01; 158 | 159 | if (frame->pts != frame->dts) { 160 | pes_header.pts_dts_flags = 0x03; 161 | pes_header.header_data_length = 0x0A; 162 | } else { 163 | pes_header.pts_dts_flags = 0x2; 164 | pes_header.header_data_length = 0x05; 165 | } 166 | 167 | uint32_t pes_size = (pes_header.header_data_length + frame->_data->size() + 3); 168 | pes_header.pes_packet_length = pes_size > 0xffff ? 0 : pes_size; 169 | pes_header.encode(&packet); 170 | 171 | if (pes_header.pts_dts_flags == 0x03) { 172 | write_pts(&packet, 3, frame->pts); 173 | write_pts(&packet, 1, frame->dts); 174 | } else { 175 | write_pts(&packet, 2, frame->pts); 176 | } 177 | first = false; 178 | } else { 179 | ts_header.encode(&packet); 180 | } 181 | 182 | uint32_t pos = packet.size(); 183 | uint32_t body_size = 188 - pos; 184 | std::vector body(body_size, 0); 185 | packet.append((const char *)body.data(), body_size); 186 | packet.skip(pos); 187 | uint32_t in_size = frame->_data->size() - frame->_data->pos(); 188 | if (body_size <= in_size) { // MpegTsAdaptationFieldType::payload_only or MpegTsAdaptationFieldType::payload_adaption_both for AVC 189 | packet.set_data(pos, frame->_data->data() + frame->_data->pos(), body_size); 190 | frame->_data->skip(body_size); 191 | } else { 192 | uint16_t stuff_size = body_size - in_size; 193 | if (ts_header.adaptation_field_control == MpegTsAdaptationFieldType::adaption_only || ts_header.adaptation_field_control == MpegTsAdaptationFieldType::payload_adaption_both) { 194 | char *base = packet.data() + 5 + packet.data()[4]; 195 | packet.set_data(base - packet.data() + stuff_size, base, packet.data() + packet.pos() - base); 196 | memset(base, 0xff, stuff_size); 197 | packet.skip(stuff_size); 198 | packet.data()[4] += stuff_size; 199 | } else { 200 | // adaptation_field_control |= 0x20 == MpegTsAdaptationFieldType::payload_adaption_both 201 | packet.data()[3] |= 0x20; 202 | packet.set_data(188 - 4 - stuff_size, packet.data() + 4, packet.pos() - 4); 203 | packet.skip(stuff_size); 204 | packet.data()[4] = stuff_size - 1; 205 | if (stuff_size >= 2) { 206 | packet.data()[5] = 0; 207 | memset(&(packet.data()[6]), 0xff, stuff_size - 2); 208 | } 209 | } 210 | 211 | packet.set_data(packet.pos(), frame->_data->data() + frame->_data->pos(), in_size); 212 | frame->_data->skip(in_size); 213 | } 214 | 215 | sb->append(packet.data(), packet.size()); 216 | } 217 | } 218 | 219 | void MpegTsMuxer::create_pcr(SimpleBuffer *sb) 220 | { 221 | uint64_t pcr = 0; 222 | TsHeader ts_header; 223 | ts_header.sync_byte = 0x47; 224 | ts_header.transport_error_indicator = 0; 225 | ts_header.payload_unit_start_indicator = 0; 226 | ts_header.transport_priority = 0; 227 | ts_header.pid = MPEGTS_PCR_PID; 228 | ts_header.transport_scrambling_control = 0; 229 | ts_header.adaptation_field_control = MpegTsAdaptationFieldType::adaption_only; 230 | ts_header.continuity_counter = 0; 231 | 232 | AdaptationFieldHeader adapt_field; 233 | adapt_field.adaptation_field_length = 188 - 4 - 1; 234 | adapt_field.discontinuity_indicator = 0; 235 | adapt_field.random_access_indicator = 0; 236 | adapt_field.elementary_stream_priority_indicator = 0; 237 | adapt_field.pcr_flag = 1; 238 | adapt_field.opcr_flag = 0; 239 | adapt_field.splicing_point_flag = 0; 240 | adapt_field.transport_private_data_flag = 0; 241 | adapt_field.adaptation_field_extension_flag = 0; 242 | 243 | char *p = sb->data(); 244 | ts_header.encode(sb); 245 | adapt_field.encode(sb); 246 | write_pcr(sb, pcr); 247 | } 248 | 249 | void MpegTsMuxer::create_null(SimpleBuffer *sb) 250 | { 251 | TsHeader ts_header; 252 | ts_header.sync_byte = 0x47; 253 | ts_header.transport_error_indicator = 0; 254 | ts_header.payload_unit_start_indicator = 0; 255 | ts_header.transport_priority = 0; 256 | ts_header.pid = MPEGTS_NULL_PACKET_PID; 257 | ts_header.transport_scrambling_control = 0; 258 | ts_header.adaptation_field_control = MpegTsAdaptationFieldType::payload_only; 259 | ts_header.continuity_counter = 0; 260 | ts_header.encode(sb); 261 | } 262 | 263 | void MpegTsMuxer::encode(TsFrame *frame, std::map stream_pid_map, uint16_t pmt_pid, SimpleBuffer *sb) 264 | { 265 | if (should_create_pat()) { 266 | uint8_t pat_pmt_cc = get_cc(0); 267 | create_pat(sb, pmt_pid, pat_pmt_cc); 268 | create_pmt(sb, stream_pid_map, pmt_pid, pat_pmt_cc); 269 | } 270 | 271 | create_pes(frame, sb); 272 | } 273 | 274 | uint8_t MpegTsMuxer::get_cc(uint32_t with_pid) 275 | { 276 | if (_pid_cc_map.find(with_pid) != _pid_cc_map.end()) { 277 | _pid_cc_map[with_pid] = (_pid_cc_map[with_pid] + 1) & 0x0F; 278 | return _pid_cc_map[with_pid]; 279 | } 280 | 281 | _pid_cc_map[with_pid] = 0; 282 | return 0; 283 | } 284 | 285 | bool MpegTsMuxer::should_create_pat() 286 | { 287 | bool ret = false; 288 | static const int pat_interval = 20; 289 | static int current_index = 0; 290 | if (current_index % pat_interval == 0) { 291 | if (current_index > 0) { 292 | current_index = 0; 293 | } 294 | ret = true; 295 | } 296 | 297 | current_index++; 298 | 299 | return ret; 300 | } 301 | -------------------------------------------------------------------------------- /mpegts/mpegts/mpegts_muxer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | class SimpleBuffer; 7 | class TsFrame; 8 | 9 | class MpegTsMuxer 10 | { 11 | public: 12 | MpegTsMuxer(); 13 | virtual ~MpegTsMuxer(); 14 | 15 | public: 16 | void create_pat(SimpleBuffer *sb, uint16_t pmt_pid, uint8_t cc); 17 | void create_pmt(SimpleBuffer *sb, std::map stream_pid_map, uint16_t pmt_pid, uint8_t cc); 18 | void create_pes(TsFrame *frame, SimpleBuffer *sb); 19 | void create_pcr(SimpleBuffer *sb); 20 | void create_null(SimpleBuffer *sb); 21 | void encode(TsFrame *frame, std::map stream_pid_map, uint16_t pmt_pid, SimpleBuffer *sb); 22 | 23 | private: 24 | uint8_t get_cc(uint32_t with_pid); 25 | bool should_create_pat(); 26 | 27 | private: 28 | std::map _pid_cc_map; 29 | }; 30 | 31 | -------------------------------------------------------------------------------- /mpegts/mpegts/ts_packet.cpp: -------------------------------------------------------------------------------- 1 | #include "ts_packet.h" 2 | #include "simple_buffer.h" 3 | 4 | #include 5 | 6 | TsFrame::TsFrame() 7 | : completed(false) 8 | , pid(0) 9 | , expected_pes_packet_length(0) 10 | { 11 | _data.reset(new SimpleBuffer); 12 | } 13 | 14 | TsFrame::TsFrame(uint8_t st) 15 | : stream_type(st) 16 | , completed(false) 17 | , pid(0) 18 | , expected_pes_packet_length(0) 19 | { 20 | _data.reset(new SimpleBuffer); 21 | } 22 | 23 | bool TsFrame::empty() 24 | { 25 | return _data->size() == 0; 26 | } 27 | 28 | void TsFrame::reset() 29 | { 30 | pid = 0; 31 | completed = false; 32 | expected_pes_packet_length = 0; 33 | _data.reset(new SimpleBuffer); 34 | } 35 | 36 | TsHeader::TsHeader() 37 | : sync_byte(0x47) 38 | , transport_error_indicator(0) 39 | , payload_unit_start_indicator(0) 40 | , transport_priority(0) 41 | , pid(0) 42 | , transport_scrambling_control(0) 43 | , adaptation_field_control(0) 44 | , continuity_counter(0) 45 | { 46 | } 47 | 48 | TsHeader::~TsHeader() 49 | { 50 | } 51 | 52 | void TsHeader::encode(SimpleBuffer *sb) 53 | { 54 | sb->write_1byte(sync_byte); 55 | 56 | uint16_t b1b2 = pid & 0x1FFF; 57 | b1b2 |= (transport_priority << 13) & 0x2000; 58 | b1b2 |= (payload_unit_start_indicator << 14) & 0x4000; 59 | b1b2 |= (transport_error_indicator << 15) & 0x8000; 60 | sb->write_2bytes(b1b2); 61 | 62 | uint8_t b3 = continuity_counter & 0x0F; 63 | b3 |= (adaptation_field_control << 4) & 0x30; 64 | b3 |= (transport_scrambling_control << 6) & 0xC0; 65 | sb->write_1byte(b3); 66 | } 67 | 68 | void TsHeader::decode(SimpleBuffer *sb) 69 | { 70 | sync_byte = sb->read_1byte(); 71 | 72 | uint16_t b1b2 = sb->read_2bytes(); 73 | pid = b1b2 & 0x1FFF; 74 | transport_error_indicator = (b1b2 >> 13) & 0x01; 75 | payload_unit_start_indicator = (b1b2 >> 14) & 0x01; 76 | transport_error_indicator = (b1b2 >> 15) & 0x01; 77 | 78 | uint8_t b3 = sb->read_1byte(); 79 | continuity_counter = b3 & 0x0F; 80 | adaptation_field_control = (b3 >> 4) & 0x03; 81 | transport_scrambling_control = (b3 >> 6) & 0x03; 82 | } 83 | 84 | PATHeader::PATHeader() 85 | : table_id(0) 86 | , section_syntax_indicator(0) 87 | , b0(0) 88 | , reserved0(0) 89 | , section_length(0) 90 | , transport_stream_id(0) 91 | , reserved1(0) 92 | , version_number(0) 93 | , current_next_indicator(0) 94 | , section_number(0) 95 | , last_section_number(0) 96 | { 97 | 98 | } 99 | 100 | PATHeader::~PATHeader() 101 | { 102 | 103 | } 104 | 105 | void PATHeader::encode(SimpleBuffer *sb) 106 | { 107 | sb->write_1byte(table_id); 108 | 109 | uint16_t b1b2 = section_length & 0x0FFF; 110 | b1b2 |= (reserved0 << 12) & 0x3000; 111 | b1b2 |= (b0 << 14) & 0x4000; 112 | b1b2 |= (section_syntax_indicator << 15) & 0x8000; 113 | sb->write_2bytes(b1b2); 114 | 115 | sb->write_2bytes(transport_stream_id); 116 | 117 | uint8_t b5 = current_next_indicator & 0x01; 118 | b5 |= (version_number << 1) & 0x3E; 119 | b5 |= (reserved1 << 6) & 0xC0; 120 | sb->write_1byte(b5); 121 | 122 | sb->write_1byte(section_number); 123 | sb->write_1byte(last_section_number); 124 | } 125 | 126 | void PATHeader::decode(SimpleBuffer *sb) 127 | { 128 | table_id = sb->read_1byte(); 129 | 130 | uint16_t b1b2 = sb->read_2bytes(); 131 | section_syntax_indicator = (b1b2 >> 15) & 0x01; 132 | b0 = (b1b2 >> 14) & 0x01; 133 | section_length = b1b2 & 0x0FFF; 134 | 135 | transport_stream_id = sb->read_2bytes(); 136 | 137 | uint8_t b5 = sb->read_1byte(); 138 | reserved1 = (b5 >> 6) & 0x03; 139 | version_number = (b5 >> 1) & 0x1F; 140 | current_next_indicator = b5 & 0x01; 141 | 142 | section_number = sb->read_1byte(); 143 | 144 | last_section_number = sb->read_1byte(); 145 | } 146 | 147 | void PATHeader::print() 148 | { 149 | std::cout << "----------PAT information----------" << std::endl; 150 | std::cout << "table_id: " << std::to_string(table_id) << std::endl; 151 | std::cout << "section_syntax_indicator: " << std::to_string(section_syntax_indicator) << std::endl; 152 | std::cout << "b0: " << std::to_string(b0) << std::endl; 153 | std::cout << "reserved0: " << std::to_string(reserved0) << std::endl; 154 | std::cout << "section_length: " << std::to_string(section_length) << std::endl; 155 | std::cout << "transport_stream_id: " << std::to_string(transport_stream_id) << std::endl; 156 | std::cout << "reserved1: " << std::to_string(reserved1) << std::endl; 157 | std::cout << "version_number: " << std::to_string(version_number) << std::endl; 158 | std::cout << "current_next_indicator: " << std::to_string(current_next_indicator) << std::endl; 159 | std::cout << "section_number: " << std::to_string(section_number) << std::endl; 160 | std::cout << "last_section_number: " << std::to_string(last_section_number) << std::endl; 161 | std::cout << std::endl; 162 | std::flush(std::cout); 163 | } 164 | 165 | PMTElementInfo::PMTElementInfo(uint8_t st, uint16_t pid) 166 | : stream_type(st) 167 | , reserved0(0x7) 168 | , elementary_PID(pid) 169 | , reserved1(0xf) 170 | , ES_info_length(0) 171 | { 172 | 173 | } 174 | 175 | PMTElementInfo::PMTElementInfo() 176 | : PMTElementInfo(0, 0) 177 | { 178 | 179 | } 180 | 181 | PMTElementInfo::~PMTElementInfo() 182 | { 183 | 184 | } 185 | 186 | void PMTElementInfo::encode(SimpleBuffer *sb) 187 | { 188 | sb->write_1byte(stream_type); 189 | 190 | uint16_t b1b2 = elementary_PID & 0x1FFF; 191 | b1b2 |= (reserved0 << 13) & 0xE000; 192 | sb->write_2bytes(b1b2); 193 | 194 | int16_t b3b4 = ES_info_length & 0x0FFF; 195 | b3b4 |= (reserved1 << 12) & 0xF000; 196 | sb->write_2bytes(b3b4); 197 | 198 | if (ES_info_length > 0) { 199 | // TODO: 200 | } 201 | } 202 | 203 | void PMTElementInfo::decode(SimpleBuffer *sb) 204 | { 205 | stream_type = sb->read_1byte(); 206 | 207 | uint16_t b1b2 = sb->read_2bytes(); 208 | reserved0 = (b1b2 >> 13) & 0x07; 209 | elementary_PID = b1b2 & 0x1FFF; 210 | 211 | uint16_t b3b4 = sb->read_2bytes(); 212 | reserved1 = (b3b4 >> 12) & 0xF; 213 | ES_info_length = b3b4 & 0xFFF; 214 | 215 | if (ES_info_length > 0) { 216 | ES_info = sb->read_string(ES_info_length); 217 | } 218 | } 219 | 220 | uint16_t PMTElementInfo::size() 221 | { 222 | return 5 + ES_info_length; 223 | } 224 | 225 | void PMTElementInfo::print() 226 | { 227 | std::cout << "**********PMTElement information**********" << std::endl; 228 | std::cout << "stream_type: " << std::to_string(stream_type) << std::endl; 229 | std::cout << "reserved0: " << std::to_string(reserved0) << std::endl; 230 | std::cout << "elementary_PID: " << std::to_string(elementary_PID) << std::endl; 231 | std::cout << "reserved1: " << std::to_string(reserved1) << std::endl; 232 | std::cout << "ES_info_length: " << std::to_string(ES_info_length) << std::endl; 233 | std::cout << "ES_info: " << ES_info << std::endl; 234 | std::flush(std::cout); 235 | } 236 | 237 | PMTHeader::PMTHeader() 238 | : table_id(0x02) 239 | , section_syntax_indicator(0) 240 | , b0(0) 241 | , reserved0(0) 242 | , section_length(0) 243 | , program_number(0) 244 | , reserved1(0) 245 | , version_number(0) 246 | , current_next_indicator(0) 247 | , section_number(0) 248 | , last_section_number(0) 249 | , reserved2(0) 250 | , PCR_PID(0) 251 | , reserved3(0) 252 | , program_info_length(0) 253 | { 254 | 255 | } 256 | 257 | PMTHeader::~PMTHeader() 258 | { 259 | 260 | } 261 | 262 | void PMTHeader::encode(SimpleBuffer *sb) 263 | { 264 | sb->write_1byte(table_id); 265 | 266 | uint16_t b1b2 = section_length & 0xFFFF; 267 | b1b2 |= (reserved0 << 12) & 0x3000; 268 | b1b2 |= (b0 << 14) & 0x4000; 269 | b1b2 |= (section_syntax_indicator << 15) & 0x8000; 270 | sb->write_2bytes(b1b2); 271 | 272 | sb->write_2bytes(program_number); 273 | 274 | uint8_t b5 = current_next_indicator & 0x01; 275 | b5 |= (version_number << 1) & 0x3E; 276 | b5 |= (reserved1 << 6) & 0xC0; 277 | sb->write_1byte(b5); 278 | 279 | sb->write_1byte(section_number); 280 | sb->write_1byte(last_section_number); 281 | 282 | uint16_t b8b9 = PCR_PID & 0x1FFF; 283 | b8b9 |= (reserved2 << 13) & 0xE000; 284 | sb->write_2bytes(b8b9); 285 | 286 | uint16_t b10b11 = program_info_length & 0xFFF; 287 | b10b11 |= (reserved3 << 12) & 0xF000; 288 | sb->write_2bytes(b10b11); 289 | 290 | for (int i = 0; i < (int)infos.size(); i++) { 291 | infos[i]->encode(sb); 292 | } 293 | } 294 | 295 | void PMTHeader::decode(SimpleBuffer *sb) 296 | { 297 | table_id = sb->read_1byte(); 298 | 299 | uint16_t b1b2 = sb->read_2bytes(); 300 | section_syntax_indicator = (b1b2 >> 15) & 0x01; 301 | b0 = (b1b2 >> 14) & 0x01; 302 | reserved0 = (b1b2 >> 12) & 0x03; 303 | section_length = b1b2 & 0xFFF; 304 | 305 | program_number = sb->read_2bytes(); 306 | 307 | uint8_t b5 = sb->read_1byte(); 308 | reserved1 = (b5 >> 6) & 0x03; 309 | version_number = (b5 >> 1) & 0x1F; 310 | current_next_indicator = b5 & 0x01; 311 | 312 | section_number = sb->read_1byte(); 313 | last_section_number = sb->read_1byte(); 314 | 315 | uint16_t b8b9 = sb->read_2bytes(); 316 | reserved2 = (b8b9 >> 13) & 0x07; 317 | PCR_PID = b8b9 & 0x1FFF; 318 | 319 | uint16_t b10b11 = sb->read_2bytes(); 320 | reserved3 = (b10b11 >> 12) & 0xF; 321 | program_info_length = b10b11 & 0xFFF; 322 | 323 | if (program_info_length > 0) { 324 | sb->read_string(program_info_length); 325 | } 326 | 327 | int remain_bytes = section_length - 4 - 9 - program_info_length; 328 | while (remain_bytes > 0) { 329 | std::shared_ptr element_info(new PMTElementInfo); 330 | element_info->decode(sb); 331 | infos.push_back(element_info); 332 | remain_bytes -= element_info->size(); 333 | } 334 | } 335 | 336 | uint16_t PMTHeader::size() 337 | { 338 | uint16_t ret = 12; 339 | for (int i = 0; i < (int)infos.size(); i++) { 340 | ret += infos[i]->size(); 341 | } 342 | 343 | return ret; 344 | } 345 | 346 | void PMTHeader::print() 347 | { 348 | std::cout << "----------PMT information----------" << std::endl; 349 | std::cout << "table_id: " << std::to_string(table_id) << std::endl; 350 | std::cout << "section_syntax_indicator: " << std::to_string(section_syntax_indicator) << std::endl; 351 | std::cout << "b0: " << std::to_string(b0) << std::endl; 352 | std::cout << "reserved0: " << std::to_string(reserved0) << std::endl; 353 | std::cout << "section_length: " << std::to_string(section_length) << std::endl; 354 | std::cout << "program_number: " << std::to_string(program_number) << std::endl; 355 | std::cout << "reserved1: " << std::to_string(reserved1) << std::endl; 356 | std::cout << "version_number: " << std::to_string(version_number) << std::endl; 357 | std::cout << "current_next_indicator: " << std::to_string(current_next_indicator) << std::endl; 358 | std::cout << "section_number: " << std::to_string(section_number) << std::endl; 359 | std::cout << "last_section_number: " << std::to_string(last_section_number) << std::endl; 360 | std::cout << "reserved2: " << std::to_string(reserved2) << std::endl; 361 | std::cout << "PCR_PID: " << std::to_string(PCR_PID) << std::endl; 362 | std::cout << "reserved3: " << std::to_string(reserved3) << std::endl; 363 | std::cout << "program_info_length: " << std::to_string(program_info_length) << std::endl; 364 | for (int i = 0; i < (int)infos.size(); i++) { 365 | infos[i]->print(); 366 | } 367 | std::cout << std::endl; 368 | std::flush(std::cout); 369 | } 370 | 371 | AdaptationFieldHeader::AdaptationFieldHeader() 372 | : adaptation_field_length(0) 373 | , adaptation_field_extension_flag(0) 374 | , transport_private_data_flag(0) 375 | , splicing_point_flag(0) 376 | , opcr_flag(0) 377 | , pcr_flag(0) 378 | , elementary_stream_priority_indicator(0) 379 | , random_access_indicator(0) 380 | , discontinuity_indicator(0) 381 | { 382 | 383 | } 384 | 385 | AdaptationFieldHeader::~AdaptationFieldHeader() 386 | { 387 | 388 | } 389 | 390 | void AdaptationFieldHeader::encode(SimpleBuffer *sb) 391 | { 392 | sb->write_1byte(adaptation_field_length); 393 | if (adaptation_field_length != 0) { 394 | uint8_t val = adaptation_field_extension_flag & 0x01; 395 | val |= (transport_private_data_flag << 1) & 0x02; 396 | val |= (splicing_point_flag << 2) & 0x04; 397 | val |= (opcr_flag << 3) & 0x08; 398 | val |= (pcr_flag << 4) & 0x10; 399 | val |= (elementary_stream_priority_indicator << 5) & 0x20; 400 | val |= (random_access_indicator << 6) & 0x40; 401 | val |= (discontinuity_indicator << 7) & 0x80; 402 | sb->write_1byte(val); 403 | } 404 | } 405 | 406 | void AdaptationFieldHeader::decode(SimpleBuffer *sb) 407 | { 408 | adaptation_field_length = sb->read_1byte(); 409 | if (adaptation_field_length != 0) { 410 | uint8_t val = sb->read_1byte(); 411 | adaptation_field_extension_flag = val & 0x01; 412 | transport_private_data_flag = (val >> 1) & 0x01; 413 | splicing_point_flag = (val >> 2) & 0x01; 414 | opcr_flag = (val >> 3) & 0x01; 415 | pcr_flag = (val >> 4) & 0x01; 416 | elementary_stream_priority_indicator = (val >> 5) & 0x01; 417 | random_access_indicator = (val >> 6) & 0x01; 418 | discontinuity_indicator = (val >> 7) & 0x01; 419 | } 420 | } 421 | 422 | PESHeader::PESHeader() 423 | : packet_start_code(0x000001) 424 | , stream_id(0) 425 | , pes_packet_length(0) 426 | , original_or_copy(0) 427 | , copyright(0) 428 | , data_alignment_indicator(0) 429 | , pes_priority(0) 430 | , pes_scrambling_control(0) 431 | , marker_bits(0x02) 432 | , pes_ext_flag(0) 433 | , pes_crc_flag(0) 434 | , add_copy_info_flag(0) 435 | , dsm_trick_mode_flag(0) 436 | , es_rate_flag(0) 437 | , escr_flag(0) 438 | , pts_dts_flags(0) 439 | , header_data_length(0) 440 | { 441 | 442 | } 443 | 444 | PESHeader::~PESHeader() 445 | { 446 | 447 | } 448 | 449 | void PESHeader::encode(SimpleBuffer *sb) 450 | { 451 | uint32_t b0b1b2b3 = (packet_start_code << 8) & 0xFFFFFF00; 452 | b0b1b2b3 |= stream_id & 0xFF; 453 | sb->write_4bytes(b0b1b2b3); 454 | 455 | sb->write_2bytes(pes_packet_length); 456 | 457 | uint8_t b6 = original_or_copy & 0x01; 458 | b6 |= (copyright << 1) & 0x02; 459 | b6 |= (data_alignment_indicator << 2) & 0x04; 460 | b6 |= (pes_priority << 3) & 0x08; 461 | b6 |= (pes_scrambling_control << 4) & 0x30; 462 | b6 |= (marker_bits << 6) & 0xC0; 463 | sb->write_1byte(b6); 464 | 465 | uint8_t b7 = pes_ext_flag & 0x01; 466 | b7 |= (pes_crc_flag << 1) & 0x02; 467 | b7 |= (add_copy_info_flag << 2) & 0x04; 468 | b7 |= (dsm_trick_mode_flag << 3) & 0x08; 469 | b7 |= (es_rate_flag << 4) & 0x10; 470 | b7 |= (escr_flag << 5) & 0x20; 471 | b7 |= (pts_dts_flags << 6) & 0xC0; 472 | sb->write_1byte(b7); 473 | 474 | sb->write_1byte(header_data_length); 475 | } 476 | 477 | void PESHeader::decode(SimpleBuffer *sb) 478 | { 479 | uint32_t b0b1b2b3 = sb->read_4bytes(); 480 | packet_start_code = (b0b1b2b3 >> 8) & 0x00FFFFFF; 481 | stream_id = (b0b1b2b3) & 0xFF; 482 | 483 | pes_packet_length = sb->read_2bytes(); 484 | 485 | uint8_t b6 = sb->read_1byte(); 486 | original_or_copy = b6 & 0x01; 487 | copyright = (b6 >> 1) & 0x01; 488 | data_alignment_indicator = (b6 >> 2) & 0x01; 489 | pes_priority = (b6 >> 3) & 0x01; 490 | pes_scrambling_control = (b6 >> 4) & 0x03; 491 | marker_bits = (b6 >> 6) & 0x03; 492 | 493 | uint8_t b7 = sb->read_1byte(); 494 | pes_ext_flag = b7 & 0x01; 495 | pes_crc_flag = (b7 >> 1) & 0x01; 496 | add_copy_info_flag = (b7 >> 2) & 0x01; 497 | dsm_trick_mode_flag = (b7 >> 3) & 0x01; 498 | es_rate_flag = (b7 >> 4) & 0x01; 499 | escr_flag = (b7 >> 5) & 0x01; 500 | pts_dts_flags = (b7 >> 6) & 0x03; 501 | 502 | header_data_length = sb->read_1byte(); 503 | } 504 | -------------------------------------------------------------------------------- /mpegts/mpegts/ts_packet.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | class SimpleBuffer; 9 | 10 | class MpegTsStream 11 | { 12 | public: 13 | static const uint8_t AAC = 0x0f; 14 | static const uint8_t AVC = 0x1b; 15 | }; 16 | 17 | class TsFrame 18 | { 19 | public: 20 | TsFrame(); 21 | TsFrame(uint8_t st); 22 | virtual ~TsFrame(){}; 23 | 24 | public: 25 | bool empty(); 26 | void reset(); 27 | 28 | public: 29 | std::shared_ptr _data; 30 | uint64_t pts; 31 | uint64_t dts; 32 | uint64_t pcr; 33 | uint8_t stream_type; 34 | uint8_t stream_id; 35 | uint16_t pid; 36 | uint16_t expected_pes_packet_length; 37 | bool completed; 38 | }; 39 | 40 | class TsHeader 41 | { 42 | public: 43 | TsHeader(); 44 | virtual ~TsHeader(); 45 | 46 | public: 47 | void encode(SimpleBuffer *sb); 48 | void decode(SimpleBuffer *sb); 49 | 50 | public: 51 | uint8_t sync_byte; // 8 bits 52 | uint8_t transport_error_indicator; // 1 bit 53 | uint8_t payload_unit_start_indicator; // 1 bit 54 | uint8_t transport_priority; // 1 bit 55 | uint16_t pid; // 13 bits 56 | uint8_t transport_scrambling_control; // 2 bits 57 | uint8_t adaptation_field_control; // 2 bits 58 | uint8_t continuity_counter; // 4 bits 59 | }; 60 | 61 | class PATHeader 62 | { 63 | public: 64 | PATHeader(); 65 | virtual ~PATHeader(); 66 | 67 | public: 68 | void encode(SimpleBuffer *sb); 69 | void decode(SimpleBuffer *sb); 70 | void print(); 71 | 72 | public: 73 | uint8_t table_id; // 8 bits 74 | uint8_t section_syntax_indicator; // 1 bit 75 | uint8_t b0; // 1 bit 76 | uint8_t reserved0; // 2 bits 77 | uint16_t section_length; // 12 bits 78 | uint16_t transport_stream_id; // 16 bits 79 | uint8_t reserved1; // 2 bits 80 | uint8_t version_number; // 5 bits 81 | uint8_t current_next_indicator; // 1 bit 82 | uint8_t section_number; // 8 bits 83 | uint8_t last_section_number; // 8 bits 84 | }; 85 | 86 | class PMTElementInfo 87 | { 88 | public: 89 | PMTElementInfo(); 90 | PMTElementInfo(uint8_t st, uint16_t pid); 91 | virtual ~PMTElementInfo(); 92 | 93 | public: 94 | void encode(SimpleBuffer *sb); 95 | void decode(SimpleBuffer *sb); 96 | uint16_t size(); 97 | void print(); 98 | 99 | public: 100 | uint8_t stream_type; // 8 bits 101 | uint8_t reserved0; // 3 bits 102 | uint16_t elementary_PID; // 13 bits 103 | uint8_t reserved1; // 4 bits 104 | uint16_t ES_info_length; // 12 bits 105 | std::string ES_info; 106 | }; 107 | 108 | class PMTHeader 109 | { 110 | public: 111 | PMTHeader(); 112 | virtual ~PMTHeader(); 113 | 114 | public: 115 | void encode(SimpleBuffer *sb); 116 | void decode(SimpleBuffer *sb); 117 | uint16_t size(); 118 | void print(); 119 | 120 | public: 121 | uint8_t table_id; // 8 bits 122 | uint8_t section_syntax_indicator; // 1 bit 123 | uint8_t b0; // 1 bit 124 | uint8_t reserved0; // 2 bits 125 | uint16_t section_length; // 12 bits 126 | uint16_t program_number; // 16 bits 127 | uint8_t reserved1; // 2 bits 128 | uint8_t version_number; // 5 bits 129 | uint8_t current_next_indicator; // 1 bit 130 | uint8_t section_number; // 8 bits 131 | uint8_t last_section_number; // 8 bits 132 | uint8_t reserved2; // 3 bits 133 | uint16_t PCR_PID; // 13 bits 134 | uint8_t reserved3; // 4 bits 135 | uint16_t program_info_length; // 12 bits 136 | std::vector> infos; 137 | }; 138 | 139 | class AdaptationFieldHeader 140 | { 141 | public: 142 | AdaptationFieldHeader(); 143 | virtual ~AdaptationFieldHeader(); 144 | 145 | public: 146 | void encode(SimpleBuffer *sb); 147 | void decode(SimpleBuffer *sb); 148 | 149 | public: 150 | uint8_t adaptation_field_length; // 8 bits 151 | uint8_t adaptation_field_extension_flag; // 1 bit 152 | uint8_t transport_private_data_flag; // 1 bit 153 | uint8_t splicing_point_flag; // 1 bit 154 | uint8_t opcr_flag; // 1 bit 155 | uint8_t pcr_flag; // 1 bit 156 | uint8_t elementary_stream_priority_indicator; // 1 bit 157 | uint8_t random_access_indicator; // 1 bit 158 | uint8_t discontinuity_indicator; // 1 bit 159 | }; 160 | 161 | class PESHeader 162 | { 163 | public: 164 | PESHeader(); 165 | virtual ~PESHeader(); 166 | 167 | public: 168 | void encode(SimpleBuffer *sb); 169 | void decode(SimpleBuffer *sb); 170 | 171 | public: 172 | uint32_t packet_start_code; // 24 bits 173 | uint8_t stream_id; // 8 bits 174 | uint16_t pes_packet_length; // 16 bits 175 | uint8_t original_or_copy; // 1 bit 176 | uint8_t copyright; // 1 bit 177 | uint8_t data_alignment_indicator; // 1 bit 178 | uint8_t pes_priority; // 1 bit 179 | uint8_t pes_scrambling_control; // 2 bits 180 | uint8_t marker_bits; // 2 bits 181 | uint8_t pes_ext_flag; // 1 bit 182 | uint8_t pes_crc_flag; // 1 bit 183 | uint8_t add_copy_info_flag; // 1 bit 184 | uint8_t dsm_trick_mode_flag; // 1 bit 185 | uint8_t es_rate_flag; // 1 bit 186 | uint8_t escr_flag; // 1 bit 187 | uint8_t pts_dts_flags; // 2 bits 188 | uint8_t header_data_length; // 8 bits 189 | }; 190 | --------------------------------------------------------------------------------