mp3draft.cpp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:12k
- /* ***** 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 "hxwintyp.h"
- #include "hxcom.h"
- #include "hxcomm.h"
- #include "hxassert.h"
- #include "hxslist.h"
- #include "hxmarsh.h"
- #include "hxcomm.h"
- #include "ihxpckts.h"
- #include "hxformt.h"
- #include "hxrendr.h"
- #include "hxformt.h"
- #include "hxengin.h"
- #include "ringbuf.h"
- #include "mp3format.h" // CMp3Format
- #include "mp3draft.h"
- MP3DraftPayloadFormat::MP3DraftPayloadFormat()
- : m_lRefCount (0)
- , m_pContext (NULL)
- , m_pClassFactory (NULL)
- , m_pStreamHeader (NULL)
- , m_ulStreamNum (0)
- , m_bPacketizing (FALSE)
- , m_bFlushed (FALSE)
- , m_pFmtBuf (NULL)
- , m_pMp3Fmt (NULL)
- , m_bPacketReceived (FALSE)
- , m_bHeaderParsed (FALSE)
- , m_fTimePerFrame (0.0)
- , m_fNextTimestamp (0.0)
- {
- }
- MP3DraftPayloadFormat::~MP3DraftPayloadFormat()
- {
- HX_RELEASE(m_pContext);
- HX_RELEASE(m_pClassFactory);
- HX_RELEASE(m_pStreamHeader);
- HX_DELETE(m_pFmtBuf);
- HX_DELETE(m_pMp3Fmt);
- }
- // *** IUnknown methods ***
- /////////////////////////////////////////////////////////////////////////
- // Method:
- // IUnknown::QueryInterface
- // Purpose:
- // Implement this to export the interfaces supported by your
- // object.
- //
- STDMETHODIMP
- MP3DraftPayloadFormat::QueryInterface(REFIID riid, void** ppvObj)
- {
- if (IsEqualIID(riid, IID_IUnknown))
- {
- AddRef();
- *ppvObj = this;
- return HXR_OK;
- }
- else if (IsEqualIID(riid, IID_IHXPayloadFormatObject))
- {
- AddRef();
- *ppvObj = (IHXPayloadFormatObject*)this;
- return HXR_OK;
- }
- *ppvObj = NULL;
- return HXR_NOINTERFACE;
- }
- /////////////////////////////////////////////////////////////////////////
- // Method:
- // IUnknown::AddRef
- // Purpose:
- // Everyone usually implements this the same... feel free to use
- // this implementation.
- //
- STDMETHODIMP_(ULONG32)
- MP3DraftPayloadFormat::AddRef()
- {
- return InterlockedIncrement(&m_lRefCount);
- }
- /////////////////////////////////////////////////////////////////////////
- // Method:
- // IUnknown::Release
- // Purpose:
- // Everyone usually implements this the same... feel free to use
- // this implementation.
- //
- STDMETHODIMP_(ULONG32)
- MP3DraftPayloadFormat::Release()
- {
- if (InterlockedDecrement(&m_lRefCount) > 0)
- {
- return m_lRefCount;
- }
- delete this;
- return 0;
- }
- STDMETHODIMP
- MP3DraftPayloadFormat::Init(IUnknown* pContext,
- BOOL bPacketize)
- {
- HX_ASSERT(pContext);
- HX_RELEASE(m_pContext);
- m_pContext = pContext;
- m_pContext->AddRef();
- HX_RELEASE(m_pClassFactory);
- m_pContext->QueryInterface(IID_IHXCommonClassFactory,
- (void**)&m_pClassFactory);
- HX_ASSERT(m_pClassFactory);
- // Remember if we are packetizing or depacketizing
- m_bPacketizing = bPacketize;
- if (!m_bPacketizing)
- {
- // For now, we don't support depacketizing
- return HXR_NOTIMPL;
- }
- // Create a ring buffer to store all incoming data
- HX_DELETE(m_pFmtBuf);
- m_pFmtBuf = new CIHXRingBuffer(m_pClassFactory, 8192, (1024<<1)+512);
- // Create an MP3 format object to handle parsing
- HX_DELETE(m_pMp3Fmt);
- m_pMp3Fmt = new CMp3Format();
- return HXR_OK;
- }
- STDMETHODIMP
- MP3DraftPayloadFormat::Reset()
- {
- // Discard all data from the ring buffer
- m_pFmtBuf->Reset();
- // Create a new MP3 format object
- HX_DELETE(m_pMp3Fmt);
- m_pMp3Fmt = new CMp3Format();
- m_bHeaderParsed = FALSE;
- m_bPacketReceived = FALSE;
- m_bFlushed = FALSE;
- return HXR_OK;
- }
- STDMETHODIMP
- MP3DraftPayloadFormat::SetStreamHeader(IHXValues* pHeader)
- {
- HX_ASSERT(pHeader);
- m_pStreamHeader = pHeader;
- m_pStreamHeader->AddRef();
- m_pStreamHeader->GetPropertyULONG32("StreamNumber", m_ulStreamNum);
- return HXR_OK;
- }
- STDMETHODIMP
- MP3DraftPayloadFormat::GetStreamHeader(REF(IHXValues*) pHeader)
- {
- HX_ASSERT(m_pStreamHeader);
- pHeader = m_pStreamHeader;
- pHeader->AddRef();
- return HXR_OK;
- }
- STDMETHODIMP
- MP3DraftPayloadFormat::SetPacket(IHXPacket* pPacket)
- {
- HX_RESULT hResult = HXR_OK;
- HX_ASSERT(pPacket);
- // Add the data from this buffer to the ring buffer
- IHXBuffer* pBuffer = pPacket->GetBuffer();
- m_pFmtBuf->CopyData(pBuffer->GetBuffer(), pBuffer->GetSize());
- HX_RELEASE(pBuffer);
- // Test for buffer overflow, and wrap the
- // ring buffer if necessary
- WrapRingBuffer();
- if (!m_bPacketReceived)
- {
- m_bPacketReceived = TRUE;
- m_fNextTimestamp = pPacket->GetTime();
- }
- if (!m_bHeaderParsed)
- {
- UCHAR* pBuf = NULL;
- UINT32 ulBytes = 0;
- // See if we have enough data to initialize our formatter
- pBuf = m_pFmtBuf->GetReadPointer(ulBytes);
- int nFrame;
- INT32 lScan = 0;
- lScan = m_pMp3Fmt->ScanForSyncWord(pBuf, ulBytes, nFrame);
- if (lScan == -1)
- {
- // We probably just don't have enough data yet to
- // be able to initialize our header information
- hResult = HXR_OK;
- }
- else
- {
- // We have enough data to initialize, but we
- // need to advance past any initial garbage to
- // get to the beginning of the first MP3 frame
- m_pFmtBuf->AdvanceRead(lScan);
- pBuf = m_pFmtBuf->GetReadPointer(ulBytes);
- // Init our reformatter
- if (!m_pMp3Fmt->Init(pBuf, ulBytes))
- {
- hResult = HXR_FAIL;
- }
- else
- {
- UINT32 ulBitRate = 0;
- UINT32 ulMaxSampleRate = 0;
- int nChannels = 0;
- int nLayer = 0;
- int nSamplesPerFrame = 0;
- m_pMp3Fmt->GetEncodeInfo(pBuf, ulBytes, ulBitRate,
- ulMaxSampleRate, nChannels,
- nLayer, nSamplesPerFrame);
- // Compute frame duration in ms
- m_fTimePerFrame = nSamplesPerFrame * 1000.0 / ulMaxSampleRate;
- hResult = HXR_OK;
- m_bHeaderParsed = TRUE;
- }
- }
- }
- return hResult;
- }
- STDMETHODIMP
- MP3DraftPayloadFormat::GetPacket(REF(IHXPacket*) pPacket)
- {
- HX_RESULT hResult = HXR_OK;
- pPacket = NULL;
- if (!m_bHeaderParsed)
- {
- if (m_bFlushed)
- {
- // We have used up all available input
- hResult = HXR_STREAM_DONE;
- }
- else
- {
- // We don't have enough input
- // data to produce a packet
- hResult = HXR_INCOMPLETE;
- }
- }
- else
- {
- hResult = CreateNormalPacket(pPacket);
- }
- return hResult;
- }
- STDMETHODIMP
- MP3DraftPayloadFormat::Flush()
- {
- m_bFlushed = TRUE;
- return HXR_OK;
- }
- HX_RESULT
- MP3DraftPayloadFormat::CreateNormalPacket(REF(IHXPacket*) pPacket)
- {
- HX_RESULT hResult = HXR_OK;
- UCHAR* pModFrameStart = NULL;
- int nModFrameSize = 0;
- // Make sure the current read position in the
- // ring buffer is the beginning of an MP3 frame
- hResult = FindMP3Frame();
- if (SUCCEEDED(hResult))
- {
- UINT32 nSync = 0;
- for (;;)
- {
- // We need 1+ audio frames
- UINT32 ulReadSize = 0;
- pModFrameStart = m_pFmtBuf->GetReadPointer(ulReadSize);
- nSync = m_pMp3Fmt->CheckValidFrame(pModFrameStart, ulReadSize);
- if (ulReadSize >= nSync + 6 ||
- m_bFlushed)
- {
- nModFrameSize = m_pMp3Fmt->ReformatMP3Frame(&pModFrameStart,
- ulReadSize,
- m_pFmtBuf->GetPrevBytes());
- // If we did not have enough back data to reformat,
- // skip this frame in the format buffer
- if (!nModFrameSize && nSync)
- {
- m_pFmtBuf->AdvanceRead(nSync);
- }
- else
- {
- break;
- }
- }
- else
- {
- nModFrameSize = 0;
- break;
- }
- }
-
- if (nModFrameSize)
- {
- m_pFmtBuf->AdvanceRead(nSync);
- }
- else
- {
- hResult = HXR_INCOMPLETE;
- }
- }
- if (SUCCEEDED(hResult))
- {
- IHXBuffer* pBuffer = NULL;
- UCHAR* pBuf = NULL;
- // Create a packet with this new formatted frame
- m_pClassFactory->CreateInstance(CLSID_IHXPacket, (void**)&pPacket);
- HX_ASSERT(pPacket);
- m_pClassFactory->CreateInstance(CLSID_IHXBuffer, (void**)&pBuffer);
- HX_ASSERT(pBuffer);
- pBuffer->SetSize(nModFrameSize + 4);
- pBuf = pBuffer->GetBuffer();
- // Set the 4-Byte audio header for this packet
- // (as dictated by RFC 2250)
- putshort(pBuf, 0);
- pBuf += 2;
- putshort(pBuf, 0);
- pBuf += 2;
- // Copy in the actual frame data
- memcpy(pBuf, pModFrameStart, nModFrameSize); /* Flawfinder: ignore */
- pPacket->Set(pBuffer, (UINT32)m_fNextTimestamp, (UINT16)m_ulStreamNum,
- HX_ASM_SWITCH_ON | HX_ASM_SWITCH_OFF, 0);
- HX_RELEASE(pBuffer);
- m_fNextTimestamp += m_fTimePerFrame;
- }
- else if (m_bFlushed)
- {
- // We have used up all available input
- hResult = HXR_STREAM_DONE;
- }
- return hResult;
- }
- HX_RESULT
- MP3DraftPayloadFormat::FindMP3Frame()
- {
- INT32 lScan = 0;
- UCHAR* pFrame = NULL;
- UINT32 ulBytes = 0;
- pFrame = m_pFmtBuf->GetReadPointer(ulBytes);
- // We should be at an mp3 frame, make sure we are
- int nSync = m_pMp3Fmt->CheckValidFrame(pFrame, ulBytes);
- // If we were not at a frame, scan for the next one
- if (!nSync)
- {
- lScan = m_pMp3Fmt->ScanForSyncWord(pFrame,
- ulBytes,
- nSync);
- if (lScan == -1)
- {
- return HXR_INCOMPLETE;
- }
- // Skip leading garbage
- m_pFmtBuf->AdvanceRead(lScan);
- // Try again...
- pFrame = m_pFmtBuf->GetReadPointer(ulBytes);
- nSync = m_pMp3Fmt->CheckValidFrame(pFrame, ulBytes);
- }
-
- if (nSync)
- {
- return HXR_OK;
- }
- return HXR_INCOMPLETE;
- }
- HX_RESULT
- MP3DraftPayloadFormat::WrapRingBuffer()
- {
- UCHAR *pTemp = NULL;
- UINT32 ulBytes = 0;
- pTemp = m_pFmtBuf->GetReadPointer(ulBytes);
- UINT32 nSync = m_pMp3Fmt->CheckValidFrame(pTemp, ulBytes);
- // Make sure we have 1+ frame in the buffer
- if (!nSync ||
- (m_pFmtBuf->GetBytesInBuffer() > (UINT32)nSync+6 &&
- ulBytes < (UINT32)nSync + 6))
- {
- // Preserve enough data for main_data_begin
- m_pFmtBuf->Wrap(512);
- }
- return HXR_OK;
- }