下载本过滤器DLL
本过滤器将PCM音频流,或ADPCM,IEEE_FLOAT,ALAW,MULAW,GSM610音频流写入WAV音频文件。
写WAV音频文件过滤器信息
过滤器名称:写WAV
过滤器GUID:{CF704A9C-0C67-4712-BA33-DD0AAE01A232}
DLL注册函数名:DllRegisterServer
删除注册函数名:DllUnregisterServer
过滤器有1个输入引脚。
输入引脚标识:In
输入引脚媒体类型:
主要类型:MEDIATYPE_Audio
子类型:
MEDIASUBTYPE_PCM
{0x00000002, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
MEDIASUBTYPE_IEEE_FLOAT
{0x00000006, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
{0x00000007, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
{0x00000031, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
格式类型:FORMAT_WaveFormatEx
样本为固定大小。
写WAV音频文件过滤器开发信息
WAV音频文件使用PCM方式表示音频数据,即使用short值表示采样点音频的幅值。即无压缩,也无编码;是表示音频数据最基本的方式。文件体积较大。故添加了使用压缩方式写WAV文件的方法,生成WAV文件后,Windows播放器仍可播放。
写WAV音频文件过滤器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
// {CF704A9C-0C67-4712-BA33-DD0AAE01A232}
DEFINE_GUID(CLSID_WavWriter,//过滤器GUID
0xcf704a9c, 0xc67, 0x4712, 0xba, 0x33, 0xdd, 0xa, 0xae, 0x1, 0xa2, 0x32);
DEFINE_GUID(MEDIASUBTYPE_ADPCM,//
0x00000002, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
DEFINE_GUID(MEDIASUBTYPE_ALAW,//
0x00000006, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
DEFINE_GUID(MEDIASUBTYPE_MULAW,//
0x00000007, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
DEFINE_GUID(MEDIASUBTYPE_GSM610,//
0x00000031, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
#include "strsafe.h"
struct WAVE_HEADER {
char RIFF_ch[4] = { 'R','I','F','F' };//文件规范标识
DWORD mSize = 0;//从下一项(文件类型)的开始位置,到文件的结束位置的大小,以字节为单位
char WAVE_ch[4] = { 'W','A','V','E' };//文件类型
char fmt_ch[4] = { 'f','m','t',' ' };//格式块标识
DWORD fmt_Size = 16;//格式块大小
WORD Format = 1;//编码方式
WORD nChannels = 0;//声道数
DWORD SampleRate = 0;//采样率
DWORD ByteRate = 0;//传输率
WORD BlockAlign = 0;//块对齐
WORD BitsPerSample = 0;//样本位数
};
class CFilter;
class CPin : public CBaseInputPin
{
friend class CFilter;
public:
CPin(CFilter *pFilter, HRESULT *phr, LPCWSTR pPinName);
~CPin();
HRESULT CheckMediaType(const CMediaType *pmt);
HRESULT SetMediaType(const CMediaType *pmt);
STDMETHODIMP Receive(IMediaSample *pSample);
HRESULT Active();
HRESULT Inactive();
STDMETHODIMP EndOfStream();
CFilter *pCFilter;
DWORD Data_Size = 0;
HANDLE hFile = NULL;//输出文件句柄
WORD cbSize = 0;//附加信息大小
char Data_ch[4] = { 'd','a','t','a' };//数据块标识
DWORD mSize = 0;//数据区块大小,以字节为单位
BYTE* pAppend = NULL;
};
class CFilter : public CBaseFilter, public CCritSec, public IFileSinkFilter
{
friend class CPin;
public:
CFilter(LPWSTR lpName, LPUNKNOWN pUnk, HRESULT *phr);
virtual ~CFilter();
DECLARE_IUNKNOWN
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv);
virtual HRESULT STDMETHODCALLTYPE SetFileName(LPCOLESTR pszFileName, const AM_MEDIA_TYPE *pmt);
virtual HRESULT STDMETHODCALLTYPE GetCurFile(LPOLESTR * ppszFileName, AM_MEDIA_TYPE *pmt);
static CUnknown * WINAPI CreateInstance(LPUNKNOWN, HRESULT *);
int GetPinCount();
CBasePin *GetPin(int n);
CPin *pCPin=NULL; //输入引脚指针
WCHAR* m_pFileName=NULL;//要创作的WAV文件路径
WAVE_HEADER header;//WAV文件头
};
template <class T> void SafeRelease(T** ppT)
{
if (*ppT)
{
(*ppT)->Release();
*ppT = NULL;
}
}
#endif //DLL_FILE
DLL.cpp
#include "DLL.h"
const AMOVIESETUP_MEDIATYPE InPinType[] = // 输入引脚媒体类型
{
{
&MEDIATYPE_Audio, //主要类型
&MEDIASUBTYPE_PCM //子类型
},
{
&MEDIATYPE_Audio, //主要类型
&MEDIASUBTYPE_ADPCM //子类型
},
{
&MEDIATYPE_Audio, //主要类型
&MEDIASUBTYPE_IEEE_FLOAT //子类型
},
{
&MEDIATYPE_Audio, //主要类型
&MEDIASUBTYPE_ALAW //子类型
},
{
&MEDIATYPE_Audio, //主要类型
&MEDIASUBTYPE_MULAW //子类型
},
{
&MEDIATYPE_Audio, //主要类型
&MEDIASUBTYPE_GSM610 //子类型
}
};
const AMOVIESETUP_PIN sudPins[] = // 引脚信息
{
{
(LPWSTR)"In", //引脚名称
FALSE, //渲染引脚
FALSE, //输出引脚
FALSE, //具有该引脚的零个实例
FALSE, //可以创建一个以上引脚的实例
&CLSID_NULL, //该引脚连接的过滤器的类标识
NULL, //该引脚连接的引脚名称
6, //引脚支持的媒体类型数
InPinType //媒体类型信息
}
};
const AMOVIESETUP_FILTER MP3Encoder = //过滤器的注册信息
{
&CLSID_WavWriter, //过滤器的类标识
L"写WAV", //过滤器的名称
MERIT_DO_NOT_USE, //过滤器优先值
1, //引脚数量
sudPins //引脚信息
};
CFactoryTemplate g_Templates[] = //类工厂模板数组
{
{
L"写WAV", //对象(这里为过滤器)名称
&CLSID_WavWriter, //对象CLSID的指针
CFilter::CreateInstance, //创建对象实例的函数的指针
NULL, //指向从DLL入口点调用的函数的指针
&MP3Encoder //指向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"
CFilter::CFilter(LPWSTR lpName, LPUNKNOWN pUnk, HRESULT *phr) : CBaseFilter(lpName, pUnk, (CCritSec *) this, CLSID_WavWriter)
{
pCPin = new CPin(this, phr, L"In");//创建输入引脚
}
CFilter::~CFilter()
{
delete[] m_pFileName;
}
CUnknown * WINAPI CFilter::CreateInstance(LPUNKNOWN pUnk, HRESULT *phr)
{
return new CFilter(L"写WAV", pUnk, phr);//创建过滤器
}
int CFilter::GetPinCount()
{
return 1;
}
CBasePin *CFilter::GetPin(int n)
{
if (n != 0)
{
return NULL;
}
return pCPin;
}
STDMETHODIMP CFilter::NonDelegatingQueryInterface(REFIID iid, void ** ppv)
{
if (iid == IID_IFileSinkFilter)
{
return GetInterface(static_cast<IFileSinkFilter*>(this), ppv);
}
else
return CBaseFilter::NonDelegatingQueryInterface(iid, ppv);
}
HRESULT CFilter::GetCurFile(LPOLESTR *ppszFileName, AM_MEDIA_TYPE *pmt)
{
CheckPointer(ppszFileName, E_POINTER);
*ppszFileName = NULL;
if (m_pFileName != NULL)
{
size_t len = 1 + lstrlenW(m_pFileName);
*ppszFileName = (LPOLESTR)QzTaskMemAlloc(sizeof(WCHAR) * (len));
if (*ppszFileName != NULL)
{
HRESULT hr = StringCchCopyW(*ppszFileName, len, m_pFileName);
}
}
if (pmt)
{
ZeroMemory(pmt, sizeof(*pmt));
pmt->majortype = MEDIATYPE_NULL;
pmt->subtype = MEDIASUBTYPE_NULL;
}
return S_OK;
}
HRESULT CFilter::SetFileName(LPCOLESTR pszFileName, const AM_MEDIA_TYPE *pmt)
{
CheckPointer(pszFileName, E_POINTER);
if (wcslen(pszFileName) > MAX_PATH || wcslen(pszFileName)<4)
return ERROR_FILENAME_EXCED_RANGE;
size_t len = 1 + lstrlenW(pszFileName);
m_pFileName = new WCHAR[len];
if (m_pFileName == 0)
return E_OUTOFMEMORY;
HRESULT hr = StringCchCopyW(m_pFileName, len, pszFileName);
if (m_pFileName[len - 2] != 'v' || m_pFileName[len - 3] != 'a' || m_pFileName[len - 4] != 'w' || m_pFileName[len - 5] != '.')//如果不是WAV文件
{
delete[] m_pFileName; m_pFileName = NULL;
return VFW_E_INVALID_FILE_FORMAT;//设置文件名失败
}
return S_OK;
}
CPin.cpp
#include "DLL.h"
CPin::CPin(CFilter *pFilter, HRESULT *phr, LPCWSTR pPinName) : CBaseInputPin(NAME("In"), pFilter, pFilter, phr, pPinName)
{
pCFilter = pFilter;
}
CPin::~CPin()//输入引脚析构函数
{
}
HRESULT CPin::CheckMediaType(const CMediaType *pmt)
{
if (pmt->majortype == MEDIATYPE_Audio && pmt->formattype == FORMAT_WaveFormatEx && pmt->bFixedSizeSamples)
{
if (pmt->subtype == MEDIASUBTYPE_PCM || pmt->subtype == MEDIASUBTYPE_ADPCM || pmt->subtype == MEDIASUBTYPE_IEEE_FLOAT
|| pmt->subtype == MEDIASUBTYPE_ALAW || pmt->subtype == MEDIASUBTYPE_MULAW || pmt->subtype == MEDIASUBTYPE_GSM610)
return S_OK;
return S_FALSE;
}
else
return S_FALSE;
}
HRESULT CPin::SetMediaType(const CMediaType *pmt)
{
WAVEFORMATEX* p = (WAVEFORMATEX*)pmt->pbFormat;
//给文件头参数赋值
pCFilter->header.Format = p->wFormatTag;//编码方式
pCFilter->header.nChannels = p->nChannels;//声道数
pCFilter->header.SampleRate = p->nSamplesPerSec;//采样率
pCFilter->header.ByteRate = p->nAvgBytesPerSec;;//传输率
pCFilter->header.BlockAlign = p->nBlockAlign;//块对齐
pCFilter->header.BitsPerSample = p->wBitsPerSample;//样本位数
pCFilter->header.fmt_Size = 16;//格式块大小
if (p->cbSize > 0)//如果有附加信息
{
cbSize = p->cbSize;
pCFilter->header.fmt_Size = p->cbSize + sizeof(WAVEFORMATEX);//格式块大小
if (pAppend != NULL)
{
delete[] pAppend; pAppend = NULL;
}
pAppend = new BYTE[p->cbSize];
if (pmt->subtype == MEDIASUBTYPE_ADPCM)
{
BYTE info[32] = {244,7,7,0,0,1,0,0,0,2,0,255,0,0,0,0,192,0,64,0,240,0,0,0,204,1,48,255,136,1,24,255};//MEDIASUBTYPE_ADPCM附加信息
CopyMemory(pAppend, &info, 32);//复制附加信息
}
else if (pmt->subtype == MEDIASUBTYPE_GSM610)
{
BYTE info[2] = {64,1};
CopyMemory(pAppend, &info, 2);//复制附加信息
}
else
{
CopyMemory(pAppend, pmt->pbFormat- sizeof(WAVEFORMATEX), cbSize);//复制附加信息
}
}
return CBaseInputPin::SetMediaType(pmt);
}
HRESULT CPin::Receive(IMediaSample * pSample)//接收函数
{
HRESULT hr;
BYTE* pBy = NULL;
hr = pSample->GetPointer(&pBy);//获取引脚样本缓冲区指针
long len = pSample->GetActualDataLength();//获取有效数据长度
if (hFile)
{
WriteFile(hFile, pBy, len, NULL, NULL);//写WAVE数据
Data_Size += len;//记录已写数据的字节大小
}
return S_OK;
}
HRESULT CPin::Active()
{
if (pCFilter->m_pFileName == NULL)
{
MessageBox(0, L"没有指定输出文件", L"写WAV", MB_OK); return S_FALSE;
}
hFile = CreateFile(pCFilter->m_pFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);//创建输出文件
if (INVALID_HANDLE_VALUE == hFile)
{
MessageBox(0, L"创建输出文件失败", L"写WAV", MB_OK); return S_FALSE;
}
Data_Size = 0;
WriteFile(hFile, &pCFilter->header, sizeof(pCFilter->header), NULL, NULL);//写WAVE文件头
if (cbSize > 0)//如果有附加信息
{
WriteFile(hFile, &cbSize, 2, NULL, NULL);//写附加信息大小
WriteFile(hFile, pAppend, cbSize, NULL, NULL);//写附加信息
}
WriteFile(hFile, Data_ch, 4, NULL, NULL);//写数据块标识
WriteFile(hFile, &mSize, 4, NULL, NULL);//写数据块大小,写入的并非真实大小
return CBaseInputPin::Active();
}
HRESULT CPin::Inactive()
{
LARGE_INTEGER Move;
Move.QuadPart = 4;
SetFilePointerEx(hFile, Move, NULL, FILE_BEGIN);//移动文件指针,到“文件大小”位置
int AppendSize = pCFilter->header.fmt_Size - 16;
DWORD FileSize = Data_Size + 36 + AppendSize;
WriteFile(hFile, &FileSize, sizeof(FileSize), NULL, NULL);//写WAVE文件大小
Move.QuadPart = 40 + AppendSize;
SetFilePointerEx(hFile, Move, NULL, FILE_BEGIN);//移动文件指针,到“数据大小”位置
WriteFile(hFile, &Data_Size, sizeof(Data_Size), NULL, NULL);//写WAVE数据大小
CloseHandle(hFile);//关闭输出文件
hFile = NULL; cbSize = 0;
if (pAppend != NULL)
{
delete[] pAppend; pAppend = NULL;
}
return CBaseInputPin::Inactive();
}
STDMETHODIMP CPin::EndOfStream()
{
pCFilter->NotifyEvent(EC_COMPLETE, S_OK, 0);
return CBaseInputPin::EndOfStream();
}