关于从海康威视或者大华摄像头获取PS数据流中的H264视频数据

PS流数据原理网上基本能够搜索到,这里我也就没必要粘贴复制,解析PS数据包主要分 00 00 00 ba 这是ps头,然后是系统头00 00 00 bb ,然后是Program Stream map包 00 00 00 bc 然后是H264数据00 00 00 e0 。

下面我附上代码,网上有类似的代码,但是有点问题,直接用的话会在视频下半部分出现花屏显现。这里所附C++代码形成两个文件可直接编译使用。

MediaPsAnaly.h:

MediaPsAnaly.h:

#ifndef MEDIAPSANALY_H
#define MEDIAPSANALY_H


#pragma pack(1)
union littel_endian_size {
	unsigned short int	length;
	unsigned char		byte[2];
};
struct pack_start_code {
	unsigned char start_code[3];
	unsigned char stream_id[1];
};
struct program_stream_pack_header {  //14字节
	pack_start_code PackStart;// 4
	unsigned char Buf[9];
	unsigned char stuffinglen;
};
struct program_stream_system_head {  //可能有系统头,pack_start_code为00 00 01 BB
	pack_start_code PackStart;
	littel_endian_size PackLength;
};
struct program_stream_map {
	pack_start_code PackStart;
	littel_endian_size PackLength;
};
struct program_stream_e {
	pack_start_code		PackStart; //4字节
	littel_endian_size	PackLength;//we mast do exchange  2字节
	char				PackInfo1[2]; //2字节
	unsigned char		stuffing_length; //1字节
};
#pragma pack()

class MediaPsAnaly {
private:
	MediaPsAnaly();
	~MediaPsAnaly();
public:
	/* 获取MediaManage对象唯一实例 */
	static MediaPsAnaly* getInstance();
	
	/* 获取h264数据 */
	int GetH246FromPs(unsigned char* buffer,int length, unsigned char *h264Buffer, int *h264length);

private:	
	/* 解析ps头 */
	int inline ProgramStreamPackHeader(unsigned char* Pack, int length, unsigned char **NextPack, int *leftlength);

	/* 去掉系统头 */
	inline int ProgramStreamSystemHead(unsigned char* Pack,int length,unsigned char **NextPack,int *leftlength);
		
	/* 去掉programstreammap */
	inline int ProgramStreamMap(unsigned char* Pack, int length, unsigned char **NextPack, int *leftlength, unsigned char **PayloadData, int *PayloadDataLen);
		
	/* 解pes包 */
	inline int Pes(unsigned char* Pack, int length, unsigned char **NextPack, int *leftlength, unsigned char **PayloadData, int *PayloadDataLen);
private:
	static MediaPsAnaly* p;
};

#endif //MEDIAPSANALY_H

MediaPsAnaly.cpp:

#include "MediaPsAnaly.h"
#include 
#include 
#include 
using namespace std;

#if 1
/*构造函数*/
MediaPsAnaly::MediaPsAnaly()
{
	
}

/* 析构函数 */
MediaPsAnaly::~MediaPsAnaly()
{

}

/* 对象实例指针 */ 
MediaPsAnaly* MediaPsAnaly::p = NULL;

/* 获取MediaPsAnaly对象唯一实例 */
MediaPsAnaly* MediaPsAnaly::getInstance() {
	if( p == NULL) {
		p = new MediaPsAnaly();
	}
	return p;
}

/* 解析ps头 */
int inline MediaPsAnaly::ProgramStreamPackHeader(unsigned char* Pack, int length, unsigned char **NextPack, int *leftlength)
{
	program_stream_pack_header *PsHead = (program_stream_pack_header *)Pack;
	unsigned char pack_stuffing_length = PsHead->stuffinglen & '\x07';
	*leftlength = length - sizeof(program_stream_pack_header) - pack_stuffing_length;//剩余字节:length减去头和填充的字节
	*NextPack = Pack+sizeof(program_stream_pack_header) + pack_stuffing_length;
	if(*leftlength<4) return 0; //无后续头部和数据	
	return *leftlength;
}
	
/* 去掉系统头 */
inline int MediaPsAnaly::ProgramStreamSystemHead(unsigned char* Pack,int length,unsigned char **NextPack,int *leftlength)
{
	program_stream_system_head *PssHead  = (program_stream_system_head*)Pack;
	littel_endian_size pssh_length;
	pssh_length.byte[0] = PssHead->PackLength.byte[1];
	pssh_length.byte[1] = PssHead->PackLength.byte[0];
	*leftlength = length - pssh_length.length - sizeof(program_stream_system_head);
	*NextPack = Pack + sizeof(program_stream_system_head) + pssh_length.length;
	if(*leftlength<4) return 0;
	return *leftlength;
}

/* 去掉programstreammap */
inline int MediaPsAnaly::ProgramStreamMap(unsigned char* Pack, int length, unsigned char **NextPack, int *leftlength, unsigned char **PayloadData, int *PayloadDataLen) {
	program_stream_map* PSMPack = (program_stream_map*)Pack;
	*PayloadData = 0;
	*PayloadDataLen = 0;
	if(length < sizeof(program_stream_map)) return 0;
	littel_endian_size psm_length;
	psm_length.byte[0] = PSMPack->PackLength.byte[1];
	psm_length.byte[1] = PSMPack->PackLength.byte[0];
	*leftlength = length - psm_length.length - sizeof(program_stream_map);
	if(*leftlength<=0) return 0;
	*NextPack = Pack + psm_length.length + sizeof(program_stream_map);
 	return *leftlength;
}

/* 解pes包 */
inline int MediaPsAnaly::Pes(unsigned char* Pack, int length, unsigned char **NextPack, int *leftlength, unsigned char **PayloadData, int *PayloadDataLen) {
	program_stream_e* PSEPack = (program_stream_e*)Pack;
	*PayloadData = 0;
	*PayloadDataLen = 0;
	if(length < sizeof(program_stream_e)) return 0;
	littel_endian_size pse_length;
	pse_length.byte[0] = PSEPack->PackLength.byte[1];
	pse_length.byte[1] = PSEPack->PackLength.byte[0];
	pse_length.byte[4] = PSEPack->stuffing_length;
	*PayloadDataLen = pse_length.length - 2 - 1 - pse_length.byte[4];
	if(*PayloadDataLen>0) {
		*PayloadData = Pack + sizeof(program_stream_e) + pse_length.byte[4];
	}
	*leftlength = length - pse_length.length - sizeof(pack_start_code) - sizeof(littel_endian_size);
	if(*leftlength<=0) return 0;
	*NextPack = Pack + sizeof(pack_start_code) + sizeof(littel_endian_size) + pse_length.length;
	return *leftlength;
}

/* 获取h264数据 */
int MediaPsAnaly::GetH246FromPs(unsigned char* buffer,int length, unsigned char *h264Buffer, int *h264length) {
	int leftlength = 0;
	unsigned char *NextPack = 0;
	*h264length = 0;
	if(ProgramStreamPackHeader(buffer, length, &NextPack, &leftlength)==0) {//跳过PS头
		return 0;
	}
	unsigned char *PayloadData=NULL; 
	int PayloadDataLen=0;
	if(NextPack && NextPack[0]==0 && NextPack[1]==0 && NextPack[2]==1 && NextPack[3]==0xbb) {//有系统头的话,跳过它
		if(ProgramStreamSystemHead(NextPack, leftlength, &NextPack, &leftlength)==0)
			return 0;
	}
	if(NextPack && NextPack[0]==0 && NextPack[1]==0 && NextPack[2]==1 && NextPack[3]==0xbc ) {//Program Stream map,直接跳过该包
			if(ProgramStreamMap(NextPack, leftlength, &NextPack, &leftlength, &PayloadData, &PayloadDataLen)==0) 
				return 0;
	}
	//printf("[%s] %x %x %x %x\n", __FUNCTION__, NextPack[0], NextPack[1], NextPack[2], NextPack[3]);
	while(leftlength >= sizeof(pack_start_code))  //处理pes包:目前所知的pes包的类型有Program Stream map和H264
	{
		PayloadData=NULL;
		PayloadDataLen=0;
		if(NextPack && NextPack[0]==00 && NextPack[1]==00 && NextPack[2]==01 && NextPack[3]==0xE0) {  //H264,需要提取出pes包的有效载荷,即H264码流
			//接着就是流包,说明是非i帧;若中间隔着Program Stream map,则是i帧; 提取H264流时,不需要区分i帧与非i帧
			if(Pes(NextPack, leftlength, &NextPack, &leftlength, &PayloadData, &PayloadDataLen)) {
				if(PayloadDataLen) {
					memcpy(h264Buffer, PayloadData, PayloadDataLen); 
					h264Buffer += PayloadDataLen;
					*h264length += PayloadDataLen;
				}
			}			
			else {//说明是最后一个pes包
				if(PayloadDataLen) {
					memcpy(h264Buffer, PayloadData, PayloadDataLen);
					h264Buffer += PayloadDataLen;
					*h264length += PayloadDataLen;
				}
			
				break;
			}
		}
		#if 1
		else if(NextPack && NextPack[0]==00 && NextPack[1]==00 && NextPack[2]==01 && NextPack[3]==0xBC) {//Program Stream map,直接跳过该包
			if(ProgramStreamMap(NextPack, leftlength, &NextPack, &leftlength, &PayloadData, &PayloadDataLen)==0) {
				break;
			}
		}
		#endif
		else {
			//printf("[%s]no konw %02x %02x %02x %02x %02x %02x %02x %02x\n", __FUNCTION__, NextPack[0], NextPack[1], NextPack[2], NextPack[3],NextPack[4], NextPack[5], NextPack[6], NextPack[7]);
			break;
		}
	}
	return *h264length;
}

#endif

 

你可能感兴趣的:(PS转H264)