add ts PCR analysis, the tool MPEG-2-ts-packet-analysis.2.4.5.0 decode PCR wrong
正在显示
2 个修改的文件
包含
158 行增加
和
36 行删除
trunk/doc/ts-PCR-analysis.txt
0 → 100644
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); |
-
请 注册 或 登录 后发表评论