I currently have implemented a DirectShow live source screen capture filter in C#. The DShow filter is being consumed by a separate process (ffmpeg) that is live encoding the stream.
I would like to render some UI/Controls on the screen for starting/stopping the capture of ffmpeg, (UI provided by a separate process) but I don't want the UI to be captured by the DShow filter and end up in the screen capture video.
Here is an excerpt, which contains the DirectShow FillBuffer method where I capture the screen frames.
public int FillBuffer(ref IMediaSampleImpl _sample)
{
IntPtr _ptr;
_sample.GetPointer(out _ptr);
IntPtr srcContext = User32.GetWindowDC(IntPtr.Zero);
IntPtr destContext = GDI32.CreateCompatibleDC(srcContext);
IntPtr destBitmap = GDI32.CreateCompatibleBitmap(srcContext, _captureWidth, _captureHeight);
IntPtr hOld = GDI32.SelectObject(destContext, destBitmap);
GDI32.BitBlt(destContext, 0, 0, _captureWidth, _captureHeight, srcContext, _captureX, _captureY, GDI32.SRCCOPY);
//Draw cursor, ommitted for brevity
GDI32.SelectObject(destContext, hOld);
GDI32.GetDIBits(destContext, destBitmap, 0, (uint)Math.Abs(_captureHeight), _ptr, ref m_bmi, 0);
GDI32.DeleteDC(destContext);
User32.ReleaseDC(IntPtr.Zero, srcContext);
GDI32.DeleteObject(destBitmap);
_sample.SetActualDataLength(_sample.GetSize());
_sample.SetSyncPoint(true);
return NOERROR;
}
I'm not exactly 100% sure how this would be possible, but here are the only things that remotely make sense to me (not saying they are possible, just brainstorming):
- Render the UI controls via a passed window pointer from another process to srcContext each frame but only after its copied to destContext
- how would you even render the passed pointer?
- how do you refresh the screen so that it wont just get captured next frame (now that its rendered to the screen)?
- could this really be viable performance wise (refreshing the screen each frame)?
- Is it really going to look nice? - i can't imagine that rendering to the WindowDC is reccomended
- is there a way to trigger a re-draw of just the UI control region before the next frame and not refresh the entire screen?
- Some how capture the window with GDI but omit the UI window handle via some native API interface i'm unaware of
- Capture the entire screen with current method, then re-draw the area that contains the UI controls with the contents of whatever window(s) were underneath (is this even possible?)
- Capture individual windows, and then render each visible window separately in z-order but skip the UI window (i have a sneaking suspicion that this may be the only way to actually do this, but i doubt that it would meet reasonable performance requirements)
- EDIT, i just thought of using
PrintWindow
of all of the windows behind the UI control, butPrintWindow
is slow and unreliable, and this is performance critical code.. So i would really like a different solution.
I understand that Fraps and similar, use DirectX hooks to intercept paint messages further up the pipeline, and are able to draw overlays on the screen that way - but this is not an option, and neither is a display mirror driver.