Udostępnij za pośrednictwem


Efekty do przechwytywania wideo

W tym temacie pokazano, jak zastosować efekty do podglądu i nagrywania strumieni wideo z kamery oraz jak używać efektu stabilizacji wideo.

Notatka

Ten artykuł opiera się na pojęciach i kodzie omówionych w Podstawowe zdjęcia, wideo i przechwytywanie audio za pomocą programu MediaCapture, w którym opisano kroki implementowania podstawowych zdjęć i przechwytywania wideo. Zalecamy zapoznanie się z podstawowym wzorcem przechwytywania multimediów w tym artykule przed przejściem do bardziej zaawansowanych scenariuszy przechwytywania. W kodzie w tym artykule przyjęto założenie, że aplikacja ma już wystąpienie MediaCapture, które zostało prawidłowo zainicjowane.

Dodawanie i usuwanie efektów ze strumienia wideo aparatu

Aby przechwycić lub wyświetlić podgląd wideo z aparatu urządzenia, użyj klasy MediaCapture zgodnie z opisem w artykule Podstawowe przechwytywanie zdjęć, wideo i audio za pomocą MediaCapture. Po zainicjowaniu obiektu MediaCapture, do podglądu lub strumienia przechwytywania można dodać jeden lub więcej efektów wideo, wywołując AddVideoEffectAsync, przekazując IVideoEffectDefinition obiektu, które reprezentuje efekt do dodania, a członek wyliczenia MediaStreamType wskazujący, czy efekt powinien zostać dodany do strumienia podglądu aparatu, czy strumienia nagrywania.

Notatka

Na niektórych urządzeniach strumień podglądu i strumień przechwytywania są takie same, co oznacza, że jeśli określisz MediaStreamType.VideoPreview lub MediaStreamType.VideoRecord podczas wywoływania AddVideoEffectAsync, efekt zostanie zastosowany zarówno do strumieni podglądu, jak i rekordów. Możesz określić, czy strumienie podglądu i rekordów są takie same na bieżącym urządzeniu, sprawdzając właściwość VideoDeviceCharacteristicMediaCaptureSettings dla obiektu MediaCapture. Jeśli wartość tej właściwości jest VideoDeviceCharacteristic.AllStreamsIdentical lub VideoDeviceCharacteristic.PreviewRecordStreamsIdentical, strumienie są takie same i wszystkie zastosowane do nich efekty będą miały wpływ na drugą.

Poniższy przykład dodaje efekt zarówno do podglądu aparatu, jak i strumieni nagrywania. W tym przykładzie pokazano sprawdzanie, czy strumienie rekordu i podglądu są takie same.

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

Należy pamiętać, że AddVideoEffectAsync zwraca obiekt implementujący IMediaExtension, który reprezentuje dodany efekt wideo. Niektóre efekty umożliwiają zmianę ustawień efektu przez przekazanie PropertySet do metody SetProperties.

Począwszy od systemu Windows 10 w wersji 1607, można również skorzystać z obiektu zwróconego przez AddVideoEffectAsync, aby usunąć efekt z potoku wideo, przekazując go do RemoveEffectAsync. RemoveEffectAsync automatycznie określa, czy parametr obiektu efektu został dodany do strumienia podglądu lub rekordu, więc nie trzeba określać typu strumienia podczas wykonywania wywołania.

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

Możesz również usunąć wszystkie efekty ze strumienia podglądu lub przechwytywania, wywołując ClearEffectsAsync i określając strumień, dla którego wszystkie efekty powinny zostać usunięte.

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

Efekt stabilizacji wideo

Efekt stabilizacji wideo manipuluje ramkami strumienia wideo, aby zminimalizować drżenie spowodowane przez trzymanie urządzenia przechwytywania w ręku. Ponieważ ta technika powoduje przesunięcie pikseli w prawo, w lewo, w górę i w dół, a efekt nie może wiedzieć, jaka zawartość znajduje się poza ramką wideo, ustabilizowane wideo jest przycięte nieznacznie z oryginalnego wideo. Udostępniana jest funkcja narzędzia umożliwiająca dostosowanie ustawień kodowania wideo w celu optymalnego zarządzania przycinaniem wykonywanym przez efekt.

Na urządzeniach, które ją obsługują, optyczna stabilizacja obrazu (OIS) stabilizuje wideo poprzez mechaniczne manipulowanie urządzeniem rejestrującym i w związku z tym nie musi przycinać krawędzi ramek wideo. Aby uzyskać więcej informacji, zobacz Capture device controls for video capture.

Konfigurowanie aplikacji do korzystania ze stabilizacji wideo

Zadeklaruj zmienną składową do przechowywania obiektu VideoStabilizationEffect. W ramach implementacji efektu zmodyfikujesz właściwości kodowania używane do kodowania przechwyconego wideo. Zadeklaruj dwie zmienne do przechowywania kopii zapasowej właściwości początkowego kodowania danych wejściowych i wyjściowych, aby można je było przywrócić później po wyłączeniu efektu. Na koniec zadeklaruj zmienną składową typu MediaEncodingProfile, ponieważ ten obiekt będzie uzyskiwany z wielu lokalizacji w kodzie.

// 
private VideoStabilizationEffect m_videoStabilizationEffect;
private VideoEncodingProperties m_inputPropertiesBackup;
private VideoEncodingProperties m_outputPropertiesBackup;
private MediaEncodingProfile m_encodingProfile;

W tym scenariuszu należy przypisać obiekt profilu kodowania multimediów do zmiennej składowej, aby można było uzyskać do niej dostęp później.

m_encodingProfile = MediaEncodingProfile.CreateMp4(VideoEncodingQuality.Auto);

Inicjowanie efektu stabilizacji wideo

Po zainicjowaniu obiektu MediaCapture, utwórz nowe wystąpienie obiektu VideoStabilizationEffectDefinition. Wywołaj MediaCapture.AddVideoEffectAsync, aby dodać efekt do przepływu wideo oraz pobrać wystąpienie klasy VideoStabilizationEffect. Określ MediaStreamType.VideoRecord, aby wskazać, że efekt powinien zostać zastosowany do strumienia rekordów wideo.

Zarejestruj program obsługi zdarzeń dla zdarzenia EnabledChanged i wywołaj metodę pomocnika SetUpVideoStabilizationRecommendationAsync, z których oba zostały omówione w dalszej części tego artykułu. Na koniec ustaw właściwość Enabled efektu na true, aby aktywować efekt.

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

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

m_videoStabilizationEffect.EnabledChanged += VideoStabilizationEffect_EnabledChanged;

await SetUpVideoStabilizationRecommendationAsync();

m_videoStabilizationEffect.Enabled = true;

Jak wspomniano wcześniej w tym artykule, technika używana przez efekt stabilizacji wideo koniecznie powoduje, że ustabilizowane wideo zostaje nieznacznie przycięte z oryginalnego wideo. Zdefiniuj następującą funkcję pomocnika w kodzie, aby dostosować właściwości kodowania wideo, aby optymalnie obsłużyć to ograniczenie efektu. Ten krok nie jest wymagany w celu użycia efektu stabilizacji wideo, ale jeśli go nie wykonasz, wynikowe wideo będzie nieco powiększone i dlatego będzie miało nieco niższą jakość obrazu.

Wywołaj GetRecommendedStreamConfiguration na swoim wystąpieniu efektu stabilizacji wideo, przekazując obiekt VideoDeviceController, który informuje efekt o bieżących właściwościach kodowania strumienia wejściowego, oraz obiekt MediaEncodingProfile, co pozwala efektowi poznać bieżące właściwości kodowania danych wyjściowych. Ta metoda zwraca obiekt VideoStreamConfiguration zawierający nowe zalecane właściwości kodowania strumienia wejściowego i wyjściowego.

Zalecane właściwości kodowania wejściowego obejmują, jeśli urządzenie to obsługuje, zastosowanie wyższej rozdzielczości niż początkowe ustawienia, aby po zastosowaniu przycinania efektu minimalizować utratę rozdzielczości.

Wywołaj VideoDeviceController.SetMediaStreamPropertiesAsync, aby ustawić nowe właściwości kodowania. Przed ustawieniem nowych właściwości użyj zmiennej składowej do przechowywania początkowych właściwości kodowania, aby można było zmienić ustawienia z powrotem po wyłączeniu efektu.

Jeśli efekt stabilizacji wideo musi przycinać wynikowy obraz wideo, zalecane właściwości kodowania wyjściowego będą odpowiadać rozmiarowi przyciętego wideo. Oznacza to, że rozdzielczość danych wyjściowych będzie zgodna z przyciętym rozmiarem wideo. Jeśli nie używasz zalecanych właściwości wyjściowych, wideo zostanie przeskalowane w górę w celu dopasowania do początkowego rozmiaru danych wyjściowych, co spowoduje utratę wierności wizualnej.

Ustaw właściwość Video obiektu MediaEncodingProfile. Przed ustawieniem nowych właściwości użyj zmiennej składowej do przechowywania początkowych właściwości kodowania, aby można było zmienić ustawienia z powrotem po wyłączeniu efektu.

private async Task SetUpVideoStabilizationRecommendationAsync()
{

    // Get the recommendation from the effect based on our current input and output configuration
    var recommendation = m_videoStabilizationEffect.GetRecommendedStreamConfiguration(m_mediaCapture.VideoDeviceController, m_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
        m_inputPropertiesBackup = m_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 m_mediaCapture.VideoDeviceController.SetMediaStreamPropertiesAsync(MediaStreamType.VideoRecord, recommendation.InputProperties);
        await m_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
        m_outputPropertiesBackup = m_encodingProfile.Video;

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

Obsługa wyłączonego efektu stabilizacji wideo

System może automatycznie wyłączyć efekt stabilizacji wideo, jeśli przepływność pikseli jest zbyt wysoka, aby efekt obsłużył lub wykrył, że efekt działa powoli. W takim przypadku zostanie zgłoszone zdarzenie EnabledChanged. Instancja VideoStabilizationEffect w parametrze źródło wskazuje nowy stan efektu, czy jest on włączony czy wyłączony. VideoStabilizationEffectEnabledChangedEventArgs ma wartość VideoStabilizationEffectEnabledChangedReason, wskazującą, dlaczego efekt został włączony lub wyłączony. Należy pamiętać, że to zdarzenie jest również zgłaszane, jeśli programowo włączysz lub wyłączysz efekt, w takim przypadku przyczyną będzie Programmatic.

Zazwyczaj to zdarzenie służy do dostosowywania interfejsu użytkownika aplikacji w celu wskazania bieżącego stanu stabilizacji wideo.

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

Czyszczenie efektu stabilizacji wideo

Aby poprawić efekt stabilizacji wideo, wywołaj RemoveEffectAsync, aby usunąć efekt z potoku wideo. Jeśli zmienne składowe zawierające właściwości początkowego kodowania nie mają wartości null, użyj ich do przywrócenia właściwości kodowania. Na koniec usuń program obsługi zdarzeń EnabledChanged i ustaw efekt na wartość null.

// Clear all effects in the pipeline
await m_mediaCapture.RemoveEffectAsync(m_videoStabilizationEffect);

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

if (m_outputPropertiesBackup != null)
{
    m_encodingProfile.Video = m_outputPropertiesBackup;
    m_outputPropertiesBackup = null;
}

m_videoStabilizationEffect.EnabledChanged -= VideoStabilizationEffect_EnabledChanged;

m_videoStabilizationEffect = null;