下载本过滤器DLL
本过滤器读取MP3音频文件数据,输出MP3音频流。
过滤器信息
过滤器名称:读MP3
过滤器GUID:{FF9AA3E1-0D31-4326-9025-CC8E8C98506E}
DLL注册函数名:DllRegisterServer
删除注册函数名:DllUnregisterServer
过滤器有一个输出引脚。
输出引脚标识:1
输出引脚媒体类型:
主要类型:MEDIATYPE_Audio
子类型:{0x00000055, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
格式类型:FORMAT_WaveFormatEx
读MP3过滤器开发信息
过滤器从CSource类和IFileSourceFilter接口派生。IFileSourceFilter接口用于指定和获取要读取的MP3文件路径。引脚从CSourceStream类和IMediaSeeking接口派生。IMediaSeeking接口用于调整播放的当前位置。使用MFCreateSourceResolver函数创建源解析器(接口为IMFSourceResolver),使用源解析器的CreateObjectFromURL方法创建媒体源对象(接口为IMFMediaSource),使用媒体源对象的Start方法启动媒体源;IMFMediaSource接口继承自IMFMediaEventGenerator接口,可以直接使用媒体源对象获取媒体源事件;媒体源启动后,第1个媒体源事件是“创建了新流”(MENewStream),事件值即为流接口IMFMediaStream的指针,使用该接口就可以读取音频文件数据。媒体源使用拉模式,即需要发送样本请求(pMFMediaStream->RequestSample(NULL);)才能获取样本;获取样本的方式为:发送样本请求后,会产生“流已生成新的样本”的流事件(MEMediaSample),该流事件的值即为样本的接口指针(IMFSample*);该样本是媒体基础样本,需转换为引脚样本,由输出引脚输出。最后释放媒体基础样本,发送下一个样本请求。
获取媒体源事件的方法为:
hr = pMFMediaSource->GetEvent(0, &pSourceEvent);
获取流事件的方法为:
hr = pMFMediaStream->GetEvent(MF_EVENT_FLAG_NO_WAIT, &pStreamEvent);
参数1,指定等待的时间。0为无限期等待;MF_EVENT_FLAG_NO_WAIT不等待。
参数2,输出事件接口指针。类型为IMFMediaEvent*。
读MP3过滤器的全部代码
DLL头文件:DLL.h
#ifndef DLL_FILE
#define DLL_FILE
#include "strmbase10.h"//过滤器基础类定义文件
#if _DEBUG
#pragma comment(lib, "strmbasd10.lib")//过滤器基础类实现文件调试版本
#else
#pragma comment(lib, "strmbase10.lib")//过滤器基础类实现文件发布版本
#endif
// {FF9AA3E1-0D31-4326-9025-CC8E8C98506E}
DEFINE_GUID(CLSID_MP3Reader,//过滤器GUID
0xff9aa3e1, 0xd31, 0x4326, 0x90, 0x25, 0xcc, 0x8e, 0x8c, 0x98, 0x50, 0x6e);
DEFINE_GUID(MEDIASUBTYPE_MP3,
0x00000055, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
#include "mfapi.h"
#include "mfidl.h"
#pragma comment(lib, "mfuuid")
#pragma comment(lib, "mfplat")
class CFilter;
class CPin : public CSourceStream, public IMediaSeeking
{
friend class CFilter;
public:
CPin(HRESULT *phr, CSource *pParent, LPCWSTR pPinName);
~CPin();
DECLARE_IUNKNOWN
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppvoid);
HRESULT GetMediaType(CMediaType *pmt);
HRESULT DecideBufferSize(IMemAllocator * pAlloc, ALLOCATOR_PROPERTIES * pRequest);//确定缓冲区大小
HRESULT FillBuffer(IMediaSample *pms);
HRESULT Init();//初始化媒体源
CFilter* pCFilter;//过滤器指针
IMFMediaSource *pMFMediaSource = NULL;//媒体源接口
IMFMediaStream* pMFMediaStream = NULL;//流接口
IMFPresentationDescriptor* pSourceD = NULL;//演示文稿描述符
IMFMediaType* pIMFMediaType = NULL;//媒体基础媒体类型
IMFSample* pCurMFSample = NULL;//当前样本
LONGLONG DUR=0;//持续时间,100纳秒单位
LONGLONG CUR=0;//基于文件总持续时间的当前时间,100纳秒单位
LONGLONG RePos=0;//重定位开始时间,100纳秒单位
protected:
virtual HRESULT DoBufferProcessingLoop(void);
public:
DWORD m_dwSeekingCaps = AM_SEEKING_CanSeekForwards | AM_SEEKING_CanSeekBackwards | AM_SEEKING_CanSeekAbsolute | AM_SEEKING_CanGetStopPos | AM_SEEKING_CanGetDuration;
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);
};
class CFilter : public CSource, public IFileSourceFilter
{
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* pCPin;//输出引脚指针
WCHAR* m_pFileName=NULL;//要读取的MP3音频文件路径
private:
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv);
};
template <class T> void SafeRelease(T** ppT)
{
if (*ppT)
{
(*ppT)->Release();
*ppT = NULL;
}
}
#endif //DLL_FILE
DLL源文件:DLL.cpp
#include "DLL.h"
const AMOVIESETUP_MEDIATYPE OutPinType = //输出引脚媒体类型
{
&MEDIATYPE_Audio, //主要类型
&MEDIASUBTYPE_MP3 //子类型
};
const AMOVIESETUP_PIN sudPins = // 引脚信息
{
(LPWSTR)"Out", //引脚名称
FALSE, //渲染过滤器
TRUE, //输出引脚
FALSE, //具有该引脚的零个实例
FALSE, //可以创建一个以上引脚的实例
&CLSID_NULL, //该引脚连接的过滤器的类标识
NULL, //该引脚连接的引脚名称
1, //引脚支持的媒体类型数
&OutPinType //媒体类型信息
};
const AMOVIESETUP_FILTER MP3Reader = //过滤器的注册信息
{
&CLSID_MP3Reader, //过滤器的类标识
L"读MP3", //过滤器的名称
MERIT_DO_NOT_USE, //过滤器优先值
1, //引脚数量
&sudPins //引脚信息
};
CFactoryTemplate g_Templates[] = //类工厂模板数组
{
{
L"读MP3", //对象(这里为过滤器)名称
&CLSID_MP3Reader, //对象CLSID的指针
CFilter::CreateInstance, //创建对象实例的函数的指针
NULL, //指向从DLL入口点调用的函数的指针
&MP3Reader //指向AMOVIESETUP_FILTER结构的指针
}
};
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.cpp
#include "DLL.h"
#include "strsafe.h"
CFilter::CFilter(LPUNKNOWN lpunk, HRESULT *phr) : CSource(NAME("读MP3"), lpunk, CLSID_MP3Reader)
{
HRESULT hr = MFStartup(MF_VERSION);//初始化媒体基础
if (hr != S_OK)
{
MessageBox(NULL, L"初始化媒体基础失败", L"读MP3", MB_OK); return;
}
pCPin = new CPin(phr, this, L"Out");//创建音频引脚
}
CFilter::~CFilter()
{
if (m_pFileName)delete[] m_pFileName;
MFShutdown();//关闭媒体基础
}
STDMETHODIMP CFilter::NonDelegatingQueryInterface(REFIID iid, void ** ppv)
{
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);//创建过滤器
}
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".mp3") != 0)//如果不是MP3音频文件
{
delete[] pWch; m_pFileName = NULL;
return VFW_E_INVALID_FILE_FORMAT;//设置文件名失败
}
pCPin->Init();
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;
}
输出引脚源文件:CPin.cpp
#include "DLL.h"
CPin::CPin(HRESULT *phr, CSource *pParent, LPCWSTR pPinName) : CSourceStream(NAME("Out"), phr, pParent, pPinName)
{
pCFilter = (CFilter*)pParent;
}
CPin::~CPin()
{
SafeRelease(&pMFMediaSource); SafeRelease(&pSourceD); SafeRelease(&pIMFMediaType);
}
STDMETHODIMP CPin::NonDelegatingQueryInterface(REFIID riid, void **ppv)
{
if (riid == IID_IMediaSeeking)
{
return GetInterface(static_cast<IMediaSeeking*>(this), ppv);
}
else
return CBaseOutputPin::NonDelegatingQueryInterface(riid, ppv);
}
HRESULT CPin::GetMediaType(CMediaType *pmt)
{
AM_MEDIA_TYPE* pMt = NULL;
pIMFMediaType->GetRepresentation(AM_MEDIA_TYPE_REPRESENTATION, (void**)&pMt);//将IMFMediaType表示的媒体类型,转换为AM_MEDIA_TYPE结构形式
pmt->Set(*pMt);
pIMFMediaType->FreeRepresentation(AM_MEDIA_TYPE_REPRESENTATION, pMt);//释放GetRepresentation分配的内存
return S_OK;
}
HRESULT CPin::DecideBufferSize(IMemAllocator * pAlloc, ALLOCATOR_PROPERTIES * pRequest)
{
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;
}
HRESULT CPin::FillBuffer(IMediaSample *pms)
{
LONGLONG star, dur;
HRESULT hr=pCurMFSample->GetSampleTime(&star);
if (hr == S_OK)
{
hr= pCurMFSample->GetSampleDuration(&dur); CUR = star;
if (hr == S_OK)
{
LONGLONG s = star - RePos, e = s + dur;
pms->SetTime(&s, &e);
}
}
IMFMediaBuffer* pMFBuffer = NULL;
hr=pCurMFSample->GetBufferByIndex(0, &pMFBuffer);
DWORD len=0;
if (hr == S_OK)
{
hr = pMFBuffer->GetCurrentLength(&len);
if (hr == S_OK)
{
pms->SetActualDataLength(len);
}
}
BYTE* pMFData = NULL;
hr=pMFBuffer->Lock(&pMFData, NULL, NULL);
BYTE* pData=NULL;
pms->GetPointer(&pData);
if (hr == S_OK && len <= 1000000 && pMFData!=NULL && pData!=NULL)
CopyMemory(pData, pMFData, len);
pMFBuffer->Unlock();
SafeRelease(&pCurMFSample); SafeRelease(&pMFBuffer);
pMFMediaStream->RequestSample(NULL);//请求下一个样本
return S_OK;
}
HRESULT CPin::Init()//初始化媒体源
{
SafeRelease(&pSourceD); SafeRelease(&pIMFMediaType); SafeRelease(&pMFMediaSource);
IMFSourceResolver* pSourceResolver = NULL;
HRESULT hr = MFCreateSourceResolver(&pSourceResolver);//创建源解析器
MF_OBJECT_TYPE ObjectType = MF_OBJECT_INVALID;
IUnknown* pSource = NULL;
hr = pSourceResolver->CreateObjectFromURL(//从URL创建媒体源
pCFilter->m_pFileName, //源的URL
MF_RESOLUTION_MEDIASOURCE, //创建源对象。
NULL, //可选属性存储。
&ObjectType, //接收创建的对象类型。
&pSource //接收指向媒体源的指针。
);
if (SUCCEEDED(hr))
{
hr = pSource->QueryInterface(IID_PPV_ARGS(&pMFMediaSource));//获取媒体源接口
}
SafeRelease(&pSourceResolver);
SafeRelease(&pSource);
if (SUCCEEDED(hr))
{
hr = pMFMediaSource->CreatePresentationDescriptor(&pSourceD);//获取演示文稿描述符
}
if (SUCCEEDED(hr))
{
hr = pSourceD->GetUINT64(MF_PD_DURATION, (UINT64*)&DUR);//获取文件流的时长,100纳秒为单位
}
IMFStreamDescriptor* pStreamD = NULL; //流描述符
if (SUCCEEDED(hr))
{
BOOL Selected;
hr = pSourceD->GetStreamDescriptorByIndex(0, &Selected, &pStreamD);//获取流描述符
}
IMFMediaTypeHandler* pHandle = NULL;
if (SUCCEEDED(hr))
{
hr = pStreamD->GetMediaTypeHandler(&pHandle);//获取媒体类型处理接口
}
SafeRelease(&pStreamD);
if (SUCCEEDED(hr))
{
hr = pHandle->GetCurrentMediaType(&pIMFMediaType);//获取文件流的媒体类型
}
SafeRelease(&pHandle);
return hr;
}
HRESULT CPin::DoBufferProcessingLoop(void)
{
pMFMediaStream = NULL; RePos=0;CUR=0;
Init();
PROPVARIANT var;
PropVariantInit(&var);
var.vt = VT_I8;
var.hVal.QuadPart = 0;
HRESULT hr = pMFMediaSource->Start(pSourceD, NULL, &var);//启动媒体源
Agan:
IMFMediaEvent* pSourceEvent = NULL;
hr = pMFMediaSource->GetEvent(0, &pSourceEvent);//获取媒体源事件,无限期等待
if (SUCCEEDED(hr))
{
MediaEventType MET; PROPVARIANT var;
hr = pSourceEvent->GetType(&MET);//获取媒体源事件类型
if (SUCCEEDED(hr))
{
if (MET != MENewStream)//如果不是“创建了新流”事件,再次获取事件
{
SafeRelease(&pSourceEvent);//释放媒体源事件
goto Agan;
}
hr = pSourceEvent->GetValue(&var);//如果是“创建了新流”事件,获取事件值,值为流接口
if (SUCCEEDED(hr))
{
if (var.vt == VT_UNKNOWN)
{
hr = var.punkVal->QueryInterface(&pMFMediaStream);//获取流接口
}
PropVariantClear(&var);
}
}
}
SafeRelease(&pSourceEvent);//释放媒体源事件
pMFMediaStream->RequestSample(NULL);//请求样本第1个样本
Command com;
OnThreadStartPlay();
do
{
while (!CheckRequest(&com))
{
IMFMediaEvent* pStreamEvent = NULL;
hr = pMFMediaStream->GetEvent(MF_EVENT_FLAG_NO_WAIT, &pStreamEvent); // 获取流事件,不等待
if (hr != S_OK)continue;//如果没有流事件,不发送样本
MediaEventType ME;
hr = pStreamEvent->GetType(&ME);//获取流事件类型
if (MEMediaSample != ME)//如果不是“流已生成新的样本”事件
{
if (MEEndOfStream == ME)//如果是“流结束”事件
{
DeliverEndOfStream();
}
SafeRelease(&pStreamEvent);//释放流事件
continue;//不发送样本
}
PROPVARIANT var;
hr = pStreamEvent->GetValue(&var);//如果是“流已生成新的样本”事件,获取事件值,值为样本接口指针
if (SUCCEEDED(hr))
{
if (var.vt == VT_UNKNOWN)
{
hr = var.punkVal->QueryInterface(&pCurMFSample);//获取样本接口
}
PropVariantClear(&var);
}
SafeRelease(&pStreamEvent);//释放流事件
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));
hr = pMFMediaSource->Stop();//停止媒体源
hr = pMFMediaSource->Shutdown();//关闭媒体源并释放它正在使用的资源
SafeRelease(&pMFMediaStream);//释放流接口
return S_OK;
}
}
else if (hr == S_FALSE)
{
pSample->Release();
DeliverEndOfStream();
hr = pMFMediaSource->Stop();//停止媒体源
hr = pMFMediaSource->Shutdown();//关闭媒体源并释放它正在使用的资源
SafeRelease(&pMFMediaStream);//释放流接口
return S_OK;
}
else
{
pSample->Release();
DbgLog((LOG_ERROR, 1, TEXT("Error %08lX from FillBuffer!!!"), hr));
DeliverEndOfStream();
m_pFilter->NotifyEvent(EC_ERRORABORT, hr, 0);
hr = pMFMediaSource->Stop();//停止媒体源
hr = pMFMediaSource->Shutdown();//关闭媒体源并释放它正在使用的资源
SafeRelease(&pMFMediaStream);//释放流接口
return hr;
}
}
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);
hr = pMFMediaSource->Stop();//停止媒体源
hr = pMFMediaSource->Shutdown();//关闭媒体源并释放它正在使用的资源
SafeRelease(&pMFMediaStream);//释放流接口
return S_FALSE;
}
HRESULT STDMETHODCALLTYPE CPin::CheckCapabilities(DWORD *pCapabilities)//查询流是否具有指定的Seek功能
{
CheckPointer(pCapabilities, E_POINTER);
return (~m_dwSeekingCaps & *pCapabilities) ? S_FALSE : S_OK;
}
HRESULT STDMETHODCALLTYPE CPin::ConvertTimeFormat(LONGLONG *pTarget, const GUID *pTargetFormat, LONGLONG Source, const GUID *pSourceFormat)//从一种时间格式转换为另一种时间格式
{
CheckPointer(pTarget, E_POINTER);
if (pTargetFormat == 0 || *pTargetFormat == TIME_FORMAT_MEDIA_TIME)
{
if (pSourceFormat == 0 || *pSourceFormat == TIME_FORMAT_MEDIA_TIME)
{
*pTarget = Source;
return S_OK;
}
}
return E_INVALIDARG;
}
HRESULT STDMETHODCALLTYPE CPin::GetAvailable(LONGLONG *pEarliest, LONGLONG *pLatest)//获取有效Seek的时间范围
{
if (pEarliest)
{
*pEarliest = 0;
}
if (pLatest)
{
CAutoLock lock(m_pLock);
*pLatest = DUR;
}
return S_OK;
}
HRESULT STDMETHODCALLTYPE CPin::GetCapabilities(DWORD *pCapabilities)//检索流的所有Seek功能
{
CheckPointer(pCapabilities, E_POINTER);
*pCapabilities = m_dwSeekingCaps;
return S_OK;
}
HRESULT STDMETHODCALLTYPE CPin::GetCurrentPosition(LONGLONG *pCurrent)//获取相对于流总持续时间的当前位置
{
*pCurrent = CUR;
return S_OK;
}
HRESULT STDMETHODCALLTYPE CPin::GetDuration(LONGLONG *pDuration)//获取流的持续时间
{
CheckPointer(pDuration, E_POINTER);
CAutoLock lock(m_pLock);
*pDuration = DUR;
return S_OK;
}
HRESULT STDMETHODCALLTYPE CPin::GetPositions(LONGLONG *pCurrent, LONGLONG *pStop)//获取相对于流总持续时间的当前位置和停止位置
{
CheckPointer(pCurrent, E_POINTER); CheckPointer(pStop, E_POINTER);
*pCurrent = CUR; *pStop = DUR;
return S_OK;
}
HRESULT STDMETHODCALLTYPE CPin::GetPreroll(LONGLONG *pllPreroll)//获取将在开始位置之前排队的数据量
{
CheckPointer(pllPreroll, E_POINTER);
*pllPreroll = 0;
return S_OK;
}
HRESULT STDMETHODCALLTYPE CPin::GetRate(double *pdRate)//获取播放速率
{
CheckPointer(pdRate, E_POINTER);
CAutoLock lock(m_pLock);
*pdRate = 1.0;
return S_OK;
}
HRESULT STDMETHODCALLTYPE CPin::GetStopPosition(LONGLONG *pStop)//获取相对于流的持续时间的停止播放时间
{
CheckPointer(pStop, E_POINTER);
CAutoLock lock(m_pLock);
*pStop = DUR;
return S_OK;
}
HRESULT STDMETHODCALLTYPE CPin::GetTimeFormat(GUID *pFormat)//获取当前用于Seek操作的时间格式
{
CheckPointer(pFormat, E_POINTER);
*pFormat = TIME_FORMAT_MEDIA_TIME;
return S_OK;
}
HRESULT STDMETHODCALLTYPE CPin::IsFormatSupported(const GUID *pFormat)//确定Seek操作是否支持指定的时间格式
{
CheckPointer(pFormat, E_POINTER);
return *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE;
}
HRESULT STDMETHODCALLTYPE CPin::IsUsingTimeFormat(const GUID *pFormat)//确定Seek操作当前是否使用指定的时间格式
{
CheckPointer(pFormat, E_POINTER);
return *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE;
}
HRESULT STDMETHODCALLTYPE CPin::QueryPreferredFormat(GUID *pFormat)//获取首选的Seek时间格式
{
CheckPointer(pFormat, E_POINTER);
*pFormat = TIME_FORMAT_MEDIA_TIME;
return S_OK;
}
HRESULT STDMETHODCALLTYPE CPin::SetPositions(LONGLONG *pCurrent, DWORD dwCurrentFlags, LONGLONG *pStop, DWORD dwStopFlags)//设置当前位置和停止位置
{
CheckPointer(pCurrent, E_POINTER);
DWORD dwCurrentPos = dwCurrentFlags & AM_SEEKING_PositioningBitsMask;
if (dwCurrentPos == AM_SEEKING_AbsolutePositioning && *pCurrent>=0 && *pCurrent<=DUR)
{
PROPVARIANT var;
PropVariantInit(&var);
var.vt = VT_I8;
var.hVal.QuadPart = *pCurrent;
*pStop = DUR;
pMFMediaSource->Start(pSourceD, NULL, &var);//从指定位置启动媒体源
RePos = *pCurrent;
return S_OK;
}
return E_INVALIDARG;
}
HRESULT STDMETHODCALLTYPE CPin::SetRate(double dRate)//设置播放速率
{
if (dRate == 1.0)return S_OK;
else return S_FALSE;
}
HRESULT STDMETHODCALLTYPE CPin::SetTimeFormat(const GUID *pFormat)//设置后续Seek操作的时间格式
{
CheckPointer(pFormat, E_POINTER);
return *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : E_INVALIDARG;
}