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; }