Program Stream 解析代码
PS和PES中使用的Head结构全部定义了。解析流程写的差不多,只是Head的后面部分属性没有解析取值。
ps_parser.h
typedef struct _PS_PACK_HEAD
{
NC_UN_INT32 start_code;//0-3
NC_UN_INT16 sys_colock_ref_base;//4.3-4.5
bool scr_marker1;//4.6
NC_UN_INT32 scr_base1;//4.7-6.5
bool scr_marker2;//6.6
NC_UN_INT32 scr_base2;//6.7-8.5
bool scr_marker3;//8.6
NC_UN_INT16 scr_ext;//8.7-9.7
bool scr_ext_marker;//9.8
NC_UN_INT32 multiplex_rate;//10-12.6
bool mulp_marker1;//12.7
bool mulp_marker2;//12.8
NC_UN_INT16 reserved;//13.1-13.5
NC_UN_INT16 stuffingLenth;//13.6-13.8
} PS_PACK_HEAD;
typedef struct _PS_SYSTEM_HEAD
{
NC_UN_INT32 start_code;//0-3
NC_UN_INT16 head_length;//4-5
bool marker1;//6.1
NC_UN_INT32 rate_bound;//6.2-8.7
bool marker2;//8.8
NC_UN_INT16 audio_bound;//9.1-9.6
bool fixed_flag;
bool csps_flag;
bool sys_audio_local_flag;
bool sys_video_local_flag;
bool marker3;//10.3
NC_UN_INT16 video_bound;//10.4-10.8
bool packet_rate_restric_flag;
NC_UN_INT16 reserved;//11.2-11.8
NC_UN_INT16 stream_id;//12
bool P_STD_buffer_bound_scale;//13.3
NC_UN_INT16 P_STD_buff_size_bound;//13.4-14.8
} PS_SYSTEM_HEAD;
typedef struct _PES_PACKET
{
NC_UN_INT16 stream_id;// 3 | 110xxxxx for audio,1110xxxx for video;
NC_UN_INT16 pesPacketLength;//4-5(2B)
// If stream ID is Private Stream 2 or Padding Stream, skip to data bytes.
NC_UN_INT16 alwaysFlag;
NC_UN_INT16 scramblingControl;//6.3-6.4
bool priority;//6.5
bool alignment;//6.6
bool copyrighted;//6.7
bool original;//6.8
// These flags are set if the corresponding data structure follows the datalength byte.
bool PTS;
bool DTS;
bool ESCR;
bool ESrate;
bool DSMtrickMode;
bool additional;
bool CRC;
bool extensionFlag;
NC_UN_INT16 PESheadDataLength;
unsigned char * pESData;
NC_UN_INT16 ESDataLength;
ES_DATA esData;
} PES_PACKET;
class NcPsParsedData
{
public:
NcPsParsedData(){
m_hasSysHead = false; m_readLenth = 0;
memset(&PsPackHead, 0, sizeof(PS_PACK_HEAD));
memset(&PsSysHead, 0, sizeof(PS_SYSTEM_HEAD));
memset(&PesPacket, 0, sizeof(PES_PACKET));
}
~NcPsParsedData(){}
public:
PS_PACK_HEAD PsPackHead;
PS_SYSTEM_HEAD PsSysHead;
PES_PACKET PesPacket;
public:
const bool HasPackHead(){
return m_hasPackHead;
}
const bool HasSysHead(){
return m_hasSysHead;
}
const bool HasPESPacket(){
return m_hasPESPacket;
}
void SetPackHead(bool val){
m_hasPackHead = val;
}
void SetSysHead(bool val){
m_hasSysHead = val;
}
void SetPESPacket(bool val){
m_hasPESPacket = val;
}
void AddReadLength(unsigned int addLength){ m_readLenth = m_readLenth + addLength; }
const unsigned int ReadLenght(){ return m_readLenth; }
bool IsVideoStream()
{
// Examples: Audio streams (0xC0-0xDF), Video streams (0xE0-0xEF)
if (PesPacket.stream_id >= 0xE0 && PesPacket.stream_id <= 0xEF)
{
return true;
}
return false;
}
bool IsAudioStream()
{
if (PesPacket.stream_id >= 0xC0 && PesPacket.stream_id <= 0xDF)
{
return true;
}
return false;
}
private:
bool m_hasPackHead;
bool m_hasSysHead;
bool m_hasPESPacket;
unsigned int m_readLenth;
};
class NcPsPacketParser
{
public:
NcPsPacketParser();
//NcPsPacketParser(const unsigned char * pBuff, unsigned int len);
~NcPsPacketParser();
NC_PS_ERROR Parse(const unsigned char *pData, int len, NcPsParsedData &psParsedData);
NC_PS_ERROR ParsePsPackHead(const unsigned char * pBuff, int len, PS_PACK_HEAD &psPackHead);
NC_PS_ERROR ParsePsSystemHead(const unsigned char * pBuff, int len, PS_SYSTEM_HEAD &psSysHead);
NC_PS_ERROR ParsePESPacket(const unsigned char * pBuff, int len, PES_PACKET &pesPacket);
NC_PS_ERROR PickupPESToFile();
private:
NC_PS_ERROR pickupMpeg2Data(const unsigned char * pBuff, int len, PES_PACKET &pesPacket);
int createFileName();
private:
const unsigned char * m_pBuff;
unsigned int m_iLen;
char m_file[256];
bool m_bOutputPes;
CESPacketAnalyzer * m_pEsAnalyzer;
};
ps_parser.cpp
unsigned char ps_pack_start_code [4] = { 0x00, 0x00, 0x01, 0xba };
unsigned char ps_pack_end_code [4] = { 0x00, 0x00, 0x01, 0xb9 };
unsigned char sys_head_start_code [4] = { 0x00, 0x00, 0x01, 0xbb };
unsigned char packet_start_code_prefix[3] = { 0x00, 0x00, 0x01 };
static unsigned int s_iFrames;
static NC_UN_INT16 bytesToUint16(const unsigned char * p)
{
NC_UN_INT16 value = 0;
value = ((*p++) << 8);
value = value + (*p);
return value;
}
static NC_UN_INT32 bytesToUint32(const unsigned char * p)
{
NC_UN_INT32 value = 0;
value = ((*p++) << 24);
value = value + ((*p++) << 16);
value = value + ((*p++) << 8);
value = value + (*p);
return value;
}
static NC_UN_INT32 parseMuxRate(const unsigned char *p)
{
NC_UN_INT32 tmp;
tmp = *p++;
tmp <<= 8;
tmp += *(p++);
tmp <<= 8;
tmp += *(p++);
tmp = (tmp & 0xfffffc) >> 2;
return tmp;
}
static NC_UN_INT16 parseSCRbase(const unsigned char *p)
{
NC_UN_INT32 tmp;
tmp = *p++;
tmp <<= 8;
tmp += *(p++);
tmp <<= 8;
tmp += *p;
tmp = (tmp & 0x3fff8) >> 3;
return tmp;
}
static NC_UN_INT16 parseSCRextension(const unsigned char *p)
{
NC_UN_INT16 tmp;
tmp = *p++;
tmp <<= 8;
tmp += *p;
tmp = (tmp & 0x3fe) >> 1;
return tmp;
}
NcPsPacketParser::NcPsPacketParser()
: m_pBuff(NULL), m_iLen(0), m_bOutputPes(false)
{
m_pEsAnalyzer = new CESPacketAnalyzer();
}
//NcPsPacketParser::NcPsPacketParser(const unsigned char * pBuff, unsigned int len)
// : m_pBuff(NULL), m_iLen(len), m_bOutputPes(false)
//{
// m_pEsAnalyzer = new CESAnalyzer();
//}
NcPsPacketParser::~NcPsPacketParser()
{
if (NULL != m_pEsAnalyzer)
{
delete m_pEsAnalyzer;
m_pEsAnalyzer = NULL;
}
}
NC_PS_ERROR NcPsPacketParser::Parse(const unsigned char *pData, int len, NcPsParsedData &psParsedData)
{
NC_PS_ERROR result = OK;
int buffLen = len;
psParsedData.SetPackHead(false);
psParsedData.SetSysHead(false);
psParsedData.SetPESPacket(false);
do
{
// Is PS packete start code ?
if (memcmp(pData, ps_pack_start_code, sizeof(ps_pack_start_code)) == 0)
{
result = ParsePsPackHead(pData, len, psParsedData.PsPackHead);
if (result != OK)
{
return result;
}
psParsedData.SetPackHead(true);
psParsedData.AddReadLength(14 + psParsedData.PsPackHead.stuffingLenth);
int buffLen = len -14 - psParsedData.PsPackHead.stuffingLenth;
pData = pData + 14 + psParsedData.PsPackHead.stuffingLenth;
if (memcmp(pData, sys_head_start_code, sizeof(sys_head_start_code)) == 0)
{
result = ParsePsSystemHead(pData, buffLen, psParsedData.PsSysHead);
if (result != OK)
{
return result;
}
psParsedData.SetSysHead(true);
psParsedData.AddReadLength(6+psParsedData.PsSysHead.head_length);
}
}
// Is PES packete start code prefix ?
if (memcmp(pData, packet_start_code_prefix, sizeof(packet_start_code_prefix)) == 0)
{
result = ParsePESPacket(pData, buffLen, psParsedData.PesPacket);
if (result != OK)
{
return result;
}
psParsedData.SetPESPacket(true);
}
else
{
pickupMpeg2Data(pData, len, psParsedData.PesPacket);
}
} while(0);
return OK;
}
NC_PS_ERROR NcPsPacketParser::ParsePsPackHead(const unsigned char * pBuff, int len, PS_PACK_HEAD &psPackHead)
{
const unsigned char *p = pBuff;
int tmp;//32bit temp
memset(&psPackHead, 0, sizeof(PS_PACK_HEAD));
//if (memcmp(p, ps_pack_start_code, sizeof(ps_pack_start_code)) != 0)
//{
// return NOT_CORRECT_SATR_CODE;
//}
psPackHead.start_code = bytesToUint32(p);
p += 4;
tmp = *p;
if ( ((tmp >> 6) & 3) != 1)//always set 01
{
return NOT_MPEG2;
}
psPackHead.sys_colock_ref_base = ((*p) >> 3) & 0x7;
psPackHead.scr_marker1 = ((*p) >> 2) & 0x1;
psPackHead.scr_base1 = parseSCRbase(p);
p += 2;
psPackHead.scr_marker2 = ((*p) >> 2) & 0x1;
psPackHead.scr_base2 = parseSCRbase(p);
p += 2;
psPackHead.scr_marker3 = ((*p) >> 2) & 0x1;
psPackHead.scr_ext = parseSCRextension(p);//p->8
// get mux rate
p += 2;
psPackHead.multiplex_rate = parseMuxRate(p);
p = pBuff + 13;
psPackHead.stuffingLenth = (*p) & 0x07;
return OK;
}
NC_PS_ERROR NcPsPacketParser::ParsePsSystemHead(const unsigned char * pBuff, int len, PS_SYSTEM_HEAD &psSysHead)
{
NC_PS_ERROR result = OK;
const unsigned char * p = pBuff;
memset(&psSysHead, 0, sizeof(PS_SYSTEM_HEAD));
//if (memcmp(p, sys_head_start_code, sizeof(sys_head_start_code)) != 0)
//{
// return NOT_CORRECT_SATR_CODE;
//}
psSysHead.start_code = bytesToUint32(p);
p = p + 4;
psSysHead.head_length = bytesToUint16(p);
p++;
psSysHead.marker1 = (*p) & 0x80;
psSysHead.rate_bound = (*p) & 0x7F;
psSysHead.rate_bound = psSysHead.rate_bound << 8;
p++;
psSysHead.rate_bound = psSysHead.rate_bound + (*p);
psSysHead.rate_bound = psSysHead.rate_bound << 8;
p++;
psSysHead.rate_bound = psSysHead.rate_bound + (*p)&0xFE;
psSysHead.rate_bound = psSysHead.rate_bound >> 1;
p++;
//psSysHead.audio_bound =
p = pBuff + 12;
psSysHead.stream_id = (*p);
return result;
}
NC_PS_ERROR NcPsPacketParser::ParsePESPacket(const unsigned char * pBuff, int len, PES_PACKET &pesPacket)
{
NC_PS_ERROR result = OK;
const unsigned char * p = pBuff;
const unsigned char * pDataStart = NULL;
const unsigned char * pDataEnd = NULL;
NC_UN_INT16 dataCount = 0;
NC_UN_INT16 buffLen = 0;
NC_UN_INT16 flags;
memset(&pesPacket, 0, sizeof(PES_PACKET));
//if (memcmp(p, packet_start_code_prefix, sizeof(packet_start_code_prefix)) != 0)
//{
// return NOT_CORRECT_PES_PREFIX;
//}
p += 3; // skip start_code_prefix to stream_id
pesPacket.stream_id = *p++;
pesPacket.pesPacketLength = *p++;
pesPacket.pesPacketLength <<= 8;
pesPacket.pesPacketLength += *p++;// p point to [Always set to 10]
pDataEnd = p + pesPacket.pesPacketLength;
if (pesPacket.stream_id == NC_PS_PADDING_STREAM)
{
return PADDING_STREAM_SKIP;
}
flags = *(p++) << 8;
flags += *(p++);
pesPacket.alwaysFlag = (flags >> 14) & 0x3;
if (pesPacket.alwaysFlag != 0x2)
{
return BAD_STREAM;
}
pesPacket.PESheadDataLength = *(p++);
pDataStart = p + pesPacket.PESheadDataLength;
dataCount = pDataEnd - pDataStart;
buffLen = len - (pDataStart - pBuff);
dataCount = dataCount > buffLen ? buffLen : dataCount;
if (m_bOutputPes)
{
pickupMpeg2Data(pDataStart, dataCount, pesPacket);
}
this->m_pEsAnalyzer->Analyse(pDataStart, dataCount, pesPacket.esData);
if (1)
{
}
return result;
}
NC_PS_ERROR NcPsPacketParser::pickupMpeg2Data(const unsigned char * pBuff, int len, PES_PACKET &pesPacket)
{
if (!m_bOutputPes)
{
return OK;
}
FILE *fp = fopen(m_file, "ab");
if (fp == NULL)
{
return OTHER_ERROR;
}
fwrite(pBuff, sizeof(unsigned char), len, fp);
fclose(fp);
return OK;
}
NC_PS_ERROR NcPsPacketParser::PickupPESToFile()
{
m_bOutputPes = true;
createFileName();
return OK;
}