📄 raformat.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 ***** */
/****************************************************************************
* Includes
*/
#include "hlxclib/stdio.h"
#include "hlxclib/string.h"
#include "raformat.h"
#include "smppkfdr.h"
#include "raparser.h"
#include "raibufs.h"
#include "rafactry.h"
#include "hxstrutl.h"
#include "hxmime.h"
#include "adjtime.h"
#ifdef _DEBUG
#undef HX_THIS_FILE
static const char HX_THIS_FILE[] = __FILE__;
#endif
/****************************************************************************
* Defines
*/
//#define RAFORMAT_LOGING_ON
#ifdef RAFORMAT_LOGING_ON
#define LOG_PATH "c:\\log\\rarender\\raformat\\"
#define SPLICE_FILE LOG_PATH##"splice.txt"
#define TIMERANGE_FILE LOG_PATH##"timerange.txt"
#define PLACE_FILE LOG_PATH##"place.txt"
#define XFADE_FILE LOG_PATH##"xfade.txt"
#define DISCARDUNTIL_FILE LOG_PATH##"discarduntil.txt"
#define TREND_FILE LOG_PATH##"trend.txt"
#define TR_FILE LOG_PATH##"timerange.txt"
#define ONPACKET_FILE LOG_PATH##"packet.txt"
#define TIME_FILE LOG_PATH##"time.txt"
#define DOAUDIO_FILE LOG_PATH##"doaudio.txt"
#else
#define SPLICE_FILE 0
#define TIMERANGE_FILE 0
#define PLACE_FILE 0
#define XFADE_FILE 0
#define DISCARDUNTIL_FILE 0
#define TREND_FILE 0
#define TR_FILE 0
#define ONPACKET_FILE 0
#define TIME_FILE 0
#define DOAUDIO_FILE 0
#endif
#define MINMAX_BLOCK_GAP 1 // in ms
#define MAXMAX_BLOCK_GAP 30 // in ms
#define MIN_CODEC_BLOCK_DELAY 3 // in ms
#define MAX_TOLERABLE_BLOCK_YIELD_DEFICIENCY 4 // in bytes
#define MAX_AUDIO_DATA_ATTEMPTS 30
#define DFLT_AUDIO_BUF_SIZE 32768
/****************************************************************************
* CRaFormat
*/
/****************************************************************************
* Constructor & Destructor
*/
CRaFormat::CRaFormat (IUnknown* pContext,
IHXCommonClassFactory* pCommonClassFactory,
IHXErrorMessages* pErrorMessages,
UINT16* pRuleToFlagMap,
UINT16 uStreamNumber)
: m_IBufs(m_StreamParam, uStreamNumber)
, m_pContext(pContext)
, m_pPacketFeeder(NULL)
, m_pCodec(NULL)
, m_ulAudioBufSize(0)
, m_pUpgradeCollection(NULL)
, m_ulCrossFadeEndTime(NO_TIME_SET)
, m_ulForceDiscardUntilTime(NO_TIME_SET)
, m_ulLastPacketTime(NO_TIME_SET)
, m_ulBytesWrite(0)
, m_pAudioSync(NULL)
, m_bRegistered(FALSE)
, m_lTimeOffset(0)
, m_ulTrackStartTime(0)
, m_ulTrackEndTime(0)
, m_bForceInterleaved(FALSE)
, m_bFirstPacket(TRUE)
, m_bDeterminedAdjustment(FALSE)
, m_bForceStartTrackTime(FALSE)
, m_bForceEndTrackTime(FALSE)
, m_bAdjustTimestamps(FALSE)
, m_bEndOfPackets(FALSE)
, m_ulNextAudioTime(NO_TIME_SET)
, m_ulNextActualAudioTime(NO_TIME_SET)
, m_bSecure(FALSE)
, m_bIsVBR(FALSE)
, m_uStreamNumber(uStreamNumber)
, m_ulMaxBlockGap(MAXMAX_BLOCK_GAP)
, m_ulMinExpectedDecodedBlockSize(0)
, m_ulCodecDelay(0)
, m_fCodecDelay(0.0)
, m_bPCMStreamStart(TRUE)
, m_pRuleToFlagMap(pRuleToFlagMap)
, m_pCachingClassFactory(NULL)
{
if (m_pContext)
{
m_pContext->AddRef();
}
m_pCommonClassFactory = pCommonClassFactory;
if (m_pCommonClassFactory)
{
m_pCommonClassFactory->AddRef();
}
if (m_pContext)
{
m_pContext->QueryInterface(IID_IHXUpgradeCollection,
(void**) &m_pUpgradeCollection);
}
if (pErrorMessages)
{
m_pErrorMessages = pErrorMessages;
m_pErrorMessages->AddRef();
}
}
CRaFormat::~CRaFormat()
{
if (m_pCodec)
{
m_pCodec->FreeDecoder();
HX_DELETE(m_pCodec);
}
HX_DELETE(m_pPacketFeeder);
HX_RELEASE(m_pUpgradeCollection);
if( m_pCachingClassFactory )
{
HX_RELEASE(m_pCachingClassFactory);
}
HX_RELEASE(m_pCommonClassFactory);
HX_RELEASE(m_pErrorMessages);
HX_RELEASE(m_pContext);
}
// Read Header
HX_RESULT
CRaFormat::NewReadRAHeader (Byte* buffer,
UINT32 bLength,
BOOL bForceStartTrackTime,
BOOL bForceEndTrackTime,
UINT32 ulTrackStartTime,
UINT32 ulTrackEndTime,
UINT32* pBytesRead,
char* pAllCodecs,
UINT32 ulAllCodecsBufLen)
{
HX_RESULT theError = HXR_INVALID_FILE;
m_bForceStartTrackTime = bForceStartTrackTime;
m_bForceEndTrackTime = bForceEndTrackTime;
m_ulTrackStartTime = ulTrackStartTime;
m_ulTrackEndTime = ulTrackEndTime;
theError = m_StreamParam.ReadOneRAHeader(buffer, bLength, pBytesRead);
// add this codec to the AllCodecs list (if its not already in there)
if (m_StreamParam.codecID && pAllCodecs && (strstr(pAllCodecs, m_StreamParam.codecID) == 0))
{
char szBuffer[64]; /* Flawfinder: ignore */
if (*pAllCodecs == '\0')
{
SafeStrCpy(szBuffer, m_StreamParam.codecID, 64);
}
else
{
SafeSprintf(szBuffer, 64, ", %s", m_StreamParam.codecID);
}
SafeStrCat(pAllCodecs, szBuffer, ulAllCodecsBufLen);
}
#if defined(HELIX_FEATURE_AUDIO_CODEC_RAAC)
// If we are RAAC and VBRS then we need to
// tell the interleave bufs class to use the
// SamplesIn property to compute the ms per block
if ((theError == HXR_OK) &&
m_StreamParam.interleaverID &&
(!strcmp(m_StreamParam.interleaverID, RA_INTERLEAVER_VBRS_ID) ||
!strcmp(m_StreamParam.interleaverID, RA_INTERLEAVER_VBRF_ID)))
{
m_bIsVBR = TRUE;
}
#endif /* #if defined(HELIX_FEATURE_AUDIO_CODEC_RAAC) */
// initialize codecs
if (theError == HXR_OK)
{
theError = LoadDecoderAndInitDeInterleaver();
}
#if defined(HELIX_FEATURE_AUTOUPGRADE)
else if (theError == HXR_INVALID_VERSION ||
theError == HXR_INVALID_REVISION)
{
// We parsed out an invalid RAformat version
// or revision, a condition on which we should AU.
ThrowUpgrade(REALAUDIO_MIME_TYPE);
}
#endif /* #if defined(HELIX_FEATURE_AUTOUPGRADE) */
if (m_StreamParam.uInterleaveFactor == 1)
{
// if the data isn't interleaved then we know
// we don't have to adjust the timestamps
m_bDeterminedAdjustment = TRUE;
}
if (m_bIsVBR)
{
m_IBufs.SetReliableSamplesIn(TRUE);
}
// initialize interleavers
if (theError == HXR_OK)
{
theError = m_IBufs.InitDeinterleaver();
if (theError == HXR_INVALID_INTERLEAVER)
{
// We had an unknown interleaver type, a condition
// for which we should AU.
ThrowUpgrade(REALAUDIO_MIME_TYPE);
}
}
// create superblock allocation
if (theError == HXR_OK)
{
theError = m_IBufs.AllocIBufs();
}
// create packet interleave puffer packet feeder
if (theError == HXR_OK)
{
m_pPacketFeeder = CreatePacketFeeder();
theError = HXR_OUTOFMEMORY;
if (m_pPacketFeeder)
{
theError = HXR_OK;
}
}
if (theError == HXR_OK)
{
if (GetMSPerBlock() >= 1.0)
{
m_ulMaxBlockGap = (UINT32) (GetMSPerBlock() / 4.0 + 0.5);
// Assume max time stamp drift of 1 ms per block of superblock
if (m_ulMaxBlockGap < GetInterleaveFactor())
{
m_ulMaxBlockGap = GetInterleaveFactor();
}
}
if (m_ulMaxBlockGap < MINMAX_BLOCK_GAP)
{
m_ulMaxBlockGap = MINMAX_BLOCK_GAP;
}
if (m_ulMaxBlockGap > MAXMAX_BLOCK_GAP)
{
m_ulMaxBlockGap = MAXMAX_BLOCK_GAP;
}
m_ulMinExpectedDecodedBlockSize = m_IBufs.CalcBytes(GetMSPerBlock());
if (m_ulMinExpectedDecodedBlockSize > MAX_TOLERABLE_BLOCK_YIELD_DEFICIENCY)
{
m_ulMinExpectedDecodedBlockSize -= MAX_TOLERABLE_BLOCK_YIELD_DEFICIENCY;
}
}
DEBUG_OUTF_IDX(m_uStreamNumber, RA_FLOW_FILE, (s, "Init(%d): BlockMS=%.2f, SuperMS=%d, IBlocks=%hd\n",
m_uStreamNumber,
GetMSPerBlock(),
GetSuperBlockTime(),
GetInterleaveFactor()));
return theError;
}
void
CRaFormat::GetAudioFormat (HXAudioFormat& audioFmt)
{
audioFmt.uChannels = m_StreamParam.uChannels;
audioFmt.uBitsPerSample = m_StreamParam.uSampleSize;
audioFmt.ulSamplesPerSec = m_StreamParam.ulSampleRate;
audioFmt.uMaxBlockSize = (UINT16) m_ulAudioBufSize;
}
CCodec*
CRaFormat::CreateDecoder(char* pCodecID)
{
if (!strcmp(pCodecID, "racp"))
{
// The racp 4cc is also handled
// by the raac codec
pCodecID = "raac";
}
return new CCodec(pCodecID, m_pContext);
}
CRealAudioPacketFeeder*
CRaFormat::CreatePacketFeeder(void)
{
#if defined(HELIX_FEATURE_RAREND_ADV_PACKET_FEEDER)
// The RealAudio advanced packet feeder is distributed
// as a binary statically-linked library and therefore must
// be created from this factory class that resides in the libary.
return CRealAudioRendererFactory::CreateRealAudioAdvancedPacketFeeder(m_StreamParam,
m_IBufs,
m_pRuleToFlagMap,
m_uStreamNumber);
#else // HELIX_FEATURE_RAREND_ADV_PACKET_FEEDER
//otherwise we just create it directly.
return new CRealAudioSimplePacketFeeder(m_StreamParam,
m_IBufs,
m_pRuleToFlagMap,
m_uStreamNumber);
#endif // HELIX_FEATURE_RAREND_ADV_PACKET_FEEDER
}
// decoding
HX_RESULT
CRaFormat::InitDecoder(CStreamParam& param, CCodec** hCodec)
{
HX_RESULT theError = HXR_OK;
CCodec* pCodec = NULL;
CHXBuffer* pBuffer = NULL;
pCodec = CreateDecoder(param.codecID);
if (!pCodec)
{
theError = HXR_OUTOFMEMORY;
}
else
{
// first load with codec w/o versioning
theError = pCodec->InitCodec(FALSE);
if (HXR_OK != theError)
{
// try to load with codec w/ versioning(xxxx3260)
theError = pCodec->InitCodec(TRUE);
}
}
if (theError == HXR_OK)
{
RADECODER_INIT_PARAMS initParams;
// set up initialization parameters
initParams.sampleRate = param.ulSampleRate;
initParams.bitsPerSample = param.uSampleSize;
initParams.channels = param.uChannels;
initParams.audioQuality = 100;
initParams.bitsPerFrame = param.uCodecFrameSize;
initParams.granularity = param.ulGranularity;
initParams.opaqueDataLength = param.ulOpaqueDataSize;
initParams.opaqueData = param.opaqueData;
theError = pCodec->InitDecoder(&initParams, FALSE);
// Sometimes the uChannels parameter may be passed
// in with a 0, and the decoder will update the
// value. Therefore, we need to copy the decoder
// value back.
param.uChannels = initParams.channels;
// If for some reason the channels parameter is
// still 0, then we have a problem worthy of failure
if (param.uChannels == 0)
{
theError = HXR_FAIL;
}
// The param.ulSampleRate parameter may be different
// coming out of InitDecoder() than it was going in.
// This indicates that the codec has initialized itself
// at a sample rate which is different the sample rate
// in param.ulSampleRate. This can happen in the
// case of the High-Efficiency AAC profile.
param.ulSampleRate = initParams.sampleRate;
// If for some reason the sample rate is 0, then
// we have a problem
if (param.ulSampleRate == 0)
{
theError = HXR_FAIL;
}
if (theError == HXR_OK)
theError = pCodec->SetFlavor(param.uFlavorIndex);
}
#if defined(HELIX_FEATURE_AUTOUPGRADE)
if (HXR_DEC_NOT_FOUND == theError || HXR_INVALID_VERSION == theError)
{
ThrowUpgrade((const char*) param.codecID);
}
#endif /* #if defined(HELIX_FEATURE_AUTOUPGRADE) */
if (theError == HXR_OK)
{
*hCodec = pCodec;
}
else
{
*hCodec = NULL;
HX_DELETE(pCodec);
}
// Ask the codec for the number of samples per block, and use this to
// figure out exactly how big our decoded data buffer needs to be.
ULONG32 * pulSamplesPerBlock;
UINT16 uPropSize = 0;
ULONG32 ulBytesPerMinute = m_StreamParam.ulBytesPerMin;
if (pCodec)
{
pulSamplesPerBlock = (ULONG32*) pCodec->GetFlavorProperty(
param.uFlavorIndex,
FLV_PROP_SAMPLES_IN,
&uPropSize);
}
if (m_bIsVBR)
{
// For VBR Streams, do not use bytes per minute to compute decoder
// buffer size since bytes per minute are variable
ulBytesPerMinute = 0;
}
#if defined(HELIX_FEATURE_MIN_HEAP)
// In case of min_heap - always use codec reported block size when avaialable
// This however does not work correctly for some non-deafult encoder setting.
// It needs to be corrected on MIN-HEAP utilizing platforms.
if (uPropSize != 0)
{
ulBytesPerMinute = 0;
}
#endif // HELIX_FEATURE_MIN_HEAP
if (ulBytesPerMinute != 0)
{
// Resort to backup plan: this is very non-optimal for heap usage!
UINT32 uMaxSecPerBlock = (m_StreamParam.uInterleaveBlockSize * 60/ulBytesPerMinute) + 1;
m_ulAudioBufSize = uMaxSecPerBlock * m_StreamParam.ulSampleRate * m_StreamParam.uSampleSize / 8 * m_StreamParam.uChannels;
}
else
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -