DirectShow过滤器开发-AAC解码器

下载本过滤器DLL
本过滤器将AAC音频流(包括MEDIASUBTYPE_RAW_AAC1和MEDIASUBTYPE_MPEG_ADTS_AAC)解码为PCM音频流,由输出引脚输出。

过滤器信息

过滤器名称:AAC解码器
过滤器GUID:{477E9EEA-F517-4DA2-8C7F-F6DA07D163E3}
DLL注册函数名:DllRegisterServer
删除注册函数名:DllUnregisterServer
过滤器有1个输入引脚和1个输出引脚。

输入引脚标识:In
输入引脚媒体类型:
主要类型:MEDIATYPE_Audio
子类型:MEDIASUBTYPE_MPEG_HEAAC,MEDIASUBTYPE_RAW_AAC1,MEDIASUBTYPE_MPEG_ADTS_AAC
格式类型:FORMAT_WaveFormatEx

输出引脚标识:Out
输出引脚媒体类型:
主要类型:MEDIATYPE_Audio
子类型:MEDIASUBTYPE_PCM,MEDIASUBTYPE_IEEE_FLOAT
格式类型:FORMAT_WaveFormatEx
样本为固定大小。
不使用时间压缩。
样本为16位(PCM),或32位(FLOAT)。

AAC解码器开发信息

过滤器从CCritSec,CBaseFilter,ISpecifyPropertyPages接口和自定义接口IMy010派生。ISpecifyPropertyPages接口用于显示属性页。自定义接口IMy010用于获取和指定输入有效负载类型(仅子类型为MEDIASUBTYPE_MPEG_HEAAC时)。
输入引脚从CBaseInputPin类派生。输出引脚从CBaseOutputPin派生,输出引脚实现了IMediaSeeking接口查询,实现了CPosPassThru对象,用于向上游过滤器输出引脚传递Seek命令。
创建了两个属性页。
输入属性页,在输入引脚没有连接时,属性页列表显示所有允许的输入媒体类型,双击MEDIASUBTYPE_MPEG_HEAAC项,可以指定有效负载类型;如果连接了输入引脚,属性页列表显示输入引脚当前媒体类型。
输出属性页,在输入引脚已经连接,输出引脚没有连接时,属性页列表显示所有允许的输出媒体类型;如果连接了输出引脚,属性页列表显示输出引脚当前媒体类型。
使用CoCreateInstance函数创建AAC音频解码器对象,其为媒体基础转换,接口为IMFTransform。在输入引脚的接收函数中,将引脚样本转换为媒体基础样本,使用IMFTransform接口的ProcessInput方法,向AAC音频解码器传递输入数据;使用IMFTransform接口的ProcessOutput方法获取AAC解码器输出数据。输出为媒体基础样本,将其转换为引脚样本,由输出引脚输出。AAC解码器需多个输入才可获得1个输出,通过检测ProcessInput返回值,确定是否还可以传递输入。

AAC解码器DLL的所有代码

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

#include "mfapi.h"
#include "mftransform.h"
#pragma comment(lib, "mfplat")
#pragma comment(lib, "mfuuid")

#include "wmcodecdsp.h"

// {477E9EEA-F517-4DA2-8C7F-F6DA07D163E3}
DEFINE_GUID(CLSID_AACDecoder,//过滤器GUID
	0x477e9eea, 0xf517, 0x4da2, 0x8c, 0x7f, 0xf6, 0xda, 0x7, 0xd1, 0x63, 0xe3);

// {14306A5F-2CBA-4C8C-8B5D-1ABED8EF14DB}
DEFINE_GUID(CLSID_PropertyPage1,//属性页1GUID
	0x14306a5f, 0x2cba, 0x4c8c, 0x8b, 0x5d, 0x1a, 0xbe, 0xd8, 0xef, 0x14, 0xdb);

// {9BB2E6D5-E0AA-445D-90A2-8B4FE2822E3C}
DEFINE_GUID(CLSID_PropertyPage2,//属性页2GUID
	0x9bb2e6d5, 0xe0aa, 0x445d, 0x90, 0xa2, 0x8b, 0x4f, 0xe2, 0x82, 0x2e, 0x3c);

// {5265D468-9A5F-43FF-A02D-BCEF20B6315D}
DEFINE_GUID(IID_IMy010,
	0x5265d468, 0x9a5f, 0x43ff, 0xa0, 0x2d, 0xbc, 0xef, 0x20, 0xb6, 0x31, 0x5d);

interface IMy010 : public IUnknown
{
	virtual HRESULT GetPAYLOAD(UINT32* mPayload) = 0;
	virtual HRESULT SetPAYLOAD(UINT32 mPayload) = 0;
};

class CFilter;
class COutPin;

class CInPin : public CBaseInputPin
{
	friend class COutPin;
	friend class CFilter;
public:
	CInPin(CFilter *pFilter, HRESULT *phr, LPCWSTR pPinName);
	~CInPin();
	HRESULT CheckMediaType(const CMediaType *pmt);
	HRESULT SetMediaType(const CMediaType *pmt);
	STDMETHODIMP Receive(IMediaSample *pSample);
	STDMETHODIMP EndOfStream();
	STDMETHODIMP BeginFlush();
	STDMETHODIMP EndFlush();
	STDMETHODIMP NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate);
	HRESULT GetOut();
	CFilter *pCFilter;
	ULONGLONG CUR=0;//当前样本的起始时间,单位毫秒
	ULONGLONG STAR = 0;//段起始时间,单位毫秒
	ULONGLONG DUR = 0;//单个样本持续时间,单位毫秒
	UINT32 PAYLOAD_TYPE = 0;//有效负载类型,仅适用于MEDIASUBTYPE_MPEG_HEAAC
};

class COutPin : public CBaseOutputPin
{
	friend class CInPin;
	friend class CFilter;
	IUnknown   *m_pPosition = NULL;
	COutputQueue *m_pOutputQueue = NULL;//样本队列
public:
	COutPin(CFilter *pFilter, HRESULT *phr, LPCWSTR pPinName);
	~COutPin();
	STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppvoid);
	HRESULT GetMediaType(int iPosition, CMediaType *pMediaType);
	HRESULT SetMediaType(const CMediaType* pmt);
	HRESULT CheckMediaType(const CMediaType *pmt);
	HRESULT DecideBufferSize(IMemAllocator *pMemAllocator, ALLOCATOR_PROPERTIES * ppropInputRequest);
	HRESULT Active();
	HRESULT Inactive();
	STDMETHODIMP Receive(IMediaSample *pSample);
	HRESULT Deliver(IMediaSample *pMediaSample);
	HRESULT DeliverEndOfStream();
	HRESULT DeliverBeginFlush();
	HRESULT DeliverEndFlush();
	HRESULT DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate);
	STDMETHODIMP Notify(IBaseFilter *pSender, Quality q);
	CFilter *pCFilter = NULL;
};

class CFilter : public CCritSec, public CBaseFilter, public ISpecifyPropertyPages, public IMy010
{
	friend class CInPin;
	friend class COutPin;
public:
	CFilter(TCHAR* pName, LPUNKNOWN pUnk, HRESULT* hr);
	~CFilter();
	CBasePin* GetPin(int n);
	int GetPinCount();
	static CUnknown* WINAPI CreateInstance(LPUNKNOWN pUnk, HRESULT* phr);
	DECLARE_IUNKNOWN
	STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv);
	virtual HRESULT Get(CBaseFilter** ppF);
	STDMETHODIMP GetPages(CAUUID *pPages)
	{
		if (pPages == NULL) return E_POINTER;
		pPages->cElems = 2;
		pPages->pElems = (GUID*)CoTaskMemAlloc(sizeof(GUID) * 2);
		if (pPages->pElems == NULL)
		{
			return E_OUTOFMEMORY;
		}
		pPages->pElems[0] = CLSID_PropertyPage1;
		pPages->pElems[1] = CLSID_PropertyPage2;
		return S_OK;
	}
	HRESULT GetPAYLOAD(UINT32* mPayload);
	HRESULT SetPAYLOAD(UINT32 mPayload);
	CInPin* pCInPin = NULL;
	COutPin* pCOutPin = NULL;
	IMFTransform *pAACDecoder = NULL;
	ULONGLONG SCUR = 0;//“当前时间”公共变量
};

class CPropertyPage1 : public CBasePropertyPage
{
	friend class CFilter;
	friend class CInPin;
public:
	CPropertyPage1(IUnknown *pUnk);
	~CPropertyPage1();
	static CUnknown * WINAPI CreateInstance(LPUNKNOWN pUnk, HRESULT *pHr);
	virtual HRESULT OnConnect(IUnknown *pUnknown);
	virtual HRESULT OnDeactivate();
	virtual HRESULT OnActivate();//用于初始化属性页对话框
	virtual INT_PTR OnReceiveMessage(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);//接收属性页对话框的消息
	WCHAR* DefineFromGUID(GUID guid);//获取GUID定义字符串
	LPWSTR GetFormatString(WAVEFORMATEX* p);//获取格式块描述字符串
	void SetDirty()
	{
		m_bDirty = TRUE;
		if (m_pPageSite)
		{
			m_pPageSite->OnStatusChange(PROPPAGESTATUS_DIRTY);
		}
	}
	HRESULT OnApplyChanges(void);
	CFilter *pCFilter = NULL;
	HWND hList, hEdit, hText1, hText2, hText3;
	HFONT hFont1, hFont2;
	HWND hE1;//“当前位置“”编辑框窗口句柄
	HWND hE2;//“当前样本”编辑框窗口句柄
	HANDLE hThread = NULL;
};

class CPropertyPage2 : public CBasePropertyPage
{
	friend class CFilter;
	CFilter* pCFilter = NULL;
public:
	CPropertyPage2(IUnknown *pUnk);
	~CPropertyPage2();
	static CUnknown * WINAPI CreateInstance(LPUNKNOWN pUnk, HRESULT *pHr);
	virtual HRESULT OnConnect(IUnknown *pUnknown);
	virtual HRESULT OnActivate();//用于初始化属性页对话框
	virtual INT_PTR OnReceiveMessage(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);//接收属性页对话框的消息
	LPWSTR DefineFromGUID(GUID guid);//获取GUID定义字符串
	LPWSTR GetFormatString(WAVEFORMATEX* p, LPWSTR& lPChannels, LPWSTR& lPAvgBytesPerSec);//获取格式块描述字符串
	HRESULT GetOutAvailableType(BOOL Init);//获取输出允许类型,参数为TRUE,标记初始化组合框2;FALSE不对组合框2进行任何操作
	void SetList(AM_MEDIA_TYPE* PMT, WAVEFORMATEX* PWF, BOOL Init);
	void SetDirty()
	{
		m_bDirty = TRUE;
		if (m_pPageSite)
		{
			m_pPageSite->OnStatusChange(PROPPAGESTATUS_DIRTY);
		}
	}
	HWND hList, hEdit, hCombox1, hCombox2, hText1, hText2;//
	HFONT hFont1, hFont2;
};


template <class T> void SafeRelease(T** ppT)
{
	if (*ppT)
	{
		(*ppT)->Release();
		*ppT = NULL;
	}
}

#endif //DLL_FILE

DLL源文件:DLL.cpp

#include "DLL.h"
#include "wmcodecdsp.h"


const AMOVIESETUP_MEDIATYPE InPinType[] =   // 输入引脚媒体类型
{
	{
	    &MEDIATYPE_Audio,                //主要类型
	    &MEDIASUBTYPE_MPEG_HEAAC         //子类型
	},
	{
		&MEDIATYPE_Audio,                //主要类型
		&MEDIASUBTYPE_RAW_AAC1           //子类型
	},
	{
		&MEDIATYPE_Audio,                //主要类型
		&MEDIASUBTYPE_MPEG_ADTS_AAC      //子类型
	}
};

const AMOVIESETUP_MEDIATYPE OutPinType[] =   // 输出引脚媒体类型
{
	{
		&MEDIATYPE_Audio,              //主要类型
	    &MEDIASUBTYPE_PCM              //子类型
	},
	{
		&MEDIATYPE_Audio,             //主要类型
		&MEDIASUBTYPE_IEEE_FLOAT      //子类型
	}
};

const AMOVIESETUP_PIN sudPins[] =  // 引脚信息
{
	{
		(LPWSTR)"In",               //引脚名称
		FALSE,                      //渲染过滤器
	    FALSE,                      //输出引脚
	    FALSE,                      //具有该引脚的零个实例
	    FALSE,                      //可以创建一个以上引脚的实例
	    &CLSID_NULL,                //该引脚连接的过滤器的类标识
	    NULL,                       //该引脚连接的引脚名称
	    3,                          //引脚支持的媒体类型数
	    InPinType                   //媒体类型信息
	},
	{
		(LPWSTR)"Out",              //引脚名称
		FALSE,                      //渲染过滤器
	    TRUE,                       //输出引脚
	    FALSE,                      //具有该引脚的零个实例
	    FALSE,                      //可以创建一个以上引脚的实例
	    &CLSID_NULL,                //该引脚连接的过滤器的类标识
	    NULL,                       //该引脚连接的引脚名称
	    2,                          //引脚支持的媒体类型数
	    OutPinType                  //媒体类型信息
	}
};

const AMOVIESETUP_FILTER AACDecoder =  //过滤器的注册信息
{
	&CLSID_AACDecoder,            //过滤器的类标识
	L"AAC解码器",                 //过滤器的名称
	MERIT_DO_NOT_USE,            //过滤器优先值
	2,                           //引脚数量
	sudPins                      //引脚信息
};

CFactoryTemplate g_Templates[] =   //类工厂模板数组
{
	{
		L"AAC解码器",               //过滤器名称
		&CLSID_AACDecoder,         //过滤器CLSID的指针
	    CFilter::CreateInstance,   //创建过滤器实例的函数的指针
	    NULL,                      //指向从DLL入口点调用的函数的指针
	    &AACDecoder                //指向AMOVIESETUP_FILTER结构的指针
	},
	{
		L"属性页1",                        //对象名称
		&CLSID_PropertyPage1,             //对象CLSID的指针
	    CPropertyPage1::CreateInstance,   //对象创建函数
	    NULL,                             //DLL入口点调用的函数
	    NULL                              //包含注册信息的AMOVIESETUP_FILTER结构
	},
	{
		L"属性页2",                        //对象名称
		&CLSID_PropertyPage2,             //对象CLSID的指针
	    CPropertyPage2::CreateInstance,   //对象创建函数
	    NULL,                             //DLL入口点调用的函数
	    NULL                              //包含注册信息的AMOVIESETUP_FILTER结构
	}
};

int g_cTemplates = 3;//模板数组大小

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"

CFilter::CFilter(TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr) : CBaseFilter(NAME("AAC解码器"), pUnk, this, CLSID_AACDecoder)
{
	HRESULT hr = MFStartup(MF_VERSION);//初始化媒体基础
	if (hr != S_OK)
	{
		MessageBox(NULL, L"初始化媒体基础失败", L"AAC解码器", MB_OK); return;
	}
	GUID CLSID_AACDecoderMft = { 0x32d186a7, 0x218f, 0x4c75, 0x88, 0x76, 0xdd, 0x77, 0x27, 0x3a, 0x89, 0x99 };//AAC解码器的类标识符
	hr = CoCreateInstance(CLSID_AACDecoderMft, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pAACDecoder));//创建AAC音频解码器(媒体基础转换)
	if (hr != S_OK)
	{
		MessageBox(NULL, L"AAC音频解码器创建失败", L"AAC解码器", MB_OK); return;
	}
	pCInPin = new CInPin(this, phr, L"In");//创建输入引脚
	pCOutPin = new COutPin(this, phr, L"Out");//创建输出引脚
}

CFilter::~CFilter()
{
	SafeRelease(&pAACDecoder);
	MFShutdown();//关闭媒体基础
}

CBasePin *CFilter::GetPin(int n)
{
	if (n == 0)return pCInPin;
	if (n == 1)return pCOutPin;
	return NULL;
}

int CFilter::GetPinCount()
{
	return 2;
}

CUnknown * WINAPI CFilter::CreateInstance(LPUNKNOWN pUnk, HRESULT *phr)
{
	return new CFilter(NAME("AAC解码器"), pUnk, phr);
}

STDMETHODIMP CFilter::NonDelegatingQueryInterface(REFIID riid, void **ppv)
{
	CheckPointer(ppv, E_POINTER);
	if (riid == IID_ISpecifyPropertyPages)
	{
		return GetInterface((ISpecifyPropertyPages*) this, ppv);
	}
	if (riid == IID_IMy010)
	{
		return GetInterface((IMy010*) this, ppv);
	}
	return CBaseFilter::NonDelegatingQueryInterface(riid, ppv);
}

HRESULT CFilter::Get(CBaseFilter** ppF)
{
	*ppF = this;
	return S_OK;
}

HRESULT CFilter::GetPAYLOAD(UINT32* mPayload)
{
	*mPayload = pCInPin->PAYLOAD_TYPE;
	return S_OK;
}

HRESULT CFilter::SetPAYLOAD(UINT32 mPayload)
{
	if (mPayload != 0 && mPayload != 1 && mPayload != 3)return S_FALSE;
	pCInPin->PAYLOAD_TYPE = mPayload;
	return S_OK;
}

输入引脚源文件:CInPin.cpp

#include "DLL.h"
#include "mferror.h"


CInPin::CInPin(CFilter *pFilter, HRESULT *phr, LPCWSTR pPinName) : CBaseInputPin(NAME("In"), pFilter, pFilter, phr, pPinName)
{
	pCFilter = pFilter;
}

CInPin::~CInPin()
{

}

HRESULT CInPin::CheckMediaType(const CMediaType *pmt)
{
	if (pmt->majortype == MEDIATYPE_Audio)
	{
		if (pmt->subtype == MEDIASUBTYPE_MPEG_HEAAC)return S_OK;
		if (pmt->subtype == MEDIASUBTYPE_RAW_AAC1)return S_OK;
		if (pmt->subtype == MEDIASUBTYPE_MPEG_ADTS_AAC)return S_OK;
	}
	return S_FALSE;
}

HRESULT CInPin::SetMediaType(const CMediaType *pmt)
{
	WAVEFORMATEX* pwf = (WAVEFORMATEX*)pmt->pbFormat;
	IMFMediaType* pMediaTypeIn = NULL;
	HRESULT hr = MFCreateMediaType(&pMediaTypeIn);//创建媒体类型
	hr = pMediaTypeIn->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio);//设置主要类型音频
	hr = pMediaTypeIn->SetGUID(MF_MT_SUBTYPE, pmt->subtype);//设置子类型
	hr = pMediaTypeIn->SetUINT32(MF_MT_AAC_PAYLOAD_TYPE, PAYLOAD_TYPE);//设置有效负载类型
	hr = pMediaTypeIn->SetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, pwf->wBitsPerSample);//设置每个样本的位数
	hr = pMediaTypeIn->SetUINT32(MF_MT_AUDIO_NUM_CHANNELS, pwf->nChannels);//设置通道数
	hr = pMediaTypeIn->SetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, pwf->nSamplesPerSec);//设置采样率
	if (pwf->cbSize)//如果有附加信息
		hr = pMediaTypeIn->SetBlob(MF_MT_USER_DATA, pmt->pbFormat + sizeof(WAVEFORMATEX), pwf->cbSize);//设置附加信息
	hr = pCFilter->pAACDecoder->SetInputType(NULL, pMediaTypeIn, 0);
	SafeRelease(&pMediaTypeIn);//释放输入媒体类型
	if (hr == S_OK)
		return CBasePin::SetMediaType(pmt);
	else
		return S_FALSE;
}

STDMETHODIMP CInPin::Receive(IMediaSample *pSample)
{
	HRESULT hr;
	BYTE* pBy = NULL;
	hr = pSample->GetPointer(&pBy);//获取引脚样本缓冲区指针
	long len = pSample->GetActualDataLength();//获取引脚样本有效数据长度
	REFERENCE_TIME star, end;
	hr = pSample->GetTime(&star, &end);//获取引脚样本时间戳

CreateBuffer:
	IMFMediaBuffer* pMFBuffer = NULL;
	hr = MFCreateMemoryBuffer(len, &pMFBuffer);//创建媒体基础缓冲区
	if (hr != S_OK || pMFBuffer == NULL)//如果创建失败
	{
		Sleep(1); goto CreateBuffer;//再次创建
	}
	BYTE* pData = NULL;
	hr = pMFBuffer->Lock(&pData, NULL, NULL);//锁定媒体基础缓冲区
	CopyMemory(pData, pBy, len);//从引脚样本缓冲区,复制数据到媒体基础样本缓冲区
	hr = pMFBuffer->Unlock();//解锁媒体基础缓冲区
	hr = pMFBuffer->SetCurrentLength((DWORD)len);//设置媒体基础缓冲区的数据长度
CreateSample:
	IMFSample* pMFSample = NULL;
	if (SUCCEEDED(hr))
	{
		hr = MFCreateSample(&pMFSample);//创建媒体基础样本
		if (hr != S_OK || pMFSample == NULL)//如果创建失败
		{
			Sleep(1); goto CreateSample;//再次创建
		}
	}
	hr = pMFSample->AddBuffer(pMFBuffer);//添加缓冲区到媒体基础样本
	REFERENCE_TIME dur = end - star;
	if (hr == S_OK)//
	{
		hr = pMFSample->SetSampleTime(star);//设置媒体基础样本显示时间
		hr = pMFSample->SetSampleDuration(dur);//设置媒体基础样本持续时间
	}
RePut:
	hr = pCFilter->pAACDecoder->ProcessInput(NULL, pMFSample, 0);//向AAC音频编码器传递输入数据
	if (hr == S_OK)//如果传递输入成功
	{
		SafeRelease(&pMFBuffer); SafeRelease(&pMFSample);//释放媒体基础缓冲区,媒体基础样本
		return S_OK;//继续下一次传递输入
	}
	if (MF_E_NOTACCEPTING == hr)//如果不可以传递输入。MF_E_NOTACCEPTING表示已不能接收更多输入
	{
		GetOut();//获取编码器输出
		goto RePut;//传递输入失败时,需将此次的样本再次传递到输入
	}
	return S_OK;
}

HRESULT CInPin::GetOut()//获取编码器输出
{
CreateOutBuffer:
	IMFMediaBuffer* pMFOutBuffer = NULL;
	HRESULT hr = MFCreateMemoryBuffer(1000000, &pMFOutBuffer);//创建输出媒体基础缓冲区,大小1M
	if (hr != S_OK || pMFOutBuffer == NULL)//如果创建失败
	{
		Sleep(1); goto CreateOutBuffer;//再次创建
	}
	BYTE* pD = NULL;
	hr = pMFOutBuffer->Lock(&pD, NULL, NULL);
CreateOutSample:
	IMFSample* pMFOutSample = NULL;
	if (SUCCEEDED(hr))
	{
		hr = MFCreateSample(&pMFOutSample);//创建输出媒体基础样本
		if (hr != S_OK || pMFOutSample == NULL)//如果创建失败
		{
			Sleep(1); goto CreateOutSample;//再次创建
		}
	}
	hr = pMFOutSample->AddBuffer(pMFOutBuffer);//添加缓冲区到媒体基础样本

	MFT_OUTPUT_DATA_BUFFER OD;
	OD.dwStreamID = NULL;
	OD.pSample = pMFOutSample;//须为MP3编码器指定输出样本
	OD.dwStatus = 0;
	OD.pEvents = NULL;
	DWORD status = 0;
	hr = pCFilter->pAACDecoder->ProcessOutput(MFT_PROCESS_OUTPUT_DISCARD_WHEN_NO_BUFFER, 1, &OD, &status);//获取MP3编码器输出数据。MP3编码器将输出数据,输出到刚才创建的输出样本的缓冲区内
	if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT)//如果MFT需要更多的输入数据,此时已不可获取输出
	{
		SafeRelease(&pMFOutBuffer); SafeRelease(&pMFOutSample); SafeRelease(&OD.pEvents);//释放媒体基础缓冲区,媒体基础样
		return S_OK;
	}
	if (hr == S_OK)//如果成功获得输出数据
	{
		LONGLONG s, d;
		hr = pMFOutSample->GetSampleTime(&s);//获取MP3编码器输出样本开始时间
		hr = pMFOutSample->GetSampleDuration(&d);//获取MP3编码器输出样本持续时间
		DWORD L;
		hr = pMFOutSample->GetTotalLength(&L);//获取MP3编码器输出样本有效数据长度
		IMediaSample *pOutSample = NULL;
		hr = pCFilter->pCOutPin->GetDeliveryBuffer(&pOutSample, NULL, NULL, 0);//获取一个空的输出引脚样本
		if (hr == S_OK)
		{
			BYTE* pOutBuffer = NULL;
			hr = pOutSample->GetPointer(&pOutBuffer);//获取输出引脚样本缓冲区指针
			CopyMemory(pOutBuffer, pD, L);//从MP3编码器输出样本缓冲区复制数据,到输出引脚样本缓冲区
			hr = pMFOutBuffer->Unlock();
			REFERENCE_TIME sOut = s, eOut = s + d;
			hr = pOutSample->SetTime(&sOut, &eOut);//设置输出引脚样本时间戳
			hr = pOutSample->SetActualDataLength(L);//设置输出引脚样本有效数据长度
			hr = pCFilter->pCOutPin->Deliver(pOutSample);//输出引脚向下游发送样本
			pOutSample->Release();//释放输出引脚样本
			if (DUR == 0)DUR = d / 10000;
			if ((ULONGLONG)s > CUR)
			{
				CUR = (ULONGLONG)(s / 10000);
				InterlockedExchange(&pCFilter->SCUR, CUR + STAR);
			}
		}
	}
	SafeRelease(&pMFOutBuffer); SafeRelease(&pMFOutSample); SafeRelease(&OD.pEvents);//释放媒体基础缓冲区,媒体基础样本
	goto CreateOutBuffer;//再次获取输出,直到不可获取为止
	return S_OK;
}

STDMETHODIMP CInPin::EndOfStream()
{
	return pCFilter->pCOutPin->DeliverEndOfStream();
}

STDMETHODIMP CInPin::BeginFlush()
{
	HRESULT hr = S_OK;
	hr = pCFilter->pCOutPin->DeliverBeginFlush();
	if (FAILED(hr))
		return hr;
	return CBaseInputPin::BeginFlush();
}

STDMETHODIMP CInPin::EndFlush()
{
	HRESULT hr = S_OK;
	hr = pCFilter->pCOutPin->DeliverEndFlush();
	if (FAILED(hr))
		return hr;
	return CBaseInputPin::EndFlush();
}

STDMETHODIMP CInPin::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
{
	STAR = tStart / 10000; CUR = 0;
	HRESULT hr = S_OK;
	hr = pCFilter->pCOutPin->DeliverNewSegment(tStart, tStop, dRate);
	if (FAILED(hr))
		return hr;
	return CBaseInputPin::NewSegment(tStart, tStop, dRate);
}

输出引脚源文件:COutPin.cpp

#include "DLL.h"

COutPin::COutPin(CFilter *pFilter, HRESULT *phr, LPCWSTR pPinName) : CBaseOutputPin(NAME("Out"), pFilter, pFilter, phr, pPinName)
{
	pCFilter = pFilter;
}

COutPin::~COutPin()
{
	SafeRelease(&m_pPosition);
}

STDMETHODIMP COutPin::NonDelegatingQueryInterface(REFIID riid, void **ppv)
{
	CheckPointer(ppv, E_POINTER);
	ASSERT(ppv);
	*ppv = NULL;
	HRESULT hr = NOERROR;
	if (riid == IID_IMediaPosition || riid == IID_IMediaSeeking)
	{
		if (m_pPosition == NULL)
		{
			hr = CreatePosPassThru(GetOwner(), FALSE, (IPin *)pCFilter->pCInPin, &m_pPosition);
			if (FAILED(hr)) return hr;
		}
		return m_pPosition->QueryInterface(riid, ppv);
	}
	return CBaseOutputPin::NonDelegatingQueryInterface(riid, ppv);
}

HRESULT COutPin::GetMediaType(int iPosition, CMediaType *pMediaType)
{
	if (iPosition < 0)return E_INVALIDARG;
	IMFMediaType *pOutType = NULL;//输出媒体类型
	int index = 0;
	while (S_OK == pCFilter->pAACDecoder->GetOutputAvailableType(NULL, index, &pOutType))
	{
		AM_MEDIA_TYPE* PMT;
		HRESULT hr = pOutType->GetRepresentation(AM_MEDIA_TYPE_REPRESENTATION, (void**)&PMT);//将IMFMediaType媒体类型转换为AM_MEDIA_TYPE结构表示的媒体类型
		if (iPosition == index)
		{
			*pMediaType = (CMediaType)*PMT;
			hr = pOutType->FreeRepresentation(AM_MEDIA_TYPE_REPRESENTATION, PMT);//释放GetRepresentation获得的内存
			SafeRelease(&pOutType);//释放输出媒体类型
			return S_OK;
		}
		hr = pOutType->FreeRepresentation(AM_MEDIA_TYPE_REPRESENTATION, PMT);//释放GetRepresentation获得的内存
		SafeRelease(&pOutType);//释放输出媒体类型
		index++;
	}
	if (iPosition > index)return VFW_S_NO_MORE_ITEMS;
	return S_FALSE;
}

HRESULT COutPin::SetMediaType(const CMediaType* pmt)
{
	AM_MEDIA_TYPE* pMt = (AM_MEDIA_TYPE*)pmt;
	IMFMediaType* pOutType = NULL;//输入媒体类型
	HRESULT hr = MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, pMt, &pOutType);//从AM_MEDIA_TYPE结构创建媒体基础媒体类型
	hr = pCFilter->pAACDecoder->SetOutputType(NULL, pOutType, 0);//设置AAC解码器输出媒体类型
	if (hr == S_OK)
	{
		SafeRelease(&pOutType);//释放输出媒体类型
		return CBasePin::SetMediaType(pmt);
	}
	SafeRelease(&pOutType);//释放输出媒体类型
	return S_FALSE;
}

HRESULT COutPin::CheckMediaType(const CMediaType *pmt)
{
	if (pCFilter->pCInPin->IsConnected() == FALSE)//如果输入引脚没有连接
	{
		MessageBox(NULL, L"须先连接输入引脚", L"AAC解码器", MB_OK); return S_FALSE;
	}
	IMFMediaType *pOutType = NULL;//输出媒体类型
	int index = 0;
	while (S_OK == pCFilter->pAACDecoder->GetOutputAvailableType(NULL, index, &pOutType))
	{
		AM_MEDIA_TYPE* PMT;
		HRESULT hr = pOutType->GetRepresentation(AM_MEDIA_TYPE_REPRESENTATION, (void**)&PMT);//将IMFMediaType媒体类型转换为AM_MEDIA_TYPE结构表示的媒体类型
		if(pmt->MatchesPartial((CMediaType*)PMT))
		{
			hr = pOutType->FreeRepresentation(AM_MEDIA_TYPE_REPRESENTATION, PMT);//释放GetRepresentation获得的内存
			SafeRelease(&pOutType);//释放输出媒体类型
			return S_OK;
		}
		hr = pOutType->FreeRepresentation(AM_MEDIA_TYPE_REPRESENTATION, PMT);//释放GetRepresentation获得的内存
		SafeRelease(&pOutType);//释放输出媒体类型
		index++;
	}
	return S_FALSE;
}

HRESULT COutPin::DecideBufferSize(IMemAllocator *pMemAllocator, ALLOCATOR_PROPERTIES * ppropInputRequest)//确定输出引脚样本缓冲区大小
{
	HRESULT hr = S_OK;
	ppropInputRequest->cBuffers = 1;//1个缓冲区
	ppropInputRequest->cbBuffer = 1000000;//缓冲区的大小
	ALLOCATOR_PROPERTIES Actual;
	hr = pMemAllocator->SetProperties(ppropInputRequest, &Actual);
	if (FAILED(hr))return hr;
	if (Actual.cbBuffer < ppropInputRequest->cbBuffer)// 这个分配器是否不合适
	{
		return E_FAIL;
	}
	ASSERT(Actual.cBuffers == 1);// 确保我们只有 1 个缓冲区
	return S_OK;
}

HRESULT COutPin::Active()
{
	HRESULT hr = NOERROR;
	if (m_Connected == NULL)
		return NOERROR;
	if (m_pOutputQueue == NULL)
	{
		m_pOutputQueue = new COutputQueue(m_Connected, &hr, TRUE, FALSE);
		if (m_pOutputQueue == NULL)
			return E_OUTOFMEMORY;
		if (FAILED(hr))
		{
			delete m_pOutputQueue;
			m_pOutputQueue = NULL;
			return hr;
		}
	}
	CBaseOutputPin::Active();
	return NOERROR;
}

HRESULT COutPin::Inactive()
{
	if (m_pOutputQueue)
	{
		delete m_pOutputQueue;
		m_pOutputQueue = NULL;
	}
	CBaseOutputPin::Inactive();
	return NOERROR;
}

HRESULT COutPin::Deliver(IMediaSample *pMediaSample)
{
	if (m_pOutputQueue == NULL)
		return NOERROR;
	pMediaSample->AddRef();
	return m_pOutputQueue->Receive(pMediaSample);
}

HRESULT COutPin::DeliverEndOfStream()
{
	if (m_pOutputQueue == NULL)
		return NOERROR;
	m_pOutputQueue->EOS();
	return NOERROR;
}

HRESULT COutPin::DeliverBeginFlush()
{
	if (m_pOutputQueue == NULL)
		return NOERROR;
	m_pOutputQueue->BeginFlush();
	return NOERROR;
}

HRESULT COutPin::DeliverEndFlush()
{
	if (m_pOutputQueue == NULL)
		return NOERROR;
	m_pOutputQueue->EndFlush();
	return NOERROR;
}

HRESULT COutPin::DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
{
	if (m_pOutputQueue == NULL)
		return NOERROR;
	m_pOutputQueue->NewSegment(tStart, tStop, dRate);
	return NOERROR;
}

STDMETHODIMP COutPin::Notify(IBaseFilter *pSender, Quality q)
{
	if (pCFilter->pCInPin->m_pQSink != NULL)
	{
		return pCFilter->pCInPin->m_pQSink->Notify(pCFilter, q);
	}
	else
	{
		HRESULT hr;
		IQualityControl * pIQC;
		hr = VFW_E_NOT_FOUND;
		if (pCFilter->pCInPin->m_Connected)
		{
			pCFilter->pCInPin->m_Connected->QueryInterface(IID_IQualityControl, (void**)&pIQC);
			if (pIQC != NULL)
			{
				hr = pIQC->Notify(pCFilter, q);
				pIQC->Release();
			}
		}
		return hr;
	}
	return NOERROR;
}

属性页1源文件:CPropertyPage1.cpp

#include "DLL.h"
#include "wchar.h"
#include "resource.h"
#include "stdio.h"
#include "wchar.h"
#include "commctrl.h "//列表视图控件使用


CPropertyPage1::CPropertyPage1(IUnknown *pUnk) : CBasePropertyPage(NAME("属性页1"), pUnk, IDD_DIALOG1, IDS_STRING103)
{
	hFont1 = CreateFont(20, 0, 0, 0, FW_NORMAL, 0, 0, 0, CHINESEBIG5_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, L"微软雅黑");
	hFont2 = CreateFont(15, 0, 0, 0, FW_NORMAL, 0, 0, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, L"Cambria");
}

CPropertyPage1::~CPropertyPage1()
{

}

CUnknown * WINAPI CPropertyPage1::CreateInstance(LPUNKNOWN pUnk, HRESULT *pHr)
{
	CPropertyPage1 *pNewObject = new CPropertyPage1(pUnk);
	if (pNewObject == NULL)
	{
		*pHr = E_OUTOFMEMORY;
	}
	return pNewObject;
}

HRESULT CPropertyPage1::OnConnect(IUnknown *pUnknown)
{
	if (pUnknown == NULL)
	{
		return E_POINTER;
	}
	IMy010* pIMy010 = NULL;
	HRESULT hr = pUnknown->QueryInterface(IID_IMy010, reinterpret_cast<void**>(&pIMy010));
	if (hr == S_OK)
	{
		pCFilter = (CFilter*)pIMy010;
		SafeRelease(&pIMy010);
	}
	return hr;
}

HRESULT CPropertyPage1::OnDeactivate()
{
	TerminateThread(hThread, 1);
	return S_OK;
}

DWORD WINAPI OnTimer(LPVOID lpParameter)
{
	CPropertyPage1* pPage1 = (CPropertyPage1*)lpParameter;
	while (TRUE)
	{
		ULONGLONG L = InterlockedExchange(&pPage1->pCFilter->SCUR, 0);
		int cur = (int)L / 1000;
		int shi = cur / 60 / 60;
		int fen = (cur / 60) % 60;
		int miao = cur % 60;
		char ch[500]; char ch2[40];
		sprintf_s(ch, 500, "%d时  %d分  %d秒", shi, fen, miao);
		ULONGLONG CurIndex;
		if (pPage1->pCFilter->pCInPin->DUR)
		{
			CurIndex = L / pPage1->pCFilter->pCInPin->DUR;
			sprintf_s(ch2, 40, "%I64u", CurIndex);
		}
		FILTER_STATE fs;
		pPage1->pCFilter->GetState(0, &fs);
		if (fs == State_Running)
		{
			SetWindowTextA(pPage1->hE1, ch); SetWindowTextA(pPage1->hE2, ch2);
		}
		Sleep(1000);
	}
	return 1;
}

HRESULT CPropertyPage1::OnActivate(void)
{
	hThread = CreateThread(NULL, 0, OnTimer, this, 0, NULL);
	ListView_SetExtendedListViewStyleEx(hList, LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES, LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);//整行选择,显示网格
	LVCOLUMN lvc;
	lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
	lvc.iSubItem = 0;
	lvc.pszText = L"序号";
	lvc.cx = 50;
	lvc.fmt = LVCFMT_LEFT;
	ListView_InsertColumn(hList, 0, &lvc);//插入第1列
	lvc.iSubItem = 1;
	lvc.pszText = L"主要类型";
	lvc.cx = 150;
	ListView_InsertColumn(hList, 1, &lvc);//插入第2列
	lvc.iSubItem = 2;
	lvc.pszText = L"子类型";
	lvc.cx = 200;
	ListView_InsertColumn(hList, 2, &lvc);//插入第3列
	lvc.iSubItem = 3;
	lvc.pszText = L"格式类型";
	lvc.cx = 170;
	ListView_InsertColumn(hList, 3, &lvc);//插入第4列
	lvc.iSubItem = 4;
	lvc.pszText = L"";
	lvc.cx = 0;
	ListView_InsertColumn(hList, 4, &lvc);//插入第5列,此列不显示文本,包含格式块描述文本
	int index = 0;
	IMFMediaType *pInType = NULL;//输入媒体类型
	if (pCFilter->pCInPin->IsConnected())//如果输入引脚已经连接
	{
		HRESULT hr = pCFilter->pAACDecoder->GetInputCurrentType(NULL, &pInType);//获取输入引脚当前媒体类型
		AM_MEDIA_TYPE* PMT;
		hr = pInType->GetRepresentation(AM_MEDIA_TYPE_REPRESENTATION, (void**)&PMT);//将IMFMediaType媒体类型转换为AM_MEDIA_TYPE结构表示的媒体类型
		if (hr == S_OK)
		{
			wchar_t wch[10];
			_itow_s(index + 1, wch, 10, 10);
			LVITEM lvI;
			lvI.mask = LVIF_TEXT;
			lvI.iItem = index;
			lvI.iSubItem = 0;
			lvI.pszText = wch;
			ListView_InsertItem(hList, &lvI);//插入项,项文本“序号”
			LPWSTR lp1 = DefineFromGUID(PMT->majortype);
			ListView_SetItemText(hList, index, 1, lp1);//设置子项1文本“主要类型”
			delete[] lp1;
			LPWSTR lp2 = DefineFromGUID(PMT->subtype);
			ListView_SetItemText(hList, index, 2, lp2);//设置子项2文本“子类型”
			wchar_t wch1[200];
			wcscpy_s(wch1, 200, lp2);
			delete[] lp2;
			LPWSTR lp3 = DefineFromGUID(PMT->formattype);
			ListView_SetItemText(hList, index, 3, lp3);//设置子项2文本“格式类型”
			delete[] lp3;
			WAVEFORMATEX* PWF = (WAVEFORMATEX*)PMT->pbFormat;
			LPWSTR lp4 = GetFormatString(PWF);//获取格式块描述字符串
			if (wcscoll(wch1, L"MEDIASUBTYPE_MPEG_HEAAC") == 0)
			{
				UINT32 PAYLOAD_TYPE;
				hr = pInType->GetUINT32(MF_MT_AAC_PAYLOAD_TYPE, &PAYLOAD_TYPE);//获取有效负载类型
				wchar_t wch[2000];
				swprintf_s(wch, 2000, L"有效负载类型=%u\r\n%s", PAYLOAD_TYPE, lp4);
				wcscpy_s(lp4, 2000, wch);
			}
			ListView_SetItemText(hList, index, 4, lp4);//设置子项3文本“格式类型”
			delete[] lp4;
			hr = pInType->FreeRepresentation(AM_MEDIA_TYPE_REPRESENTATION, PMT);//释放GetRepresentation获得的内存
		}
		SafeRelease(&pInType);//释放输出媒体类型
	}
	else//如果输入引脚没有连接
	{
		while (S_OK == pCFilter->pAACDecoder->GetInputAvailableType(NULL, index, &pInType))//获取输入引脚所有允许的媒体类型
		{
			AM_MEDIA_TYPE* PMT;
			HRESULT hr = pInType->GetRepresentation(AM_MEDIA_TYPE_REPRESENTATION, (void**)&PMT);//将IMFMediaType媒体类型转换为AM_MEDIA_TYPE结构表示的媒体类型
			if (hr == S_OK)
			{
				wchar_t wch[10];
				_itow_s(index + 1, wch, 10, 10);
				LVITEM lvI;
				lvI.mask = LVIF_TEXT;
				lvI.iItem = index;
				lvI.iSubItem = 0;
				lvI.pszText = wch;
				ListView_InsertItem(hList, &lvI);//插入项,项文本“序号”
				LPWSTR lp1 = DefineFromGUID(PMT->majortype);
				ListView_SetItemText(hList, index, 1, lp1);//设置子项1文本“主要类型”
				delete[] lp1;
				LPWSTR lp2 = DefineFromGUID(PMT->subtype);
				ListView_SetItemText(hList, index, 2, lp2);//设置子项2文本“子类型”
				wchar_t wch1[200];
				wcscpy_s(wch1, 200, lp2);
				delete[] lp2;
				LPWSTR lp3 = DefineFromGUID(PMT->formattype);
				ListView_SetItemText(hList, index, 3, lp3);//设置子项2文本“格式类型”
				delete[] lp3;
				WAVEFORMATEX* PWF = (WAVEFORMATEX*)PMT->pbFormat;
				LPWSTR lp4 = GetFormatString(PWF);//获取格式块描述字符串
				if (wcscoll(wch1, L"MEDIASUBTYPE_MPEG_HEAAC") == 0)
				{
					UINT32 PAYLOAD_TYPE;
					hr = pInType->GetUINT32(MF_MT_AAC_PAYLOAD_TYPE, &PAYLOAD_TYPE);//获取有效负载类型
					wchar_t wch[2000];
					swprintf_s(wch, 2000, L"有效负载类型=%u\r\n%s", PAYLOAD_TYPE, lp4);
					wcscpy_s(lp4, 2000, wch);
				}
				ListView_SetItemText(hList, index, 4, lp4);//设置子项3文本“格式类型”
				delete[] lp4;
				hr = pInType->FreeRepresentation(AM_MEDIA_TYPE_REPRESENTATION, PMT);//释放GetRepresentation获得的内存
			}
			SafeRelease(&pInType);//释放输出媒体类型
			index++;
		}
	}
	return 0;
}

INT_PTR CPropertyPage1::OnReceiveMessage(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	hList = GetDlgItem(m_Dlg, IDC_LIST2);//获取列表视图控件窗口句柄
	hEdit = GetDlgItem(m_Dlg, IDC_EDIT2);
	hText1 = GetDlgItem(m_Dlg, IDC_STA5);
	hText2 = GetDlgItem(m_Dlg, IDC_STA6);
	hText3 = GetDlgItem(m_Dlg, IDC_STA7);
	hE1 = GetDlgItem(m_Dlg, IDC_EDIT3);
	hE2 = GetDlgItem(m_Dlg, IDC_EDIT4);
	RECT rect; int w; LPNMITEMACTIVATE lpnmitem;
	switch (uMsg)
	{
	case WM_INITDIALOG://初始化属性页对话框
		GetClientRect(m_Dlg, &rect);
		w = rect.right - rect.left;
		MoveWindow(hList, 10, 10, w - 20, 210, 1); SendMessage(hList, WM_SETFONT, (WPARAM)hFont2, (LPARAM)1);
		MoveWindow(hEdit, 10, 230, w - 20, 200, 1); SendMessage(hEdit, WM_SETFONT, (WPARAM)hFont1, (LPARAM)1);
		MoveWindow(hText3, 17, 440, 160, 20, 1); SendMessage(hText3, WM_SETFONT, (WPARAM)hFont1, (LPARAM)1);
		MoveWindow(hText1, 10, 470, 78, 20, 1); SendMessage(hText1, WM_SETFONT, (WPARAM)hFont1, (LPARAM)1);
		MoveWindow(hE1, 90, 468, 180, 24, 1); SendMessage(hE1, WM_SETFONT, (WPARAM)hFont1, (LPARAM)1);
		MoveWindow(hText2, 10, 500, 78, 20, 1); SendMessage(hText2, WM_SETFONT, (WPARAM)hFont1, (LPARAM)1);
		MoveWindow(hE2, 90, 498, 180, 24, 1); SendMessage(hE2, WM_SETFONT, (WPARAM)hFont1, (LPARAM)1);
		return TRUE;
	case WM_NOTIFY:
		lpnmitem = (LPNMITEMACTIVATE)lParam; 
		if (lpnmitem->hdr.code == NM_CLICK && lpnmitem->hdr.idFrom == IDC_LIST2)//如果鼠标左键单击了列表某项
		{
			wchar_t wch[2000]; wmemset(wch, 0, 2000);
			ListView_GetItemText(lpnmitem->hdr.hwndFrom, lpnmitem->iItem, 4, wch, 2000);
			SetWindowText(hEdit, wch);
			return (INT_PTR)TRUE;
		}
		if (lpnmitem->hdr.code == NM_DBLCLK && lpnmitem->hdr.idFrom == IDC_LIST2)//如果鼠标左键双击了列表某项
		{
			if (!pCFilter->pCInPin->IsConnected())//如果输入引脚没有连接
			{
				wchar_t wch[200]; wmemset(wch, 0, 200);
				ListView_GetItemText(lpnmitem->hdr.hwndFrom, lpnmitem->iItem, 2, wch, 200);
				if (wcscoll(wch, L"MEDIASUBTYPE_MPEG_HEAAC") == 0)//如果子类型为MEDIASUBTYPE_MPEG_HEAAC
				{
					int index = 0; IMFMediaType* pInType = NULL;
					while (S_OK == pCFilter->pAACDecoder->GetInputAvailableType(NULL, index, &pInType))//获取输入引脚所有允许的媒体类型
					{
						if (lpnmitem->iItem == index)
						{
							HRESULT hr=pInType->GetUINT32(MF_MT_AAC_PAYLOAD_TYPE, &pCFilter->pCInPin->PAYLOAD_TYPE);//获取有效负载类型
							if (hr == S_OK)
							{
								SafeRelease(&pInType);
								SetDirty();
								return (INT_PTR)TRUE;
							}
						}
						SafeRelease(&pInType);
						index++;
					}
				}
			}
			return (INT_PTR)TRUE;
		}
		break;
	}
	return CBasePropertyPage::OnReceiveMessage(hwnd, uMsg, wParam, lParam);//让父类处理消息
}

HRESULT CPropertyPage1::OnApplyChanges(void)//应用更改
{
	char ch1[100];
	sprintf_s(ch1, "有效负载类型=%u", pCFilter->pCInPin->PAYLOAD_TYPE);
	char ch[500];
	sprintf_s(ch, 500, "已应用更改。新数据为:\r\n%s", ch1);
	MessageBoxA(0, ch, "AAC解码器", MB_OK);
	return S_OK;
}

WCHAR* CPropertyPage1::DefineFromGUID(GUID guid)//获取GUID定义字符串
{
	WCHAR* pW = new WCHAR[200];
	if (guid == MEDIATYPE_Audio)
	{
		wcscpy_s(pW, 200, L"MEDIATYPE_Audio");
		return pW;
	}
	if (guid == MEDIASUBTYPE_MPEG_HEAAC)
	{
		wcscpy_s(pW, 200, L"MEDIASUBTYPE_MPEG_HEAAC");
		return pW;
	}
	if (guid == MEDIASUBTYPE_RAW_AAC1)
	{
		wcscpy_s(pW, 200, L"MEDIASUBTYPE_RAW_AAC1");
		return pW;
	}
	if (guid == MEDIASUBTYPE_MPEG_ADTS_AAC)
	{
		wcscpy_s(pW, 200, L"MEDIASUBTYPE_MPEG_ADTS_AAC");
		return pW;
	}
	if (guid == FORMAT_WaveFormatEx)
	{
		wcscpy_s(pW, 200, L"FORMAT_WaveFormatEx");
		return pW;
	}
	delete[] pW;
	return NULL; 
}

LPWSTR CPropertyPage1::GetFormatString(WAVEFORMATEX* p)//获取格式块描述字符串
{
	LPWSTR lp = new wchar_t[2000];
	swprintf_s(lp, 2000, L"wFormatTag = %d;//编码方式\r\nnChannels = %d;//声道数\r\nnSamplesPerSec = %u;//采样率\r\nnAvgBytesPerSec = %u;//数据传输率\r\nnBlockAlign = %d;//块对齐\r\nwBitsPerSample = %d;//样本位数\r\ncbSize = %d;//附加信息大小",
		p->wFormatTag,
		p->nChannels,
		p->nSamplesPerSec,
		p->nAvgBytesPerSec,
		p->nBlockAlign,
		p->wBitsPerSample,
		p->cbSize);
	if (p->cbSize != 0)//如果有附加信息
	{
		wchar_t wch[500] = L"\r\n附加信息={", wch1[10];
		BYTE* pB = new BYTE[p->cbSize];
		BYTE* pS = (BYTE*)p + sizeof(WAVEFORMATEX);
		CopyMemory(pB, pS, p->cbSize);
		for (int i = 0; i < p->cbSize - 1; i++)
		{
			swprintf_s(wch1, 10, L"%d, ", pB[i]);
			wcscat_s(wch, 500, wch1);//在末尾添加字符串
		}
		swprintf_s(wch1, 10, L"%d}", pB[p->cbSize - 1]);
		wcscat_s(wch, 500, wch1);
		delete[] pB;
		wcscat_s(lp, 2000, wch);
	}
	return lp;
}

属性页2源文件:CPropertyPage2.cpp

#include "DLL.h"
#include "resource.h"
#include "wchar.h"
#include "commctrl.h "//列表视图控件使用
#include "stdio.h"

CPropertyPage2::CPropertyPage2(IUnknown *pUnk) : CBasePropertyPage(NAME("属性页2"), pUnk, IDD_DIALOG2, IDS_STRING102)
{
	hFont1 = CreateFont(20, 0, 0, 0, FW_NORMAL, 0, 0, 0, CHINESEBIG5_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, L"微软雅黑");
	hFont2 = CreateFont(15, 0, 0, 0, FW_NORMAL, 0, 0, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, L"Cambria");
}

CPropertyPage2::~CPropertyPage2()
{

}

CUnknown * WINAPI CPropertyPage2::CreateInstance(LPUNKNOWN pUnk, HRESULT *pHr)
{
	CPropertyPage2 *pNewObject = new CPropertyPage2(pUnk);
	if (pNewObject == NULL)
	{
		*pHr = E_OUTOFMEMORY;
	}
	return pNewObject;
}

HRESULT CPropertyPage2::OnConnect(IUnknown *pUnknown)
{
	if (pUnknown == NULL)
	{
		return E_POINTER;
	}
	IMy010* pIMy010 = NULL;
	HRESULT hr = pUnknown->QueryInterface(IID_IMy010, reinterpret_cast<void**>(&pIMy010));
	if (hr == S_OK)
	{
		pCFilter = (CFilter*)pIMy010;
		SafeRelease(&pIMy010);
	}
	return hr;
}

HRESULT CPropertyPage2::OnActivate(void)
{
	ListView_SetExtendedListViewStyleEx(hList, LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES, LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);//整行选择,显示网格
	LVCOLUMN lvc;
	lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
	lvc.iSubItem = 0;
	lvc.pszText = L"序号";
	lvc.cx = 50;
	lvc.fmt = LVCFMT_LEFT;
	ListView_InsertColumn(hList, 0, &lvc);//插入第1列
	lvc.iSubItem = 1;
	lvc.pszText = L"主要类型";
	lvc.cx = 130;
	ListView_InsertColumn(hList, 1, &lvc);//插入第2列
	lvc.iSubItem = 2;
	lvc.pszText = L"子类型";
	lvc.cx = 210;
	ListView_InsertColumn(hList, 2, &lvc);//插入第3列
	lvc.iSubItem = 3;
	lvc.pszText = L"格式类型";
	lvc.cx = 170;
	ListView_InsertColumn(hList, 3, &lvc);//插入第4列
	lvc.iSubItem = 4;
	lvc.pszText = L"";
	lvc.cx = 0;
	ListView_InsertColumn(hList, 4, &lvc);//插入第5列,此列不显示文本,包含格式块描述文本
	ComboBox_AddString(hCombox1, L"全部");  
	GetOutAvailableType(TRUE);
	ComboBox_SelectString(hCombox1, -1, L"全部"); ComboBox_SelectString(hCombox2, -1, L"全部");//选中”全部“项”
	return 0;
}

INT_PTR CPropertyPage2::OnReceiveMessage(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	hList = GetDlgItem(m_Dlg, IDC_LIST1);//获取列表视图控件窗口句柄
	hEdit = GetDlgItem(m_Dlg, IDC_EDIT1);//获取编辑框窗口句柄
	hCombox1 = GetDlgItem(m_Dlg, IDC_COMBO1);//获取声道数组合框窗口句柄
	hCombox2 = GetDlgItem(m_Dlg, IDC_COMBO2);//获取传输率组合框窗口句柄
	hText1 = GetDlgItem(m_Dlg, IDC_STA1);//获取“声道数”静态文本控件窗口句柄
	hText2 = GetDlgItem(m_Dlg, IDC_STA2);//获取“传输率”静态文本控件窗口句柄
	LPNMITEMACTIVATE lpnmitem; RECT rect; int w;
	switch (uMsg)
	{
	case WM_INITDIALOG://初始化属性页对话框
		GetClientRect(m_Dlg, &rect);
		w = rect.right - rect.left;
		MoveWindow(hText1, 10, 10, 110, 20, 1); SendMessage(hText1, WM_SETFONT, (WPARAM)hFont1, (LPARAM)1);
		MoveWindow(hCombox1, 130, 7, 90, 100, 1); SendMessage(hCombox1, WM_SETFONT, (WPARAM)hFont1, (LPARAM)1);
		MoveWindow(hText2, 230, 10, 80, 20, 1); SendMessage(hText2, WM_SETFONT, (WPARAM)hFont1, (LPARAM)1);
		MoveWindow(hCombox2, 315, 7, 120, 500, 1); SendMessage(hCombox2, WM_SETFONT, (WPARAM)hFont1, (LPARAM)1);
		MoveWindow(hList, 10, 43, w - 20, 280, 1); SendMessage(hList, WM_SETFONT, (WPARAM)hFont2, (LPARAM)1);
		MoveWindow(hEdit, 10, 333, w - 20, 200, 1); SendMessage(hEdit, WM_SETFONT, (WPARAM)hFont1, (LPARAM)1);
		return TRUE;
	case WM_NOTIFY:
		lpnmitem = (LPNMITEMACTIVATE)lParam;
		if (lpnmitem->hdr.code == NM_CLICK && lpnmitem->hdr.idFrom == IDC_LIST1 && lpnmitem->iItem != -1)//如果鼠标左键单击了列表的某项
		{
			wchar_t wch[2000]; wmemset(wch, 0, 2000);
			ListView_GetItemText(lpnmitem->hdr.hwndFrom, lpnmitem->iItem, 4, wch, 2000);
			SetWindowText(hEdit, wch);//将格式块说明文本显示在编辑框中
			return (INT_PTR)TRUE;
		}
		break;
	}
	return CBasePropertyPage::OnReceiveMessage(hwnd, uMsg, wParam, lParam);//让父类处理消息
}

HRESULT CPropertyPage2::GetOutAvailableType(BOOL Init)//获取输出允许类型,参数为TRUE,标记初始化组合框2;FALSE不对组合框2进行任何操作
{
	ListView_DeleteAllItems(hList);
	if (Init)
		ComboBox_AddString(hCombox2, L"全部");
	int index = 0; HRESULT hr;
	IMFMediaType *pOutType = NULL;//输出媒体类型
	if (pCFilter->pCOutPin->IsConnected())//如果输出引脚已经连接
	{
		hr = pCFilter->pAACDecoder->GetOutputCurrentType(NULL, &pOutType);
		if (hr == S_OK)
		{
			AM_MEDIA_TYPE* PMT;
			HRESULT hr = pOutType->GetRepresentation(AM_MEDIA_TYPE_REPRESENTATION, (void**)&PMT);//将IMFMediaType媒体类型转换为AM_MEDIA_TYPE结构表示的媒体类型
			if (hr == S_OK)
			{
				WAVEFORMATEX* PWF = (WAVEFORMATEX*)PMT->pbFormat;
				SetList(PMT, PWF, Init); //将媒体类型信息,添加到列表
				hr = pOutType->FreeRepresentation(AM_MEDIA_TYPE_REPRESENTATION, PMT);//释放GetRepresentation获得的内存
			}
		}
		SafeRelease(&pOutType);//释放输出媒体类型
	}
	else//如果输出引脚没有连接
	{
		while (S_OK == pCFilter->pAACDecoder->GetOutputAvailableType(NULL, index, &pOutType))
		{
			AM_MEDIA_TYPE* PMT;
			HRESULT hr = pOutType->GetRepresentation(AM_MEDIA_TYPE_REPRESENTATION, (void**)&PMT);//将IMFMediaType媒体类型转换为AM_MEDIA_TYPE结构表示的媒体类型
			if (hr == S_OK)
			{
				WAVEFORMATEX* PWF = (WAVEFORMATEX*)PMT->pbFormat;
				SetList(PMT, PWF, Init);//将媒体类型信息,添加到列表
				hr = pOutType->FreeRepresentation(AM_MEDIA_TYPE_REPRESENTATION, PMT);//释放GetRepresentation获得的内存
			}
			SafeRelease(&pOutType);//释放输出媒体类型
			index++;
		}
	}
	return S_OK;
}

void CPropertyPage2::SetList(AM_MEDIA_TYPE* PMT, WAVEFORMATEX* PWF, BOOL Init)//将媒体类型信息,添加到列表
{
	int index = ListView_GetItemCount(hList);
	wchar_t wch[10];
	_itow_s(index + 1, wch, 10, 10);
	LVITEM lvI;
	lvI.mask = LVIF_TEXT;
	lvI.iItem = index;
	lvI.iSubItem = 0;
	lvI.pszText = wch;
	ListView_InsertItem(hList, &lvI);//插入项,项文本“序号”
	LPWSTR lp1 = DefineFromGUID(PMT->majortype);
	ListView_SetItemText(hList, index, 1, lp1);//设置子项1文本“主要类型”
	delete[] lp1;
	LPWSTR lp2 = DefineFromGUID(PMT->subtype);
	ListView_SetItemText(hList, index, 2, lp2);//设置子项2文本“子类型”
	delete[] lp2;
	LPWSTR lp3 = DefineFromGUID(PMT->formattype);
	ListView_SetItemText(hList, index, 3, lp3);//设置子项2文本“格式类型”
	delete[] lp3;
	LPWSTR lp5 = NULL, lp6 = NULL;
	LPWSTR lp4 = GetFormatString(PWF, lp5, lp6);//获取格式块描述字符串
	ListView_SetItemText(hList, index, 4, lp4);//设置子项3文本“格式类型”
	delete[] lp4;
	if (CB_ERR == ComboBox_FindStringExact(hCombox2, -1, lp6) && Init)//如果组合框2中没有与lp6相同的字符串,只在Init为TRUE时,操作组合框2
	{
		ComboBox_AddString(hCombox2, lp6);
	}
	if (CB_ERR == ComboBox_FindStringExact(hCombox1, -1, lp5) && Init)//如果组合框1中没有与lp5相同的字符串,只在Init为TRUE时,操作组合框1
	{
		ComboBox_AddString(hCombox1, lp5);
	}
	delete[] lp5; delete[] lp6;
}

WCHAR* CPropertyPage2::DefineFromGUID(GUID guid)//获取GUID定义字符串
{
	WCHAR* pW = new WCHAR[200];
	if (guid == MEDIATYPE_Audio)
	{
		wcscpy_s(pW, 200, L"MEDIATYPE_Audio");
		return pW;
	}
	if (guid == MEDIASUBTYPE_PCM)
	{
		wcscpy_s(pW, 200, L"MEDIASUBTYPE_PCM");
		return pW;
	}
	if (guid == MEDIASUBTYPE_IEEE_FLOAT)
	{
		wcscpy_s(pW, 200, L"MEDIASUBTYPE_IEEE_FLOAT");
		return pW;
	}
	if (guid == MEDIASUBTYPE_MPEG_HEAAC)
	{
		wcscpy_s(pW, 200, L"MEDIASUBTYPE_MPEG_HEAAC");
		return pW;
	}
	if (guid == FORMAT_WaveFormatEx)
	{
		wcscpy_s(pW, 200, L"FORMAT_WaveFormatEx");
		return pW;
	}
	delete[] pW;
	return NULL;
}

LPWSTR CPropertyPage2::GetFormatString(WAVEFORMATEX* p, LPWSTR& lPChannels, LPWSTR& lPAvgBytesPerSec)//获取格式块描述字符串
{
	lPChannels = new wchar_t[8];
	swprintf_s(lPChannels, 8, L"%d", p->nChannels);//声道数字符串
	lPAvgBytesPerSec = new wchar_t[12];
	swprintf_s(lPAvgBytesPerSec, 12, L"%u", p->nAvgBytesPerSec);//传输率字符串
	LPWSTR lp = new wchar_t[2000];
	swprintf_s(lp, 2000, L"wFormatTag = %d;//编码方式\r\nnChannels = %d;//声道数\r\nnSamplesPerSec = %u;//采样率\r\nnAvgBytesPerSec = %u;//数据传输率\r\nnBlockAlign = %d;//块对齐\r\nwBitsPerSample = %d;//样本位数\r\ncbSize = %d;//附加信息大小",
		p->wFormatTag,
		p->nChannels,
		p->nSamplesPerSec,
		p->nAvgBytesPerSec,
		p->nBlockAlign,
		p->wBitsPerSample,
		p->cbSize);
	if (p->cbSize != 0)//如果有附加信息
	{
		wchar_t wch[500] = L"\r\n附加信息={", wch1[10];
		BYTE* pB = new BYTE[p->cbSize];
		BYTE* pS = (BYTE*)p + sizeof(WAVEFORMATEX);
		CopyMemory(pB, pS, p->cbSize);
		for (int i = 0; i < p->cbSize - 1; i++)
		{
			swprintf_s(wch1, 10, L"%d, ", pB[i]);
			wcscat_s(wch, 500, wch1);//在末尾添加字符串
		}
		swprintf_s(wch1, 10, L"%d}", pB[p->cbSize - 1]);
		wcscat_s(wch, 500, wch1);
		delete[] pB;
		wcscat_s(lp, 2000, wch);
	}
	return lp;
}

下载本过滤器DLL

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

h3974

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

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

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

打赏作者

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

抵扣说明:

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

余额充值