C++ DirectShow W32 Drawing directly on frame
How can I draw directly on video frame (webcam)? I need to place a watermark in the corner, so when I capture the video to the file, this watermark should be on each frame?
My setup is as follows:
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
}
};
And the initialization :
hCameraWindow= CreateWindowEx(WS_EX_CLIENTEDGE, "Static", NULL, WS_CHILD | WS_VISIBLE , 20, 5, 640, 480, okno, NULL, GetModuleHandle(NULL), NULL);
ShowWindow(hCameraWindow,SW_SHOW开发者_Python百科);
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();
I can access the frame with "DoRenderSample". DShow really is quite non users friendly for DShow beginners.
I switched from VFW and I need to draw with GDI+ on the frame, is it possible with SetBitmapBits / GetBitmapBits?
Resolved Ok I've got it working, if anyone is interested - look below into the code, it will draw a text with GDIplus - no error handling, i leave it for yourself.
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);
}
精彩评论