Basic photo, video, and audio capture with MediaCapture in a WinUI 3 app
This article shows the simplest way to capture photos and video using the MediaCapture class. The MediaCapture class exposes a robust set of APIs that provide low-level control over the capture pipeline and enable advanced capture scenarios, but this article is intended to help you add basic media capture to your app quickly and easily. To learn about more of the features that MediaCapture provides, see Camera.
Initialize the MediaCapture object
All of the capture methods described in this article require the first step of initializing the MediaCapture object. This includes instantiating the object, selecting a capture device, setting initialization parameters, and then calling InitializeAsync. Typically camera apps will display the camera preview while capturing photos or video in their UI using the MediaPlayerElement. For a walkthrough of initializing MediaCapture and showing the preview in a XAML UI, see Show the camera preview in a WinUI 3 app. The code examples in this article will assume that an initialized instance of MediaCapture has already been created.
Capture a photo to a SoftwareBitmap
The SoftwareBitmap class provides a common representation of images across multiple features. If you want to capture a photo and then immediately use the captured image in your app, such as displaying it in XAML, instead of capturing to a file, then you should capture to a SoftwareBitmap. You still have the option of saving the image to disk later.
Capture a photo to a SoftwareBitmap using the LowLagPhotoCapture class. Get an instance of this class by calling PrepareLowLagPhotoCaptureAsync, passing in an ImageEncodingProperties object specifying the image format you want. CreateUncompressed creates an uncompressed encoding with the specified pixel format. Initiate photo capture by calling CaptureAsync, which returns a CapturedPhoto object. Get a SoftwareBitmap by accessing the Frame property and then the SoftwareBitmap property.
You can capture multiple photos by repeatedly calling CaptureAsync. When you are done capturing, call FinishAsync to shut down the LowLagPhotoCapture session and free up the associated resources. After calling FinishAsync, to begin capturing photos again you will need to call PrepareLowLagPhotoCaptureAsync again to reinitialize the capture session before calling CaptureAsync.
// Prepare and capture photo
var lowLagCapture = await m_mediaCapture.PrepareLowLagPhotoCaptureAsync(ImageEncodingProperties.CreateUncompressed(MediaPixelFormat.Bgra8));
var capturedPhoto = await lowLagCapture.CaptureAsync();
var softwareBitmap = capturedPhoto.Frame.SoftwareBitmap;
// Capture more photos, if desired.
// Then call FinishAsync to clean up resources
await lowLagCapture.FinishAsync();
Capture a photo to a memory stream
You can use MediaCapture to capture a photo to an in-memory stream, which you can then use to transcode the photo from the stream to a file on disk.
Create an InMemoryRandomAccessStream and then call CapturePhotoToStreamAsync to capture a photo to the stream, passing in the stream and an ImageEncodingProperties object specifying the image format that should be used. You can create custom encoding properties by initializing the object yourself, but the class provides static methods, like ImageEncodingProperties.CreateJpeg for common encoding formats.
Create a BitmapDecoder to decode the image from the in memory stream. Create a BitmapEncoder to encode the image to file by calling CreateForTranscodingAsync.
You can optionally create a BitmapPropertySet object and then call SetPropertiesAsync on the image encoder to include metadata about the photo in the image file. For more information about encoding properties, see Image metadata.
Finally, call FlushAsync on the encoder object to transcode the photo from the in-memory stream to the file.
// Prepare and capture photo
var lowLagCapture = await m_mediaCapture.PrepareLowLagPhotoCaptureAsync(ImageEncodingProperties.CreateUncompressed(MediaPixelFormat.Bgra8));
var capturedPhoto = await lowLagCapture.CaptureAsync();
var softwareBitmap = capturedPhoto.Frame.SoftwareBitmap;
// Capture more photos, if desired.
// Then call FinishAsync to clean up resources
await lowLagCapture.FinishAsync();
Capture a video
Quickly add video capture to your app by using the LowLagMediaRecording class.
First, the LowLagMediaRecording needs to persist while video is being captured, so declare a class variable to for the object.
LowLagMediaRecording m_mediaRecording;
Call PrepareLowLagRecordToStorageFileAsync to initialize the media recording, passing in the storage file and a MediaEncodingProfile object specifying the encoding for the video. The class provides static methods, like CreateMp4, for creating common video encoding profiles. Call StartAsync to begin capturing video.
var myVideos = await Windows.Storage.StorageLibrary.GetLibraryAsync(Windows.Storage.KnownLibraryId.Videos);
StorageFile file = await myVideos.SaveFolder.CreateFileAsync("video.mp4", CreationCollisionOption.GenerateUniqueName);
m_mediaRecording = await m_mediaCapture.PrepareLowLagRecordToStorageFileAsync(
MediaEncodingProfile.CreateMp4(VideoEncodingQuality.Auto), file);
m_mediaCapture.RecordLimitationExceeded += m_mediaCapture_RecordLimitationExceeded;
await m_mediaRecording.StartAsync();
To stop recording video, call StopAsync.
await m_mediaRecording.StopAsync();
You can continue to call StartAsync and StopAsync to capture additional videos. When you are done capturing videos, call FinishAsync to dispose of the capture session and clean up associated resources. After this call, you must call PrepareLowLagRecordToStorageFileAsync again to reinitialize the capture session before calling StartAsync.
await m_mediaRecording.FinishAsync();
When capturing video, you should register a handler for the RecordLimitationExceeded event of the MediaCapture object, which will be raised by the operating system if you surpass the limit for a single recording, currently three hours. In the handler for the event, you should finalize your recording by calling StopAsync.
private async void m_mediaCapture_RecordLimitationExceeded(MediaCapture sender)
{
await m_mediaRecording.StopAsync();
DispatcherQueue.TryEnqueue(() =>
{
tbStatus.Text = "Record limitation exceeded.";
});
}
You can pause a video recording and then resume recording without creating a separate output file by calling PauseAsync and then calling ResumeAsync.
await m_mediaRecording.PauseAsync(Windows.Media.Devices.MediaCapturePauseBehavior.ReleaseHardwareResources);
await m_mediaRecording.ResumeAsync();
Calling PauseWithResultAsync returns a MediaCapturePauseResult object. The LastFrame property is a VideoFrame object representing the last frame. To display the frame in XAML, get the SoftwareBitmap representation of the video frame. Currently, only images in BGRA8 format with premultiplied or empty alpha channel are supported, so call Convert if necessary to get the correct format. PauseWithResultAsync also returns the duration of the video that was recorded in the preceding segment in case you need to track how much total time has been recorded.
You can also get a result frame when you stop the video by calling StopWithResultAsync.
Play and edit captured video files
Once you have captured a video to a file, you may want to load the file and play it back within your app's UI. You can do this using the MediaPlayerElement XAML control and an associated MediaPlayer. For information on playing media in a XAML page, see Play audio and video with MediaPlayer.
[TBD - Is the MediaComposition framework supported / recommended for WinUI?]
You can also create a MediaClip object from a video file by calling CreateFromFileAsync. A MediaComposition provides basic video editing functionality like arranging the sequence of MediaClip objects, trimming video length, creating layers, adding background music, and applying video effects. For more information on working with media compositions, see Media compositions and editing.
Capture audio
You can quickly add audio capture to your app by using the same technique shown above for capturing video. Call PrepareLowLagRecordToStorageFileAsync to initialize the capture session, passing in the file and a MediaEncodingProfile which is generated in this example by the CreateMp3 static method. To begin recording, call StartAsync.
[TBD - This code is throwing 'The request is invalid in the current state.']
m_mediaCapture.RecordLimitationExceeded += m_mediaCapture_RecordLimitationExceeded;
var myVideos = await Windows.Storage.StorageLibrary.GetLibraryAsync(Windows.Storage.KnownLibraryId.Videos);
StorageFile file = await myVideos.SaveFolder.CreateFileAsync("audio.mp3", CreationCollisionOption.GenerateUniqueName);
m_mediaRecording = await m_mediaCapture.PrepareLowLagRecordToStorageFileAsync(
MediaEncodingProfile.CreateMp3(AudioEncodingQuality.High), file);
await m_mediaRecording.StartAsync();
Call StopAsync to stop the audio recording.
await m_mediaRecording.StopAsync();
You can call StartAsync and StopAsync multiple times to record several audio files. When you are done capturing audio, call FinishAsync to dispose of the capture session and clean up associated resources. After this call, you must call PrepareLowLagRecordToStorageFileAsync again to reinitialize the capture session before calling StartAsync.
For information about detecting when the system changes the audio level of the audio capture stream, see Detect and respond to audio level changes by the system.
Windows developer