0

I have a directshow filter that I use to capture the screen using the code below.

First I get the window rect using

EnumWindows

this gives me lpRect

HDC         hMemDC;
HBITMAP     hBitmap, hOldBitmap;
int         nX, nY, nX2, nY2;
int         nWidth, nHeight;

if (IsRectEmpty(lpRect))
  return NULL;

hMemDC = CreateCompatibleDC(hScrDC);

nX  = lpRect->left;
nY  = lpRect->top;
nX2 = lpRect->right;
nY2 = lpRect->bottom;

nWidth  = nX2 - nX;
nHeight = nY2 - nY;

hBitmap = CreateCompatibleBitmap(hScrDC, nWidth, nHeight);

hOldBitmap = (HBITMAP) SelectObject(hMemDC, hBitmap);

BitBlt(hMemDC, 0, 0, nWidth, nHeight, hScrDC, nX, nY, SRCCOPY); 

hBitmap = (HBITMAP) SelectObject(hMemDC, hOldBitmap);

GetDIBits(hScrDC, hRawBitmap, 0, nHeightScanLines, pData, pHeader, DIB_RGB_COLORS);     

DeleteDC(hMemDC);

The problem is when I resize the window I'm trying to capture, it should look like thisenter image description here

However it ends up like this enter image description here

I have a feeling it is due to the pixel count for the width of the image however I'm unsure how to resize the output width and height of the directshow filter?

kiwijus
  • 1,217
  • 1
  • 20
  • 40
  • Can you share the code that does the actual resizing and the code that does the rendering? Somewhere it appears that a "pitch" variable is getting ignored. – selbie Jan 26 '12 at 21:42
  • The above code is what I use to do the rendering (in the FillBuffer method). For the resizing I'm literally just changing lpRect to the window's rectangle. – kiwijus Jan 26 '12 at 21:51
  • Right, but how are you saving those bits to file and/or rendering them to the screen? I suspect your problem lies there. – selbie Jan 26 '12 at 21:55
  • I get the samples in "HRESULT CScreenCap::FillBuffer(IMediaSample *pSample)" and then use "pSample->GetPointer(&pData);" then pData gets passed into DIBits – kiwijus Jan 26 '12 at 22:03
  • I suspect that somewhere during all this capturing and conversion process - one of you "width" variables is not divisible by 4. You should be familiar with "surface strides" and how that relates to BMP files and/or blitting to the screen. More details at the bottom of this page: http://msdn.microsoft.com/en-us/library/windows/desktop/dd318229(v=vs.85).aspx – selbie Jan 26 '12 at 22:14

2 Answers2

0

This issue may occur when the filter provides a video sample with dimensions different from what was negotiated.

If the filter should capture only the window content without cropping or padding and the window size changes, then it should renegotiate the media format with the downstream filter. The article Dynamic Format Changes describes different solutions. Also, see Custom DirectShow Source Filter - Dynamic Resolution Change for an example.

Community
  • 1
  • 1
Dmitry Shkuropatsky
  • 3,902
  • 2
  • 21
  • 13
  • So would I be correct in adding the ReceiveConnection function to my directshow filter? – kiwijus Jan 28 '12 at 16:22
  • Yes, if you need to increase the buffer size. See [Handling Dynamic Format Changes in DirectShow](http://stackoverflow.com/questions/6124609/handling-dynamic-format-changes-in-directshow) for more information. It may be more expensive than using `QueryAccept` approach though. – Dmitry Shkuropatsky Jan 31 '12 at 15:32
0

The effect you are having is that your buffers don't match media type your filter has on its pin connection. Typically this happens if filters (pins) incorrectly handle extended video stride changes as described in Handling Format Changes from the Video Renderer.

More likely in your case however is that you are losing correct media type trying to resize. Your code does not actually do any resizing, and as you possibly expect resizing to take place your filled buffers end up mismatching the media type on the connection.

Roman R.
  • 68,205
  • 6
  • 94
  • 158
  • So in order to do some resizing should I create a new BITMAPINFO and VIDEOINFOHEADER and set a new AM_MEDIA_TYPE? – kiwijus Jan 28 '12 at 16:24
  • Your filter is connected with certain media type on the output pin. You are to `FillBuffer` respectively, to match this media type. Nobody is going to resize the payload data for you if you only change some `RECT`. Hence, the first thing is that your buffer have to be consistent with media type (immediate cause of the effect you have). Next is if you need to resize, post more details when and how you would like to have it done. – Roman R. Jan 28 '12 at 17:28
  • Ahh okay! I'm trying to get the buffer to resize when the window that I'm tracking is resized – kiwijus Jan 28 '12 at 21:41
  • Let's suppose you have 800x600 window and your filter is connected with 800x600 video media type. Then your window is resized to 640x480. You should renegotiate the media type and before it happens you cannot just push video sized 640x480. You have a few options for changing media type described there http://msdn.microsoft.com/en-us/library/windows/desktop/dd388731%28v=vs.85%29.aspx however be prepared that they might fail: changing media type on run time is nor a mandatory feature of a filter, so many filters are just not capable of changing media type while the graph his running. – Roman R. Jan 29 '12 at 09:07
  • That seems to make more sense! After reading through the msdn document, would I be correct in saying the best way would be to first use QueryAccept (Downstream) and if that fails then try ReceiveConnection? – kiwijus Jan 29 '12 at 17:53
  • It is up to you, the order is irrelevant. Your best hope is that at least one of these is supported. – Roman R. Jan 29 '12 at 18:03
  • As you've said it seems a bit hit and miss whether it can be supported I've decided on a simpler way, make the output size fixed and instead stretchblt to fit this. Thanks very much for your help! – kiwijus Jan 29 '12 at 20:41