Compartir a través de


Captura básica de fotos, audio y vídeo con MediaCapture

En este artículo se muestra la forma más sencilla de capturar fotos y vídeos mediante la clase MediaCapture. La clase MediaCapture expone un eficaz conjunto de API que proporciona control de bajo nivel sobre la canalización de captura y habilita escenarios de captura avanzados, pero este artículo está pensado para ayudar a agregar la captura multimedia básica a la aplicación de forma rápida y fácil. Para obtener más información sobre las características que proporciona MediaCapture, consulte Cámara.

Si simplemente quiere capturar una foto o un vídeo y no tiene intención de agregar características adicionales de captura multimedia, o si no quiere crear su propia interfaz de usuario de cámara, es posible que quiera usar la clase CameraCaptureUI, que le permite simplemente iniciar la aplicación de cámara integrada de Windows y recibir el archivo de fotos o vídeo capturados. Para obtener más información, consulte Captura de fotos y vídeo con la interfaz de usuario de cámara integrada de Windows

El código de este artículo se ha adaptado del ejemplo del Kit de inicio de cámara. Puede descargar el ejemplo para ver el código usado en contexto o para usar el ejemplo como punto de partida para su propia aplicación.

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. Si desea guardar fotos y vídeos capturados en la biblioteca de imágenes o vídeos de los usuarios, también debe declarar la funcionalidad picturesLibrary y videosLibrary.

Para agregar 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.
  4. Para obtener acceso a la biblioteca de imágenes y vídeos, active las casillas Biblioteca de imágenes y Biblioteca de vídeos.

Inicialización del objeto MediaCapture

Todos los métodos de captura descritos en este artículo requieren el primer paso para inicializar el objeto MediaCapture llamando al constructor y, a continuación, llamando a InitializeAsync. Dado que se tendrá acceso al objeto MediaCapture desde varios lugares de la aplicación, declare una variable de clase para contener el objeto. Implemente un controlador para el evento Failed del objeto MediaCapture para recibir una notificación si se produce un error en una operación de captura.

MediaCapture mediaCapture;
bool isPreviewing;
mediaCapture = new MediaCapture();
await mediaCapture.InitializeAsync();
mediaCapture.Failed += MediaCapture_Failed;

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.

Configuración de la vista previa de la cámara

Es posible capturar fotos, vídeos y audio con MediaCapture sin mostrar la vista previa de la cámara, pero normalmente querrá mostrar la secuencia de vista previa para que el usuario pueda ver lo que se está capturando. Además, algunas características de MediaCapture requieren que la secuencia de vista previa se ejecute para que se puedan habilitar, incluidos el enfoque automático, la exposición automática y el balance de blancos automático. Para ver cómo configurar la vista previa de la cámara, consulte Visualización de la vista previa de la cámara.

Capturar una foto en un SoftwareBitmap

La clase SoftwareBitmap se introdujo en Windows 10 para proporcionar una representación común de las imágenes en varias características. Si quiere capturar una foto y, a continuación, usar inmediatamente la imagen capturada en su aplicación, como mostrarla en XAML, en lugar de capturarla en un archivo, debe capturarla en un SoftwareBitmap. Tiene la opción de guardar la imagen en el disco más adelante.

Después de inicializar el objeto MediaCapture, puede capturar una foto en un SoftwareBitmap mediante la clase LowLagPhotoCapture. Para obtener una instancia de esta clase, llame a PrepareLowLagPhotoCaptureAsync y pase un objeto ImageEncodingProperties que especifique el formato de imagen que desee. CreateUncompressed crea una codificación sin comprimir con el formato de píxel especificado. Capture una foto llamando a CaptureAsync, que devuelve un objeto CapturedPhoto. Obtenga un objeto SoftwareBitmap accediendo a la propiedad Frame y, a continuación, a la propiedad SoftwareBitmap.

Si lo desea, puede capturar varias fotos llamando repetidamente a CaptureAsync. Cuando haya terminado de capturar, llame a FinishAsync para apagar la sesión LowLagPhotoCapture y liberar los recursos asociados. Después de llamar a FinishAsync, para empezar a capturar fotos de nuevo, deberá llamar a PrepareLowLagPhotoCaptureAsync de nuevo para reinicializar la sesión de captura antes de llamar a CaptureAsync.

// Prepare and capture photo
var lowLagCapture = await mediaCapture.PrepareLowLagPhotoCaptureAsync(ImageEncodingProperties.CreateUncompressed(MediaPixelFormat.Bgra8));

var capturedPhoto = await lowLagCapture.CaptureAsync();
var softwareBitmap = capturedPhoto.Frame.SoftwareBitmap;

await lowLagCapture.FinishAsync();

A partir de Windows, versión 1803, puede acceder a la propiedad BitmapProperties de la clase CapturedFrame devuelta desde CaptureAsync para recuperar metadatos sobre la foto capturada. Puede pasar estos datos a un BitmapEncoder para guardar los metadatos en un archivo. Anteriormente, no había ninguna manera de acceder a estos datos para los formatos de imagen sin comprimir. También puede acceder a la propiedad ControlValues para recuperar un objeto CapturedFrameControlValues que describa los valores de control, como la exposición y el balance de blancos, para el marco capturado.

Para obtener información sobre el uso de BitmapEncoder y sobre cómo trabajar con el objeto SoftwareBitmap, incluido cómo mostrar uno en una página XAML, consulte Crear, editar y guardar imágenes de mapa de bits.

Para obtener más información sobre cómo establecer los valores de control de dispositivo de captura, consulte Capturar controles de dispositivo para fotos y vídeos.

A partir de Windows 10, versión 1803, puede obtener los metadatos, como la información EXIF, para las fotos capturadas en formato sin comprimir accediendo a la propiedad BitmapProperties del CapturedFrame devuelto por MediaCapture. En versiones anteriores, estos datos solo eran accesibles en el encabezado de las fotos capturadas en un formato de archivo comprimido. Puede proporcionar estos datos a un BitmapEncoder al escribir manualmente un archivo de imagen. Para obtener más información sobre la codificación de mapas de bits, vea Crear, editar y guardar imágenes de mapa de bits. También puede acceder a los valores de control de fotogramas, como la exposición y la configuración de flash, que se usan cuando la imagen se capturó accediendo a la propiedad ControlValues. Para obtener más información, consulte Controles del dispositivo de captura para la captura de fotos y vídeos.

Capturar una foto en un archivo

Una aplicación de fotografía típica guardará una foto capturada en el disco o en el almacenamiento en la nube y tendrá que agregar metadatos, como la orientación de la foto, al archivo. En el ejemplo siguiente se muestra cómo capturar una foto en un archivo. Todavía tiene la opción de crear un SoftwareBitmap a partir del archivo de imagen más adelante.

La técnica que se muestra en este ejemplo captura la foto en una secuencia en memoria y, a continuación, transcodifica la foto de la secuencia a un archivo en el disco. En este ejemplo se usa GetLibraryAsync para obtener la biblioteca de imágenes del usuario y, a continuación, la propiedad SaveFolder para obtener una carpeta de guardado predeterminada de referencia. No olvide agregar la funcionalidad Biblioteca de imágenes al manifiesto de la aplicación para acceder a esta carpeta. CreateFileAsync crea un nuevo StorageFile en el que se guardará la foto.

Cree un InMemoryRandomAccessStream y, a continuación, llame a CapturePhotoToStreamAsync para capturar una foto en la secuencia, pasando la secuencia y un objeto ImageEncodingProperties que especifica el formato de imagen que se debe usar. Puede crear propiedades de codificación personalizadas inicializando el objeto usted mismo, pero la clase proporciona métodos estáticos, como ImageEncodingProperties.CreateJpeg para formatos de codificación comunes. A continuación, cree una secuencia de archivos en el archivo de salida llamando a OpenAsync. Cree un BitmapDecoder para descodificar la imagen de la secuencia de memoria y, a continuación, cree un BitmapEncoder para codificar la imagen en el archivo llamando a CreateForTranscodingAsync.

Opcionalmente, puede crear un objeto BitmapPropertySet y, a continuación, llamar a SetPropertiesAsync en el codificador de imágenes para incluir metadatos sobre la foto en el archivo de imagen. Para obtener más información sobre las propiedades de codificación, consulte Metadatos de imagen. Controlar la orientación del dispositivo correctamente es esencial para la mayoría de las aplicaciones de fotografía. Para obtener más información, consulte Controlar la orientación del dispositivo con MediaCapture.

Por último, llame a FlushAsync en el objeto codificador para transcodificar la foto de la secuencia en memoria al archivo.

var myPictures = await Windows.Storage.StorageLibrary.GetLibraryAsync(Windows.Storage.KnownLibraryId.Pictures);
StorageFile file = await myPictures.SaveFolder.CreateFileAsync("photo.jpg", CreationCollisionOption.GenerateUniqueName);

using (var captureStream = new InMemoryRandomAccessStream())
{
    await mediaCapture.CapturePhotoToStreamAsync(ImageEncodingProperties.CreateJpeg(), captureStream);

    using (var fileStream = await file.OpenAsync(FileAccessMode.ReadWrite))
    {
        var decoder = await BitmapDecoder.CreateAsync(captureStream);
        var encoder = await BitmapEncoder.CreateForTranscodingAsync(fileStream, decoder);

        var properties = new BitmapPropertySet {
            { "System.Photo.Orientation", new BitmapTypedValue(PhotoOrientation.Normal, PropertyType.UInt16) }
        };
        await encoder.BitmapProperties.SetPropertiesAsync(properties);

        await encoder.FlushAsync();
    }
}

Para obtener más información sobre cómo trabajar con archivos y carpetas, vea Archivos, carpetas y bibliotecas.

Capturar un vídeo

Agregue rápidamente la captura de vídeo a la aplicación mediante la clase LowLagMediaRecording. En primer lugar, declare una variable de clase para el objeto.

LowLagMediaRecording _mediaRecording;

A continuación, cree un objeto StorageFile al que se guardará el vídeo. Tenga en cuenta que para guardar en la biblioteca de vídeos del usuario, como se muestra en este ejemplo, debe agregar la funcionalidad Biblioteca de vídeos al manifiesto de la aplicación. Llame a PrepareLowLagRecordToStorageFileAsync para inicializar la grabación multimedia, pasando el archivo de almacenamiento y un objeto MediaEncodingProfile que especifica la codificación para el vídeo. La clase proporciona métodos estáticos, como CreateMp4, para crear perfiles comunes de codificación de vídeo.

Por último, llame a StartAsync para empezar a capturar vídeo.

var myVideos = await Windows.Storage.StorageLibrary.GetLibraryAsync(Windows.Storage.KnownLibraryId.Videos);
StorageFile file = await myVideos.SaveFolder.CreateFileAsync("video.mp4", CreationCollisionOption.GenerateUniqueName);
_mediaRecording = await mediaCapture.PrepareLowLagRecordToStorageFileAsync(
        MediaEncodingProfile.CreateMp4(VideoEncodingQuality.Auto), file);
await _mediaRecording.StartAsync();

Para detener la grabación de vídeo, llame a StopAsync.

await _mediaRecording.StopAsync();

Puede seguir llamando a StartAsync y StopAsync para capturar vídeos adicionales. Cuando haya terminado de capturar vídeos, llame a FinishAsync para eliminar la sesión de captura y limpiar los recursos asociados. Después de esta llamada, debe llamar a PrepareLowLagRecordToStorageFileAsync de nuevo para reinicializar la sesión de captura antes de llamar a StartAsync.

await _mediaRecording.FinishAsync();

Al capturar vídeo, debe registrar un controlador para el evento RecordLimitationExceeded del objeto MediaCapture, que generará el sistema operativo si supera el límite de una sola grabación, actualmente tres horas. En el controlador del evento, debe finalizar la grabación llamando a StopAsync.

mediaCapture.RecordLimitationExceeded += MediaCapture_RecordLimitationExceeded;
private async void MediaCapture_RecordLimitationExceeded(MediaCapture sender)
{
    await _mediaRecording.StopAsync();
    System.Diagnostics.Debug.WriteLine("Record limitation exceeded.");
}

Reproducir y editar archivos de vídeo capturados

Una vez que haya capturado un vídeo en un archivo, es posible que quiera cargar el archivo y reproducirlo dentro de la interfaz de usuario de la aplicación. Puede hacerlo con el control XAML MediaPlayerElement y un objeto MediaPlayer asociado. Para obtener información sobre cómo reproducir elementos multimedia en una página XAML, consulte Reproducir audio y vídeo con MediaPlayer.

También puede crear un objeto MediaClip desde un archivo de vídeo llamando a CreateFromFileAsync. Una MediaComposition proporciona una funcionalidad básica de edición de vídeo, como organizar la secuencia de objetos MediaClip, recortar la longitud del vídeo, crear capas, agregar música de fondo y aplicar efectos de vídeo. Para obtener más información sobre cómo trabajar con composiciones multimedia, vea Composiciones multimedia y edición.

Pausar y reanudar la grabación de vídeo

Puede pausar una grabación de vídeo y reanudar la grabación sin crear un archivo de salida independiente llamando a PauseAsync y, a continuación, llamando a ResumeAsync.

await _mediaRecording.PauseAsync(Windows.Media.Devices.MediaCapturePauseBehavior.ReleaseHardwareResources);
await _mediaRecording.ResumeAsync();

A partir de Windows 10, versión 1607, puede pausar una grabación de vídeo y recibir el último fotograma capturado antes de pausar la grabación. A continuación, puede superponer este fotograma en la vista previa de la cámara para permitir al usuario alinear la cámara con el marco en pausa antes de reanudar la grabación. Al llamar a PauseWithResultAsync, se devuelve un objeto MediaCapturePauseResult. La propiedad LastFrame es un objeto VideoFrame que representa el último fotograma. Para mostrar el fotograma en XAML, obtenga la representación SoftwareBitmap del fotograma de vídeo. Actualmente, solo se admiten imágenes en formato BGRA8 con canal alfa vacío o premultiplicado, por lo que llame a Convert si es necesario para obtener el formato correcto. Cree un nuevo objeto SoftwareBitmapSource y llame a SetBitmapAsync para inicializarlo. Por último, establezca la propiedad Source de un control Image XAML para mostrar la imagen. Para que este truco funcione, la imagen debe alinearse con el control CaptureElement y debe tener un valor de opacidad menor que uno. No olvide que solo puede modificar la interfaz de usuario en el subproceso de la interfaz de usuario, por lo que debe realizar esta llamada dentro de RunAsync.

PauseWithResultAsync también devuelve la duración del vídeo que se grabó en el segmento precedente en caso de que necesite realizar un seguimiento de cuánto tiempo total se ha grabado.

MediaCapturePauseResult result = 
    await _mediaRecording.PauseWithResultAsync(Windows.Media.Devices.MediaCapturePauseBehavior.RetainHardwareResources);

var pausedFrame = result.LastFrame.SoftwareBitmap;
if(pausedFrame.BitmapPixelFormat != BitmapPixelFormat.Bgra8 || pausedFrame.BitmapAlphaMode != BitmapAlphaMode.Ignore)
{
    pausedFrame = SoftwareBitmap.Convert(pausedFrame, BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore);
}

var source = new SoftwareBitmapSource();
await source.SetBitmapAsync(pausedFrame);

await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
    PauseImage.Source = source;
    PauseImage.Visibility = Visibility.Visible;
});

_totalRecordedTime += result.RecordDuration;

Al reanudar la grabación, puede establecer el origen de la imagen en null y ocultarla.

await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
    PauseImage.Source = null;
    PauseImage.Visibility = Visibility.Collapsed;
});

await _mediaRecording.ResumeAsync();

Tenga en cuenta que también puede obtener un fotograma de resultado al detener el vídeo llamando a StopWithResultAsync.

Captura de audio

Puede agregar rápidamente la captura de audio a la aplicación mediante la misma técnica que se muestra anteriormente para capturar vídeo. En el ejemplo siguiente se crea un StorageFile en la carpeta de datos de la aplicación. Llame a PrepareLowLagRecordToStorageFileAsync para inicializar la sesión de captura, pasando el archivo y un archivo MediaEncodingProfile que el método estático CreateMp3 genera en este ejemplo. Para comenzar la grabación, llame a StartAsync.

mediaCapture.RecordLimitationExceeded += MediaCapture_RecordLimitationExceeded;

var localFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
StorageFile file = await localFolder.CreateFileAsync("audio.mp3", CreationCollisionOption.GenerateUniqueName);
_mediaRecording = await mediaCapture.PrepareLowLagRecordToStorageFileAsync(
        MediaEncodingProfile.CreateMp3(AudioEncodingQuality.High), file);
await _mediaRecording.StartAsync();

Llame a StopAsync para detener la grabación de audio.

await _mediaRecording.StopAsync();

Puede llamar a StartAsync y StopAsync varias veces para grabar varios archivos de audio. Cuando haya terminado de capturar audio, llame a FinishAsync para eliminar la sesión de captura y limpiar los recursos asociados. Después de esta llamada, debe llamar a PrepareLowLagRecordToStorageFileAsync de nuevo para reinicializar la sesión de captura antes de llamar a StartAsync.

await _mediaRecording.FinishAsync();

Detección y respuesta a cambios de nivel de audio por parte del sistema

A partir de Windows 10, versión 1803, la aplicación puede detectar cuándo el sistema baja o cambia el nivel de audio de la captura de audio de la aplicación y las secuencias de representación de audio. Por ejemplo, el sistema puede silenciar las secuencias de la aplicación cuando entra en segundo plano. La clase AudioStateMonitor permite registrarse para recibir un evento cuando el sistema modifica el volumen de una secuencia de audio. Obtenga una instancia de AudioStateMonitor para supervisar secuencias de captura de audio mediante una llamada a CreateForCaptureMonitoring. Obtenga una instancia para supervisar las secuencias de representación de audio mediante una llamada a CreateForRenderMonitoring. Registre un controlador para el evento SoundLevelChanged de cada monitor que se notificará cuando el sistema cambie el audio de la categoría de secuencia correspondiente.

// Namespaces for monitoring audio state
using Windows.Media;
using Windows.Media.Audio;
AudioStateMonitor captureAudioStateMonitor;
AudioStateMonitor renderAudioStateMonitor;
captureAudioStateMonitor = AudioStateMonitor.CreateForCaptureMonitoring();
captureAudioStateMonitor.SoundLevelChanged += CaptureAudioStateMonitor_SoundLevelChanged; ;

renderAudioStateMonitor = AudioStateMonitor.CreateForRenderMonitoring();
renderAudioStateMonitor.SoundLevelChanged += RenderAudioStateMonitor_SoundLevelChanged; ;

En el controlador SoundLevelChanged de la secuencia de captura, puede comprobar la propiedad SoundLevel del emisor AudioStateMonitor para determinar el nuevo nivel de sonido. Tenga en cuenta que el sistema nunca debe bajar o hundir una secuencia de captura. Solo debe silenciarse o cambiarse de nuevo al volumen completo. Si la secuencia de audio está silenciada, puede detener una captura en curso. Si la secuencia de audio se restaura al volumen completo, puede empezar a capturar de nuevo. En el ejemplo siguiente se usan algunas variables de clase booleanas para realizar un seguimiento de si la aplicación está capturando audio y si la captura se detuvo debido al cambio de estado de audio. Estas variables se usan para determinar cuándo es adecuado detener o iniciar la captura de audio mediante programación.

bool isCapturingAudio = false;
bool capturingStoppedForAudioState = false;
private void CaptureAudioStateMonitor_SoundLevelChanged(AudioStateMonitor sender, object args)
{
    switch (sender.SoundLevel)
    {
        case SoundLevel.Full:
            if(capturingStoppedForAudioState)
            {
                StartAudioCapture();
                capturingStoppedForAudioState = false;
            }  
            break;
        case SoundLevel.Muted:
            if(isCapturingAudio)
            {
                StopAudioCapture();
                capturingStoppedForAudioState = true;
            }
            break;
        case SoundLevel.Low:
            // This should never happen for capture
            Debug.WriteLine("Unexpected audio state.");
            break;
    }
}

En el ejemplo de código siguiente se muestra una implementación del controlador SoundLevelChanged para la representación de audio. Según el escenario de la aplicación y el tipo de contenido que esté reproduciendo, es posible que quiera pausar la reproducción de audio cuando el nivel de sonido se hunda. Para obtener más información sobre cómo controlar los cambios de nivel de sonido para la reproducción multimedia, consulte Reproducir audio y vídeo con MediaPlayer.

private void RenderAudioStateMonitor_SoundLevelChanged(AudioStateMonitor sender, object args)
{
    if ((sender.SoundLevel == SoundLevel.Full) ||
  (sender.SoundLevel == SoundLevel.Low && !isPodcast))
    {
        mediaPlayer.Play();
    }
    else if ((sender.SoundLevel == SoundLevel.Muted) ||
         (sender.SoundLevel == SoundLevel.Low && isPodcast))
    {
        // Pause playback if we’re muted or if we’re playing a podcast and are ducked
        mediaPlayer.Pause();
    }
}