Эффекты для видеозахвата

В этом разделе показано, как применять эффекты к предварительному просмотру камеры и потокам видеозаписи, а также как использовать эффект стабилизации видео.

Примечание

В этой статье используются понятия и код из статьи Основные принципы фото-, аудио- и видеозахвата с помощью MediaCapture, в которой описаны этапы реализации основных принципов фото- и видеозахвата. Мы рекомендуем ознакомиться с базовым шаблоном захвата мультимедиа в этой статье, прежде чем перейти к более сложным сценариям захвата. Код в этой статье подразумевает, что ваше приложение уже содержит экземпляр MediaCapture, инициализированный надлежащим образом.

Добавление и удаление эффектов из видеопотока камеры

Для записи или предварительно просмотра видео с камеры устройства используйте объект MediaCapture, как описано в статье Основные принципы фото-, аудио- и видеозахвата с помощью MediaCapture. После инициализации объекта MediaCapture можно добавить один или несколько видеоэффектов в поток предварительного просмотра или захвата, вызвав метод AddVideoEffectAsync и передав объект IVideoEffectDefinition, представляющий нужный эффект, и член перечисления MediaStreamType, указывающий, следует ли добавить эффект в потока предварительного просмотра или записи камеры.

Примечание

На некоторых устройствах поток предварительного просмотра и поток захвата совпадают, т. е. если указать MediaStreamType.VideoPreview или MediaStreamType.VideoRecord при вызове AddVideoEffectAsync, эффект будет применен к обоим потокам. Вы можете определить, совпадают ли потоки предварительного просмотра и записи на текущем устройстве, проверив свойство VideoDeviceCharacteristic в MediaCaptureSettings для объекта MediaCapture. Если значение этого свойства равно VideoDeviceCharacteristic.AllStreamsIdentical или VideoDeviceCharacteristic.PreviewRecordStreamsIdentical, то потоки одинаковые, и все эффекты будут применяться к обоим потокам.

В следующем примере эффект добавляется в потоки предварительного просмотра и записи камеры. В примере показано, как проверить, совпадают ли потоки предварительного просмотра и записи.

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

Обратите внимание, что AddVideoEffectAsync возвращает объект, реализующий расширение IMediaExtension, которое представляет добавленный видеоэффект. Некоторые эффекты позволяют изменить свои параметры, передав PropertySet методу SetProperties.

Начиная с Windows 10 версии 1607 можно также использовать объект, возвращенный AddVideoEffectAsync, чтобы удалить эффект из видеоконвейера, передав его в RemoveEffectAsync. Метод RemoveEffectAsync автоматически определяет, был ли параметр объекта эффекта добавлен в поток предварительного просмотра или записи, чтобы вам не нужно было указывать тип потока при вызове.

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

Вы также можете удалить все эффекты из потока предварительного просмотра или записи, вызвав метод ClearEffectsAsync и указав поток, из которого необходимо удалить все эффекты.

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

Эффект стабилизации видео

Эффект стабилизации видео управляет кадрами видеопотока, чтобы минимизировать подергивание, когда вы держите снимающее устройство в руке. Поскольку этот метод перемещает пиксели вправо, влево, вверх и вниз и эффект не учитывает содержимое за пределами видеокадра, стабилизированное видео получается несколько обрезанным по сравнению с исходным. Имеется служебная функция, которая позволяет настраивать параметры кодирования видео для оптимального управления обрезкой, выполняемой эффектом.

На устройствах с поддержкой функции оптической стабилизации изображений (OIS) видео стабилизируется посредством механического управления записывающим устройством, поэтому нет необходимости обрезать края видеокадров. Дополнительные сведения см. в статье Доступ к элементам управления видеозахватом на устройстве.

Настройка приложения для использования стабилизации видео

Помимо пространства имен, необходимого для основного захвата мультимедиа, для использования эффекта стабилизации видео нужно следующее пространство имен.

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

Объявите переменную-член для хранения объекта VideoStabilizationEffect. В рамках реализации эффекта измените свойства кодирования, применяемые для кодирования захваченного видео. Объявите две переменные для хранения резервной копии исходных свойств кодирования входного и выходного потока, чтобы их можно было восстановить после отключения эффекта. Наконец объявите переменную-член типа MediaEncodingProfile, поскольку этот объект будет доступен из разных мест кода.

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

Для этого сценария следует назначать объект профиля кодирования мультимедиа переменной-члену, чтобы можно было получить к нему доступ позже.

_encodingProfile = MediaEncodingProfile.CreateMp4(VideoEncodingQuality.Auto);

Инициализация эффекта стабилизации видео

После инициализации объекта MediaCapture создайте новый экземпляр объекта VideoStabilizationEffectDefinition. Вызовите MediaCapture.AddVideoEffectAsync для добавления эффекта к видеоконвейеру и получения экземпляра класса VideoStabilizationEffect. Определите MediaStreamType.VideoRecord, чтобы указать, что эффект должен применяться к потоку видеозаписи.

Зарегистрируйте обработчик для события EnabledChanged и вызовите вспомогательный метод SetUpVideoStabilizationRecommendationAsync, которые рассматриваются ниже в этой статье. В заключение установите для свойства Enabled значение true, чтобы включить эффект.

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

Как было сказано выше в этой статье, метод, используемый для эффекта стабилизации видео, неизбежно приводит к небольшой обрезке исходного видео. Определите следующую вспомогательную функцию в коде, чтобы настроить свойства кодирования видео и перекрыть это ограничение эффекта наилучшим образом. Эффект стабилизации видео можно использовать и без этого этапа, но если вы его пропустите, полученное видео будет слегка растянутым, то есть его визуальное качество будет несколько ниже.

Вызовите GetRecommendedStreamConfiguration для экземпляра эффекта стабилизации видео, передавая объект VideoDeviceController, который сообщает эффекту информацию о текущих свойствах кодирования входного потока и вашем профиле MediaEncodingProfile, благодаря чему эффект получает информацию о текущих свойствах кодирования на выходе. Этот метод возвращает объект VideoStreamConfiguration, содержащий новые рекомендуемые свойства кодирования входящего и выходящего потоков.

Рекомендуемые свойства кодирования входящего потока обеспечивают более высокое разрешение (если такая возможность поддерживается устройством) по сравнению с заданными исходными параметрами, чтобы минимизировать потери разрешения из-за обрезки в результате применения эффекта.

Вызовите VideoDeviceController.SetMediaStreamPropertiesAsync для установки новых свойств кодирования. Перед установкой новых свойств используйте переменную-член для хранения исходных свойств кодирования, чтобы иметь возможность вернуть настройки при отключении эффекта.

Если эффект стабилизации должен обрезать выходящее видео, то рекомендуемые свойства кодирования выходящего потока будут обеспечивать размер обрезанного видео. Это означает, что выходящее разрешение будет соответствовать размеру обрезанного видео. Если не использовать рекомендованные свойства выходного потока, видео будет растянуто для соответствия исходному размеру выходного потока, что приведет к потере визуального качества.

Задайте свойство Video объекта MediaEncodingProfile. Перед установкой новых свойств используйте переменную-член для хранения исходных свойств кодирования, чтобы иметь возможность вернуть настройки при отключении эффекта.

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

Обработка отключения эффекта стабилизации видео

Система может автоматически отключать эффект стабилизации видео, если поток пикселей слишком высок и эффект не может с ним справиться либо работает медленно. В этом случае вызывается событие EnabledChanged. Экземпляр VideoStabilizationEffect в параметре sender показывает новое состояние эффекта: включен или выключен. VideoStabilizationEffectEnabledChangedEventArgs имеет значение VideoStabilizationEffectEnabledChangedReason, показывающее, по какой причине включен или выключен эффект. Обратите внимание, что это событие также вызывается при включении или выключении эффекта программным способом. В этом случае причина будет указана как Programmatic.

Как правило, это событие используется для того, чтобы настроить в пользовательском интерфейсе приложения отображение текущего состояния стабилизации видео.

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

Удаление эффекта стабилизации видео

Для удаления эффекта стабилизации видео вызовите RemoveEffectAsync, чтобы удалить эффект из видеоконвейера. Если значения переменных-членов, содержащих начальные свойства кодирования, не равны null, используйте их для восстановления свойств кодирования. Наконец удалите обработчик событий EnabledChanged и установите для эффекта значение 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;