mpapktparse.cpp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:15k
- /* ***** BEGIN LICENSE BLOCK *****
- * Version: RCSL 1.0/RPSL 1.0
- *
- * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved.
- *
- * The contents of this file, and the files included with this file, are
- * subject to the current version of the RealNetworks Public Source License
- * Version 1.0 (the "RPSL") available at
- * http://www.helixcommunity.org/content/rpsl unless you have licensed
- * the file under the RealNetworks Community Source License Version 1.0
- * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl,
- * in which case the RCSL will apply. You may also obtain the license terms
- * directly from RealNetworks. You may not use this file except in
- * compliance with the RPSL or, if you have a valid RCSL with RealNetworks
- * applicable to this file, the RCSL. Please see the applicable RPSL or
- * RCSL for the rights, obligations and limitations governing use of the
- * contents of the file.
- *
- * This file is part of the Helix DNA Technology. RealNetworks is the
- * developer of the Original Code and owns the copyrights in the portions
- * it created.
- *
- * This file, and the files included with this file, is distributed and made
- * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- *
- * Technology Compatibility Kit Test Suite(s) Location:
- * http://www.helixcommunity.org/content/tck
- *
- * Contributor(s):
- *
- * ***** END LICENSE BLOCK ***** */
- #include "hxtypes.h"
- #include "hlxclib/stdio.h"
- #include "hxcom.h" // IUnknown
- #include "hxcomm.h" // IHXCommonClassFactory
- #include "ihxpckts.h" // IHXBuffer, IHXPacket, IHXValues
- #include "hxplugn.h" // IHXPlugin
- #include "hxrendr.h" // IHXRenderer
- #include "hxengin.h" // IHXInterruptSafe
- #include "hxcore.h" // IHXStream
- #include "hxausvc.h" // Audio Services
- #include "hxmon.h" // IHXStatistics
- #include "hxupgrd.h" // IHXUpgradeCollection
- #include "hxslist.h" // CHXSimpleList
- #include "carray.h" // CHXPtrArray
- #include "tconverter.h"
- #include "hxstrutl.h"
- #include "mpadecobj.h" // MPEG Audio Decoder (selects fixed-pt or floating-pt based on HELIX_CONFIG_FIXEDPOINT)
- #include "mp3format.h" // MP3 formatter
- #ifdef DEMUXER
- #include "xmddemuxer.h" // Demuxer
- #include "xmdtypes.h"
- #endif
- #include "mp3rend.h" // CRnMp3Ren
- #include "pktparse.h" // CPacketParser
- #include "mpapktparse.h" // CMpaPacketParser
- CMpaPacketParser::CMpaPacketParser() :
- CPacketParser(),
- m_pPacket(NULL),
- m_bPacketLoss(FALSE)
- {
- m_bReformatted = FALSE;
- }
- CMpaPacketParser::~CMpaPacketParser()
- {
- HX_RELEASE(m_pPacket);
- }
- /********************************************************************
- * CMpaPacketParser::AddPacket: Adds a packet. Assumes that all frames
- * in the packet will be retrieved before AddPacket is called again.
- * Will not queue packets.
- */
- HX_RESULT
- CMpaPacketParser::AddPacket(IHXPacket* pPacket, INT32 streamOffsetTime)
- {
- #ifdef SIM_PKT_LOSS
- static int nPackets = 0;
- if (++nPackets % 10 == 0)
- {
- m_bPacketLoss = TRUE;
- return HXR_FAIL;
- }
- #endif //SIM_PKT_LOSS
- HX_ASSERT(pPacket);
- if(pPacket->IsLost())
- {
- m_bPacketLoss = TRUE;
- return HXR_FAIL;
- }
- else
- {
- // Save this packet
- HX_RELEASE(m_pPacket);
- m_pPacket = pPacket;
- m_pPacket->AddRef();
- m_lStreamOffsetTime = streamOffsetTime;
- }
- return HXR_OK;
- }
- HX_RESULT
- CMpaPacketParser::RenderAll()
- {
- if(!m_pRenderer || !m_pFmt || !m_pPacket)
- {
- return HXR_FAIL;
- }
- UINT32 ulSize;
- UCHAR* pBuffer;
- IHXBuffer* pBufObj = m_pPacket->GetBuffer();
- if(!pBufObj)
- {
- // Null buffer?
- return HXR_FAIL;
- }
- pBufObj->Get(pBuffer, ulSize);
- if(!pBuffer || !ulSize)
- {
- // empty packet!
- HX_RELEASE(pBufObj);
- return HXR_FAIL;
- }
- if(!ParseHeaders(pBuffer, ulSize))
- {
- HX_RELEASE(pBufObj);
- return HXR_FAIL;
- }
- if (m_bPacketLoss)
- {
- HandlePacketLoss();
- m_bPacketLoss = FALSE;
- }
- if(m_dNextPts == 0.0)
- {
- m_dNextPts = m_pPacket->GetTime();
- if(m_lStreamOffsetTime > m_dNextPts)
- {
- m_dNextPts = 0;
- }
- else
- {
- m_dNextPts -= m_lStreamOffsetTime;
- }
- }
- HX_RESULT retVal = HXR_OK;
- // Packets may exceed the decode buffer size, so copy the
- // packet iteratively if necessary.
- do
- {
- // Copy packet data to decode buffer to prevent a potential
- // access vioaltion in the mp3 decoder and to deal with rtp
- // packet fragmentation.
- UINT32 ulCopy = min(ulSize, DEC_BUFFER_SIZE - m_ulDecBufBytes);
- memcpy(m_pDecBuffer + m_ulDecBufBytes, pBuffer, ulCopy); /* Flawfinder: ignore */
- m_ulDecBufBytes += ulCopy;
-
- pBuffer += ulCopy;
- ulSize -= ulCopy;
- // Use these temp variables to pass to the decoder
- UCHAR *pDec = m_pDecBuffer;
- UINT32 ulDec = m_ulDecBufBytes;
- int nFrameSize = 0;
- INT32 lScan = 0;
- // Do we need to init our decoder
- if (!m_pDecoder)
- {
- lScan = m_pFmt->ScanForSyncWord(pDec, ulDec, nFrameSize);
- if (lScan >= 0)
- {
- pDec += lScan;
- ulDec -= lScan;
- m_ulDecBufBytes -= lScan;
- }
- else
- {
- // If our buffer is full and we could not find a frame,
- // we have bad data. So skip 3/4 of buffered data.
- if (DEC_BUFFER_SIZE == m_ulDecBufBytes)
- {
- pDec += DEC_BUFFER_SIZE * 3 / 4;
- m_ulDecBufBytes -= DEC_BUFFER_SIZE * 3 / 4;
- }
-
- ulDec = 0;
- }
- if (ulDec && !InitDecoder(pDec, ulDec, FALSE))
- {
- HX_RELEASE(pBufObj);
- return HXR_FAIL;
- }
- }
- // Decode all frames in this buffer
- while (ulDec)
- {
- // Make sure we don't have a packet frag
- if (!m_pFmt->CheckValidFrame(pDec, ulDec))
- {
- // Scan through any bad data in the file
- nFrameSize = 0;
- lScan = m_pFmt->ScanForSyncWord(pDec, ulDec, nFrameSize);
- if (lScan >= 0)
- {
- pDec += lScan;
- ulDec -= lScan;
- m_ulDecBufBytes -= lScan;
- }
- else
- {
- // If our buffer is full and we could not find a frame,
- // we have bad data. So skip 3/4 of buffered data.
- if (DEC_BUFFER_SIZE == m_ulDecBufBytes)
- {
- pDec += DEC_BUFFER_SIZE * 3 / 4;
- m_ulDecBufBytes -= DEC_BUFFER_SIZE * 3 / 4;
- }
- break;
- }
- }
- // Decode and render this frame
- ulDec = DecodeAndRender(pDec, ulDec, m_dNextPts, m_bPacketLoss);
- if (ulDec)
- {
- if(ulDec > m_ulDecBufBytes)
- ulDec = m_ulDecBufBytes;
- pDec += ulDec;
- m_ulDecBufBytes -= ulDec;
- ulDec = m_ulDecBufBytes;
- m_dNextPts += m_dFrameTime;
- }
- else
- {
- retVal = HXR_OUTOFMEMORY;
- break;
- }
- }
- // Copy the leftovers to the start of the buffer
- if (m_ulDecBufBytes)
- memmove(m_pDecBuffer, pDec, m_ulDecBufBytes);
- } while (ulSize);
- HX_RELEASE(pBufObj);
- return retVal;
- }
- void
- CMpaPacketParser::RestartStream(void)
- {
- m_bPacketLoss = FALSE;
- m_ulDecBufBytes = 0;
- HX_RELEASE(m_pLastPCMBuffer);
- m_dLastPCMTime = 0.0;
- }
- C2250PacketParser::~C2250PacketParser()
- {
- HX_DELETE(m_pTsConvert);
- }
- void C2250PacketParser::PostSeek(UINT32 time)
- {
- CMpaPacketParser::PostSeek(time);
- HX_DELETE(m_pTsConvert);
- }
- BOOL
- C2250PacketParser::ParseHeaders(UCHAR*& pBuffer, UINT32& ulSize)
- {
- // Skip rtp payload header
- // Check for bad or unknown packets
- if(pBuffer[0] || pBuffer[1])
- return FALSE;
- // Only extract the rtp pts for a packet containing the start of a frame
- if (!pBuffer[2] && !pBuffer[3] && !m_pPacket->IsLost())
- {
- IHXRTPPacket *pRtpPacket = NULL;
- m_pPacket->QueryInterface(IID_IHXRTPPacket, (void**)&pRtpPacket);
- if (pRtpPacket)
- {
- if (!m_pTsConvert)
- {
- m_pTsConvert = new CHXTimestampConverter(CHXTimestampConverter::FACTORS,
- 1,
- 90);
- if (m_pTsConvert)
- {
- m_pTsConvert->setHXAnchor(m_pPacket->GetTime());
- }
- }
- if (m_pTsConvert)
- m_dNextPts = m_pTsConvert->rtp2hxa(pRtpPacket->GetRTPTime());
- else
- m_dNextPts = pRtpPacket->GetRTPTime()/90.0;
- pRtpPacket->Release();
-
- if(m_lStreamOffsetTime > m_dNextPts)
- m_dNextPts = 0;
- else
- m_dNextPts -= m_lStreamOffsetTime;
- }
- }
- // If we lost packets, resync with the start of a frame
- else if (m_bPacketLoss)
- {
- return FALSE;
- }
- pBuffer += 4;
- ulSize -= 4;
- return TRUE;
- }
- void C2250PacketParser::HandlePacketLoss()
- {
- // Render the last PCM buffer for the number of frames we lost
- if (m_pLastPCMBuffer)
- {
- double dTime = m_dLastPCMTime + m_dFrameTime;
- int nLostFrames = (int)((m_dNextPts - dTime) / m_dFrameTime + .5);
- for (int i=0; i<nLostFrames; i++)
- {
- m_pRenderer->Render(m_pLastPCMBuffer, dTime);
- dTime += m_dFrameTime;
- }
- }
- // Remove any partial audio frames in the decode buffer
- m_ulDecBufBytes = 0;
- }
- #ifdef DEMUXER
- CSysPacketParser::CSysPacketParser(BOOL bMPEG2, IHXRegistry* pRegistry) :
- CMpaPacketParser(),
- m_pRegistry(pRegistry),
- m_llLastPts(0),
- m_llFirstPts(0),
- m_ulPlayTime(0),
- m_bCheckVcdBug(TRUE),
- m_bVcdBug(FALSE)
- {
- m_pDemuxer = new CDemuxer(bMPEG2);
- }
- BOOL
- CSysPacketParser::Demux(UCHAR*& pBuffer, UINT32& ulSize, UINT32 ulFragSize)
- {
- if(!m_pDemuxer)
- {
- return TRUE;
- }
- // Get the es data
- Packet packet;
- m_pDemuxer->Demux_ul(pBuffer, ulSize, &packet);
- pBuffer = packet.pData;
- ulSize = packet.lBytes;
- // Sync clock with the first stream time stamp
- if (m_dNextPts == 0.0)
- {
- if (!packet.cHasPts)
- {
- return FALSE;
- }
- m_llFirstPts = packet.llPts;
- m_llLastPts = packet.llPts;
- INT32 lTime = m_pPacket->GetTime();
- // Set the first timestamp in the registry (don't include the stream
- // offset in this value since the video renderer needs the offset
- // in its timestamps for proper a/v sync).
- INT32 nDelta = (INT32)(packet.llPts/UNITS_CONVERSION_MS) - lTime;
- // This fixes 108347, dont synchronize against a bad packet when starting playback
- if( nDelta < 0 && lTime == 0 )
- {
- nDelta = 0;
- packet.llPts = 0;
- m_llFirstPts = m_llLastPts = 0;
- }
- if(m_pRegistry)
- {
- m_pRegistry->SetIntByName("FirstPts", nDelta);
- }
-
- if(m_lStreamOffsetTime > lTime)
- {
- lTime = 0;
- }
- else
- {
- lTime -= m_lStreamOffsetTime;
- }
-
- m_dNextPts = lTime;
- #if defined _DEBUG && defined _WIN32
- char szTmp[256]; /* Flawfinder: ignore */
- SafeSprintf(szTmp, 256, "Audio Pts %ldn", (UINT32)m_dNextPts);
- //OutputDebugString(szTmp);
- #endif
- m_ulPlayTime = lTime;
- }
- else if (packet.llPts)
- {
- // Make sure we inited our decoder before doing ts manipulation
- if (m_ulBitRate)
- {
- // Update the pts (stream ts - 1st stream ts + playtime)
- double dNewTs = (double)(packet.llPts - m_llFirstPts) /
- (double)UNITS_CONVERSION_MS + m_ulPlayTime;
- // Pts refer to the first frame in this packet, so if we have
- // a partial frame in our decode buffer, the new pts is not
- // for that frame. Decrement the new pts by on frame time to
- // sync with the partial frame.
- if (ulFragSize)
- {
- // Ok, some vcds generate erroneous time stamps. The pts
- // refers to the first byte in the packet not instead of
- // the first frame. Try and catch this bug here and adjust.
-
- if (m_bCheckVcdBug)
- {
- m_bCheckVcdBug = FALSE;
- if ((dNewTs - ulFragSize * 1000 / (m_ulBitRate>>3)) -
- m_dNextPts <= 1)
- {
- m_bVcdBug = TRUE;
- }
- }
-
- if (m_bVcdBug)
- dNewTs -= ulFragSize * 1000 / (m_ulBitRate>>3);
- else
- dNewTs -= m_dFrameTime;
- }
- // Dynamic timestamp change
- // Look for timestamps that go backwards or are less than 1000.
- // An encoder is supposed to send timestamps at least every .7 sec
- INT32 lDelta = dNewTs - m_dNextPts;
- if (abs(lDelta) > 1000)
- {
- if(m_pRegistry)
- {
- m_pRegistry->SetIntByName("FirstPts",
- (INT32)(packet.llPts/UNITS_CONVERSION_MS) -
- (INT32)m_dNextPts);
- }
- m_llFirstPts = packet.llPts -
- (INT64)m_dNextPts*UNITS_CONVERSION_MS +
- (INT64)m_ulPlayTime*UNITS_CONVERSION_MS;
- }
- else
- m_dNextPts = dNewTs;
- }
-
- m_llLastPts = packet.llPts;
- }
- return TRUE;
- }
- #endif // DEMUXER