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

📄 audrend.cpp

📁 著名的 helix realplayer 基于手机 symbian 系统的 播放器全套源代码
💻 CPP
📖 第 1 页 / 共 3 页
字号:
    {
	retVal = m_pAudioStats->DisplayStats(m_ulRegistryID);
    }

    return retVal;
#else
    return HXR_NOTIMPL;
#endif /* HELIX_FEATURE_STATS */
}


/****************************************************************************
 *  Renderer's customizable fuctions - can be called any time
 */
/****************************************************************************
 *  GetStreamVersion
 */
void CAudioRenderer::GetStreamVersion(ULONG32 &ulThisMajorVersion,
					      ULONG32 &ulThisMinorVersion)
{
    ulThisMajorVersion = STREAM_MAJOR_VERSION;
    ulThisMinorVersion = STREAM_MINOR_VERSION;
}

/****************************************************************************
 *  GetContentVersion
 */
void CAudioRenderer::GetContentVersion(ULONG32 &ulThisMajorVersion,
					       ULONG32 &ulThisMinorVersion)
{
    ulThisMajorVersion = CONTENT_MAJOR_VERSION;
    ulThisMinorVersion = CONTENT_MINOR_VERSION;
}

/****************************************************************************
 *  GetUpgradeMimeType
 */
const char* CAudioRenderer::GetUpgradeMimeType(void)
{
    const char** pStreamMimeTypes = NULL;
    UINT32 ulInitialGranularity;

    GetRendererInfo(pStreamMimeTypes, ulInitialGranularity);

    if (pStreamMimeTypes)
    {
	return pStreamMimeTypes[0];
    }

    return NULL;
}

/****************************************************************************
 *  GetRendererName
 */
const char* CAudioRenderer::GetRendererName(void)
{
    return BASE_AUDIO_RENDERER_NAME;
}

/****************************************************************************
 *  GetCodecName
 */
const char* CAudioRenderer::GetCodecName(void)
{
    return NULL;
}

/****************************************************************************
 *  GetCoGetCodecFourCCdec4CC
 */
const char* CAudioRenderer::GetCodecFourCC(void)
{
    return NULL;
}


/****************************************************************************
 *  CreateFormatObject
 */
CAudioFormat* CAudioRenderer::CreateFormatObject(IHXValues* pHeader)
{
    return new CAudioFormat(m_pCommonClassFactory,
			    this);
}


/////////////////////////////////////////////////////////////////////////////
//  Method:
//	CAudioRenderer::InitAudioStream
HX_RESULT CAudioRenderer::InitAudioStream(IHXValues* pHeader,
					  IHXAudioStream** ppAudioStream)
{
    HX_RESULT retVal = HXR_OK;

    // init so we can HX_RELEASE on error.
    *ppAudioStream = NULL;

    retVal = m_pAudioPlayer->CreateAudioStream(ppAudioStream);
    if (SUCCEEDED(retVal))
    {
	IHXCommonClassFactory* pCommonClassFactory;
	if (HXR_OK == (*ppAudioStream)->QueryInterface(IID_IHXCommonClassFactory,
			    (void**)&pCommonClassFactory))
	{
	    m_pAudioFormat->OverrideFactory(pCommonClassFactory);
	    pCommonClassFactory->Release();
	}

	HXAudioFormat audioFmt;

	m_pAudioFormat->GetAudioFormat(audioFmt);

#if defined(HELIX_FEATURE_STATS)
	ReportStat(AS_CHANNELS, (INT32) audioFmt.uChannels);
	ReportStat(AS_SAMPLING_RATE, (INT32) audioFmt.ulSamplesPerSec);
	ReportStat(AS_SAMPLE_SIZE, (INT32) audioFmt.uBitsPerSample);
#endif /* #if defined(HELIX_FEATURE_STATS) */

	/* Add default dry notification BEFORE initializing the audio
	 * stream. This is so that if we are started mid presentation
	 * and there was no audio present earlier, the timeline will
	 * change from being a fake timeline to audio timeline and
	 * the audio services will write audio for initial pushdown
	 * time. We need to get dry notifications so that we can halt
	 * the timeline, if the renderer does not have enough data.
	 */
	IHXDryNotification* pDryNot = NULL;
	// Get my own DryNotification interface with an add
	QueryInterface(IID_IHXDryNotification, (void**)&pDryNot);

	retVal = (*ppAudioStream)->AddDryNotification(pDryNot);

	HX_ASSERT(SUCCEEDED(retVal));

        MLOG_MISC(m_pErrorMessages, "AS Init (%u,%u,%lu,%u)\n",
                  audioFmt.uChannels, audioFmt.uBitsPerSample,
                  audioFmt.ulSamplesPerSec, audioFmt.uMaxBlockSize);

	retVal = (*ppAudioStream)->Init(&audioFmt, pHeader);

	HX_RELEASE(pDryNot);
    }

    if (HXR_OK != retVal)
    {
	HX_RELEASE((*ppAudioStream));
    }

    return retVal;
}

/////////////////////////////////////////////////////////////////////////////
//  Method:
//	CAudioRenderer::WriteToAudioServices
HX_RESULT CAudioRenderer::WriteToAudioServices(HXAudioData* pAudioData)
{
    HX_RESULT pnr = HXR_OK;
    BOOL bTryWrite = TRUE;

    // Can the audio stream change on the fly?
    // If so, then check for any change. If not,
    // then skip the check.
    if (m_bCanChangeAudioStream)
    {
        BOOL bAudioStreamChanged = FALSE;
        pnr = CheckForAudioStreamChange(bAudioStreamChanged);
        if (FAILED(pnr))
        {
            return pnr;
        }
        if (bAudioStreamChanged)
        {
            pAudioData->uAudioStreamType = TIMED_AUDIO;
        }
    }

    while (bTryWrite)
    {
	pnr = CheckAudioServices();
        if (FAILED(pnr))
        {
            return pnr;
        }

        MLOG_MISC(m_pErrorMessages, "AS Write (%lu,%lu,%lu) ms=%lu tick=%lu\n",
                  (pAudioData->pData ? pAudioData->pData->GetSize() : 0),
                  pAudioData->ulAudioTime,
                  pAudioData->uAudioStreamType,
                  m_pAudioFormat->ConvertBytesToMs((pAudioData->pData ? pAudioData->pData->GetSize() : 0)),
                  HX_GET_BETTERTICKCOUNT());

	DEBUG_OUTF_IDX(m_ulCurAudioStream, AUDREND_FLOW_FILE, 
		       (s, "Audio Write: Time=%u, Bytes=%u, Duration=%u, %s\n",
			    pAudioData->ulAudioTime,
			    (pAudioData->pData ? pAudioData->pData->GetSize() : 0),
			    m_pAudioFormat->ConvertBytesToMs((pAudioData->pData ? pAudioData->pData->GetSize() : 0)),
			    ((pAudioData->uAudioStreamType == STREAMING_AUDIO) ? "STREAMING" : "TIMED")
			    ));

        // Write to AS
        if (m_ppAudioStream[m_ulCurAudioStream])
            pnr = m_ppAudioStream[m_ulCurAudioStream]->Write( pAudioData );

	if (SUCCEEDED(pnr))
	{
	    CalculateMaxTimeStamp(pAudioData);
	    bTryWrite = FALSE;
	}
	else
	{
	    // we got an error on write, check what time the audio stream
	    // expects data for
	    HXAudioData audioData;
	    audioData.pData = NULL;

            if (m_ppAudioStream[m_ulCurAudioStream])
                m_ppAudioStream[m_ulCurAudioStream]->Write( &audioData );

	    if (IsTimeLess(audioData.ulAudioTime, pAudioData->ulAudioTime))
	    {
		// we are skipping ahead and should just mark this packet
		// as timed and write it again
		pAudioData->uAudioStreamType = TIMED_AUDIO;

	    }
	    else if (IsTimeGreater(audioData.ulAudioTime, pAudioData->ulAudioTime) &&
		IsTimeLessOrEqual(audioData.ulAudioTime, pAudioData->ulAudioTime +
		m_pAudioFormat->ConvertBytesToMs(pAudioData->pData->GetSize())))
	    {
		// we are a little behind but at least part of this stream
		// is on time, we should clip off this buffer to the time
		// the audio stream wants and try again.
		bTryWrite = m_pAudioFormat->ClipAudioBuffer(pAudioData,
		    audioData.ulAudioTime, TRUE);
	    }
	    else
	    {
		// we are a lot behind and should tell this format to discard
		// data until the audio stream time.
		m_pAudioFormat->
		    DiscardAudioUntil(audioData.ulAudioTime);

		// we don't want to try again with this data
		bTryWrite = FALSE;
	    }
	}
    }

    // Handle exiting rebuffer started by OnDryNotification from
    // Audio Services
    // if we just wrote audio to audio services that is greater than
    // or equal to the audio wanted time from the dry notification
    // call then we can leave buffering
    
    if (IsRebuffering() &&
        IsTimeGreaterOrEqual(m_ulLastWriteTime, m_ulAudioWantedTime))
    {
        EndRebuffer();
    }

    return pnr;
}

/////////////////////////////////////////////////////////////////////////////
//  Method:
//	CAudioRenderer::DoAudio
//
//  Note:  See Switchsod.txt for how this is supposed to work, please keep
//	the sod up to date with changes here too.
//
HX_RESULT CAudioRenderer::DoAudio(UINT32& ulAudioTime,
				  AUDIO_STATE audioState)
{
    HX_RESULT retVal;
    HXAudioData audioData;
    ULONG32 ulPreviousLastWriteTime;
    LONG32 lTimeDelta;

    audioData.pData = NULL;
    audioData.ulAudioTime = ulAudioTime = 0;

    // write the lowest stream to audio services
    ulPreviousLastWriteTime = m_ulLastWriteTime;

    do
    {
	retVal = m_pAudioFormat->CreateAudioFrame(
	    audioData,
	    (m_bEndOfPackets) ? AUDIO_END_OF_PACKETS : audioState);

	if (retVal == HXR_OK)
	{
	    audioData.uAudioStreamType = TIMED_AUDIO;

        // Update the timestamp of the audio services write
        audioData.ulAudioTime = AdjustTimestamp(audioData.ulAudioTime, m_lTimeOffset);

	    if (m_ulLastWriteTime != NO_TIME_SET)
	    {
		lTimeDelta = audioData.ulAudioTime -
			     m_ulLastWriteTime;

		HX_ASSERT(lTimeDelta >= (-TIME_FUDGE));

		if (lTimeDelta <= TIME_FUDGE)
		{
		    audioData.uAudioStreamType = STREAMING_AUDIO;
		}
#ifdef _AUDREND_FLOW_LOG
		else if (lTimeDelta < (-TIME_FUDGE))
		{
		    DEBUG_OUTF_IDX(m_ulCurAudioStream, AUDREND_FLOW_FILE, 
		       (s, "Overlapping Audio: Time=%u, LastWriteTime=%u, Overlap=%d\n",
			    audioData.ulAudioTime,
			    m_ulLastWriteTime,
			    -lTimeDelta
			    ));
		}
#endif	// _AUDREND_FLOW_LOG
	    }

	    retVal = WriteToAudioServices(&audioData);
	}
	else
	{
	    break;
	}
                               // do not loop here if writing to
                               // satisfy dry notification
     } while (audioState != AUDIO_DRYNOTIFICATION &&
            ((m_ulLastWriteTime - ulPreviousLastWriteTime) <
	     MAX_AUDIO_WRITE_TIME));

    // release the data buffer if we got one
    HX_RELEASE(audioData.pData);

    // update the out param
    ulAudioTime = audioData.ulAudioTime;

    return retVal;
}

HX_RESULT CAudioRenderer::AttemptToSatisfyDryRequest(UINT32 ulAudioWantedTime)
{
    HX_RESULT pnr = HXR_OK;
    UINT32 ulAudioTime = 0;

    while (HXR_OK == pnr &&
	IsTimeGreaterOrEqual(ulAudioWantedTime, m_ulLastWriteTime))
    {
	pnr = DoAudio(ulAudioTime, AUDIO_DRYNOTIFICATION);
    }

    return pnr;
}

void
CAudioRenderer::CalculateMaxTimeStamp(HXAudioData* pAudioData)
{
    UINT32 ulTimestamp = pAudioData->ulAudioTime +
	m_pAudioFormat->ConvertBytesToMs(pAudioData->pData->GetSize());

    if (m_ulLastWriteTime == NO_TIME_SET ||
	IsTimeLess(m_ulLastWriteTime, ulTimestamp))
    {
	m_ulLastWriteTime = ulTimestamp;
    }
}

HX_RESULT CAudioRenderer::CheckForAudioStreamChange(REF(BOOL) rbAudioStreamChanged)
{
    HX_RESULT retVal = HXR_FAIL;

    if (m_pAudioFormat)
    {
	retVal = HXR_OK;

	// Check to see if the audio format has changed
	if (HasAudioFormatChanged())
	{
	    // Transfer the current audio stream to
	    // a newly created audio stream
	    retVal = IncrementAudioStream();
	    rbAudioStreamChanged = SUCCEEDED(retVal);
	}
    }

    return retVal;
}

BOOL CAudioRenderer::HasAudioFormatChanged()
{
    BOOL bRet = FALSE;

    if (m_pAudioFormat)
    {
        // Get the audio format from the CAudioFormat object
        HXAudioFormat cAudioFormat1;
        HX_RESULT retVal = m_pAudioFormat->GetAudioFormat(cAudioFormat1);
        if (SUCCEEDED(retVal))
        {
            // Get the audio format from the current IHXAudioStream object
            if (m_ppAudioStream &&
                m_ulCurAudioStream < m_ulNumAudioStreams &&
                m_ppAudioStream[m_ulCurAudioStream])
            {
                IHXAudioStream2* pStream2 = NULL;
                retVal = m_ppAudioStream[m_ulCurAudioStream]->QueryInterface(IID_IHXAudioStream2,
                                                                             (void**) &pStream2);
                if (SUCCEEDED(retVal))
                {
                    HXAudioFormat cAudioFormat2;
                    retVal = pStream2->GetAudioFormat(&cAudioFormat2);
                    if (SUCCEEDED(retVal))
                    {
                        // Check if the formats are different
                        if (cAudioFormat1.uChannels       != cAudioFormat2.uChannels       ||
                            cAudioFormat1.uBitsPerSample  != cAudioFormat2.uBitsPerSample  ||
                            cAudioFormat1.ulSamplesPerSec != cAudioFormat2.ulSamplesPerSec ||
                            cAudioFormat1.uMaxBlockSize    > cAudioFormat2.uMaxBlockSize)
                        {
                            bRet = TRUE;
                        }
                    }
                }
                HX_RELEASE(pStream2);
            }
        }
    }

    return bRet;
}

HX_RESULT CAudioRenderer::IncrementAudioStream()
{
    HX_RESULT retVal = HXR_FAIL;

    if (m_ulCurAudioStream + 1 >= m_ulNumAudioStreams)
    {
        // We need to create a larger buffer to hold the
        // audio stream pointers
        UINT32 ulNewSize = m_ulNumAudioStreams * 2;
        IHXAudioStream** ppAudioStream = new IHXAudioStream* [ulNewSize];
        if (ppAudioStream)
        {
            // NULL out the buffer
            memset((void*) ppAudioStream, 0, ulNewSize * sizeof(IHXAudioStream*));
            // Copy the current pointers
            memcpy((void*) ppAudioStream, /* Flawfinder: ignore */
                   (const void*) m_ppAudioStream,
                   m_ulNumAudioStreams * sizeof(IHXAudioStream*));
            // Delete the old array
            HX_VECTOR_DELETE(m_ppAudioStream);
            // Assign the new one
            m_ppAudioStream = ppAudioStream;
            // Assign the new size
            m_ulNumAudioStreams = ulNewSize;
        }
    }
    if (m_ulCurAudioStream + 1 < m_ulNumAudioStreams)
    {
        // Remove the dry notification from the old stream
        if (m_ppAudioStream[m_ulCurAudioStream])
        {
            IHXAudioStream2* pStream2 = NULL;
            m_ppAudioStream[m_ulCurAudioStream]->QueryInterface(IID_IHXAudioStream2,
                                                                (void**) &pStream2);
            if (pStream2)
            {
                // Get our own IHXDryNotification interface
                IHXDryNotification* pDryNot = NULL;
                QueryInterface(IID_IHXDryNotification, (void**) &pDryNot);
                if (pDryNot)
                {
                    pStream2->RemoveDryNotification(pDryNot);
                }
                HX_RELEASE(pDryNot);
            }
            HX_RELEASE(pStream2);
        }
        // Init the new stream
        retVal = InitAudioStream(m_pHeader, &m_ppAudioStream[m_ulCurAudioStream + 1]);
        if (SUCCEEDED(retVal))
        {
            // Increment the current audio stream index
            m_ulCurAudioStream += 1;
        }
    }

    return retVal;
}

BOOL CAudioRenderer::IsRebuffering() const
{
    return (NO_TIME_SET != m_ulAudioWantedTime) ? TRUE : FALSE;
}

void CAudioRenderer::StartRebuffer(UINT32 ulAudioWantedTime)
{
    if (m_pStream)
    {
        m_ulAudioWantedTime = ulAudioWantedTime;
        m_pStream->ReportRebufferStatus(1,0);
    }
}

void CAudioRenderer::EndRebuffer()
{
    m_ulAudioWantedTime = NO_TIME_SET;

    if (m_pStream)
    {
        m_pStream->ReportRebufferStatus(1,1);
    }
}

⌨️ 快捷键说明

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