diff --git a/trunk/conf/srs.conf b/trunk/conf/srs.conf index 8328dbda4..633848f8a 100755 --- a/trunk/conf/srs.conf +++ b/trunk/conf/srs.conf @@ -1,5 +1,5 @@ # the listen ports, split by space. -listen 1937; +listen 1935; # the default chunk size is 128, max is 65536, # some client does not support chunk size change, # however, most clients supports it and it can improve diff --git a/trunk/research/ts_info.cpp b/trunk/research/ts_info.cpp index 39f23ef2c..7795e8fb9 100755 --- a/trunk/research/ts_info.cpp +++ b/trunk/research/ts_info.cpp @@ -1,646 +1,1073 @@ -/** -g++ -o ts_info ts_info.cpp -g -O0 -ansi -*/ -#if 1 -#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 - -struct TSPacket -{ - // 4B ts packet header. - struct Header - { - // 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 - - int get_size() - { - return 4; - } - - int demux(TSPacket* ppkt, 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; - - 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; - } - } *header; - - // variant ts packet adation field. - struct AdaptionField - { - // 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; - - AdaptionField() - { - transport_private_data = NULL; - af_ext_reserved = NULL; - af_reserved = NULL; - - __user_size = 0; - } - - virtual ~AdaptionField() - { - srs_freepa(transport_private_data); - srs_freepa(af_ext_reserved); - srs_freepa(af_reserved); - } - - int get_size() - { - return __user_size; - } - - int demux(TSPacket* ppkt, 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; - } - } *adaption_field; - - // variant ts packet payload. - // PES packet or PSI table. - struct Payload - { - /** - * the size of payload(payload plush the 1byte pointer_field). - */ - int size; - int pointer_field_size; - - /** - * the actually parsed type. - */ - enum Type - { - TypeUnknown=-1, - TypeReserved, // TypeReserved, nothing parsed, used reserved. - TypePAT, //TypePAT, PAT parsed, in pat field. - } type; - - /** - * 2.4.4.2 Semantics definition of fields in pointer syntax - */ - u_int8_t pointer_field; - - /** - * if not parsed, store data in this field. - */ - struct Reserved - { - int size; - char* bytes; - - Reserved() - { - size = 0; - bytes = NULL; - } - - virtual ~Reserved() - { - srs_freepa(bytes); - } - - int demux(TSPacket* ppkt, u_int8_t* start, u_int8_t* last, u_int8_t*& p) - { - int ret = 0; - - size = ppkt->payload->size - ppkt->payload->pointer_field_size; - - // not parsed bytes. - if (size > 0) { - bytes = new char[size]; - memcpy(bytes, p, size); - p += size; - } - - return ret; - } - } *reserved; - - /** - * 2.4.4.3 Program association Table. page 61. - */ - struct PAT { - // 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 - - PAT() - { - programs = NULL; - } - - virtual ~PAT() - { - srs_freepa(programs); - } - - int get_program(int index) - { - srs_assert(index < program_size); - return programs[index] & 0x1FFF; - } - - int demux(TSPacket* ppkt, 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++; - } - } - - pp = (char*)&CRC_32; - pp[3] = *p++; - pp[2] = *p++; - pp[1] = *p++; - pp[0] = *p++; - - return ret; - } - } *pat; - - /** - * 2.4.3.6 PES packet. page 49. - */ - - Payload() - { - size = 0; - pointer_field_size = 0; - - type = TypeUnknown; - reserved = NULL; - pat = NULL; - } - - virtual ~Payload() - { - srs_freep(reserved); - srs_freep(pat); - } - - int demux(TSPacket* ppkt, u_int8_t* start, u_int8_t* last, u_int8_t*& p) - { - int ret = 0; - - if (ppkt->header->payload_unit_start_indicator) { - pointer_field = *p++; - pointer_field_size = 1; - } - - if (ppkt->header->pid == PID_PAT) { - type = TypePAT; - pat = new PAT(); - return pat->demux(ppkt, start, last, p); - } - - // not parsed bytes. - type = TypeReserved; - reserved = new Reserved(); - if ((ret = reserved->demux(ppkt, start, last, p)) != 0) { - return ret; - } - - return ret; - } - } *payload; - - TSPacket() - { - header = new Header(); - adaption_field = new AdaptionField(); - payload = new Payload(); - } - - virtual ~TSPacket() - { - srs_freep(header); - srs_freep(adaption_field); - srs_freep(payload); - } - - int demux(u_int8_t* start, u_int8_t* last, u_int8_t*& p) - { - int ret = 0; - - if ((ret = header->demux(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(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(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 finish() - { - return 0; - } -}; - -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"); - 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(start, last, p)) != 0) { - trace("demuxer+read decode ts packet error. ret=%d", ret); - return ret; - } - - offset += nread; - } - - close(fd); - return ret; -} - +/** +g++ -o ts_info ts_info.cpp -g -O0 -ansi +*/ +#if 1 +#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); +}; + + +/** +* 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 + + 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() +{ +} + +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++; + + 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; +} + diff --git a/trunk/src/srs/srs.upp b/trunk/src/srs/srs.upp index 6cb7f96c1..fa698f372 100755 --- a/trunk/src/srs/srs.upp +++ b/trunk/src/srs/srs.upp @@ -41,7 +41,9 @@ file ..\core\srs_core_pithy_print.hpp, ..\core\srs_core_pithy_print.cpp, ..\core\srs_core_log.hpp, - ..\core\srs_core_log.cpp; + ..\core\srs_core_log.cpp, + research readonly separator, + ..\..\research\ts_info.cpp; mainconfig "" = "MAIN";