2010-06-10 2 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

정말 못 생겼어. 제발 그만 하지마. 대신 샘플 그래버와 같은 통과 필터를 삽입하십시오 (동일한 주제에 대해 다른 게시물에 답한대로). 샘플 그래버를 널 렌더러에 연결하면 이미지를 렌더링하지 않고 깨끗하고 안전한 방법으로 비트를 얻을 수 있습니다.

스트라이드를 얻으려면 ISampleGrabber 또는 IPin :: ConnectionMediaType을 통해 미디어 유형을 가져와야합니다. 포맷 블록은 VIDEOINFOHEADER 또는 VIDEOINFOHEADER2입니다 (GUID 포맷을 확인하십시오). bitmapinfo 헤더 인 biWidth와 biHeight는 비트 맵 차원 (따라서 스트라이드)을 정의합니다. RECT가 비어 있지 않으면 비트 맵에서 관련 이미지 영역을 정의합니다.

나는이 게시물을 만진 후 지금 손을 씻어야 할 것이다.

+0

하하하. 나는 코드가 너무 짧아서 좋지 않다고 생각했다. 나는 너의 다른 지위를 조사 할 것이다. –

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

질문과 어떤 관련이 있습니까? –

+0

그는 렌더링 창을 제거하는 방법을 물었습니다. – tetsuoii

관련 문제