下载本过滤器
本过滤器将未压缩的PCM音频流编码为MP3音频流,由输出引脚输出。
过滤器信息
过滤器名称:MP3编码器
过滤器GUID: {CF320B80-C5B1-4867-8C89-6023E77DDD55}
DLL注册函数名:DllRegisterServer
删除注册函数名:DllUnregisterServer
过滤器有1个输入引脚,和一个输出引脚。
输入引脚标识:In
输入引脚媒体类型:
主要类型:MEDIATYPE_Audio
子类型:MEDIASUBTYPE_PCM
格式类型:FORMAT_WaveFormatEx
样本为固定大小。
不使用时间压缩。
样本为16位。
采样率:48000,44100,32000。
输出引脚标识:Out
输出引脚媒体类型:
主要类型:MEDIATYPE_Audio
子类型:{0x00000055, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
格式类型:FORMAT_WaveFormatEx
采样率等于输入采样率。
过滤器开发信息
过滤器类从CCritSec,CBaseFilter类和ISpecifyPropertyPages接口,自定义接口IMy008派生。输入引脚从CBaseInputPin派生。输出引脚从CBaseOutputPin派生。在过滤器构造函数中,使用CoCreateInstance函数创建MP3音频编码器,其为媒体基础转换(MFT),接口为IMFTransform。过滤器运行后,输入引脚的Receive方法被反复调用,在此方法中,接收上游引脚传递的样本,转换为媒体基础样本,使用IMFTransform::ProcessInput方法向编码器传递输入样本;然后,获取编码器的输出,输出以MFT_OUTPUT_DATA_BUFFER结构方式提供,需事先为结构的pSample参数提供一个媒体基础样本,编码器ProcessOutput方法调用后,媒体基础样本将包含编码器的输出数据。将其转换为引脚样本,由输出引脚向下游发送。
虽然本过滤器为编码器,仍有可能被串联在末端有音频渲染器的过滤器链中,故,在输出引脚添加了查询IMediaSeeking接口的方法(COutPin::NonDelegatingQueryInterface),在方法中,使用CreatePosPassThru函数创建一个CPosPassThru对象,该对象可以将Seek命令向上游过滤器的输出引脚传递。
创建了两页的属性页,属性页1在输入引脚连接后,可以显示输入引脚当前媒体类型。在过滤器运行时可以指示当前位置的时间和样本序号。属性页2,在输入输出引脚没有连接的情况下,可以显示MP3编码器所有可能的输出媒体类型,连接输入引脚后,可以显示输出引脚将使用的媒体类型(输出引脚连接后使用该媒体类型)。
MP3编码器不能更改采样率,即输出采样率等于输入采样率,采样率支持:48000,44100,32000;不能更改声道数量,即输出声道数等于输入声道数;MP3编码器要求先指定输出媒体类型,输出媒体类型必须是MP3编码器允许的输出类型之一。
InterlockedExchange函数,用于在不同线程中访问公共变量,不会引发访问冲突。
自定义接口IMy008用于获取和设置编码器输出比特率。
下面是本过滤器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")
// {CF320B80-C5B1-4867-8C89-6023E77DDD55}
DEFINE_GUID(CLSID_MP3Encoder,//过滤器GUID
0xcf320b80, 0xc5b1, 0x4867, 0x8c, 0x89, 0x60, 0x23, 0xe7, 0x7d, 0xdd, 0x55);
DEFINE_GUID(MEDIASUBTYPE_MP3,
0x00000055, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
// {AC505E71-ED56-4C18-8A2D-AE4B2AD8C8A3}
DEFINE_GUID(CLSID_PropertyPage1,//属性页1GUID
0xac505e71, 0xed56, 0x4c18, 0x8a, 0x2d, 0xae, 0x4b, 0x2a, 0xd8, 0xc8, 0xa3);
// {10490879-0252-44A0-AAE3-2FC098058832}
DEFINE_GUID(CLSID_PropertyPage2,//属性页2GUID
0x10490879, 0x252, 0x44a0, 0xaa, 0xe3, 0x2f, 0xc0, 0x98, 0x5, 0x88, 0x32);
// {6F0BAAE9-FDE3-496E-A6F2-70D6F31B3643}
DEFINE_GUID(IID_IMy008,
0x6f0baae9, 0xfde3, 0x496e, 0xa6, 0xf2, 0x70, 0xd6, 0xf3, 0x1b, 0x36, 0x43);
interface IMy008 : public IUnknown
{
virtual HRESULT GetBYTES(UINT32* mBytes) = 0;
virtual HRESULT SetBYTES(UINT32 mBytes) = 0;
};
template <class T> void SafeRelease(T** ppT)
{
if (*ppT)
{
(*ppT)->Release();
*ppT = NULL;
}
}
class COutPin;
class CFilter;
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;//单个样本持续时间,单位毫秒
};
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 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;
IMFMediaType* pOutType = NULL;
};
class CFilter : public CCritSec, public CBaseFilter, public ISpecifyPropertyPages, public IMy008
{
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 GetBYTES(UINT32* mBytes);
HRESULT SetBYTES(UINT32 mBytes);
CInPin* pCInPin = NULL;
COutPin* pCOutPin = NULL;
IMFTransform *pMP3Encoder = NULL;
UINT32 SAMPLES_PER_SECOND = 0;//采样率要求值
UINT32 NUM_CHANNELS = 0;//声道数要求值
UINT32 BYTES_PER_SECOND = 0;//传输率要求值
ULONGLONG SCUR = 0;//“当前时间”公共变量
CMediaType OutMt;//输出媒体类型
};
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);//接收属性页对话框的消息
LPWSTR DefineFromGUID(GUID guid);//获取GUID定义字符串
LPWSTR GetFormatString(WAVEFORMATEX* p);//获取格式块描述字符串
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);
}
}
HRESULT OnApplyChanges(void);
UINT32 NUM_CHANNELS = 0;
UINT32 SAMPLES_PER_SECOND = 0;
UINT32 BYTES_PER_SECOND = 0;
HWND hList, hEdit, hCombox1, hCombox2, hText1, hText2;//
HFONT hFont1, hFont2;
};
#endif //DLL_FILE
DLL源文件:DLL.cpp
#include "DLL.h"
const AMOVIESETUP_MEDIATYPE InPinType = // 输入引脚媒体类型
{
&MEDIATYPE_Audio, //主要类型
&MEDIASUBTYPE_PCM //子类型
};
const AMOVIESETUP_MEDIATYPE OutPinType = //输出引脚媒体类型
{
&MEDIATYPE_Audio, //主要类型
&MEDIASUBTYPE_MP3 //子类型
};
const AMOVIESETUP_PIN sudPins[] = //引脚信息
{
{
(LPWSTR)"In", //引脚名称
FALSE, //渲染过滤器
FALSE, //输出引脚
FALSE, //具有该引脚的零个实例
FALSE, //可以创建一个以上引脚的实例
&CLSID_NULL, //该引脚连接的过滤器的类标识
NULL, //该引脚连接的引脚名称
1, //引脚支持的媒体类型数
&InPinType //媒体类型信息
},
{
(LPWSTR)"Out", //引脚名称
FALSE, //渲染过滤器
TRUE, //输出引脚
FALSE, //具有该引脚的零个实例
FALSE, //可以创建一个以上引脚的实例
&CLSID_NULL, //该引脚连接的过滤器的类标识
NULL, //该引脚连接的引脚名称
1, //引脚支持的媒体类型数
&OutPinType //媒体类型信息
}
};
const AMOVIESETUP_FILTER MP3Encoder = //过滤器的注册信息
{
&CLSID_MP3Encoder, //过滤器的类标识
L"MP3编码器", //过滤器的名称
MERIT_DO_NOT_USE, //过滤器优先值
2, //引脚数量
sudPins //引脚信息
};
CFactoryTemplate g_Templates[] = //类工厂模板数组
{
{
L"MP3编码器", //过滤器名称
&CLSID_MP3Encoder, //过滤器CLSID的指针
CFilter::CreateInstance, //创建过滤器实例的函数的指针
NULL, //指向从DLL入口点调用的函数的指针
&MP3Encoder //指向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("MP3编码器"), pUnk, this, CLSID_MP3Encoder)
{
HRESULT hr = MFStartup(MF_VERSION);//初始化媒体基础
if (hr != S_OK)
{
MessageBox(NULL, L"初始化媒体基础失败", L"MP3编码器", MB_OK); return;
}
GUID CLSID_Mp3Mft = { 0x11103421, 0x354c, 0x4cca, 0xa7, 0xa3, 0x1a, 0xff, 0x9a, 0x5b, 0x67, 0x01 };//MP3编码器的类标识符
hr = CoCreateInstance(CLSID_Mp3Mft, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pMP3Encoder));//MP3音频编码器(媒体基础转换)
if (hr != S_OK)
{
MessageBox(NULL, L"MP3音频编码器创建失败", L"MP3编码器", MB_OK); return;
}
pCInPin = new CInPin(this, phr, L"In");//创建输入引脚
pCOutPin = new COutPin(this, phr, L"Out");//创建输出引脚
}
void _FreeMediaType(AM_MEDIA_TYPE& mt)//释放媒体类型的格式块。
{
if (mt.cbFormat != 0)
{
CoTaskMemFree((PVOID)mt.pbFormat);
mt.cbFormat = 0;
mt.pbFormat = NULL;
}
if (mt.pUnk != NULL)
{
mt.pUnk->Release();
mt.pUnk = NULL;
}
}
CFilter::~CFilter()
{
_FreeMediaType(OutMt); SafeRelease(&pMP3Encoder);
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("MP3编码器"), 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_IMy008)
{
return GetInterface((IMy008*) this, ppv);
}
return CBaseFilter::NonDelegatingQueryInterface(riid, ppv);
}
HRESULT CFilter::Get(CBaseFilter** ppF)
{
*ppF = this;
return S_OK;
}
HRESULT CFilter::GetBYTES(UINT32* mBytes)
{
*mBytes = BYTES_PER_SECOND;
return S_OK;
}
HRESULT CFilter::SetBYTES(UINT32 mBytes)
{
if (mBytes != 1000 && mBytes != 2000 && mBytes != 2250 && mBytes != 2500 && mBytes != 3000 && mBytes != 4000 && mBytes != 5000 && mBytes != 6000 && mBytes != 7000 && mBytes != 8000
&& mBytes != 10000 && mBytes != 12000 && mBytes != 14000 && mBytes != 16000 && mBytes != 20000 && mBytes != 24000 && mBytes != 28000 && mBytes != 32000 && mBytes != 40000)
return S_FALSE;
BYTES_PER_SECOND = mBytes;
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 && pmt->subtype == MEDIASUBTYPE_PCM && pmt->formattype == FORMAT_WaveFormatEx && pmt->bFixedSizeSamples & !pmt->bTemporalCompression)
{
WAVEFORMATEX* pwf = (WAVEFORMATEX*)pmt->pbFormat;
if (pwf->wFormatTag != 1 || (pwf->nSamplesPerSec != 48000 && pwf->nSamplesPerSec != 44100 && pwf->nSamplesPerSec != 32000) || pwf->wBitsPerSample != 16)return S_FALSE;
return S_OK;
}
return S_FALSE;
}
HRESULT CInPin::SetMediaType(const CMediaType *pmt)
{
WAVEFORMATEX* pwf = (WAVEFORMATEX*)pmt->pbFormat;
IMFMediaType *pOutType = NULL;//输出媒体类型
int index = 0;
while (S_OK == pCFilter->pMP3Encoder->GetOutputAvailableType(NULL, index, &pOutType))
{
AM_MEDIA_TYPE* PMT;
HRESULT hr = pOutType->GetRepresentation(AM_MEDIA_TYPE_REPRESENTATION, (void**)&PMT);//将IMFMediaType媒体类型转换为AM_MEDIA_TYPE结构表示的媒体类型
WAVEFORMATEX* PWF = (WAVEFORMATEX*)PMT->pbFormat;
if (pCFilter->BYTES_PER_SECOND == 0)//如果用户没有指定传输率
{
if (pwf->nChannels == 1)//单声道
{
pCFilter->BYTES_PER_SECOND = 12000;//设置默认传输率
}
else//双声道
{
pCFilter->BYTES_PER_SECOND = 24000;//设置默认传输率
}
}
if (pwf->nChannels == PWF->nChannels && pwf->nSamplesPerSec == PWF->nSamplesPerSec && pCFilter->BYTES_PER_SECOND == PWF->nAvgBytesPerSec)//如果采样率,声道数,传输率相符
{
hr = pCFilter->pMP3Encoder->SetOutputType(NULL, pOutType, 0);//设置MP3音频编码器输出媒体类型
if (hr == S_OK)
{
AM_MEDIA_TYPE* pMt = (AM_MEDIA_TYPE*)pmt;
IMFMediaType* pInType = NULL;//输入媒体类型
hr = MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, pMt, &pInType);//从AM_MEDIA_TYPE结构创建媒体基础媒体类型
if (hr == S_OK)
{
hr = pCFilter->pMP3Encoder->SetInputType(NULL, pInType, 0);//设置MP3音频编码器输入媒体类型
}
SafeRelease(&pInType);//释放输入媒体类型
if (hr == S_OK)
{
pCFilter->SAMPLES_PER_SECOND = pwf->nSamplesPerSec;//输出采样率等于输入采样率
pCFilter->NUM_CHANNELS = pwf->nChannels;//输出声道数等于输入声道数
pCFilter->OutMt = *PMT;
hr = pOutType->FreeRepresentation(AM_MEDIA_TYPE_REPRESENTATION, PMT);//释放GetRepresentation获得的内存
SafeRelease(&pOutType);//释放输出媒体类型
return CBasePin::SetMediaType(pmt);
}
}
}
hr = pOutType->FreeRepresentation(AM_MEDIA_TYPE_REPRESENTATION, PMT);//释放GetRepresentation获得的内存
SafeRelease(&pOutType);//释放输出媒体类型
index++;
}
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->pMP3Encoder->ProcessInput(NULL, pMFSample, 0);//向MP3音频编码器传递输入数据
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->pMP3Encoder->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); SafeRelease(&pOutType);
}
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;
if (iPosition > 0)return VFW_S_NO_MORE_ITEMS;
*pMediaType = pCFilter->OutMt;
return S_OK;
}
HRESULT COutPin::CheckMediaType(const CMediaType *pmt)
{
if (pCFilter->pCInPin->IsConnected() == FALSE)//如果输入引脚没有连接
{
MessageBox(NULL, L"须先连接输入引脚", L"MP3编码器", MB_OK); return S_FALSE;
}
if (pmt->majortype == MEDIATYPE_Audio && pmt->subtype == MEDIASUBTYPE_MP3 && pmt->formattype == FORMAT_WaveFormatEx)
{
WAVEFORMATEX* pwf = (WAVEFORMATEX*)pmt->pbFormat;
if (pwf->wFormatTag != 85 || pwf->nSamplesPerSec != pCFilter->SAMPLES_PER_SECOND || pwf->nChannels != pCFilter->NUM_CHANNELS)return S_FALSE;
return S_OK;
}
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 "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;
}
IMy008* pIMy008 = NULL;
HRESULT hr = pUnknown->QueryInterface(IID_IMy008, reinterpret_cast<void**>(&pIMy008));
if (hr == S_OK)
{
pCFilter = (CFilter*)pIMy008;
SafeRelease(&pIMy008);
}
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 *pOutType = NULL;//输出媒体类型
while (S_OK == pCFilter->pMP3Encoder->GetInputAvailableType(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)
{
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;
WAVEFORMATEX* PWF = (WAVEFORMATEX*)PMT->pbFormat;
LPWSTR lp4 = GetFormatString(PWF);//获取格式块描述字符串
ListView_SetItemText(hList, index, 4, lp4);//设置子项3文本“格式类型”
delete[] lp4;
hr = pOutType->FreeRepresentation(AM_MEDIA_TYPE_REPRESENTATION, PMT);//释放GetRepresentation获得的内存
}
SafeRelease(&pOutType);//释放输出媒体类型
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;
}
break;
}
return CBasePropertyPage::OnReceiveMessage(hwnd, uMsg, wParam, lParam);//让父类处理消息
}
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_PCM)
{
wcscpy_s(pW, 200, L"MEDIASUBTYPE_PCM");
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;
}
IMy008* pIMy008 = NULL;
HRESULT hr = pUnknown->QueryInterface(IID_IMy008, reinterpret_cast<void**>(&pIMy008));
if (hr == S_OK)
{
pCFilter = (CFilter*)pIMy008;
SafeRelease(&pIMy008);
}
return hr;
}
HRESULT CPropertyPage2::OnActivate(void)
{
if (pCFilter->pCInPin->IsConnected())
{
EnableWindow(hCombox1, FALSE); EnableWindow(hCombox2, FALSE);
}
else
{
EnableWindow(hCombox1, TRUE); EnableWindow(hCombox2, TRUE);
}
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"全部"); ComboBox_AddString(hCombox1, L"2"); ComboBox_AddString(hCombox1, L"1");
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;
case WM_COMMAND:
if (HIWORD(wParam) == CBN_SELCHANGE)//组合框选择改变
{
if (LOWORD(wParam) == IDC_COMBO1)//声道数组合框
{
int Sel = ComboBox_GetCurSel((HWND)lParam);//获取组合框当前选择
if (Sel != -1 && !pCFilter->pCInPin->IsConnected())//如果输入引脚没有连接,可以设置声道数值要求值
{
int Len = ComboBox_GetLBTextLen((HWND)lParam, Sel);
wchar_t* pw = new wchar_t[Len + 1];
ComboBox_GetLBText((HWND)lParam, Sel, pw);
if (wcscoll(pw, L"全部") == 0)//如果项文本为“全部”
{
NUM_CHANNELS = 0;//将声道数置0
}
else
{
NUM_CHANNELS = _wtoi(pw);//设置输出声道数要求值
}
delete[] pw;
GetOutAvailableType(FALSE);
SetDirty();
return (INT_PTR)TRUE;
}
}
if (LOWORD(wParam) == IDC_COMBO2)//传输率组合框
{
int Sel = ComboBox_GetCurSel((HWND)lParam);//获取组合框当前选择
if (Sel != -1 && !pCFilter->pCInPin->IsConnected())//如果输入引脚没有连接,可以设置传输率要求值(该MP3编码器不能更改采样率,故输出采样率=输入采样率)
{
int Len = ComboBox_GetLBTextLen((HWND)lParam, Sel);
wchar_t* pw = new wchar_t[Len + 1];
ComboBox_GetLBText((HWND)lParam, Sel, pw);
if (wcscoll(pw, L"全部") == 0)
{
SAMPLES_PER_SECOND = 0; BYTES_PER_SECOND = 0;//将采样率,传输率置0
}
else
{
BYTES_PER_SECOND = _wtoi(pw);//设置输出传输率要求值
}
delete[] pw;
GetOutAvailableType(FALSE);
SetDirty();
return (INT_PTR)TRUE;
}
}
}
break;
}
return CBasePropertyPage::OnReceiveMessage(hwnd, uMsg, wParam, lParam);//让父类处理消息
}
HRESULT CPropertyPage2::OnApplyChanges(void)//应用更改
{
pCFilter->BYTES_PER_SECOND = BYTES_PER_SECOND;
pCFilter->NUM_CHANNELS = NUM_CHANNELS;
pCFilter->SAMPLES_PER_SECOND = SAMPLES_PER_SECOND;
char ch1[100];
if (BYTES_PER_SECOND == 0)
{
sprintf_s(ch1, "传输率=%u//可以为任何值", BYTES_PER_SECOND);
}
else
{
sprintf_s(ch1, "传输率=%u", BYTES_PER_SECOND);
}
char ch[500];
sprintf_s(ch, 500, "已应用更改。新数据为:\r\n%s", ch1);
MessageBoxA(0, ch, "MP3 编码器", MB_OK);
return S_OK;
}
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->pCInPin->IsConnected())//如果输入引脚已经连接
{
hr = pCFilter->pMP3Encoder->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->pMP3Encoder->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;
BOOL B1 = FALSE, B2 = FALSE, B3 = FALSE;
if (NUM_CHANNELS == 0)//如果声道数要求值为0(没有要求值)
{
B1 = TRUE;
}
else//如果声道数不为0
{
if (NUM_CHANNELS == PWF->nChannels)B1 = TRUE;//如果声道数匹配,标记TRUE
}
if (SAMPLES_PER_SECOND == 0)//如果采样率为0(没有要求值)
{
B2 = TRUE;
}
else //如果采样率不为0
{
if (SAMPLES_PER_SECOND == PWF->nSamplesPerSec)B2 = TRUE;//如果采样率匹配,,标记TRUE
}
if (BYTES_PER_SECOND == 0)//如果传输率为0(没有要求值)
{
B3 = TRUE;
}
else//如果传输率不为0
{
if (BYTES_PER_SECOND == PWF->nAvgBytesPerSec)B3 = TRUE;//如果传输率匹配,,标记TRUE
}
if (B1 && B2 && B3)//如果3个标记都为TRUE
{
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);
}
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_MP3)
{
wcscpy_s(pW, 200, L"MEDIASUBTYPE_MP3");
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;
}