如何获取directshow网络摄像头视频流的宽度和高度
我发现了一些代码,可以从我的网络摄像头访问原始像素数据。但是,如果图像的宽度,高度,像素格式以及数据跨度(音调,内存填充或任何您想要调用它的内容)的宽度*每像素的字节数*如何获取directshow网络摄像头视频流的宽度和高度
#include <windows.h>
#include <dshow.h>
#pragma comment(lib,"Strmiids.lib")
#define DsHook(a,b,c) if (!c##_) { INT_PTR* p=b+*(INT_PTR**)a; VirtualProtect(&c##_,4,PAGE_EXECUTE_READWRITE,&no);\
*(INT_PTR*)&c##_=*p; VirtualProtect(p, 4,PAGE_EXECUTE_READWRITE,&no); *p=(INT_PTR)c; }
// Here you get image video data in buf/len. Process it before calling Receive_ because renderer dealocates it.
HRESULT (__stdcall * Receive_) (void* inst, IMediaSample *smp) ;
HRESULT __stdcall Receive (void* inst, IMediaSample *smp) {
BYTE* buf; smp->GetPointer(&buf); DWORD len = smp->GetActualDataLength();
//AM_MEDIA_TYPE* info;
//smp->GetMediaType(&info);
HRESULT ret = Receive_ (inst, smp);
return ret;
}
int WINAPI WinMain(HINSTANCE inst,HINSTANCE prev,LPSTR cmd,int show){
HRESULT hr = CoInitialize(0); MSG msg={0}; DWORD no;
IGraphBuilder* graph= 0; hr = CoCreateInstance(CLSID_FilterGraph, 0, CLSCTX_INPROC,IID_IGraphBuilder, (void **)&graph);
IMediaControl* ctrl = 0; hr = graph->QueryInterface(IID_IMediaControl, (void **)&ctrl);
ICreateDevEnum* devs = 0; hr = CoCreateInstance (CLSID_SystemDeviceEnum, 0, CLSCTX_INPROC, IID_ICreateDevEnum, (void **) &devs);
IEnumMoniker* cams = 0; hr = devs?devs->CreateClassEnumerator (CLSID_VideoInputDeviceCategory, &cams, 0):0;
IMoniker* mon = 0; hr = cams->Next (1,&mon,0); // get first found capture device (webcam?)
IBaseFilter* cam = 0; hr = mon->BindToObject(0,0,IID_IBaseFilter, (void**)&cam);
hr = graph->AddFilter(cam, L"Capture Source"); // add web cam to graph as source
IEnumPins* pins = 0; hr = cam?cam->EnumPins(&pins):0; // we need output pin to autogenerate rest of the graph
IPin* pin = 0; hr = pins?pins->Next(1,&pin, 0):0; // via graph->Render
hr = graph->Render(pin); // graph builder now builds whole filter chain including MJPG decompression on some webcams
IEnumFilters* fil = 0; hr = graph->EnumFilters(&fil); // from all newly added filters
IBaseFilter* rnd = 0; hr = fil->Next(1,&rnd,0); // we find last one (renderer)
hr = rnd->EnumPins(&pins); // because data we are intersted in are pumped to renderers input pin
hr = pins->Next(1,&pin, 0); // via Receive member of IMemInputPin interface
IMemInputPin* mem = 0; hr = pin->QueryInterface(IID_IMemInputPin,(void**)&mem);
DsHook(mem,6,Receive); // so we redirect it to our own proc to grab image data
hr = ctrl->Run();
while (GetMessage( &msg, 0, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage( &msg);
}
};
奖励积分,如果你能告诉我如何让这件事情不呈现一个窗口,但仍然让我访问图像数据。
这真的很丑。请不要这样做。而不是像样本采集器那样插入传递过滤器(因为我在同一主题上回复了您的其他帖子)。将采样器连接到null渲染器可以在不渲染图像的情况下以干净,安全的方式获取位。
要获得跨步,您需要通过ISampleGrabber或IPin :: ConnectionMediaType获取媒体类型。格式块将是VIDEOINFOHEADER或VIDEOINFOHEADER2(检查格式GUID)。 bitmapinfo头文件biWidth和biHeight定义了位图维度(因此也定义了步幅)。如果RECT不是空的,则定义位图内的相关图像区域。
触碰此帖后我现在不得不洗手。
我很抱歉。当界面被创建时,可能不是最好的程序员。
// Here you get image video data in buf/len. Process it before calling Receive_ because renderer dealocates it.
BITMAPINFOHEADER bmpInfo; // current bitmap header info
int stride;
HRESULT (__stdcall * Receive_) (void* inst, IMediaSample *smp) ;
HRESULT __stdcall Receive (void* inst, IMediaSample *smp)
{
BYTE* buf; smp->GetPointer(&buf); DWORD len = smp->GetActualDataLength();
HRESULT ret = Receive_ (inst, smp);
AM_MEDIA_TYPE* info;
HRESULT hr = smp->GetMediaType(&info);
if (hr != S_OK)
{ //TODO: error }
else
{
if (type->formattype == FORMAT_VideoInfo)
{
const VIDEOINFOHEADER * vi = reinterpret_cast<VIDEOINFOHEADER*>(type->pbFormat);
const BITMAPINFOHEADER & bmiHeader = vi->bmiHeader;
//! now the bmiHeader.biWidth contains the data stride
stride = bmiHeader.biWidth;
bmpInfo = bmiHeader;
int width = (vi->rcTarget.right - vi->rcTarget.left);
//! replace the data stride be the actual width
if (width != 0)
bmpInfo.biWidth = width;
}
else
{ // unsupported format }
}
DeleteMediaType(info);
return ret;
}
这里是如何添加Null渲染抑制呈现窗口。创建IGraphBuilder后直接添加*
//create null renderer and add null renderer to graph
IBaseFilter *m_pNULLRenderer; hr = CoCreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void **)&m_pNULLRenderer);
hr = graph->AddFilter(m_pNULLRenderer, L"Null Renderer");
dshook hack是我知道的唯一一个优雅的directshow代码。
以我的经验,DirectShow API是一个令人费解的噩梦,需要数百行代码才能完成最简单的操作,并调整整个编程范例以访问您的网络摄像头。所以如果这个代码为你做了这个工作,就像它为我做的那样,使用它并享受更少的代码行来维护。
它与问题有什么关系? – 2014-03-11 07:00:11
他问如何摆脱渲染窗口,这是如何。 – tetsuoii 2014-03-11 07:05:03
哈哈哈。我认为代码太短而不好。我会检查你的其他帖子。 – 2010-06-10 13:17:59