Exibir a visualização da câmera

Este artigo descreve como exibir rapidamente o fluxo de visualização de câmera em uma página XAML de um aplicativo UWP (Plataforma Universal do Windows). Criar um aplicativo que captura fotos e vídeos usando a câmera exige que você realize tarefas como manipular a orientação do dispositivo e da câmera ou definir opções de codificação para o arquivo capturado. Em alguns cenários de aplicativo, talvez você queira simplesmente mostrar o fluxo de visualização da câmera sem se preocupar com essas outras considerações. Este artigo mostra como fazer isso com um mínimo de código. Observe que você deve sempre desligar o fluxo de visualização corretamente quando o tiver concluído, seguindo as etapas abaixo.

Para saber mais sobre como desenvolver um aplicativo de câmera que capture fotos ou vídeos, consulte Captura básica de fotos, vídeo e áudio com o MediaCapture.

Adicionar declarações de funcionalidades ao manifesto do aplicativo

Para que seu app acesse a câmera do dispositivo, você deve declarar que o app usa as funcionalidades de webcam e microphone do dispositivo.

Adicionar funcionalidades ao manifesto do aplicativo

  1. No Microsoft Visual Studio, no Gerenciador de Soluções, abra o designer do manifesto do aplicativo clicando duas vezes no item package.appxmanifest.
  2. Selecione a guia Funcionalidades.
  3. Marque a caixa da Webcam e a caixa do Microfone.

Adicionar um CaptureElement à sua página

Use um CaptureElement para exibir o fluxo de visualização na página XAML.

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

Usar o MediaCapture para iniciar o fluxo de visualização

O objeto MediaCapture é a interface do seu aplicativo para a câmera do dispositivo. Esta classe é um membro do namespace Windows.Media.Capture. O exemplo deste artigo também usa APIs dos namespaces Windows.ApplicationModel e System.Threading.Tasks, além daqueles incluídos pelo modelo de projeto padrão.

Adicione usando diretivas para incluir os seguintes namespaces no arquivo. cs da sua página.

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 uma variável de membro de classe para o objeto MediaCapture e um valor booliano para controlar se a câmera está visualizando no momento.

MediaCapture mediaCapture;
bool isPreviewing;

Declare uma variável do tipo DisplayRequest que será usada para garantir que a exibição não seja desativada enquanto a visualização estiver em execução.

DisplayRequest displayRequest = new DisplayRequest();

Crie um método auxiliar para iniciar a visualização de câmera, chamada StartPreviewAsync neste exemplo. Dependendo do cenário do aplicativo, você pode querer chamá-lo a partir do manipulador de eventos OnNavigatedTo que é chamado quando a página é carregada ou esperar e iniciar a visualização em resposta a eventos da interface do usuário.

Crie uma nova instância da classe MediaCapture e chame InitializeAsync para inicializar o dispositivo de captura. Esse método pode falhar em dispositivos que não têm uma câmera, por exemplo. Por isso, você deve chamá-lo de dentro de um bloco try. Uma UnauthorizedAccessException será lançada quando você tentar inicializar a câmera, se o usuário tiver desabilitado o acesso à câmera nas configurações de privacidade do dispositivo. Você também verá essa exceção durante o desenvolvimento, se não tiver adicionado os recursos adequados ao manifesto do seu aplicativo.

Importante Em algumas famílias de dispositivos, uma solicitação de consentimento do usuário é exibida para o usuário antes de seu aplicativo receber acesso à câmera do dispositivo. Por esse motivo, você só deve chamar MediaCapture.InitializeAsync do thread de interface do usuário principal. Tentar iniciar a câmera de outro thread pode resultar em falha de inicialização.

Conecte a MediaCapture ao CaptureElement definindo a propriedade Source. Inicie a visualização chamando StartPreviewAsync. Esse método gerará uma FileLoadException se outro app tiver controle exclusivo do dispositivo de captura. Veja a próxima seção para obter informações sobre as alterações no controle exclusivo.

Chame RequestActive para garantir que o dispositivo não entre em suspensão enquanto a visualização estiver em execução. Por fim, defina a propriedade DisplayInformation.AutoRotationPreferences como Landscape para impedir que a interface do usuário e o CaptureElement girem quando o usuário mudar a orientação do dispositivo. Para obter mais informações sobre como lidar com alterações de orientação do dispositivo, consulte Manipular a orientação do dispositivo com o 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;
           }

       }

Manipular as alterações no controle exclusivo

Conforme mencionado na seção anterior, StartPreviewAsync gerará uma FileLoadException se outro aplicativo tiver o controle exclusivo do dispositivo de captura. A partir do Windows 10, versão 1703, você pode registrar um manipulador para o evento MediaCapture.CaptureDeviceExclusiveControlStatusChanged, que é acionado sempre que o status de controle exclusivo do dispositivo é alterado. No manipulador para este evento, verifique a propriedade MediaCaptureDeviceExclusiveControlStatusChangedEventArgs.Status para ver qual é o status atual. Se o novo status for SharedReadOnlyAvailable, então você saberá que no momento não é possível iniciar a visualização e talvez convenha atualizar sua interface do usuário para alertar o usuário. Se o novo status for ExclusiveControlAvailable, então você poderá tentar iniciar a visualização de câmera novamente.

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

Desligar o fluxo de visualização

Ao terminar de usar o fluxo de visualização, você sempre deve desligar o fluxo e dispor corretamente dos recursos associados para garantir que a câmera esteja disponível para outros aplicativos no dispositivo. As etapas necessárias para desligar o fluxo de visualização são:

  • Se a câmera estiver atualmente em visualização, chame StopPreviewAsync para interromper o fluxo de visualização. Uma exceção será gerada se você chamar StopPreviewAsync enquanto a visualização não estiver em execução.
  • Defina a propriedade Source do CaptureElement como nulo. Use CoreDispatcher.RunAsync para garantir que essa chamada seja executada no thread de interface do usuário.
  • Chame o método Dispose do objeto MediaCapture para liberar o objeto. Novamente, use CoreDispatcher.RunAsync para garantir que essa chamada seja executada no thread de interface do usuário.
  • Defina a variável do membro do MediaCapture como nulo.
  • Chame RequestRelease para permitir que a tela seja desativada quando inativa.
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;
        });
    }
    
}

Você deve desligar o fluxo de visualização quando o usuário navegar para fora de sua página, substituindo o método OnNavigatedFrom.

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

Você também deve desligar o fluxo de visualização corretamente quando seu aplicativo estiver suspenso. Para fazer isso, registre um manipulador para o evento Application.Suspending no construtor da página.

public MainPage()
{
    this.InitializeComponent();

    Application.Current.Suspending += Application_Suspending;
}

No manipulador de eventos Suspending, verifique primeiro se a página está exibindo o Frame do aplicativo, comparando o tipo de página com a propriedade CurrentSourcePageType. Se a página não estiver sendo exibida no momento, o evento OnNavigatedFrom já deve tiver sido gerado e o fluxo de visualização encerrado. Se a página estiver sendo exibida no momento, obtenha um objeto SuspendingDeferral dos argumentos de evento passados para o manipulador para garantir que o sistema não suspenda seu aplicativo até que o fluxo de visualização seja encerrado. Depois de desligar o fluxo, chame o método Complete de adiamento para permitir que o sistema continue a suspender seu aplicativo.

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