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 converter mídia em dispositivos remotos de um aplicativo WinUI.
Transmissão de mídia integrada com MediaPlayerElement
A maneira mais simples de converter mídia de um aplicativo WinUI é usar a funcionalidade de conversão interna do controle MediaPlayerElement .
No arquivo XAML do aplicativo, adicione um MediaPlayerElement e defina AreTransportControlsEnabled como true.
<MediaPlayerElement Name="mediaPlayerElement" MinHeight="100" MaxWidth="600" HorizontalAlignment="Stretch" AreTransportControlsEnabled="True"/>
Adicione um botão para permitir que o usuário inicie a seleção de um arquivo.
<Button x:Name="bOpenButton" Click="bOpenButton_Click" Content="Open"/>
No manipulador de eventos Clique para o botão, crie uma nova instância do FileOpenPicker, adicione tipos de arquivo de vídeo à coleção FileTypeFilter e defina o local inicial para a biblioteca de vídeos do usuário.
Chame PickSingleFileAsync para iniciar a caixa de diálogo do seletor de arquivos. Quando esse método é retornado, o resultado é um objeto StorageFile que representa o arquivo de vídeo. Verifique se o arquivo não é nulo, o que será se o usuário cancelar a operação de seleção. Chame o método OpenAsync do arquivo para obter um IRandomAccessStream para o arquivo. Por fim, crie um novo objeto MediaSource do arquivo selecionado chamando CreateFromStorageFile e atribua-o à propriedade Source do objeto MediaPlayerElement para tornar o arquivo de vídeo a fonte de vídeo para o controle.
private async void bOpenButton_Click(object sender, RoutedEventArgs e)
{
//Create a new picker
var filePicker = new Microsoft.Windows.Storage.Pickers.FileOpenPicker(this.AppWindow.Id)
{
SuggestedStartLocation = PickerLocationId.VideosLibrary,
FileTypeFilter = { ".wmv", ".mp4", ".mkv" },
};
//Retrieve file from picker
var result = await filePicker.PickSingleFileAsync();
if (result is not null)
{
var storageFile = await Windows.Storage.StorageFile.GetFileFromPathAsync(result.Path);
mediaPlayerElement.Source = MediaSource.CreateFromStorageFile(storageFile);
mediaPlayerElement.MediaPlayer.Play();
}
}
Depois que o vídeo é carregado no MediaPlayerElement, o usuário pode simplesmente pressionar o botão de conversão nos controles de transporte para iniciar uma caixa de diálogo interna que permite que ele escolha um dispositivo para o qual a mídia carregada será convertida.
Transmissão de mídia com o CastingDevicePicker
Uma segunda maneira de converter mídia em um dispositivo é usar o CastingDevicePicker. Primeiro, declare uma variável de membro para o objeto Windows.Media.Casting.CastingDevicePicker .
CastingDevicePicker castingPicker;
Quando a janela for inicializada, crie uma nova instância do seletor de conversão e defina a propriedade Filter to SupportsVideo para indicar que os dispositivos de conversão listados pelo seletor devem dar suporte ao vídeo. Registre um manipulador para o evento CastingDeviceSelected, que é gerado quando o usuário escolhe um dispositivo para transmissão.
//Initialize our picker object
castingPicker = new CastingDevicePicker();
//Set the picker to filter to video capable casting devices
castingPicker.Filter.SupportsVideo = true;
//Hook up device selected event
castingPicker.CastingDeviceSelected += CastingPicker_CastingDeviceSelected;
No arquivo XAML, adicione um botão para permitir que o usuário inicie o seletor.
<Button x:Name="bCastPickerButton" Content="Cast Button" Click="bCastPickerButton_Click"/>
No manipulador de eventos Clique para o botão, chame TransformToVisual para obter a transformação de um elemento de interface do usuário em relação a outro elemento. Neste exemplo, a transformação é a posição do botão de seleção de transmissão em relação à raiz visual da janela do aplicativo. Chame o método Show do objeto CastingDevicePicker para abrir a caixa de diálogo do seletor de dispositivo para transmissão. Especifique o local e as dimensões do botão seletor de conversão para que o sistema possa fazer a caixa de diálogo voar para fora do botão que o usuário pressionou.
private void bCastPickerButton_Click(object sender, RoutedEventArgs e)
{
//Retrieve the location of the casting button
GeneralTransform transform = bCastPickerButton.TransformToVisual(this.Content as UIElement);
Point pt = transform.TransformPoint(new Point(0, 0));
//Show the picker above our casting button
castingPicker.Show(new Rect(pt.X, pt.Y, bCastPickerButton.ActualWidth, bCastPickerButton.ActualHeight),
Windows.UI.Popups.Placement.Above);
}
No manipulador de eventos CastingDeviceSelected, chame o método CreateCastingConnection da propriedade SelectedCastingDevice dos argumentos do evento, que representa o dispositivo de transmissão selecionado pelo usuário. Registre manipuladores para os eventos ErrorOccurred e StateChanged . Por fim, chame RequestStartCastingAsync para começar a transmitir, passando o resultado para o controle MediaPlayerElement do objeto MediaPlayer e do método GetAsCastingSource para especificar que a mídia a ser transmitida é o conteúdo do MediaPlayer associado ao MediaPlayerElement.
Observação
A conexão de transmissão deve ser iniciada na thread da interface do usuário. Como o CastingDeviceSelected não é chamado na linha de execução da interface do usuário, você deve colocar essas chamadas dentro de uma chamada para DispatcherQueue.TryEnqueue para que sejam executadas na linha de execução da interface do usuário.
private void CastingPicker_CastingDeviceSelected(CastingDevicePicker sender, CastingDeviceSelectedEventArgs args)
{
//Casting must occur from the UI thread. This dispatches the casting calls to the UI thread.
DispatcherQueue.TryEnqueue( async () =>
{
//Create a casting conneciton from our selected casting device
CastingConnection connection = args.SelectedCastingDevice.CreateCastingConnection();
//Hook up the casting events
connection.ErrorOccurred += Connection_ErrorOccurred;
connection.StateChanged += Connection_StateChanged;
//Cast the content loaded in the media element to the selected casting device
await connection.RequestStartCastingAsync(mediaPlayerElement.MediaPlayer.GetAsCastingSource());
});
}
Nos manipuladores de eventos ErrorOccurred e StateChanged, você deve atualizar a interface do usuário para informar o usuário sobre o status atual de transmissão. Esses eventos são discutidos detalhadamente na seção a seguir sobre como criar um seletor de dispositivo de conversão personalizado.
private void Connection_StateChanged(CastingConnection sender, object args)
{
DispatcherQueue.TryEnqueue( () =>
{
ShowMessageToUser("Casting Connection State Changed: " + sender.State);
});
}
private void Connection_ErrorOccurred(CastingConnection sender, CastingConnectionErrorOccurredEventArgs args)
{
DispatcherQueue.TryEnqueue(() =>
{
ShowMessageToUser("Casting Connection State Changed: " + sender.State);
});
}
Transmissão de mídia com um seletor de dispositivos personalizado
A seção a seguir descreve como criar sua própria interface do usuário do seletor de dispositivos de transmissão enumerando os dispositivos de transmissão e iniciando a conexão a partir do seu código.
Adicione os seguintes controles à página XAML para implementar a interface do usuário rudimentar para este exemplo:
- Um botão para iniciar o observador de dispositivos que procura dispositivos de conversão disponíveis.
- Um controle ProgressRing para fornecer retorno ao usuário de que a enumeração de transmissão está em andamento.
- Um ListBox para listar os dispositivos de conversão descobertos. Defina um ItemTemplate para o controle para que possamos atribuir os objetos de dispositivo de conversão diretamente ao controle e ainda exibir a propriedade FriendlyName .
- Um botão para permitir que o usuário desconecte o dispositivo de conversão.
<Button x:Name="bStartWatcherButton" Content="Watcher Button" Click="bStartWatcherButton_Click"/>
<ProgressRing x:Name="prWatcherProgressRing" IsActive="False"/>
<ListBox x:Name="lbCastingDevicesListBox" MaxWidth="300" HorizontalAlignment="Left" SelectionChanged="lbCastingDevicesListBox_SelectionChanged">
<!--Listbox content is bound to the FriendlyName field of our casting devices-->
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=FriendlyName}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button x:Name="bDisconnectButton" Content="Disconnect" Click="bDisconnectButton_Click" Visibility="Collapsed"/>
Em seu código subjacente, declare variáveis de membro para o DeviceWatcher e o CastingConnection.
DeviceWatcher deviceWatcher;
CastingConnection castingConnection;
No manipulador clique do startWatcherButton, primeiro atualize a interface do usuário desabilitando o botão e tornando o anel de progresso ativo enquanto a enumeração do dispositivo está em andamento. Desmarque a caixa de listagem de dispositivos de conversão.
Em seguida, crie um observador de dispositivo chamando DeviceInformation.CreateWatcher. Esse método pode ser usado para observar muitos tipos diferentes de dispositivos. Especifique que você deseja observar dispositivos que dão suporte à conversão de vídeo usando a cadeia de caracteres do seletor de dispositivo retornada por CastingDevice.GetDeviceSelector.
Por fim, registre manipuladores de eventos para os eventos Adicionados, Removidos, EnumerationCompleted e Parados .
private void bStartWatcherButton_Click(object sender, RoutedEventArgs e)
{
bStartWatcherButton.IsEnabled = false;
prWatcherProgressRing.IsActive = true;
lbCastingDevicesListBox.Items.Clear();
//Create our watcher and have it find casting devices capable of video casting
deviceWatcher = DeviceInformation.CreateWatcher(CastingDevice.GetDeviceSelector(CastingPlaybackTypes.Video));
//Register for watcher events
deviceWatcher.Added += DeviceWatcher_Added; ;
deviceWatcher.Removed += DeviceWatcher_Removed; ;
deviceWatcher.EnumerationCompleted += DeviceWatcher_EnumerationCompleted; ;
deviceWatcher.Stopped += DeviceWatcher_Stopped; ;
//Start the watcher
deviceWatcher.Start();
}
O evento Adicionado é gerado quando um novo dispositivo é descoberto pelo observador. No manipulador desse evento, crie um novo objeto CastingDevice chamando CastingDevice.FromIdAsync e passando a ID do dispositivo de conversão descoberto, que está contido no objeto DeviceInformation passado para o manipulador.
Adicione o CastingDevice ao ListBox de dispositivos de transmissão para que o usuário possa selecioná-lo. Devido ao ItemTemplate definido no XAML, a propriedade FriendlyName será usada como o texto do item na caixa de listagem. Como este manipulador de eventos não é chamado na thread da interface do usuário, você deve atualizar a interface do usuário a partir de uma chamada para DispatcherQueue.TryEnqueue.
private void DeviceWatcher_Added(DeviceWatcher sender, DeviceInformation args)
{
DispatcherQueue.TryEnqueue(async () =>
{
//Add each discovered device to our listbox
CastingDevice addedDevice = await CastingDevice.FromIdAsync(args.Id);
lbCastingDevicesListBox.Items.Add(addedDevice);
});
}
O evento Removido é gerado quando o observador detecta que um dispositivo de conversão não está mais presente. Compare a propriedade ID do objeto Adicionado passada para o manipulador com a ID de cada Adicionado na coleção Items da caixa de listagem. Se a ID corresponder, remova esse objeto da coleção. Novamente, como a interface do usuário está sendo atualizada, essa chamada deve ser feita de dentro de uma chamada RunAsync .
private void DeviceWatcher_Removed(DeviceWatcher sender, DeviceInformationUpdate args)
{
DispatcherQueue.TryEnqueue( () =>
{
foreach (CastingDevice currentDevice in lbCastingDevicesListBox.Items)
{
if (currentDevice.Id == args.Id)
{
lbCastingDevicesListBox.Items.Remove(currentDevice);
}
}
});
}
O evento EnumerationCompleted é gerado quando o observador termina de detectar dispositivos. No manipulador desse evento, atualize a interface do usuário para que o usuário saiba que a enumeração do dispositivo foi concluída e interrompa o observador de dispositivo chamando Parar.
private void DeviceWatcher_EnumerationCompleted(DeviceWatcher sender, object args)
{
DispatcherQueue.TryEnqueue(() =>
{
//If enumeration completes, update UI and transition watcher to the stopped state
ShowMessageToUser("Watcher completed enumeration of devices");
deviceWatcher.Stop();
});
}
O evento Parado é gerado quando o observador de dispositivos termina de parar. No manipulador desse evento, interrompa o controle ProgressRing e reinicie o startWatcherButton para que o usuário possa reiniciar o processo de enumeração do dispositivo.
private void DeviceWatcher_Stopped(DeviceWatcher sender, object args)
{
DispatcherQueue.TryEnqueue( () =>
{
//Update UX when the watcher stops
bStartWatcherButton.IsEnabled = true;
prWatcherProgressRing.IsActive = false;
});
}
Quando o usuário seleciona um dos dispositivos de conversão na caixa de listagem, o evento SelectionChanged é acionado. É nesse handler que a conexão de transmissão será criada e a transmissão será iniciada.
Primeiro, verifique se o observador de dispositivo está parado para que a enumeração do dispositivo não interfira na conversão de mídia. Crie uma conexão de transmissão chamando CreateCastingConnection no objeto CastingDevice selecionado pelo usuário. Adicione manipuladores de eventos para os eventos StateChanged e ErrorOccurred .
Inicie a conversão de mídia chamando RequestStartCastingAsync, passando a fonte de conversão retornada chamando o método MediaPlayerGetAsCastingSource. Por fim, torne o botão de desconexão visível para permitir que o usuário interrompa a transmissão de mídia.
private async void lbCastingDevicesListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (lbCastingDevicesListBox.SelectedItem != null)
{
//When a device is selected, first thing we do is stop the watcher so it's search doesn't conflict with streaming
if (deviceWatcher.Status != DeviceWatcherStatus.Stopped)
{
deviceWatcher.Stop();
}
//Create a new casting connection to the device that's been selected
castingConnection = ((CastingDevice)lbCastingDevicesListBox.SelectedItem).CreateCastingConnection();
//Register for events
castingConnection.ErrorOccurred += CastingConnection_ErrorOccurred; ;
castingConnection.StateChanged += CastingConnection_StateChanged; ;
//Cast the loaded video to the selected casting device.
await castingConnection.RequestStartCastingAsync(mediaPlayerElement.MediaPlayer.GetAsCastingSource());
bDisconnectButton.Visibility = Visibility.Visible;
}
}
No manipulador de estado alterado, a ação que você toma depende do novo estado da conexão de transmissão.
- Se o estado estiver Conectado ou Renderizando, verifique se o controle ProgressRing está inativo e se o botão de desconexão está visível.
- Se o estado estiver Desconectado, desmarque o dispositivo de conversão atual na caixa de listagem, torne o controle ProgressRing inativo e oculte o botão desconectar.
- Se o estado estiver se conectando, ative o controle ProgressRing e oculte o botão de desconexão.
- Se o estado estiver desconectando, torne o controle ProgressRing ativo e oculte o botão desconectar.
private void CastingConnection_StateChanged(CastingConnection sender, object args)
{
DispatcherQueue.TryEnqueue( () =>
{
//Update the UX based on the casting state
if (sender.State == CastingConnectionState.Connected || sender.State == CastingConnectionState.Rendering)
{
bDisconnectButton.Visibility = Visibility.Visible;
prWatcherProgressRing.IsActive = false;
}
else if (sender.State == CastingConnectionState.Disconnected)
{
bDisconnectButton.Visibility = Visibility.Collapsed;
lbCastingDevicesListBox.SelectedItem = null;
prWatcherProgressRing.IsActive = false;
}
else if (sender.State == CastingConnectionState.Connecting)
{
bDisconnectButton.Visibility = Visibility.Collapsed;
ShowMessageToUser("Connecting");
prWatcherProgressRing.IsActive = true;
}
else
{
//Disconnecting is the remaining state
bDisconnectButton.Visibility = Visibility.Collapsed;
prWatcherProgressRing.IsActive = true;
}
});
}
No manipulador do evento ErrorOccurred , atualize a interface do usuário para informar ao usuário que ocorreu um erro de conversão e desmarque o objeto CastingDevice atual na caixa de listagem.
private void CastingConnection_ErrorOccurred(CastingConnection sender, CastingConnectionErrorOccurredEventArgs args)
{
DispatcherQueue.TryEnqueue( () =>
{
//Clear the selection in the listbox on an error
ShowMessageToUser("Casting Error: " + args.Message);
lbCastingDevicesListBox.SelectedItem = null;
});
}
Por fim, implemente o manipulador para o botão desconectar. Interrompa a conversão de mídia e desconecte-se do dispositivo de conversão chamando o método DisconnectAsync do objeto CastingConnection. Essa chamada deve ser enviada para o thread da interface do usuário chamando DispatcherQueue.TryEnqueue.
private async void bDisconnectButton_Click(object sender, RoutedEventArgs e)
{
if (castingConnection != null)
{
//When disconnect is clicked, the casting conneciton is disconnected. The video should return locally to the media element.
await castingConnection.DisconnectAsync();
}
}
Windows developer