I need to display the local webcam stream on the screen, horizontally flipped, so that the screen appears as a mirror. I have a DirectShow graph which does all of this, except for mirroring the image. I have tried several approaches to mirror the image, but none have worked.
Approach A: VideoControlFlag_FlipHorizontal
I tried setting the VideoControlFlag_FlipHorizontal
flag
on the output pin of the webcam filter,
like so:
IAMVideoControl* pAMVidControl;
IPin* pWebcamOutputPin;
// ...
// Omitting error-handing for brevity
pAMVidControl->SetMode(pWebcamOutputPin, VideoControlFlag_FlipHorizontal);
However, this has no effect. Indeed, the webcam filter claims to not have this capability, or any other capabilities:
long supportedModes;
hr = pAMVidControl->GetCaps(pWebcamOutputPin, &supportedModes);
// Prints 0, i.e. no capabilities
printf("Supported modes: %ld\n", supportedModes);
Approach B: SetVideoPosition
I tried flipping the image by flipping the rectangles passed to SetVideoPosition
.
(I am using an Enhanced Video Renderer filter, in windowless mode.)
There are two rectangles:
a source rectangle and a destination rectangle.
I tried both.
Here's approach B(i),
flipping the source rectangle:
MFVideoNormalizedRect srcRect;
srcRect.left = 1.0; // note flipped
srcRect.right = 0.0; // note flipped
srcRect.top = 0.0;
srcRect.bottom = 0.5;
return m_pVideoDisplay->SetVideoPosition(&srcRect, &destRect);
This results in nothing being displayed.
It works in other configurations,
but appears to dislike srcRect.left > srcRect.right
.
Here's approach B(ii), flipping the destination rectangle:
RECT destRect;
GetClientRect(hwnd, &destRect);
LONG left = destRect.left;
destRect.left = destRect.right;
destRect.right = left;
return m_pVideoDisplay->SetVideoPosition(NULL, &destRect);
This also results in nothing being displayed.
It works in other configurations,
but appears to dislike destRect.left > destRect.right
.
Approach C: IMFVideoProcessorControl::SetMirror
IMFVideoProcessorControl::SetMirror(MF_VIDEO_PROCESSOR_MIRROR)
sounds like what I want.
This IMFVideoProcessorControl
interface is implemented by the Video Processor MFT.
Unfortunately, this is a Media Foundation Transform,
and I can't see how I could use it in DirectShow.
Approach D: Video Resizer DSP
The Video Resizer DSP is "a COM object that can act as a DMO", so theoretically I could use it in DirectShow. Unfortunately, I have no experience with DMOs, and in any case, the docs for the Video Resizer don't say whether it would support flipping the image.
Approach E: IVMRMixerControl9::SetOutputRect
I found
IVMRMixerControl9::SetOutputRect
,
which explicitly says:
Because this rectangle exists in compositional space, there is no such thing as an "invalid" rectangle. For example, set left greater than right to mirror the video in the x direction.
However, IVMRMixerControl9
appears to be deprecated,
and I'm using an EVR rather than a VMR,
and there are no docs on how to obtain a IVMRMixerControl9
anyway.
Approach F: Write my own DirectShow filter
I'm reluctant to try this one unless I have to. It will be a major investment, and I'm not sure it will be performant enough anyway.
Approach G: start again with Media Foundation
Media Foundation would possibly allow me to solve this problem, because it provides "Media Foundation Transforms". But it's not even clear that Media Foundation would fit all my other requirements.
I'm very surprised that I am looking at such radical solutions for a transform that seems so standard. What other approaches exist? Is there anything I've overlooked in the approaches I've tried? How can I horizontally mirror video in DirectShow?
IMFVideoMixerControl::SetStreamOutputRect
and perhaps it's the first thing to try out. The interface itself can be obtained throughIMFGetService
(same as explained here). Unlike VMR-9, in EVR the mixer is detached from renderer itself, so the interface is not available directly. Options F would surely work, and G+C too but it's a backup plan. – Roman R.