Captura básica de fotos, áudio e vídeo com MediaCapture

Este artigo mostra a maneira mais simples de capturar fotos e vídeos usando a classe MediaCapture. A classe MediaCapture expõe um conjunto robusto de APIs que fornecem controle aprofundado sobre o pipeline de captura e permite a captura de cenários avançados, mas este artigo se destina a ajudá-lo a adicionar captura de mídia básica ao seu aplicativo com rapidez e facilidade. Para saber mais sobre os recursos que o MediaCapture oferece, consulte Câmera.

Se você simplesmente deseja capturar uma foto ou vídeo e não pretende adicionar nenhum recurso adicional de captura de mídia, ou se não quiser criar sua própria interface do usuário da câmera, convém usar a classe CameraCaptureUI, que permite que você simplesmente inicie o aplicativo de câmera interno do Windows e receba o arquivo de foto ou vídeo que foi capturado. Para mais informações, consulte Capturar fotos e vídeos com a interface do usuário da câmera interna do Windows

O código neste artigo foi adaptado do exemplo do kit inicial da câmera. Você pode baixar o exemplo para ver o código usado no contexto ou para usar o exemplo como ponto de partida para seu próprio aplicativo.

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. Se quiser salvar fotos e vídeos capturados na biblioteca de Imagens ou Vídeos dos usuários, você também deverá declarar o recurso picturesLibrary e videosLibrary.

Adicionar recursos 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.
  4. Para acessar a biblioteca de Imagens e Vídeos, marque as caixas Biblioteca de Imagens e a caixa Biblioteca de Vídeos.

Inicializar o objeto MediaCapture

Todos os métodos de captura descritos neste artigo têm a primeira etapa de inicializar o objeto MediaCapture chamando o construtor e, em seguida, chamando InitializeAsync. Como o objeto MediaCapture será acessado de vários lugares em seu aplicativo, declare uma variável de classe para conter o objeto. Implemente um manipulador para o evento Failed do objeto MediaCapture para ser notificado se uma operação de captura falhar.

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

Observação

O Windows permite que os usuários concedam ou neguem acesso à câmera do dispositivo no aplicativo Configurações do Windows, em Privacidade e Segurança -> Câmera. Ao inicializar o dispositivo de captura, os aplicativos devem verificar se têm acesso à câmera e lidar com o caso em que o acesso é negado pelo usuário. Para mais informações, consulte Manipular a configuração de privacidade da câmera do Windows.

Configurar a pré-visualização da câmara

É possível capturar fotos, vídeos e áudio usando o MediaCapture sem mostrar a visualização da câmera, mas normalmente você deseja mostrar o fluxo de visualização para que o usuário possa ver o que está sendo capturado. Além disso, alguns recursos do MediaCapture exigem que o fluxo de visualização esteja em execução antes de poderem ser ativados, incluindo foco automático, exposição automática e balanço de branco automático. Para ver como configurar a visualização da câmera, consulte Exibir a visualização da câmera.

Capturar uma foto para um SoftwareBitmap

A classe SoftwareBitmap foi introduzida no Windows 10 para fornecer uma representação comum de imagens em vários recursos. Se você quiser capturar uma foto e, em seguida, usar imediatamente a imagem capturada em seu aplicativo, como exibi-la em XAML, em vez de capturar em um arquivo, então você deve capturar em um SoftwareBitmap. Você ainda tem a opção de salvar a imagem no disco mais tarde.

Depois de inicializar o objeto MediaCapture, você pode capturar uma foto para um SoftwareBitmap usando a classe LowLagPhotoCapture. Obtenha uma instância dessa classe chamando PrepareLowLagPhotoCaptureAsync, passando um objeto ImageEncodingProperties especificando o formato de imagem desejado. CreateUncompressed cria uma codificação descompactada com o formato de pixel especificado. Capture uma foto chamando CaptureAsync, que retorna um objeto CapturedPhoto. Obtenha um SoftwareBitmap acessando a propriedade Frame e, em seguida, a propriedade SoftwareBitmap.

Se desejar, você pode capturar várias fotos chamando CaptureAsync repetidamente. Quando terminar a captura, chame FinishAsync para desligar a sessão LowLagPhotoCapture e liberar os recursos associados. Depois de chamar FinishAsync, para começar a capturar fotos novamente, você precisará chamar PrepareLowLagPhotoCaptureAsync novamente para reinicializar a sessão de captura antes de chamar 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 do Windows, versão 1803, você pode acessar a propriedade BitmapProperties da classe CapturedFrame retornada de CaptureAsync para recuperar metadados sobre a foto capturada. Você pode passar esses dados para um BitmapEncoder e salvar os metadados em um arquivo. Anteriormente, não havia como acessar esses dados para formatos de imagem não compactados. Você também pode acessar a propriedade ControlValues para recuperar um objeto CapturedFrameControlValues que descreve os valores de controle, como exposição e balanço de branco, para o quadro capturado.

Para mais informações sobre como usar o BitmapEncoder e sobre como trabalhar com o objeto SoftwareBitmap, incluindo como exibir um em uma página XAML, consulte Criar, editar e salvar imagens de bitmap.

Para mais informações sobre como definir valores de controle de dispositivo de captura, consulte Controles de dispositivo de captura para foto e vídeo.

A partir do Windows 10, versão 1803, você pode obter os metadados, como informações EXIF, para fotos capturadas em formato não compactado acessando a propriedade BitmapProperties do CapturedFrame retornado por MediaCapture. Em versões anteriores, esses dados só eram acessíveis no cabeçalho de fotos capturadas em um formato de arquivo compactado. Você pode fornecer esses dados para um BitmapEncoder ao gravar manualmente um arquivo de imagem. Para mais informações sobre codificação de bitmaps, consulte Criar, editar e salvar imagens de bitmap. Você também pode acessar os valores de controle de quadro, como configurações de exposição e flash, usados quando a imagem foi capturada acessando a propriedade ControlValues. Para mais informações, consulte Controles de dispositivo de captura para captura de fotos e vídeos.

Capturar uma foto para um arquivo

Um aplicativo de fotografia comum salvará uma foto capturada em disco ou no armazenamento em nuvem e precisará adicionar metadados, como orientação da foto, ao arquivo. O exemplo a seguir mostra como capturar uma foto em um arquivo. Você também tem a opção de criar um SoftwareBitmap a partir do arquivo de imagem mais tarde.

A técnica mostrada neste exemplo captura a foto para um fluxo na memória e, em seguida, transcodifica a foto do fluxo para um arquivo no disco. Este exemplo usa GetLibraryAsync para obter a biblioteca de imagens do usuário e, em seguida, a propriedade SaveFolder para obter uma pasta de salvamento padrão de referência. Lembre-se de adicionar o recurso Biblioteca de Imagens ao manifesto do aplicativo para acessar essa pasta. CreateFileAsync cria um novo StorageFile no qual a foto será salva.

Crie um InMemoryRandomAccessStream e chame CapturePhotoToStreamAsync para capturar uma foto para o fluxo, passando o fluxo e um objeto ImageEncodingProperties especificando o formato de imagem que deve ser usado. Você pode criar propriedades de codificação personalizadas inicializando o objeto por conta própria, mas a classe fornece métodos estáticos, como ImageEncodingProperties.CreateJpeg para formatos de codificação comuns. Em seguida, crie um fluxo de arquivos para o arquivo de saída chamando OpenAsync. Crie um BitmapDecoder para decodificar a imagem do fluxo de memória e, em seguida, crie um BitmapEncoder para codificar a imagem para o arquivo chamando CreateForTranscodingAsync.

Opcionalmente, você pode criar um objeto BitmapPropertySet e chamar SetPropertiesAsync no codificador de imagem para incluir metadados sobre a foto no arquivo de imagem. Para mais informações sobre propriedades de codificação, consulte Metadados de imagem. Trabalhar com a orientação do dispositivo corretamente é essencial para a maioria dos aplicativos de fotografia. Para mais informações, consulte Trabalhar com a orientação do dispositivo com o MediaCapture.

Finalmente, chame FlushAsync no objeto codificador para transcodificar a foto do fluxo na memória para o arquivo.

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 mais informações sobre como trabalhar com arquivos e pastas, consulte Arquivos, pastas e bibliotecas.

Capturar um vídeo

Adicione rapidamente a captura de vídeo ao seu aplicativo usando a classe LowLagMediaRecording. Primeiro, declare uma variável de classe para o objeto.

LowLagMediaRecording _mediaRecording;

Em seguida, crie um objeto StorageFile no qual o vídeo será salvo. Para salvar na biblioteca de vídeos do usuário, como mostrado neste exemplo, você deve adicionar o recurso Biblioteca de Vídeos ao manifesto do aplicativo. Chame PrepareLowLagRecordToStorageFileAsync para inicializar a gravação de mídia, passando o arquivo de armazenamento e um objeto MediaEncodingProfile especificando a codificação para o vídeo. A classe fornece métodos estáticos, como CreateMp4, para criar perfis de codificação de vídeo comuns.

Finalmente, chame StartAsync para começar a capturar vídeos.

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 interromper a gravação de vídeo, chame StopAsync.

await _mediaRecording.StopAsync();

Você pode continuar a chamar StartAsync e StopAsync para capturar vídeos adicionais. Quando terminar de capturar vídeos, chame FinishAsync para descartar a sessão de captura e limpar os recursos associados. Após essa chamada, você deve chamar PrepareLowLagRecordToStorageFileAsync novamente para reinicializar a sessão de captura antes de chamar StartAsync.

await _mediaRecording.FinishAsync();

Ao capturar vídeos, você deve registrar um manipulador para o evento RecordLimitationExceeded do objeto MediaCapture, que será gerado pelo sistema operacional se você ultrapassar o limite para uma única gravação, atualmente de três horas. No manipulador do evento, você deve finalizar sua gravação chamando StopAsync.

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

Reproduzir e editar arquivos de vídeo capturados

Depois de capturar um vídeo para um arquivo, convém carregá-lo e reproduzi-lo na interface do usuário do aplicativo. Você pode fazer isso usando o controle XAML MediaPlayerElement e um MediaPlayer associado. Para mais informações sobre como reproduzir mídia em uma página XAML, consulte Reproduzir áudio e vídeo com o MediaPlayer.

Você também pode criar um objeto MediaClip a partir de um arquivo de vídeo chamando CreateFromFileAsync. Um MediaComposition fornece funcionalidade básica de edição de vídeo, como organizar a sequência de objetos MediaClip, cortar a duração do vídeo, criar camadas, adicionar música de fundo e aplicar efeitos de vídeo. Para mais informações sobre como trabalhar com composições de mídia, consulte Composições e edição de mídia.

Pausar e retomar a gravação de vídeo

Você pode pausar uma gravação de vídeo e, em seguida, retomar a gravação sem criar um arquivo de saída separado chamando PauseAsync e, em seguida, chamando ResumeAsync.

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

A partir do Windows 10, versão 1607, você pode pausar uma gravação de vídeo e receber o último quadro capturado antes da pausa da gravação. Em seguida, você pode sobrepor esse quadro na visualização da câmera para permitir que o usuário alinhe a câmera com o quadro pausado antes de retomar a gravação. Chamar PauseWithResultAsync retorna um objeto MediaCapturePauseResult. A propriedade LastFrame é um objeto VideoFrame que representa o último quadro. Para exibir o quadro em XAML, obtenha a representação SoftwareBitmap do quadro de vídeo. Atualmente, apenas imagens no formato BGRA8 com canal alfa pré-multiplicado ou vazio são suportadas, então chame Convert se necessário para obter o formato correto. Crie um objeto SoftwareBitmapSource e chame SetBitmapAsync para inicializá-lo. Finalmente, defina a propriedade Source de um controle XAML Image para exibir a imagem. Para que esse truque funcione, sua imagem deve estar alinhada com o controle CaptureElement e deve ter um valor de opacidade menor que um. Não se esqueça de que você só pode modificar a interface do usuário no thread da interface do usuário, portanto, faça essa chamada dentro do RunAsync.

PauseWithResultAsync também retorna a duração do vídeo que foi gravado no segmento anterior, caso você precise acompanhar quanto tempo total foi gravado.

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;

Ao retomar a gravação, você pode definir a origem da imagem como nula e ocultá-la.

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

await _mediaRecording.ResumeAsync();

Você também pode obter um quadro de resultado ao parar o vídeo chamando StopWithResultAsync.

Capturar áudio

Você pode adicionar rapidamente a captura de áudio ao seu aplicativo usando a mesma técnica mostrada acima para capturar vídeo. O exemplo abaixo cria um StorageFile na pasta de dados do aplicativo. Chame PrepareLowLagRecordToStorageFileAsync para inicializar a sessão de captura, passando o arquivo e um MediaEncodingProfile que é gerado neste exemplo pelo método estático CreateMp3. Para começar a gravar, chame 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();

Chame StopAsync para interromper a gravação de áudio.

await _mediaRecording.StopAsync();

Você pode chamar StartAsync e StopAsync várias vezes para gravar vários arquivos de áudio. Quando terminar de capturar áudios, chame FinishAsync para descartar a sessão de captura e limpar os recursos associados. Após essa chamada, você deve chamar PrepareLowLagRecordToStorageFileAsync novamente para reinicializar a sessão de captura antes de chamar StartAsync.

await _mediaRecording.FinishAsync();

Detectar e responder a alterações de nível de áudio pelo sistema

A partir do Windows 10, versão 1803, seu aplicativo pode detectar quando o sistema reduz ou silencia o nível de áudio dos fluxos de captura e renderização de áudio do aplicativo. Por exemplo, o sistema pode silenciar os fluxos do seu aplicativo quando ele fica em segundo plano. A classe AudioStateMonitor permite que você registre para receber um evento quando o sistema modifica o volume de um fluxo de áudio. Obtenha uma instância do AudioStateMonitor para monitorar fluxos de captura de áudio chamando CreateForCaptureMonitoring. Obtenha uma instância para monitorar fluxos de renderização de áudio chamando CreateForRenderMonitoring. Registre um manipulador para o evento SoundLevelChanged de cada monitor a ser notificado quando o áudio da categoria de fluxo correspondente for alterado pelo sistema.

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

No manipulador SoundLevelChanged para o fluxo de captura, você pode verificar a propriedade SoundLevel do remetente AudioStateMonitor para determinar o novo nível de som. Um fluxo de captura nunca deve ser rebaixado, ou "abaixado", pelo sistema. Ele só deve ser silenciado ou retornado ao volume total. Se o fluxo de áudio estiver mudo, você poderá interromper uma captura em andamento. Se o fluxo de áudio for restaurado para o volume total, você poderá começar a capturar novamente. O exemplo a seguir usa algumas variáveis de classe booleana para controlar se o aplicativo está capturando áudio no momento e se a captura foi interrompida devido à alteração de estado do áudio. Essas variáveis são usadas para determinar quando é apropriado parar ou iniciar programaticamente a captura de áudio.

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

O exemplo de código a seguir ilustra uma implementação do manipulador SoundLevelChanged para renderização de áudio. Dependendo do cenário do aplicativo e do tipo de conteúdo que você está reproduzindo, convém pausar a reprodução de áudio quando o nível de som for reduzido. Para mais informações sobre como trabalhar com alterações de nível de som para reprodução de mídia, consulte Reproduzir áudio e vídeo com o 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();
    }
}