Upravit

Sdílet prostřednictvím


Display the camera preview

This article describes how to quickly display the camera preview stream within a XAML page in a Universal Windows Platform (UWP) app. Creating an app that captures photos and videos using the camera requires you to perform tasks like handling device and camera orientation or setting encoding options for the captured file. For some app scenarios, you may want to just simply show the preview stream from the camera without worrying about these other considerations. This article shows you how to do that with a minimum of code. Note that you should always shut down the preview stream properly when you are done with it by following the steps below.

For information on writing a camera app that captures photos or videos, see Basic photo, video, and audio capture with MediaCapture.

Add capability declarations to the app manifest

In order for your app to access a device's camera, you must declare that your app uses the webcam and microphone device capabilities.

Add capabilities to the app manifest

  1. In Microsoft Visual Studio, in Solution Explorer, open the designer for the application manifest by double-clicking the package.appxmanifest item.
  2. Select the Capabilities tab.
  3. Check the box for Webcam and the box for Microphone.

Add a CaptureElement to your page

Use a CaptureElement to display the preview stream within your XAML page.

<CaptureElement Name="PreviewControl" Stretch="Uniform"/>

Use MediaCapture to start the preview stream

The MediaCapture object is your app's interface to the device's camera. This class is a member of the Windows.Media.Capture namespace. The example in this article also uses APIs from the Windows.ApplicationModel and System.Threading.Tasks namespaces, in addition to those included by the default project template.

Add using directives to include the following namespaces in your page's .cs file.

//MainPage.xaml.cs
using Windows.UI.Core;
using Windows.UI.Xaml.Navigation;
using Windows.Media.Capture;
using Windows.ApplicationModel;
using System.Threading.Tasks;
using Windows.System.Display;
using Windows.Graphics.Display;

Declare a class member variable for the MediaCapture object and a boolean to track whether the camera is currently previewing.

MediaCapture mediaCapture;
bool isPreviewing;

Declare a variable of type DisplayRequest that will be used to make sure the display does not turn off while the preview is running.

DisplayRequest displayRequest = new DisplayRequest();

Create a helper method to start up the camera preview, called StartPreviewAsync in this example. Depending on your app's scenario, you may want to call this from the OnNavigatedTo event handler that is called when the page is loaded or wait and launch the preview in response to UI events.

Create a new instance of the MediaCapture class and call InitializeAsync to initialize the capture device. This method may fail, on devices that don't have a camera for example, so you should call it from within a try block. An UnauthorizedAccessException will be thrown when you attempt to initialize the camera if the user has disabled camera access in the device's privacy settings. You will also see this exception during development if you have neglected to add the proper capabilities to your app manifest.

Important On some device families, a user consent prompt is displayed to the user before your app is granted access to the device's camera. For this reason, you must only call MediaCapture.InitializeAsync from the main UI thread. Attempting to initialize the camera from another thread may result in initialization failure.

Note

Windows allows users to grant or deny access to the device's camera in the Windows Settings app, under Privacy & Security -> Camera. When initializing the capture device, apps should check whether they have access to the camera and handle the case where access is denied by the user. For more information, see Handle the Windows camera privacy setting.

Connect the MediaCapture to the CaptureElement by setting the Source property. Start the preview by calling StartPreviewAsync. This method will throw a FileLoadException if another app has exclusive control of the capture device. See the next section for information listening for changes in exclusive control.

Call RequestActive to make sure the device doesn't go to sleep while the preview is running. Finally, set the DisplayInformation.AutoRotationPreferences property to Landscape to prevent the UI and the CaptureElement from rotating when the user changes the device orientation. For more information on handling device orientation changes, see Handle device orientation with MediaCapture.

       private async Task StartPreviewAsync()
       {
           try
           {

               mediaCapture = new MediaCapture();
               await mediaCapture.InitializeAsync();

               displayRequest.RequestActive();
               DisplayInformation.AutoRotationPreferences = DisplayOrientations.Landscape;
           }
           catch (UnauthorizedAccessException)
           {
               // This will be thrown if the user denied access to the camera in privacy settings
               ShowMessageToUser("The app was denied access to the camera");
               return;
           }

           try
           {
               PreviewControl.Source = mediaCapture;
               await mediaCapture.StartPreviewAsync();
               isPreviewing = true;
           }
           catch (System.IO.FileLoadException)
           {
               mediaCapture.CaptureDeviceExclusiveControlStatusChanged += _mediaCapture_CaptureDeviceExclusiveControlStatusChanged;
           }

       }

Handle changes in exclusive control

As stated in the previous section, StartPreviewAsync will throw a FileLoadException if another app has exclusive control of the capture device. Starting with Windows 10, version 1703, you can register a handler for the MediaCapture.CaptureDeviceExclusiveControlStatusChanged event, which is raised whenever the exclusive control status of the device changes. In the handler for this event, check the MediaCaptureDeviceExclusiveControlStatusChangedEventArgs.Status property to see what the current status is. If the new status is SharedReadOnlyAvailable, then you know you can't currently start the preview and you may want to update your UI to alert the user. If the new status is ExclusiveControlAvailable, then you can try starting the camera preview again.

private async void _mediaCapture_CaptureDeviceExclusiveControlStatusChanged(MediaCapture sender, MediaCaptureDeviceExclusiveControlStatusChangedEventArgs args)
{
    if (args.Status == MediaCaptureDeviceExclusiveControlStatus.SharedReadOnlyAvailable)
    {
        ShowMessageToUser("The camera preview can't be displayed because another app has exclusive access");
    }
    else if (args.Status == MediaCaptureDeviceExclusiveControlStatus.ExclusiveControlAvailable && !isPreviewing)
    {
        await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
        {
            await StartPreviewAsync();
        });
    }
}

Shut down the preview stream

When you are done using the preview stream, you should always shut down the stream and properly dispose of the associated resources to ensure that the camera is available to other apps on the device. The required steps for shutting down the preview stream are:

  • If the camera is currently previewing, call StopPreviewAsync to stop the preview stream. An exception will be thrown if you call StopPreviewAsync while the preview is not running.
  • Set the Source property of the CaptureElement to null. Use CoreDispatcher.RunAsync to make sure this call is executed on the UI thread.
  • Call the MediaCapture object's Dispose method to release the object. Again, use CoreDispatcher.RunAsync to make sure this call is executed on the UI thread.
  • Set the MediaCapture member variable to null.
  • Call RequestRelease to allow the screen to turn off when inactive.
private async Task CleanupCameraAsync()
{
    if (mediaCapture != null)
    {
        if (isPreviewing)
        {
            await mediaCapture.StopPreviewAsync();
        }

        await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
        {
            PreviewControl.Source = null;
            if (displayRequest != null)
            {
                displayRequest.RequestRelease();
            }

            mediaCapture.Dispose();
            mediaCapture = null;
        });
    }
    
}

You should shut down the preview stream when the user navigates away from your page by overriding the OnNavigatedFrom method.

protected async override void OnNavigatedFrom(NavigationEventArgs e)
{
    await CleanupCameraAsync();
}

You should also shut down the preview stream properly when your app is suspending. To do this, register a handler for the Application.Suspending event in your page's constructor.

public MainPage()
{
    this.InitializeComponent();

    Application.Current.Suspending += Application_Suspending;
}

In the Suspending event handler, first check to make sure that the page is being displayed the application's Frame by comparing the page type to the CurrentSourcePageType property. If the page is not currently being displayed, then the OnNavigatedFrom event should already have been raised and the preview stream shut down. If the page is currently being displayed, get a SuspendingDeferral object from the event args passed into the handler to make sure the system does not suspend your app until the preview stream has been shut down. After shutting down the stream, call the deferral's Complete method to let the system continue suspending your app.

private async void Application_Suspending(object sender, SuspendingEventArgs e)
{
    // Handle global application events only if this page is active
    if (Frame.CurrentSourcePageType == typeof(MainPage))
    {
        var deferral = e.SuspendingOperation.GetDeferral();
        await CleanupCameraAsync();
        deferral.Complete();
    }
}