1、本文的基本作用:引导理解封装格式,但更重要的是要自己去阅读协议,上手实践;
2、本文的最大价值:久之,皆已遗忘;顾之,皆已忆起。
一、基本知识
1、结构概览
区别与TS的分包,将一个或多个PES组合而成的单一的数据流称为节目流(Program Stream)。
TS通过同步字节0x47分包,PS通过定义长度来指示下一内容的位置。
PS包由包头、系统头、节目映射表、PES包等部分构成。因此PS的解析就是找到各种头,根据长度去寻找下一个类型。
2、pack_header
pack_start_code为0x000001BA,标识是pack_header。接下来是10个固定字节。其中pack_stuffing_length描述了stuffing_byte的长度,算出这个,就能得到所有packet_header的数据。
3、system_header
system_header_start_code为0x000001BB,标识是system_header。接下来的2个字节描述了header_length,算出这个,就能得到所有system_header的数据。
4、program_stream_map
packet_start_code_prefix为0x000001BC,标识是program_stream_map。接下来是7个固定字节。其中program_stream_info_length描述了stream_info的长度。跳过program_stream_info_length,接下来2个字节elementary_stream_map_length描述了elementary_info的长度,其中最重要的是stream_type(描述了流的类型)和elementary_stream_id(对应PES包中的stream_id)。算出program_stream_info_length和elementary_stream_map_length,就能得到所有program_stream_map的数据。
5、pes_packet
太长了,只列出头上的,具体的参见下面源码里面的注释。packet_start_code_prefix为0x000001xx,其中xx为program_stream_map中的stream_id。PES_packet_length描述了PES包的长度。下面还有重要的是PTS和DTS。
二、重点代码
1、解析pack_header
int main() {
switch (startCode)
{
case SCODE_PS_HEADER:
memset(psData, 0x0, sizeof(psData));
readLen = fread(psData, 1, MMIN_PS_HEADER_LEN-4, fp);
if ((MMIN_PS_HEADER_LEN-4) != readLen)
{
fclose(fp);
return 0;
}
pack_stuffing_length = psData[MMIN_PS_HEADER_LEN-5] & 0x7;
fseek(fp, pack_stuffing_length, SEEK_CUR);
break;
}
}
2、解析system_header
int main() {
switch (startCode)
{
case SCODE_PS_SYSTEM_HEADER:
if (1 != fread(&psSystemHeaderLen, 2, 1, fp))
{
fclose(fp);
return 0;
}
psSystemHeaderLen = ntohs(psSystemHeaderLen);
fseek(fp, psSystemHeaderLen, SEEK_CUR);
break;
}
}
3、解析program_stream_map
static void parsePsSystemMapHeader(unsigned char* const psMapHeaderData) {
psMap.curNextInd = (data[0]>>7) & 0x1;
psMap.version = data[0] & 0x1f;
data += 2;
psMap.psInfoLen = (data[0] << 8) | data[1];
data += psMap.psInfoLen;
psMap.esStreamMapLen = (data[0] << 8) | data[1];
psMap.esMapNum = psMap.esStreamMapLen / 4;
for (i=0; i<psMap.esMapNum; i++)
{
if (i == MAX_ES_NUMS)
{
printf("now just save %d es info!\n", MAX_ES_NUMS);
break;
}
psMap.esMaps[i].streamType = data[0];
psMap.esMaps[i].esId = data[1];
psMap.esMaps[i].esInfoLen = (data[2] << 8) | data[3];
data += (4+psMap.esMaps[i].esInfoLen);
}
}
4、解析pes_packet
int main() {
switch(startCode) {
default:
pesStreamId = startCode & 0xff;
if (1 != fread(&pesPacketLen, 2, 1, fp))
{
fclose(fp);
return 0;
}
pesPacketLen = ntohs(pesPacketLen);
pesData = (unsigned char*)malloc(pesPacketLen);
if (pesData)
{
memset(pesData, 0x0, pesPacketLen);
if (pesPacketLen != fread(pesData, 1, pesPacketLen, fp))
{
fclose(fp);
return 0;
}
parsePes(pesStreamId, pesData, pesPacketLen);
}
}
5、解析PTS和DTS
static void parsePes(const unsigned char streamId, unsigned char* const pesData, const unsigned short pesLen) {
switch (pts_dts_flag)
{
case 0: /* 00, no pts, dts */
break;
case 2: /* 10, only pts*/
memset(pts, 0x0, sizeof(pts));
memcpy(pts, data, MAX_PDTS_LEN);
getPdts(pts, &psPes.pts, psPes.ptsStr);
break;
case 3: /* 11 pts & dts*/
memset(pts, 0x0, sizeof(pts));
memset(dts, 0x0, sizeof(dts));
memcpy(pts, data, MAX_PDTS_LEN);
memcpy(dts, data+MAX_PDTS_LEN, MAX_PDTS_LEN);
getPdts(pts, &psPes.pts, psPes.ptsStr);
getPdts(dts, &psPes.dts, psPes.dtsStr);
break;
default:
break;
}
}
static void getPdts(unsigned char *pdtsData, long long *pdts, unsigned char *pdtsString)
{
unsigned char ptsStr[MAX_PDTS_STRING_LEN+1] = {0};
/* 5个字节转33位的值 */
pts = (((pdtsData[0]>>1) & 0x7) << 30) | (pdtsData[1] << 22) | (((pdtsData[2]>>1) & 0x7f) << 15) | (pdtsData[3] << 7) | (pdtsData[4]>>1 & 0x7f);
/* 90KHz, 1000ms/90 */
pts2Ms = pts/90;
hour = pts2Ms/(60*60*1000);
minute = (pts2Ms - hour * (60*60*1000)) / (60*1000);
second = (pts2Ms - hour * (60*60*1000) - minute * (60*1000)) / 1000;
msecond = pts2Ms - hour * (60*60*1000) - minute * (60*1000) - second * 1000;
sprintf(ptsStr, "%02d:%02d:%02d:%03d", hour, minute, second, msecond);
ptsStr[MAX_PDTS_STRING_LEN] = '\0';
memcpy(pdtsString, ptsStr, MAX_PDTS_STRING_LEN);
*pdts = pts;
}
三、完整源码
纯C代码,gcc编译就能直接运行,打印格式模仿Elecard的形式。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#define TAB44 " "
#define PRINTF_DEBUG
#define MAX_PS_STARTCODE_LEN 4
#define MAX_PDTS_LEN 5
#define MAX_ES_NUMS 6
#define MAX_PDTS_STRING_LEN 12
#define MMIN_PS_HEADER_LEN 14
#define SCODE_PS_END 0x000001B9
#define SCODE_PS_HEADER 0x000001BA
#define SCODE_PS_SYSTEM_HEADER 0x000001BB
#define SCODE_PS_SYSTEM_MAP_HEADER 0x000001BC
/**********************************************************************************************************
pack_header() {
pack_start_code 32 bits
'01' 2 bits
system_clock_reference_base[32..30] 3 bits
marker_bit 1 bit
system_clock_reference_base[29..15] 15 bits
marker_bit 1 bit
system_clock_reference_base[14..0] 15 bits
marker_bit 1 bit
system_clock_reference_extension 9 bits
marker_bit 1 bit
program_mux_rate 22 bits
marker_bit 1 bit
marker_bit 1 bit
reserved 5 bit
pack_stuffing_length 3 bits (2+3+1+...+1+5+3=80)
for (i=0; i<pack_stuffing_length; i++){
stuffing_byte 8 bits
}
if (nextbits() == system_header_start_code) {
system_header()
}
}
**********************************************************************************************************/
/**********************************************************************************************************
system_header() {
system_header_start_code 32 bits
header_length 16 bits
marker_bit 1 bit
rate_bound 22 bits
marker_bit 1 bit
audio_bound 6 bits
fixed_flag 1 bit
CSPS_flag 1 bit
system_audio_lock_flag 1 bit
system_video_lock_flag 1 bit
marker_bit 1 bit
vedio_bound 5 bits
packet_rate_restriction_flag 1 bit
reserved_bits 7 bits
while (nextbits() == '1') {
stream_id 8 bits
'11' 2 bits
P-STD_buffer_bound_scale 1 bit
P-STD_buffer_size_bound 13 bits
}
}
**********************************************************************************************************/
/**********************************************************************************************************
program_stream_map() {
packet_start_code_prefix 24 bits
map_stream_id 8 bits
program_stream_map_length 16 bits
current_next_indicator 1 bit
reserved 2 bits
program_stream_map_version 5 bits
reserved 7 bits
marker_bit 1 bit
program_stream_info_length 16 bits
for (i=0;i<N;i++) {
descriptor()
}
elementary_stream_map_length 16 bits
for (i=0;i<N1;i++) {
stream_type 8 bits
elementary_stream_id 8 bits
elementary_stream_info_length 16 bits
for (i=0;i<N2;i++) {
descriptor()
}
}
CRC_32 32 bits
}
** current_next_indicator: 当前下一个指示符字段, 1位字段. 置'1'时表示传送的节目流映射当前是可用的.
置'0'时表示传送的节目流映射还不可用, 但它将是下一个生效的表.
** program_stream_map_version: 5位字段, 表示整个节目流映射的版本号. 一旦节目流映射的定义发生变化,
该字段将递增1, 并对32取模. 在current_next_indicator为'1'时, 该字段应该是当前适用的节目流映射的版本号;
在current_next_indicator为'0'时, 该字段应该是下一个适用的节目流映射的版本号.
** stream_type: 流类型字段, 该字段只能标志包含在PES分组中的基本流且取值不能为0x05.
1. MPEG-4视频流: 0x10;
2. H.264视频流: 0x1B;
3. SVAC视频流: 0x80;
4. G.711音频流: 0x90;
5. G.722.1音频流: 0x92;
6. G.723.1音频流: 0x93;
7. G.729音频流: 0x99;
8. SVAC音频流: 0x9B.
因为节目映射流字段只有在关键帧打包的时候, 才会存在, 所以如果要判断PS打包的流编码类型, 就根据这个字段来判断.
** elementary_stream_map_length: 基本流映射长度字段. 指出在该节目流映射中的所有基本流信息的字节长度.
它只包括stream_type、elementary_stream_id和elementary_stream_info_length字段.
** elementary_stream_id: 基本流标识字段, 8位字段, 指出该基本流所在PES分组的PES分组标题中stream_id字段的值.
这个字段的定义, 其中0x(C0~DF)指音频, 0x(E0~EF)为视频.
**********************************************************************************************************/
typedef struct t_es_map
{
unsigned char streamType;
unsigned char esId;
unsigned short esInfoLen;
} T_ES_MAP;
typedef struct t_ps_map
{
unsigned char curNextInd:1, :2, version:5;
unsigned short psInfoLen;
unsigned short esStreamMapLen;
unsigned int esMapNum;
T_ES_MAP esMaps[MAX_ES_NUMS];
} T_PS_MAP;
/**********************************************************************************************************
PES_packet() {
packet_start_code_prefix 24 bits
stream_id 8 bits
PES_packet_length 16 bits
if (stream_id != program_stream_map
&& stream_id != padding_stream
&& stream_id != private_stream_2
&& stream_id != ECM
&& stream_id != EMM
&& stream_id != program_stream_directory
&& stream_id != DSMCC_stream
&& stream_id != ITU-T Rec.H.222.1 type E stream) {
'10' 2 bits
PES_scrambling_control 2 bits
PES_priority 1 bit
data_alignment_indicator 1 bit
copyright 1 bit
original_or_copy 1 bit
PTS_DTS_flags 2 bits
ESCR_flag 1 bit
ES_rate_flag 1 bit
DSM_trick_mode_flag 1 bit
additional_copy_info_flag 1 bit
PES_CRC_flag 1 bit
PES_extension_flag 1 bit
PES_header_data_length 8 bits
if (PTS_DTS_flags == '10') {
'0010' 4 bits
PTS[32..30] 3 bits
marker_bit 1 bit
PTS[29..15] 15 bits
marker_bit 1 bit
PTS[14..0] 15 bits
marker_bit 1 bit
}
if (PTS_DTS_flags == '11') {
'0011' 4 bits
PTS[32..30] 3 bits
marker_bit 1 bit
PTS[29..15] 15 bits
marker_bit 1 bit
PTS[14..0] 15 bits
marker_bit 1 bit
'0001' 4 bits
PTS[32..30] 3 bits
marker_bit 1 bit
PTS[29..15] 15 bits
marker_bit 1 bits
PTS[14..0] 15 bits
marker_bit 1 bit
}
if (ESCR_flag == '1') {
reserved 2 bits
ESCR_base[32..30] 3 bits
marker_bit 1 bit
ESCR_base[29..15] 15 bits
marker_bit 1 bit
ESCR_base[14..0] 15 bits
marker_bit 1 bit
ESCR_extension 9 bits
marker_bit 1 bit
}
if (ES_rate_flag == '1') {
marker_bit 1 bit
ES_rate 22 bits
marker_bit 1 bit
}
if (DSM_trick_mode_flag == '1') {
trick_mode_control 3 bits
if (trick_mode_control == fast_forward) {
field_id 2 bits
intra_slice_refresh 1 bits
frequency_truncation 2 bits
} else if (trick_mode_control == slow_motion) {
rep_cntrl 5 bits
} else if (trick_mode _control == freeze_frame) {
field_id 2 bits
reserved 3 bits
} else if (trick_mode _control == fast_reverse) {
field_id 2 bits
intra_slice_refresh 1 bit
frequency_truncation 2 bits
} else if (trick_mode_control == slow_reverse) {
rep_cntrl 5 bits
} else {
reserved 5 bits
}
}
if (additional_copy_info_flag =='1') {
marker_bit 1 bit
additional_copy_info 7 bits
}
if (PES_CRC_flag == ‘1’) {
previous_PES_packet_CRC 16 bits
}
if (PES_extension_flag == '1') {
PES_private_data_flag 1 bit
pack_header_field_flag 1 bit
program_packet_sequence_counter_flag 1 bit
P-STD_buffer_flag 1 bit
reserved 3 bits
PES_extension_flag_2 1 bit
if (PES_private_data_flag == '1') {
PES_private_data 128 bits
}
if (pack_header_field_flag == '1') {
pack_field_length 8 bits
pack_header()
}
if (program_packet_sequence_counter_flag == '1') {
marker_bit 1 bit
program_packet_sequence_counter 7 bits
marker-bit 1 bit
MPEG1_MPEG2_indentifier 1 bit
original_stuff_length 6 bits
}
if (P-STD_buffer_flag == '1') {
'01' 2 bits
P-STD_buffer_scale 1 bit
P-STD_buffer_size 13 bits
}
if (PES_extension_flag_2 == '1') {
marker_bit 1 bit
PES_extension_field_length 7 bits
for (i=0; i<PES_extension_field_length; i++) {
reserved 8 bits
}
}
}
for (i=0; i<N1; i++) {
stuffing_byte 8 bits
}
for (i=0; i<N2; i++) {
PES_packet_data_byte 8 bits
}
} else if (stream_id == program_stream_map
|| stream_id == private_stream_2
|| stream_id == ECM
|| stream_id == EMM
|| stream_id == program_stream_directory
|| stream_id == DSMCC_stream
|| stream_id == ITU-T Rec. H.222.1 type E stream ) {
for (i=0; i<PES_packet_length; i++) {
PES_packet_data_byte 8 bits
}
} else if (steam_id == padding_stream) {
for (i=0; i<PES_packet_length; i++) {
padding_byte 8 bits
}
}
}
** stream_id:
1011 1100 program_stream_map(0xBC)
1011 1101 private_stream_1(0xBD)
1011 1110 padding_stream(0xBE)
1011 1111 private_stream-2(0xBF)
110x xxxx GB/T XXXX.3或GB/T AAAA.3音频流编号xxxx(0xC0~0xDF)
1110 xxxx GB/T XXXX.2或GB/T AAAA.2视频流编号xxxx(0xE0~0xEF)
1111 0000 ECM_stream(0xF0)
1111 0001 EMM_stream(0xF1)
1111 0010 GB/T XXXX.1附录B或GB/T XXXX.6_DSMCC_stream(0xF2)
1111 0011 ISO/IEC_13522_stream(0xF3)
1111 0100 ITU-T Rec. H.222.1类型A
1111 0101 ITU-T Rec. H.222.1类型B
1111 0110 ITU-T Rec. H.222.1类型C
1111 0111 ITU-T Rec. H.222.1类型D
1111 1000 ITU-T Rec. H.222.1类型E
1111 1001 ancillary_stream(0xF9)
1111 1010…1111 1110 保留数据流
1111 1111 program_stream_directory(0xFF)
符号x表示值'0'或'1'均被允许且可产生相同的流类型. 流号码由x的取值决定.
**********************************************************************************************************/
typedef struct t_ps_pes
{
unsigned char streamId;
long long pts;
long long dts;
unsigned char ptsStr[MAX_PDTS_STRING_LEN+1];
unsigned char dtsStr[MAX_PDTS_STRING_LEN+1];
unsigned char pesHeaderLen;
} T_PS_PES;
static void parsePsHeader(unsigned char* const psHeaderData)
{
}
static void parsePsSystemHeader(unsigned char* const psSysHeaderData)
{
}
static void parsePsSystemMapHeader(unsigned char* const psMapHeaderData)
{
int i = 0;
T_PS_MAP psMap = {0};
unsigned char *data = NULL;
data = psMapHeaderData;
memset(&psMap, 0, sizeof(psMap));
psMap.curNextInd = (data[0]>>7) & 0x1;
psMap.version = data[0] & 0x1f;
data += 2;
psMap.psInfoLen = (data[0] << 8) | data[1];
data += psMap.psInfoLen;
psMap.esStreamMapLen = (data[0] << 8) | data[1];
psMap.esMapNum = psMap.esStreamMapLen / 4;
for (i=0; i<psMap.esMapNum; i++)
{
if (i == MAX_ES_NUMS)
{
printf("now just save %d es info!\n", MAX_ES_NUMS);
break;
}
psMap.esMaps[i].streamType = data[0];
psMap.esMaps[i].esId = data[1];
psMap.esMaps[i].esInfoLen = (data[2] << 8) | data[3];
data += (4+psMap.esMaps[i].esInfoLen);
}
#ifdef PRINTF_DEBUG
int mNUm = 0;
if (psMap.esMapNum > MAX_ES_NUMS)
{
mNUm = MAX_ES_NUMS;
}
for (i=0; i<mNUm; i++)
{
printf("%s%sstreamNum: %d, streamType: %d, esId: %d\n", TAB44, TAB44, i, psMap.esMaps[i].streamType, psMap.esMaps[i].esId);
}
#endif
}
static void getPdts(unsigned char *pdtsData, long long *pdts, unsigned char *pdtsString)
{
int hour = 0;
int minute = 0;
int second = 0;
int msecond = 0;
long long pts = 0;
long long pts2Ms = 0;
unsigned char ptsStr[MAX_PDTS_STRING_LEN+1] = {0};
/* 5个字节转33位的值 */
pts = (((pdtsData[0]>>1) & 0x7) << 30) | (pdtsData[1] << 22) | (((pdtsData[2]>>1) & 0x7f) << 15) | (pdtsData[3] << 7) | (pdtsData[4]>>1 & 0x7f);
/* 90KHz, 1000ms/90 */
pts2Ms = pts/90;
hour = pts2Ms/(60*60*1000);
minute = (pts2Ms - hour * (60*60*1000)) / (60*1000);
second = (pts2Ms - hour * (60*60*1000) - minute * (60*1000)) / 1000;
msecond = pts2Ms - hour * (60*60*1000) - minute * (60*1000) - second * 1000;
sprintf(ptsStr, "%02d:%02d:%02d:%03d", hour, minute, second, msecond);
ptsStr[MAX_PDTS_STRING_LEN] = '\0';
memcpy(pdtsString, ptsStr, MAX_PDTS_STRING_LEN);
*pdts = pts;
}
/*********************************************************************************
startcode(24) + streamid(8) + pes_len(16) + {header: flag1(8) + flag2(8, pts标识在这儿) + header_len(8)} + {header_data(header_len, 若前面的flag有数据, 数据就在这儿)} + pes_data(pes_len-3-header_len)
**********************************************************************************/
static void parsePes(const unsigned char streamId, unsigned char* const pesData, const unsigned short pesLen)
{
unsigned char pts_dts_flag;
static int audioNum = 0;
static int videoNum = 0;
static int privateNum = 0;
static int paddingNum = 0;
unsigned char *data = NULL;
unsigned char pts[MAX_PDTS_LEN+1] = {0};
unsigned char dts[MAX_PDTS_LEN+1] = {0};
T_PS_PES psPes = {0};
data = pesData;
memset(&psPes, 0x0, sizeof(psPes));
psPes.streamId = streamId;
if (((streamId>=0xC0) && (streamId<=0xDF)) || ((streamId>=0xE0) && (streamId<=0xEF)))
{
pts_dts_flag = data[1]>>6 & 0x3;
psPes.pesHeaderLen = data[2];
data += 3;
switch (pts_dts_flag)
{
case 0: /* 00, no pts, dts */
break;
case 2: /* 10, only pts*/
memset(pts, 0x0, sizeof(pts));
memcpy(pts, data, MAX_PDTS_LEN);
getPdts(pts, &psPes.pts, psPes.ptsStr);
break;
case 3: /* 11 pts & dts*/
memset(pts, 0x0, sizeof(pts));
memset(dts, 0x0, sizeof(dts));
memcpy(pts, data, MAX_PDTS_LEN);
memcpy(dts, data+MAX_PDTS_LEN, MAX_PDTS_LEN);
getPdts(pts, &psPes.pts, psPes.ptsStr);
getPdts(dts, &psPes.dts, psPes.dtsStr);
break;
default:
break;
}
}
#ifdef PRINTF_DEBUG
if ((streamId>=0xC0) && (streamId<=0xDF))
{
audioNum++;
printf("%s%spes, Audio[%d], streamId: 0x%02X(%d), pesLength: %d, pesHeaderLen: %d", TAB44, TAB44, audioNum, streamId, streamId, pesLen, psPes.pesHeaderLen);
if (2 == pts_dts_flag)
{
printf(", pts: %s(%lld)", psPes.ptsStr, psPes.pts);
}
if (3 == pts_dts_flag)
{
printf(", pts: %s(%lld), dts: %s(%lld)", psPes.ptsStr, psPes.pts, psPes.dtsStr, psPes.dts);
}
printf("\n");
}
else if ((streamId>=0xE0) && (streamId<=0xEF))
{
videoNum++;
printf("%s%spes, Video[%d], streamId: 0x%02X(%d), pesLength: %d, pesHeaderLen: %d", TAB44, TAB44, videoNum, streamId, streamId, pesLen, psPes.pesHeaderLen);
if (2 == pts_dts_flag)
{
printf(", pts: %s(%lld)", psPes.ptsStr, psPes.pts);
}
if (3 == pts_dts_flag)
{
printf(", pts: %s(%lld), dts: %s(%lld)", psPes.ptsStr, psPes.pts, psPes.dtsStr, psPes.dts);
}
printf("\n");
}
else if ((streamId==0xBD) || (streamId==0xBF))
{
privateNum++;
printf("%s%spes, private[%d], streamId: 0x%02X(%d), pesLength: %d\n", TAB44, TAB44, privateNum, streamId, streamId, pesLen);
}
else if (streamId==0xBE)
{
paddingNum++;
printf("%s%spes, padding[%d], streamId: 0x%02X(%d), pesLength: %d\n", TAB44, TAB44, privateNum, streamId, streamId, pesLen);
}
else
{
printf("%s%spes, streamId: 0x%02X(%d), pesLength: %d\n", TAB44, TAB44, streamId, streamId, pesLen);
}
#endif
}
int main(int argc, char *argv[])
{
int readLen = 0;
int pack_stuffing_length = 0;
unsigned int startCode = 0;
unsigned short pesPacketLen = 0;
unsigned short psSystemHeaderLen = 0;
unsigned short psSystemMapHeaderLen = 0;
unsigned char pesStreamId = 0;
unsigned char sCodeData[MAX_PS_STARTCODE_LEN+1] = {0};
unsigned char psData[MMIN_PS_HEADER_LEN-3] = {0};
unsigned char *pesData = NULL;
FILE *fp = NULL;
if (2 != argc)
{
printf("Usage: psparse **.mpg\n");
return -1;
}
fp = fopen(argv[1], "rb");
if (!fp)
{
printf("open file[%s] error!\n", argv[1]);
return -1;
}
while (1)
{
readLen = fread(&startCode, MAX_PS_STARTCODE_LEN, 1, fp);
if (1 != readLen)
{
break;
}
startCode = ntohl(startCode);
#ifdef PRINTF_DEBUG
if (SCODE_PS_HEADER == startCode)
{
printf("+startCode: 0x%08X\n", startCode);
}
else
{
printf("%s+startCode: 0x%08X\n", TAB44, startCode);
}
#endif
if ((0 != (startCode>>24 & 0xff)) && (0 != (startCode>>16 & 0xff)) && (1 != (startCode>>8 & 0xff)))
{
return -1;
}
switch (startCode)
{
case SCODE_PS_HEADER:
memset(psData, 0x0, sizeof(psData));
readLen = fread(psData, 1, MMIN_PS_HEADER_LEN-4, fp);
if ((MMIN_PS_HEADER_LEN-4) != readLen)
{
fclose(fp);
return 0;
}
pack_stuffing_length = psData[MMIN_PS_HEADER_LEN-5] & 0x7;
fseek(fp, pack_stuffing_length, SEEK_CUR);
break;
case SCODE_PS_SYSTEM_HEADER:
if (1 != fread(&psSystemHeaderLen, 2, 1, fp))
{
fclose(fp);
return 0;
}
psSystemHeaderLen = ntohs(psSystemHeaderLen);
fseek(fp, psSystemHeaderLen, SEEK_CUR);
break;
case SCODE_PS_SYSTEM_MAP_HEADER:
if (1 != fread(&psSystemMapHeaderLen, 2, 1, fp))
{
fclose(fp);
return 0;
}
psSystemMapHeaderLen = ntohs(psSystemMapHeaderLen);
pesData = (unsigned char*)malloc(psSystemMapHeaderLen);
if (pesData)
{
memset(pesData, 0x0, pesPacketLen);
if (psSystemMapHeaderLen != fread(pesData, 1, psSystemMapHeaderLen, fp))
{
fclose(fp);
return 0;
}
parsePsSystemMapHeader(pesData);
free(pesData);
pesData = NULL;
}
break;
case SCODE_PS_END:
#ifdef PRINTF_DEBUG
printf("ps is end!\n");
#endif
return 0;
break;
/* pes pcaket */
default:
pesStreamId = startCode & 0xff;
if (1 != fread(&pesPacketLen, 2, 1, fp))
{
fclose(fp);
return 0;
}
pesPacketLen = ntohs(pesPacketLen);
pesData = (unsigned char*)malloc(pesPacketLen);
if (pesData)
{
memset(pesData, 0x0, pesPacketLen);
if (pesPacketLen != fread(pesData, 1, pesPacketLen, fp))
{
fclose(fp);
return 0;
}
parsePes(pesStreamId, pesData, pesPacketLen);
free(pesData);
pesData = NULL;
}
break;
}
}
fclose(fp);
return 0;
}