📄 mediademux.cpp
字号:
wSegHeaderLen = GET2(rlpIn) >> 4;
if(false == CheckCRC32(rlpIn, wSegHeaderLen))
{
wVideoUnitNum = 0;
return DEMUX_CRC_ERROR;
}
int i = 0;
LPBYTE end = rlpIn + wSegHeaderLen;
rlpIn += 2;
while(rlpIn + MIN_ONEVIDEOUNIT_PARAMSHOLD_BYTE <= end)
{
tVideoUnitParams[i].wUnitLen = STEP2(rlpIn);
//printf("Video Unit Length = %d\n", tVideoUnitParams[i].wUnitLen);
BYTE u8TP_SN_EF_RPTF = STEP1(rlpIn);
tVideoUnitParams[i].nType = u8TP_SN_EF_RPTF >> 5; // 3, Frame Type, I/B/P
tVideoUnitParams[i].nStreamNum = (u8TP_SN_EF_RPTF >> 2) & 7; // 3, Stream ID
tVideoUnitParams[i].nEndFlag = (u8TP_SN_EF_RPTF >> 1) & 1; // 1, true if the frame is complete
tVideoUnitParams[i].nRTFlag = u8TP_SN_EF_RPTF & 1; // 1, Releative time stamp
//printf("StreamID = %d, type = %d (0 is I Frame)\n", tVideoUnitParams[i].nStreamNum, tVideoUnitParams[i].nType);
if(tVideoUnitParams[i].nEndFlag)
{
//printf("Video frame END\n", tVideoUnitParams[i].nType);
}
if (tVideoUnitParams[i].nRTFlag)
{
tVideoUnitParams[i].wRelativeTime = STEP2(rlpIn);
//printf("Relative timestamp = %x\n", tVideoUnitParams[i].wRelativeTime);
}
else
{
tVideoUnitParams[i].wRelativeTime = 0;// in 1/22500, value: [0, 2912.666(65535/22500)] ms
}
i++;
}
wVideoUnitNum = i;
rlpIn += 4;
return 0;
}
/* Ƶͷ */
DWORD CAudioDataSegHeader::Parse(LPBYTE& rlpIn)
{
nUnitNum = GET1(rlpIn);
if(false == CheckCRC32(rlpIn, AUDIO_UNIT_CNTHOLD_BYTE + nUnitNum * ONE_AUDIO_UNIT_PARAMS_HOLD_BYTE))
{
nUnitNum=0;
return DEMUX_CRC_ERROR;
}
/*====================================================================*/
rlpIn ++;
for (int i = 0; i < nUnitNum; i++)
{
tAudioUnitParams[i].wUnitLen = STEP2(rlpIn);
BYTE u8TrackNum_Reserve = STEP1(rlpIn);
tAudioUnitParams[i].nTrackNum = u8TrackNum_Reserve >> 5; // 3
tAudioUnitParams[i].nReserve = u8TrackNum_Reserve & 0x1f;
tAudioUnitParams[i].wRelativeTime = STEP2(rlpIn);
}
rlpIn += 4;
return DEMUX_NO_ERROR;
}
DWORD CDataDataSegHeader::Parse(/*IN/OUT*/LPBYTE& rlpIn, DWORD dwDataSegLen)
{
nUnitNum = GET1(rlpIn);
if(false == CheckCRC32(rlpIn, DATA_UNIT_CNTHOLD_BYTE + nUnitNum * ONE_DATA_UNIT_PARAMS_HOLD_BYTE))
{
nUnitNum = 0;
return DEMUX_CRC_ERROR;
}
rlpIn++;
for (int i = 0; i < nUnitNum; i++)
{
tDataUnitParams[i].nUnitType = STEP1(rlpIn);
tDataUnitParams[i].wUnitLen = STEP2(rlpIn);
}
rlpIn += 4; //DO NOT remove this line, since it is a OUT parameter
return DEMUX_NO_ERROR;
}
void CDemuxer::OnProgramGuide(CProgramGuide&pf){}
void CDemuxer::OnESGData(LPBYTE, DWORD){}
DWORD CProgramGuide::Parse(LPBYTE lpIn, DWORD len)
{
if(false == CheckCRC32(lpIn, len))
return DEMUX_CRC_ERROR;
nRecordCount = STEP1(lpIn);
nRecordCount >>= 6; // 2 bits
for(int i=0;i<nRecordCount;i++)
{
record[i].MJDate = STEP2(lpIn); //
*(lpIn-2) = 0;
*(lpIn-1) = 0;
STEPTIME(lpIn, record[i].nHour, record[i].nMinute,record[i].nSecond);
record[i].durationTime= STEP2(lpIn); // 16 bits
record[i].language[0] = STEP1(lpIn); // 24 bits
record[i].language[1] = STEP1(lpIn);
record[i].language[2] = STEP1(lpIn);
record[i].language[3] = 0;
record[i].themeLength= STEP1(lpIn); // 8 bits
record[i].theme = lpIn;
lpIn += record[i].themeLength; //
}
*lpIn = 0;
*(lpIn+1) = 0;
return DEMUX_NO_ERROR;
}
// Apr 15, 2008 Ge Yanlei Check with the standard-GY220.5
bool CXpe::ParseHeader(LPBYTE& rlpIn, DWORD len)
{
WORD temp = STEP2(rlpIn);
startFlag = temp>>15;
endFlag = temp>>14;
flag = temp>>13;
pl = temp&0xfff;
temp = STEP1(rlpIn);
crcFlag = temp>>7;
transSN = temp;
int header_len = 3;
if(startFlag)
{
if(endFlag == 0)
{
dataLength = STEP2(rlpIn);
header_len += 2;
}
if (flag == 0)
{ //XPE Package
temp = STEP1(rlpIn);
serviceModeFlag = temp>>7; //0:stream; 1:file
++ header_len;
}
else
{ //XPE_FEC
fec.FEC_type = STEP1(rlpIn);
fec.FEC_Length = STEP1(rlpIn);
STEPS(fec.FEC, rlpIn, fec.FEC_Length);
header_len += fec.FEC_Length+2;
}
}
checksum8 = STEP1(rlpIn);
LPBYTE pTemp = rlpIn - header_len - 1;
BYTE calcChecksum8 = 0;
for(int i = 0; i < header_len; i++)
{
calcChecksum8 ^= pTemp[i];
}
return calcChecksum8==checksum8;
}
#ifndef RTP_OUTPUT_SUPPORT
int CDemuxer::RtpToNal(DWORD ts, BYTE * buf, int len,NAL_FRAGMENT_POS_IND StartEndInd )
{
BYTE nal = buf[0];
BYTE type = (nal & 0x1f);
/*
if(type == 12)
{
OnVideoNalData(ts, 0, 0, StartEndInd);
return 0;
}
//*/
if (type >= 1 && type <= 23)
{
buf[-3] = 0;
buf[-2] = 0;
buf[-1] = 1;
OnVideoNalData(ts, buf-3, len+3, StartEndInd);
return 0;
}
if(type == 24) // STAP-A (one packet, multiple nals)
{
buf++;
len--;
BYTE *src= buf;
NAL_FRAGMENT_POS_IND start = NAL_FRAGMENT_POS_IND(StartEndInd & FRAME_BEGIN);
NAL_FRAGMENT_POS_IND end = NAL_FRAGMENT_POS_IND(StartEndInd & FRAME_TAIL);
NAL_FRAGMENT_POS_IND lastnal = FRAME_MID;
while(src < buf + len - 2)
{
WORD nal_size = GET2(src); // this going to be a problem if unaligned (can it be?)
if(src + nal_size + 2 > buf + len)
{
break;
}
src[-1] = 0;
src[0] = 0;
src[1] = 1;
lastnal =( ((src+nal_size + 2)>=(buf + len - 2))?FRAME_TAIL:FRAME_MID);
OnVideoNalData(ts, src-1, nal_size+3, NAL_FRAGMENT_POS_IND(start|(end&lastnal)));
start = FRAME_MID;
src += nal_size + 2;
}
return 0;
}
if(type == 25/*STAP-B*/ || type == 26/*MTAP-16*/|| type == 27/*MTAP-24*/|| type == 29/*FU-B*/) //
{
printf("Unhandled type (%d) (See RFC for implementation details\n",type);
return -1;
}
if(type == 28) // FU-A (fragmented nal)
{
buf++;
len--; // skip the fu_indicator
// these are the same as above, we just redo them here for clarity...
BYTE fu_indicator = nal;
BYTE fu_header = *buf; // read the fu_header.
BYTE start_bit = fu_header >> 7;
BYTE end_bit = (fu_header >> 6) & 1;
BYTE reconstructed_nal;
// reconstruct this packet's true nal; only the data follows..
reconstructed_nal = fu_indicator & 0xe0; // the original nal forbidden bit and NRI are stored in this packet's nal;
reconstructed_nal |= fu_header&0x1f;
// skip the fu_header...
buf++;
len--;
if(start_bit)
{
buf[-4] = 0;
buf[-3] = 0;
buf[-2] = 1;
buf[-1] = reconstructed_nal;
OnVideoNalData(ts, buf-4, len + 4, StartEndInd);
//fprintf(f, "start\n");
}
else
{
OnVideoNalData(ts, buf, len, StartEndInd);
//fprintf(f, "append\n");
}
return 0;
}
printf("Unhandled type (%d)\n",type);
return -1;
}
#else
void CDemuxer::NalToRtp(WORD &seq, DWORD ts, LPBYTE nal, DWORD nalSize)
{
CRtp rtp;
rtp.cc = 0;
rtp.m = 0;
rtp.p = 0;
rtp.ssrc_0 = 0;
rtp.ssrc_1 = 0;
rtp.ssrc_2 = 0;
rtp.ssrc_3 = 0;
rtp.version = 2;
rtp.pt = RTP_PT_H264;
int fu_hdr_len = 1;
DWORD outlen;
bool firstFragment = true;
int offset = 0;
unsigned char NALhdr = nal[3];
unsigned char NALtype = NALhdr & 0x1f;
rtp.ts_0 = (BYTE) (ts>>24);
rtp.ts_1 = (BYTE) (ts>>16);
rtp.ts_2 = (BYTE) (ts>>8);
rtp.ts_3 = (BYTE) (ts);
if (nalSize < 4)
return;
nalSize -= 4;
while(nalSize > 0)
{
rtp.seq_h = (BYTE)(seq>>8);
rtp.seq_l = (BYTE)(seq);
seq++;
rtp.pt = RTP_PT_H264;
if (nalSize <= NAL_FRAG_THRESH)
{
//==============================================
//Single NAL or last fragment of FU-A
//==============================================
rtp.m = 1; // set M bit
outlen = nalSize + RTP_HDR_LEN + fu_hdr_len;
if (fu_hdr_len==2)
{
//==============================================
//Last fragment of FU-A
//==============================================
rtp.data[0] = 0x00 | (NALhdr & 0x60) | 28; //FU indicator
rtp.data[1] = 0x40 | NALtype; //FU header
}
else
{
rtp.data[0] = NALhdr; //NAL Header
}
memcpy(rtp.data + fu_hdr_len, nal + offset + 4, nalSize);
nalSize = 0;
offset = 0;
}
else
{
//==============================================
//FU-A (not the last fragment though)
//==============================================
rtp.m = 0; // set M bit
fu_hdr_len = 2;
outlen = (NAL_FRAG_THRESH - fu_hdr_len) + RTP_HDR_LEN + fu_hdr_len;
rtp.data[0] = 0x00 | (NALhdr & 0x60) | 28; //FU indicator
rtp.data[1] = ( (firstFragment) ? 0x80 : 0x00 ) | NALtype; //FU header
memcpy(rtp.data+fu_hdr_len, nal + offset + 4, NAL_FRAG_THRESH - fu_hdr_len);
nalSize -= (NAL_FRAG_THRESH-fu_hdr_len);
offset += (NAL_FRAG_THRESH-fu_hdr_len);
firstFragment = false;
}
OnAvRtpPacket((LPBYTE)&rtp, outlen);
}
}
#endif
void CDemuxer::OnFileModeXpe(LPBYTE dest, WORD length){}
#ifndef RTP_OUTPUT_SUPPORT
void CDemuxer::RtpToAacFrame(DWORD ts, LPBYTE data, WORD len) //For AAC Audio
{
LPBYTE lpEnd = data + len;
while(data < lpEnd)
{
WORD length = data[0];
if(data + length > lpEnd)
break;
switch(length)
{
case 0xff:length = 0x100 + data[1] - 1;data+=2;break;
case 0xfe:length = 0x200 + data[1] - 1;data+=2;break;
default:data++;break;
}
OnAudioAacFrame(ts, data, length);
data+=length;
}
}
#endif
void CDemuxer::OnEcmPacket(LPBYTE data, size_t len, int CAS_ID) {} //For ECM, max len of ECM is 255
int CDemuxer::OnAVMode2Fragment(DWORD ts, LPBYTE & lpStart, LPBYTE lpEnd, int data_type)
{
BYTE startByte = STEP1(lpStart);
if(startByte == 0x55)
{
int start, end;
WORD temp = STEP2(lpStart);
WORD pkLen = temp&0xfff;
BYTE crc8 = STEP1(lpStart);
BYTE realcrc8 = CalcCRC8(lpStart-4, 3);
BYTE startendInd = FRAME_MID;
BYTE pkType = (temp>>12) & 3;
start = (temp>>15) & 1;
end = (temp>>14) & 1;
if (start == 0)
{
if (end == 1)
startendInd = FRAME_TAIL;
else
startendInd = FRAME_MID;
}
else if (start == 1)
{
if (end != 1)
{
startendInd = FRAME_BEGIN;
}
else
{
startendInd = WHOLE_FRAME;
}
}
if(realcrc8 == crc8)
{
#ifdef RTP_OUTPUT_SUPPORT
CRtpHeader* pRtp = (CRtpHeader*)(lpStart - 12);
//TODO
//m=1:Single NAL or last fragment of FU-A
//m=0:FU-A (not the last fragment though)
if((startendInd == FRAME_MID) || (startendInd == FRAME_BEGIN))
pRtp->m=0;
else
pRtp->m=1;
pRtp->p=0;
pRtp->cc=0;
pRtp->ssrc_0=0;
pRtp->ssrc_1=0;
pRtp->ssrc_2=0;
pRtp->ssrc_3=0;
pRtp->version=2;
pRtp->x=0;
pRtp->pt = RTP_PT_H264+pkType;
if(pkType == 0)
pRtp->set_seq(m_videoSeq++);
else
pRtp->set_seq(m_audioSeq++);
pRtp->set_ts(ts);
OnAvRtpPacket((LPBYTE)pRtp, pkLen+12);
#else
switch(pkType)
{
case VIDEO:
RtpToNal(ts, lpStart, pkLen, NAL_FRAGMENT_POS_IND(startendInd));
break;
case AUDIO:
RtpToAacFrame(ts, lpStart, pkLen);
break;
case DATA:
break;
}
#endif
lpStart += pkLen;
return 0;
}
lpStart++;
return -1;
}
return 0;
}
void CDemuxer::OnVideoUnit(DWORD ts, LPBYTE lpIn, WORD wUnitLen)
{
LPBYTE lpEnd = lpIn + wUnitLen;
while(lpIn + 4 < lpEnd)//4 is the minumum length of Mode2 Fragment
{
OnAVMode2Fragment(ts, lpIn, lpEnd, VIDEO);
}
return;
}
void CDemuxer::OnAudioUnit(DWORD ts, LPBYTE lpIn, WORD wUnitLen)
{
LPBYTE lpEnd = lpIn + wUnitLen;
while(lpIn + 4 < lpEnd)//4 is the minumum length of Mode2 Fragment
{
OnAVMode2Fragment(ts, lpIn, lpEnd, AUDIO);
}
return;
}
bool CDemuxer::OnMode1DataUnit(BYTE nUnitType, LPBYTE lpIn, WORD wUnitLen)
{
printf("Data unit type: %d\n", nUnitType);
switch(nUnitType)
{
case 0:OnESGData(lpIn, wUnitLen-4/*there is a CRC32*/);break;//Esg Content
case 1:ParseProgramGuideInfo(lpIn, wUnitLen-4/*there is a CRC32*/);break;// Program Guide
case 128: // Jan 22, 2008
case 130:
case 132:
if ((tSubFrame[m_subFrameId].nCyptInd == 2/*Encypted*/) && (tSubFrame[m_subFrameId].ECMInd == 1/*There is ECM*/))
{
/*
nCyptInd: 2 bits
00 No Encypted
10 Encypted
ECMInd: 1 bit, true if there is ECM in this subframe
*/
printf ("On ECM_Data_Type=%d\n", nUnitType);
OnEcmPacket (lpIn, wUnitLen-4, nUnitType);
}
break;
case 129:
case 131:
case 133:
if (tSubFrame[m_subFrameId].nCyptInd == 2 && tSubFrame[m_subFrameId].ECMInd == 1)
{
printf ("On EMM_Data_Type=%d\n", nUnitType);
OnEmmPacket (lpIn, wUnitLen-4, nUnitType);
}
break;
case 160:ParseXpe(lpIn, wUnitLen);break;//XPE
case 161://XPE-FEC
printf("XPE/FEC\n");
break;
case 162:
case 163:
case 164:
case 165:
case 166:
case 167:
case 168:
case 169://reserved for data service
break;
case 255:
break;
}
return true;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -