DirectShow过滤器开发-读MP3音频文件过滤器

下载本过滤器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;
}

下载本过滤器DLL

  • 20
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

h3974

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值