📄 umc_mpeg2ts_parser.cpp
字号:
{
Ipp16u program_number = GET_16U(&tsHeader[iPos + 0]);
Ipp16u program_PID = GET_16U(&tsHeader[iPos + 2]) & 0x1fff;
if (0 == program_number)
continue;
if (!pat.uiSecLen)
{ // fill program params
pat.pProgs[i].uiProgInd = (Ipp16s)i;
pat.pProgs[i].uiProgNum = program_number;
pat.pProgs[i].uiProgPid = program_PID;
}
else if (m_bDetectPSIChanges)
{ // check changes in programs's numbers/PIDs
if (pat.pProgs[i].uiProgNum != program_number || pat.pProgs[i].uiProgPid != program_PID)
{
m_bPatWasChanged = true;
return UMC_WRN_INVALID_STREAM;
}
}
i++;
}
if (!pat.uiSecLen)
{ // fill PAT fields only once
pat.uiSecLen = (Ipp16u)section_length;
pat.uiTsId = transport_stream_id;
pat.uiVer = version_number;
pat.uiProgs = uiPrograms;
}
return UMC_OK;
}
Status Mpeg2TsParser::ParseTsPmt(Mpeg2TsPmt &pmt, Ipp32s iPos, bool bDetectChanges)
{
if (pmt.uiSecLen > 0 && !bDetectChanges)
return UMC_OK;
// read rest of packet
Ipp8u tsHeader[TTS_PACKET_SIZE];
CACHE_N_BYTES(&tsHeader[iPos], TTS_PACKET_SIZE - iPos, iPos);
Ipp32u pointer_field = tsHeader[iPos];
iPos += 1 + pointer_field;
if (iPos + 3 >= m_iPacketSize)
return UMC_ERR_INVALID_STREAM;
Ipp32u table_id = tsHeader[iPos++];
if (2 != table_id)
return UMC_ERR_INVALID_STREAM;
Ipp32s section_length = GET_16U(&tsHeader[iPos]) & 0xfff;
Ipp32s section_end = (Ipp16u)(iPos + 2 + section_length);
if (section_end > m_iPacketSize)
return UMC_ERR_INVALID_STREAM;
Ipp8u version_number = (tsHeader[iPos + 4] >> 1) & 0x1f;
Ipp32u section_number = tsHeader[iPos + 5];
Ipp32u last_section_number = tsHeader[iPos + 6];
if (0 != section_number || 0 != last_section_number)
return UMC_ERR_INVALID_STREAM; // multi-section tables are not supported
Ipp16u PCR_PID = GET_16U(&tsHeader[iPos + 7]) & 0x1fff;
Ipp32s program_info_length = GET_16U(&tsHeader[iPos + 9]) & 0x0fff;
if (iPos + 11 + program_info_length + 4 > section_end)
return UMC_ERR_INVALID_STREAM;
iPos += 11; // points program info
Ipp8u *pProgInfo = &tsHeader[iPos];
iPos += program_info_length;
//first count ESs
Ipp32u uiESs = 0;
Ipp32s iTmpPos = iPos;
Ipp32s iBytesLeft = section_length - 13 - program_info_length;
for (uiESs = 0; iTmpPos + 5 < section_end; uiESs++)
{
Ipp32u ES_info_length = GET_16U(&tsHeader[iTmpPos + 3]) & 0x0fff;
if (ES_info_length >= 1023) return UMC_ERR_INVALID_STREAM;
iTmpPos += 5 + ES_info_length;
iBytesLeft -= 5 + ES_info_length;
}
if (!pmt.uiSecLen && uiESs > 0)
{ // allocate Mpeg2TsPmts only ones
pmt.pESs = new Mpeg2Es[uiESs];
if (!pmt.pESs)
{
pmt.Release();
return UMC_ERR_ALLOC;
}
pmt.uiProgInfoLen = (Ipp16u)program_info_length;
if (program_info_length > 0)
pmt.SetInfo(pProgInfo, (Ipp16u)program_info_length);
}
else if (bDetectChanges)
{ // check some PMT fields for changes
if (pmt.uiSecLen != section_length || pmt.uiVer != version_number ||
pmt.uiProgInfoLen != program_info_length || pmt.uiESs != uiESs)
{
m_bPmtWasChanged = true;
return UMC_WRN_INVALID_STREAM;
}
}
// parse ESs PIDs/types checking changes
Ipp32u i;
Ipp32s ES_info_length = 0;
iBytesLeft = section_length - 13 - program_info_length;
for (i = 0; i < uiESs; i++, iPos += 5 + ES_info_length)
{
Ipp8u stream_type = tsHeader[iPos];
Ipp16u elementary_PID = GET_16U(&tsHeader[iPos + 1]) & 0x1fff;
ES_info_length = GET_16U(&tsHeader[iPos + 3]) & 0x0fff;
if (!pmt.uiSecLen)
{ // first PMT
pmt.pESs[i].uiType = stream_type;
pmt.pESs[i].uiPid = elementary_PID;
pmt.pESs[i].uiEsInfoLen = ES_info_length;
if (ES_info_length > 0)
pmt.pESs[i].SetInfo(&tsHeader[iPos + 5], (Ipp16u)ES_info_length);
pmt.uiESs++;
}
else if (bDetectChanges)
{ // check ES description
if (pmt.pESs[i].uiPid != elementary_PID || pmt.pESs[i].uiType != stream_type ||
pmt.pESs[i].uiEsInfoLen != (Ipp16u)ES_info_length)
{
m_bPmtWasChanged = true;
return UMC_WRN_INVALID_STREAM;
}
}
}
if (!pmt.uiSecLen)
{ // firsr PMT, fill fields
pmt.uiPcrPid = PCR_PID;
pmt.uiSecLen = (Ipp16u)section_length;
pmt.uiVer = version_number;
}
iPos += 4;
return UMC_OK;
}
Status Mpeg2TsParser::ReSync(void)
{
if (m_iOrig < 0)
{
for (m_iOrig = 0; m_iOrig < m_iPacketSize; m_iOrig++)
{
Status umcRes;
Ipp8u byte1, byte2, byte3;
umcRes = m_pDataReader->Check8u(&byte1, m_iOrig + 1 * m_iPacketSize - TS_PACKET_SIZE);
umcRes = m_pDataReader->Check8u(&byte2, m_iOrig + 2 * m_iPacketSize - TS_PACKET_SIZE);
umcRes = m_pDataReader->Check8u(&byte3, m_iOrig + 3 * m_iPacketSize - TS_PACKET_SIZE);
if (UMC_OK != umcRes)
return UMC_ERR_FAILED;
if (ID_TS_SYNC == byte1 && ID_TS_SYNC == byte2 && ID_TS_SYNC == byte3)
break;
}
if (m_iOrig >= m_iPacketSize)
{
m_iOrig = -1;
return UMC_ERR_FAILED;
}
}
Ipp64u uiCurPos = m_pDataReader->GetPosition();
Ipp64u uiPos = IPP_MAX(uiCurPos, m_iOrig);
uiPos = ((uiPos - m_iOrig + m_iPacketSize - 1) / m_iPacketSize) * m_iPacketSize + m_iOrig;
return uiPos > uiCurPos ? m_pDataReader->MovePosition(uiPos - uiCurPos) : UMC_OK;
}
// convert stream type from mpeg2ts pmt into internal TrackType
TrackType PmtStreamTypeToTrackType(Ipp8u uiStreamType)
{
switch (uiStreamType)
{
case 0x01: return TRACK_MPEG1V;
case 0x02: return TRACK_MPEG2V;
case 0x03: return TRACK_MPEGA;
case 0x04: return TRACK_MPEGA;
case 0x0F: return TRACK_AAC;
case 0x10: return TRACK_MPEG4V;
case 0x11: return TRACK_AAC;
case 0x1A: return TRACK_H264;
case 0x1B: return TRACK_H264;
case 0x81: return TRACK_AC3;
case 0x83: return TRACK_LPCM;
default: return TRACK_UNKNOWN;
}
}
Status Mpeg2TsParser::GetSystemTime(CheckPoint &rCheckPoint, Ipp64u upToPos)
{
Status umcRes = UMC_OK;
Packet packet;
// if pid is unspecified find out it from PAT/PMT
for (; m_iSysTimePid < 0;)
{
// find PAT table
Mpeg2TsPat pat;
packet.iPid = ID_TS_PAT;
for (umcRes = UMC_OK; !pat.uiProgs && UMC_OK == umcRes; umcRes = SKIP_TS_PACKET())
{
Ipp32s iPos = 0;
packet.uiAbsPos = upToPos;
umcRes = DispatchPacketWithPid(packet, iPos, false);
if (UMC_ERR_INVALID_STREAM == umcRes)
continue;
if (UMC_OK == umcRes)
umcRes = ParseTsPat(pat, iPos, false);
}
if (UMC_OK != umcRes)
return umcRes;
// find any PMT table with valid PCR_PID
Ipp32s prog = 0;
Ipp32u uiProgsChecked = 0;
for (; packet.uiAbsPos < upToPos && UMC_OK == umcRes; umcRes = SKIP_TS_PACKET())
{
Ipp32s iPos = 0;
umcRes = DispatchPacket(packet, iPos, false);
if (UMC_OK == umcRes && (prog = pat.GetProgIdx(packet.iPid)) >= 0)
{
if (!pat.pProgs[prog].uiSecLen)
uiProgsChecked++;
umcRes = ParseTsPmt(pat.pProgs[prog], iPos, false);
if (UMC_OK != umcRes)
uiProgsChecked--;
else if (pat.pProgs[prog].uiPcrPid != ID_TS_NULL || uiProgsChecked >= pat.uiProgs)
break; // exit if 'good' pcr_pid is found or if all programs are checked
}
}
if (packet.uiAbsPos >= upToPos)
return UMC_ERR_FAILED;
else if (UMC_OK != umcRes)
return umcRes;
if (ID_TS_NULL == pat.pProgs[prog].uiPcrPid)
{ // PCR is absent in the stream, try to use PTS/DTS of one of tracks
m_bPcrPresent = false;
Ipp32s iVideoPid = -1;
for (prog = 0; prog < (Ipp32s)pat.uiProgs && m_iSysTimePid < 0; prog++)
{
Ipp32u es;
for (es = 0; es < pat.pProgs[prog].uiESs && m_iSysTimePid < 0; es++)
{
if (PmtStreamTypeToTrackType(pat.pProgs[prog].pESs[es].uiType) & TRACK_ANY_AUDIO)
m_iSysTimePid = (Ipp32s)pat.pProgs[prog].pESs[es].uiPid;
else if (PmtStreamTypeToTrackType(pat.pProgs[prog].pESs[es].uiType) & TRACK_ANY_VIDEO)
iVideoPid = iVideoPid < 0 ? (Ipp32s)pat.pProgs[prog].pESs[es].uiPid : iVideoPid;
}
}
if (m_iSysTimePid < 0)
m_iSysTimePid = iVideoPid;
if (m_iSysTimePid < 0) // critical situation, stream with nor audio neither video
return UMC_ERR_FAILED;
}
else
{ // PCR presents in the stream
m_bPcrPresent = true;
m_iSysTimePid = pat.pProgs[prog].uiPcrPid;
}
}
packet.iPid = m_iSysTimePid;
for (; UMC_OK == umcRes; umcRes = SKIP_TS_PACKET())
{
Ipp32s iPos = 0;
packet.uiAbsPos = upToPos;
packet.dPTS = packet.dDTS = -1.0;
umcRes = DispatchPacketWithPid(packet, iPos, m_bPcrPresent);
if (UMC_OK != umcRes)
return umcRes;
if (!m_bPcrPresent)
{ // if pcr isn't present in the stream, we have to get pes packet timestamps
if (!packet.GetFlag(FCSample::PES_START))
continue;
umcRes = ParsePesHeader(packet, iPos, true);
if (UMC_ERR_INVALID_STREAM == umcRes)
continue;
}
if (packet.dPTS < 0.0)
continue;
rCheckPoint.uiPos = packet.uiAbsPos;
rCheckPoint.dTime = packet.dDTS < 0.0 ? packet.dPTS : packet.dDTS;
umcRes = SKIP_TS_PACKET();
break;
}
return umcRes;
}
Status Mpeg2TsParser::MoveToNextHeader(void)
{
PARSER_CHECK_INIT;
if (END_OF_STREAM == m_ParserState)
return UMC_ERR_END_OF_STREAM;
else if (HEADER == m_ParserState)
return UMC_OK;
m_ParserState = HEADER;
Status umcRes = m_pDataReader->MovePosition(m_iPacketSize);
Reset();
return umcRes;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -