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

📄 umc_mpeg2ps_parser.cpp

📁 audio-video-codecs.rar语音编解码器
💻 CPP
字号:
/*//////////////////////////////////////////////////////////////////////////////
//
//                  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_mpeg2ps_parser.h"

using namespace UMC;

#define PARSER_CHECK_INIT CHECK_OBJ_INIT(m_pDataReader)
#define ON_ERR_RETURN_UMC_STATUS(res) {     \
    if (UMC_OK != res) {                    \
        if (UMC_ERR_END_OF_STREAM == res)   \
            m_ParserState = END_OF_STREAM;  \
        return res;                         \
    }                                       \
}

Status Mpeg2PsParser::Init(StreamParserParams &rInit)
{
    if (m_pDataReader)
        return UMC_ERR_FAILED;

    Status umcRes = Mpeg2PesParser::Init(rInit);
    m_SystemType = UNDEF_STREAM;
    m_Pmt.Release();
    return umcRes;
}

Status Mpeg2PsParser::Close(void)
{
    PARSER_CHECK_INIT;
    m_Pmt.Release();
    return Mpeg2PesParser::Close();
}

Status Mpeg2PsParser::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;

    Status umcRes = UMC_OK;
    if (HEADER == m_ParserState)
    {
        m_pPacket->SetFlag(FCSample::PES_START, 1);
        m_pPacket->uiSize = 0;
        for (; UMC_OK == umcRes;)
        {
            Ipp32s iPos = 0;
            Ipp8u packet[6];
            CACHE_N_BYTES(&packet[0], 6, 0);
            if (packet[0] != 0 || packet[1] != 0 || packet[2] != 1 || packet[3] < ID_PS_PACK)
            {
                umcRes = ReSync();
                ON_ERR_RETURN_UMC_STATUS(umcRes)
                CACHE_N_BYTES(&packet[0], 6, 0);
            }

            if(IS_PES_PACKET(packet[3]))
            { // pes packet found
                umcRes = ParsePesHeader(*m_pPacket, iPos, false);
            }
            else if (ID_PS_PACK == packet[3])
            { // pack found
                umcRes = ParsePsPack(iPos);
                m_pPacket->iBufOffset = iPos;
                m_pPacket->uiSize = 0;
            }
            else if (ID_PS_SYS == packet[3])
            { // skip padding bytes
                m_pPacket->iBufOffset = 6 + GET_16U(&packet[4]);
                m_pPacket->uiSize = 0;
            }
            else if (ID_PADDING == packet[3])
            { // skip padding bytes
                m_pPacket->iBufOffset = 6 + GET_16U(&packet[4]);
                m_pPacket->uiSize = 0;
            }
            else if (ID_PS_MAP == packet[3] && !m_uiTracks)
            { // we find PMT, parse it only once and only if we have allocated no tracks
                umcRes = ParsePsPmt(m_Pmt, iPos, false);
                if (UMC_OK == umcRes)
                    umcRes = ParsePmtInfo(m_Pmt);
                if (UMC_OK != umcRes)
                    m_Pmt.Release();
                m_pPacket->iBufOffset = iPos;
                m_pPacket->uiSize = 0;
            }
            else if (ID_PRIVATE_2 == packet[3])
            {
                m_pPacket->iPid = ID_PRIVATE_2;
                m_pPacket->iBufOffset = 6;
                m_pPacket->uiSize = GET_16U(&packet[4]);
                m_pPacket->dPTS = m_pPacket->dDTS = -1.0;
            }
            else
            {
                umcRes = m_pDataReader->MovePosition(1);
                continue;
            }

            if (UMC_ERR_INVALID_STREAM == umcRes)
            {
                umcRes = m_pDataReader->MovePosition(1);
                continue;
            }
            else
            {
                ON_ERR_RETURN_UMC_STATUS(umcRes);
            }

            Ipp32s iTrack = 0;
            if (m_pPacket->uiSize > 0)
            {
                bool isNew = false;
                m_pPacket->uiAbsPos = m_pDataReader->GetPosition();
                iTrack = GetTrackByPidOrCreateNew(m_pPacket->iPid, &isNew);
                if (iTrack < 0) // cannot allocate new track, skip packet
                {
                    m_pPacket->iBufOffset += m_pPacket->uiSize;
                    m_pPacket->uiSize = 0;
                }
            }

            // packet is OK, but it does not contain payload
            // go to next packet using pes_packet_length field
            if (!m_pPacket->uiSize)
            {
                umcRes = m_pDataReader->MovePosition(m_pPacket->iBufOffset);
                ON_ERR_RETURN_UMC_STATUS(umcRes);
                continue;
            }

            // Cut private_stream_1 headers
            if (TRACK_AC3 == m_pInfo[iTrack]->m_Type || TRACK_DTS == m_pInfo[iTrack]->m_Type)
            {
                m_pPacket->iBufOffset += IPP_MIN(m_pPacket->uiSize, 4);
                m_pPacket->uiSize -= IPP_MIN(m_pPacket->uiSize, 4);
            }
            else if (TRACK_LPCM == m_pInfo[iTrack]->m_Type && m_pPacket->uiSize >= 7)
            {
                m_pPacket->iBufOffset += IPP_MIN(m_pPacket->uiSize, 7);
                m_pPacket->uiSize -= IPP_MIN(m_pPacket->uiSize, 7);
            }

            break;
        }
    }

    m_ParserState = PAYLOAD;
    pTrack[0] = GetTrackByPid(m_pPacket->iPid);
    PacketToMediaData(*m_pPacket, *pData);
    return umcRes;
}

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

Status Mpeg2PsParser::ReSync(void)
{
    // need to any chunk
    // startcodes could be easily emulated
    // so we have to be sure that found chunk is followed by another valid chunk

    // for most of chunks 6 bytes is enough to identify it and to determine its size
    // but for pack we need 14 bytes to determine its size
    Ipp8u data[14];

    Ipp64u uiOffset;
    Ipp64u uiMaxOffset = 0x10000;
    for (uiOffset = 0; uiOffset < uiMaxOffset; uiOffset++)
    {
        CACHE_N_BYTES(&data[0], 14, uiOffset);
        if (0 != data[0] || 0 != data[1] || 1 != data[2] || data[3] < ID_PS_PACK)
            continue;

        Ipp64u uiNextChunk;
        if (ID_PS_PACK == data[3])
        {
            if (0x40 == (data[4] & 0xc0) && MPEG1_SYSTEM_STREAM != m_SystemType)
            {
                m_SystemType = MPEG2_PROGRAMM_STREAM;
                uiNextChunk = 14 + (data[13] & 7);
            }
            else if (0x20 == (data[4] & 0xf0) && MPEG2_PROGRAMM_STREAM != m_SystemType)
            {
                m_SystemType = MPEG1_PROGRAMM_STREAM;
                uiNextChunk = 12;
            }
            else // seems it was pack start code emulation
                continue;
        }
        else
        {
            uiNextChunk = GET_16U(&data[4]); // pes_packet_length
            if (0 == uiNextChunk)
                continue; // seems it was pes packet start code emulation
            uiNextChunk += 6;
        }

        // check following chunk
        CACHE_N_BYTES(&data[0], 4, uiOffset + uiNextChunk);
        if (0 == data[0] && 0 == data[1] && 1 == data[2] && data[3] >= ID_PS_PACK)
            break;
    }

    if (uiOffset < uiMaxOffset)
        m_pDataReader->MovePosition(uiOffset);
    return uiOffset < uiMaxOffset ? UMC_OK : UMC_ERR_END_OF_STREAM;
}

Ipp32s Mpeg2PsParser::GetTrackByPidOrCreateNew(Ipp32s iPid, bool *pIsNew)
{
    Ipp32s iTrack = StreamParser::GetTrackByPidOrCreateNew(iPid, pIsNew);
    if (iTrack >= 0 && pIsNew && pIsNew[0] && !m_Pmt.uiSecLen)
    { // new track and we have no PMT, use stream_id to determine track type
        if (IS_ID_OF(ID_VIDEO, m_pPacket->iPid))
            m_pInfo[iTrack]->m_Type = TRACK_MPEG2V;
        else if (IS_ID_OF(ID_AUDIO, m_pPacket->iPid))
            m_pInfo[iTrack]->m_Type = TRACK_MPEGA;
        else if (IS_ID_OF(SUB_ID_AC3, m_pPacket->iPid))
            m_pInfo[iTrack]->m_Type = TRACK_AC3;
        else if (IS_ID_OF(SUB_ID_DTS, m_pPacket->iPid))
            m_pInfo[iTrack]->m_Type = TRACK_DTS;
        else if (IS_ID_OF(SUB_ID_LPCM, m_pPacket->iPid))
            m_pInfo[iTrack]->m_Type = TRACK_LPCM;
        else if (IS_ID_OF(SUB_ID_SUBPIC, m_pPacket->iPid))
            m_pInfo[iTrack]->m_Type = TRACK_SUB_PIC;
        else if (ID_PRIVATE_2 == m_pPacket->iPid)
            m_pInfo[iTrack]->m_Type = TRACK_DVD_NAV;
        else
        { // oops, unsupported track type, rollback
            m_uiTracks--;
            iTrack = -1;
        }

        if (iTrack >= 0)
        { // allocate StreamInfo
            if (!m_pInfo[iTrack]->m_pStreamInfo)
                m_pInfo[iTrack]->Alloc();

            // for LPCM audio track we have to extract channel info from 7-byte header
            if (TRACK_LPCM == m_pInfo[iTrack]->m_Type && m_pInfo[iTrack]->m_pStreamInfo && m_pPacket->uiSize >= 7)
            {
                Ipp8u chan = 0;
                m_pDataReader->Check8u(&chan, m_pPacket->iBufOffset + 5);
                ((AudioStreamInfo *)m_pInfo[iTrack]->m_pStreamInfo)->channels =
                    AudioFrameConstructor::LPCMChannels[chan & 0x0F];
            }
        }
    }

    return iTrack;
}

Status Mpeg2PsParser::ParsePsPack(Ipp32s &iPos)
{
    Ipp32s iInnerPos = iPos;
    Ipp8u packet[14]; // this is enough for both mpeg2 and mpeg1 pack
    CACHE_N_BYTES(&packet[0], 14, iPos);
    if (packet[0] != 0 || packet[1] != 0 || packet[2] != 1 || packet[3] != ID_PS_PACK)
        return UMC_ERR_INVALID_STREAM;

    if (0x40 == (packet[4] & 0xc0))
    {
        if (UNDEF_STREAM == m_SystemType)
            m_SystemType = MPEG2_PROGRAMM_STREAM;
        else if (MPEG2_PROGRAMM_STREAM != m_SystemType)
            return UMC_ERR_INVALID_STREAM;
        iInnerPos += 14 + (packet[13] & 7);
    }
    else if (0x20 == (packet[4] & 0xf0))
    {
        if (UNDEF_STREAM == m_SystemType)
            m_SystemType = MPEG1_PROGRAMM_STREAM;
        else if (MPEG1_PROGRAMM_STREAM != m_SystemType)
            return UMC_ERR_INVALID_STREAM;
        iInnerPos += 12;
    }

    CACHE_N_BYTES(&packet[0], 6, iInnerPos);
    if (0 == packet[0] && 0 == packet[1] && 1 == packet[2] && ID_PS_SYS == packet[3])
        iInnerPos += 6 + GET_16U(&packet[4]);

    iPos += iInnerPos;
    return UMC_OK;
}

Status Mpeg2PsParser::ParsePsPmt(Mpeg2TsPmt &pmt, Ipp32s &iPos, bool bDetectChanges)
{
    if (pmt.uiSecLen > 0 && !bDetectChanges)
        return UMC_OK;

    Ipp32s iInnerPos = 0;
    Ipp8u packet[1024]; // this is maximum length of Program Stream map
    CACHE_N_BYTES(&packet[0], 6, iPos);
    if (packet[0] != 0 || packet[1] != 0 || packet[2] != 1 || packet[3] != ID_PS_MAP)
        return UMC_ERR_INVALID_STREAM;

    Ipp32s map_length = GET_16U(&packet[4]);
    if (map_length < 10 || map_length > 1018)
        return UMC_ERR_INVALID_STREAM;

    CACHE_N_BYTES(&packet[6], map_length, iPos + 6);
    Ipp8u version_number = packet[iInnerPos + 6] & 0x1f;
    Ipp32s prog_info_len = GET_16U(&packet[8]);
    Ipp8u *pProgInfo = &packet[10];
    if (prog_info_len + 10 > map_length)
        return UMC_ERR_INVALID_STREAM;

    iInnerPos += 10 + prog_info_len;
    Ipp32s es_map_len = GET_16U(&packet[iInnerPos]);
    if (iInnerPos + 2 + es_map_len > map_length + 6)
        return UMC_ERR_INVALID_STREAM;

    // first count elementary streams
    iInnerPos += 2;
    Ipp32s iEsMapStart = iInnerPos;
    Ipp32s iEsCount = 0;
    while (iInnerPos - iEsMapStart + 4 <= es_map_len)
    {
        iEsCount++;
        iInnerPos += 4 + GET_16U(&packet[iInnerPos + 2]);
    }

    // return to start and parse
    iInnerPos = iEsMapStart;
    if (!pmt.uiProgInfoLen)
    {
        pmt.pESs = new Mpeg2Es[iEsCount];
        if (!pmt.pESs)
        {
            pmt.Release();
            return UMC_ERR_ALLOC;
        }
        pmt.uiProgInfoLen = (Ipp16u)prog_info_len;
        if (prog_info_len > 0)
            pmt.SetInfo(pProgInfo, (Ipp16u)prog_info_len);
    }

    Ipp32s i;
    for (i = 0; i < iEsCount; i++)
    {
        pmt.pESs[i].uiType = packet[iInnerPos];
        pmt.pESs[i].uiPid = packet[iInnerPos + 1];
        pmt.pESs[i].uiEsInfoLen = GET_16U(&packet[iInnerPos + 2]);
        if (pmt.pESs[i].uiEsInfoLen > 0)
            pmt.pESs[i].SetInfo(&packet[iInnerPos + 4], (Ipp16u)pmt.pESs[i].uiEsInfoLen);
        iInnerPos += 4 + pmt.pESs[i].uiEsInfoLen;
    }

    if (!pmt.uiProgInfoLen)
    {
        pmt.uiESs = (Ipp32u)iEsCount;
        pmt.uiSecLen = (Ipp16u)map_length;
        pmt.uiVer = version_number;
    }

    iPos += iInnerPos + 4;
    return UMC_OK;
}

Status Mpeg2PsParser::GetSystemTime(CheckPoint &rCheckPoint, Ipp64u upToPos)
{
    PARSER_CHECK_INIT;
    Ipp8u packet[14];
    for (;; m_pDataReader->MovePosition(GET_16U(&packet[4])))
    {
        Ipp64u pos = m_pDataReader->GetPosition();
        if (pos >= upToPos)
            return UMC_ERR_SYNC;

        Status umcRes = ReSync();
        if (UMC_OK != umcRes)
            return umcRes;

        CACHE_N_BYTES(&packet[0], 14, 0);
        if (ID_PS_PACK != packet[3])
            continue;

        Ipp32u uiNextChunk;
        if (MPEG2_PROGRAMM_STREAM == m_SystemType)
        {
            rCheckPoint.dTime = GetMpeg2PsSysTime(&packet[4]);
            uiNextChunk = 14 + (packet[13] & 7);
        }
        else
        {
            rCheckPoint.dTime = GetMpeg1PsSysTime(&packet[4]);
            uiNextChunk = 12;
        }
        rCheckPoint.uiPos = pos;
        umcRes = m_pDataReader->MovePosition(uiNextChunk);
        if (UMC_OK != umcRes)
            return umcRes;
        break;
    }

    return UMC_OK;
}

⌨️ 快捷键说明

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