一、硬加速的启动
对于能够启动硬加速的功能的实现,在decoder filter 和 后面的render filter都是有一定的要求的
在decoder能够启动硬加速之前,必须做以下这几个事情
1.Negotiate a media type.
2.Find a DXVA decoder configuration.
这一步又可以分成下面几个小的步骤:
1.Query the renderer's input pin for the IMFGetService interface.
2.Call IMFGetService::GetService to get a pointer to the IDirect3DDeviceManager9 interface. The service GUID is MR_VIDEO_ACCELERATION_SERVICE.
3.Call IDirect3DDeviceManager9::OpenDeviceHandle to get a handle to the renderer's Direct3D device.
4.Call IDirect3DDeviceManager9::GetVideoService and pass in the device handle. This method returns a pointer to the IDirectXVideoDecoderService interface.
5.Call IDirectXVideoDecoderService::GetDecoderDeviceGuids. This method returns an array of decoder device GUIDs.
6.Loop through the array of decoder GUIDs to find the ones that the decoder filter supports. For example, for an MPEG-2 decoder, you would look for DXVA2_ModeMPEG2_MOCOMP, DXVA2_ModeMPEG2_IDCT, or DXVA2_ModeMPEG2_VLD.
7.When you find a candidate decoder device GUID, pass the GUID to the IDirectXVideoDecoderService::GetDecoderRenderTargets method. This method returns an array of render target formats, specified as D3DFORMAT values.
8.Loop through the render target formats and look for one that matches your output format. Typically, a decoder device supports a single render target format. The decoder filter should connect to the renderer using this subtype. In the first call to CompleteConnect, the decoder can determing the render target format and then return this format as a preferred output type.
9.Call IDirectXVideoDecoderService::GetDecoderConfigurations. Pass in the same decoder device GUID, along with a DXVA2_VideoDesc structure that describes the proposed format. The method returns an array of DXVA2_ConfigPictureDecode structures. Each structure describes one possible configuration for the decoder device.
10.Assuming that the previous steps are successful, store the Direct3D device handle, the decoder device GUID, and the configuration structure. The filter will use this information to create the decoder device.
从以上步骤可以看出,对于DX提供的render来看的话,EVR支持DXVA2.0,VMR7和VMR9支持DXVA1.0。假设我们的decoder已经启动硬加速的设置操作已经完成,我们要创建一个自己的Filter,使它能够和deocoder配合起来启动硬加速,那么这个filter必须实现IMFGetService::GetService方法来得到IDirect3DDeviceManager9 接口。
3.Notify the video renderer that the decoder is using DXVA decoding.
这一步又可以分成下面几个小的步骤:
1.Query the renderer's input pin for the IMFGetService interface.
2.Call IMFGetService::GetService to get a pointer to the IDirectXVideoMemoryConfiguration interface. The service GUID is MR_VIDEO_ACCELERATION_SERVICE.
3.Call IDirectXVideoMemoryConfiguration::GetAvailableSurfaceTypeByIndex in a loop, incrementing the dwTypeIndex variable from zero. Stop when the method returns the value DXVA2_SurfaceType_DecoderRenderTarget in the pdwType parameter. This step ensures that the video renderer supports hardware-accelerated decoding. This step will always succeed for the EVR filter.
4.If the previous step succeeded, call IDirectXVideoMemoryConfiguration::SetSurfaceType with the value DXVA2_SurfaceType_DecoderRenderTarget. Calling SetSurfaceType with this value puts the video renderer into DXVA mode. When the video renderer is in this mode, the decoder must provide its own allocator.
同理,对于我们自己设计的和decoder连接的Filter要实现 IMFGetService::GetService方法来得到IDirectXVideoMemoryConfiguration。并且要重写IDirectXVideoMemoryConfiguration接口的GetAvailableSurfaceTypeByIndex方法和SetSurfaceType 方法。
4.Provide a custom allocator that allocates Direct3D surfaces.
二 filter组件的连接 以下是Graph中Filter之间连接的详细过程,这个对于Filter应用程序的开发和Filter组建的开发都有很好的参考帮助(1) Filter Graph Manager 在输出Pin上调用IPin::Connect函数 1首先进入输出Pin的方法CBasePin ::Connect(IPin * pReceivePin,const AM_MEDIA_TYPE *pmt)函数,pReceivePin要连接的下一级的输入PIn,pmt指定的连接用的媒体类型。 2真正的连接过程在函数HRESULT CBasePin::AgreeMediaType(IPin *pReceivePin,const CMediaType *pmt)中进行,在这个函数里,如果pmt是一个完整的媒体类型则调用AttemptConnection进行试连接(无论成功或失败,连接都会停止);如果pmt是空或是不完全制定的媒体类型,那么就进行协商:首先得到输入Pin的媒体类型枚举器进行试连接,如果不成功则得到输出Pin上媒体类型枚举器进行试连接。 3试连接的操作是在HRESULT CBasePin::TryMediaTypes(IPin *pReceivePin,const CMediaType *pmt,IEnumMediaTypes *pEnum)函数中完成的。该函数使用媒体类型枚举器枚举Pin上所有的媒体类型,然后进行试连接(AttemptConnection函数完成),如果有一种媒体类型试连接成功,则整个Pin连接成功。如果输入Pin和输出Pin上的所有媒体类型连接都失败,则此次Pin之间的连接操作宣告失败。 4 最后看看AttemptConnection函数做的工作:首先调用输出Pin上的CheckConnect函数进行连接检查,然后继续调用输出Pin上的CheckMediaType,进行连接用的媒体类型检查,如成功,则将输入Pin对象指针以及当前用的媒体类型保存在输出Pin对象中,然后调用输入Pin上的ReceiveConnection函数。(2)如果输出Pin接受连接,则调用输入Pin上的IPin::ReceiveConnnection 1 该函数在输入Pin上进行一系列类似于上述输出Pin上的检查。如果该函数调用成功,则最后调用输出Pin上的CompleteConnect函数。这个函数主要完成数据传输的内存分配和管理等“收尾”工作。此函数实现了DecideAllocator函数 2 在DecideAllocator函数里,首先询问输入Pin上的分配器的配置要求。如果输入Pin创建了分配器,则取得这个分配器,然后再输入Pin上决定每个Sample使用的内存大小、使用的Sample数量(在输出的DecideBufferSize中完成)。如上述调用都能成功则分配器协商完成,使用输入Pin上的分配器。如上述过程协商不成,输出Pin则创建一个自己的分配器,然后调用DecideBufferSize成功,调用输入Pin的NotifyAllocator,通知它最终使用的分配器(3)如果输入Pin接受此次连接,则成功