国标PS流解包(解封装)代码

本文介绍了一段修复和完善后的PS流解包代码,适用于GB28181标准,包括streamdef.h、PsPacket.h和PsToEsConsole.cpp三个文件。代码能够解析PS包提取PES,解析PSM,进行数据完整性验证,并处理实时流中的数据缺失。提供了参考资料链接,适合国标开发者参考学习。
摘要由CSDN通过智能技术生成

该代码最初的版本来自于互联网,首先感谢前辈无私分享的精神,这个PS流解析代码小巧和可读性好,是学习PS格式的一个很好的参考例子。但原来的代码有不少Bug,QuickGBLink在原先代码基础上做了很多问题修复和改进,现在对代码开源,希望能帮助更多国标开发者开发相关的功能。

实现的功能:

1. 解析PS包,从中提取出PES。

2. 解析PSM(节目流映射表),获得每个流的信息。

3. 对流格式做一些合法性判断和验证,检查数据是否完整。

4. 对实时流做了一些特殊处理,检查数据有无缺损或丢包,如果有则丢掉该块,从下一个PS头开始读起。

这个PS流解包的代码包含两个文件:streamdef.h, PsPacket.h,另外写了一个调用的例子(文件名:PsToEsConsole.cpp )。

streamdef.h文件

#ifndef _STREAMDEF_H_
#define _STREAMDEF_H_
#define MAX_PS_LENGTH  (1024*800)
#define MAX_PES_LENGTH (1024*1000)
#define MAX_ES_LENGTH  (0x100000)
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;

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

typedef struct RTP_HEADER
{
#ifdef ORTP_BIGENDIAN
    uint16_t version:2;
    uint16_t padbit:1;
    uint16_t extbit:1;
    uint16_t cc:4;
    uint16_t markbit:1;
    uint16_t paytype:7;
#else
    uint16_t cc:4;
    uint16_t extbit:1;
    uint16_t padbit:1;
    uint16_t version:2;
    uint16_t paytype:7;  //负载类型
    uint16_t markbit:1;  //1表示前面的包为一个解码单元,0表示当前解码单元未结束
#endif
    uint16_t seq_number;  //序号
    uint32_t timestamp; //时间戳
    uint32_t ssrc;  //循环校验码
    //uint32_t csrc[16];
} RTP_header_t;
 
typedef struct ps_header{
    unsigned char pack_start_code[4];  //'0x000001BA'
 
    unsigned char system_clock_reference_base21:2;
    unsigned char marker_bit:1;
    unsigned char system_clock_reference_base1:3;
    unsigned char fix_bit:2;    //'01'
 
    unsigned char system_clock_reference_base22;
 
    unsigned char system_clock_reference_base31:2;
    unsigned char marker_bit1:1;
    unsigned char system_clock_reference_base23:5;
 
    unsigned char system_clock_reference_base32;
    unsigned char system_clock_reference_extension1:2;
    unsigned char marker_bit2:1;
    unsigned char system_clock_reference_base33:5; //system_clock_reference_base 33bit
 
    unsigned char marker_bit3:1;
    unsigned char system_clock_reference_extension2:7; //system_clock_reference_extension 9bit
 
    unsigned char program_mux_rate1;
 
    unsigned char program_mux_rate2;
    unsigned char marker_bit5:1;
    unsigned char marker_bit4:1;
    unsigned char program_mux_rate3:6;
 
    unsigned char pack_stuffing_length:3;
    unsigned char reserved:5;
}ps_header_t;  //14
 
typedef struct sh_header
{
    unsigned char system_header_start_code[4]; //32
 
    unsigned char header_length[2];            //16 uimsbf
 
    uint32_t marker_bit1:1;   //1  bslbf
    uint32_t rate_bound:22;   //22 uimsbf
    uint32_t marker_bit2:1;   //1 bslbf
    uint32_t audio_bound:6;   //6 uimsbf
    uint32_t fixed_flag:1;    //1 bslbf
    uint32_t CSPS_flag:1;     //1 bslbf
 
    uint16_t system_audio_lock_flag:1;  // bslbf
    uint16_t system_video_lock_flag:1;  // bslbf
    uint16_t marker_bit3:1;             // bslbf
    uint16_t video_bound:5;             // uimsbf
    uint16_t packet_rate_restriction_flag:1; //bslbf
    uint16_t reserved_bits:7;                //bslbf
    unsigned char reserved[6];
}sh_header_t; //18
 
//注意: 该PSM表结构有误,PSM表结构是可变长度的,包含的流的数目不同,长度也不一样。从22处开始后面的字段内容在不同情况下会有变化,详情请看PS格式中关于PSM的结构定义
typedef struct psm_header{
    unsigned char promgram_stream_map_start_code[4];
 
    unsigned char program_stream_map_length[2];
 
    unsigned char program_stream_map_version:5;
    unsigned char reserved1:2;
    unsigned char current_next_indicator:1;
 
    unsigned char marker_bit:1;
    unsigned char reserved2:7;
 
    unsigned char program_stream_info_length[2];
    unsigned char elementary_stream_map_length[2];
	//11: 下面可能会有多段Stream的定义,Stream的数目依据上面的elementary_stream_map_length的长度决定,StreamNum = elementary_stream_map_length/4
    unsigned char stream_type;
    unsigned char elementary_stream_id;
    unsigned char elementary_stream_info_length[2];
	//22:
    unsigned char CRC_32[4];
    unsigned char reserved[16];
}psm_header_t; 

struct program_stream_map
{
	pack_start_code PackStart;
	littel_endian_size PackLength;
};
 
typedef struct pes_header
{
    unsigned char pes_start_code_prefix[3];
    unsigned char stream_id;
    unsigned short PES_packet_length;
}pes_header_t; //6
 
typedef struct optional_pes_header{
    unsigned char original_or_copy:1;
    unsigned char copyright:1;
    unsigned char data_alignment_indicator:1;
    unsigned char PES_priority:1;
    unsigned char PES_scrambling_control:2;
    unsigned char fix_bit:2;
 
    unsigned char PES_extension_flag:1;
    unsigned char PES_CRC_flag:1;
    unsigned char additional_copy_info_flag:1;
    unsigned char DSM_trick_mode_flag:1;
    unsigned char ES_rate_flag:1;
    unsigned char ESCR_flag:1;
    unsigned char PTS_DTS_flags:2;
 
    unsigned char PES_header_data_length;
}optional_pes_header_t;
 
#pragma pack ()
 
 
enum PSStatus
{
    ps_padding, //未知状态
    ps_ps,      //ps状态
    ps_sh,
    ps_psm,
    ps_pes,
    ps_pes_video,
    ps_pes_audio
};

typedef struct _program_map_info
{
    unsigned char stream_type;
    unsigned char elementary_stream_id;
}program_map_info;
 
#endif

PsPacket.h文件

#ifndef _PSUNPACKET_H_
#define _PSUNPACKET_H_

#include <atlbase.h>
#include "streamdef.h"
#include <vector>
using namespace std;

#define MAX_VIDEO_BUFSIZE  (200*1024)

struct ESFrameData
{
	unsigned char*	buffer;
	int				len;
	int             frame_num; //缓冲区中帧的数目
	unsigned char	cFrameType;			//帧的类型, 'I'、 'P'、 'B'
	unsigned int	bDropFrame;			//是否丢掉该帧,如果有丢包,则丢掉
	//PSStatus        ps_status;   //PS的类型
	 __int64  first_pts_time; //帧缓存里可能含有多帧,记录第一帧的时间戳
	 __int64 ptsTime; //帧缓存里最后一帧的时间戳
	 __int64 dtsTime;
	 unsigned char pts_dts_flag; //一个PS帧由多个PES帧组成,其中开头帧有时间戳,值为2(有PTS)或3(有PTS和DTS),而除开头帧之外的其他帧,该值为0,并且PTS和DTS都为0.
};


//#include <tuple>
//using namespace std::tr1;

#ifndef AV_RB16
#   define AV_RB16(x)               
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值