winlin

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

packet#7:
Adaptation fields
Adaptation_field_length: 7
discontinuity_indicator: False
random_access_indicator: True
ES_priority_indicator: False
PCR_flag: True
OPCR_flag: False
splicing_point_flag: False
transport_private_data_flag: False
adaptation_field_extension_flag: False
PCR: 50572350000
PES header
stream_id: E0 (video stream 224)
PES_packet_length: 35808
PES_scrambling: 0
PES_priority: False
data_alignment: False
copyright: False
original_or_copy: False
PTS_flag: True
DTS_flag: True
ESCR_flag: False
ES_rate_flag: False
DSM_trick_mode_flag: False
additional_copy_info_flag: False
PES_CRC_flag: False
PES_extension_flag: False
PES_header_data_length: 10
PTS: 168704280
DTS: 168700500
packet#665:
Adaptation fields
Adaptation_field_length: 7
discontinuity_indicator: False
random_access_indicator: True
ES_priority_indicator: False
PCR_flag: True
OPCR_flag: False
splicing_point_flag: False
transport_private_data_flag: False
adaptation_field_extension_flag: False
PCR: 50616225000
PES header
stream_id: E0 (video stream 224)
PES_packet_length: 29213
PES_scrambling: 0
PES_priority: False
data_alignment: False
copyright: False
original_or_copy: False
PTS_flag: True
DTS_flag: True
ESCR_flag: False
ES_rate_flag: False
DSM_trick_mode_flag: False
additional_copy_info_flag: False
PES_CRC_flag: False
PES_extension_flag: False
PES_header_data_length: 10
PTS: 168850530
DTS: 168846750
参考nginx-rtmp函数:ngx_rtmp_mpegts_write_frame
其中,nginx-rtmp写入PCR的逻辑如下:
if (f->key) {
packet[3] |= 0x20; /* adaptation */
*p++ = 7; /* size */
*p++ = 0x50; /* random access + PCR */
p = ngx_rtmp_mpegts_write_pcr(p, f->dts - NGX_RTMP_HLS_DELAY);
}
只要碰到关键帧,就写入PCR。
ngx_rtmp_mpegts_write_pcr(u_char *p, uint64_t pcr)
{
*p++ = (u_char) (pcr >> 25);
*p++ = (u_char) (pcr >> 17);
*p++ = (u_char) (pcr >> 9);
*p++ = (u_char) (pcr >> 1);
*p++ = (u_char) (pcr << 7 | 0x7e);
*p++ = 0;
return p;
}
即将高9位置0,6个reserverd置1,低33位输出(little-endian)。
nginx-rtmp写入dts的逻辑如下:
p = ngx_rtmp_mpegts_write_pts(p, 1, f->dts + NGX_RTMP_HLS_DELAY);
也就是说,
pcr = f->dts - NGX_RTMP_HLS_DELAY
f->dts = dts - NGX_RTMP_HLS_DELAY
计算出来的:
pcr = program_clock_reference_base = 168574500
dts = 168700500
168574500 = 168700500 - 63000 - 63000
可见,工具MPEG-2 TS packet analyser分析出来的pcr是不对的。
解码出来的结果:
demuxer+read packet 0006 0001128 0x47 0x41 0x00 0x35 ... 0xb6 0x9f 0x89
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
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:
// user defined total adaption field size.
int __field_size;
// logic pcr/original_pcr
int64_t pcr;
int64_t original_pcr;
TSAdaptionField();
virtual ~TSAdaptionField();
... ... @@ -764,6 +767,8 @@ TSAdaptionField::TSAdaptionField()
af_ext_reserved = NULL;
af_reserved = NULL;
__field_size = 0;
pcr = 0;
original_pcr = 0;
}
TSAdaptionField::~TSAdaptionField()
... ... @@ -802,10 +807,6 @@ int TSAdaptionField::demux(TSContext* ctx, TSPacket* pkt, u_int8_t* start, u_int
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;
... ... @@ -816,8 +817,14 @@ int TSAdaptionField::demux(TSContext* ctx, TSPacket* pkt, u_int8_t* start, u_int
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;
program_clock_reference_extension = program_clock_reference_base & 0x1ff;
program_clock_reference_base = (program_clock_reference_base >> 15) & 0x1ffffffff;
// high 9bits
pcr = program_clock_reference_extension;
pcr = (pcr << 33) & 0x3fe00000000;
// low 33bits
pcr |= program_clock_reference_base;
}
if (OPCR_flag) {
pp = (char*)&original_program_clock_reference_base;
... ... @@ -828,8 +835,14 @@ int TSAdaptionField::demux(TSContext* ctx, TSPacket* pkt, u_int8_t* start, u_int
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;
original_program_clock_reference_extension = original_program_clock_reference_base & 0x1ff;
original_program_clock_reference_base = (original_program_clock_reference_base >> 15) & 0x1ffffffff;
// high 9bits
original_pcr = program_clock_reference_extension;
original_pcr = (original_pcr << 33) & 0x3fe00000000;
// low 33bits
original_pcr |= program_clock_reference_base;
}
if (splicing_point_flag) {
splice_countdown = *p++;
... ... @@ -909,6 +922,10 @@ int TSAdaptionField::demux(TSContext* ctx, TSPacket* pkt, u_int8_t* start, u_int
p += af_size;
}
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"",
discontinuity_indicator, random_access_indicator, elementary_stream_priority_indicator, PCR_flag, OPCR_flag, splicing_point_flag,
transport_private_data_flag, adaptation_field_extension_flag, pcr, original_pcr);
return ret;
}
... ... @@ -1550,6 +1567,34 @@ int TSPayload::demux(TSContext* ctx, TSPacket* pkt, u_int8_t* start, u_int8_t* l
return pmt->demux(ctx, pkt, start, last, p, pmsg);
}
if (pid && (pid->type == TSPidTypeVideo || pid->type == TSPidTypeAudio)) {
TSMessage* msg = ctx->get_msg(pkt->header->pid);
// flush previous PES_packet_length(0) packets.
if (msg->packet_start_code_prefix == 0x01
&& pkt->header->payload_unit_start_indicator == 1
&& msg->PES_packet_length == 0
) {
msg->detach(ctx, pmsg);
// reparse current message
p = start;
return ret;
}
// parse continous packet.
if (!pkt->header->payload_unit_start_indicator) {
if (msg->packet_start_code_prefix != 0x01) {
trace("ts+pes decode continous packet error, msg is empty.");
return -1;
}
msg->append(p, last - p);
// for PES_packet_length is 0, donot attach it.
if (msg->PES_packet_length > 0) {
msg->detach(ctx, pmsg);
}
return ret;
}
type = pid->type;
pes = new TSPayloadPES();
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*&
payload->size = TS_PACKET_SIZE - header->get_size() - adaption_field->get_size();
if (header->adaption_field_control == TSAdaptionTypePayloadOnly || header->adaption_field_control == TSAdaptionTypeBoth) {
TSMessage* msg = ctx->get_msg(header->pid);
// flush previous PES_packet_length(0) packets.
if (msg->packet_start_code_prefix == 0x01
&& header->payload_unit_start_indicator == 1
&& msg->PES_packet_length == 0
) {
msg->detach(ctx, pmsg);
// reparse current message
p = start;
return ret;
}
// parse continous packet.
if (!header->payload_unit_start_indicator) {
if (msg->packet_start_code_prefix != 0x01) {
trace("ts+pes decode continous packet error, msg is empty.");
return -1;
}
msg->append(p, last - p);
// for PES_packet_length is 0, donot attach it.
if (msg->PES_packet_length > 0) {
msg->detach(ctx, pmsg);
}
return ret;
}
// parse new packet.
if ((ret = payload->demux(ctx, this, start, last, p, pmsg)) != 0) {
trace("ts+header payload decode error. ret=%d", ret);
... ...