⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hxaudstr_new.cpp

📁 著名的 helix realplayer 基于手机 symbian 系统的 播放器全套源代码
💻 CPP
📖 第 1 页 / 共 5 页
字号:
}

/************************************************************************
 *  Method:
 *		IHXAudioStream::ResetStream
 *	Purpose:
 */
void CHXAudioStream::ResetStream()
{
    m_bInited		= FALSE;
    m_bCanBeRewound	= FALSE;
    m_bSetupDone	= FALSE;
    m_bAudioFormatKnown	= FALSE;
    m_bIsResumed	= FALSE;
    
    UnRegister();

    while (m_pAvailableBuffers && m_pAvailableBuffers->GetCount() > 0)
    {
	IHXBuffer* pBuffer = (IHXBuffer*) m_pAvailableBuffers->RemoveHead();
	HX_RELEASE(pBuffer);
    }

    HX_DELETE(m_pAvailableBuffers);

    // Delete all entries in the audio data list
    FlushBuffers();
    HX_DELETE(m_pDataList);
    HX_DELETE(m_pInstantaneousList);

    CleanupRAByToTs();
    HX_DELETE(m_pRAByToTsInList);
    HX_DELETE(m_pRAByToTsAdjustedList);

    HX_DELETE(m_pMixEngine);

    m_bGotHooks = FALSE;

    m_llLastWriteTime = 0;
    m_ulTSRollOver = 0;

    HX_RELEASE(m_pValues);

#if defined(HELIX_FEATURE_AUDIO_PREMIXHOOK)
    // Delete all entries in the pre-mix hook list.
    if ( m_PreMixHookMap.GetCount() > 0)
    {
        HXAudioHookInfo* h = 0;
        CHXMapPtrToPtr::Iterator lIter = m_PreMixHookMap.Begin();
        for (; lIter != m_PreMixHookMap.End(); ++lIter)
        {
            h = (HXAudioHookInfo*) (*lIter);
	    ProcessAudioHook(ACTION_REMOVE, h->pHook);
            h->pHook->Release();
            delete h;
        }
	
	m_PreMixHookMap.RemoveAll();
    }
#endif /* HELIX_FEATURE_AUDIO_PREMIXHOOK */

#ifdef HELIX_FEATURE_VOLUME
    if( m_pStreamVolume )
    {
        m_pStreamVolume->RemoveAdviseSink(this);
        m_pStreamVolume->Release();
        m_pStreamVolume=NULL;
    }
#endif    

    
    HX_DELETE(m_pInDataPtr);
    HX_DELETE(m_pOutDataPtr);

    if (m_DryNotificationMap && m_DryNotificationMap->GetCount() > 0)
    {
        IHXDryNotification* pDryNotification = 0;
        CHXMapPtrToPtr::Iterator lIter = m_DryNotificationMap->Begin();
        for (; lIter != m_DryNotificationMap->End(); ++lIter)
        {
            pDryNotification = (IHXDryNotification*) (*lIter);
            pDryNotification->Release();
        }
	
	m_DryNotificationMap->RemoveAll();
    }

    HX_RELEASE(m_pCrossFadeStream);
    HX_RELEASE(m_pCommonClassFactory);
#if defined(HELIX_FEATURE_PREFERENCES)
    HX_RELEASE(m_pPreferences);
#endif /* HELIX_FEATURE_PREFERENCES */
    HX_RELEASE(m_Owner);

    return;
}

HX_RESULT
CHXAudioStream::ProcessAudioHook(PROCESS_ACTION action, 
				 IHXAudioHook* pAudioHook)
{
    return HXR_OK;
}

/************************************************************************
 *  Method:
 *		IHXAudioStream::InitHooks
 *	Purpose:
 *	Init any pre-mix hooks. Return TRUE if hooks exist else return
 *	FALSE.
 */
void CHXAudioStream::InitHooks()
{
#if defined(HELIX_FEATURE_AUDIO_PREMIXHOOK)
    /* Iterate thru the hook list and call the hook's OnInit().
     * If any of the hooks have disabled write set to TRUE, then
     * we will let this override any set to FALSE.
     */
    if ( m_PreMixHookMap.GetCount() > 0 )
    {
	HXAudioHookInfo* h = 0;
	CHXMapPtrToPtr::Iterator lIter = m_PreMixHookMap.Begin();
	for (; lIter != m_PreMixHookMap.End(); ++lIter)
	{
	    h = (HXAudioHookInfo*) (*lIter);
	    if (h->bIgnoreAudioData ||
		HXR_OK == ProcessAudioHook(ACTION_CHECK, h->pHook))
	    {
		h->pHook->OnInit( &m_AudioFmt );
	    }
	}
    }
#endif /* HELIX_FEATURE_AUDIO_PREMIXHOOK */

    m_bHooksInitialized = TRUE;
}

/************************************************************************
 *  Method:
 *		IHXAudioStream::ProcessHooks
 *	Purpose:
 */
HX_RESULT CHXAudioStream::ProcessHooks
( 
    HXAudioData*	pInData,
    HXAudioData*	pOutData
)
{
    HX_RESULT theErr = HXR_OK;

#if defined(HELIX_FEATURE_AUDIO_PREMIXHOOK)
    m_pInDataPtr->pData		= pInData->pData;
    m_pInDataPtr->pData->AddRef();
    m_pInDataPtr->ulAudioTime	= pInData->ulAudioTime;
    
    m_pOutDataPtr->pData	= NULL;
    m_pOutDataPtr->ulAudioTime	= pInData->ulAudioTime;

    m_pInDataPtr->uAudioStreamType    = pInData->uAudioStreamType;
    m_pOutDataPtr->uAudioStreamType   = pInData->uAudioStreamType;

    if ( m_PreMixHookMap.GetCount() > 0 )
    {
	HXAudioHookInfo* pPreMixHookInfo = 0;
	CHXMapPtrToPtr::Iterator lIter = m_PreMixHookMap.Begin();
	for (; !theErr && lIter != m_PreMixHookMap.End(); ++lIter)
	{
	    pPreMixHookInfo = (HXAudioHookInfo*) (*lIter);

	    if (HXR_OK == ProcessAudioHook(ACTION_CHECK, pPreMixHookInfo->pHook))
	    {
                // XXXHP, disable hooks when it doesn't support multi-channel
                if (m_AudioFmt.uChannels <= 2 || pPreMixHookInfo->bMultiChannelSupport)
                {
		    theErr = pPreMixHookInfo->pHook->OnBuffer( m_pInDataPtr, m_pOutDataPtr);

		    /* Check to see if renderer changed the buffer. If so, then
		     * make this output as input to the next Hook.
		     */
		    if (!theErr && m_pOutDataPtr->pData)
		    {
		        m_pInDataPtr->pData->Release();
		        m_pInDataPtr->pData	    = m_pOutDataPtr->pData;
		        m_pInDataPtr->ulAudioTime   = m_pOutDataPtr->ulAudioTime;

		        m_pOutDataPtr->pData	= 0;
		    }
                }
	    }
	    else if (pPreMixHookInfo->bIgnoreAudioData)
	    {
		IHXBuffer* pTempBuf = m_pInDataPtr->pData;
		m_pInDataPtr->pData = NULL;
		theErr = pPreMixHookInfo->pHook->OnBuffer( m_pInDataPtr, m_pOutDataPtr);
		m_pInDataPtr->pData = pTempBuf;
	    }
	}
    }

    /* Final output is always in InDataPtr*/
    pOutData->pData		= m_pInDataPtr->pData;
    pOutData->ulAudioTime	= m_pInDataPtr->ulAudioTime;

    pOutData->uAudioStreamType  = m_pInDataPtr->uAudioStreamType;
#endif /* HELIX_FEATURE_AUDIO_PREMIXHOOK */

    return theErr;
}

/************************************************************************
 *  Method:
 *	CHXAudioStream::MixIntoBuffer
 *  Purpose:
 *	Mix stream data into this pPlayerBuf.
 *
 */
HX_RESULT CHXAudioStream::MixIntoBuffer
(
    UCHAR*   pPlayerBuf,
    ULONG32  ulBufSize,
    ULONG32& ulBufTime,
    BOOL&    bIsMixBufferDirty,
    BOOL     bGetCrossFadeData
)
{
    HX_RESULT res = HXR_OK ;

    if (!m_bInited)
    {
	return HXR_NOT_INITIALIZED;
    }

    // bGetCrossFadeData should now be a thing of the past.
    HX_ASSERT(!bGetCrossFadeData) ;

//{FILE* f1 = ::fopen("c:\\temp\\rasync.txt", "a+"); ::fprintf(f1, "Call MixIntoBuffer: %lu\n", m_ulLastWriteTime);::fclose(f1);}
    /* If this is a *FROM* stream, we may have already mixed
     * data during cross-fade with *TO* stream
     */

    // update the outside world's sense of time.
    // XXX wschildbach: how to account for rollover?
    INT64 llNextMixTime = m_pMixEngine->GetNextMixTimeMillis();
    UINT32 ulLastWriteTime = INT64_TO_UINT32(llNextMixTime - CAST_TO_INT64(m_ulTSRollOver) * CAST_TO_INT64(MAX_UINT32));

    // In a surestream situation, ulBufTime is 0 on the first stream, and a time corresponding
    // to the granularity in the second stream. I don't know what this code tries to do.
    // XXX wschildbach
    if (ulBufTime < ulLastWriteTime)
    {
	ulBufTime = ulLastWriteTime;
    }

    /* If there are any DryNotifications and the data list is empty
     * we need to notify them so that they can write more data.
     *
     * If EnoughDataAvailable() returns FALSE, it will have updated
     * the input values to point at where the buffer needs to be filled.
     */

    INT64  llStartMix, llEndMix;

    m_pMixEngine->GetMixRange(ulBufSize, llStartMix, llEndMix) ;
    UINT32 nSamplesNeeded = INT64_TO_UINT32(llEndMix - llStartMix) ; // always fits into UINT32

    if (!EnoughDataAvailable(llStartMix, nSamplesNeeded))
    {
        // Check if the audio device is really empty ("ReallyNeedData") or if we are
        // just over-eagerly filling up the pre-roll. If the latter is the case,
        // return HXR_WOULD_BLOCK
	if (!bIsMixBufferDirty && !m_Owner->m_Owner->ReallyNeedData())
	{
	    return HXR_WOULD_BLOCK;
	}

        // renderer might pause playback if has no packets
	if (m_DryNotificationMap->GetCount() > 0)
	{
	    IHXDryNotification* pDryNotification = 0;
	    CHXMapPtrToPtr::Iterator lIter = m_DryNotificationMap->Begin();
	    for (; lIter != m_DryNotificationMap->End(); ++lIter)
	    {
		pDryNotification = (IHXDryNotification*) (*lIter);
                UINT64 streamTime = Samples2Ms(llStartMix, &m_AudioFmt) -
                    CAST_TO_INT64(m_ulTSRollOver)*CAST_TO_INT64(MAX_UINT32);
		HX_RESULT theErr = pDryNotification->OnDryNotification( INT64_TO_UINT32(streamTime),
                                                     INT64_TO_UINT32(Samples2Ms(nSamplesNeeded, &m_AudioFmt))) ;
                if( theErr == HXR_OUTOFMEMORY )
                {
                    return theErr;
                }
	    }

	    if (m_Owner->GetState() != E_PLAYING)
	    {
		return HXR_OK;
	    }
	}
    }

    // XXX wschildbach what does this do?
    m_Owner->DataInAudioDevice(TRUE);

    /*
    {FILE *f1 = fopen("c:\\temp\\mix.txt","a+");
     fprintf(f1,"\ncall MixIntoBuffer(%I64d, id=%ld)\n",(INT64)mixTimeInSamples,m_pMixEngine - (HXAudioSvcMixEngine*)0xdde198);
     fclose(f1);}
*/

    // this call does all the mixing.
    res = m_pMixEngine->MixIntoBuffer(pPlayerBuf, ulBufSize, bIsMixBufferDirty) ;
    if( m_wLastError == HXR_OUTOFMEMORY )
    {
        return m_wLastError;
    }
 
    if (FAILED(res))
        return res ; 

#if defined(HELIX_FEATURE_AUDIO_INACCURATESAMPLING)
    if( m_bRealAudioStream )
        MapFudgedTimestamps();
#endif    
    
    // update the inside world's sense of time.
    m_llLastWriteTime = m_pMixEngine->GetNextMixTimeMillis() ;

#if 0
    {FILE *f = fopen("c:\\temp\\incoming.txt","a+");
    fprintf(f,"mix %ld %I64d\n",ulBufTime,m_llLastWriteTime);fclose(f);}
#endif

    return HXR_OK;
}

/*
 * This is the callback function that m_pMixEngine->MixIntoBuffer() will call to read
 * new samples.
 */

BOOL CHXAudioStream::ConvertIntoBuffer(tAudioSample* buffer, UINT32 nSamples, INT64 llStartTimeInSamples)
{
    HXAudioInfo*    pInfo           = 0;
    LISTPOSITION    lp              = 0;
    INT32           nBytesPerSample = m_AudioFmt.uBitsPerSample>>3 ;
    BOOL            didMix          = FALSE ; // set to TRUE if we have packets in this time range
    BOOL            bPacketsAfterRange = FALSE;

    /*
    {FILE *f1 = fopen("c:\\temp\\mix.txt","a+");
     fprintf(f1," ConvertIntoBuffer(%I64d - %I64d, len=%ld)\n",(INT64)llStartTimeInSamples,(INT64)llStartTimeInSamples+nSamples,nSamples);
     fclose(f1);}
     */

    // there are two lists of packets here: timed audio and instantaneous audio.
    // We only look into the list for timed buffers -- Instantaneoue audio is ignored
    // (it never properly worked anyway, so support is discontinued).

    /* remove old packets. Old packets are packets that have an end time that is before
       our current mix time. */
    lp = m_pDataList->GetHeadPosition();
    while( lp )
    {
	LISTPOSITION lastlp = lp;
	pInfo	= (HXAudioInfo*) m_pDataList->GetNext(lp);

	if (pInfo->llEndTimeInSamples < llStartTimeInSamples)
	{
            /*
    {FILE *f1 = fopen("c:\\temp\\mix.txt","a+");
     fprintf(f1,"-- reaping packet (%I64d,%I64d)\n",
         pInfo->llStartTimeInSamples,pInfo->llEndTimeInSamples);
     fclose(f1);}
     */

	    FreeInfo(pInfo);
	    m_pDataList->RemoveAt(lastlp);
            if( m_wLastError == HXR_OUTOFMEMORY )
            {
                return FALSE;
            }
	}
        else // if monotonous and non-overlapping
            break ;
    }

    // now go through the entire list of packets, and look for overlap with the
    // convert buffer. Any packet with overlap will be at least partially converted
    // into the buffer.

    // If packets overlap, one packet will then take precedence over another -- not
    // much we can do about that.

    lp = m_pDataList->GetHeadPosition();
    while( lp )
    {
	pInfo	= (HXAudioInfo*) m_pDataList->GetNext(lp);

	if (pInfo->llStartTimeInSamples < llStartTimeInSamples + nSamples &&
            pInfo->llEndTimeInSamples > llStartTimeInSamples)
        {
            // This packet has some overlap with what we are converting.

            // if this is the first packet to be mixed into this buffer,
            // silence out the entire buffer. This is inefficient, but safe
            if (!didMix)
                CAudioSvcSampleConverter::silence(buffer, nSamples) ;

            didMix = TRUE ;

            INT32 nMixbufferOffset = 0;
            INT32 pastPacketStart = INT64_TO_INT32(llStartTimeInSamples - pInfo->llStartTimeInSamples) ;
            if (pastPacketStart < 0)
            {
                nMixbufferOffset = -pastPacketStart;
                pastPacketStart = 0 ;
            }

            INT32 nn = Bytes2Samples(pInfo->pBuffer->GetSize(), &m_AudioFmt) ;
            INT32 nSamplesToUse = nn - pastPacketStart;
            if (nSamplesToUse > (INT32)(nSamples - nMixbufferOffset))
                nSamplesToUse = nSamples - nMixbufferOffset;

            const unsigned char *cvtin = pInfo->pBuffer->GetBuffer() + pastPacketStart * nBytesPerSample ;
            tAudioSample *cvtout = buffer + nMixbufferOffset ;

            /*
    {FILE *f1 = fopen("c:\\temp\\mix.txt","a+");
     fprintf(f1,"  mix packet (%I64d,%I64d,len=%ld) into buffer(%ld,%ld,len=%ld)\n",
         pInfo->llStartTimeInSamples,pInfo->llEndTimeInSamples,
         nn,
         nMixbufferOffset,nMixbufferOffset+nSamplesToUse,nSamplesToUse);
     fprintf(f1,"  pastPacketStart = %I64d, nMixbufferOffset = %ld\n",
                pastPacketStart,nMixbufferOffset) ;
     fclose(f1);}
*/

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -