DirectShow(三)AudioCapture

  1. 环境:xp+vs2005+DXSDK9_sumer2004
  2. 目的:将采集到的麦克风声音送至声卡
  3. GraphEdit模拟
  • add filter

  • connect filter

  • play,即可在耳机中听到麦克风中自己的声音(确认耳机和麦克风插好,并且没有被静音),有一点延时 :-)

 4.  代码实现(具体解释请参考此处,代码是俺抄的:-)):

// AudioCaptureSaveConsole.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include<iostream>
#include<cstring>
#include<dshow.h>
#include<windows.h>
#include<conio.h>
#include<stdio.h>
//#include"streams.h"


bool Bstr_Compare(BSTR,BSTR);//Function to compare BSTR strings
void HR_Failed(HRESULT hr);// hr status function
IMoniker* Device_Read(ICreateDevEnum*,IMoniker*,GUID,BSTR);//Device reading function
IBaseFilter* Device_Init(IMoniker*,IBaseFilter*);//Function to initialize Input/Output devices
void Device_Addition(IGraphBuilder*,IBaseFilter*,BSTR);//Function to add device to graph
void Device_Connect(IBaseFilter*,IBaseFilter*,BSTR,BSTR);//Function to connect the two devices
void Run_Graph(IMediaControl*);//Function to run the graph
IFileSinkFilter* Add_File(IGraphBuilder*,IBaseFilter*,IFileSinkFilter*,BSTR);//Function to access default WAV file

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
	HRESULT hr;	// COM result
	IGraphBuilder *pGraph = NULL;// Main graphbuilder pointer
	IMediaControl *pControl = NULL;	// Media Control interface
	ICreateDevEnum *pDeviceEnum = NULL;// System device enumerator
	IBaseFilter *pInputDevice = NULL, *pOutputDevice = NULL;// Input and output filters(devices)
	IBaseFilter *pWAVRecorder = NULL;//This is the transform filter that converts raw input to WAV
	IBaseFilter *pFileWriter = NULL;// FileWriter filter shall be refernced by this pointer
	IFileSinkFilter *pFile = NULL;

	IMoniker *pDeviceMonik = NULL;// Device moniker
	GUID DEVICE_CLSID ;// GUID i.e.  CLSID_Xxxxxxxxxxx
	BSTR bstrDeviceName= {'\0'};// FriendlyName of device
	BSTR bstrInPinName= {'\0'};// Input pin name
	BSTR bstrOutPinName= {'\0'};// Output pin name

	hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED );// Initialise COM
	if (FAILED(hr))
	{
		HR_Failed(hr);
		return hr;
	}
	hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,IID_IGraphBuilder, (void**)&pGraph);//Initialize Graph builder
	if (FAILED(hr))
	{
		HR_Failed(hr);
		return hr;
	}
	hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,IID_ICreateDevEnum, (void **)&pDeviceEnum);//Initialize Device enumerator
	if (FAILED(hr))
	{
		HR_Failed(hr);
		return hr;
	}
	hr = pGraph->QueryInterface(IID_IMediaControl,(void**)&pControl);// Query interface for IMediaControl
	if (FAILED(hr))
	{
		HR_Failed(hr);
		return hr;
	}


	/*******************************************************************************/
	//Front mic input
	DEVICE_CLSID = CLSID_AudioInputDeviceCategory;// the input device category
	//bstrDeviceName = SysAllocString(L"Front Mic (IDT High Definition ");// device name as seen in Graphedit.exe
	bstrDeviceName = SysAllocString(L"Realtek HD Audio Input");
	pDeviceMonik = Device_Read(pDeviceEnum,pDeviceMonik,DEVICE_CLSID,bstrDeviceName);//read the required device 
	pInputDevice = Device_Init(pDeviceMonik,pInputDevice);//Return the device after initializing it
	Device_Addition(pGraph,pInputDevice,bstrDeviceName);//add device to graph
	SysFreeString(bstrDeviceName);
	/******************************************************************************/
	//Transform filter
	DEVICE_CLSID = CLSID_LegacyAmFilterCategory;// the DirectShow filters category
	//bstrDeviceName = SysAllocString(L"AudioRecorder WAV Dest");// device name as seen in Graphedit.exe,using SysAllicString(..) to properly allocate string 
	bstrDeviceName = SysAllocString(L"WAV Dest");
	pDeviceMonik = Device_Read(pDeviceEnum,pDeviceMonik,DEVICE_CLSID,bstrDeviceName);//read the required device
	pWAVRecorder = Device_Init(pDeviceMonik,pWAVRecorder);//Return the device after initializing it
	Device_Addition(pGraph,pWAVRecorder,bstrDeviceName);//add device to graph
	SysFreeString(bstrDeviceName);
	/******************************************************************************/
	//Connect input to output, Mic to AudioRecoder WAV Dest filter
	bstrInPinName = SysAllocString(L"Capture");//Input pin name, as seen in GraphEdit
	bstrOutPinName = SysAllocString(L"In");//Output pin name, this one will be input for AudioRecorder WAV Dest filter
	Device_Connect(pInputDevice,pWAVRecorder,bstrInPinName,bstrOutPinName);//connect
	SysFreeString(bstrInPinName);
	SysFreeString(bstrOutPinName);
	SysFreeString(bstrDeviceName);
	/*******************************************************************************/
	//Default output device
	DEVICE_CLSID = CLSID_LegacyAmFilterCategory;// the DirectShow filters category
	bstrDeviceName = SysAllocString(L"File writer");// device name as seen in Graphedit.exe,using SysAllicString(..) to properly allocate string 
	pDeviceMonik = Device_Read(pDeviceEnum,pDeviceMonik,DEVICE_CLSID,bstrDeviceName);//read the required device
	pFileWriter = Device_Init(pDeviceMonik,pFileWriter);//Return the device after initializing it
	SysFreeString(bstrDeviceName);
	SysAllocString(L"..\\test.wav");//This is the file name as seen in GraphEdit
	// access the default file before adding to the graph.
	//This function must be called first before adding
	//the device to the graph.
	pFile = Add_File(pGraph,pFileWriter,pFile,bstrDeviceName);
	Device_Addition(pGraph,pFileWriter,bstrDeviceName);//add device to graph
	/******************************************************************************/
	//Connect input to output, AudioRecoder WAV Dest filter to test.wav i.e. File writer filter
	bstrInPinName = SysAllocString(L"Out");//Input pin name, as seen in GraphEdit
	bstrOutPinName = SysAllocString(L"in");//Output pin name, this one will be input for File writer filter
	Device_Connect(pWAVRecorder,pFileWriter,bstrInPinName,bstrOutPinName);//Connect
	SysFreeString(bstrInPinName);
	SysFreeString(bstrOutPinName);
	SysFreeString(bstrDeviceName);
	/*******************************************************************************/

	//Now run the graph
	Run_Graph(pControl);

	//Loop till you don't close the console window or hit a key!
	cout<<"Close the window to exit or hit any key"<<endl;
	while(!_kbhit())
	{

	}

	pFile->Release();
	pControl->Release();//Release control
	pDeviceEnum->Release();//Release Device enumerator
	pGraph->Release();//Release the Graph
}


/************************************************************/
bool Bstr_Compare(BSTR bstrFilter,BSTR bstrDevice)
{
	bool flag = true;
	int strlenFilter = SysStringLen(bstrFilter);//set string length
	int strlenDevice = SysStringLen(bstrDevice);//set string length
	char* chrFilter = (char*)malloc(strlenFilter+1);// allocate memory
	char* chrDevice = (char*)malloc(strlenDevice+1);// allocate memory
	int j = 0;

	if (strlenFilter!=strlenDevice)//if the strings are of not the same length,means they totall different strings
		flag = false;//sety flag to false to indicate "not-same" strings
	else
	{
		for(; j < strlenFilter;j++)//now, copy 1 by 1 each char to chrFilter and chrDevice respectively
		{
			chrFilter[j] = (char)bstrFilter[j];//copy
			chrDevice[j] = (char)bstrDevice[j];//copy
			cout<<j;

		}
		chrFilter[strlenFilter] = '\0';//add terminating character
		chrDevice[strlenDevice] = '\0';//add terminating character

		for(j=0; j < strlenFilter;j++)//check loop
		{
			if(chrFilter[j] != chrDevice[j])//check if there are chars that are not samne
				flag = false;//if chars are not same, set flag to false to indicate "not-same" strings
		}

		if(flag == true && j == strlenFilter-1)//see if we went through the 'check loop' 
			flag = true;//means strings are same
	}
	return flag;
}


/************************************************************/
void HR_Failed(HRESULT hr)
{
// 	TCHAR szErr[MAX_ERROR_TEXT_LEN];
// 	DWORD res = AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN);
// 	if (res == 0)
// 	{
// 		StringCchPrintf(szErr, MAX_ERROR_TEXT_LEN, L"Unknown Error: 0x%2x", hr);
// 	}
// 
// 	MessageBox(0, szErr, TEXT("Error!"), MB_OK | MB_ICONERROR);
	return;
}

/************************************************************/
IMoniker* Device_Read(ICreateDevEnum* pDeviceEnum,IMoniker *pDeviceMonik,GUID DEVICE_CLSID,BSTR bstrDeviceName)
{
	HRESULT hr;
	IEnumMoniker *pEnumCat = NULL;// Device enumeration moniker
	VARIANT varName;

	hr = pDeviceEnum->CreateClassEnumerator(DEVICE_CLSID, &pEnumCat, 0);// Enumerate the specified device, distinguished by DEVICE_CLSID

	if (hr == S_OK) 
	{
		ULONG cFetched;
		while (pEnumCat->Next(1, &pDeviceMonik, &cFetched) == S_OK)//Pickup as moniker
		{
			IPropertyBag *pPropBag = NULL;
			hr = pDeviceMonik->BindToStorage(0, 0, IID_IPropertyBag,(void **)&pPropBag);//bind the properties of the moniker
			if (SUCCEEDED(hr))
			{
				VariantInit(&varName);// Initialise the variant data type
				hr = pPropBag->Read(L"FriendlyName", &varName, 0);
				if (SUCCEEDED(hr))
				{	
					if(Bstr_Compare(varName.bstrVal,bstrDeviceName) == true)//make a comparison
					{	
						wcout<<varName.bstrVal<<" found"<<endl;
						return pDeviceMonik;
					}
				}
				else HR_Failed(hr);
				VariantClear(&varName);//clear the variant data type
				pPropBag->Release();//release the properties
			}
			else HR_Failed(hr);
			pDeviceMonik->Release();//release Device moniker
		}
		pEnumCat->Release();//release category enumerator
	}
	else HR_Failed(hr);
	return NULL;
}

/************************************************************/
IBaseFilter* Device_Init(IMoniker* pDeviceMonik,IBaseFilter* pDevice)
{
	HRESULT hr;
	hr = pDeviceMonik->BindToObject(NULL, NULL, IID_IBaseFilter,(void**)&pDevice);//Instantiate the device
	if (SUCCEEDED(hr))
	{
		cout<<"Device initiation successful..."<<endl;
	}
	else HR_Failed(hr);

	return pDevice;
}


/************************************************************/
void Device_Addition(IGraphBuilder* pGraph,IBaseFilter* pDevice,BSTR bstrName)
{
	HRESULT hr;
	hr = pGraph->AddFilter(pDevice,bstrName);//Adding to main graph
	if(SUCCEEDED(hr))
	{
		wcout<<"Addition of "<<bstrName<<" successful..."<<endl;
	}
	else HR_Failed(hr);
}


/************************************************************/
void Device_Connect(IBaseFilter* pInputDevice,IBaseFilter* pOutputDevice,BSTR bstrInputPin,BSTR bstrOutputPin)
{
	HRESULT hr;
	IEnumPins *pInputPin = NULL,*pOutputPin  = NULL;// Pin enumeration
	IPin *pIn = NULL, *pOut = NULL;// Pins

	hr = pInputDevice->EnumPins(&pInputPin);// Enumerate the pin
	if(SUCCEEDED(hr))
	{
		cout<<"Input Pin Enumeration successful..."<<endl;
		hr = pInputDevice->FindPin(bstrInputPin,&pIn);//Get hold of the pin as seen in GraphEdit
		if(SUCCEEDED(hr))
		{
			wcout<<bstrInputPin<<" Input pin found"<<endl;	
		}
		else HR_Failed(hr);

	}
	else HR_Failed(hr);

	hr = pOutputDevice->EnumPins(&pOutputPin);//Enumerate the pin
	if(SUCCEEDED(hr))
	{
		cout<<"Output Pin Enumeration successful..."<<endl;
		hr = pOutputDevice->FindPin(bstrOutputPin,&pOut);
		if(SUCCEEDED(hr))
		{
			wcout<<bstrOutputPin<<" Output pin found"<<endl;
		}
		else HR_Failed(hr);

	}
	else HR_Failed(hr);

	hr = pIn->Connect(pOut,NULL);	//Connect the input pin to output pin
	if(SUCCEEDED(hr))
	{
		cout<<"Pin connection successful..."<<endl;
	}
	else HR_Failed(hr);

}


/************************************************************/
void Run_Graph(IMediaControl* pControl)
{
	HRESULT hr;
	hr = pControl->Run();// Now run the graph, i.e. start recording!
	if(SUCCEEDED(hr))
	{
		cout<<"You must be recodring to something!!!"<<endl;
	}
	else HR_Failed(hr);
}
IFileSinkFilter* Add_File(IGraphBuilder *pGraph,IBaseFilter* pDevice,IFileSinkFilter* pFile,BSTR bstrName)
{
	HRESULT hr;

	IFileSinkFilter *pFileSink= NULL;// pointer to filter that allows data writing
	hr = pDevice->QueryInterface(IID_IFileSinkFilter, (void**)&pFile);
	if(SUCCEEDED(hr))
	{
		wcout<<"Querying of IFileSinkFilter "<<bstrName<<" successful..."<<endl;
	}
	else HR_Failed(hr);
	hr = pFile->SetFileName(bstrName,NULL);//setting the name of the file
	if(SUCCEEDED(hr))
	{
		wcout<<"Setting name to "<<bstrName<<" successful..."<<endl;
	}
	else HR_Failed(hr);

	return pFileSink = pFile;
}
posted @ 2011-06-24 17:04  iThinking  阅读(932)  评论(0编辑  收藏  举报