Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Este artigo mostra como usar as APIs no Windows. Media.Editing namespace para desenvolver rapidamente aplicativos que permitem que os usuários criem composições de mídia a partir de arquivos de origem de áudio e vídeo. Os recursos da estrutura incluem a capacidade de acrescentar programaticamente vários clipes de vídeo, adicionar sobreposições de vídeo e imagem, adicionar áudio em segundo plano e aplicar efeitos de áudio e vídeo. Depois de criadas, as composições de mídia podem ser renderizadas em um arquivo de mídia simples para reprodução ou compartilhamento, mas as composições também podem ser serializadas e desserializadas do disco, permitindo que o usuário carregue e modifique composições criadas anteriormente. Toda essa funcionalidade é fornecida em uma interface de Windows Runtime fácil de usar que reduz drasticamente a quantidade e a complexidade do código necessários para executar essas tarefas em comparação com a API Microsoft Media Foundation de baixo nível.
Criar uma nova composição de mídia
A classe MediaComposition é o contêiner para todos os clipes de mídia que compõem a composição e é responsável por renderizar a composição final, carregar e salvar composições em disco e fornecer um fluxo de visualização da composição para que o usuário possa exibi-la na interface do usuário. Para usar MediaComposition em seu aplicativo, inclua o Windows. Media.Editing namespace, bem como o Windows. Media.Core namespace que fornece APIs relacionadas que você precisará.
using Windows.Media.Editing;
using Windows.Media.Core;
using Windows.Media.Playback;
using System.Threading.Tasks;
O objeto MediaComposition será acessado de vários pontos em seu código, portanto, normalmente, você declarará uma variável de membro na qual armazená-lo.
private MediaComposition composition = null!;
O construtor para MediaComposition não usa argumentos.
composition = new MediaComposition();
Adicionar clipes de mídia a uma composição
As composições de mídia normalmente contêm um ou mais clipes de vídeo. Você pode usar um FileOpenPicker para permitir que o usuário selecione um arquivo de vídeo. Depois que o arquivo tiver sido selecionado, crie um novo objeto MediaClip para conter o clipe de vídeo chamando MediaClip.CreateFromFileAsync. Em seguida, você adiciona o clipe à lista de Clipes do objeto 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);
}
Os clipes de mídia aparecem no MediaComposition na mesma ordem em que aparecem na lista Clipes .
Um MediaClip só pode ser incluído em uma composição uma vez. A tentativa de adicionar um MediaClip que já está sendo usado pela composição resultará em um erro. Para reutilizar um clipe de vídeo várias vezes em uma composição, chame Clone para criar novos objetos MediaClip que podem ser adicionados à composição.
Um MediaComposition dá suporte a clipes de vídeo no formato MP4.
Se um arquivo de vídeo contiver várias faixas de áudio inseridas, você poderá selecionar qual faixa de áudio é usada na composição definindo a propriedade SelectedEmbeddedAudioTrackIndex .
Crie um MediaClip com uma única cor preenchendo todo o quadro chamando CreateFromColor e especificando uma cor e uma duração para o clipe.
Crie um MediaClip de um arquivo de imagem chamando CreateFromImageFileAsync e especificando um arquivo de imagem e uma duração para o clipe.
Crie um MediaClip de um IDirect3DSurface chamando CreateFromSurface e especificando uma superfície e uma duração do clipe.
Visualizar a composição em um MediaPlayerElement
Para permitir que o usuário exiba a composição de mídia, adicione um MediaPlayerElement ao arquivo XAML que define sua interface do usuário.
<MediaPlayerElement
x:Name="mediaPlayerElement"
AutoPlay="False"
AreTransportControlsEnabled="True"
HorizontalAlignment="Stretch"
MinHeight="360" />
Declare uma variável membro do tipo MediaStreamSource.
private MediaStreamSource mediaStreamSource = null!;
Chame o método GeneratePreviewMediaStreamSource do objeto MediaComposition para criar um MediaStreamSource para a composição. Crie um objeto MediaSource chamando o método de fábrica CreateFromMediaStreamSource e atribua-o à propriedade Source da propriedade MediaPlayerElement. Agora, a composição pode ser exibida na interface do usuário.
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);
}
A MediaComposition deve conter pelo menos um clipe de mídia antes de chamar GeneratePreviewMediaStreamSource ou o objeto retornado será nulo.
A linha do tempo MediaPlayerElement não é atualizada automaticamente para refletir as alterações na composição. É recomendável que você chame GeneratePreviewMediaStreamSource e defina a propriedade MediaPlayerElementSource sempre que fizer um conjunto de alterações na composição e quiser atualizar a interface do usuário.
É recomendável que você defina o objeto MediaStreamSource e a propriedade Source do MediaPlayerElement como nulo quando a janela for fechada para liberar recursos associados.
private void OnWindowClosed(object sender, WindowEventArgs args)
{
mediaPlayerElement.Source = null;
mediaStreamSource = null!;
}
Renderizar a composição em um arquivo de vídeo
Para renderizar uma composição de mídia em um arquivo de vídeo simples para que ele possa ser compartilhado e exibido em outros dispositivos, você precisará usar APIs do Windows. Media.Transcoding namespace.
using Windows.Media.Transcoding;
using Microsoft.UI.Dispatching;
Depois de permitir que o usuário selecione um arquivo de saída com um FileSavePicker renderize a composição para o arquivo selecionado chamando o objeto MediaCompositionRenderToFileAsync. O restante do código no exemplo a seguir simplesmente segue o padrão de manipulação de um 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");
}
}
- O MediaTrimmingPreference permite priorizar a velocidade da operação de transcodificação versus a precisão do corte de clipes de mídia adjacentes. Rápido faz com que a transcodificação seja mais rápida com corte de precisão inferior, Precise faz com que a transcodificação seja mais lenta, mas com corte mais preciso.
Cortar um clipe de vídeo
Ajuste a duração de um clipe de vídeo em uma composição definindo a propriedade TrimTimeFromStart do objeto MediaClip, a propriedade TrimTimeFromEnd ou ambas.
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;
}
- Você pode usar qualquer interface do usuário que quiser para permitir que o usuário especifique os valores de corte inicial e final. O exemplo acima usa a propriedade Position da MediaPlaybackSession associada ao MediaPlayerElement para primeiro determinar qual MediaClip está sendo reproduzido na posição atual da composição, verificando as propriedades StartTimeInComposition e EndTimeInComposition. Em seguida, as propriedades Position e StartTimeInComposition são usadas novamente para calcular quanto tempo deve ser removido do início do clipe. O método FirstOrDefault é um método de extensão do namespace System.Linq que simplifica o código para selecionar itens de uma lista.
- A propriedade OriginalDuration do objeto MediaClip permite que você saiba a duração do clipe de mídia sem nenhum recorte aplicado.
- A propriedade TrimmedDuration permite que você saiba a duração do clipe de mídia após a aplicação do corte.
- Especificar um valor de corte maior que a duração original do clipe não gerará um erro. No entanto, se uma composição contiver apenas um único clipe e que é cortado para tamanho zero especificando um valor de corte grande, uma chamada subsequente para GeneratePreviewMediaStreamSource retornará nulo, como se a composição não tivesse clipes.
Adicionar uma faixa de áudio em segundo plano a uma composição
Para adicionar uma faixa de plano de fundo a uma composição, carregue um arquivo de áudio e crie um objeto BackgroundAudioTrack chamando o método de fábrica BackgroundAudioTrack.CreateFromFileAsync. Em seguida, adicione o BackgroundAudioTrack à propriedade BackgroundAudioTracks da composição.
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);
}
Um MediaComposition dá suporte a faixas de áudio em segundo plano nos seguintes formatos: MP3, WAV, FLAC
Uma faixa de áudio em segundo plano
Assim como no MediaClip, um BackgroundAudioTrack só pode ser incluído em uma composição uma vez. A tentativa de adicionar um BackgroundAudioTrack que já está sendo usado pela composição resultará em um erro. Para reutilizar uma faixa de áudio várias vezes em uma composição, chame Clone para criar novos objetos BackgroundAudioTrack que podem ser adicionados à composição.
Por padrão, as faixas de áudio em segundo plano começam a ser reproduzidas no início da composição. Se houver várias faixas de fundo, todas começarão a ser reproduzidas no início da composição. Para fazer com que uma faixa de áudio em segundo plano comece a ser reproduzida em outro momento, defina a propriedade Delay como o deslocamento de tempo desejado.
Adicionar uma sobreposição a uma composição
As sobreposições permitem que você empilhe várias camadas de vídeo em cima umas das outras em uma composição. Uma composição pode conter várias camadas de sobreposição, cada uma delas pode incluir várias sobreposições. Crie um objeto MediaOverlay passando um objeto MediaClip para seu construtor. Defina a posição e a opacidade da sobreposição, em seguida, crie um novo MediaOverlayLayer e adicione o MediaOverlay à sua lista Overlays. Por fim, adicione o MediaOverlayLayer à lista OverlayLayers da composição.
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);
}
As sobreposições dentro de uma camada são ordenadas por z com base em sua ordem na lista sobreposições da camada que contém. Os índices mais altos na lista são renderizados em cima de índices inferiores. O mesmo se aplica às camadas de sobreposição dentro de uma composição. Uma camada com índice mais alto na lista SobrelayLayers da composição será renderizada em cima de índices inferiores.
Como as sobreposições são empilhadas umas sobre as outras em vez de serem reproduzidas sequencialmente, todas as sobreposições iniciam a reprodução no início da composição por padrão. Para que uma sobreposição inicie a reprodução em outro momento, defina a propriedade Delay com o deslocamento de tempo desejado.
Adicionar efeitos a um clipe de mídia
Cada MediaClip em uma composição tem uma lista de efeitos de áudio e vídeo aos quais vários efeitos podem ser adicionados. Os efeitos devem implementar IAudioEffectDefinition e IVideoEffectDefinition respectivamente. O exemplo a seguir usa a posição atual do MediaPlayerElement para escolher o MediaClip atualmente visualizado e, em seguida, cria uma nova instância de VideoStabilizationEffectDefinition e a adiciona à lista VideoEffectDefinitions do clipe de mí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);
}
Salvar uma composição em um arquivo
As composições de mídia podem ser serializadas em um arquivo a ser modificado posteriormente. Escolha um arquivo de saída e chame o método MediaComposition método SaveAsync para salvar a composição.
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"));
}
};
}
}
Carregar uma composição de um arquivo
As composições de mídia podem ser desserializadas de um arquivo para permitir que o usuário exiba e modifique a composição. Escolha um arquivo de composição e chame o método MediaComposition método LoadAsync para carregar a composição.
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");
}
}
}
- Se um arquivo de mídia na composição não estiver em um local que possa ser acessado pelo seu aplicativo, um erro será gerado ao carregar a composição.
Consulte também
Windows developer