本系列的第一篇文章讲解了如何把ts包拼装为pes包,本章主要讲解如何解析pes包。
一、pes包的格式如下图所示:
二、相关字段解析
packet_start_code_prefix 标识包起始端的包起始码。固定值为 0000 0000 0000 0000 0000 0001 (0x000001)
stream_id 指示基本流的类型
PES_packet_length 指示 PES 包中跟随该字段最后字节的字节数。
PES_scrambling_control 指示 PES 包有效载荷的加扰方式。
PTS (presentation time stamp) 显示时间戳
DTS (decoding time stamp) 解码时间戳
三、pes解析代码
int mpeg_pes_packet_parse(pes_packet_t *ppespkt, uint8_t *data, uint32_t size, uint32_t type)
{
uint8_t *ptr = data;
if (NULL==ptr || NULL==ppespkt) {
print_err("phdrts=%p data=%p\n", ptr, ppespkt);
return -1;
}
if (MPEG_STREAM_TYPE_VIDEO == type) {
if (!MPEG_STREAM_IS_VIDEO(ptr[3])) {
print_err("pes stream_id=0x%x is not video\n", ptr[3]);
return -1;
}
}
else if (MPEG_STREAM_TYPE_AUDIO == type) {
if (!MPEG_STREAM_IS_AUDIO(ptr[3])) {
print_err("pes stream_id=0x%x is not audio\n", ptr[3]);
return -1;
}
}
else { /*暂不支持其他类型*/
print_err("pes type=%d\n", type);
return -1;
}
ppespkt->packet_start_code_prefix = ((ptr[0] << 16) | (ptr[1] << 8) | (ptr[2]));
ppespkt->stream_id = ((ptr[3]));
ppespkt->packet_length = ((ptr[4]<< 8) | (ptr[5]));
ppespkt->reserved_0 = ((ptr[6]&0xc0) >> 6);
ppespkt->scrambling_control = ((ptr[6]&0x30) >> 4);
ppespkt->priority = ((ptr[6]&0x08) >> 3); /* 1 bslbf*/
ppespkt->data_alignment_indicator = ((ptr[6]&0x04) >> 2); /* 1 bslbf*/
ppespkt->copyright = ((ptr[6]&0x02) >> 1); /* 1 bslbf*/
ppespkt->original_or_copy = ((ptr[6]&0x01)); /* 1 bslbf*/
ppespkt->pts_dts_flags = ((ptr[7]&0xc0) >> 6); /* 2 bslbf*/
ppespkt->escr_flag = ((ptr[7]&0x20) >> 5); /* 1 bslbf*/
ppespkt->es_rate_flag = ((ptr[7]&0x10) >> 4); /* 1 bslbf*/
ppespkt->dsm_trick_mode_flag = ((ptr[7]&0x08) >> 3); /* 1 bslbf*/
ppespkt->additional_copy_info_flag = ((ptr[7]&0x04) >> 2); /* 1 bslbf*/
ppespkt->crc_flag = ((ptr[7]&0x02) >> 1); /* 1 bslbf*/
ppespkt->extension_flag = ((ptr[7]&0x01)); /* 1 bslbf*/
ppespkt->header_data_length = ((ptr[8])); /* 8 uimsbf*/
ptr += 9;
ppespkt->playload_offset = ppespkt->header_data_length + 9;
switch (ppespkt->pts_dts_flags) {
case 2:
ppespkt->pts = ((uint64_t)((ptr[0]&0x0e)>>1)<<30) | ((((ptr[1]<<8)|(ptr[2]&0xfe))>>1)<<15) | (((ptr[3]<<8)|(ptr[4]&0xfe))>>1);
ppespkt->dts = NOPTS_VALUE;
break;
case 3:
ppespkt->pts = ((uint64_t)((ptr[0]&0x0e)>>1)<<30) | ((((ptr[1]<<8)|(ptr[2]&0xfe))>>1)<<15) | (((ptr[3]<<8)|(ptr[4]&0xfe))>>1);
ptr += 5;
ppespkt->dts = ((uint64_t)((ptr[0]&0x0e)>>1)<<30) | ((((ptr[1]<<8)|(ptr[2]&0xfe))>>1)<<15) | (((ptr[3]<<8)|(ptr[4]&0xfe))>>1);
ptr += 5;
break;
default:
ppespkt->pts = NOPTS_VALUE;
ppespkt->dts = NOPTS_VALUE;
}
return 0;
}
四、关于pts和dts
这里的pts、dts都是以90kHz为基准,转换为毫秒的算法:
pts * 1000 / 90000
pts和dts都是一个由27MHz脉冲触发计数器生成,再经300分频器分频成90kHz脉冲送入一个33位计数器生成90kHz基值是时间戳。这就是pts、dts位33位并以90khz为基准的原因。
五、pes解析运行结果
|+++++++++++++++++++++++++++++++++++++++++++++|
sizeof(pes_packet_t) = 32
packet_start_code_prefix = 0x1
stream_id = 0xea
packet_length = 0x0
reserved_0 = 0x2
scrambling_control = 0x0
priority = 0x1
data_alignment_indicator = 0x1
copyright = 0x0
original_or_copy = 0x0
pts_dts_flags = 0x3
escr_flag = 0x0
es_rate_flag = 0x0
dsm_trick_mode_flag = 0x0
additional_copy_info_flag= 0x0
crc_flag = 0x0
extension_flag = 0x0
header_data_length = 0xa
playload_offset = 0x13
reserved_1 = 0x0
pts = 0x121e7b6d6(4863801046)(15:00:42 233)
dts = 0x121e78ca6(4863790246)(15:00:42 113)
|+++++++++++++++++++++++++++++++++++++++++++++|
mpeg2标准:https://download.youkuaiyun.com/download/maxzero/10402761
完整的代码:https://download.youkuaiyun.com/download/maxzero/10572383