2010-06-10 66 views
0

我發現了一些代碼,可以從我的網絡攝像頭訪問原始像素數據。但是,如果圖像的寬度,高度,像素格式以及數據跨度(音調,內存填充或任何您想要調用它的內容)的寬度*每像素的字節數*如何獲取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); 
    } 
}; 

獎勵積分,如果你能告訴我如何讓這件事情不呈現一個窗口,但仍然讓我訪問圖像數據。

回答

4

這真的很醜。請不要這樣做。而不是像樣本採集器那樣插入傳遞過濾器(因爲我在同一主題上回復了您的其他帖子)。將採樣器連接到null渲染器可以在不渲染圖像的情況下以乾淨,安全的方式獲取位。

要獲得跨步,您需要通過ISampleGrabber或IPin :: ConnectionMediaType獲取媒體類型。格式塊將是VIDEOINFOHEADER或VIDEOINFOHEADER2(檢查格式GUID)。 bitmapinfo頭文件biWidth和biHeight定義了位圖維度(因此也定義了步幅)。如果RECT不是空的,則定義位圖內的相關圖像區域。

觸碰此帖後我現在不得不洗手。

+0

哈哈哈。我認爲代碼太短而不好。我會檢查你的其他帖子。 – 2010-06-10 13:17:59

0

我很抱歉。當界面被創建時,可能不是最好的程序員。

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

這裏是如何添加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是一個令人費解的噩夢,需要數百行代碼才能完成最簡單的操作,並調整整個編程範例以訪問您的網絡攝像頭。所以如果這個代碼爲你做了這個工作,就像它爲我做的那樣,使用它並享受更少的代碼行來維護。

+0

它與問題有什麼關係? – 2014-03-11 07:00:11

+0

他問如何擺脫渲染窗口,這是如何。 – tetsuoii 2014-03-11 07:05:03

相關問題