3

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, but PrintWindow 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.

caesay
  • 16,932
  • 15
  • 95
  • 160

0 Answers0