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

📄 hxaudstr_new.cpp

📁 著名的 helix realplayer 基于手机 symbian 系统的 播放器全套源代码
💻 CPP
📖 第 1 页 / 共 5 页
字号:
            switch (nBytesPerSample)
            {
            case 1:
                CAudioSvcSampleConverter::cvt8(cvtin, cvtout, nSamplesToUse);
                break ;
            case 2:
                CAudioSvcSampleConverter::cvt16(cvtin, cvtout, nSamplesToUse);
                break ;
            case 4:
                CAudioSvcSampleConverter::cvt32(cvtin, cvtout, nSamplesToUse);
                break ;
            }
        }
	else if (pInfo->llStartTimeInSamples >= llStartTimeInSamples + nSamples)
	{
	    /* We've found audio data that is past the
	     * desired range.
	     */
	    bPacketsAfterRange = TRUE;
	}
    }

    if (!didMix && bPacketsAfterRange)
    {
	/* We do not have packets for this range, but we
	 * do have packets after the range.
	 * Create silence data and make it look like we
	 * actually had data for this range.
	 */
	CAudioSvcSampleConverter::silence(buffer, nSamples) ;
	didMix = TRUE;
    }

    return didMix ;
}





/************************************************************************
 *  Method:
 *              CHXAudioStream::Bytes2Samples
 *      Purpose:
 *		Translate from units of bytes to samples.
 */
UINT32 CHXAudioStream::Bytes2Samples 
(
    UINT64	ulNumBytes,
    const HXAudioFormat *fmt 
)
{
    ASSERT(ulNumBytes % (fmt->uBitsPerSample >> 3) == 0) ;
    return INT64_TO_UINT32(ulNumBytes / (fmt->uBitsPerSample >> 3)) ;
}

/************************************************************************
 *  Method:
 *              CHXAudioStream::Samples2Ms
 *      Purpose:
 *		Calculate the duration in millisecs for this number of samples.
 */
UINT64 CHXAudioStream::Samples2Ms
(
    INT64 nSamples,
    const HXAudioFormat *fmt
)
{
    UINT32 ulDenom = fmt->uChannels * fmt->ulSamplesPerSec;
    UINT64 q = nSamples / ulDenom;
    UINT64 r = nSamples - q * ulDenom;

    return q * 1000 + (r * 1000) / ulDenom;
}


/************************************************************************
 *  Method:
 *              CHXAudioStream::CalcMs
 *      Purpose:
 *		Calculate the duration in millisecs for this number of
 *              bytes in input format.
 */
ULONG32 CHXAudioStream::CalcMs
(
    ULONG32	ulNumBytes
)
{
    return INT64_TO_ULONG32(Samples2Ms(Bytes2Samples(ulNumBytes, &m_AudioFmt), &m_AudioFmt));
}

/************************************************************************
 *  Method:
 *              CHXAudioStream::CalcDeviceMs
 *      Purpose:
 *		Calculate the duration in millisecs for this number of 
 *		bytes in Device format.
 */
ULONG32 CHXAudioStream::CalcDeviceMs
(
    ULONG32	ulNumBytes
)
{
    return INT64_TO_ULONG32(Samples2Ms(Bytes2Samples(ulNumBytes, &m_DeviceFmt), &m_DeviceFmt));
}

/************************************************************************
 *  Method:
 *              CHXAudioStream::CalcOffset
 *      Purpose:
 *		Calculate the offset in bytes given time.
 */
UINT32 CHXAudioStream::CalcOffset
(
    INT64 llStartTime
,   INT64 llEndTime
)
{
    /* Using m_ulBytesPerMs may introduce cumulative error due 
     * to decimal cutoff 
     */
    HX_ASSERT(llEndTime - llStartTime < MAX_TIMESTAMP_GAP);

    return m_ulGranularity ?
        INT64_TO_UINT32((llEndTime - llStartTime) * m_ulInputBytesPerGran / m_ulGranularity) :
        0 ;
}


void CHXAudioStream::FlushBuffers(BOOL bInstantaneousAlso)
{
    while (m_pDataList && m_pDataList->GetCount() > 0)
    {
	HXAudioInfo* pInfo = (HXAudioInfo*) m_pDataList->RemoveHead();
	FreeInfo(pInfo);
    }

    while (bInstantaneousAlso && m_pInstantaneousList && m_pInstantaneousList->GetCount() > 0)
    {
	CHXSimpleList* pList = (CHXSimpleList*) m_pInstantaneousList->RemoveHead();
	while (pList->GetCount() > 0)
	{
	    HXAudioInfo* pInfo = (HXAudioInfo*) pList->RemoveHead();
	    FreeInfo(pInfo, TRUE);
	}

	HX_DELETE(pList);
    }

    // reset m_bLastNMilliSecsToBeSaved so that we actually 
    // delete buffers in FreeInfo
    BOOL bLastNMilliSecsToBeSaved = m_bLastNMilliSecsToBeSaved;
    m_bLastNMilliSecsToBeSaved = FALSE;

    while (m_pLastNMilliSecsList && m_pLastNMilliSecsList->GetCount() > 0)
    {
	HXAudioInfo* pInfo = (HXAudioInfo*) m_pLastNMilliSecsList->RemoveHead();
	FreeInfo(pInfo);
    }

    m_bLastNMilliSecsToBeSaved = bLastNMilliSecsToBeSaved;

    HX_DELETE(m_pLastNMilliSecsList);
}

/*
    this routine checks if there are enough packets waiting in the queue
    to be mixed. It will return FALSE if not, or if there are packets missing
    in the middle of the queue.
*/

BOOL
CHXAudioStream::EnoughDataAvailable(INT64& llStartTimeInSamples, UINT32& nSamplesRequired)
{
    INT64           llEndTimeInSamples   = llStartTimeInSamples + nSamplesRequired ;

    HXAudioInfo*    pInfoOld        = 0 ;
    HXAudioInfo*    pInfo           = 0;
    LISTPOSITION    lp              = 0;

    // if the list is completely empty, report the whole data range as missing
    if (m_pDataList->IsEmpty())
	return FALSE ;

    nSamplesRequired = 0 ;

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

	if (pInfoOld->llEndTimeInSamples >= llStartTimeInSamples)
            break ;
    }

#if 0 // disabled missing packet detection
    // pInfoOld is the first packet to be mixed. To make sure it overlaps with the start
    // of the mix buffer, do this (disabled for now):
    
    if (pInfoOld->llStartTimeInSamples > llStartTimeInSamples)
        return FALSE ;
#endif    

    // now go through the rest of packets, and make sure they are contiguous until
    // the end of our mix time

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

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

        // if we see a packet with a timestamp after the mix time ("future packet")
        // or one that does not abut with the previous one ("discontinuity"), stop.
        if (pInfo->llStartTimeInSamples >= llEndTimeInSamples)         // future packet
//            pInfo->llStartTimeInSamples != pInfoOld->llEndTimeInSamples) // discontinuity
        {
            break ;
        }

        pInfoOld = pInfo ;
    }

    // pInfoOld is the last packet to be mixed (or the last before a discontinuity).
    // Make sure it overlaps with the end of the mix buffer.
    if (pInfoOld->llEndTimeInSamples < llEndTimeInSamples)
    {
        llStartTimeInSamples = pInfoOld->llEndTimeInSamples ;
        nSamplesRequired = INT64_TO_UINT32(llEndTimeInSamples - llStartTimeInSamples) ;
        return FALSE ;
    }

    return TRUE ; // Data available!
}


HX_RESULT    
CHXAudioStream::StartCrossFade(CHXAudioStream*  pFromStream, 
			       UINT32		ulCrossFadeStartTime,
			       UINT32		ulCrossFadeDuration, 
			       BOOL		bToStream)
{
#if defined(HELIX_FEATURE_CROSSFADE)
    // XXX wschildbach need to account for rollover.
    INT64 llStartTimeInSamples = CAST_TO_INT64(ulCrossFadeStartTime) * m_DeviceFmt.ulSamplesPerSec / 1000 * m_DeviceFmt.uChannels ;
    INT64 llEndTimeInSamples = (CAST_TO_INT64(ulCrossFadeStartTime)+ulCrossFadeDuration) * m_DeviceFmt.ulSamplesPerSec / 1000 * m_DeviceFmt.uChannels ;

    m_pMixEngine->SetCrossFade(bToStream ? HXAudioSvcMixEngine::FADE_IN : HXAudioSvcMixEngine::FADE_OUT,
        llStartTimeInSamples, llEndTimeInSamples) ;
/*
    {
        FILE *f2 = fopen("c:\\temp\\mix.txt","a+");
        fprintf(f2,"** StartCrossFade(%I64d, %I64d, len=%ld, to=%s\n",
            llStartTimeInSamples,
            llEndTimeInSamples,
            (INT32)(-llStartTimeInSamples+llEndTimeInSamples),
            bToStream?"yes":"no");
        fclose(f2);
    }
*/

    return HXR_OK;
#else
    return HXR_NOTIMPL;
#endif /* HELIX_FEATURE_CROSSFADE */
}

/*
 *  IHXRealAudioSync methods
 */

/************************************************************************
 *  Method:
 *      IHXRealAudioSync::Register
 *  Purpose:
 */
STDMETHODIMP
CHXAudioStream::Register(void) 
{
#if defined _DEBUG && defined HELIX_FEATURE_AUDIO_MULTIPLAYER_PAUSE 
    if (HXDebugOptionEnabled("zDoNotUseFudge"))
    {
        return HXR_OK;
    }
#endif

    if (m_bRealAudioStream)
    {
	return HXR_UNEXPECTED;
    }

    m_bRealAudioStream = TRUE;
    m_Owner->RegisterRealAudioStream(this);

#if defined(HELIX_FEATURE_AUDIO_INACCURATESAMPLING)
    if (!m_pRAByToTsInList)
    {
	m_pRAByToTsInList	= new CHXSimpleList;
	m_pRAByToTsAdjustedList	= new CHXSimpleList;
    }
#endif /* HELIX_FEATURE_AUDIO_INACCURATESAMPLING */

    return HXR_OK;
}

/************************************************************************
 *  Method:
 *      IHXRealAudioSync::UnRegister
 *  Purpose:
 */
STDMETHODIMP
CHXAudioStream::UnRegister(void)
{
#if defined _DEBUG && defined HELIX_FEATURE_AUDIO_MULTIPLAYER_PAUSE 
    if (HXDebugOptionEnabled("zDoNotUseFudge"))
    {
        return HXR_OK;
    }
#endif

    if (!m_bRealAudioStream)
    {
	return HXR_UNEXPECTED;
    }

    m_bRealAudioStream = FALSE;
    m_Owner->UnRegisterRealAudioStream(this);

    CleanupRAByToTs();

    return HXR_OK;
}

/************************************************************************
 *  Method:
 *      IHXRealAudioSync::FudgeTimestamp
 *  Purpose:
 *	Tell the audio stream about the relationship between the number 
 *	of bytes written to the actual timestamp.
 *	    
 */
STDMETHODIMP
CHXAudioStream::FudgeTimestamp(UINT32 /*IN*/ ulNumberofBytes,
			       UINT32 /*IN*/ ulTimestamp)
{
#if defined(HELIX_FEATURE_AUDIO_INACCURATESAMPLING)
#if defined _DEBUG && defined HELIX_FEATURE_AUDIO_MULTIPLAYER_PAUSE 
    if (HXDebugOptionEnabled("zDoNotUseFudge"))
    {
        return HXR_OK;
    }
#endif

    RealAudioBytesToTimeStamp* pByToTs = 
	new RealAudioBytesToTimeStamp;

    pByToTs->m_ulTimestamp	= ulTimestamp;
    pByToTs->m_ulInTimestamp	= m_ulLastInputStartTime;
    pByToTs->m_ulInEndTime	= m_ulLastInputEndTime;

    if (m_bIsLive && m_ulBaseTime > 0)
    {
	pByToTs->m_ulTimestamp	+= m_ulLiveDelay;

	if (pByToTs->m_ulTimestamp > m_ulBaseTime)
	{
	    pByToTs->m_ulTimestamp -= m_ulBaseTime;
	}
	else
	{
	    pByToTs->m_ulTimestamp  = 0;
	}
    }

    pByToTs->m_ulOrigTimestamp	= pByToTs->m_ulTimestamp;

    m_pRAByToTsInList->AddTail((void*) pByToTs);
#endif /* HELIX_FEATURE_AUDIO_INACCURATESAMPLING */

//{FILE* f1 = ::fopen("d:\\temp\\audio.txt", "a+"); ::fprintf(f1, "Fudge:\t%lu\t%lu\n", ulTimestamp, m_ulLastInputStartTime);::fclose(f1);}
    return HXR_OK;
}

void
CHXAudioStream::CleanupRAByToTs(void)
{
#if defined(HELIX_FEATURE_AUDIO_INACCURATESAMPLING)
    if (!m_pRAByToTsInList)
    {
	return;
    }

    CHXSimpleList::Iterator ndx = m_pRAByToTsInList->Begin();
    for (; ndx != m_pRAByToTsInList->End(); ++ndx)
    {
	RealAudioBytesToTimeStamp* pByToTs = 
	    (RealAudioBytesToTimeStamp*) (*ndx);
	delete pByToTs;
    }

    m_pRAByToTsInList->RemoveAll();

    ndx = m_pRAByToTsAdjustedList->Begin();
    for (; ndx != m_pRAByToTsAdjustedList->End(); ++ndx)
    {
	RealAudioBytesToTimeStamp* pByToTs = 
	    (RealAudioBytesToTimeStamp*) (*ndx);
	delete pByToTs;
    }

    m_pRAByToTsAdjustedList->RemoveAll();
#endif /* HELIX_FEATURE_AUDIO_INACCURATESAMPLING */
} 

HX_RESULT
CHXAudioStream::ConvertCurrentTime(double dBytesPlayed, 
				   UINT32 ulCurrentTime, 
				   UINT32& ulAdjustedTime)
{
#if defined(HELIX_FEATURE_AUDIO_INACCURATESAMPLING)
    HX_ASSERT(m_bRealAudioStream);

    ulAdjustedTime  = ulCurrentTime;

    LISTPOSITION posRABytes = m_pRAByToTsAdjustedList->GetHeadPosition();
    RealAudioBytesToTimeStamp* pByToTsLower = NULL;
    RealAudioBytesToTimeStamp* pByToTsHigher = NULL;

    INT64   llActualByToTsHigherTimestamp = 0;
    INT64   llActualByToTsLowerTimestamp =0;

    while(posRABytes)
    

⌨️ 快捷键说明

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