Поделиться через


Отображение предварительной версии камеры

В этой статье описывается, как быстро отобразить поток предварительного просмотра камеры на странице XAML в приложении универсальная платформа Windows (UWP). Создание приложения, которое записывает фотографии и видео с помощью камеры, требует выполнения задач, таких как обработка ориентации устройства и камеры или настройка параметров кодирования для захваченного файла. Для некоторых сценариев приложений может потребоваться просто отобразить поток предварительной версии с камеры, не беспокоясь об этих других соображениях. В этой статье показано, как это сделать с минимальным кодом. Обратите внимание, что вы всегда должны правильно завершить работу потока предварительной версии, выполнив указанные ниже действия.

Сведения о написании приложения камеры, которое записывает фотографии или видео, см. в разделе "Базовый" фото, видео и аудиозапись с помощью MediaCapture.

Добавление объявлений возможностей в манифест приложения

Чтобы приложение получите доступ к камере устройства, необходимо объявить, что ваше приложение использует возможности веб-камеры и микрофона .

Добавление возможностей в манифест приложения

  1. В Microsoft Visual Studio в Обозреватель решений откройте конструктор манифеста приложения, дважды щелкнув элемент package.appxmanifest.
  2. Перейдите на вкладку Возможности.
  3. Установите флажок для веб-камеры и флажок для микрофона.

Добавление CaptureElement на страницу

Используйте CaptureElement для отображения потока предварительного просмотра на странице XAML.

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

Запуск потока предварительной версии с помощью MediaCapture

Объект MediaCapture — это интерфейс приложения к камере устройства. Этот класс является членом пространства имен Windows.Media.Capture. В примере в этой статье также используются API из пространств имен Windows.ApplicationModel и System.Threading.Tasks , в дополнение к тем, которые включены в шаблон проекта по умолчанию.

Добавьте директивы using, чтобы включить следующие пространства имен в файл .cs страницы.

//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;

Объявите переменную члена класса для объекта MediaCapture и логическое значение для отслеживания того, просматривается ли камера в настоящее время.

MediaCapture mediaCapture;
bool isPreviewing;

Объявите переменную типа DisplayRequest , которая будет использоваться, чтобы убедиться, что отображение не отключается во время выполнения предварительной версии.

DisplayRequest displayRequest = new DisplayRequest();

Создайте вспомогательный метод для запуска предварительной версии камеры с именем StartPreviewAsync в этом примере. В зависимости от сценария приложения может потребоваться вызвать это из обработчика событий OnNavigatedTo , вызываемого при загрузке или ожидании страницы, и запустить предварительную версию в ответ на события пользовательского интерфейса.

Создайте новый экземпляр класса MediaCapture и вызовите InitializeAsync для инициализации устройства записи. Этот метод может завершиться ошибкой на устройствах, у которых нет камеры, например, поэтому его следует вызвать из блока try . При попытке инициализировать камеру при попытке инициализировать камеру, если пользователь отключил доступ к камере в параметрах конфиденциальности устройства. Это исключение также будет отображаться во время разработки, если вы не забыли добавить соответствующие возможности в манифест приложения.

Важно, чтобы в некоторых семействах устройств отображался запрос на согласие пользователя перед предоставлением приложению доступа к камере устройства. По этой причине необходимо вызывать только MediaCapture.InitializeAsync из основного потока пользовательского интерфейса. Попытка инициализации камеры из другого потока может привести к сбою инициализации.

Примечание.

Windows позволяет пользователям предоставлять или запрещать доступ к камере устройства в приложении "Параметры Windows" в разделе "Конфиденциальность и безопасность —> камера". При инициализации устройства записи приложения должны проверить, имеют ли они доступ к камере и обрабатывают ситуацию, когда доступ запрещен пользователем. Дополнительные сведения см. в разделе "Обработка параметра конфиденциальности камеры Windows".

Подключите MediaCapture к CaptureElement, задав свойство Source. Запустите предварительную версию, вызвав StartPreviewAsync. Этот метод создает файл FileLoadException , если другое приложение имеет монопольное управление устройством записи. Дополнительные сведения о прослушивании изменений в монопольном элементе управления см. в следующем разделе.

Вызов RequestActive, чтобы убедиться, что устройство не переходит в спящий режим во время выполнения предварительной версии. Наконец, задайте для свойства DisplayInformation.AutoRotationPreferences значение "Альбом" для предотвращения поворота пользовательского интерфейса и CaptureElement при изменении ориентации устройства пользователем. Дополнительные сведения об обработке изменений ориентации устройства см. в разделе "Обработка ориентации устройства с помощью 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;
           }

       }

Обработка изменений в эксклюзивном элементе управления

Как указано в предыдущем разделе, StartPreviewAsync создает файл FileLoadException, если другое приложение имеет монопольный контроль над устройством записи. Начиная с Windows 10 версии 1703, можно зарегистрировать обработчик для события MediaCapture.CaptureDeviceExclusiveControlStatusChanged , которое возникает при изменении состояния монопольного управления устройства. В обработчике этого события проверьте свойство MediaCaptureDeviceExclusiveControlStatusChangedEventArgs.Status , чтобы узнать, что такое текущее состояние. Если новое состояние — SharedReadOnlyAvailable, вы знаете, что вы не можете запустить предварительную версию, и вы можете обновить пользовательский интерфейс для оповещения пользователя. Если новое состояние — ExclusiveControlAvailable, попробуйте снова запустить предварительную версию камеры.

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();
        });
    }
}

Завершение работы потока предварительной версии

Когда вы закончите использование потока предварительной версии, всегда следует завершить работу потока и правильно удалить связанные ресурсы, чтобы убедиться, что камера доступна другим приложениям на устройстве. Ниже приведены необходимые действия для завершения работы потока предварительной версии:

  • Если камера в настоящее время просматривается, вызовите StopPreviewAsync , чтобы остановить поток предварительной версии. Исключение возникает при вызове StopPreviewAsync , пока предварительная версия не запущена.
  • Задайте свойству Source объекта CaptureElement значение NULL. Используйте CoreDispatcher.RunAsync , чтобы убедиться, что этот вызов выполняется в потоке пользовательского интерфейса.
  • Вызовите метод Dispose объекта MediaCapture, чтобы освободить объект. Опять же, используйте CoreDispatcher.RunAsync , чтобы убедиться, что этот вызов выполняется в потоке пользовательского интерфейса.
  • Задайте для переменной члена MediaCapture значение NULL.
  • Вызов RequestRelease , чтобы разрешить экран отключать при неактивном режиме.
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;
        });
    }
    
}

Вы должны завершить работу потока предварительной версии, когда пользователь переходит от страницы, переопределив метод OnNavigatedFrom .

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

При приостановке приложения также следует правильно завершить работу потока предварительной версии. Для этого зарегистрируйте обработчик события Application.Suspending в конструкторе страницы.

public MainPage()
{
    this.InitializeComponent();

    Application.Current.Suspending += Application_Suspending;
}

В обработчике событий Приостановки сначала проверьте, отображается ли страница кадр приложения, сравнивая тип страницы со свойством CurrentSourcePageType. Если страница не отображается в данный момент, событие OnNavigatedFrom уже должно быть создано, а поток предварительной версии завершится. Если страница отображается в настоящее время, получите объект SuspendingDeferral из событий, передаваемых в обработчик, чтобы убедиться, что система не приостанавливает приложение до завершения предварительного просмотра потока. После завершения работы потока вызовите метод завершения отсрочки, чтобы система продолжала приостановку приложения.

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();
    }
}