⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 umc_mpeg2ts_parser.cpp

📁 audio-video-codecs.rar语音编解码器
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/*//////////////////////////////////////////////////////////////////////////////
//
//                  INTEL CORPORATION PROPRIETARY INFORMATION
//     This software is supplied under the terms of a license agreement or
//     nondisclosure agreement with Intel Corporation and may not be copied
//     or disclosed except in accordance with the terms of that agreement.
//          Copyright(c) 2005-2007 Intel Corporation. All Rights Reserved.
//
*/

#include "umc_mpeg2ts_parser.h"

using namespace UMC;

#define PARSER_CHECK_INIT CHECK_OBJ_INIT(m_pDataReader)
#define SKIP_TS_PACKET() m_pDataReader->MovePosition((Ipp64u)m_iPacketSize)

Mpeg2TsParser::Mpeg2TsParser()
{
}

Status Mpeg2TsParser::Init(StreamParserParams &init)
{
    Status umcRes = Mpeg2PesParser::Init(init);
    if (UMC_OK != umcRes)
        return umcRes;

    m_iSysTimePid = -1;
    m_iOrig = -1;
    m_bPatWasChanged = false;
    m_bPmtWasChanged = false;
    m_bDetectPSIChanges = false;
    m_bPcrPresent = false;
    ippsZero_8u((Ipp8u *)m_uiFirstPesPos, MAX_TRACK * sizeof(Ipp64u));
    ippsZero_8u((Ipp8u *)m_uiLastPesPos, MAX_TRACK * sizeof(Ipp64u));
    ippsZero_8u((Ipp8u *)m_dLastPesPts, MAX_TRACK * sizeof(Ipp64f));
    ippsZero_8u((Ipp8u *)m_dLastPesDts, MAX_TRACK * sizeof(Ipp64f));

    if (DynamicCast<Mpeg2TsParserParams>(&init))
        m_bDetectPSIChanges = ((Mpeg2TsParserParams *)&init)->m_bDetectPSIChanges;

    // find start of first packet
    m_iPacketSize = (MPEG2_TRANSPORT_STREAM == init.m_SystemType) ? TS_PACKET_SIZE : TTS_PACKET_SIZE;
    m_Pat.Release();
    umcRes = ReSync();
    return umcRes;
}

Status Mpeg2TsParser::Close(void)
{
    PARSER_CHECK_INIT;
    m_Pat.Release();
    m_iOrig = -1;
    return Mpeg2PesParser::Close();
}

Status Mpeg2TsParser::SetPosition(Ipp64u pos)
{
    PARSER_CHECK_INIT;
    // reset TS variables
    m_pPacket->Reset();
    ippsZero_8u((Ipp8u *)m_uiLastPesPos, MAX_TRACK * sizeof(Ipp64u));
    ippsZero_8u((Ipp8u *)m_dLastPesPts, MAX_TRACK * sizeof(Ipp64f));
    ippsZero_8u((Ipp8u *)m_dLastPesDts, MAX_TRACK * sizeof(Ipp64f));
    m_bPatWasChanged = false;
    m_bPmtWasChanged = false;

    Status umcRes = Mpeg2PesParser::SetPosition(pos);
    if (UMC_OK != umcRes)
        return umcRes;
    return ReSync();
}

Status Mpeg2TsParser::CheckNextData(MediaData *pData, Ipp32u* pTrack)
{
    PARSER_CHECK_INIT;
    if (END_OF_STREAM == m_ParserState)
        return UMC_ERR_END_OF_STREAM;
    if (!pData || !pTrack)
         return UMC_ERR_NULL_PTR;

    if (m_bPatWasChanged || m_bPmtWasChanged)
    {
        // PSI change was detected at previous CheckNextData
        // Upper component is notified so we can destroy old track infos
        Ipp32u i;
        for (i = 0; i < m_uiTracks; i++)
        {
            m_pInfo[i]->ReleaseAll();
            delete m_pInfo[i];
            m_pInfo[i] = NULL;
        }

        if (m_bPatWasChanged)
            m_Pat.Release(); // release pat and all pmt
        if (m_bPmtWasChanged)
            for (i = 0; i < m_Pat.uiProgs; i++)
                m_Pat.pProgs[i].Release(); // release only all pmt

        m_uiTracks = 0;
        m_bPatWasChanged = m_bPmtWasChanged = false;
    }

    Status umcRes = UMC_OK;
    if (HEADER == m_ParserState)
    {
        m_pPacket->uiSize = 0;
        for (umcRes = UMC_OK; UMC_OK == umcRes; umcRes = SKIP_TS_PACKET())
        {
            Ipp32s iPos = 0;
            umcRes = DispatchPacket(*m_pPacket, iPos, false);
            if (UMC_ERR_INVALID_STREAM == umcRes)
                continue;
            else if (UMC_OK != umcRes)
                return umcRes;

            Ipp32s iProg;
            Ipp32s iTrack;
            if (ID_TS_PAT == m_pPacket->iPid)
            { // PAT found, parse it
                umcRes = ParseTsPat(m_Pat, iPos, m_bDetectPSIChanges);
            }
            else if ((iProg = m_Pat.GetProgIdx(m_pPacket->iPid)) >= 0)
            { // PMT found, parse it
                bool bFirstPmt = !m_Pat.pProgs[iProg].uiSecLen;
                umcRes = ParseTsPmt(m_Pat.pProgs[iProg], iPos, m_bDetectPSIChanges);
                if (UMC_OK == umcRes && bFirstPmt)
                    umcRes = ParsePmtInfo(m_Pat.pProgs[iProg]);
            }
            else if ((iTrack = GetTrackByPid(m_pPacket->iPid)) >= 0)
            { // track PID found
                if (m_pPacket->GetFlag(FCSample::PES_START))
                { // data follows PES header
                    if (0 == m_uiFirstPesPos[iTrack]) // save first PES header position
                        m_uiFirstPesPos[iTrack] = m_pPacket->uiAbsPos;
                    if (m_pPacket->uiAbsPos < m_uiFirstPesPos[iTrack])
                        continue; // this works after repositions to prevent 'early' samples
                    umcRes = ParsePesHeader(*m_pPacket, iPos, true);
                    m_pPacket->uiSize = (Ipp32u)(m_iPacketSize - iPos);
                }
                else if (m_uiLastPesPos[iTrack] > 0)
                { // this is continuation of PES packet
                    m_pPacket->iBufOffset = iPos;
                    m_pPacket->uiSize = (Ipp32u)(m_iPacketSize - iPos);
                }
                else
                { // have to wait for PES header
                    continue;
                }
            }
            else
            { // unregistered PID found
                continue;
            }

            if (UMC_ERR_INVALID_STREAM == umcRes)
                continue;
            else if (UMC_OK != umcRes)
                return umcRes;

            if (!m_pPacket->uiSize)
                continue;

            iTrack = GetTrackByPid(m_pPacket->iPid);
            if (iTrack < 0)
                continue;

            if (!m_pPacket->GetFlag(FCSample::PES_START))
            {
                m_pPacket->dPTS = m_dLastPesPts[iTrack];
                m_pPacket->dDTS = m_dLastPesDts[iTrack];
                m_pPacket->uiAbsPos = m_uiLastPesPos[iTrack];
            }
            else
            {
                m_dLastPesPts[iTrack] = m_pPacket->dPTS;
                m_dLastPesDts[iTrack] = m_pPacket->dDTS;
                m_uiLastPesPos[iTrack] = m_pPacket->uiAbsPos;
            }

            m_ParserState = PAYLOAD;
            break;
        }
    }

    if (UMC_ERR_END_OF_STREAM == umcRes)
        m_ParserState = END_OF_STREAM;

    *pTrack = GetTrackByPid(m_pPacket->iPid);
    PacketToMediaData(*m_pPacket, *pData);
    return umcRes;
}

Status Mpeg2TsParser::DispatchPacket(Packet &packet, Ipp32s &iPos, bool bExtractPcr)
{
    if (TTS_PACKET_SIZE == m_iPacketSize)
        iPos += 4;

    packet.uiAbsPos = m_pDataReader->GetPosition();
    Ipp8u tsHeader[12]; // that's enough for transport packet headers
    CACHE_N_BYTES(&tsHeader[0], 6, iPos);
    Ipp32s sync_byte = tsHeader[0];
    packet.SetFlag(FCSample::PES_START, (tsHeader[1] >> 6) & 0x01);
    packet.iPid = ((tsHeader[1] & 0x1f) << 8) + tsHeader[2];
    Ipp32s scrambling_ctrl = (tsHeader[3] >> 6) & 0x03;
    Ipp32s adapt_field_ctrl = (tsHeader[3] >> 4) & 0x03;
    Ipp32s adapt_field_len = tsHeader[4];

    // check forbidden values
    if (ID_TS_SYNC != sync_byte || scrambling_ctrl > 1 || ID_TS_NULL == packet.iPid ||
        ID_TS_CAT == packet.iPid || ID_TS_DT == packet.iPid || 0 == adapt_field_ctrl)
        return UMC_ERR_INVALID_STREAM;

    iPos += 4;
    if (bExtractPcr)
        packet.dPTS = -1.0;

    // skip adaptation field if present
    if (adapt_field_ctrl & 2)
    {
        if (adapt_field_len > 0)
        {
            if ((3 == adapt_field_ctrl && adapt_field_len > 182) || (2 == adapt_field_ctrl && adapt_field_len > 183))
                return UMC_ERR_INVALID_STREAM;
            if (bExtractPcr)
            {
                CACHE_N_BYTES(&tsHeader[6], 6, iPos + 2);
                if (tsHeader[5] & 0x10) // PCR_flag
                    packet.dPTS = GetMpeg2TsSysTime(&tsHeader[6]);
            }
        }
        iPos += 1 + adapt_field_len;
    }

    packet.uiAbsPos = m_pDataReader->GetPosition();
    return UMC_OK;
}

Status Mpeg2TsParser::DispatchPacketWithPid(Packet &packet, Ipp32s &iPos, bool bExtractPcr)
{
    Status umcRes = UMC_OK;
    Ipp64u upToPos = packet.uiAbsPos;
    Ipp32s iPid = packet.iPid;
    packet.uiAbsPos = 0;

    for (; m_pDataReader->GetPosition() < upToPos && UMC_OK == umcRes; umcRes = SKIP_TS_PACKET())
    {
        iPos = 0;
        umcRes = DispatchPacket(packet, iPos, bExtractPcr);
        if (UMC_ERR_INVALID_STREAM == umcRes)
            continue;
        else if (UMC_OK != umcRes)
            return umcRes;
        if (packet.iPid == iPid)
            break;
    }

    return m_pDataReader->GetPosition() < upToPos ? umcRes : UMC_ERR_FAILED;
}

Status Mpeg2TsParser::ParseTsPat(Mpeg2TsPat &pat, Ipp32s iPos, bool bDetectChanges)
{
    if (pat.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 (0 != table_id)
        return UMC_ERR_INVALID_STREAM;

    Ipp32s section_length = GET_16U(&tsHeader[iPos]) & 0x0fff;
    if (section_length > m_iPacketSize - iPos - 2 || section_length < 9)
        return UMC_ERR_INVALID_STREAM;

    Ipp16u transport_stream_id = GET_16U(&tsHeader[iPos + 2]);
    Ipp8u version_number = (tsHeader[iPos + 4] >> 1) & 0x1f;
    Ipp32s 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;

    iPos += 7;
    Ipp32s i;
    Ipp32u uiPrograms = 0;
    // first count programs
    for (i = 0; i < (section_length - 9) / 4; i++)
        if (GET_16U(&tsHeader[iPos + 4 * i]) > 0)
            uiPrograms++;

    if (!pat.uiSecLen && uiPrograms > 0)
    { // allocate Mpeg2TsPmts only ones
        pat.pProgs = new Mpeg2TsPmt[uiPrograms];
        if (!pat.pProgs)
            return UMC_ERR_ALLOC;
    }
    else if (bDetectChanges)
    { // check some PAT fields for changes
        if (pat.uiSecLen != section_length || pat.uiTsId != transport_stream_id ||
            pat.uiVer != version_number || pat.uiProgs != uiPrograms)
        {
            m_bPatWasChanged = true;
            return UMC_WRN_INVALID_STREAM;
        }
    }

    // parse program PID's checking chasnges
    for (i = 0; i < (Ipp32s)uiPrograms; iPos += 4)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -