网上很多讲解directshow的资料,讲的都很好,但是就想说各位老大们···上份简单的代码吧,快速开发中 不一定有时间仔细阅读那么多页的文档,对着文档一段段的copy函数也很烦躁,今天我自己传一份directshow获取本地话筒录音的代码。用的时候记得插话筒。
#include "stdafx.h"
#include <dshow.h>
#include <atlconv.h>
#define OUTPUT_PIN 1
#define OUTPUT_MEDIATYPE 1
char* GuidToString(const GUID &guid)
{
int buf_len=64;
char *buf =(char *)malloc(buf_len);
_snprintf(
buf,
buf_len,
"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
guid.Data1, guid.Data2, guid.Data3,
guid.Data4[0], guid.Data4[1],
guid.Data4[2], guid.Data4[3],
guid.Data4[4], guid.Data4[5],
guid.Data4[6], guid.Data4[7]);
//printf("%s\n",buf);
return buf;
}
HRESULT AddFilterByCLSID(
IGraphBuilder *pGraph, // Pointer to the Filter Graph Manager.
const GUID& clsid, // CLSID of the filter to create.
LPCWSTR wszName, // A name for the filter.
IBaseFilter **ppF) // Receives a pointer to the filter.
{
if (!pGraph || ! ppF) return E_POINTER;
*ppF = 0;
IBaseFilter *pF = 0;
HRESULT hr = CoCreateInstance(clsid, 0, CLSCTX_INPROC_SERVER,
IID_IBaseFilter, reinterpret_cast<void**>(&pF));
if (SUCCEEDED(hr))
{
hr = pGraph->AddFilter(pF, wszName);
if (SUCCEEDED(hr))
*ppF = pF;
else
pF->Release();
}
return hr;
}
//
//HRESULT GetUnconnectedPin(
// IBaseFilter *pFilter, // Pointer to the filter.
// PIN_DIRECTION PinDir, // Direction of the pin to find.
// IPin **ppPin) // Receives a pointer to the pin.
//{
// *ppPin = 0;
// IEnumPins *pEnum = 0;
// IPin *pPin = 0;
// HRESULT hr = pFilter->EnumPins(&pEnum);
// if (FAILED(hr))
// {
// return hr;
// }
// while (pEnum->Next(1, &pPin, NULL) == S_OK)
// {
// PIN_DIRECTION ThisPinDir;
// pPin->QueryDirection(&ThisPinDir);
// if (ThisPinDir == PinDir)
// {
// IPin *pTmp = 0;
// hr = pPin->ConnectedTo(&pTmp);
// if (SUCCEEDED(hr)) // Already connected, not the pin we want.
// {
// pTmp->Release();
// }
// else // Unconnected, 这就是我们想要的pin,空闲的pin
// {
// pEnum->Release();
// *ppPin = pPin;
// return S_OK;
// }
// }
// pPin->Release();
// }
// pEnum->Release();
// // Did not find a matching pin.
// return E_FAIL;
//}
//
// Find an unconnected pin on a filter.
// This too is stolen from the DX9 SDK.
HRESULT GetUnconnectedPin(IBaseFilter *pFilter, // Pointer to the filter.
PIN_DIRECTION PinDir, // Direction of the pin to find.
IPin **ppPin) // Receives a pointer to the pin.
{
*ppPin = 0;
IEnumPins *pEnum = 0;
IPin *pPin = 0;
HRESULT hr = pFilter->EnumPins(&pEnum);
if (FAILED(hr))
{
return hr;
}
while (pEnum->Next(1, &pPin, NULL) == S_OK)
{
PIN_DIRECTION ThisPinDir;
pPin->QueryDirection(&ThisPinDir);
if (ThisPinDir == PinDir)
{
IPin *pTmp = 0;
hr = pPin->ConnectedTo(&pTmp);
if (SUCCEEDED(hr)) // Already connected--not the pin we want
{
pTmp->Release();
}
else // Unconnected--this is the pin we want
{
pEnum->Release();
*ppPin = pPin;
return S_OK;
}
}
pPin->Release();
}
pEnum->Release();
// Did not find a matching pin.
return E_FAIL;
}
HRESULT ConnectFilters(
IGraphBuilder *pGraph, // Filter Graph Manager.
IPin *pOut, // Output pin on the upstream filter.
IBaseFilter *pDest) // Downstream filter.
{
if ((pGraph == NULL) || (pOut == NULL) || (pDest == NULL))
{
return E_POINTER;
}
#ifdef debug
PIN_DIRECTION PinDir;
pOut->QueryDirection(&PinDir);
_ASSERTE(PinDir == PINDIR_OUTPUT);
#endif
//找一个空闲的输入pin
IPin *pIn = 0;
HRESULT hr = GetUnconnectedPin(pDest, PINDIR_INPUT, &pIn);
if (FAILED(hr))
{
return hr;
}
// Try to connect them.
hr = pGraph->Connect(pOut, pIn);
pIn->Release();
return hr;
}
static const GUID CLSID_WavDest =
{ 0x3c78b8e2, 0x6c4d, 0x11d1, { 0xad, 0xe2, 0x0, 0x0, 0xf8, 0x75, 0x4b, 0x99 } };
// Enumerate all of the audio input devices
// Return the _first_ of these to the caller
// That should be the one chosen in the control panel.
HRESULT EnumerateAudioInputFilters(void** gottaFilter)
{
// Once again, code stolen from the DX9 SDK.
// Create the System Device Enumerator.
ICreateDevEnum *pSysDevEnum = NULL;
HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL,
CLSCTX_INPROC_SERVER, IID_ICreateDevEnum,
(void **)&pSysDevEnum);
if (FAILED(hr))
{
return hr;
}
// Obtain a class enumerator for the audio input category.
IEnumMoniker *pEnumCat = NULL;
hr = pSysDevEnum->CreateClassEnumerator(CLSID_AudioInputDeviceCategory,
&pEnumCat, 0);
if (hr == S_OK)
{
// Enumerate the monikers.
IMoniker *pMoniker = NULL;
ULONG cFetched;
if (pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK)
{
// Bind the first moniker to an object.
IPropertyBag *pPropBag;
hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag,
(void **)&pPropBag);
if (SUCCEEDED(hr))
{
// To retrieve the filter's friendly name,
// do the following:
VARIANT varName;
VariantInit(&varName);
hr = pPropBag->Read(L"FriendlyName", &varName, 0);
if (SUCCEEDED(hr))
{
wprintf(L"Selecting Audio Input Device: %s\n",
varName.bstrVal);
}
VariantClear(&varName);
// To create an instance of the filter,
// do the following:
// Remember to release gottaFilter later.
hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter,gottaFilter);
pPropBag->Release();
}
pMoniker->Release();
}
pEnumCat->Release();
}
pSysDevEnum->Release();
return hr;
}
// Code adopted from example in the DX9 SDK.
// This code allows us to find the input pins an audio input filter.
// We'll print out a list of them, indicating the enabled one.
HRESULT EnumerateAudioInputPins(IBaseFilter *pFilter)
{
IEnumPins *pEnum = NULL;
IPin *pPin = NULL;
PIN_DIRECTION PinDirThis;
PIN_INFO pInfo;
IAMAudioInputMixer *pAMAIM = NULL;
BOOL pfEnable = FALSE;
// Begin by enumerating all the pins on a filter.
HRESULT hr = pFilter->EnumPins(&pEnum);
if (FAILED(hr))
{
return NULL;
}
// Now, look for a pin that matches the direction characteristic.
// When we've found it, we'll examine it.
while(pEnum->Next(1, &pPin, 0) == S_OK)
{
// Get the pin direction.
pPin->QueryDirection(&PinDirThis);
if (PinDirThis == PINDIR_INPUT) {
// OK, we've found an input pin on the filter.
// Now let's get the information on that pin
// so we can print the name of the pin to the console.
hr = pPin->QueryPinInfo(&pInfo);
if (SUCCEEDED(hr)) {
wprintf(L"Input pin: %s\n", pInfo.achName);
// Now let's get the correct interface.
hr = pPin->QueryInterface(IID_IAMAudioInputMixer,
(void**) &pAMAIM);
if (SUCCEEDED(hr)) {
// Find out whether the pin is enabled.
// Is it the active input pin on the filter?
hr = pAMAIM->get_Enable(&pfEnable);
if (SUCCEEDED(hr)) {
if (pfEnable) {
wprintf(L"\tENABLED\n");
}
}
pAMAIM->Release();
}
pInfo.pFilter->Release(); // from QueryPinInfo
}
}
pPin->Release();
}
pEnum->Release();
return hr;
}
// Connect two filters together with the Filter Graph Manager,
// Stolen from the DX9 SDK.
// This is the base version.
//HRESULT ConnectFilters(IGraphBuilder *pGraph, // Filter Graph Manager.
// IPin *pOut, // Output pin on the upstream filter.
// IBaseFilter *pDest) // Downstream filter.
//{
// if ((pGraph == NULL) || (pOut == NULL) || (pDest == NULL))
// {
// return E_POINTER;
// }
// // Find an input pin on the downstream filter.
// IPin *pIn = 0;
// HRESULT hr = GetUnconnectedPin(pDest, PINDIR_INPUT, &pIn);
// if (FAILED(hr))
// {
// return hr;
// }
// // Try to connect them.
// hr = pGraph->Connect(pOut, pIn);
// pIn->Release();
// return hr;
//}
// Enumerate all of the audio compressors.
// Return the one with the matching name to the caller.
HRESULT EnumerateAudioCompressorFilters(void** gottaCompressor,
wchar_t* matchName)
{
// Once again, code stolen from the DX9 SDK.
// Create the System Device Enumerator.
ICreateDevEnum *pSysDevEnum = NULL;
HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL,
CLSCTX_INPROC_SERVER,
IID_ICreateDevEnum,
(void **)&pSysDevEnum);
if (FAILED(hr))
{
return hr;
}
// Obtain a class enumerator for the audio input category.
IEnumMoniker *pEnumCat = NULL;
hr = pSysDevEnum->CreateClassEnumerator(CLSID_AudioCompressorCategory,
&pEnumCat, 0);
if (hr == S_OK)
{
// Enumerate the monikers.
IMoniker *pMoniker = NULL;
ULONG cFetched;
BOOL done = false;
while ((pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK) && (!done))
{
// Bind the first moniker to an object.
IPropertyBag *pPropBag;
hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag,
(void **)&pPropBag);
if (SUCCEEDED(hr))
{
// Retrieve the filter's friendly name.
VARIANT varName;
VariantInit(&varName);
hr = pPropBag->Read(L"FriendlyName", &varName, 0);
if (SUCCEEDED(hr))
{
wprintf(L"Testing Audio Compressor: %s\n",
varName.bstrVal);
// Is it the right one?
if (wcsncmp(varName.bstrVal, matchName,
wcslen(matchName)) == 0)
{
// We found it; send it back to the caller
hr = pMoniker->BindToObject(NULL, NULL,
IID_IBaseFilter,
gottaCompressor);
done = true;
}
}
VariantClear(&varName);
pPropBag->Release();
}
pMoniker->Release();
}
pEnumCat->Release();
}
pSysDevEnum->Release();
return hr;
}
// Connect two filters together with the Filter Graph Manager.
// Again, stolen from the DX9 SDK.
// This is an overloaded version.
HRESULT ConnectFilters(IGraphBuilder *pGraph,
IBaseFilter *pSrc,
IBaseFilter *pDest)
{
if ((pGraph == NULL) || (pSrc == NULL) || (pDest == NULL))
{
return E_POINTER;
}
// Find an output pin on the first filter.
IPin *pOut = 0;
HRESULT hr = GetUnconnectedPin(pSrc, PINDIR_OUTPUT, &pOut);
if (FAILED(hr))
{
return hr;
}
hr = ConnectFilters(pGraph, pOut, pDest);
pOut->Release();
return hr;
}
int _tmain(int argc, _TCHAR* argv[])
{
IGraphBuilder *pGraph = NULL; // Filter graph builder object
IMediaControl *pControl = NULL; // Media control object
IFileSinkFilter *pSink = NULL; // Interface on file writer
IBaseFilter *pAudioInputFilter = NULL; // Audio capture filter
IBaseFilter *pFileWriter = NULL; // File writer filter
// Initialize the COM library.
HRESULT hr = CoInitialize(NULL);
if (FAILED(hr))
{
// We'll send our error messages to the console.
printf("ERROR - Could not initialize COM library");
return hr;
}
// Create the Filter Graph Manager and query for interfaces.
hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
IID_IGraphBuilder, (void **)&pGraph);
if (FAILED(hr)) // FAILED is a macro that tests the return value
{
printf("ERROR - Could not create the Filter Graph Manager.");
return hr;
}
// Using QueryInterface on the graph builder object,
// get the IMediaControl object.
hr = pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl);
if (FAILED(hr))
{
printf("ERROR - Could not create the Media Control object.");
pGraph->Release(); // Clean up after ourselves
CoUninitialize(); // And uninitalize COM
return hr;
}
// OK, so now we want to build the filter graph
// using an AudioCapture filter.
// But there are several to choose from,
// so we need to enumerate them and then pick one.
hr = EnumerateAudioInputFilters((void**) &pAudioInputFilter);
hr = EnumerateAudioInputPins(pAudioInputFilter);
// Add the audio capture filter to the filter graph.
hr = pGraph->AddFilter(pAudioInputFilter, L"Capture");
// Next add the AVIMux. (You'll see why.)
IBaseFilter *pAVIMux = NULL;
hr = AddFilterByCLSID(pGraph, CLSID_AviDest, L"AVI Mux", &pAVIMux);
// Connect the filters.
hr = ConnectFilters(pGraph, pAudioInputFilter, pAVIMux);
// And now we instance a file writer filter.
hr = AddFilterByCLSID(pGraph, CLSID_FileWriter,
L"File Writer", &pFileWriter);
// Set the file name.
hr = pFileWriter->QueryInterface(IID_IFileSinkFilter, (void**)&pSink);
pSink->SetFileName(L"C:\\MyWAVFile.AVI", NULL);
// Connect the filters.
hr = ConnectFilters(pGraph, pAVIMux, pFileWriter);
if (SUCCEEDED(hr))
{
// Run the graph.
hr = pControl->Run();
if (SUCCEEDED(hr))
{
// Wait patiently for completion of the recording.
wprintf(L"Started recording...press Enter to stop recording.\n");
// Wait for completion.
char ch;
ch = getchar(); // We wait for keyboard input
}
// And stop the filter graph.
hr = pControl->Stop();
wprintf(L"Stopped recording.\n"); // To the console
// Before we finish, save the filter graph to a file.
// SaveGraphFile(pGraph, L"C:\\MyGraph.GRF");
}
// Now release everything and clean up.
pSink->Release();
pAVIMux->Release();
pFileWriter->Release();
pAudioInputFilter->Release();
pControl->Release();
pGraph->Release();
CoUninitialize();
return 0;
}