手写解复用(五):PS(MPEG2)解析

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;
}

  • 21
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FlightYe

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值