I am developing an application for Windows 10 phone on Universal Windows Platform. I need to get a frame from the devices camera and do some processing; this is supposed to happen in the background, the user is not supposed to see the camera feed anywhere in the UI.
There are two classes that handle the most common use cases, namely CameraCaptureUI and MediaCapture. The MediaCapture class allows to grab the so called preview frame but the whole workflow revolves around binding a MediaCapture instance to a UI control (ie CaptureElement) and if I do not do it then I am unable to get the preview frames. This makes the MediaCapture class unsuitable for my case unless there is another way to use it that I am not aware of.
An answer to a related question How to get preview buffer of MediaCapture - Universal app suggests usage of Lumia Imaging SDK but it is targeted at Windows 8 family and the classes and methods used there are now deprecated in the current Lumia Imaging SDK for Windows 10.
Additionaly, the aforementioned answer brings up custom media sinks but I am unsure if that can help me in my scenario and if yes, then where should I start.
To sum up, how do I acquire frames from a camera device that can be used for further processing in a Windows 10 universal app?
There are multiple options available to you for this. CameraCaptureUI is not one of them.
Hide the CaptureElement
Opacity = 0
Visibility.Collapsed
Create it in code and don't add it to your layout
etc.
StartPreviewToCustomSink (https://msdn.microsoft.com/en-us/library/windows/apps/hh700850.aspx) although I've never done this. This link might also help.
Once you've done that, you can take photos or just get preview frames. The CameraStarterKit will teach you the former, CameraGetPreviewFrame will teach you the latter.
How about you put a CaptureElement in UI, but hide it with overlay or set width / height to 1 ? Its kind of a hack but it will provide you the frame.
Related
I would like to create a "virtual camera" that can be used with 3rd party apps such as Zoom or Skype, browser etc. In the same way these can work with a virtual camera app such as Snap.
I want to take the feed from the built in webcam on the laptop, make some changes to it e.g. brightness, then be able to select in Zoom, Skype, browser, my edited feed.
So far I have written something as a Universal Windows Platform app that takes the webcam feed, applies my processing to it, and shows it in a window. For that I have used the Windows Media API.
https://learn.microsoft.com/en-us/uwp/api/windows.media.effects?view=winrt-19041
Can anyone point me in the right direction of how to take this modified feed and make available to Zoom, Skype, browsers? I've seen a lot of stuff related to DirectShow but nothing that fully makes sense or that has been written in the last 6 or 7 years. What would be the best way to do this in 2020, with C#?
Many thanks
I'm working on a UWP app that needs to scan QR codes from a laptop webcam. I'm using the Windows.Media.Capture.MediaCapture class for this. Everything works well, except for when using qr code on a smartphone with it's brightness set too high for the limited dynamic range of built-in webcams. The auto-exposure of the webcam is active, but the screen can still be too bright compared to the environment.
I'm looking for a way to control or override the brightness or exposure either manually or by using some kind of exposure compensation mode.
The only properties to do with brightness/exposure that are enabled/working on my regular built-in webcam are Brightness and Contrast, and those change the image accordingly, but look like they are post-processing effects. They don't change the exposure of the camera itself, thus not fixing the issue.
mediaCapture.VideoDeviceController.ExposureCompensationControl.Supported;
mediaCapture.VideoDeviceController.ExposureControl.Supported;
mediaCapture.VideoDeviceController.ExposurePriorityVideoControl.Supported;
mediaCapture.VideoDeviceController.Exposure.Capabilities.Supported;
all return false
mediaCapture.VideoDeviceController.Brightness.TrySetValue(10);
changes the image, but highlights are still washed out and have no detail for the scanner to pickup
With respect to programmatically controlling the camera exposure via a windows driver, you are considering the correct interface. Using the MS Surface Pro 4, I have successfully modified the exposure using this interface:
mediaCapture.VideoDeviceController.ExposureControl
As well, MS has provided some nice examples and documentation for how to get this to work. Keep in mind, the examples (and the MS camera app) will hide the controls if the exposure feature is not supported by your HW.
https://learn.microsoft.com/en-us/windows/uwp/audio-video-camera/capture-device-controls-for-photo-and-video-capture
https://github.com/microsoft/Windows-universal-samples/tree/master/Samples/CameraManualControls
The lack of access to imaging controls (such as exposure) really has nothing to do with quality. It has more to do with completeness of the camera solution. Camera sensors have a control interface (for example i2c) which is separate from the data interface which drives image. Most third party camera modules will not implement the HW/SW required to enable these controls.
The Supported property of the VideoDeviceController's control objects (ExposureCompensationControl.Supported, for example) doesn't always give accurate information unless the camera is active. So, be sure to get the preview or frame capture started before asking whether the camera controls are supported.
From VideoDeviceController
Some drivers may require that the camera device preview to be in a
running state before it can determine which controls are supported by
the VideoDeviceController. If you check whether a certain control is
supported by the VideoDeviceController before the preview stream is
running, the control may be described as unsupported even though it is
supported by the video device.
I need a very simple video player in my C# app. It only has to loop a video from file and nothing more. Since I'm developing a WPF application, I've tried to use System.Windows.Controls.MediaElement. It has all the functions I need, but works quite poor: I've played some full HD videos on it, and it's always lagging and spiking.
To make sure, it's not my app problem, I've created 2 test applications. The first in a WinForms borderless 1920x1080 window with only AxWMPLib.AxWindowsMediaPlayer control. And the second in a borderless WPF window of the same size with System.Windows.Controls.MediaElement.
Then I run 2 videos on both of players. Here are their specs:
1: 1920x1080, 12000kb/s, 25 FPS, wmv
2: 1920x1080, 5730kb/s, 25 FPS, mp4
On AxWindowsMediaPlayer everything looks fine. But MediaElement seems to drop some frames and ignore vertical sync (it's possible to see parts of one frame on another during fast scene changes). So, it's completely unsuitable and shouldn't be like that, but I've found nothing about the problem in Microsoft official docs (they only suggest to use MediaElement instead of AxWindowsMediaPlayer in WPF apps). Is it possible to make it work more smoothly or using an additional WinForms Form with AxWindowsMediaPlayer is the only solution?
It was written over five years ago (look up James Dailey messages in the thread), there were possibly some improvements but overall I suppose the statements are still in good standing. I will pick up some relevant quotes:
As you know the WPF environment is constructed from the ground up to offer developers a very rich “graphics first” environment. The MediaElement in particular was designed to allow you to mix video with various other UI components seamlessly. This solution will give you the flicker free, “draw over video” solution that you are looking for. The best part is you can do all of this in C#. The bad part of this solution is that the MediaElement is not designed for displaying time sensitive media content. In other words, the MediaElement is notorious for dropping and delaying the display of video frames. There are ways to minimize this such as using SD rather than HD content, use a video accelerated codec, etc.
also:
Unfortunately you can’t really tell the WPF MediaElement to never drop frames. The term we use for this class of issues is “disparate clocks”. In this case WPF is updating the screen at a certain rate (clock 1). The MediaElement (based on WMP) is cranking out video frames at a slightly different rate (clock 2). Given the underlying technologies there is currently no way to synchronize the two clocks and force them to “tick” at the same rate. Since the display will only be updated according to the WPF clock, multiple frames of video may be sent from the MediaElement to WPF between clock ticks. Because of this the MediaElement may appear to drop frames. This is a very common problem in multimedia development and there is no simple solution.
Windows Media Player uses Media Foundation and DirectShow APIs which power media playback with high quality video experience.
Is there a way to apply canvas effects listed in following MSDN page to all display?
http://microsoft.github.io/Win2D/html/N_Microsoft_Graphics_Canvas_Effects.htm
So, can the input and output of ,e.g., TemperatureAndTintEffect be the display buffer?
robertos is correct. Win2D is a UWP API, and there is no general purpose way for UWP apps to read or write to the display outside of their specific app window.
On mobile devices you can use ScreenCapture APIs to read the displayed image, but there is no way to modify that or replace it with something else. Or if you want to apply filters only within your own XAML app, you can do that by rendering the XAML visual tree to a bitmap. More about both options in this thread: Universal Windows Library (UWP) Way to take screenshot?
No. UWP apps do not have access to the raw graphics card and buffers outside of their app.
I need to capture the visual output (like a screenshot) of a DirectX window.
Currently, I use this approach.
But, when the window is in background, it captures whatever is in front of it.
I see that DirectX windows render even when minimized or in background, so this should be possible.
But, how? (It also needs to be fast, and it needs to work on Windows XP too, unfortunately...)
Edit: I am very busy these days... Don't worry, I'll put the bounty back if it expires.
To capture Direct3D windows that are in the background (or moved off screen), I believe you have the following options:
Inject and hook Direct3D within the target application via the link you have already posted or this more up-to-date example (EasyHook can be difficult to get setup but it does work really well) - you can always ask for help about getting it working. I have used that technique for capturing in a number of games without issues (most recently for an ambilight-clone project). The problem with this approach is your concern about game protection causing bans, however FRAPs also uses hooking to achieve this, so perhaps your concerns are exaggerated? I guess gamers being banned for a screen shot is an expensive way of finding out.
For windowed applications on Vista/Win 7 - you could inject and hook the DWM and make your capture requests through its shared surface. I have had this working on Vista, but have not finished getting it working on Windows 7, here is an example of it working for Windows 7 http://www.youtube.com/watch?v=G75WKeXqXkc. The main problem with this approach is the use of undocumented API's which could mean your application breaks without any warning upon a windows patch release - also you would have to redo the technique for each new major Windows flavour. This also does not address your need to capture in Windows XP.
Also within the DWM, there is a thumbnail API. This has limitations depending on what your trying to do. There is some information on this API along with other DWM API's here http://blogs.msdn.com/b/greg_schechter/archive/2006/09/14/753605.aspx
There are other techniques for intercepting the Direct3D calls without using EasyHook, such as substituting the various DLL's with wrappers. You will find various other game hooking/interception techniques here: http://www.gamedeception.net/
Simply bring the Direct3D application to the foreground (which I guess is undesirable in your situation) - this wouldn't work for off-screen windows unless you also move the window.
Unfortunately the only solution for Windows XP that I can think of is intercepting the Direct3D API in some form.
Just a clarification on Direct3D rendering while minimised. During my fairly limited testing on this matter I have found this to be application dependant; it is generally not recommended that rendering take place while the application is minimized (also this reference), it does continue to render while in the background however.
UPDATED: provided additional link to more up-to-date injection example for point 1.
A quick google and i found this Code Project which relates to Windows XP. I dont know if you can apply this knowledge to Windows Vista and 7??
http://www.codeproject.com/Articles/5051/Various-methods-for-capturing-the-screen
EDIT:
I found this article as well:
http://www.codeproject.com/Articles/20651/Capturing-Minimized-Window-A-Kid-s-Trick
This links off from Justins blog post here from the comments. It seems he was working on this with someone (i see thats your link about).
http://spazzarama.com/2009/02/07/screencapture-with-direct3d/
The code that you linked to (from spazzarama), which you said you were using in your project, captures the front buffer of your DirectX device. Have you tried capturing the back buffer instead? Going from the code on your linked site, you would change line 90 from
device.GetFrontBufferData(0, surface);
to
Surface backbuffer = device.GetBackBuffer(0, 0, BackBufferType.Mono);
SurfaceLoader.Save("Screenshot.bmp", ImageFileFormat.Bmp, backbuffer);
This would also involve removing lines 96-98 in your linked example. The backbuffer might be generated without the obstructing window.
EDIT
Nevermind all of that. I just realized that your linked sample code is using the window handle to define a region of the screen, and not actually doing anything with the DirectX window. Your sample code won't work around the obstruction because your region is already drawn with the other window in front of it by the time you access it.
Your best bet to salvage the application is probably to bring the DirectX window to the top of the screen before running the code to capture the image. You can use the Wind32API BringWindowToTop function to do that (http://msdn.microsoft.com/en-us/library/ms632673%28VS.85%29.aspx).