|
看来看去,大家都是用ds graph 来做,需要一整条链。 车门大侠说不需要render就能采集到音视频了,不管三七二十一, 狠狠的抄袭一个demo,居然真的可以了。 fuck she,
对比一下其他的方式,比如音频的采集,玩过WaveIn 之类的api,那还得搞搞搞一段内存去接收,可能还得用上队列的形式,,,,,
算了,总之我觉得写一个filter去连接前端的 audio capture device 或者 video capture device 是最简单的方式! 二话不说,上代码:
先声明:老衲在win7,vs2003 亲自跑过, 可以拿到音频、视频数据的。感谢大师兄, 车门大侠,感谢ffmpeg x264 28785698各位群友,
class CDumpInputPin;
class CDumpFilter;
class CaptureData;
#define BYTES_PER_LINE 20
#define FIRST_HALF_LINE TEXT (" %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x")
#define SECOND_HALF_LINE TEXT (" %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x")
#define PIN_COUNT 1
typedef int(*CALLBACK_CAPTURE)(byte* data, int len);
// Main filter object
class CDumpFilter : public CBaseFilter
{
public:
// Constructor
CDumpFilter(CaptureData *pCap,
LPUNKNOWN pUnk,
CCritSec *pLock,
HRESULT *phr);
~CDumpFilter();
// Pin enumeration
CBasePin * GetPin(int n);
int GetPinCount();
CaptureData* m_pCap;
};
// Pin object
class CDumpInputPin : public CRenderedInputPin
{
public:
CDumpInputPin(CBaseFilter *pFilter,
CCritSec *pLock,
HRESULT *phr);
// Do something with this media sample
STDMETHODIMP Receive(IMediaSample *pSample);
// Check if the pin can support this specific proposed type and format
HRESULT CheckMediaType(const CMediaType * type);
void SetOnRecieveCallback(CALLBACK_CAPTURE fn) { m_pfn = fn; }
private:
CALLBACK_CAPTURE m_pfn;
};
class __declspec(dllexport) CaptureData
{
public:
CaptureData(CALLBACK_CAPTURE fn, bool isaudio=true);
~CaptureData();
int Start();
int Stop();
CDumpInputPin* m_pin[PIN_COUNT];
private:
HRESULT EnumerateDevices(REFGUID category, IEnumMoniker **ppEnum);
HRESULT GetDevices(IEnumMoniker* pEnum);
void SetAudioProperty(IPin *pin);
void SetVideoProperty(IPin *pin);
IGraphBuilder *m_pGraph;
IBaseFilter* m_pFilter;
CDumpFilter* m_pDumpFilter;
IMediaControl *m_pControl;
bool m_bisaudio;
CCritSec m_Lock;
CALLBACK_CAPTURE m_pfn;
};
//以下是cpp文件
#include <windows.h>
#include <commdlg.h>
#include <streams.h>
#include <initguid.h>
#include "dumpuids.h"
#include "dump.h"
#include <stdio.h>
// Setup data
const AMOVIESETUP_MEDIATYPE sudPinTypes =
{
&MEDIATYPE_NULL, // Major type
&MEDIASUBTYPE_NULL // Minor type
};
const AMOVIESETUP_PIN sudPins =
{
L"Input", // Pin string name
FALSE, // Is it rendered
FALSE, // Is it an output
FALSE, // Allowed none
FALSE, // Likewise many
&CLSID_NULL, // Connects to filter
L"Output", // Connects to pin
1, // Number of types
&sudPinTypes // Pin information
};
const AMOVIESETUP_FILTER sudDump =
{
&CLSID_Dump, // Filter CLSID
L"Dump", // String name
MERIT_DO_NOT_USE, // Filter merit
PIN_COUNT, // Number pins
&sudPins // Pin details
};
//
// Object creation stuff
//
CFactoryTemplate g_Templates[]= {
L"Dump", &CLSID_Dump, NULL, NULL, &sudDump
};
int g_cTemplates = 1;
// Constructor
CDumpFilter::CDumpFilter(CaptureData *pCap, LPUNKNOWN pUnk,
CCritSec *pLock,
HRESULT *phr) :
CBaseFilter(NAME("CDumpFilter"), pUnk, pLock, CLSID_Dump), m_pCap(pCap)
{
}
CDumpFilter::~CDumpFilter()
{
}
//
// GetPin
//
CBasePin * CDumpFilter::GetPin(int n)
{
if (n < PIN_COUNT)
return m_pCap->m_pin[n];
else
return NULL;
}
//
// GetPinCount
//
int CDumpFilter::GetPinCount()
{
return PIN_COUNT;
}
//
// Definition of CDumpInputPin
//
CDumpInputPin::CDumpInputPin(CBaseFilter *pFilter,
CCritSec *pLock,
HRESULT *phr)
:CRenderedInputPin(NAME("CDumpInputPin"),
pFilter, // Filter
pLock, // Locking
phr, // Return code
L"Input") // Pin name
{
}
//
// CheckMediaType
//
// Check if the pin can support this specific proposed type and format
//
HRESULT CDumpInputPin::CheckMediaType(const CMediaType *type)
{
return S_OK;
}
//
// Receive
//
// Do something with this media sample
//
STDMETHODIMP CDumpInputPin::Receive(IMediaSample *pSample)
{
CheckPointer(pSample,E_POINTER);
CheckPointer(m_pfn, E_POINTER);
PBYTE pbData;
HRESULT hr = pSample->GetPointer(&pbData);
if (FAILED(hr)) {
return hr;
}
m_pfn(pbData, pSample->GetActualDataLength());
return S_OK;
}
CaptureData::CaptureData(CALLBACK_CAPTURE fn, bool isaudio)
{
CoInitializeEx(NULL, COINIT_MULTITHREADED);
m_bisaudio = isaudio;
m_pfn = fn;
}
CaptureData::~CaptureData()
{
CoUninitialize();
}
int CaptureData::Start()
{
int ret = 0;
IEnumMoniker *pEnum;
IEnumPins *pins;
IPin* pin;
GUID guid = m_bisaudio ? CLSID_AudioInputDeviceCategory : CLSID_VideoInputDeviceCategory;
HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL,
CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&m_pGraph);
if (FAILED(hr)) {
ret = 1;
goto clean;
}
hr = EnumerateDevices(guid, &pEnum);
if (SUCCEEDED(hr)) {
GetDevices(pEnum);
pEnum->Release();
} else {
ret = 2;
goto clean;
}
m_pDumpFilter = new CDumpFilter(this,NULL, &m_Lock, &hr);
for (int i = 0; i < PIN_COUNT; i++) {
m_pin[i] = new CDumpInputPin(m_pDumpFilter, &m_Lock, &hr);
m_pin[i]->SetOnRecieveCallback(m_pfn);
}
m_pGraph->AddFilter((IBaseFilter*)m_pFilter, m_bisaudio?L"audio_cap": L"video_cap");
m_pGraph->AddFilter(m_pDumpFilter, L"m_pDumpFilter");
m_pFilter->EnumPins(&pins);
while (pins->Next(1, &pin, NULL) == S_OK) {
_PinDirection dir;
pin->QueryDirection(&dir);
if (dir == PINDIR_OUTPUT) {
break;
} else {
pin->Release();
}
}
if (m_bisaudio) {
SetAudioProperty(pin);
} else {
SetVideoProperty(pin);
}
hr = m_pGraph->Connect(pin, m_pin[0]);
hr = m_pGraph->QueryInterface(IID_IMediaControl, (void **)&m_pControl);
hr = m_pControl->Run();
pin->Release();
pins->Release();
clean:
return ret;
}
int CaptureData::Stop()
{
if (m_pControl) {
m_pControl->Stop();
m_pControl->Release();
m_pControl = NULL;
}
if (m_pFilter) {
m_pFilter->Release();
m_pFilter = NULL;
}
if (m_pGraph) {
m_pGraph->Release();
m_pGraph = NULL;
}
if (m_pDumpFilter) {
m_pDumpFilter = NULL;
}
for (int i = 0; i < PIN_COUNT; i++) {
delete m_pin[i];
m_pin[i] = NULL;
}
return 0;
}
HRESULT CaptureData::EnumerateDevices(REFGUID category, IEnumMoniker **ppEnum)
{
// Create the System Device Enumerator.
ICreateDevEnum *pDevEnum;
HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL,
CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pDevEnum));
if (SUCCEEDED(hr))
{
// Create an enumerator for the category.
hr = pDevEnum->CreateClassEnumerator(category, ppEnum, 0);
if (hr == S_FALSE)
{
hr = VFW_E_NOT_FOUND; // The category is empty. Treat as an error.
}
pDevEnum->Release();
}
return hr;
}
HRESULT CaptureData::GetDevices(IEnumMoniker* pEnum)
{
HRESULT hr = 0;
IMoniker *pMoniker = NULL;
IBindCtx* ctx = NULL;
CreateBindCtx(0, &ctx);
while (pEnum->Next(1, &pMoniker, NULL) == S_OK) {
hr = pMoniker->BindToObject(ctx, NULL, IID_IBaseFilter, (void**)&m_pFilter);
pMoniker->Release();
if (FAILED(hr)) {
goto clean;
}
// break;
}
clean:
if (ctx)
ctx->Release();
return 0;
}
void CaptureData::SetAudioProperty(IPin *pin)
{
IAMStreamConfig* pConfig = NULL;
AM_MEDIA_TYPE *pmt = NULL;
WAVEFORMATEX *pWF = NULL;
IAMBufferNegotiation *pNegotiation = NULL;
int nBitPerSample = 16;
int nSampleRate = 11025;
int nChannels = 2;
HRESULT hr;
hr = pin->QueryInterface(IID_IAMStreamConfig, (void**)&pConfig);
hr = pin->QueryInterface(IID_IAMBufferNegotiation, (void **)&pNegotiation);
hr = pConfig->GetFormat(&pmt);
if (SUCCEEDED(hr))
{
pWF = (WAVEFORMATEX *)pmt->pbFormat;
pWF->wFormatTag = WAVE_FORMAT_PCM;
pWF->nChannels = (WORD)nChannels;
pWF->wBitsPerSample = (WORD)(nBitPerSample);
pWF->nBlockAlign = (WORD)nChannels * (pWF->wBitsPerSample / 8);
pWF->nSamplesPerSec = nSampleRate;
pWF->nAvgBytesPerSec = pWF->nBlockAlign * pWF->nSamplesPerSec;//nSampleRate * pWF->wBitsPerSample / 8;
// Set the new formattype for the output pin
hr = pConfig->SetFormat(pmt);
DeleteMediaType(pmt);
}
ALLOCATOR_PROPERTIES prop = { 0 };
prop.cBuffers = 6;
prop.cbBuffer = 8192; // pWF->nAvgBytesPerSec;
prop.cbAlign = (nBitPerSample/8) * nChannels;
hr = pNegotiation->SuggestAllocatorProperties(&prop);
pNegotiation->Release();
pConfig->Release();
}
void CaptureData::SetVideoProperty(IPin *pin)
{
IAMStreamConfig* pConfig = NULL;
AM_MEDIA_TYPE *pmt = NULL;
VIDEO_STREAM_CONFIG_CAPS scc;
int count = 0;
int size = 0;
HRESULT hr;
hr = pin->QueryInterface(IID_IAMStreamConfig, (void**)&pConfig);
/*
hr = pConfig->GetNumberOfCapabilities(&count, &size);
for (int i = 0; i < count; i++) {
hr = pConfig->GetStreamCaps(i, &pmt, (BYTE*)&scc);
if (SUCCEEDED(hr)) {
DeleteMediaType(pmt);
}
}
*/
hr = pConfig->GetFormat(&pmt);
if (SUCCEEDED(hr)) {
VIDEOINFOHEADER *pvi = (VIDEOINFOHEADER *)pmt->pbFormat;
//pmt->subtype = MEDIASUBTYPE_YUY2;
pvi->bmiHeader.biWidth = 640;
pvi->bmiHeader.biHeight = 480;
pvi->bmiHeader.biSizeImage = 3 * pvi->bmiHeader.biWidth * pvi->bmiHeader.biHeight;
pvi->AvgTimePerFrame = 25;
hr = pConfig->SetFormat(pmt);
DeleteMediaType(pmt);
}
pConfig->Release();
}
////////////////////////////////////////////////////////////////////////
//
// Exported entry points for registration and unregistration
// (in this case they only call through to default implementations).
//
////////////////////////////////////////////////////////////////////////
//
// DllRegisterSever
//
// Handle the registration of this filter
//
STDAPI DllRegisterServer()
{
return AMovieDllRegisterServer2( TRUE );
} // DllRegisterServer
//
// DllUnregisterServer
//
STDAPI DllUnregisterServer()
{
return AMovieDllRegisterServer2( FALSE );
} // DllUnregisterServer
//
// DllEntryPoint
//
extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);
BOOL APIENTRY DllMain(HANDLE hModule,
DWORD dwReason,
LPVOID lpReserved)
{
return DllEntryPoint((HINSTANCE)(hModule), dwReason, lpReserved);
}
|
|