winlin

add ts PCR analysis, the tool MPEG-2-ts-packet-analysis.2.4.5.0 decode PCR wrong

  1 +packet#7:
  2 +Adaptation fields
  3 + Adaptation_field_length: 7
  4 + discontinuity_indicator: False
  5 + random_access_indicator: True
  6 + ES_priority_indicator: False
  7 + PCR_flag: True
  8 + OPCR_flag: False
  9 + splicing_point_flag: False
  10 + transport_private_data_flag: False
  11 + adaptation_field_extension_flag: False
  12 + PCR: 50572350000
  13 +PES header
  14 + stream_id: E0 (video stream 224)
  15 + PES_packet_length: 35808
  16 + PES_scrambling: 0
  17 + PES_priority: False
  18 + data_alignment: False
  19 + copyright: False
  20 + original_or_copy: False
  21 + PTS_flag: True
  22 + DTS_flag: True
  23 + ESCR_flag: False
  24 + ES_rate_flag: False
  25 + DSM_trick_mode_flag: False
  26 + additional_copy_info_flag: False
  27 + PES_CRC_flag: False
  28 + PES_extension_flag: False
  29 + PES_header_data_length: 10
  30 + PTS: 168704280
  31 + DTS: 168700500
  32 +
  33 +
  34 +
  35 +packet#665:
  36 +Adaptation fields
  37 + Adaptation_field_length: 7
  38 + discontinuity_indicator: False
  39 + random_access_indicator: True
  40 + ES_priority_indicator: False
  41 + PCR_flag: True
  42 + OPCR_flag: False
  43 + splicing_point_flag: False
  44 + transport_private_data_flag: False
  45 + adaptation_field_extension_flag: False
  46 + PCR: 50616225000
  47 +PES header
  48 + stream_id: E0 (video stream 224)
  49 + PES_packet_length: 29213
  50 + PES_scrambling: 0
  51 + PES_priority: False
  52 + data_alignment: False
  53 + copyright: False
  54 + original_or_copy: False
  55 + PTS_flag: True
  56 + DTS_flag: True
  57 + ESCR_flag: False
  58 + ES_rate_flag: False
  59 + DSM_trick_mode_flag: False
  60 + additional_copy_info_flag: False
  61 + PES_CRC_flag: False
  62 + PES_extension_flag: False
  63 + PES_header_data_length: 10
  64 + PTS: 168850530
  65 + DTS: 168846750
  66 +
  67 +参考nginx-rtmp函数:ngx_rtmp_mpegts_write_frame
  68 +其中,nginx-rtmp写入PCR的逻辑如下:
  69 + if (f->key) {
  70 + packet[3] |= 0x20; /* adaptation */
  71 +
  72 + *p++ = 7; /* size */
  73 + *p++ = 0x50; /* random access + PCR */
  74 +
  75 + p = ngx_rtmp_mpegts_write_pcr(p, f->dts - NGX_RTMP_HLS_DELAY);
  76 + }
  77 +只要碰到关键帧,就写入PCR。
  78 +ngx_rtmp_mpegts_write_pcr(u_char *p, uint64_t pcr)
  79 +{
  80 + *p++ = (u_char) (pcr >> 25);
  81 + *p++ = (u_char) (pcr >> 17);
  82 + *p++ = (u_char) (pcr >> 9);
  83 + *p++ = (u_char) (pcr >> 1);
  84 + *p++ = (u_char) (pcr << 7 | 0x7e);
  85 + *p++ = 0;
  86 +
  87 + return p;
  88 +}
  89 +即将高9位置0,6个reserverd置1,低33位输出(little-endian)。
  90 +
  91 +nginx-rtmp写入dts的逻辑如下:
  92 + p = ngx_rtmp_mpegts_write_pts(p, 1, f->dts + NGX_RTMP_HLS_DELAY);
  93 +也就是说,
  94 + pcr = f->dts - NGX_RTMP_HLS_DELAY
  95 + f->dts = dts - NGX_RTMP_HLS_DELAY
  96 +计算出来的:
  97 + pcr = program_clock_reference_base = 168574500
  98 + dts = 168700500
  99 + 168574500 = 168700500 - 63000 - 63000
  100 +可见,工具MPEG-2 TS packet analyser分析出来的pcr是不对的。
  101 +
  102 +解码出来的结果:
  103 +demuxer+read packet 0006 0001128 0x47 0x41 0x00 0x35 ... 0xb6 0x9f 0x89
  104 +ts+af af flags parsed, discontinuity: 0 random: 1 priority: 0 PCR: 1 OPCR: 0 slicing: 0 private: 0 extension: 0 pcr: 168574500 opcr: 0
  105 +ts+pes stream_id: 224 size: 35808 pts: 168704280 dts: 168700500 total: 35808 header: 13 packet_size: 35795 parsed_size: 157
@@ -228,6 +228,9 @@ public: @@ -228,6 +228,9 @@ public:
228 228
229 // user defined total adaption field size. 229 // user defined total adaption field size.
230 int __field_size; 230 int __field_size;
  231 + // logic pcr/original_pcr
  232 + int64_t pcr;
  233 + int64_t original_pcr;
231 234
232 TSAdaptionField(); 235 TSAdaptionField();
233 virtual ~TSAdaptionField(); 236 virtual ~TSAdaptionField();
@@ -764,6 +767,8 @@ TSAdaptionField::TSAdaptionField() @@ -764,6 +767,8 @@ TSAdaptionField::TSAdaptionField()
764 af_ext_reserved = NULL; 767 af_ext_reserved = NULL;
765 af_reserved = NULL; 768 af_reserved = NULL;
766 __field_size = 0; 769 __field_size = 0;
  770 + pcr = 0;
  771 + original_pcr = 0;
767 } 772 }
768 773
769 TSAdaptionField::~TSAdaptionField() 774 TSAdaptionField::~TSAdaptionField()
@@ -802,10 +807,6 @@ int TSAdaptionField::demux(TSContext* ctx, TSPacket* pkt, u_int8_t* start, u_int @@ -802,10 +807,6 @@ int TSAdaptionField::demux(TSContext* ctx, TSPacket* pkt, u_int8_t* start, u_int
802 transport_private_data_flag = (value >> 1) & 0x01; 807 transport_private_data_flag = (value >> 1) & 0x01;
803 adaptation_field_extension_flag = (value >> 0) & 0x01; 808 adaptation_field_extension_flag = (value >> 0) & 0x01;
804 809
805 - trace("ts+af af flags parsed, discontinuity: %d random: %d priority: %d PCR: %d OPCR: %d slicing: %d private: %d extension: %d",  
806 - discontinuity_indicator, random_access_indicator, elementary_stream_priority_indicator, PCR_flag, OPCR_flag, splicing_point_flag,  
807 - transport_private_data_flag, adaptation_field_extension_flag);  
808 -  
809 char* pp = NULL; 810 char* pp = NULL;
810 if (PCR_flag) { 811 if (PCR_flag) {
811 pp = (char*)&program_clock_reference_base; 812 pp = (char*)&program_clock_reference_base;
@@ -816,8 +817,14 @@ int TSAdaptionField::demux(TSContext* ctx, TSPacket* pkt, u_int8_t* start, u_int @@ -816,8 +817,14 @@ int TSAdaptionField::demux(TSContext* ctx, TSPacket* pkt, u_int8_t* start, u_int
816 pp[1] = *p++; 817 pp[1] = *p++;
817 pp[0] = *p++; 818 pp[0] = *p++;
818 819
819 - program_clock_reference_extension = program_clock_reference_base & 0x1F;  
820 - program_clock_reference_base = (program_clock_reference_base >> 9) & 0x1FFFFFFFF; 820 + program_clock_reference_extension = program_clock_reference_base & 0x1ff;
  821 + program_clock_reference_base = (program_clock_reference_base >> 15) & 0x1ffffffff;
  822 +
  823 + // high 9bits
  824 + pcr = program_clock_reference_extension;
  825 + pcr = (pcr << 33) & 0x3fe00000000;
  826 + // low 33bits
  827 + pcr |= program_clock_reference_base;
821 } 828 }
822 if (OPCR_flag) { 829 if (OPCR_flag) {
823 pp = (char*)&original_program_clock_reference_base; 830 pp = (char*)&original_program_clock_reference_base;
@@ -828,8 +835,14 @@ int TSAdaptionField::demux(TSContext* ctx, TSPacket* pkt, u_int8_t* start, u_int @@ -828,8 +835,14 @@ int TSAdaptionField::demux(TSContext* ctx, TSPacket* pkt, u_int8_t* start, u_int
828 pp[1] = *p++; 835 pp[1] = *p++;
829 pp[0] = *p++; 836 pp[0] = *p++;
830 837
831 - original_program_clock_reference_extension = original_program_clock_reference_base & 0x1F;  
832 - original_program_clock_reference_base = (original_program_clock_reference_base >> 9) & 0x1FFFFFFFF; 838 + original_program_clock_reference_extension = original_program_clock_reference_base & 0x1ff;
  839 + original_program_clock_reference_base = (original_program_clock_reference_base >> 15) & 0x1ffffffff;
  840 +
  841 + // high 9bits
  842 + original_pcr = program_clock_reference_extension;
  843 + original_pcr = (original_pcr << 33) & 0x3fe00000000;
  844 + // low 33bits
  845 + original_pcr |= program_clock_reference_base;
833 } 846 }
834 if (splicing_point_flag) { 847 if (splicing_point_flag) {
835 splice_countdown = *p++; 848 splice_countdown = *p++;
@@ -909,6 +922,10 @@ int TSAdaptionField::demux(TSContext* ctx, TSPacket* pkt, u_int8_t* start, u_int @@ -909,6 +922,10 @@ int TSAdaptionField::demux(TSContext* ctx, TSPacket* pkt, u_int8_t* start, u_int
909 p += af_size; 922 p += af_size;
910 } 923 }
911 924
  925 + trace("ts+af af flags parsed, discontinuity: %d random: %d priority: %d PCR: %d OPCR: %d slicing: %d private: %d extension: %d pcr: %"PRId64" opcr: %"PRId64"",
  926 + discontinuity_indicator, random_access_indicator, elementary_stream_priority_indicator, PCR_flag, OPCR_flag, splicing_point_flag,
  927 + transport_private_data_flag, adaptation_field_extension_flag, pcr, original_pcr);
  928 +
912 return ret; 929 return ret;
913 } 930 }
914 931
@@ -1550,6 +1567,34 @@ int TSPayload::demux(TSContext* ctx, TSPacket* pkt, u_int8_t* start, u_int8_t* l @@ -1550,6 +1567,34 @@ int TSPayload::demux(TSContext* ctx, TSPacket* pkt, u_int8_t* start, u_int8_t* l
1550 return pmt->demux(ctx, pkt, start, last, p, pmsg); 1567 return pmt->demux(ctx, pkt, start, last, p, pmsg);
1551 } 1568 }
1552 if (pid && (pid->type == TSPidTypeVideo || pid->type == TSPidTypeAudio)) { 1569 if (pid && (pid->type == TSPidTypeVideo || pid->type == TSPidTypeAudio)) {
  1570 + TSMessage* msg = ctx->get_msg(pkt->header->pid);
  1571 +
  1572 + // flush previous PES_packet_length(0) packets.
  1573 + if (msg->packet_start_code_prefix == 0x01
  1574 + && pkt->header->payload_unit_start_indicator == 1
  1575 + && msg->PES_packet_length == 0
  1576 + ) {
  1577 + msg->detach(ctx, pmsg);
  1578 + // reparse current message
  1579 + p = start;
  1580 + return ret;
  1581 + }
  1582 +
  1583 + // parse continous packet.
  1584 + if (!pkt->header->payload_unit_start_indicator) {
  1585 + if (msg->packet_start_code_prefix != 0x01) {
  1586 + trace("ts+pes decode continous packet error, msg is empty.");
  1587 + return -1;
  1588 + }
  1589 + msg->append(p, last - p);
  1590 +
  1591 + // for PES_packet_length is 0, donot attach it.
  1592 + if (msg->PES_packet_length > 0) {
  1593 + msg->detach(ctx, pmsg);
  1594 + }
  1595 + return ret;
  1596 + }
  1597 +
1553 type = pid->type; 1598 type = pid->type;
1554 pes = new TSPayloadPES(); 1599 pes = new TSPayloadPES();
1555 return pes->demux(ctx, pkt, start, last, p, pmsg); 1600 return pes->demux(ctx, pkt, start, last, p, pmsg);
@@ -1599,34 +1644,6 @@ int TSPacket::demux(TSContext* ctx, u_int8_t* start, u_int8_t* last, u_int8_t*& @@ -1599,34 +1644,6 @@ int TSPacket::demux(TSContext* ctx, u_int8_t* start, u_int8_t* last, u_int8_t*&
1599 payload->size = TS_PACKET_SIZE - header->get_size() - adaption_field->get_size(); 1644 payload->size = TS_PACKET_SIZE - header->get_size() - adaption_field->get_size();
1600 1645
1601 if (header->adaption_field_control == TSAdaptionTypePayloadOnly || header->adaption_field_control == TSAdaptionTypeBoth) { 1646 if (header->adaption_field_control == TSAdaptionTypePayloadOnly || header->adaption_field_control == TSAdaptionTypeBoth) {
1602 - TSMessage* msg = ctx->get_msg(header->pid);  
1603 -  
1604 - // flush previous PES_packet_length(0) packets.  
1605 - if (msg->packet_start_code_prefix == 0x01  
1606 - && header->payload_unit_start_indicator == 1  
1607 - && msg->PES_packet_length == 0  
1608 - ) {  
1609 - msg->detach(ctx, pmsg);  
1610 - // reparse current message  
1611 - p = start;  
1612 - return ret;  
1613 - }  
1614 -  
1615 - // parse continous packet.  
1616 - if (!header->payload_unit_start_indicator) {  
1617 - if (msg->packet_start_code_prefix != 0x01) {  
1618 - trace("ts+pes decode continous packet error, msg is empty.");  
1619 - return -1;  
1620 - }  
1621 - msg->append(p, last - p);  
1622 -  
1623 - // for PES_packet_length is 0, donot attach it.  
1624 - if (msg->PES_packet_length > 0) {  
1625 - msg->detach(ctx, pmsg);  
1626 - }  
1627 - return ret;  
1628 - }  
1629 -  
1630 // parse new packet. 1647 // parse new packet.
1631 if ((ret = payload->demux(ctx, this, start, last, p, pmsg)) != 0) { 1648 if ((ret = payload->demux(ctx, this, start, last, p, pmsg)) != 0) {
1632 trace("ts+header payload decode error. ret=%d", ret); 1649 trace("ts+header payload decode error. ret=%d", ret);