Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
In diesem Artikel erfahren Sie, wie Sie die APIs im Namespace Windows.Media.Editing verwenden, um schnell Apps zu entwickeln, mit denen Benutzer Medienkompositionen aus Audio- und Videoquelldateien erstellen können. Features des Frameworks umfassen die Möglichkeit, mehrere Videoclips programmgesteuert zusammen anzufügen, Video- und Bildüberlagerungen hinzuzufügen, Hintergrundaudio hinzuzufügen und Audio- und Videoeffekte anzuwenden. Nach der Erstellung können Medienkompositionen für die Wiedergabe oder Freigabe in einer flachen Mediendatei gerendert werden. Kompositionen können jedoch auch auf den Datenträger serialisiert und deserialisiert werden, sodass der Benutzer Kompositionen laden und ändern kann, die sie zuvor erstellt haben. All diese Funktionen werden in einer benutzerfreundlichen Windows-Runtime Schnittstelle bereitgestellt, die die Menge und Komplexität des Codes erheblich reduziert, der zum Ausführen dieser Aufgaben im Vergleich zu den low-level Microsoft Media Foundation API erforderlich ist.
Erstellen einer neuen Medienkomposition
Die MediaComposition-Klasse ist der Container für alle Medienclips, aus denen die Komposition besteht, und ist für das Rendern der endgültigen Komposition, das Laden und Speichern von Kompositionen auf dem Datenträger verantwortlich und stellt einen Vorschaudatenstrom der Komposition bereit, damit der Benutzer sie auf der Benutzeroberfläche anzeigen kann. Um MediaComposition in Ihrer App zu verwenden, fügen Sie den Namespace Windows.Media.Editing sowie den Namespace Windows.Media.Core hinzu, der verwandte APIs bereitstellt, die Sie ebenfalls benötigen.
using Windows.Media.Editing;
using Windows.Media.Core;
using Windows.Media.Playback;
using System.Threading.Tasks;
Auf das MediaComposition-Objekt wird von mehreren Punkten im Code zugegriffen. In der Regel deklarieren Sie also eine Membervariable, in der sie gespeichert werden soll.
private MediaComposition composition = null!;
Der Konstruktor für MediaComposition akzeptiert keine Argumente.
composition = new MediaComposition();
Hinzufügen von Medienclips zu einer Komposition
Medienkompositionen enthalten in der Regel einen oder mehrere Videoclips. Sie können ein FileOpenPicker verwenden, damit der Benutzer eine Videodatei auswählen kann. Nachdem die Datei ausgewählt wurde, erstellen Sie ein neues MediaClip-Objekt, das den Videoclip enthalten soll, indem Sie MediaClip.CreateFromFileAsync aufrufen. Anschließend fügen Sie den Clip zur Clipsliste des MediaComposition-Objekts hinzu.
private async Task PickFileAndAddClip()
{
if (composition == null)
{
ShowErrorMessage("Create a composition before adding clips");
return;
}
var picker = new Windows.Storage.Pickers.FileOpenPicker();
WinRT.Interop.InitializeWithWindow.Initialize(picker, _hwnd);
picker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.VideosLibrary;
picker.FileTypeFilter.Add(".mp4");
Windows.Storage.StorageFile pickedFile = await picker.PickSingleFileAsync();
if (pickedFile == null)
{
ShowErrorMessage("File picking cancelled");
return;
}
var storageItemAccessList = Windows.Storage.AccessCache.StorageApplicationPermissions.FutureAccessList;
storageItemAccessList.Add(pickedFile);
var clip = await MediaClip.CreateFromFileAsync(pickedFile);
composition.Clips.Add(clip);
}
Medienclips werden in der MediaComposition in der gleichen Reihenfolge wie in der Liste "Clips " angezeigt.
Ein MediaClip kann nur einmal in eine Komposition aufgenommen werden. Wenn Sie versuchen, einen MediaClip hinzuzufügen, der bereits von der Komposition verwendet wird, tritt ein Fehler auf. Wenn Sie einen Videoclip mehrmals in einer Komposition wiederverwenden möchten, rufen Sie Clone auf, um neue MediaClip-Objekte zu erstellen, die dann der Komposition hinzugefügt werden können.
Eine MediaComposition unterstützt Videoclips im MP4-Format.
Wenn eine Videodatei mehrere eingebettete Audiospuren enthält, können Sie auswählen, welche Audiospur in der Komposition verwendet wird, indem Sie die SelectedEmbeddedAudioTrackIndex-Eigenschaft festlegen.
Erstellen Sie einen MediaClip mit einer einzelnen Farbe, die den gesamten Frame ausfüllt, indem Sie CreateFromColor aufrufen und eine Farbe und eine Dauer für den Clip angeben.
Erstellen Sie einen MediaClip aus einer Bilddatei, indem Sie CreateFromImageFileAsync aufrufen und eine Bilddatei und eine Dauer für den Clip angeben.
Erstellen eines MediaClip aus einem IDirect3DSurface durch Aufrufen von CreateFromSurface und Angeben einer Oberfläche und einer Dauer aus dem Clip.
Anzeigen einer Vorschau der Komposition in einem MediaPlayerElement
Damit der Benutzer die Medienkomposition anzeigen kann, fügen Sie der XAML-Datei, die Ihre Benutzeroberfläche definiert, ein MediaPlayerElement hinzu.
<MediaPlayerElement
x:Name="mediaPlayerElement"
AutoPlay="False"
AreTransportControlsEnabled="True"
HorizontalAlignment="Stretch"
MinHeight="360" />
Deklarieren Sie eine Membervariable vom Typ MediaStreamSource.
private MediaStreamSource mediaStreamSource = null!;
Rufen Sie die GeneratePreviewMediaStreamSource-Methode des MediaComposition-Objekts auf, um eine MediaStreamSource für die Komposition zu erstellen. Erstellen Sie ein MediaSource-Objekt, indem Sie die Factorymethode CreateFromMediaStreamSource aufrufen, und weisen Sie es der Source-Eigenschaft des MediaPlayerElement zu. Jetzt kann die Komposition auf der Benutzeroberfläche angezeigt werden.
public void UpdateMediaElementSource()
{
if (composition == null)
{
ShowErrorMessage("Create or open a composition first");
return;
}
mediaStreamSource = composition.GeneratePreviewMediaStreamSource(
(int)mediaPlayerElement.ActualWidth,
(int)mediaPlayerElement.ActualHeight);
mediaPlayerElement.Source = MediaSource.CreateFromMediaStreamSource(mediaStreamSource);
}
Die MediaComposition muss mindestens einen Medienclip enthalten, bevor Sie GeneratePreviewMediaStreamSource aufrufen, oder das zurückgegebene Objekt ist NULL.
Die MediaPlayerElement-Zeitachse wird nicht automatisch aktualisiert, um Änderungen in der Komposition widerzuspiegeln. Es wird empfohlen, sowohl GeneratePreviewMediaStreamSource aufzurufen als auch die MediaPlayerElementSource-Eigenschaft jedes Mal festzulegen, wenn Sie eine Reihe von Änderungen an der Komposition vornehmen und die Benutzeroberfläche aktualisieren möchten.
Es wird empfohlen, das MediaStreamSource-Objekt und die Source-Eigenschaft des MediaPlayerElements auf NULL festzulegen, wenn das Fenster geschlossen wird, um zugeordnete Ressourcen freizugeben.
private void OnWindowClosed(object sender, WindowEventArgs args)
{
mediaPlayerElement.Source = null;
mediaStreamSource = null!;
}
Rendern der Komposition in einer Videodatei
Um eine Medienkomposition in eine einfache Videodatei zu rendern, damit sie auf anderen Geräten geteilt und angezeigt werden kann, müssen Sie APIs aus dem Namespace Windows.Media.Transcoding verwenden.
using Windows.Media.Transcoding;
using Microsoft.UI.Dispatching;
Nachdem der Benutzer mit einem FileSavePicker eine Ausgabedatei ausgewählt hat, rendern Sie die Komposition in die ausgewählte Datei, indem Sie die Methode RenderToFileAsync des MediaComposition-Objekts aufrufen. Der rest des Codes im folgenden Beispiel folgt einfach dem Muster der Behandlung eines AsyncOperationWithProgress.
private async Task RenderCompositionToFile()
{
if (composition == null)
{
ShowErrorMessage("Create or open a composition first");
return;
}
var picker = new Windows.Storage.Pickers.FileSavePicker();
WinRT.Interop.InitializeWithWindow.Initialize(picker, _hwnd);
picker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.VideosLibrary;
picker.FileTypeChoices.Add("MP4 files", new List<string>() { ".mp4" });
picker.SuggestedFileName = "RenderedComposition.mp4";
Windows.Storage.StorageFile file = await picker.PickSaveFileAsync();
if (file != null)
{
var saveOperation = composition.RenderToFileAsync(file, MediaTrimmingPreference.Precise);
saveOperation.Progress = new AsyncOperationProgressHandler<TranscodeFailureReason, double>((info, progress) =>
{
_dispatcherQueue.TryEnqueue(() =>
{
ShowErrorMessage(string.Format("Saving file... Progress: {0:F0}%", progress));
});
});
saveOperation.Completed = new AsyncOperationWithProgressCompletedHandler<TranscodeFailureReason, double>((info, status) =>
{
_dispatcherQueue.TryEnqueue(() =>
{
try
{
var results = info.GetResults();
if (results != TranscodeFailureReason.None || status != AsyncStatus.Completed)
{
ShowErrorMessage("Saving was unsuccessful");
}
else
{
ShowErrorMessage("Composition saved to file");
}
}
finally
{
}
});
});
}
else
{
ShowErrorMessage("User cancelled the file selection");
}
}
- Mit dem MediaTrimmingPreference können Sie die Geschwindigkeit des Transcodierungsvorgangs im Vergleich zur Genauigkeit der Kürzung benachbarter Medienclips priorisieren. Schnell beschleunigt die Transcodierung, allerdings mit weniger präzisem Zuschneiden; Präzise verlangsamt die Transcodierung, ermöglicht dafür aber ein präziseres Zuschneiden.
Kürzen eines Videoclips
Kürzen Sie die Dauer eines Videoclips in einer Komposition, indem Sie den MediaClip Objekte TrimTimeFromStart-Eigenschaft festlegen, die eigenschaft TrimTimeFromEnd, oder beides.
private void TrimClipBeforeCurrentPosition()
{
if (composition == null || mediaPlayerElement.MediaPlayer == null)
{
ShowErrorMessage("Create or open a composition first");
return;
}
var currentClip = composition.Clips.FirstOrDefault(
mc => mc.StartTimeInComposition <= mediaPlayerElement.MediaPlayer.PlaybackSession.Position &&
mc.EndTimeInComposition >= mediaPlayerElement.MediaPlayer.PlaybackSession.Position);
if (currentClip == null)
{
ShowErrorMessage("No clip exists at the current playback position");
return;
}
TimeSpan positionFromStart = mediaPlayerElement.MediaPlayer.PlaybackSession.Position - currentClip.StartTimeInComposition;
currentClip.TrimTimeFromStart = positionFromStart;
}
- Sie können eine beliebige Benutzeroberfläche verwenden, mit der der Benutzer die Start- und Endkürzungswerte angeben kann. Im obigen Beispiel wird die Position-Eigenschaft der MediaPlaybackSession, die dem MediaPlayerElement zugeordnet ist, verwendet, um zunächst zu bestimmen, welcher MediaClip bei der aktuellen Position in der Komposition wiedergegeben wird, indem StartTimeInComposition und EndTimeInComposition überprüft werden. Anschließend werden die Eigenschaften Position und StartTimeInComposition erneut verwendet, um den Zeitraum zu berechnen, der am Anfang des Clips gekürzt werden soll. Die FirstOrDefault-Methode ist eine Erweiterungsmethode aus dem System.Linq-Namespace , die den Code zum Auswählen von Elementen aus einer Liste vereinfacht.
- Mit der OriginalDuration-Eigenschaft des MediaClip-Objekts können Sie die Dauer des Medienclips erkennen, ohne dass clipping angewendet wird.
- Die Eigenschaft TrimmedDuration gibt die Dauer des Medienclips an, nachdem das Zuschneiden angewendet wurde.
- Wenn Sie einen Kürzungswert angeben, der größer als die ursprüngliche Dauer des Clips ist, wird kein Fehler ausgelöst. Wenn eine Komposition jedoch nur einen einzelnen Clip enthält und durch Angeben eines großen Kürzungswerts auf null gekürzt wird, gibt ein anschließender Aufruf von GeneratePreviewMediaStreamSource null zurück, als ob die Komposition keine Clips enthält.
Hinzufügen einer Hintergrundaudiospur zu einer Komposition
Um einer Komposition einen Hintergrundtitel hinzuzufügen, laden Sie eine Audiodatei, und erstellen Sie dann eine BackgroundAudioTrackobjekt, indem Sie die Factorymethode BackgroundAudioTrack.CreateFromFileAsync aufrufen. Fügen Sie dann den BackgroundAudioTrack zur BackgroundAudioTracks-Eigenschaft der Komposition hinzu.
private async Task AddBackgroundAudioTrack()
{
if (composition == null)
{
ShowErrorMessage("Create or open a composition first");
return;
}
var picker = new Windows.Storage.Pickers.FileOpenPicker();
WinRT.Interop.InitializeWithWindow.Initialize(picker, _hwnd);
picker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.MusicLibrary;
picker.FileTypeFilter.Add(".mp3");
picker.FileTypeFilter.Add(".wav");
picker.FileTypeFilter.Add(".flac");
Windows.Storage.StorageFile audioFile = await picker.PickSingleFileAsync();
if (audioFile == null)
{
ShowErrorMessage("File picking cancelled");
return;
}
var storageItemAccessList = Windows.Storage.AccessCache.StorageApplicationPermissions.FutureAccessList;
storageItemAccessList.Add(audioFile);
var backgroundTrack = await BackgroundAudioTrack.CreateFromFileAsync(audioFile);
composition.BackgroundAudioTracks.Add(backgroundTrack);
}
Eine MediaComposition unterstützt Hintergrundaudiospuren in den folgenden Formaten: MP3, WAV, FLAC
Eine Hintergrundaudiospur
Wie bei MediaClip kann ein BackgroundAudioTrack nur einmal in eine Komposition aufgenommen werden. Wenn Sie versuchen, einen BackgroundAudioTrack hinzuzufügen, der bereits von der Komposition verwendet wird, tritt ein Fehler auf. Um eine Audiospur mehrmals in einer Komposition wiederzuverwenden, rufen Sie Clone auf, um neue BackgroundAudioTrack-Objekte zu erstellen, die dann der Komposition hinzugefügt werden können.
Standardmäßig werden Hintergrund-Audiospuren zu Beginn der Komposition wiedergegeben. Wenn mehrere Hintergrundspuren vorhanden sind, beginnen alle Spuren zu Beginn der Komposition mit der Wiedergabe. Damit eine Hintergrundaudiospur zu einem anderen Zeitpunkt mit der Wiedergabe beginnt, legen Sie die Delay-Eigenschaft auf den gewünschten Zeitversatz fest.
Hinzufügen einer Überlagerung zu einer Komposition
Überlagerungen ermöglichen es Ihnen, mehrere Videoebenen in einer Komposition übereinander zu stapeln. Eine Komposition kann mehrere Überlagerungsebenen enthalten, von denen jede mehrere Überlagerungen enthalten kann. Erstellen Sie ein MediaOverlayObjekt, indem Sie einen MediaClip an seinen Konstruktor übergeben. Legen Sie die Position und Deckkraft der Überlagerung fest, und erstellen Sie dann eine neue MediaOverlayLayer und fügen Sie das MediaOverlay ihrer Overlays-Liste hinzu. Fügen Sie schließlich die MediaOverlayLayer zur OverlayLayers-Liste der Komposition hinzu.
private void AddOverlay(MediaClip overlayMediaClip, double scale, double left, double top, double opacity)
{
if (composition == null)
{
ShowErrorMessage("Create or open a composition first");
return;
}
Windows.Media.MediaProperties.VideoEncodingProperties encodingProperties =
overlayMediaClip.GetVideoEncodingProperties();
Rect overlayPosition = new Rect();
overlayPosition.Width = (double)encodingProperties.Width * scale;
overlayPosition.Height = (double)encodingProperties.Height * scale;
overlayPosition.X = left;
overlayPosition.Y = top;
MediaOverlay mediaOverlay = new MediaOverlay(overlayMediaClip);
mediaOverlay.Position = overlayPosition;
mediaOverlay.Opacity = opacity;
MediaOverlayLayer mediaOverlayLayer = new MediaOverlayLayer();
mediaOverlayLayer.Overlays.Add(mediaOverlay);
composition.OverlayLayers.Add(mediaOverlayLayer);
}
Überlagerungen innerhalb einer Ebene werden entsprechend ihrer Reihenfolge in der Overlays-Liste der enthaltenden Ebene in der Z-Reihenfolge angeordnet. Höhere Indizes innerhalb der Liste werden über niedrigeren Indizes gerendert. Das gleiche gilt für Überlagerungsebenen innerhalb einer Komposition. Eine Ebene mit höherem Index in der OverlayLayers-Liste der Komposition wird oberhalb der Ebenen mit niedrigerem Index dargestellt.
Da Überlagerungen übereinander gestapelt werden, anstatt sequenziell wiedergegeben zu werden, beginnen alle Überlagerungen standardmäßig mit der Wiedergabe am Anfang der Komposition. Damit die Wiedergabe einer Überlagerung zu einem anderen Zeitpunkt beginnt, setzen Sie die Eigenschaft Delay auf den gewünschten Zeitversatz.
Hinzufügen von Effekten zu einem Medienclip
Jeder MediaClip in einer Komposition verfügt über eine Liste von Audio- und Videoeffekten, denen mehrere Effekte hinzugefügt werden können. Die Effekte müssen IAudioEffectDefinition und IVideoEffectDefinition implementieren. Im folgenden Beispiel wird die aktuelle Position des MediaPlayerElement verwendet, um den aktuell angezeigten MediaClip auszuwählen, dann eine neue Instanz von VideoStabilizationEffectDefinition zu erstellen und sie an die VideoEffectDefinitions-Liste des MediaClip anzufügen.
private void AddVideoEffect()
{
if (composition == null || mediaPlayerElement.MediaPlayer == null)
{
ShowErrorMessage("Create or open a composition first");
return;
}
var currentClip = composition.Clips.FirstOrDefault(
mc => mc.StartTimeInComposition <= mediaPlayerElement.MediaPlayer.PlaybackSession.Position &&
mc.EndTimeInComposition >= mediaPlayerElement.MediaPlayer.PlaybackSession.Position);
if (currentClip == null)
{
ShowErrorMessage("No clip exists at the current playback position");
return;
}
VideoStabilizationEffectDefinition videoEffect = new VideoStabilizationEffectDefinition();
currentClip.VideoEffectDefinitions.Add(videoEffect);
}
Speichern einer Komposition in einer Datei
Medienkompositionen können in eine Datei serialisiert werden, um sie zu einem späteren Zeitpunkt zu ändern. Wählen Sie eine Ausgabedatei aus, und rufen Sie dann die MediaCompositionMethode SaveAsync auf, um die Komposition zu speichern.
private async Task SaveComposition()
{
if (composition == null)
{
ShowErrorMessage("Create or open a composition first");
return;
}
var picker = new Windows.Storage.Pickers.FileSavePicker();
WinRT.Interop.InitializeWithWindow.Initialize(picker, _hwnd);
picker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.VideosLibrary;
picker.FileTypeChoices.Add("Composition files", new List<string>() { ".cmp" });
picker.SuggestedFileName = "SavedComposition";
Windows.Storage.StorageFile compositionFile = await picker.PickSaveFileAsync();
if (compositionFile == null)
{
ShowErrorMessage("User cancelled the file selection");
}
else
{
var action = composition.SaveAsync(compositionFile);
action.Completed = (info, status) =>
{
if (status != AsyncStatus.Completed)
{
_dispatcherQueue.TryEnqueue(() => ShowErrorMessage("Error saving composition"));
}
else
{
_dispatcherQueue.TryEnqueue(() => ShowErrorMessage("Composition saved"));
}
};
}
}
Laden einer Komposition aus einer Datei
Medienkompositionen können aus einer Datei deserialisiert werden, damit der Benutzer die Komposition anzeigen und ändern kann. Wählen Sie eine Kompositionsdatei aus, und rufen Sie dann die MediaCompositionMethode LoadAsync auf, um die Komposition zu laden.
private async Task OpenComposition()
{
var picker = new Windows.Storage.Pickers.FileOpenPicker();
WinRT.Interop.InitializeWithWindow.Initialize(picker, _hwnd);
picker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.VideosLibrary;
picker.FileTypeFilter.Add(".cmp");
Windows.Storage.StorageFile compositionFile = await picker.PickSingleFileAsync();
if (compositionFile == null)
{
ShowErrorMessage("File picking cancelled");
}
else
{
composition = null!;
composition = await MediaComposition.LoadAsync(compositionFile);
if (composition != null)
{
UpdateMediaElementSource();
}
else
{
ShowErrorMessage("Unable to open composition");
}
}
}
- Wenn sich eine Mediendatei in der Komposition nicht an einem Speicherort befindet, auf den Ihre App zugreifen kann, wird beim Laden der Komposition ein Fehler ausgelöst.
Siehe auch
Windows developer