Отображение предварительной версии камеры
В этой статье описывается, как быстро отобразить поток предварительного просмотра камеры на странице XAML в приложении универсальная платформа Windows (UWP). Создание приложения, которое записывает фотографии и видео с помощью камеры, требует выполнения задач, таких как обработка ориентации устройства и камеры или настройка параметров кодирования для захваченного файла. Для некоторых сценариев приложений может потребоваться просто отобразить поток предварительной версии с камеры, не беспокоясь об этих других соображениях. В этой статье показано, как это сделать с минимальным кодом. Обратите внимание, что вы всегда должны правильно завершить работу потока предварительной версии, выполнив указанные ниже действия.
Сведения о написании приложения камеры, которое записывает фотографии или видео, см. в разделе "Базовый" фото, видео и аудиозапись с помощью MediaCapture.
Добавление объявлений возможностей в манифест приложения
Чтобы приложение получите доступ к камере устройства, необходимо объявить, что ваше приложение использует возможности веб-камеры и микрофона .
Добавление возможностей в манифест приложения
- В Microsoft Visual Studio в Обозреватель решений откройте конструктор манифеста приложения, дважды щелкнув элемент package.appxmanifest.
- Перейдите на вкладку Возможности.
- Установите флажок для веб-камеры и флажок для микрофона.
Добавление 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();
}
}