DirectShow过滤器开发-写WAV音频文件过滤器

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

下载本过滤器DLL

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

h3974

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

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

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

打赏作者

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

抵扣说明:

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

余额充值