/** g++ -o ts_info ts_info.cpp -g -O0 -ansi */ #if 1 // for int64_t print using PRId64 format. #ifndef __STDC_FORMAT_MACROS #define __STDC_FORMAT_MACROS #endif #include #include #include #include #include #include #include #include #include #define trace(msg, ...) printf(msg"\n", ##__VA_ARGS__); #define srs_freep(p) delete p; p = NULL #define srs_freepa(p) delete[] p; p = NULL #define srs_assert(p) assert(p) #endif /** ISO/IEC 13818-1:2000(E) Introduction Intro. 1 Transport Stream Intro. 2 Program Stream Intro. 4 Packetized Elementary Stream SECTION 2 ¨C TECHNICAL ELEMENTS 2.4 Transport Stream bitstream requirements 2.4.1 Transport Stream coding structure and parameters 2.4.2 Transport Stream system target decoder 2.4.3 Specification of the Transport Stream syntax and semantics 2.4.3.1 Transport Stream 2.4.3.2 Transport Stream packet layer 2.4.3.3 Semantic definition of fields in Transport Stream packet layer 2.4.3.5 Semantic definition of fields in adaptation field 2.4.3.6 PES packet 2.4.3.7 Semantic definition of fields in PES packet 2.4.4 Program specific information 2.4.4.5 Semantic definition of fields in program association section 2.4.4.6 Conditional access Table 2.5 Program Stream bitstream requirements 2.6 Program and program element descriptors 2.7 Restrictions on the multiplexed stream semantics Annex A ¨C CRC Decoder Model */ #if 1 // Transport Stream packets are 188 bytes in length. #define TS_PACKET_SIZE 188 // Program Association Table(see Table 2-25). #define PID_PAT 0x00 // Conditional Access Table (see Table 2-27). #define PID_CAT 0x01 // Transport Stream Description Table #define PID_TSDT 0x02 // null packets (see Table 2-3) #define PID_NULL 0x01FFF /*adaptation_field_control*/ // No adaptation_field, payload only #define AFC_PAYLOAD_ONLY 0x01 // Adaptation_field only, no payload #define AFC_ADAPTION_ONLY 0x02 // Adaptation_field followed by payload #define AFC_BOTH 0x03 #endif // Table 2-29 – Stream type assignments. page 66. enum TSStreamType { /*defined by ffmpeg*/ TSStreamTypeVideoMpeg1 = 0x01, TSStreamTypeVideoMpeg2 = 0x02, TSStreamTypeAudioMpeg1 = 0x03, TSStreamTypeAudioMpeg2 = 0x04, TSStreamTypePrivateSection = 0x05, TSStreamTypePrivateData = 0x06, TSStreamTypeAudioAAC = 0x0f, TSStreamTypeVideoMpeg4 = 0x10, TSStreamTypeVideoH264 = 0x1b, TSStreamTypeAudioAC3 = 0x81, TSStreamTypeAudioDTS = 0x8a, }; /** * the actually parsed type. */ enum TSPidType { TSPidTypeReserved = 0, // TSPidTypeReserved, nothing parsed, used reserved. TSPidTypePAT, // Program associtate table TSPidTypePMT, // Program map table. TSPidTypeVideo, TSPidTypeAudio, }; // forward declares. class TSHeader; class TSAdaptionField; class TSPayload; class TSPayloadReserved; class TSPayloadPAT; class TSPayloadPMT; class TSPayloadPES; class TSContext; // TSPacket declares. class TSPacket { public: TSHeader* header; TSAdaptionField* adaption_field; TSPayload* payload; TSPacket(); virtual ~TSPacket(); int demux(TSContext* ctx, u_int8_t* start, u_int8_t* last, u_int8_t*& p); int finish(); }; // TSHeader declares. class TSHeader { public: // 1B int8_t sync_byte; //8bits // 2B int8_t transport_error_indicator; //1bit int8_t payload_unit_start_indicator; //1bit int8_t transport_priority; //1bit u_int16_t pid; //13bits // 1B int8_t transport_scrambling_control; //2bits int8_t adaption_field_control; //2bits u_int8_t continuity_counter; //4bits TSHeader(); virtual ~TSHeader(); int get_size(); int demux(TSContext* ctx, TSPacket* pkt, u_int8_t* start, u_int8_t* last, u_int8_t*& p); }; // variant ts packet adation field. page 40. class TSAdaptionField { public: // 1B u_int8_t adaption_field_length; //8bits // 1B int8_t discontinuity_indicator; //1bit int8_t random_access_indicator; //1bit int8_t elementary_stream_priority_indicator; //1bit int8_t PCR_flag; //1bit int8_t OPCR_flag; //1bit int8_t splicing_point_flag; //1bit int8_t transport_private_data_flag; //1bit int8_t adaptation_field_extension_flag; //1bit // if PCR_flag, 6B int64_t program_clock_reference_base; //33bits //6bits reserved. int16_t program_clock_reference_extension; //9bits // if OPCR_flag, 6B int64_t original_program_clock_reference_base; //33bits //6bits reserved. int16_t original_program_clock_reference_extension; //9bits // if splicing_point_flag, 1B int8_t splice_countdown; //8bits // if transport_private_data_flag, 1+p[0] B u_int8_t transport_private_data_length; //8bits char* transport_private_data; //[transport_private_data_length]bytes // if adaptation_field_extension_flag, 2+x bytes u_int8_t adaptation_field_extension_length; //8bits int8_t ltw_flag; //1bit int8_t piecewise_rate_flag; //1bit int8_t seamless_splice_flag; //1bit //5bits reserved // if ltw_flag, 2B int8_t ltw_valid_flag; //1bit int16_t ltw_offset; //15bits // if piecewise_rate_flag, 3B //2bits reserved int32_t piecewise_rate; //22bits // if seamless_splice_flag, 5B int8_t splice_type; //4bits int8_t DTS_next_AU0; //3bits int8_t marker_bit0; //1bit int16_t DTS_next_AU1; //15bits int8_t marker_bit1; //1bit int16_t DTS_next_AU2; //15bits int8_t marker_bit2; //1bit // left bytes. char* af_ext_reserved; // left bytes. char* af_reserved; // user defined data size. int __user_size; TSAdaptionField(); virtual ~TSAdaptionField(); int get_size(); int demux(TSContext* ctx, TSPacket* pkt, u_int8_t* start, u_int8_t* last, u_int8_t*& p); }; // variant ts packet payload. // PES packet or PSI table. // TSPayloadPAT: page 61. class TSPayload { public: /** * the size of payload(payload plush the 1byte pointer_field). */ int size; int pointer_field_size; TSPidType type; /** * 2.4.4.2 Semantics definition of fields in pointer syntax */ u_int8_t pointer_field; TSPayloadReserved* reserved; TSPayloadPAT* pat; TSPayloadPMT* pmt; TSPayloadPES* pes; /** * 2.4.3.6 PES packet. page 49. */ TSPayload(); virtual ~TSPayload();; void read_pointer_field(TSPacket* pkt, u_int8_t*& p); int demux(TSContext* ctx, TSPacket* pkt, u_int8_t* start, u_int8_t* last, u_int8_t*& p); }; /** * 2.4.4.3 Program association Table. page 61. */ class TSPayloadPAT { public: // 1B u_int8_t table_id; //8bits // 2B int8_t section_syntax_indicator; //1bit int8_t const0_value; //1bit // 2bits reserved. u_int16_t section_length; //12bits // 2B u_int16_t transport_stream_id; //16bits // 1B // 2bits reerverd. int8_t version_number; //5bits int8_t current_next_indicator; //1bit // 1B u_int8_t section_number; //8bits // 1B u_int8_t last_section_number; //8bits // multiple 4B program data. // program_number 16bits // reserved 2bits // 13bits data: 0x1FFF // if program_number program_map_PID 13bits // else network_PID 13bytes. int program_size; int32_t* programs; //32bits // 4B int32_t CRC_32; //32bits TSPayloadPAT(); virtual ~TSPayloadPAT(); int demux(TSContext* ctx, TSPacket* pkt, u_int8_t* start, u_int8_t* last, u_int8_t*& p); }; class TSPMTESInfo { public: // 1B u_int8_t stream_type; //8bits // 2B // 3bits reserved int16_t elementary_PID; //13bits // 2B // 4bits reserved int16_t ES_info_length; //12bits char* ES_info; //[ES_info_length] bytes. TSPMTESInfo(); virtual ~TSPMTESInfo(); }; /** * 2.4.4.8 Program Map Table. page 64. */ class TSPayloadPMT { public: // 1B u_int8_t table_id; //8bits // 2B int8_t section_syntax_indicator; //1bit int8_t const0_value; //1bit // 2bits reserved. u_int16_t section_length; //12bits // 2B u_int16_t program_number; //16bits // 1B // 2bits reerverd. int8_t version_number; //5bits int8_t current_next_indicator; //1bit // 1B u_int8_t section_number; //8bits // 1B u_int8_t last_section_number; //8bits // 2B // 2bits reserved. int16_t PCR_PID; //16bits // 2B // 4bits reserved. int16_t program_info_length; //12bits char* program_info_desc; //[program_info_length]bytes // array of TSPMTESInfo. std::vector ES_info; // 4B int32_t CRC_32; //32bits TSPayloadPMT(); virtual ~TSPayloadPMT(); int demux(TSContext* ctx, TSPacket* pkt, u_int8_t* start, u_int8_t* last, u_int8_t*& p); }; /** * Table 2-18 – Stream_id assignments. page 52. */ enum TSPESStreamId { PES_program_stream_map = 0b10111100, PES_private_stream_1 = 0b10111101, PES_padding_stream = 0b10111110, PES_private_stream_2 = 0b10111111, // 110x xxxx // ISO/IEC 13818-3 or ISO/IEC 11172-3 or ISO/IEC 13818-7 or ISO/IEC // 14496-3 audio stream number x xxxx // (stream_id>>5)&0x07 == PES_audio_prefix PES_audio_prefix = 0b110, // 1110 xxxx // ITU-T Rec. H.262 | ISO/IEC 13818-2 or ISO/IEC 11172-2 or ISO/IEC // 14496-2 video stream number xxxx // (stream_id>>5)&0x07 == PES_audio_prefix PES_video_prefix = 0b1110, PES_ECM_stream = 0b11110000, PES_EMM_stream = 0b11110001, PES_DSMCC_stream = 0b11110010, PES_13522_stream = 0b11110011, PES_H_222_1_type_A = 0b11110100, PES_H_222_1_type_B = 0b11110101, PES_H_222_1_type_C = 0b11110110, PES_H_222_1_type_D = 0b11110111, PES_H_222_1_type_E = 0b11111000, PES_ancillary_stream = 0b11111001, PES_SL_packetized_stream = 0b11111010, PES_FlexMux_stream = 0b11111011, // reserved data stream // 1111 1100 … 1111 1110 PES_program_stream_directory= 0b11111111, }; /** * 2.4.3.7 Semantic definition of fields in PES packet. page 49. */ class TSPayloadPES { public: // 3B int32_t packet_start_code_prefix; //24bits // 1B u_int8_t stream_id; //8bits // 2B u_int16_t PES_packet_length; //16bits // 1B // 2bits const '10' int8_t PES_scrambling_control; //2bits int8_t PES_priority; //1bit int8_t data_alignment_indicator; //1bit int8_t copyright; //1bit int8_t original_or_copy; //1bit // 1B int8_t PTS_DTS_flags; //2bits int8_t ESCR_flag; //1bit int8_t ES_rate_flag; //1bit int8_t DSM_trick_mode_flag; //1bit int8_t additional_copy_info_flag; //1bit int8_t PES_CRC_flag; //1bit int8_t PES_extension_flag; //1bit // 1B u_int8_t PES_header_data_length; //8bits /** * logic data. */ // generated by PTS_DTS_flags int64_t pts; // 33bits int64_t dts; // 33bits TSPayloadPES(); virtual ~TSPayloadPES(); int demux(TSContext* ctx, TSPacket* pkt, u_int8_t* start, u_int8_t* last, u_int8_t*& p); }; class TSPayloadReserved { public: int size; char* bytes; TSPayloadReserved(); virtual ~TSPayloadReserved(); int demux(TSContext* ctx, TSPacket* pkt, u_int8_t* start, u_int8_t* last, u_int8_t*& p); }; struct TSPid { TSPidType type; int16_t pid; }; // ts context class TSContext { public: /** * consumed pids. */ int pid_size; TSPid* pids; TSContext(); virtual ~TSContext(); bool exists(int16_t pid); TSPid* get(int16_t pid); void push(TSPidType type, int16_t pid); }; TSContext::TSContext() { pid_size = 0; pids = NULL; } TSContext::~TSContext() { srs_freepa(pids); } bool TSContext::exists(int16_t pid) { for (int i = 0; i < pid_size; i++) { if (pid == pids[i].pid) { return true; } } return false; } TSPid* TSContext::get(int16_t pid) { for (int i = 0; i < pid_size; i++) { if (pid == pids[i].pid) { return &pids[i]; } } return NULL; } void TSContext::push(TSPidType type, int16_t pid) { if (exists(pid)) { return; } TSPid* p = new TSPid[pid_size + 1]; memcpy(p, pids, sizeof(TSPid) * pid_size); p[pid_size] = (TSPid){type, pid}; pid_size++; srs_freepa(pids); pids = p; } TSAdaptionField::TSAdaptionField() { transport_private_data = NULL; af_ext_reserved = NULL; af_reserved = NULL; __user_size = 0; } TSAdaptionField::~TSAdaptionField() { srs_freepa(transport_private_data); srs_freepa(af_ext_reserved); srs_freepa(af_reserved); } int TSAdaptionField::get_size() { return __user_size; } int TSAdaptionField::demux(TSContext* ctx, TSPacket* pkt, u_int8_t* start, u_int8_t* last, u_int8_t*& p) { int ret = 0; adaption_field_length = *p++; u_int8_t* pos_af = p; __user_size = 1 + adaption_field_length; if (adaption_field_length <= 0) { trace("ts+af empty af decoded."); return ret; } int8_t value = *p++; discontinuity_indicator = (value >> 7) & 0x01; random_access_indicator = (value >> 6) & 0x01; elementary_stream_priority_indicator = (value >> 5) & 0x01; PCR_flag = (value >> 4) & 0x01; OPCR_flag = (value >> 3) & 0x01; splicing_point_flag = (value >> 2) & 0x01; transport_private_data_flag = (value >> 1) & 0x01; adaptation_field_extension_flag = (value >> 0) & 0x01; trace("ts+af af flags parsed, discontinuity: %d random: %d priority: %d PCR: %d OPCR: %d slicing: %d private: %d extension: %d", discontinuity_indicator, random_access_indicator, elementary_stream_priority_indicator, PCR_flag, OPCR_flag, splicing_point_flag, transport_private_data_flag, adaptation_field_extension_flag); char* pp = NULL; if (PCR_flag) { pp = (char*)&program_clock_reference_base; pp[5] = *p++; pp[4] = *p++; pp[3] = *p++; pp[2] = *p++; pp[1] = *p++; pp[0] = *p++; program_clock_reference_extension = program_clock_reference_base & 0x1F; program_clock_reference_base = (program_clock_reference_base >> 9) & 0x1FFFFFFFF; } if (OPCR_flag) { pp = (char*)&original_program_clock_reference_base; pp[5] = *p++; pp[4] = *p++; pp[3] = *p++; pp[2] = *p++; pp[1] = *p++; pp[0] = *p++; original_program_clock_reference_extension = original_program_clock_reference_base & 0x1F; original_program_clock_reference_base = (original_program_clock_reference_base >> 9) & 0x1FFFFFFFF; } if (splicing_point_flag) { splice_countdown = *p++; } if (transport_private_data_flag) { transport_private_data_length = *p++; transport_private_data = new char[transport_private_data_length]; for (int i = 0; i < transport_private_data_length; i++) { transport_private_data[i] = *p++; } } if (adaptation_field_extension_flag) { adaptation_field_extension_length = *p++; u_int8_t* pos_af_ext = p; ltw_flag = *p++; piecewise_rate_flag = (ltw_flag >> 6) & 0x01; seamless_splice_flag = (ltw_flag >> 5) & 0x01; ltw_flag = (ltw_flag >> 7) & 0x01; if (ltw_flag) { pp = (char*)<w_offset; pp[1] = *p++; pp[0] = *p++; ltw_valid_flag = (ltw_offset >> 15) &0x01; ltw_offset &= 0x7FFF; } if (piecewise_rate_flag) { pp = (char*)&piecewise_rate; pp[2] = *p++; pp[1] = *p++; pp[0] = *p++; piecewise_rate &= 0x3FFFFF; } if (seamless_splice_flag) { // 1B marker_bit0 = *p++; splice_type = (marker_bit0 >> 4) & 0x0F; DTS_next_AU0 = (marker_bit0 >> 1) & 0x07; marker_bit0 &= 0x01; // 2B pp = (char*)&DTS_next_AU1; pp[1] = *p++; pp[0] = *p++; marker_bit1 = DTS_next_AU1 & 0x01; DTS_next_AU1 = (DTS_next_AU1 >> 1) & 0x7FFF; // 2B pp = (char*)&DTS_next_AU2; pp[1] = *p++; pp[0] = *p++; marker_bit2 = DTS_next_AU2 & 0x01; DTS_next_AU2 = (DTS_next_AU2 >> 1) & 0x7FFF; } // af_ext_reserved int ext_size = adaptation_field_extension_length - (p - pos_af_ext); if (ext_size > 0) { af_ext_reserved = new char[ext_size]; memcpy(af_ext_reserved, p, ext_size); p += ext_size; } } // af_reserved int af_size = adaption_field_length - (p - pos_af); if (af_size > 0) { af_reserved = new char[af_size]; memcpy(af_reserved, p, af_size); p += af_size; } return ret; } TSPayloadReserved::TSPayloadReserved() { size = 0; bytes = NULL; } TSPayloadReserved::~TSPayloadReserved() { srs_freepa(bytes); } int TSPayloadReserved::demux(TSContext* ctx, TSPacket* pkt, u_int8_t* start, u_int8_t* last, u_int8_t*& p) { int ret = 0; size = pkt->payload->size - pkt->payload->pointer_field_size; // not parsed bytes. if (size > 0) { bytes = new char[size]; memcpy(bytes, p, size); p += size; } return ret; } TSPayloadPAT::TSPayloadPAT() { programs = NULL; } TSPayloadPAT::~TSPayloadPAT() { srs_freepa(programs); } int TSPayloadPAT::demux(TSContext* ctx, TSPacket* pkt, u_int8_t* start, u_int8_t* last, u_int8_t*& p) { int ret = 0; table_id = *p++; char* pp = (char*)§ion_length; pp[1] = *p++; pp[0] = *p++; u_int8_t* pos = p; section_syntax_indicator = (section_length >> 15) & 0x01; const0_value = (section_length >> 14) & 0x01; section_length &= 0x0FFF; pp = (char*)&transport_stream_id; pp[1] = *p++; pp[0] = *p++; current_next_indicator = *p++; version_number = (current_next_indicator >> 1) & 0x1F; current_next_indicator &= 0x01; section_number = *p++; last_section_number = *p++; // 4 is crc size. int program_bytes = section_length - 4 - (p - pos); program_size = program_bytes / 4; if (program_size > 0) { programs = new int32_t[program_size]; for (int i = 0; i < program_size; i++) { pp = (char*)&programs[i]; pp[3] = *p++; pp[2] = *p++; pp[1] = *p++; pp[0] = *p++; int16_t pid = programs[i] & 0x1FFF; ctx->push(TSPidTypePMT, pid); } } pp = (char*)&CRC_32; pp[3] = *p++; pp[2] = *p++; pp[1] = *p++; pp[0] = *p++; return ret; } TSPMTESInfo::TSPMTESInfo() { ES_info_length = 0; ES_info = NULL; } TSPMTESInfo::~TSPMTESInfo() { srs_freepa(ES_info); } TSPayloadPMT::TSPayloadPMT() { program_info_length = 0; program_info_desc = NULL; } TSPayloadPMT::~TSPayloadPMT() { srs_freepa(program_info_desc); for (std::vector::iterator it = ES_info.begin(); it != ES_info.end(); ++it) { TSPMTESInfo* info = *it; srs_freep(info); } ES_info.clear(); } int TSPayloadPMT::demux(TSContext* ctx, TSPacket* pkt, u_int8_t* start, u_int8_t* last, u_int8_t*& p) { int ret = 0; table_id = *p++; char* pp = (char*)§ion_length; pp[1] = *p++; pp[0] = *p++; u_int8_t* pos = p; section_syntax_indicator = (section_length >> 15) & 0x01; const0_value = (section_length >> 14) & 0x01; section_length &= 0x0FFF; pp = (char*)&program_number; pp[1] = *p++; pp[0] = *p++; current_next_indicator = *p++; version_number = (current_next_indicator >> 1) & 0x1F; current_next_indicator &= 0x01; section_number = *p++; last_section_number = *p++; pp = (char*)&PCR_PID; pp[1] = *p++; pp[0] = *p++; PCR_PID &= 0x1FFF; pp = (char*)&program_info_length; pp[1] = *p++; pp[0] = *p++; program_info_length &= 0xFFF; if (program_info_length > 0) { program_info_desc = new char[program_info_length]; memcpy(program_info_desc, p, program_info_length); p += program_info_length; } // [section_length] - 4(CRC) - 9B - [program_info_length] int ES_bytes = section_length - 4 - 9 - program_info_length; while (ES_bytes > 0) { TSPMTESInfo* info = new TSPMTESInfo(); info->stream_type = *p++; ES_bytes--; pp = (char*)&info->elementary_PID; pp[1] = *p++; pp[0] = *p++; ES_bytes -= 2; info->elementary_PID &= 0x1FFF; pp = (char*)&info->ES_info_length; pp[1] = *p++; pp[0] = *p++; ES_bytes -= 2; info->ES_info_length &= 0x0FFF; if (info->ES_info_length > 0) { info->ES_info = new char[info->ES_info_length]; memcpy(info->ES_info, p, info->ES_info_length); p += info->ES_info_length; ES_bytes -= info->ES_info_length; } ES_info.push_back(info); // TODO: support more video type. if (info->stream_type == TSStreamTypeVideoH264) { ctx->push(TSPidTypeVideo, info->elementary_PID); } // TODO: support more audio type. if (info->stream_type == TSStreamTypeAudioAAC) { ctx->push(TSPidTypeAudio, info->elementary_PID); } } pp = (char*)&CRC_32; pp[3] = *p++; pp[2] = *p++; pp[1] = *p++; pp[0] = *p++; return ret; } TSPayloadPES::TSPayloadPES() { pts = dts = 0; } TSPayloadPES::~TSPayloadPES() { } int TSPayloadPES::demux(TSContext* ctx, TSPacket* pkt, u_int8_t* start, u_int8_t* last, u_int8_t*& p) { int ret = 0; char* pp = (char*)&packet_start_code_prefix; pp[2] = *p++; pp[1] = *p++; pp[0] = *p++; packet_start_code_prefix &= 0xFFFFFF; stream_id = *p++; pp = (char*)&PES_packet_length; pp[1] = *p++; pp[0] = *p++; if (stream_id != PES_program_stream_map && stream_id != PES_padding_stream && stream_id != PES_private_stream_2 && stream_id != PES_ECM_stream && stream_id != PES_EMM_stream && stream_id != PES_program_stream_directory && stream_id != PES_DSMCC_stream && stream_id != PES_H_222_1_type_E ) { original_or_copy = *p++; //int8_t const2bits = (original_or_copy >> 6) & 0x03; PES_scrambling_control = (original_or_copy >> 4) & 0x03; PES_priority = (original_or_copy >> 3) & 0x01; data_alignment_indicator = (original_or_copy >> 2) & 0x01; copyright = (original_or_copy >> 1) & 0x01; original_or_copy &= 0x01; PES_extension_flag = *p++; PTS_DTS_flags = (PES_extension_flag >> 6) & 0x03; ESCR_flag = (PES_extension_flag >> 5) & 0x01; ES_rate_flag = (PES_extension_flag >> 4) & 0x01; DSM_trick_mode_flag = (PES_extension_flag >> 3) & 0x01; additional_copy_info_flag = (PES_extension_flag >> 2) & 0x01; PES_CRC_flag = (PES_extension_flag >> 1) & 0x01; PES_extension_flag &= 0x01; PES_header_data_length = *p++; if (PTS_DTS_flags == 0x2) { int64_t temp = 0; pp = (char*)&temp; pp[4] = *p++; pp[3] = *p++; pp[2] = *p++; pp[1] = *p++; pp[0] = *p++; // marker_bit 1bit temp = temp >> 1; // PTS [14..0] 15bits pts |= temp & 0x3FFF; // marker_bit 1bit temp = temp >> 1; // PTS [29..15] 15bits pts |= temp & 0x3fff8000; // marker_bit 1bit temp = temp >> 1; // PTS [32..30] 3bits pts |= temp & 0x1c0000000; // '0010' 4bits //int8_t const4bits = (temp >> 32) & 0x0F; } if (PTS_DTS_flags == 0x3) { int64_t temp = 0; pp = (char*)&temp; pp[4] = *p++; pp[3] = *p++; pp[2] = *p++; pp[1] = *p++; pp[0] = *p++; // marker_bit 1bit temp = temp >> 1; // PTS [14..0] 15bits pts |= temp & 0x3FFF; // marker_bit 1bit temp = temp >> 1; // PTS [29..15] 15bits pts |= temp & 0x3fff8000; // marker_bit 1bit temp = temp >> 1; // PTS [32..30] 3bits pts |= temp & 0x1c0000000; // '0010' 4bits //int8_t const4bits = (temp >> 32) & 0x0F; pp = (char*)&temp; pp[4] = *p++; pp[3] = *p++; pp[2] = *p++; pp[1] = *p++; pp[0] = *p++; // marker_bit 1bit temp = temp >> 1; // PTS [14..0] 15bits dts |= temp & 0x3FFF; // marker_bit 1bit temp = temp >> 1; // PTS [29..15] 15bits dts |= temp & 0x3fff8000; // marker_bit 1bit temp = temp >> 1; // PTS [32..30] 3bits dts |= temp & 0x1c0000000; // '0010' 4bits //int8_t const4bits = (temp >> 32) & 0x0F; } if (ESCR_flag) { } } else if (stream_id == PES_program_stream_map || stream_id == PES_private_stream_2 || stream_id == PES_ECM_stream || stream_id == PES_EMM_stream || stream_id == PES_program_stream_directory || stream_id == PES_DSMCC_stream || stream_id == PES_H_222_1_type_E ) { // for (i = 0; i < PES_packet_length; i++) { // PES_packet_data_byte // } } else if (stream_id != PES_padding_stream) { // for (i = 0; i < PES_packet_length; i++) { // padding_byte // } } trace("ts+pes stream_id: %d size: %d pts: %"PRId64" dts: %"PRId64"", stream_id, PES_packet_length, pts, dts); return ret; } /** * 2.4.3.6 PES packet. page 49. */ TSPayload::TSPayload() { size = 0; pointer_field_size = 0; type = TSPidTypeReserved; reserved = NULL; pat = NULL; pmt = NULL; pes = NULL; } TSPayload::~TSPayload() { srs_freep(reserved); srs_freep(pat); srs_freep(pmt); srs_freep(pes); } void TSPayload::read_pointer_field(TSPacket* pkt, u_int8_t*& p) { if (pkt->header->payload_unit_start_indicator) { pointer_field = *p++; pointer_field_size = 1; } } int TSPayload::demux(TSContext* ctx, TSPacket* pkt, u_int8_t* start, u_int8_t* last, u_int8_t*& p) { int ret = 0; if (pkt->header->pid == PID_PAT) { read_pointer_field(pkt, p); type = TSPidTypePAT; pat = new TSPayloadPAT(); return pat->demux(ctx, pkt, start, last, p); } TSPid* pid = ctx->get(pkt->header->pid); if (pid && pid->type == TSPidTypePMT) { read_pointer_field(pkt, p); type = pid->type; pmt = new TSPayloadPMT(); return pmt->demux(ctx, pkt, start, last, p); } if (pid && (pid->type == TSPidTypeVideo || pid->type == TSPidTypeAudio)) { type = pid->type; pes = new TSPayloadPES(); return pes->demux(ctx, pkt, start, last, p); } // not parsed bytes. type = TSPidTypeReserved; reserved = new TSPayloadReserved(); if ((ret = reserved->demux(ctx, pkt, start, last, p)) != 0) { return ret; } return ret; } TSPacket::TSPacket() { header = new TSHeader(); adaption_field = new TSAdaptionField(); payload = new TSPayload(); } TSPacket::~TSPacket() { srs_freep(header); srs_freep(adaption_field); srs_freep(payload); } int TSPacket::demux(TSContext* ctx, u_int8_t* start, u_int8_t* last, u_int8_t*& p) { int ret = 0; if ((ret = header->demux(ctx, this, start, last, p)) != 0) { return ret; } if (header->adaption_field_control == AFC_ADAPTION_ONLY || header->adaption_field_control == AFC_BOTH) { if ((ret = adaption_field->demux(ctx, this, start, last, p)) != 0) { trace("ts+header af(adaption field) decode error. ret=%d", ret); return ret; } trace("ts+header af(adaption field) decoded."); } // calc the user defined data size for payload. payload->size = TS_PACKET_SIZE - header->get_size() - adaption_field->get_size(); if (header->adaption_field_control == AFC_PAYLOAD_ONLY || header->adaption_field_control == AFC_BOTH) { if ((ret = payload->demux(ctx, this, start, last, p)) != 0) { trace("ts+header payload decode error. ret=%d", ret); return ret; } trace("ts+header payload decoded."); } trace("ts+header parsed finished. parsed: %d left: %d header: %d payload: %d(%d+%d)", (int)(p - start), (int)(last - p), header->get_size(), payload->size, payload->pointer_field_size, payload->size - payload->pointer_field_size); return finish(); } int TSPacket::finish() { return 0; } TSHeader::TSHeader() { } TSHeader::~TSHeader() { } int TSHeader::get_size() { return 4; } int TSHeader::demux(TSContext* ctx, TSPacket* pkt, u_int8_t* start, u_int8_t* last, u_int8_t*& p) { int ret = 0; // ts packet header. sync_byte = *p++; if (sync_byte != 0x47) { trace("ts+sync_bytes invalid sync_bytes: %#x, expect is 0x47", sync_byte); return -1; } pid = 0; ((char*)&pid)[1] = *p++; ((char*)&pid)[0] = *p++; transport_error_indicator = (pid >> 15) & 0x01; payload_unit_start_indicator = (pid >> 14) & 0x01; transport_priority = (pid >> 13) & 0x01; pid &= 0x1FFF; ctx->push(TSPidTypePAT, pid); continuity_counter = *p++; transport_scrambling_control = (continuity_counter >> 6) & 0x03; adaption_field_control = (continuity_counter >> 4) & 0x03; continuity_counter &= 0x0F; trace("ts+header sync: %#x error: %d unit_start: %d priotiry: %d pid: %d scrambling: %d adaption: %d counter: %d", sync_byte, transport_error_indicator, payload_unit_start_indicator, transport_priority, pid, transport_scrambling_control, adaption_field_control, continuity_counter); return ret; } int main(int /*argc*/, char** /*argv*/) { const char* file = "livestream-1347.ts"; //file = "nginx-rtmp-hls/livestream-1347-currupt.ts"; int fd = open(file, O_RDONLY); int ret = 0; trace("demuxer+read packet count offset T+0 T+1 T+2 T+3 T+x T+L2 T+L1 T+L0"); TSContext ctx; for (int i = 0, offset = 0; ; i++) { u_int8_t ts_packet[TS_PACKET_SIZE]; memset(ts_packet, 0, sizeof(ts_packet)); int nread = read(fd, ts_packet, sizeof(ts_packet)); if (nread == 0) { trace("demuxer+read got EOF, read completed, offset: %07d.", offset); break; } if (nread != TS_PACKET_SIZE) { trace("demuxer+read error to read ts packet. nread=%d", nread); break; } trace("demuxer+read packet %04d %07d 0x%02x 0x%02x 0x%02x 0x%02x ... 0x%02x 0x%02x 0x%02x", i, offset, ts_packet[0], ts_packet[1], ts_packet[2], ts_packet[3], ts_packet[TS_PACKET_SIZE - 3], ts_packet[TS_PACKET_SIZE - 2], ts_packet[TS_PACKET_SIZE - 1]); u_int8_t* p = ts_packet; u_int8_t* start = ts_packet; u_int8_t* last = ts_packet + TS_PACKET_SIZE; TSPacket pkt; if ((ret = pkt.demux(&ctx, start, last, p)) != 0) { trace("demuxer+read decode ts packet error. ret=%d", ret); return ret; } offset += nread; } close(fd); return ret; }