Mostrar la vista previa de la cámara

En este artículo se describe cómo mostrar rápidamente la secuencia de vista previa de la cámara dentro de una página XAML en una aplicación de Plataforma universal de Windows (UWP). La creación de una aplicación que capture fotos y vídeos con la cámara requiere realizar tareas como controlar la orientación del dispositivo y la cámara o establecer opciones de codificación para el archivo capturado. En algunos escenarios de aplicaciones, puede que quiera simplemente mostrar la secuencia de vista previa desde la cámara sin preocuparse por estas otras consideraciones. En este artículo se muestra cómo hacerlo con un mínimo de código. Tenga en cuenta que siempre debe apagar correctamente la secuencia de vista previa cuando haya terminado con ella siguiendo los pasos que se indican a continuación.

Para obtener información sobre cómo escribir una aplicación de cámara que capture fotos o vídeos, consulta Captura básica de fotos, vídeos y audio con MediaCapture.

Adición de declaraciones de funcionalidad al manifiesto de la aplicación

Para que la aplicación acceda a la cámara de un dispositivo, debe declarar que la aplicación usa las funcionalidades de dispositivo de cámara web y micrófono.

Adición de funcionalidades al manifiesto de la aplicación

  1. En Microsoft Visual Studio, en el Explorador de soluciones, abra el diseñador para el manifiesto de aplicación haciendo doble clic en el elemento package.appxmanifest.
  2. Seleccione la pestaña Funcionalidades.
  3. Active la casilla Cámara web y la casilla Micrófono.

Agregar un objeto CaptureElement a la página

Usa un objeto CaptureElement para mostrar la secuencia de vista previa dentro de la página XAML.

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

Uso de MediaCapture para iniciar la secuencia de vista previa

El objeto MediaCapture es la interfaz de la aplicación a la cámara del dispositivo. Esta clase es miembro del espacio de nombres Windows.Media.Capture. En el ejemplo de este artículo también se usan las API de los espacios de nombres Windows.ApplicationModel y System.Threading.Tasks , además de los incluidos en la plantilla de proyecto predeterminada.

Agregue directivas using para incluir los siguientes espacios de nombres en el archivo .cs de la página.

//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 una variable de miembro de clase para el objeto MediaCapture y un valor booleano para realizar un seguimiento de si la cámara está actualmente en vista previa.

MediaCapture mediaCapture;
bool isPreviewing;

Declare una variable de tipo DisplayRequest que se usará para asegurarse de que la pantalla no se desactiva mientras se ejecuta la vista previa.

DisplayRequest displayRequest = new DisplayRequest();

Cree un método auxiliar para iniciar la vista previa de la cámara, denominada StartPreviewAsync en este ejemplo. En función del escenario de la aplicación, es posible que quieras llamarlo desde el controlador de eventos OnNavigatedTo al que se llama cuando se carga o espera la página e inicia la vista previa en respuesta a eventos de interfaz de usuario.

Cree una nueva instancia de la clase MediaCapture y llame a InitializeAsync para inicializar el dispositivo de captura. Este método puede producir un error en los dispositivos que no tienen una cámara, por ejemplo, por lo que debe llamarlo desde dentro de un bloque try . Se producirá una excepción UnauthorizedAccessException al intentar inicializar la cámara si el usuario ha deshabilitado el acceso a la cámara en la configuración de privacidad del dispositivo. También verá esta excepción durante el desarrollo si no ha olvidado agregar las funcionalidades adecuadas al manifiesto de la aplicación.

Importante En algunas familias de dispositivos, se muestra un mensaje de consentimiento del usuario al usuario antes de que se conceda acceso a la cámara del dispositivo. Por este motivo, solo debe llamar a MediaCapture.InitializeAsync desde el subproceso principal de la interfaz de usuario. Si se intenta inicializar la cámara desde otro subproceso, puede producirse un error de inicialización.

Nota:

Windows permite a los usuarios conceder o denegar el acceso a la cámara del dispositivo en la aplicación Configuración de Windows, en Privacidad y seguridad -> Cámara. Al inicializar el dispositivo de captura, las aplicaciones deben comprobar si tienen acceso a la cámara y gestionar el caso en el que el acceso sea denegado por el usuario. Para obtener más información, consulte Manipular la configuración de privacidad de la cámara de Windows.

Conecte MediaCapture a CaptureElement estableciendo la propiedad Source. Inicie la versión preliminar llamando a StartPreviewAsync. Este método iniciará una excepción FileLoadException si otra aplicación tiene control exclusivo del dispositivo de captura. Consulte la sección siguiente para obtener información sobre cómo escuchar los cambios en el control exclusivo.

Llame a RequestActive para asegurarse de que el dispositivo no se suspende mientras se ejecuta la versión preliminar. Por último, establezca la propiedad DisplayInformation.AutoRotationPreferences en Horizontal para evitar que la interfaz de usuario y CaptureElement giren cuando el usuario cambie la orientación del dispositivo. Para obtener más información sobre cómo controlar los cambios de orientación del dispositivo, consulte Controlar la orientación del dispositivo con 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;
           }

       }

Controlar los cambios en el control exclusivo

Como se indicó en la sección anterior, StartPreviewAsync iniciará una excepción FileLoadException si otra aplicación tiene control exclusivo del dispositivo de captura. A partir de Windows 10, versión 1703, puedes registrar un controlador para el evento MediaCapture.CaptureDeviceExclusiveControlStatusChanged , que se genera cada vez que cambia el estado de control exclusivo del dispositivo. En el controlador de este evento, compruebe la propiedad MediaCaptureDeviceExclusiveControlStatusChangedEventArgs.Status para ver cuál es el estado actual. Si el nuevo estado es SharedReadOnlyAvailable, sabe que actualmente no puede iniciar la versión preliminar y es posible que quiera actualizar la interfaz de usuario para alertar al usuario. Si el nuevo estado es ExclusiveControlAvailable, puede intentar volver a iniciar la vista previa de la cámara.

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

Apagar la secuencia de vista previa

Cuando haya terminado de usar la secuencia de vista previa, siempre debe apagar la secuencia y eliminar correctamente los recursos asociados para asegurarse de que la cámara está disponible para otras aplicaciones del dispositivo. Los pasos necesarios para apagar la secuencia de vista previa son:

  • Si la cámara está actualmente en versión preliminar, llame a StopPreviewAsync para detener la secuencia de vista previa. Se producirá una excepción si llama a StopPreviewAsync mientras la versión preliminar no se está ejecutando.
  • Establezca la propiedad Source de CaptureElement en null. Use CoreDispatcher.RunAsync para asegurarse de que esta llamada se ejecuta en el subproceso de la interfaz de usuario.
  • Llame al método Dispose del objeto MediaCapture para liberar el objeto. De nuevo, use CoreDispatcher.RunAsync para asegurarse de que esta llamada se ejecuta en el subproceso de la interfaz de usuario.
  • Establezca la variable miembro MediaCapture en NULL.
  • Llame a RequestRelease para permitir que la pantalla se desactive cuando esté inactiva.
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;
        });
    }
    
}

Debe apagar la secuencia de vista previa cuando el usuario salga de la página reemplazando el método OnNavigatedFrom.

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

También debes apagar correctamente la secuencia de vista previa cuando la aplicación se suspenda. Para ello, registre un controlador para el evento Application.Suspending en el constructor de la página.

public MainPage()
{
    this.InitializeComponent();

    Application.Current.Suspending += Application_Suspending;
}

En el controlador de eventos Suspending, compruebe primero para asegurarse de que la página se muestra en Frame de la aplicación comparando el tipo de página con la propiedad CurrentSourcePageType. Si la página no se muestra actualmente, el evento OnNavigatedFrom ya debería haberse generado y la secuencia de vista previa se cerró. Si la página se muestra actualmente, obtenga un objeto SuspendingDeferral de los argumentos de evento pasados al controlador para asegurarse de que el sistema no suspenda la aplicación hasta que se haya cerrado la secuencia de vista previa. Después de apagar la secuencia, llame al método Complete del aplazamiento para permitir que el sistema continúe suspendiendo la aplicación.

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