Remarque
L’accès à cette page requiert une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page requiert une autorisation. Vous pouvez essayer de modifier des répertoires.
Cet article explique comment utiliser les API dans le Windows. Media.Editing espace de noms pour développer rapidement des applications qui permettent aux utilisateurs de créer des compositions multimédias à partir de fichiers sources audio et vidéo. Les fonctionnalités de l’infrastructure incluent la possibilité d’ajouter par programmation plusieurs clips vidéo ensemble, d’ajouter des superpositions de vidéos et d’images, d’ajouter du son d’arrière-plan et d’appliquer des effets audio et vidéo. Une fois créées, les compositions multimédias peuvent être rendues dans un fichier multimédia plat pour la lecture ou le partage, mais les compositions peuvent également être sérialisées vers et désérialisées à partir du disque, ce qui permet à l’utilisateur de charger et de modifier des compositions créées précédemment. Toutes ces fonctionnalités sont fournies dans une interface de Windows Runtime facile à utiliser qui réduit considérablement la quantité et la complexité du code requises pour effectuer ces tâches par rapport à l’API Microsoft Media Foundation de bas niveau.
Créer une composition multimédia
La classe MediaComposition est le conteneur de tous les clips multimédias qui composent la composition et est responsable du rendu de la composition finale, du chargement et de l’enregistrement des compositions sur disque, et de la fourniture d’un flux d’aperçu de la composition afin que l’utilisateur puisse l’afficher dans l’interface utilisateur. Pour utiliser MediaComposition dans votre application, incluez l’espace de noms Windows.Media.Editing ainsi que l’espace de noms Windows.Media.Core, qui fournit les API associées dont vous aurez besoin.
using Windows.Media.Editing;
using Windows.Media.Core;
using Windows.Media.Playback;
using System.Threading.Tasks;
L’objet MediaComposition est accessible à partir de plusieurs points dans votre code. En règle générale, vous allez déclarer une variable membre dans laquelle la stocker.
private MediaComposition composition = null!;
Le constructeur de MediaComposition ne prend aucun argument.
composition = new MediaComposition();
Ajouter des clips multimédias à une composition
Les compositions multimédias contiennent généralement un ou plusieurs clips vidéo. Vous pouvez utiliser un FileOpenPicker pour permettre à l’utilisateur de sélectionner un fichier vidéo. Une fois le fichier sélectionné, créez un objet MediaClip pour contenir le clip vidéo en appelant MediaClip.CreateFromFileAsync. Ensuite, vous ajoutez le clip à la liste Clips de l’objet MediaComposition.
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);
}
Les clips multimédias apparaissent dans le MediaComposition dans le même ordre qu’ils apparaissent dans la liste Clips .
Un MediaClip ne peut être inclus qu’une seule fois dans une composition. Toute tentative d’ajout d’un MediaClip déjà utilisé par la composition entraîne une erreur. Pour réutiliser un clip vidéo plusieurs fois dans une composition, appelez Clone pour créer de nouveaux objets MediaClip qui peuvent ensuite être ajoutés à la composition.
Un MediaComposition prend en charge les clips vidéo au format MP4.
Si un fichier vidéo contient plusieurs pistes audio incorporées, vous pouvez sélectionner la piste audio utilisée dans la composition en définissant la propriété SelectedEmbeddedAudioTrackIndex .
Créez un MediaClip avec une couleur unique remplissant l’ensemble du cadre en appelant CreateFromColor et en spécifiant une couleur et une durée pour le clip.
Créez un MediaClip à partir d’un fichier image en appelant CreateFromImageFileAsync et en spécifiant un fichier image et une durée pour le clip.
Créer un MediaClip à partir d’une IDirect3DSurface en appelant CreateFromSurface et en spécifiant une surface et une durée pour le clip.
Afficher un aperçu de la composition dans un MediaPlayerElement
Pour permettre à l’utilisateur d’afficher la composition multimédia, ajoutez un MediaPlayerElement au fichier XAML qui définit votre interface utilisateur.
<MediaPlayerElement
x:Name="mediaPlayerElement"
AutoPlay="False"
AreTransportControlsEnabled="True"
HorizontalAlignment="Stretch"
MinHeight="360" />
Déclarez une variable membre de type MediaStreamSource.
private MediaStreamSource mediaStreamSource = null!;
Appelez la méthode GeneratePreviewMediaStreamSource de l’objet MediaComposition pour créer un MediaStreamSource pour la composition. Créez un objet MediaSource en appelant la méthode de fabrique CreateFromMediaStreamSource et affectez-le à la propriété Source de la propriété MediaPlayerElement. À présent, la composition peut être consultée dans l’interface utilisateur.
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);
}
MediaComposition doit contenir au moins un clip multimédia avant d’appeler GeneratePreviewMediaStreamSource, ou l’objet retourné est null.
La chronologie MediaPlayerElement n’est pas automatiquement mise à jour pour refléter les modifications de la composition. Nous vous recommandons d’appeler GeneratePreviewMediaStreamSource et de définir la propriété Source MediaPlayerElement chaque fois que vous apportez un ensemble de modifications à la composition et que vous souhaitez mettre à jour l’interface utilisateur.
Il est recommandé de définir l’objet MediaStreamSource et la propriété Source du MediaPlayerElement sur null lorsque la fenêtre est fermée afin de libérer les ressources associées.
private void OnWindowClosed(object sender, WindowEventArgs args)
{
mediaPlayerElement.Source = null;
mediaStreamSource = null!;
}
Afficher la composition dans un fichier vidéo
Pour effectuer le rendu d’une composition multimédia dans un fichier vidéo simple afin de pouvoir le partager et le visionner sur d’autres appareils, vous devrez utiliser les API de l’espace de noms Windows.Media.Transcoding.
using Windows.Media.Transcoding;
using Microsoft.UI.Dispatching;
Après avoir autorisé l'utilisateur à sélectionner un fichier de sortie avec un FileSavePicker, affiche la composition dans le fichier sélectionné en appelant le MediaComposition de l'objet RenderToFileAsync. Le reste du code de l’exemple suivant suit simplement le modèle de gestion d’un 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");
}
}
- Le MediaTrimmingPreference vous permet de hiérarchiser la vitesse de l’opération de transcodage par rapport à la précision du découpage des clips multimédias adjacents. Rapide accélère le transcodage avec un découpage moins précis, Précis ralentit le transcodage mais avec un découpage plus précis.
Découper un clip vidéo
Découpez la durée d’un clip vidéo dans une composition en définissant les objets MediaClipTrimTimeFromStart, propriété TrimTimeFromEnd, ou les deux.
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;
}
- Vous pouvez utiliser n’importe quelle interface utilisateur que vous souhaitez permettre à l’utilisateur de spécifier les valeurs de découpage de début et de fin. L’exemple ci-dessus utilise la propriété Position de la propriété MediaPlaybackSession associée au MediaPlayerElement pour déterminer d’abord quel MediaClip rejoue à la position actuelle dans la composition en vérifiant le StartTimeInComposition et EndTimeInComposition. Ensuite, les propriétés Position et StartTimeInComposition sont utilisées à nouveau pour calculer la durée à découper à partir du début du clip. La méthode FirstOrDefault est une méthode d’extension de l’espace de noms System.Linq qui simplifie le code de sélection d’éléments dans une liste.
- La propriété OriginalDuration de l’objet MediaClip vous permet de connaître la durée du clip multimédia sans aucune capture appliquée.
- La propriété TrimmedDuration vous indique la durée du clip multimédia après l’application du découpage.
- La spécification d’une valeur de découpage supérieure à la durée d’origine du clip ne génère pas d’erreur. Toutefois, si une composition ne contient qu’un seul clip et qui est rogné en longueur nulle en spécifiant une valeur de découpage volumineux, un appel ultérieur à GeneratePreviewMediaStreamSource retourne null, comme si la composition n’a pas de clips.
Ajouter une piste audio d’arrière-plan à une composition
Pour ajouter une piste d’arrière-plan à une composition, chargez un fichier audio, puis créez un objet BackgroundAudioTrack en appelant la méthode de fabrique BackgroundAudioTrack.CreateFromFileAsync. Ensuite, ajoutez BackgroundAudioTrack à la propriété BackgroundAudioTracks de la composition.
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);
}
Un MediaComposition prend en charge les pistes audio en arrière-plan dans les formats suivants : MP3, WAV, FLAC
Piste audio d’arrière-plan
Comme avec MediaClip, un BackgroundAudioTrack ne peut être inclus qu’une seule fois dans une composition. Toute tentative d’ajout d’un BackgroundAudioTrack déjà utilisé par la composition entraîne une erreur. Pour réutiliser une piste audio plusieurs fois dans une composition, appelez Clone pour créer des objets BackgroundAudioTrack qui peuvent ensuite être ajoutés à la composition.
Par défaut, les pistes audio de fond commencent à être lues au début de la composition. Si plusieurs pistes d’arrière-plan sont présentes, toutes les pistes commencent à jouer au début de la composition. Pour provoquer la lecture d’une piste audio en arrière-plan à un autre moment, définissez la propriété Delay sur le décalage horaire souhaité.
Ajouter une superposition à une composition
Les superpositions vous permettent d’empiler plusieurs couches de vidéo les unes sur les autres dans une composition. Une composition peut contenir plusieurs couches de superposition, chacune pouvant inclure plusieurs superpositions. Créez un objet MediaOverlay en passant un objet MediaClip dans son constructeur. Définir la position et l’opacité de la superposition, créez ensuite un MediaOverlayLayer et ajoutez la liste MediaOverlay à sa liste Overlays. Enfin, ajoutez MediaOverlayLayer à la liste OverlayLayers de la composition.
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);
}
Les superpositions au sein d’une couche sont classées par z en fonction de leur ordre dans la liste des superpositions de couche contenant. Les index supérieurs de la liste sont affichés en haut des index inférieurs. Il en va de même pour les couches de superposition au sein d’une composition. Une couche avec un index supérieur dans la liste OverlayLayers de la composition est affichée en haut des index inférieurs.
Étant donné que les superpositions sont empilées les unes sur les autres au lieu d’être lues séquentiellement, toutes les superpositions démarrent la lecture au début de la composition par défaut. Pour que l’incrustation démarre la lecture à un moment différent, définissez la propriété Delay sur la valeur de décalage temporel souhaitée.
Ajouter des effets à un clip multimédia
Chaque MediaClip d’une composition contient une liste d’effets audio et vidéo auxquels plusieurs effets peuvent être ajoutés. Les effets doivent implémenter IAudioEffectDefinition et IVideoEffectDefinition respectivement. L'exemple suivant utilise la position actuelle de MediaPlayerElement pour sélectionner le MediaClip actuellement affiché, puis crée une nouvelle instance de VideoStabilizationEffectDefinition et l'ajoute à la liste VideoEffectDefinitions du clip multimédia.
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);
}
Enregistrer une composition dans un fichier
Les compositions multimédias peuvent être sérialisées dans un fichier à modifier ultérieurement. Choisissez un fichier de sortie, puis appelez la méthode MediaComposition méthode SaveAsync pour enregistrer la composition.
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"));
}
};
}
}
Charger une composition à partir d’un fichier
Les compositions multimédias peuvent être désérialisées à partir d’un fichier pour permettre à l’utilisateur d’afficher et de modifier la composition. Choisissez un fichier de composition, puis appelez la méthode MediaComposition méthode LoadAsync pour charger la composition.
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");
}
}
}
- Si un fichier multimédia dans la composition n’est pas dans un emplacement accessible par votre application, une erreur est générée lors du chargement de la composition.
Voir aussi
Windows developer