C ++ DirectShow W32 Рисование прямо на фрейме - PullRequest
3 голосов
/ 09 августа 2011

Как рисовать прямо на видеокадре (веб-камере)? Мне нужно разместить водяной знак в углу, поэтому, когда я записываю видео в файл, этот водяной знак должен быть на каждом кадре?

Моя настройка следующая:

struct Sampler : public CBaseVideoRenderer 
{
    Sampler( IUnknown* unk, HRESULT *hr ) : CBaseVideoRenderer(__uuidof(CLSID_Sampler), NAME("Frame Sampler"), unk, hr) {};

    HRESULT CheckMediaType(const CMediaType *media ) 
    {    
        VIDEOINFO* vi; 
        if(!IsEqualGUID( *media->Subtype(), MEDIASUBTYPE_RGB24) || !(vi=(VIDEOINFO *)media->Format()) ) return E_FAIL;
        bmih=vi->bmiHeader; 
        return  S_OK;
    }
    HRESULT DoRenderSample(IMediaSample *sample)
    {
            int w=bmih.biWidth;
            int h=bmih.biHeight;
            BYTE* data; sample->GetPointer( &data ); 
            HDC dc=GetDC(hCameraWindow);
            BITMAPINFO bmi={0}; bmi.bmiHeader=bmih; RECT r; GetClientRect( hCameraWindow, &r ); 
            StretchDIBits(dc,0,0,r.right,r.bottom,0,0,bmih.biWidth,bmih.biHeight,data,&bmi,DIB_RGB_COLORS,SRCCOPY);
            ReleaseDC(hCameraWindow,dc);
            return  S_OK;
    }
    HRESULT ShouldDrawSampleNow(IMediaSample *sample, REFERENCE_TIME *start, REFERENCE_TIME *stop) 
    {
        return S_OK; // disable droping of frames
    }
};

И инициализация:

hCameraWindow= CreateWindowEx(WS_EX_CLIENTEDGE, "Static", NULL, WS_CHILD | WS_VISIBLE , 20, 5, 640, 480, okno, NULL, GetModuleHandle(NULL), NULL);
ShowWindow(hCameraWindow,SW_SHOW);
if(!hCameraWindow)exit(0);


IGraphBuilder*  graph= 0;       hr = CoCreateInstance( CLSID_FilterGraph, 0, CLSCTX_INPROC,IID_IGraphBuilder, (void **)&graph );
IMediaControl*  ctrl = 0;       hr = graph->QueryInterface( IID_IMediaControl, (void **)&ctrl );
    IMediaEventEx*  mediaEvent=0;   hr = graph->QueryInterface(IID_IMediaEvent, (LPVOID *) &mediaEvent);
    IVideoWindow*   m_pVWMoniker=0; hr = graph->QueryInterface(IID_IVideoWindow, (LPVOID *) &m_pVWMoniker);

 m_pVWMoniker->put_Owner((OAHWND)hCameraWindow);
 m_pVWMoniker->put_WindowStyle(WS_CHILD | WS_CLIPCHILDREN);
 m_pVWMoniker->put_Visible(OATRUE);
 m_pVWMoniker->put_MessageDrain((OAHWND)hCameraWindow);

 Sampler*        sampler      = new Sampler(0,&hr); 


IPin*           rnd  = 0; hr = sampler->FindPin(L"In", &rnd);
                          hr = graph->AddFilter((IBaseFilter*)sampler, L"Sampler");

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?cams->Next (1, &mon, 0):0;
IBaseFilter*    cam  = 0; hr = mon?mon->BindToObject(0,0,IID_IBaseFilter, (void**)&cam):0;
IEnumPins*      pins = 0; hr = cam?cam->EnumPins(&pins):0; 
IPin*           cap  = 0; hr = pins?pins->Next(1,&cap, 0):0;
                          hr = graph->AddFilter(cam, L"Capture Source"); 
    // Change resolution
    IAMStreamConfig *pConfig=0;
    if(cap->QueryInterface( IID_IAMStreamConfig, (void **)&pConfig) == S_OK )
    {
        int iCount = 0;
        int iSize = 0;      
        hr = pConfig->GetNumberOfCapabilities(&iCount, &iSize);
        VIDEO_STREAM_CONFIG_CAPS caps;
        AM_MEDIA_TYPE *pmtConfig;
        for(int i=0;i<iSize;i++)
        {           
            pConfig->GetStreamCaps(i, &pmtConfig, (BYTE*)&caps);
            // if a resoltion has been found, set format to it
            if( caps.MaxOutputSize.cx == 640  && caps.MinOutputSize.cy == 480 )
            {
                pConfig->SetFormat(pmtConfig);
            }

        }
        DeleteMediaType(pmtConfig);
    } 

hr = graph->Connect(cap,rnd);
hr = graph->Render( cap);
hr = ctrl->Run();

Я могу получить доступ к кадру с помощью «DoRenderSample». DShow действительно не подходит для начинающих пользователей DShow.

Я переключился с VFW и мне нужно рисовать с помощью GDI + на кадре, возможно ли это с помощью SetBitmapBits / GetBitmapBits?

1 Ответ

1 голос
/ 09 октября 2011

Решено Хорошо, у меня это работает, если кому-то интересно - посмотрите ниже на код, он нарисует текст с GDIplus - без обработки ошибок, я оставляю это для себя.

int m_stride;
VIDEOINFOHEADER m_videoInfo;


    HRESULT CheckMediaType(const CMediaType *media ) 
    {    
        VIDEOINFO* vi; 
        if(!IsEqualGUID( *media->Subtype(), MEDIASUBTYPE_RGB24) || !(vi=(VIDEOINFO *)media->Format()) ) return E_FAIL;
        bmih=vi->bmiHeader; 
        m_stride = bmih.biBitCount / 8 * bmih.biWidth;       
        return  S_OK;
    }

 HRESULT DoRenderSample(IMediaSample *sample)
    {       BYTE* data; 
            int w=bmih.biWidth;
            int h=bmih.biHeight;
            int len = sample->GetActualDataLength();
            sample->GetPointer( &data ); 


            BITMAPINFOHEADER bih = bmih;
            Bitmap bmp(bih.biWidth, bih.biHeight, (bmih.biBitCount/8*bmih.biWidth), PixelFormat24bppRGB, data);
            Graphics graphics(&bmp);
            WCHAR wavists[1024];    
            char txt[1024];
            sprintf(txt,"THIS TEXT IS DISPLAYED ON EACH FRAME");MultiByteToWideChar( GetACP(), 0, txt, -1, wavists, strlen(txt));       
            graphics.DrawString(wavists,strlen(txt),&Font(&FontFamily(L"Tahoma"), 16, FontStyleBold, UnitPixel),PointF(0,0),&SolidBrush(Color(200,0,255,0)));





            HDC dc=GetDC(hCameraWindow);
            BITMAPINFO bmi={0}; bmi.bmiHeader=bmih; RECT r; GetClientRect( hCameraWindow, &r ); 
            StretchDIBits(dc,0,0,r.right,r.bottom,0,0,bmih.biWidth,bmih.biHeight,data,&bmi,DIB_RGB_COLORS,SRCCOPY);
            ReleaseDC(hCameraWindow,dc);



}
...