下载由本文代码制作的DLL
本过滤器解析并读取音频文件,将音频解码为未压缩的PCM音频流由输出引脚输出。可以解析的音频文件格式有:aac,m4a,m4r,mp3,wav,wma。
过滤器的参数信息
过滤器名称:读音频文件
过滤器GUID:{9EA694F1-8B08-428D-9718-A353932B7995}
DLL注册函数名:DllRegisterServer
删除注册函数名:DllUnregisterServer
过滤器有1个输出引脚。
输出引脚标识:1
输出引脚媒体类型:
主要类型:MEDIATYPE_Audio
子类型:MEDIASUBTYPE_PCM
格式类型:FORMAT_WaveFormatEx
过滤器开发过程
过滤器从CSource派生,实现了IFileSourceFilter,IMediaSeeking接口。IFileSourceFilter接口用于指定要读取的音频文件。在IFileSourceFilter的Load方法中,创建了一个线程,在线程中创建了一个源读取器,用于获取指定媒体类型为PCM音频时,媒体类型的全部信息。IMediaSeeking接口用于调整播放的当前位置。
引脚从CSourceStream派生。
重写了ThreadProc函数,该函数是引脚的线程函数。在函数中创建了第2个源读取器,并指定源读取器音频流的媒体类型为在IFileSourceFilter的Load方法中获取到的媒体类型。当指定媒体类型成功时,源读取器将实例化解码器。在引脚类中声明了一个BOOL变量B_Pasue,在收到运行,停止,暂停请求时,设定B_Pasue的值。ThreadProc函数的其它代码,从CSourceStream::ThreadProc定义复制而来。
重写了DoBufferProcessingLoop函数,在函数中添加使用B_Pasue变量控制样本的发送代码。
重写了FillBuffer函数。在函数中,从源读取器读取样本,包括样本的显示时间,持续时间,有效数据长度,样本数据;使用这些参数填充引脚样本缓冲区,指定引脚样本各参数。
重写了GetMediaType函数,用于指定引脚的媒体类型。
重写了DecideBufferSize函数,用于确定引脚样本缓冲区的大小。
下面是本过滤器DLL的全部代码
DLL模块定义文件:AudioReader.def
LIBRARY AudioReader.dll
EXPORTS
DllMain PRIVATE
DllGetClassObject PRIVATE
DllCanUnloadNow PRIVATE
DllRegisterServer PRIVATE
DllUnregisterServer PRIVATE
DLL头文件:AudioReader.h
#ifndef DLL_FILE
#define DLL_FILE
#include "streams.h"
#include "initguid.h"
#if _DEBUG
#pragma comment(lib, "Strmbasd.lib")//C:\Program Files\Microsoft SDKs\Windows\v7.1\Samples\multimedia\directshow\baseclasses\Debug\strmbasd.lib
#else
#pragma comment(lib, "Strmbase.lib")//C:\Program Files\Microsoft SDKs\Windows\v7.1\Samples\multimedia\directshow\baseclasses\Release\strmbase.lib
#endif
#pragma comment(lib, "Winmm.lib")//C:\Program Files\Microsoft SDKs\Windows\v7.1\Lib\Winmm.lib
#pragma comment(lib, "msvcrt.lib")//C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\lib\msvcrt.lib
#include "strsafe.h"
#include "mfapi.h"
#include "mfidl.h"
#include "mfreadwrite.h"
#include "mferror.h"
#pragma comment(lib, "mfplat.lib")
#pragma comment(lib, "mfreadwrite.lib")
#pragma comment(lib, "mfuuid.lib")
template <class T> void SafeRelease(T** ppT)
{
if (*ppT)
{
(*ppT)->Release();
*ppT = NULL;
}
}
// {9EA694F1-8B08-428D-9718-A353932B7995}
DEFINE_GUID(CLSID_AudioReader,
0x9ea694f1, 0x8b08, 0x428d, 0x97, 0x18, 0xa3, 0x53, 0x93, 0x2b, 0x79, 0x95);
#endif // DLL_FILE
DLL源文件:AudioReader.cpp
#include "AudioReader.h"
#include "CFilter.h"
const AMOVIESETUP_MEDIATYPE PinTypes =
{
&MEDIATYPE_Audio, // 主要类型
&MEDIASUBTYPE_PCM // 子类型
};
const AMOVIESETUP_PIN PinInfo = // 引脚信息
{
L"Out", //引脚名称
FALSE, //必须渲染输入引脚
TRUE, //输出引脚
FALSE, //具有该引脚的零个实例
FALSE, //可以创建一个以上引脚的实例
&CLSID_NULL, //该引脚连接的过滤器的类标识
NULL, //该引脚连接的引脚名称
1, //引脚支持的媒体类型数
&PinTypes //媒体类型信息
};
const AMOVIESETUP_FILTER FilterInfo = //过滤器的注册信息
{
&CLSID_AudioReader, //过滤器的类标识
L"读音频文件", //过滤器的名称
MERIT_DO_NOT_USE, //过滤器优先值
1, //引脚数量
&PinInfo //引脚信息
};
CFactoryTemplate g_Templates [] = {
{
L"读音频文件"
, &CLSID_AudioReader
, CFilter::CreateInstance
, NULL
, &FilterInfo
}
};
int g_cTemplates = 1;
STDAPI DllRegisterServer()//注册DLL
{
return AMovieDllRegisterServer2(TRUE);
}
STDAPI DllUnregisterServer()//删除DLL注册
{
return AMovieDllRegisterServer2(FALSE);
}
extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);
BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
{
return DllEntryPoint((HINSTANCE)(hModule), dwReason, lpReserved);
}
过滤器头文件:CFilter.h
#ifndef FILTER_FILE
#define FILTER_FILE
#include "AudioReader.h"
#include "CPin.h"
class CFilter : public CSource, public IFileSourceFilter, public IMediaSeeking
{
friend class CPin;
public:
CFilter(LPUNKNOWN pUnk,HRESULT *phr);
~CFilter();
static CUnknown * WINAPI CreateInstance(LPUNKNOWN pUnk, HRESULT *phr);
DECLARE_IUNKNOWN
STDMETHODIMP Load(LPCOLESTR lpwszFileName, const AM_MEDIA_TYPE *pmt);
STDMETHODIMP GetCurFile(LPOLESTR * ppszFileName, AM_MEDIA_TYPE *pmt);
CPin* pCAudioOut;//音频引脚指针
LPWSTR m_pFileName;//要读取的音频文件路径
HANDLE hInit;//“获取信息完成”事件句柄
HANDLE hAReset;//“音频更改播放位置”事件句柄
IMFMediaType* pUncompressedAudioType;
LONGLONG CUR;//音频当前时间,100纳秒单位
LONGLONG DUR;//音频持续时间,100纳秒单位
LONGLONG AResetPos;//音频新位置,100纳秒单位
private:
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv);
public:
HRESULT STDMETHODCALLTYPE CheckCapabilities(DWORD *pCapabilities);
HRESULT STDMETHODCALLTYPE ConvertTimeFormat(LONGLONG *pTarget, const GUID *pTargetFormat, LONGLONG Source, const GUID *pSourceFormat);
HRESULT STDMETHODCALLTYPE GetAvailable(LONGLONG *pEarliest, LONGLONG *pLatest);
HRESULT STDMETHODCALLTYPE GetCapabilities(DWORD *pCapabilities);
HRESULT STDMETHODCALLTYPE GetCurrentPosition(LONGLONG *pCurrent);
HRESULT STDMETHODCALLTYPE GetDuration(LONGLONG *pDuration);
HRESULT STDMETHODCALLTYPE GetPositions(LONGLONG *pCurrent, LONGLONG *pStop);
HRESULT STDMETHODCALLTYPE GetPreroll(LONGLONG *pllPreroll);
HRESULT STDMETHODCALLTYPE GetRate(double *pdRate);
HRESULT STDMETHODCALLTYPE GetStopPosition(LONGLONG *pStop);
HRESULT STDMETHODCALLTYPE GetTimeFormat(GUID *pFormat);
HRESULT STDMETHODCALLTYPE IsFormatSupported(const GUID *pFormat);
HRESULT STDMETHODCALLTYPE IsUsingTimeFormat(const GUID *pFormat);
HRESULT STDMETHODCALLTYPE QueryPreferredFormat(GUID *pFormat);
HRESULT STDMETHODCALLTYPE SetPositions(LONGLONG *pCurrent, DWORD dwCurrentFlags, LONGLONG *pStop, DWORD dwStopFlags);
HRESULT STDMETHODCALLTYPE SetRate(double dRate);
HRESULT STDMETHODCALLTYPE SetTimeFormat(const GUID *pFormat);
};
#endif // FILTER_FILE
过滤器源文件:CFilter.cpp
#include "CFilter.h"
#include "CPin.h"
CFilter::CFilter(LPUNKNOWN lpunk, HRESULT *phr) : CSource(NAME("读音频文件"), lpunk, CLSID_AudioReader)
{
m_paStreams = new CSourceStream*[1];
pCAudioOut=new CPin(phr, this, L"Out");//创建音频引脚
m_paStreams[0]=(CSourceStream*)pCAudioOut;
pUncompressedAudioType = NULL;
DUR=0;//音频持续时间,100纳秒单位
AResetPos=0;
hInit = CreateEvent( NULL, TRUE, FALSE, NULL); //创建事件,为手动重置,初始状态无信号
hAReset = CreateEvent( NULL, FALSE, FALSE, NULL); //创建事件,自动重置,初始状态无信号
}
CFilter::~CFilter()
{
CloseHandle(hInit);CloseHandle(hAReset);
SafeRelease(&pUncompressedAudioType);
}
STDMETHODIMP CFilter::NonDelegatingQueryInterface(REFIID iid, void ** ppv)
{
if(iid==IID_IMediaSeeking)
{
return GetInterface(static_cast<IMediaSeeking*>(this), ppv);
}
else if(iid==IID_IFileSourceFilter)
{
return GetInterface(static_cast<IFileSourceFilter*>(this), ppv);
}
else
return CBaseFilter::NonDelegatingQueryInterface(iid, ppv);
}
CUnknown * WINAPI CFilter::CreateInstance(LPUNKNOWN pUnk, HRESULT *phr)
{
return new CFilter(pUnk, phr);//创建过滤器
}
DWORD WINAPI GetInfoThread(LPVOID pParam);//“读取音频参数”线程函数声明
STDMETHODIMP CFilter::Load(LPCOLESTR lpwszFileName, const AM_MEDIA_TYPE *pmt)
{
CheckPointer(lpwszFileName,E_POINTER);
if(wcslen(lpwszFileName) > MAX_PATH || wcslen(lpwszFileName)<4)
return ERROR_FILENAME_EXCED_RANGE;
size_t len = 1+lstrlenW(lpwszFileName);
WCHAR* pWch=new WCHAR[len];
m_pFileName = (LPWSTR)pWch;
if (m_pFileName == NULL)return E_OUTOFMEMORY;
HRESULT hr = StringCchCopyW(m_pFileName, len, lpwszFileName);
wchar_t ExName[5]={m_pFileName[len-5],m_pFileName[len-4],m_pFileName[len-3],m_pFileName[len-2],0};
if(wcscmp(ExName,L".aac") != 0 && wcscmp(ExName,L".m4a") != 0 && wcscmp(ExName,L".m4r") != 0
&& wcscmp(ExName,L".mp3") != 0 && wcscmp(ExName,L".wav") != 0 && wcscmp(ExName,L".wma") != 0)//如果不是指定的音频文件
{
delete[] pWch; m_pFileName=NULL;
return VFW_E_INVALID_FILE_FORMAT;//设置文件名失败
}
ResetEvent(hInit);//设置“获取信息完成”无信号
CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)GetInfoThread,this,0,NULL);//创建“读取音频参数”线程
return S_OK;
}
STDMETHODIMP CFilter::GetCurFile(LPOLESTR * ppszFileName, AM_MEDIA_TYPE *pmt)
{
CheckPointer(ppszFileName, E_POINTER);
*ppszFileName = NULL;
if (m_pFileName !=NULL)
{
DWORD n = sizeof(WCHAR)*(1+lstrlenW(m_pFileName));
*ppszFileName = (LPOLESTR)CoTaskMemAlloc(n);
if (*ppszFileName!=NULL)CopyMemory(*ppszFileName, m_pFileName, n);
}
return S_OK;
}
DWORD WINAPI GetInfoThread(LPVOID pParam)//“读取音频参数”线程
{
CFilter* pCFilter=(CFilter*)pParam;//参数为过滤器指针
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
if (hr != S_OK)
{
MessageBox(NULL,L"初始化COM库失败",NULL,MB_OK);
return 0;
}
hr = MFStartup(MF_VERSION);
if (hr != S_OK)
{
MessageBox(NULL,L"初始化媒体基础失败",NULL,MB_OK);
CoUninitialize();//关闭COM库
return 0;
}
IMFSourceReader* pReader = NULL;
hr = MFCreateSourceReaderFromURL(pCFilter->m_pFileName, NULL, &pReader);
if (hr != S_OK)
{
MessageBox(NULL,L"创建源读取器失败",NULL,MB_OK);
MFShutdown();//关闭媒体基础
CoUninitialize();//关闭COM库
return 0;
}
IMFMediaType* pPartialType = NULL;
if (SUCCEEDED(hr))
{
hr = MFCreateMediaType(&pPartialType);//创建空的媒体类型
}
if (SUCCEEDED(hr))
{
hr = pPartialType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio);//设置主要类型音频
}
if (SUCCEEDED(hr))
{
hr = pPartialType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM);//设置子类型PCM
}
if (SUCCEEDED(hr))
{
hr = pReader->SetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM,NULL, pPartialType);//在源读取器上设置此媒体类型
}
SafeRelease(&pCFilter->pUncompressedAudioType);
if (SUCCEEDED(hr))
{
hr = pReader->GetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM,&pCFilter->pUncompressedAudioType);//获取完整的音频媒体类型
}
PROPVARIANT var;
if (SUCCEEDED(hr))
{
PropVariantInit(&var);
hr=pReader->GetPresentationAttribute(MF_SOURCE_READER_MEDIASOURCE ,MF_PD_DURATION,&var);//获取音频时间长度,100纳秒单位
}
if (SUCCEEDED(hr))
{
pCFilter->DUR=(LONGLONG)var.uhVal.QuadPart;
PropVariantClear(&var);
}
SafeRelease(&pReader);SafeRelease(&pPartialType);
MFShutdown();//关闭媒体基础
CoUninitialize();//关闭COM库
if (hr!=S_OK)
{
MessageBox(0,L"获取信息失败",0,MB_OK);return 0;
}
SetEvent(pCFilter->hInit);//发出“获取信息完成”信号
return 1;
}
HRESULT STDMETHODCALLTYPE CFilter::CheckCapabilities(DWORD *pCapabilities)//检查是否具有指定的查找功能
{
if(pCapabilities==NULL)return E_POINTER;
if(*pCapabilities == (AM_SEEKING_CanSeekAbsolute | AM_SEEKING_CanGetDuration))
return S_OK;
else if(*pCapabilities & AM_SEEKING_CanSeekAbsolute) //可以查找到绝对位置
{
return S_FALSE;
}
else if(*pCapabilities & AM_SEEKING_CanGetDuration)//可以获取持续时间
{
return S_FALSE;
}
else return E_FAIL;
}
HRESULT STDMETHODCALLTYPE CFilter::ConvertTimeFormat(LONGLONG *pTarget, const GUID *pTargetFormat, LONGLONG Source, const GUID *pSourceFormat)
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE CFilter::GetAvailable(LONGLONG *pEarliest, LONGLONG *pLatest)
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE CFilter::GetCapabilities(DWORD *pCapabilities)
{
*pCapabilities=AM_SEEKING_CanSeekAbsolute | AM_SEEKING_CanGetDuration;
return S_OK;
}
HRESULT STDMETHODCALLTYPE CFilter::GetCurrentPosition(LONGLONG *pCurrent)
{
*pCurrent=CUR;return S_OK;
}
HRESULT STDMETHODCALLTYPE CFilter::GetDuration(LONGLONG *pDuration)
{
DWORD dw=WaitForSingleObject(hInit,0);
if(dw!=WAIT_OBJECT_0)return E_NOTIMPL;
*pDuration=DUR;
return S_OK;
}
HRESULT STDMETHODCALLTYPE CFilter::GetPositions(LONGLONG *pCurrent, LONGLONG *pStop)
{
DWORD dw=WaitForSingleObject(hInit,0);
if(dw==WAIT_OBJECT_0)
{
*pCurrent=CUR;return S_OK;
}
else return S_FALSE;
}
HRESULT STDMETHODCALLTYPE CFilter::GetPreroll(LONGLONG *pllPreroll)
{
*pllPreroll=0;
return S_OK;
}
HRESULT STDMETHODCALLTYPE CFilter::GetRate(double *pdRate)
{
*pdRate=1.0;return S_OK;
}
HRESULT STDMETHODCALLTYPE CFilter::GetStopPosition(LONGLONG *pStop)
{
*pStop=DUR-AResetPos;
return S_OK;
}
HRESULT STDMETHODCALLTYPE CFilter::GetTimeFormat(GUID *pFormat)
{
if(pFormat==NULL)return E_POINTER;
*pFormat=TIME_FORMAT_MEDIA_TIME;return S_OK;
}
HRESULT STDMETHODCALLTYPE CFilter::IsFormatSupported(const GUID *pFormat)
{
if(TIME_FORMAT_MEDIA_TIME==*pFormat)return S_OK;
else return S_FALSE;
}
HRESULT STDMETHODCALLTYPE CFilter::IsUsingTimeFormat(const GUID *pFormat)
{
if(*pFormat==TIME_FORMAT_MEDIA_TIME)return S_OK;
else return S_FALSE;
}
HRESULT STDMETHODCALLTYPE CFilter::QueryPreferredFormat(GUID *pFormat)
{
if(pFormat==NULL)return E_POINTER;
*pFormat=TIME_FORMAT_MEDIA_TIME;return S_OK;
}
HRESULT STDMETHODCALLTYPE CFilter::SetPositions(LONGLONG *pCurrent, DWORD dwCurrentFlags, LONGLONG *pStop, DWORD dwStopFlags)
{
DWORD dw=WaitForSingleObject(hInit,0);
if((dw==WAIT_OBJECT_0) && (dwCurrentFlags & AM_SEEKING_AbsolutePositioning))
{
AResetPos=*pCurrent;*pStop=DUR-*pCurrent;
SetEvent(hAReset);//发出“音频更改播放位置”信号
return S_OK;
}
else
{
return S_FALSE;
}
}
HRESULT STDMETHODCALLTYPE CFilter::SetRate(double dRate)
{
if(dRate==1.0)return S_OK;
else return S_FALSE;
}
HRESULT STDMETHODCALLTYPE CFilter::SetTimeFormat(const GUID *pFormat)
{
if(*pFormat==TIME_FORMAT_MEDIA_TIME)return S_OK;
else return S_FALSE;
}
引脚头文件:CPin.h
#ifndef PIN_FILE
#define PIN_FILE
#include "AudioReader.h"
#include "CFilter.h"
class CPin : public CSourceStream
{
friend class CFilter;
public:
CPin(HRESULT *phr, CSource *pParent, LPCWSTR pPinName);
~CPin();
HRESULT GetMediaType(CMediaType *pmt);
HRESULT DecideBufferSize(IMemAllocator * pAlloc, ALLOCATOR_PROPERTIES * pRequest);//确定缓冲区大小
STDMETHODIMP Notify(IBaseFilter * pSender, Quality q);
HRESULT FillBuffer(IMediaSample *pms);
HRESULT OnThreadDestroy(void);
CFilter* pCFilter;//过滤器指针
IMFSourceReader* pReader;//源读取器接口
BOOL B_Pasue;//TRUE,暂停状态;FALSE,运行或停止状态
protected:
DWORD ThreadProc(void);
HRESULT DoBufferProcessingLoop(void);
};
#endif // PIN_FILE
引脚源文件:CPin.cpp
#include "CPin.h"
CPin::CPin(HRESULT *phr, CSource *pParent, LPCWSTR pPinName) : CSourceStream(NAME("Out"), phr, pParent, pPinName)
{
pCFilter=(CFilter*)pParent;
pReader = NULL;B_Pasue=FALSE;
}
CPin::~CPin()
{
}
HRESULT CPin::GetMediaType(CMediaType *pmt)
{
DWORD dw=WaitForSingleObject(pCFilter->hInit,2000);//最多等待2秒
if(dw!=WAIT_OBJECT_0) return E_UNEXPECTED;//如果没有“获取信息完成”信号,返回错误
AM_MEDIA_TYPE* pMt=NULL;
pCFilter->pUncompressedAudioType->GetRepresentation(AM_MEDIA_TYPE_REPRESENTATION,(void**)&pMt);//将IMFMediaType表示的媒体类型,转换为AM_MEDIA_TYPE结构形式
pmt->Set(*pMt);
pCFilter->pUncompressedAudioType->FreeRepresentation(AM_MEDIA_TYPE_REPRESENTATION,pMt);//释放GetRepresentation分配的内存
return S_OK;
}
HRESULT CPin::DecideBufferSize(IMemAllocator * pAlloc, ALLOCATOR_PROPERTIES * pRequest)
{
DWORD dw=WaitForSingleObject(pCFilter->hInit,2000);//最多等待2秒
if(dw!=WAIT_OBJECT_0) return E_FAIL;//如果没有“获取信息完成”信号,函数失败
HRESULT hr;
pRequest->cBuffers = 1;//1个缓冲区
pRequest->cbBuffer = 1000000;//缓冲区的大小1M
ALLOCATOR_PROPERTIES Actual;
hr = pAlloc->SetProperties(pRequest,&Actual);
if(FAILED(hr))return hr;
if(Actual.cbBuffer < pRequest->cbBuffer)// 这个分配器是否不合适
{
return E_FAIL;
}
return NOERROR;
}
STDMETHODIMP CPin::Notify(IBaseFilter * pSender, Quality q)
{
return NOERROR;
}
HRESULT CPin::FillBuffer(IMediaSample *pms)
{
HRESULT hr;
BYTE *pBuffer;
pms->GetPointer(&pBuffer);//获取样本缓冲区指针
long BufferLen = pms->GetSize();//获取样本缓冲区大小
DWORD dw=WaitForSingleObject(pCFilter->hAReset,0);
if(dw==WAIT_OBJECT_0)//如果有“音频更改播放位置”信号
{
hr=DeliverBeginFlush();
Sleep(1);
hr=DeliverEndFlush();
hr=DeliverNewSegment(0,pCFilter->DUR-pCFilter->AResetPos,1.0);
PROPVARIANT pv;
PropVariantInit(&pv);
pv.vt=20;
pv.hVal.QuadPart=pCFilter->AResetPos;
hr=pReader->SetCurrentPosition(GUID_NULL, pv);//更改源读取器读取位置
PropVariantClear(&pv);
pms->SetDiscontinuity(TRUE);//设置流中断
}
DWORD index,flags;LONGLONG stime;
IMFSample* pIMFSample=NULL;IMFMediaBuffer* pIMFMediaBuffer=NULL;
AganRead:
hr=pReader->ReadSample(MF_SOURCE_READER_FIRST_AUDIO_STREAM,0,&index,&flags,&stime,&pIMFSample);//读取音频样本
if(MF_SOURCE_READERF_ENDOFSTREAM == flags)return S_FALSE;//如果到达流的末尾,返回S_FALSE
if(pIMFSample==NULL)
{
Sleep(1);goto AganRead;//如果读取失败,再次读取
}
LONGLONG Cur, Dur, End;
hr=pIMFSample->GetSampleTime(&Cur);//获取样本显示时间
pCFilter->CUR=Cur;//在此获取音频当前时间
hr=pIMFSample->GetSampleDuration(&Dur);//获取样本持续时间
End=Cur+Dur;//计算样本结束时间
Cur-=pCFilter->AResetPos;End-=pCFilter->AResetPos;//使用IMediaSeeking接口调整播放位置后,AResetPos可能不为0,需计算时间戳的值
DWORD Lt;
hr=pIMFSample->GetTotalLength(&Lt);//获取样本有效长度
hr=pIMFSample->GetBufferByIndex(0,&pIMFMediaBuffer);//获取缓冲区接口
BYTE* pSB=NULL;
hr=pIMFMediaBuffer->Lock(&pSB,NULL,NULL);//锁定缓冲区
if(Lt<=(DWORD)BufferLen)//防止数据长度大于样本缓冲区大小时,进行数据复制
CopyMemory(pBuffer, pSB, Lt);//复制数据
pms->SetTime(&Cur,&End);//设置时间戳
pms->SetActualDataLength(Lt);//设置有效数据长度
pms->SetSyncPoint(TRUE);//设置样本为同步点
hr=pIMFMediaBuffer->Unlock();//解锁缓冲区
SafeRelease(&pIMFMediaBuffer);SafeRelease(&pIMFSample);//释放接口
return S_OK;
}
HRESULT CPin::OnThreadDestroy(void)
{
SafeRelease(&pReader);//释放源读取器接口
MFShutdown();//关闭媒体基础
return NOERROR;
}
DWORD CPin::ThreadProc()
{
WaitForSingleObject(pCFilter->hInit,INFINITE);//等待“获取信息完成”信号
HRESULT hr;
hr = MFStartup(MF_VERSION);
if (hr != S_OK)
{
MessageBox(NULL,L"初始化媒体基础失败",NULL,MB_OK);
return 1;
}
hr = MFCreateSourceReaderFromURL(pCFilter->m_pFileName, NULL, &pReader);
if (hr != S_OK)
{
MessageBox(NULL,L"创建源读取器失败",NULL,MB_OK);
MFShutdown();//关闭媒体基础
CoUninitialize();//关闭COM库
return 1;
}
if (SUCCEEDED(hr))
{
hr = pReader->SetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM,NULL, pCFilter->pUncompressedAudioType);//在源读取器上设置此媒体类型
}
if(FAILED(hr))
{
MessageBox(NULL,L"初始化音频媒体类型失败",NULL,MB_OK);return 1;
}
Command com;
do
{
com = GetRequest();
if (com != CMD_INIT)
{
DbgLog((LOG_ERROR, 1, TEXT("Thread expected init command")));
Reply((DWORD) E_UNEXPECTED);
}
} while (com != CMD_INIT);
DbgLog((LOG_TRACE, 1, TEXT("CSourceStream worker thread initializing")));
hr = OnThreadCreate();
if (FAILED(hr))
{
DbgLog((LOG_ERROR, 1, TEXT("CSourceStream::OnThreadCreate failed. Aborting thread.")));
OnThreadDestroy();
Reply(hr);
return 1;
}
Reply(NOERROR);
B_Pasue=TRUE;
Command cmd;
do
{
cmd = GetRequest();
switch (cmd)
{
case CMD_EXIT:
Reply(NOERROR);
break;
case CMD_RUN:
DbgLog((LOG_ERROR, 1, TEXT("CMD_RUN received before a CMD_PAUSE???")));
case CMD_PAUSE:
if(B_Pasue)
{
B_Pasue=FALSE;
}
else
{
B_Pasue=TRUE;
}
Reply(NOERROR);
DoBufferProcessingLoop();
break;
case CMD_STOP:
B_Pasue=FALSE;
Reply(NOERROR);
break;
default:
DbgLog((LOG_ERROR, 1, TEXT("Unknown command %d received!"), cmd));
Reply((DWORD) E_NOTIMPL);
break;
}
} while (cmd != CMD_EXIT);
hr = OnThreadDestroy();
if (FAILED(hr))
{
DbgLog((LOG_ERROR, 1, TEXT("CSourceStream::OnThreadDestroy failed. Exiting thread.")));
return 1;
}
DbgLog((LOG_TRACE, 1, TEXT("CSourceStream worker thread exiting")));
return 0;
}
HRESULT CPin::DoBufferProcessingLoop(void)
{
Command com;
OnThreadStartPlay();
do
{
while (!CheckRequest(&com))
{
if(B_Pasue)
{
continue;//如果是暂停状态,不获取样本缓冲区,不填充样本和发送样本
}
IMediaSample *pSample;
HRESULT hr = GetDeliveryBuffer(&pSample,NULL,NULL,0);
if (FAILED(hr))
{
Sleep(1);
continue;
}
hr = FillBuffer(pSample);
if (hr == S_OK)
{
hr = Deliver(pSample);
pSample->Release();
if(hr != S_OK)
{
DbgLog((LOG_TRACE, 2, TEXT("Deliver() returned %08x; stopping"), hr));
return S_OK;
}
}
else if (hr == S_FALSE)
{
pSample->Release();
DeliverEndOfStream();
return S_OK;
}
else
{
pSample->Release();
DbgLog((LOG_ERROR, 1, TEXT("Error %08lX from FillBuffer!!!"), hr));
DeliverEndOfStream();
m_pFilter->NotifyEvent(EC_ERRORABORT, hr, 0);
return hr;
}
}//while
if (com == CMD_RUN || com == CMD_PAUSE)
{
Reply(NOERROR);
}
else if (com != CMD_STOP)
{
Reply((DWORD) E_UNEXPECTED);
DbgLog((LOG_ERROR, 1, TEXT("Unexpected command!!!")));
}
} while (com != CMD_STOP);
return S_FALSE;
}