DirectShow之音频录制Wav

//环境:win10 + DirectX9.0bSDK

一.准备工作

1.WavDestFilter

//采集音频写入WAV文件需要用到DirectShow的一个Filter,这个Filter用于将音频数据写入完毕时加入WAV格式数据!

//DirectXSDK目录\Samples\C++\DirectShow\Filters\WavDest

//拷贝wavdest.h,wavdest.cpp 这里采用源码拷贝走修改方式使用DirectShow提供的Filter!

2.创建Win32项目

//删除Win32自动生成代码

// DirectShowAudioCaptureWav.cpp : 定义应用程序的入口点。
//

#include "stdafx.h"
#include "DirectShowAudioCaptureWav.h"

int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
	_In_opt_ HINSTANCE hPrevInstance,
	_In_ LPTSTR    lpCmdLine,
	_In_ int       nCmdShow)
{

	return 0;
}

//环境配置

// stdafx.h : 标准系统包含文件的包含文件,
// 或是经常使用但不常更改的
// 特定于项目的包含文件
//

#pragma once

#include "targetver.h"

#define WIN32_LEAN_AND_MEAN             //  从 Windows 头文件中排除极少使用的信息
// Windows 头文件: 
#include <windows.h>

// C 运行时头文件
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>


// TODO:  在此处引用程序需要的其他头文件
#include "streams.h"

#ifdef _DEBUG
#pragma comment(lib,"strmbasd.lib")
#else
#pragma comment(lib,"STRMBASE.lib")
#endif

//添加wavdest.h,wavdest.cpp

1.修改wavdest.cpp

#include <streams.h> #include "wavdest.h" -> 改成 #include "stdafx.h"

stdafx.h 添加 #include "wavdest.h"

2.挪走GUID代码至wavdest.h

// {3C78B8E2-6C4D-11d1-ADE2-0000F8754B99}
static const GUID CLSID_WavDest =
{ 0x3c78b8e2, 0x6c4d, 0x11d1, { 0xad, 0xe2, 0x0, 0x0, 0xf8, 0x75, 0x4b, 0x99 } };


const AMOVIESETUP_FILTER sudWavDest =
{
    &CLSID_WavDest,           // clsID
    L"WAV Dest",              // strName
    MERIT_DO_NOT_USE,         // dwMerit
    0,                        // nPins
    0                         // lpPin
};

3.挪走wavdest.cpp 中全局数据

// Global data
CFactoryTemplate g_Templates[]= {
    {L"WAV Dest", &CLSID_WavDest, CWavDestFilter::CreateInstance, NULL, &sudWavDest},
};

int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);

//此时编译一下看看

我们会发现报错:

stdafx.h 加入:#pragma comment(lib,"winmm.lib")

这里我们就可以正式编写我们的音频采集代码!

 

二.代码实现

// DirectShowAudioCaptureWav.cpp : 定义应用程序的入口点。
//

#include "stdafx.h"
#include "DirectShowAudioCaptureWav.h"
#include <vector>
#include <map>

using namespace std;

// Global data
CFactoryTemplate g_Templates[] = {
	{ L"WAV Dest", &CLSID_WavDest, CWavDestFilter::CreateInstance, NULL, &sudWavDest },
};

int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);


///AddFilterToGraph
HRESULT AddFilterToGraph(IGraphBuilder* pGraph, const GUID& clsId, LPCWSTR wstrName, IBaseFilter** pFilter)
{
	if (!pGraph || !pFilter)
		return E_POINTER;
	*pFilter = NULL;
	//CreateFilter
	IBaseFilter* pBaseFilter = NULL;
	HRESULT hr = CoCreateInstance(clsId, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&pBaseFilter);
	if (SUCCEEDED(hr))
	{
		//AddFilterToGraph
		hr = pGraph->AddFilter(pBaseFilter, wstrName);
		if (SUCCEEDED(hr))
		{
			//SaveFilter
			*pFilter = pBaseFilter;
		}
		else
		{
			//FreeFilter
			pBaseFilter->Release();
		}
	}
	return hr;
}
///GetFilterDirectionPin
HRESULT GetUnconnectedPin(IBaseFilter* pFilter, PIN_DIRECTION pinDirection, IPin** ppPin)
{
	if (!pFilter || !ppPin)
		return E_POINTER;
	//获取pin枚举器
	*ppPin = NULL;
	IEnumPins* pEnumPin = NULL;
	HRESULT hr = pFilter->EnumPins(&pEnumPin);
	if (FAILED(hr))
	{
		return hr;
	}
	//遍历pin枚举器
	IPin* pPin = NULL;
	while (pEnumPin->Next(1, &pPin, NULL) == S_OK)
	{
		//查pin方向
		PIN_DIRECTION curPinDirection;
		pPin->QueryDirection(&curPinDirection);
		if (curPinDirection == pinDirection)
		{
			IPin* tmpPin = NULL;
			//尝试连接
			hr = pPin->ConnectedTo(&tmpPin);
			if (SUCCEEDED(hr))
			{
				//可以连接
				tmpPin->Release();
			}
			else
			{
				pEnumPin->Release();
				*ppPin = pPin;
				return S_OK;
			}
		}
	}
	//释放pin枚举器
	pEnumPin->Release();
	return E_FAIL;
}
///FilterConnectedToFilter
//PinToFilterPinConnected
HRESULT ConnectedFilters(IGraphBuilder* pGraph, IPin* pOutPin, IBaseFilter* pDstFilter)
{
	if (!pGraph || !pOutPin || !pDstFilter)
		return E_POINTER;
	//获取输入pin
	IPin* pInPin = NULL;
	HRESULT hr = GetUnconnectedPin(pDstFilter, PINDIR_INPUT, &pInPin);
	if (FAILED(hr))
		return hr;
	//连接输入pin
	hr = pGraph->Connect(pOutPin, pInPin);
	pInPin->Release();
	return hr;
}
//FilterToFilterConnected
HRESULT ConnectedFilters(IGraphBuilder* pGraph, IBaseFilter* pSrcFilter, IBaseFilter* pDstFilter)
{
	if (!pGraph || !pSrcFilter || !pDstFilter)
		return E_POINTER;
	//获取输入pin
	IPin* pOutPin = NULL;
	HRESULT hr = GetUnconnectedPin(pSrcFilter, PINDIR_OUTPUT, &pOutPin);
	if (FAILED(hr))
		return hr;
	//连接输入pin
	hr = ConnectedFilters(pGraph, pOutPin, pDstFilter);
	pOutPin->Release();
	return hr;
}


HRESULT EnumDeviceInfo(vector<wstring>& devicesNames, map<wstring, IMoniker*>& devicesInfo, const IID InputDeviceCategory)
{
	//创建系统设备枚举器
	ICreateDevEnum* pSystemDevEnum = NULL;
	HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void**)&pSystemDevEnum);
	if (FAILED(hr))
	{
		return hr;
	}
	//创建设备枚举器
	IEnumMoniker* pEnumMoniker = NULL;
	hr = pSystemDevEnum->CreateClassEnumerator(InputDeviceCategory, &pEnumMoniker, 0);
	if (hr == S_OK)
	{
		IMoniker* pMoniker = NULL;
		ULONG cFetched;
		while (pEnumMoniker->Next(1, &pMoniker, &cFetched) == S_OK)
		{
			IPropertyBag* pPropertyBag = NULL;
			hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void**)&pPropertyBag);
			if (SUCCEEDED(hr))
			{
				//获取设备信息
				VARIANT varName;
				VariantInit(&varName);
				hr = pPropertyBag->Read(L"FriendlyName", &varName, 0); //获取友好名
				if (SUCCEEDED(hr))
				{
					//保存设备信息
					devicesNames.push_back(varName.bstrVal);
					devicesInfo.insert(pair<wstring, IMoniker*>(varName.bstrVal, pMoniker));
				}
				VariantClear(&varName);
			}
			else
			{
				return hr;
			}
			pPropertyBag->Release();
		}
	}
	pEnumMoniker->Release();
	pSystemDevEnum->Release();
	return hr;
}

HRESULT FindAudioCaptureFilter(IMoniker* pMoniker, IBaseFilter** pFilter)
{
	if (!pFilter || !pMoniker)
		return E_POINTER;
	*pFilter = NULL;
	HRESULT hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter, (void**)pFilter);
	if (FAILED(hr))
	{
		return E_FAIL;
	}
	return S_OK;
}


int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
	_In_opt_ HINSTANCE hPrevInstance,
	_In_ LPTSTR    lpCmdLine,
	_In_ int       nCmdShow)
{

	///COM_Begin:
	if (FAILED(::CoInitialize(NULL)))
	{
		MessageBox(NULL, L"CoInitialize failed!", L"ErrWnd", NULL);
		return 0;
	}

	///FilterGraph IGraphBuilder
	IGraphBuilder* pGraph = NULL;
	IBaseFilter* pAudioCaptureFilter = NULL,*pDestWavFilter = NULL, *pWriteFilter = NULL;
	HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void**)&pGraph);
	if (FAILED(hr))
	{
		MessageBox(NULL, L"IFilterGraph failed!", L"ErrWnd", NULL);
		return 0;
	}

	///AudioCaptureFilter
	vector<wstring> audioDeviceNamesVector;
	map<wstring, IMoniker*> audioDeviceFriendlyMap;
	EnumDeviceInfo(audioDeviceNamesVector, audioDeviceFriendlyMap, CLSID_AudioInputDeviceCategory);
	hr = FindAudioCaptureFilter(audioDeviceFriendlyMap[audioDeviceNamesVector[0]], &pAudioCaptureFilter);
	if (FAILED(hr))
	{
		MessageBox(NULL, L"FindAudioCaptureFilter failed!", L"ErrWnd", NULL);
		return 0;
	}
	pGraph->AddFilter(pAudioCaptureFilter, L"AudioCaptureFilter");
	///WavDestFilter
	pDestWavFilter = new CWavDestFilter(NULL, &hr);
	if (FAILED(hr))
	{
		MessageBox(NULL, L"WavDestFilter failed!", L"ErrWnd", NULL);
		return 0;
	}
	pGraph->AddFilter(pDestWavFilter, L"WavDestFilter");
	///WriteFilter
	hr = AddFilterToGraph(pGraph, CLSID_FileWriter, L"WriteFilter", &pWriteFilter);
	if (FAILED(hr))
	{
		MessageBox(NULL, L"WriteFilter failed!", L"ErrWnd", NULL);
		return 0;
	}
	IFileSinkFilter* pFileSinkFilter;
	hr = pWriteFilter->QueryInterface(IID_IFileSinkFilter, (void**)&pFileSinkFilter);
	if (FAILED(hr))
	{
		MessageBox(NULL, L"IFileSinkFilter failed!", L"ErrWnd", NULL);
		return 0;
	}
	pFileSinkFilter->SetFileName(L"E:\\TestFile\\AudioCapture.wav", NULL);
	///ConnectedFilters
	ConnectedFilters(pGraph, pAudioCaptureFilter, pDestWavFilter);
	ConnectedFilters(pGraph, pDestWavFilter, pWriteFilter);
	///MediaControl
	IMediaControl* pControl = NULL;
	hr = pGraph->QueryInterface(IID_IMediaControl, (void**)&pControl);
	if (FAILED(hr))
	{
		MessageBox(NULL, L"QueryInterface IMediaControl Failed!", L"ErrWnd", NULL);
		return 0;
	}
	//
	hr = pControl->Run();
	if (SUCCEEDED(hr))
	{
		Sleep(10000);
		pControl->Stop();
	}

	///COM_End:
	::CoUninitialize();

	return 0;
}

//上面API函数:均是DirectShow教程中封装的函数,我们可以封装起来拿来用!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值