影片擷取的效果

本主題說明如何將效果套用至相機預覽和錄製視訊串流,並示範如何使用影片防震效果。

注意

本文以使用 MediaCapture 進行基本相片、視訊和音訊的擷取中所討論的概念和程式碼為基礎,說明實作基本相片和視訊擷取的步驟。 我們建議您先熟悉該文章中的基本媒體擷取模式後,再繼續進行更進階的擷取案例。 本文中的程式碼假設您的應用程式已經有已正確初始化的 MediaCapture 執行個體。

從相機視訊串流新增和移除效果

若要從裝置的相機擷取或預覽視訊,請使用 MediaCapture 物件,如使用 MediaCapture 擷取基本相片、視訊和音訊所述。 初始化 MediaCapture 物件後,您可以透過呼叫 AddVideoEffectAsync,傳入表示要新增的效果的 IVideoEffectDefinition 物件,將一種或多種視訊效果新增至預覽或擷取串流中,以及 MediaStreamType 列舉的成員,指示是否應將效果新增至相機的預覽串流或記錄串流。

注意

在某些裝置上,預覽串流和擷取串流是相同的,這表示如果您在呼叫 AddVideoEffectAsync 時指定 MediaStreamType.VideoPreviewMediaStreamType.VideoRecord,效果將同時套用於預覽串流和記錄串流。 您可以透過檢查 MediaCapture 物件的 MediaCaptureSettingsVideoDeviceCharacteristic 屬性來確定目前裝置上的預覽串流和記錄串流是否相同。 如果此屬性的值是 VideoDeviceCharacteristic.AllStreamsIdenticalVideoDeviceCharacteristic.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 來設定新的編碼屬性。 在設定新屬性之前,請使用成員變數來儲存初始編碼屬性,以便在停用效果時將設定變更回去。

如果影片防震效果必須裁剪輸出視訊,建議的輸出編碼屬性會是裁剪的視訊大小。 這表示輸出解析度會符合裁剪的視訊大小。 如果您未使用建議的輸出屬性,影片將會相應增加以符合初始輸出大小,這會導致視覺逼真度遺失。

設定 MediaEncodingProfile 物件的 Video 屬性。 在設定新屬性之前,請使用成員變數來儲存初始編碼屬性,以便在停用效果時將設定變更回去。

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 執行個體會指示效果的新狀態 (啟用或停用)。 VideoStabilizationEffectEnabledChangedEventArgs 有一個 VideoStabilizationEffectEnabledChangedReason 值,指示啟用或停用該效果的原因。 請注意,如果您以程式設計方式啟用或停用該效果,也會引發此事件,在這種情況下,原因將是程式設計

一般而言,您會使用此事件來調整應用程式的 UI,以指出影片防震的目前狀態。

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;