Efeitos para captura de vídeo

Este tópico mostra como aplicar efeitos à visualização de câmera e fluxos de gravação de vídeo e mostra como usar o efeito de estabilização de vídeo.

Observação

Este artigo se baseia em conceitos e códigos discutidos em Captura básica de fotos, áudio e vídeo com o MediaCapture, que descreve as etapas para implementar uma captura básica de fotos e vídeos. Recomendamos que você se familiarize com o padrão de captura de mídia básica neste artigo antes de passar para cenários de captura mais avançados. O código neste artigo presume que seu aplicativo já tenha uma instância de MediaCapture inicializada corretamente.

Adicionando e removendo efeitos do fluxo de vídeo da câmera

Para capturar ou visualizar vídeos da câmera do dispositivo, use o objeto MediaCapture conforme descrito em Captura básica de fotos, áudio e vídeo com MediaCapture. Após ter inicializado o objeto MediaCapture, você pode adicionar um ou mais efeitos de vídeo ao fluxo de visualização ou captura chamando AddVideoEffectAsync, transmitindo um objeto IVideoEffectDefinition que representa o efeito a ser adicionado e um membro da enumeração MediaStreamType que indica se o efeito deve ser adicionado ao fluxo de visualização da câmera ou ao fluxo de registro.

Observação

Em alguns dispositivos, o fluxo de visualização e o fluxo de captura são os mesmos, o que significa que, se você especificar MediaStreamType.VideoPreview ou MediaStreamType.VideoRecord ao chamar AddVideoEffectAsync, o efeito será aplicado aos fluxos de visualização e gravação. Você pode determinar se os fluxos de visualização e gravação são os mesmos no dispositivo atual verificando a propriedade VideoDeviceCharacteristic do objeto MediaCaptureSettings para o MediaCapture. Se o valor dessa propriedade for VideoDeviceCharacteristic.AllStreamsIdentical ou VideoDeviceCharacteristic.PreviewRecordStreamsIdentical, os fluxos são os mesmos e qualquer efeito que se aplica a um afeta o outro.

O exemplo a seguir adiciona um efeito aos fluxos de visualização e gravação da câmera. Esse exemplo ilustra a verificação de se os fluxos de visualização e gravação são os mesmos.

if (mediaCapture.MediaCaptureSettings.VideoDeviceCharacteristic == VideoDeviceCharacteristic.AllStreamsIdentical ||
    mediaCapture.MediaCaptureSettings.VideoDeviceCharacteristic == VideoDeviceCharacteristic.PreviewRecordStreamsIdentical)
{
    // This effect will modify both the preview and the record streams, because they are the same stream.
    myRecordEffect = await mediaCapture.AddVideoEffectAsync(myEffectDefinition, MediaStreamType.VideoRecord);
}
else
{
    myRecordEffect = await mediaCapture.AddVideoEffectAsync(myEffectDefinition, MediaStreamType.VideoRecord);
    myPreviewEffect = await mediaCapture.AddVideoEffectAsync(myEffectDefinition, MediaStreamType.VideoPreview);
}

Observe que AddVideoEffectAsync retorna um objeto que implementa IMediaExtension que representa o efeito de vídeo adicionado. Alguns efeitos permitem que você altere as configurações de efeito transmitindo um PropertySet para o método SetProperties.

A partir do Windows 10, versão 1607, você também pode usar o objeto retornado por AddVideoEffectAsync para remover o efeito do pipeline do vídeo transmitindo-o para RemoveEffectAsync. RemoveEffectAsync determina automaticamente se o parâmetro de objeto de efeito foi adicionado ao fluxo de visualização ou gravação. Portanto, você não precisa especificar o tipo de fluxo ao fazer a chamada.

if (myRecordEffect != null)
{
    await mediaCapture.RemoveEffectAsync(myRecordEffect);
}
if(myPreviewEffect != null)
{
    await mediaCapture.RemoveEffectAsync(myPreviewEffect);
}

Você também pode remover todos os efeitos do fluxo de visualização ou captura chamando ClearEffectsAsync e especificando o fluxo para o qual todos os efeitos devem ser removidos.

await mediaCapture.ClearEffectsAsync(MediaStreamType.VideoPreview);
await mediaCapture.ClearEffectsAsync(MediaStreamType.VideoRecord);

Efeito de estabilização de vídeo

O efeito de estabilização de vídeo manipula os quadros de um fluxo de vídeo para minimizar a vibração causada por segurar o dispositivo de captura em sua mão. Como essa técnica faz com que os pixels sejam deslocados para a direita, para a esquerda, para cima e para baixo, e como o efeito identifica o conteúdo fora do quadro de vídeo, o vídeo estabilizado é cortado ligeiramente do vídeo original. Uma função utilitária é fornecida para permitir que você ajuste suas configurações de codificação para gerenciar de forma ideal o corte realizado pelo efeito.

Nos dispositivos com suporte para isso, a OIS (estabilização de imagem ótica) estabiliza o vídeo manipulando mecanicamente o dispositivo de captura e, portanto, não precisa cortar as bordas dos quadros do vídeo. Para obter mais informações, consulte Controles de captura do dispositivo para a captura de vídeo.

Configurar seu aplicativo para usar estabilização de vídeo

Além dos namespaces necessários para captura de mídia básica, o uso do efeito de estabilização de vídeo exige o namespace a seguir.

using Windows.Media.Core;
using Windows.Media.MediaProperties;
using Windows.Media.Effects;
using Windows.Media;

Declare uma variável membro para armazenar o objeto VideoStabilizationEffect. Como parte da implementação do efeito, você modificará as propriedades de codificação que usa para codificar o vídeo capturado. Declare duas variáveis para armazenar uma cópia de backup das propriedades de codificação de entrada e saída para poder restaurá-las mais tarde, quando o efeito estiver desabilitado. Por fim, declare uma variável membro do tipo MediaEncodingProfile, pois esse objeto será acessado em vários locais dentro do seu código.

private VideoStabilizationEffect _videoStabilizationEffect;
private VideoEncodingProperties _inputPropertiesBackup;
private VideoEncodingProperties _outputPropertiesBackup;
private MediaEncodingProfile _encodingProfile;

Para esse cenário, você deve atribuir o objeto de perfil de codificação de mídia a uma variável membro para poder acessá-lo posteriormente.

_encodingProfile = MediaEncodingProfile.CreateMp4(VideoEncodingQuality.Auto);

Inicializar o efeito de estabilização de vídeo

Após a inicialização do seu objeto MediaCapture, crie uma nova instância do objeto VideoStabilizationEffectDefinition. Chame MediaCapture.AddVideoEffectAsync para adicionar o efeito ao pipeline de vídeo e recuperar uma instância da classe VideoStabilizationEffect. Especifique MediaStreamType.VideoRecord para indicar que o efeito deve ser aplicado ao fluxo de gravação de vídeo.

Registre um manipulador de eventos para o evento EnabledChanged e chame o método auxiliar SetUpVideoStabilizationRecommendationAsync, ambos discutidos mais adiante neste artigo. Por fim, defina a propriedade Enabled do efeito como "true" para habilitá-lo.

// Create the effect definition
VideoStabilizationEffectDefinition stabilizerDefinition = new VideoStabilizationEffectDefinition();

// Add the video stabilization effect to media capture
_videoStabilizationEffect =
    (VideoStabilizationEffect)await mediaCapture.AddVideoEffectAsync(stabilizerDefinition, MediaStreamType.VideoRecord);

_videoStabilizationEffect.EnabledChanged += VideoStabilizationEffect_EnabledChanged;

await SetUpVideoStabilizationRecommendationAsync();

_videoStabilizationEffect.Enabled = true;

Conforme discutido anteriormente neste artigo, a técnica usada pelo efeito de estabilização de vídeo faz inevitavelmente com que o vídeo estabilizado seja cortado em uma certa medida da fonte de vídeo. Defina a função de auxiliar a seguir em seu código para ajustar as propriedades de codificação de vídeo para lidar do modo ideal com essa limitação do efeito. Esta etapa não é necessária para usar o efeito de estabilização de vídeo, mas, se você não executá-la, o vídeo resultante será ampliado um pouco e, portanto, terá uma fidelidade visual um pouco menor.

Chame GetRecommendedStreamConfiguration na sua instância de efeito de estabilização de vídeo, transmitindo o objeto VideoDeviceController, que informa o efeito sobre as suas propriedades de codificação de fluxo de entrada atuais, e seu MediaEncodingProfile, que faz com que o evento conheça as suas propriedades de codificação de saída atuais. Esse método retorna um objeto VideoStreamConfiguration contendo novas propriedades de codificação de fluxo de entrada e saída recomendadas.

As propriedades recomendadas de codificação de entrada apresentam, caso o dispositivo ofereça suporte, uma resolução mais alta do que as configurações iniciais que você forneceu, para que haja o mínimo de perda na resolução após a aplicação do efeito de corte.

Chame VideoDeviceController.SetMediaStreamPropertiesAsync para definir as novas propriedades de codificação. Antes de definir as novas propriedades, use a variável membro para armazenar as propriedades de codificação iniciais para que você possa modificar as configurações de novo quando desabilitar o efeito.

Se o efeito de estabilização de vídeo precisar cortar o vídeo de saída, as propriedades de codificação de saída recomendadas serão do tamanho do vídeo cortado. Isso significa que a resolução de saída corresponderá ao tamanho do vídeo cortado. Se você não usar as propriedades de saída recomendadas, o vídeo será dimensionado para corresponder ao tamanho de saída inicial, o que resultará em uma perda de fidelidade visual.

Defina a propriedade Video do objeto MediaEncodingProfile. Antes de definir as novas propriedades, use a variável membro para armazenar as propriedades de codificação iniciais para que você possa modificar as configurações de novo quando desabilitar o efeito.

private async Task SetUpVideoStabilizationRecommendationAsync()
{

    // Get the recommendation from the effect based on our current input and output configuration
    var recommendation = _videoStabilizationEffect.GetRecommendedStreamConfiguration(mediaCapture.VideoDeviceController, _encodingProfile.Video);

    // Handle the recommendation for the input into the effect, which can contain a larger resolution than currently configured, so cropping is minimized
    if (recommendation.InputProperties != null)
    {
        // Back up the current input properties from before VS was activated
        _inputPropertiesBackup = mediaCapture.VideoDeviceController.GetMediaStreamProperties(MediaStreamType.VideoRecord) as VideoEncodingProperties;

        // Set the recommendation from the effect (a resolution higher than the current one to allow for cropping) on the input
        await mediaCapture.VideoDeviceController.SetMediaStreamPropertiesAsync(MediaStreamType.VideoRecord, recommendation.InputProperties);
        await mediaCapture.VideoDeviceController.SetMediaStreamPropertiesAsync(MediaStreamType.VideoPreview, recommendation.InputProperties);
    }

    // Handle the recommendations for the output from the effect
    if (recommendation.OutputProperties != null)
    {
        // Back up the current output properties from before VS was activated
        _outputPropertiesBackup = _encodingProfile.Video;

        // Apply the recommended encoding profile for the output
        _encodingProfile.Video = recommendation.OutputProperties;
    }
}

Manipular o efeito de estabilização de vídeo sendo desabilitado

O sistema poderá desabilitar automaticamente o efeito de estabilização de vídeo se a taxa de transferência de pixel for muito alta para o efeito ou se detectar que o efeito está sendo executado lentamente. Se isso ocorrer, o evento EnabledChanged será gerado. A instância VideoStabilizationEffect no parâmetro sender indica o novo estado do efeito, habilitado ou desabilitado. O VideoStabilizationEffectEnabledChangedEventArgs tem um valor VideoStabilizationEffectEnabledChangedReason que indica por que o efeito foi habilitado ou desabilitado. Observe que esse evento também será gerado se você habilitá-lo ou desabilitá-lo o efeito programaticamente, nesse caso, o motivo será Programmatic.

Normalmente, você usaria esse evento para ajustar a interface do usuário do seu aplicativo para indicar o status atual de estabilização de vídeo.

private async void VideoStabilizationEffect_EnabledChanged(VideoStabilizationEffect sender, VideoStabilizationEffectEnabledChangedEventArgs args)
{
    await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
    {
        // Update your UI to reflect the change in status
        ShowMessageToUser("video stabilization status: " + sender.Enabled + ". Reason: " + args.Reason);
    });
}

Limpar o efeito de estabilização de vídeo

Para limpar o efeito de estabilização de vídeo, chame RemoveEffectAsync para remover o efeito do pipeline do vídeo. Se as variáveis membro que contêm as propriedades de codificação iniciais não forem nulas, use-as para restaurar as propriedades de codificação. Por fim, remova o manipulador de eventos EnabledChanged e defina o efeito como "null".

// Clear all effects in the pipeline
await mediaCapture.RemoveEffectAsync(_videoStabilizationEffect);

// If backed up settings (stream properties and encoding profile) exist, restore them and clear the backups
if (_inputPropertiesBackup != null)
{
    await mediaCapture.VideoDeviceController.SetMediaStreamPropertiesAsync(MediaStreamType.VideoRecord, _inputPropertiesBackup);
    _inputPropertiesBackup = null;
}

if (_outputPropertiesBackup != null)
{
    _encodingProfile.Video = _outputPropertiesBackup;
    _outputPropertiesBackup = null;
}

_videoStabilizationEffect.EnabledChanged -= VideoStabilizationEffect_EnabledChanged;

_videoStabilizationEffect = null;