多音轨wma格式音频选择音轨问题
在大部分播放器中,包括暴风影音和千千静听等都不能对多语言音轨的wma格式音频进行音轨选择操作。windows media player可以进行音轨选择。
在使用directshow做自己的播放器时,有时会有特殊需求需要选择音轨,但又同时不能用wmplayer时,就需要自己实现音轨选择功能了。
实现方案
dshow的WMASFReader Filter提供了IWMReaderAdvanced, IWMReaderAdvanced2接口,但并未提供SetStreamsSelected等wmfsdk的用于选择音轨的接口,所以,WMASFReader 是用不了了,只能自己写过一个sourcefilter。关于sourceFilter的列子可以参考directshow实务精选里的Appendix_D/FilterQQSource。可以直接在上面改,然后在里面使用WMFormat的IWMReaderAdvanced接口来进行wma文件的读取和音轨的选择。关于使用wmformat读取文件可以参考sdk里的sample,也可参考
如有改进建议或意见,或有应用需求,请联系QQ:22154912
HRESULT CASFOutPin::FillBuffer(IMediaSample * pSample)
{
//=================================================================
if (g_pWMReader->mIsEOF)//&&g_pWMReader->m_nUsedBufferCount<1)
{
return S_FALSE;
}
// CAutoLock lock(&mSharedState);
// lock(&mSharedState);
if (m_bChangeStart)
{
Sleep(30);
// while (g_pWMReader->m_nUsedBufferCount<2)
// {
// Sleep(5);
// }
m_bChangeStart = FALSE;
}
while (g_pWMReader->m_nUsedBufferCount<1)
{
Sleep(5);
continue;
}
WriteLog("FillBuffer/n");
CheckPointer(pSample,E_POINTER);
// ASSERT(m_Ball);
BYTE *pData;
long lDataLen;
pSample->GetPointer(&pData);//得到Sample的地址指针
lDataLen = pSample->GetSize();//得到Sample的大小
ZeroMemory(pData, lDataLen);//清零
{
// CAutoLock cAutoLockShared(&m_cSharedState);
CopyMemory(pData,g_pWMReader->m_pBufferNodeFillBuffer->pBuffer, g_pWMReader->m_pBufferNodeFillBuffer->nBufferLen);
ZeroMemory(g_pWMReader->m_pSampleData,g_pWMReader->m_pBufferNodeFillBuffer->nBufferLen);
// The current time is the sample's start
CRefTime rtStart,rtSampleTime;// = m_rtSampleTime;
rtStart = g_pWMReader->m_pBufferNodeFillBuffer->nSampleTime-m_rtStart;
rtSampleTime = g_pWMReader->m_pBufferNodeFillBuffer->nSampleTime+(long)((float)lDataLen/176400*10000000);//这个数只是针对44.1kHz16bit的数值。
// Increment to find the finish time
pSample->SetActualDataLength(g_pWMReader->m_pBufferNodeFillBuffer->nBufferLen);
pSample->SetTime((REFERENCE_TIME *) &rtStart,(REFERENCE_TIME *) &rtSampleTime);//(REFERENCE_TIME *) &m_rtSampleTime);
g_pWMReader->m_pBufferNodeFillBuffer = g_pWMReader->m_pBufferNodeFillBuffer->pNext;
g_pWMReader->m_nUsedBufferCount--;
g_pWMReader->Resume();
}
//=================================================================
pSample->SetSyncPoint(TRUE);
return NOERROR;
}
HRESULT CWMReader::OnSample( /* [in] */ DWORD dwOutputNum,
/* [in] */ QWORD cnsSampleTime,
/* [in] */ QWORD cnsSampleDuration,
/* [in] */ DWORD dwFlags,
/* [in] */ INSSBuffer __RPC_FAR *pSample,
/* [in] */ void __RPC_FAR *pvContext )
{
#ifdef _DEBUG
DWORD threadId = GetCurrentThreadId();
#endif
// Check the output number of the sample against the stored output number.
// Because only the first audio output is stored, all other outputs,
// regardless of type, will be ignored.
if (dwOutputNum != mOutputNum)
{
WriteLog("dwOutputNum != mOutputNum/n");
return S_OK;
}
BYTE *pData = NULL;
DWORD cbData = 0;
// Get the sample from the buffer object.
HRESULT hr = pSample->GetBufferAndLength(&pData, &cbData);
if (FAILED(hr))
{
return hr;
}
mTimeElapsed = cnsSampleTime;
//================================================================
g_Time2=cnsSampleTime;
while (m_nUsedBufferCount>2)
{
Sleep(5);
continue;
}
if (m_pSampleData == NULL)
{
m_pSampleData = ( BYTE * )new BYTE[ BUFFERSIZE ];
}
CopyMemory(m_pBufferNodeOnSample->pBuffer, pData, cbData);
WriteLog("CopyMemory(m_pBufferNodeOnSample->pBuffer, pData, cbData);/n");
m_pBufferNodeOnSample->nBufferLen = cbData;
m_pBufferNodeOnSample->nSampleTime = cnsSampleTime;
m_pBufferNodeOnSample = m_pBufferNodeOnSample->pNext;
m_nUsedBufferCount++;
if (m_nUsedBufferCount>2)
{
Pause();
}
CopyMemory(m_pSampleData,pData,cbData);
WriteLog("CopyMemory(m_pSampleData,pData,cbData);/n");
if( FAILED( hr ) )
{
return( hr );
}
// BOOL ret = mPlayer->Play(pData, cbData, cnsSampleTime);
return(S_OK);// ret ? S_OK : E_FAIL;
//==============================================================
}