📄 mp4afmt.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 ***** */
/****************************************************************************
* Defines
*/
// #define _BYPASS_DECODER
// #define _SILENT_PLAY
// #define ENABLE_FRAME_TRACE
#define _IGNORE_UNSUPPORTED // must be defined if _BYPASS_DECODER is defined
#define MIN_ACCEPTBALE_DATA_REMAINDER 1 // in bytes
#define MP4_DEFAULT_AUDIO_PREROLL 2000 // in milliseconds
#define MAX_TOLERABLE_TIME_GAP 5 // in milliseconds
/****************************************************************************
* Includes
*/
#include "mp4afmt.h"
#include "mp4adec.h"
#include "hxtick.h"
#include "hxassert.h"
#include "hxstrutl.h"
#include "mp4audio.h"
#include "mp4apyld.h"
#include "mp4gpyld.h"
#include "amrpyld.h"
#include "hxamrpyld.h"
#if defined(HELIX_FEATURE_AUDIO_CODEC_MP3)
#include "mp3draft.h"
#endif /* #if defined(HELIX_FEATURE_AUDIO_CODEC_MP3) */
/****************************************************************************
* Debug
*/
#ifdef ENABLE_FRAME_TRACE
#define MAX_FRAME_TRACE_ENTRIES 100000
ULONG32 ulFrameTraceIdx = 0;
LONG32 frameTraceArray[MAX_FRAME_TRACE_ENTRIES][4];
void DumpFrameEntries(void)
{
FILE* pFile = NULL;
ULONG32 ulIdx;
if (ulFrameTraceIdx > 0)
{
pFile = fopen("c:\\mp4a.txt", "wb");
}
if (pFile)
{
for (ulIdx = 0; ulIdx < ulFrameTraceIdx; ulIdx++)
{
fprintf(pFile, "%c(%d=%d) = %d\n", (char) frameTraceArray[ulIdx][1],
frameTraceArray[ulIdx][2],
frameTraceArray[ulIdx][3],
frameTraceArray[ulIdx][0]);
}
fclose(pFile);
}
ulFrameTraceIdx = 0;
}
#endif // ENABLE_FRAME_TRACE
/****************************************************************************
* Locals
*/
/****************************************************************************
* Method:
* CMP4AudioFormat::CMP4AudioFormat
*
*/
CMP4AudioFormat::CMP4AudioFormat(IHXCommonClassFactory* pCommonClassFactory,
CMP4AudioRenderer* pMP4AudioRenderer)
: CAudioFormat(pCommonClassFactory, pMP4AudioRenderer)
, m_pRssm(NULL)
, m_bNewAssembledFrame(TRUE)
, m_ulAUDuration(0)
, m_ulLastDecodedEndTime(0)
, m_ulLastFrameTime(0)
, m_ulCodecDelayMs(0)
, m_bCanChangeAudioStream(FALSE)
, m_ulMaxDecoderOutputBytes(0)
, m_ulMaxDecoderOutputSamples(0)
, m_pDecoderBuffer(NULL)
, m_ulDecoderBufferSize(0)
, m_pDecoderModule(NULL)
, m_pDecoderInstance(NULL)
, m_pMP4AudioRenderer(pMP4AudioRenderer)
{
// Register the payload format builders with m_fmtFactory
RegisterPayloadFormats();
HX_ASSERT(m_pCommonClassFactory);
}
/****************************************************************************
* Method:
* CMP4AudioFormat::~CMP4AudioFormat
*
*/
CMP4AudioFormat::~CMP4AudioFormat()
{
_Reset();
HX_RELEASE(m_pDecoderInstance);
HX_DELETE(m_pDecoderModule);
HX_VECTOR_DELETE(m_pDecoderBuffer);
HX_RELEASE(m_pRssm);
#ifdef ENABLE_FRAME_TRACE
DumpFrameEntries();
#endif // ENABLE_FRAME_TRACE
}
/****************************************************************************
* Method:
* CMP4AudioFormat::Init
*
*/
HX_RESULT CMP4AudioFormat::Init(IHXValues* pHeader)
{
HX_RESULT retVal = CAudioFormat::Init(pHeader);
// Open the Decoder Module
if (SUCCEEDED(retVal))
{
m_pDecoderModule = CreateDecoder();
retVal = HXR_OUTOFMEMORY;
if (m_pDecoderModule)
{
retVal = HXR_OK;
}
}
if (SUCCEEDED(retVal))
{
retVal = m_pDecoderModule->Open(pHeader,
&m_pDecoderInstance,
m_pContext);
#if defined(HELIX_FEATURE_AUTOUPGRADE)
if (FAILED(retVal) && retVal == HXR_REQUEST_UPGRADE)
{
// If we returned a HXR_REQUEST_UPGRADE, then we
// failed to load the decoder binary. Therefore, we
// will copy the decoder's AU string into our
// own AU String
SafeStrCpy(m_szAUStr, // m_szAUStr is from our parent class
m_pDecoderModule->GetAutoUpgradeString(),
MAX_AUSTR_SIZE);
}
#endif /* #if defined(HELIX_FEATURE_AUTOUPGRADE) */
}
#if defined(HELIX_FEATURE_STATS)
if (SUCCEEDED(retVal))
{
char* pVal = (char*) m_pDecoderModule->GetCodecName();
if (pVal)
{
m_pMP4AudioRenderer->ReportStat(AS_CODEC_NAME, pVal);
}
pVal = (char*) m_pDecoderModule->GetCodecFourCC();
if (pVal)
{
m_pMP4AudioRenderer->ReportStat(AS_CODEC_4CC, pVal);
}
}
#endif /* #if defined(HELIX_FEATURE_STATS) */
// Create Packet Assembler
if (SUCCEEDED(retVal))
{
retVal = m_fmtFactory.BuildFormat(m_pCommonClassFactory, FALSE,
pHeader, m_pRssm);
#if defined(HELIX_FEATURE_AUTOUPGRADE)
if (FAILED(retVal) && retVal == HXR_REQUEST_UPGRADE)
{
// If BuildFormat returns HXR_REQUEST_UPGRADE, then
// it means that no depacketizer had successful calls
// to Init() and SetStreamHeader(), but at least one
// of the depacketizers returned HXR_REQUEST_UPGRADE.
//
// Copy our own mime type into the AU string
IHXBuffer* pMimeTypeStr = NULL;
pHeader->GetPropertyCString("MimeType", pMimeTypeStr);
if (pMimeTypeStr)
{
SafeStrCpy(m_szAUStr, // m_szAUStr is from our parent class
(const char*) pMimeTypeStr->GetBuffer(),
MAX_AUSTR_SIZE);
}
HX_RELEASE(pMimeTypeStr);
}
#endif /* #if defined(HELIX_FEATURE_AUTOUPGRADE) */
#ifdef _IGNORE_UNSUPPORTED
if (FAILED(retVal))
{
HX_RELEASE(m_pDecoderInstance);
retVal = HXR_OK;
}
#endif // _IGNORE_UNSUPPORTED
}
// Open Codec Instance
if (SUCCEEDED(retVal) && m_pDecoderInstance)
{
HX_ASSERT(m_pDecoderModule);
ULONG32 ulBitstreamHeaderSize;
const UINT8* pBitstreamHeader;
UINT8 unBitstreamType;
ulBitstreamHeaderSize = m_pRssm->GetBitstreamHeaderSize();
pBitstreamHeader = m_pRssm->GetBitstreamHeader();
unBitstreamType = m_pRssm->GetBitstreamType();
retVal = HXR_FAIL;
if (pBitstreamHeader && (ulBitstreamHeaderSize > 0))
{
retVal = HXR_OK;
}
if (SUCCEEDED(retVal))
{
retVal = m_pDecoderInstance->OpenDecoder(unBitstreamType, // eCfgDesc
pBitstreamHeader,
ulBitstreamHeaderSize);
if (FAILED(retVal))
{
#if defined(HELIX_FEATURE_AUTOUPGRADE)
// If we failed in our OpenDecoder() call, then the
// decoder must be a version which does not support the
// particular profile which we passed in. Therefore,
// we will AU with the "qtplayer" string to instruct
// the TLC to attempt to play this file other means.
//
// Copy into our parent class's AU string buffer
SafeStrCpy(m_szAUStr, // m_szAUStr is from our parent class
"qtplayer",
MAX_AUSTR_SIZE);
#endif /* #if defined(HELIX_FEATURE_AUTOUPGRADE) */
// When CAudioFormat::Init() returns to where it was called
// from CAudioRenderer::OnHeader(), then if the return code
// is HXR_REQUEST_UPGRADE, then it will assume it needs
// to AU, and will look for an AU string from CAudioFormat.
// So we need to return HXR_REQUEST_UPGRADE.
retVal = HXR_REQUEST_UPGRADE;
}
}
#ifdef _IGNORE_UNSUPPORTED
if (FAILED(retVal) && retVal != HXR_REQUEST_UPGRADE)
{
HX_RELEASE(m_pDecoderInstance);
retVal = HXR_OK;
}
#endif // _IGNORE_UNSUPPORTED
}
// Inquire and set Audio data parameters
if (SUCCEEDED(retVal) && m_pDecoderInstance)
{
retVal = UpdateAudioFormat(m_ulLastDecodedEndTime, TRUE);
}
if (SUCCEEDED(retVal))
{
m_bCanChangeAudioStream = CanChangeAudioStream();
}
#ifdef _BYPASS_DECODER
HX_RELEASE(m_pDecoderInstance);
#endif // _BYPASS_DECODER
return retVal;
}
/****************************************************************************
* CMP4AudioFormat::GetDefaultPreroll
*/
ULONG32 CMP4AudioFormat::GetDefaultPreroll(IHXValues* pValues)
{
return MP4_DEFAULT_AUDIO_PREROLL;
}
HX_RESULT CMP4AudioFormat::UpdateAudioFormat(ULONG32& ulAnchorTime,
BOOL bForceUpdate)
{
HX_RESULT retVal = HXR_FAIL;
if (m_pDecoderInstance && m_pAudioFmt && m_pRssm)
{
UINT32 ulChannels = 0;
BOOL bFormatChanged = FALSE;
// Set the bits per sample (always 16 bits per sample)
m_pAudioFmt->uBitsPerSample = 16;
// Set number of channels
retVal = m_pDecoderInstance->GetNChannels(ulChannels);
if (SUCCEEDED(retVal))
{
retVal = HXR_FAIL;
if (ulChannels)
{
retVal = HXR_OK;
if ((ulChannels != m_pAudioFmt->uChannels) || bForceUpdate)
{
bFormatChanged = TRUE;
}
}
}
// Set the sample rate
if (SUCCEEDED(retVal))
{
UINT32 ulSampleRate = 0;
retVal = m_pDecoderInstance->GetSampleRate(ulSampleRate);
if (SUCCEEDED(retVal))
{
retVal = HXR_FAIL;
if (ulSampleRate)
{
retVal = HXR_OK;
if ((m_pAudioFmt->ulSamplesPerSec != ulSampleRate) ||
bForceUpdate)
{
ULONG32 ulAnchorInMs = m_TSConverter.Convert(ulAnchorTime);
m_pAudioFmt->uChannels = (UINT16) ulChannels;
m_pAudioFmt->ulSamplesPerSec = ulSampleRate;
ulAnchorTime = ConvertMsToTime(ulAnchorInMs);
ConfigureRssm(ulAnchorInMs);
m_TSConverter.SetBase(ulSampleRate, 1000);
m_TSConverter.SetOffset(ulAnchorInMs);
bFormatChanged = TRUE;
}
else
{
m_pAudioFmt->uChannels = (UINT16) ulChannels;
}
}
}
}
// Set the max samples out
if (SUCCEEDED(retVal))
{
UINT32 ulMaxSamplesOut = 0;
retVal = m_pDecoderInstance->GetMaxSamplesOut(ulMaxSamplesOut);
if (SUCCEEDED(retVal))
{
retVal = HXR_FAIL;
if (ulMaxSamplesOut)
{
retVal = HXR_OK;
if ((ulMaxSamplesOut != m_ulMaxDecoderOutputSamples) ||
bForceUpdate)
{
// Save the max samples out
m_ulMaxDecoderOutputSamples = ulMaxSamplesOut;
// Compute and set the AU duration
m_ulAUDuration = m_ulMaxDecoderOutputSamples / m_pAudioFmt->uChannels;
m_pRssm->SetAUDuration(m_ulAUDuration);
// Compute the max output in bytes
m_ulMaxDecoderOutputBytes = CAudioFormat::ConvertSamplesToBytes(m_ulMaxDecoderOutputSamples);
// Save the max block size
m_pAudioFmt->uMaxBlockSize = (UINT16) m_ulMaxDecoderOutputBytes;
bFormatChanged = TRUE;
}
}
}
}
// Set the codec delay in samples
if (bFormatChanged && SUCCEEDED(retVal))
{
UINT32 ulCodecDelaySamples = 0;
retVal = m_pDecoderInstance->GetDelay(ulCodecDelaySamples);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -