📄 audrendf.cpp
字号:
/* ***** 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 ***** */
//////////////////////////////////////////////////////////////////////////////
//
// audio format for QuickTime renderer for RealMedia Architecture.
//
// Notes:
// This class puts together the audio packets and decodes the audio data.
// There are still unresolved problems with this code - audio data gets
// dropped. This only occurs when there is more than one frame of audio
// data per packet - like MP3. Also, audio services doesn't seem to be
// releasing the audio buffers. This is a huge problem when trying to
// listen to CD quality audio for any amount of time. Another problem -
// the current implementation will not work when one audio frame spans
// multiple rtp packets. The code from the video renderer will need to be
// adapted to work with audio. The class CQTPacket does all the QuickTime
// header parsing. See the notes in that file for more info on the QT header
// structure.
//
/****************************************************************************
* Defines
*/
#define MAX_DECODE_GRANULARITY 200 // in milliseconds
#define DEFAULT_AUDIO_PREROLL 2000 // in milliseconds
#if defined(HELIX_FEATURE_MIN_HEAP)
#define MAXIMUM_AUDIO_PREROLL 3000 // in milliseconds
#else
#define MAXIMUM_AUDIO_PREROLL 15000 // in milliseconds
#endif
/****************************************************************************
* Includes
*/
#include "hlxclib/stdio.h"
#include "hlxclib/string.h"
// #include "netbyte.h"
#include "hxtypes.h"
#include "hxresult.h"
#include "hxcom.h"
#include "hxcomm.h"
#include "hxausvc.h"
#include "ihxpckts.h"
#include "hxerror.h"
#include "hxcore.h"
#include "hxupgrd.h"
#include "hxslist.h"
#include "hxassert.h"
#include "hxstrutl.h"
#include "hxheap.h"
#ifdef _DEBUG
#undef HX_THIS_FILE
static const char HX_THIS_FILE[] = __FILE__;
#endif
#include "hxtick.h"
#include "audrend.h"
#include "audrendf.h"
/****************************************************************************
* CAudioFormat
*/
/****************************************************************************
* Constructor/Destructor
*/
CAudioFormat::CAudioFormat(IHXCommonClassFactory* pCommonClassFactory,
CAudioRenderer* pAudioRenderer)
: m_pCommonClassFactory(pCommonClassFactory)
, m_pContext(NULL)
, m_pPendingPacketQueue(NULL)
, m_ulForceDiscardUntilTime(NO_TIME_SET)
, m_bPostStartTime(FALSE)
, m_ulTrackStartTime(0)
, m_ulTrackEndTime(NO_TIME_SET)
, m_pAudioFmt(NULL)
, m_fCompressionRatio(1.0)
, m_ulStartTime(0)
, m_lRefCount(0)
{
if (m_pCommonClassFactory)
{
m_pCommonClassFactory->AddRef();
}
m_pContext = pAudioRenderer->GetContext();
if (m_pContext)
{
m_pContext->AddRef();
}
// NULL out the AU String
memset(&m_szAUStr[0], 0, MAX_AUSTR_SIZE);
}
CAudioFormat::~CAudioFormat()
{
HX_DELETE(m_pAudioFmt);
FlushQueues();
HX_DELETE(m_pPendingPacketQueue);
HX_RELEASE(m_pCommonClassFactory);
HX_RELEASE(m_pContext);
}
/****************************************************************************
* CAudioFormat::Init
*/
HX_RESULT CAudioFormat::Init(IHXValues* pHeader)
{
HX_RESULT retVal = HXR_FAIL;
if (pHeader)
{
m_pAudioFmt = new HXAudioFormat;
if (m_pAudioFmt)
{
m_pPendingPacketQueue = new CHXSimpleList;
if (m_pPendingPacketQueue)
{
m_pAudioFmt->uChannels = (UINT16) GetULONG32Property(pHeader, "Channels", 1);
m_pAudioFmt->uBitsPerSample = (UINT16) GetULONG32Property(pHeader, "BitsPerSample", 16);
m_pAudioFmt->ulSamplesPerSec = GetULONG32Property(pHeader, "SamplesPerSecond", 8000);
// MaxBlockSize - default to 200ms of data
#ifdef HELIX_FEATURE_FLP_AUDREND
m_pAudioFmt->uMaxBlockSize = (UINT16)
(((double) (m_pAudioFmt->ulSamplesPerSec)) *
((double) (m_pAudioFmt->uBitsPerSample)) *
((double) (m_pAudioFmt->uChannels)) *
MAX_DECODE_GRANULARITY /
8000.0 +
((double) (m_pAudioFmt->uBitsPerSample)) * // Compensate for possible round off
((double) (m_pAudioFmt->uChannels)) /
8.0);
#else // HELIX_FEATURE_FLP_AUDREND
HX_ASSERT((((UINT32) (m_pAudioFmt->ulSamplesPerSec)) *
((UINT32) (m_pAudioFmt->uBitsPerSample)) *
((UINT32) (m_pAudioFmt->uChannels))) <
(((ULONG32) 0xFFFFFFFF) / MAX_DECODE_GRANULARITY));
m_pAudioFmt->uMaxBlockSize = (UINT16)
(((UINT32) (m_pAudioFmt->ulSamplesPerSec)) *
((UINT32) (m_pAudioFmt->uBitsPerSample)) *
((UINT32) (m_pAudioFmt->uChannels)) *
MAX_DECODE_GRANULARITY /
8000 +
((UINT32) (m_pAudioFmt->uBitsPerSample)) * // Compensate for possible round off
((UINT32) (m_pAudioFmt->uChannels)) /
8);
#endif // HELIX_FEATURE_FLP_AUDREND
// Clear return value
retVal = HXR_OK;
}
}
}
return retVal;
}
/****************************************************************************
* CAudioFormat::GetDefaultPreroll
*/
ULONG32 CAudioFormat::GetDefaultPreroll(IHXValues* pValues)
{
return DEFAULT_AUDIO_PREROLL;
}
ULONG32 CAudioFormat::GetMaximumPreroll(IHXValues* pValues)
{
return MAXIMUM_AUDIO_PREROLL;
}
void CAudioFormat::FlushQueues(void)
{
if (m_pPendingPacketQueue != NULL)
{
CMediaPacket* pQTPkt;
while (!m_pPendingPacketQueue->IsEmpty())
{
// empty all of the pending packets
// and delete them
pQTPkt = (CMediaPacket*) m_pPendingPacketQueue->RemoveHead();
CMediaPacket::DeletePacket(pQTPkt);
}
}
}
HX_RESULT CAudioFormat::GetAudioFormat(HXAudioFormat& audioFmt)
{
audioFmt.uChannels = m_pAudioFmt->uChannels;
audioFmt.uBitsPerSample = m_pAudioFmt->uBitsPerSample;
audioFmt.ulSamplesPerSec = m_pAudioFmt->ulSamplesPerSec;
audioFmt.uMaxBlockSize = m_pAudioFmt->uMaxBlockSize;
return HXR_OK;
}
/****************************************************************************
* CAudioFormat::Enqueue
*/
BOOL CAudioFormat::Enqueue(IHXPacket* pPacket)
{
CMediaPacket* pFramePacket = NULL;
HX_RESULT retVal = HXR_OK;
HX_ASSERT(m_pPendingPacketQueue);
pFramePacket = CreateAssembledPacket(pPacket);
if (pFramePacket)
{
m_pPendingPacketQueue->AddTail(pFramePacket);
}
return retVal;
}
HX_RESULT CAudioFormat::CreateAudioFrame(HXAudioData& audioData,
AUDIO_STATE audioState)
{
HX_RESULT retVal = HXR_NO_DATA;
BOOL bTryAgain;
do
{
bTryAgain = FALSE;
HX_RELEASE(audioData.pData);
audioData.ulAudioTime = 0;
retVal = DecodeAudioData(audioData, audioState == AUDIO_END_OF_PACKETS);
if (retVal == HXR_OK)
{
if (AdjustAudioData(audioData))
{
// once we are passed the start time, disable it as a
// a requirement to prevent clipping on wrap-around
m_bPostStartTime = TRUE;
// if we've fulfilled the discard, reset state
if ((m_ulForceDiscardUntilTime != NO_TIME_SET) &&
IsTimeGreater(audioData.ulAudioTime +
ConvertBytesToMs(audioData.pData->GetSize()),
m_ulForceDiscardUntilTime))
{
m_ulForceDiscardUntilTime = NO_TIME_SET;
}
}
else
{
retVal = HXR_NO_DATA;
HX_RELEASE(audioData.pData);
bTryAgain = TRUE;
}
}
} while (bTryAgain);
return retVal;
}
CMediaPacket* CAudioFormat::PeekAudioPacket(void)
{
CMediaPacket* pAudioPacket = NULL;
if (m_pPendingPacketQueue && (!m_pPendingPacketQueue->IsEmpty()))
{
pAudioPacket = (CMediaPacket*) m_pPendingPacketQueue->GetHead();
}
return pAudioPacket;
}
CMediaPacket* CAudioFormat::GetAudioPacket(void)
{
CMediaPacket* pAudioPacket = NULL;
if (m_pPendingPacketQueue && (!m_pPendingPacketQueue->IsEmpty()))
{
pAudioPacket = (CMediaPacket*) m_pPendingPacketQueue->RemoveHead();
}
return pAudioPacket;
}
HX_RESULT CAudioFormat::PutAudioPacket(CMediaPacket* pMediaPacket)
{
HX_RESULT retVal = HXR_FAIL;
HX_ASSERT(m_pPendingPacketQueue);
if (m_pPendingPacketQueue && pMediaPacket)
{
m_pPendingPacketQueue->AddTail(pMediaPacket);
retVal = HXR_OK;
}
return retVal;
}
CMediaPacket* CAudioFormat::CreateAssembledPacket(IHXPacket* pPayloadPacket)
{
return NULL;
}
HX_RESULT CAudioFormat::DecodeAudioData(HXAudioData& audioData,
BOOL bFlushCodec)
{
return HXR_NOTIMPL;
}
void CAudioFormat::DiscardAudioUntil(UINT32 ulTimestamp)
{
BOOL bDone = FALSE;
// cannot equal NO_TIME_SET so we bump it up one
if (ulTimestamp == NO_TIME_SET)
{
ulTimestamp += 1;
}
m_ulForceDiscardUntilTime = ulTimestamp;
// look through the re-assembled packet queue and delete data
// from there that's earlier than the discard until time
CMediaPacket* pQTPkt;
while (!m_pPendingPacketQueue->IsEmpty())
{
pQTPkt = (CMediaPacket*) m_pPendingPacketQueue->GetHead();
if (pQTPkt->m_ulTime >= ulTimestamp)
{
break;
}
m_pPendingPacketQueue->RemoveHead();
CMediaPacket::DeletePacket(pQTPkt);
}
}
void CAudioFormat::Reset(void)
{
m_bPostStartTime = FALSE;
m_ulForceDiscardUntilTime = NO_TIME_SET;
FlushQueues();
}
void CAudioFormat::OverrideFactory(IHXCommonClassFactory* pCommonClassFactory)
{
HX_ASSERT(pCommonClassFactory);
if (pCommonClassFactory)
{
HX_RELEASE(m_pCommonClassFactory);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -