Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
En este artículo se muestra cómo convertir elementos multimedia en dispositivos remotos desde una aplicación WinUI.
Conversión multimedia integrada con MediaPlayerElement
La manera más sencilla de convertir elementos multimedia desde una aplicación WinUI es usar la funcionalidad de conversión integrada del control MediaPlayerElement .
En el archivo XAML de la aplicación, agrega un objeto MediaPlayerElement y establece AreTransportControlsEnabled en true.
<MediaPlayerElement Name="mediaPlayerElement" MinHeight="100" MaxWidth="600" HorizontalAlignment="Stretch" AreTransportControlsEnabled="True"/>
Agregue un botón para permitir que el usuario inicie la selección de un archivo.
<Button x:Name="bOpenButton" Click="bOpenButton_Click" Content="Open"/>
En el controlador de eventos Click del botón, cree una nueva instancia de FileOpenPicker, agregue tipos de archivo de vídeo a la colección FileTypeFilter y establezca la ubicación inicial en la biblioteca de vídeos del usuario.
Llame a PickSingleFileAsync para iniciar el cuadro de diálogo del selector de archivos. Cuando este método devuelve, el resultado es un objeto StorageFile que representa el archivo de vídeo. Asegúrese de que el archivo no sea NULL, que será si el usuario cancela la operación de selección. Llame al método OpenAsync del archivo para obtener un IRandomAccessStream para el archivo. Por último, cree un nuevo objeto MediaSource desde el archivo seleccionado llamando a CreateFromStorageFile y asígnelo a la propiedad Source del objeto MediaPlayerElement para convertir el archivo de vídeo en el origen del vídeo para el control.
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();
}
}
Una vez cargado el vídeo en MediaPlayerElement, el usuario simplemente puede presionar el botón de conversión en los controles de transporte para iniciar un cuadro de diálogo integrado que les permita elegir un dispositivo al que se convertirá el medio cargado.
Conversión multimedia con CastingDevicePicker
Una segunda forma de convertir medios en un dispositivo es usar CastingDevicePicker. En primer lugar, declare una variable miembro para el objeto Windows.Media.CastingDevicePicker .
CastingDevicePicker castingPicker;
Cuando se inicialice la ventana, cree una nueva instancia del selector de conversión y establezca la propiedad Filter en SupportsVideo para indicar que los dispositivos de conversión enumerados por el selector deben admitir vídeo. Registre un controlador para el evento CastingDeviceSelected, que se genera cuando el usuario elige un dispositivo para la transmisión.
//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;
En el archivo XAML, agregue un botón para permitir al usuario iniciar el selector.
<Button x:Name="bCastPickerButton" Content="Cast Button" Click="bCastPickerButton_Click"/>
En el controlador de eventos Click del botón, llame a TransformToVisual para obtener la transformación de un elemento de interfaz de usuario en relación con otro elemento. En este ejemplo, la transformación es la posición del botón del selector de transmisión en relación con la raíz visual de la ventana de la aplicación. Llame al método Show del objeto CastingDevicePicker para iniciar el cuadro de diálogo del selector de dispositivos de transmisión. Especifique la ubicación y las dimensiones del botón de selección de transmisión para que el sistema pueda mostrar el cuadro de diálogo desde el botón que el usuario ha presionado.
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);
}
En el controlador de eventos CastingDeviceSelected , llame al método CreateCastingConnection de la propiedad SelectedCastingDevice de los argumentos del evento, que representa el dispositivo de conversión seleccionado por el usuario. Registre controladores para los eventos ErrorOccurred y StateChanged . Por último, llame a RequestStartCastingAsync para comenzar a transmitir, pasando el resultado al método GetAsCastingSource del objeto MediaPlayer del control MediaPlayerElement para especificar que el contenido multimedia que se va a transmitir es el contenido del MediaPlayer asociado al MediaPlayerElement.
Nota:
La conexión de transmisión debe iniciarse en el subproceso de la interfaz de usuario. Dado que no se llama a CastingDeviceSelected en el subproceso de la interfaz de usuario, debe realizar estas llamadas dentro de una llamada a DispatcherQueue.TryEnqueue que hace que se ejecuten en el subproceso de la interfaz de usuario.
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());
});
}
En los manejadores de eventos ErrorOccurred y StateChanged, debe actualizar la interfaz de usuario para informar al usuario del estado de transmisión actual. Estos eventos se describen en detalle en la siguiente sección sobre cómo crear un selector de dispositivos de conversión 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);
});
}
Transmisión de medios con un selector de dispositivos personalizado
En la sección siguiente se describe cómo crear su propia interfaz de usuario del selector de dispositivos de transmisión mediante la enumeración de los dispositivos de transmisión y la iniciación de la conexión desde su código.
Agregue los siguientes controles a la página XAML para implementar la interfaz de usuario rudimentaria para este ejemplo:
- Un botón para iniciar el monitor de dispositivos que busca dispositivos de conversión disponibles.
- Un control ProgressRing para indicar al usuario que la transformación de enumeración está en progreso.
- ListBox para enumerar los dispositivos de conversión detectados. Defina un ItemTemplate para el control para que podamos asignar los objetos de dispositivo de conversión directamente al control y seguir mostrando la propiedad FriendlyName .
- Botón para permitir que el usuario desconecte el dispositivo de conversión.
<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"/>
En el código subyacente, declare variables de miembro para DeviceWatcher y CastingConnection.
DeviceWatcher deviceWatcher;
CastingConnection castingConnection;
En el controlador Click del startWatcherButton, actualice primero la interfaz de usuario deshabilitando el botón y activando el anillo de progreso mientras la enumeración del dispositivo está en curso. Desactive el cuadro de lista de dispositivos de conversión.
A continuación, cree un monitor de dispositivo llamando a DeviceInformation.CreateWatcher. Este método se puede usar para observar muchos tipos diferentes de dispositivos. Especifique que desea ver los dispositivos que admiten la conversión de vídeo mediante la cadena del selector de dispositivos devuelta por CastingDevice.GetDeviceSelector.
Por último, registre controladores de eventos para los eventos Added, Removed, EnumerationCompleted y Stopped .
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();
}
El evento Added se activa cuando el monitor descubre un nuevo dispositivo. En el controlador de este evento, cree un nuevo objeto CastingDevice llamando a CastingDevice.FromIdAsync y pasando el identificador del dispositivo de conversión detectado, que se encuentra en el objeto DeviceInformation pasado al controlador.
Agregue el CastingDevice al ListBox de dispositivos de transmisión para que el usuario pueda seleccionarlo. Debido a la ItemTemplate definida en el XAML, la propiedad FriendlyName se usará como el texto del elemento en el cuadro de lista. Dado que no se llama a este controlador de eventos en el subproceso de la interfaz de usuario, debe actualizar la interfaz de usuario desde dentro de una llamada a 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);
});
}
El evento Removed se genera cuando el monitor detecta que un dispositivo de conversión ya no está presente. Compare la propiedad ID del objeto Added pasado al controlador con la ID de cada Added en la colección Items del list box. Si el identificador coincide, quite ese objeto de la colección. De nuevo, dado que la interfaz de usuario se está actualizando, esta llamada se debe realizar desde dentro de una llamada 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);
}
}
});
}
El evento EnumerationCompleted se genera cuando el vigilante ha terminado de detectar dispositivos. En el controlador de este evento, actualice la interfaz de usuario para que el usuario sepa que la enumeración del dispositivo se ha completado y detenga el monitor de dispositivos llamando a Stop.
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();
});
}
El evento Stopped se genera cuando el monitor de dispositivo ha terminado de detenerse. En el controlador de este evento, detenga el control ProgressRing y vuelva a habilitar startWatcherButton para que el usuario pueda reiniciar el proceso de enumeración del dispositivo.
private void DeviceWatcher_Stopped(DeviceWatcher sender, object args)
{
DispatcherQueue.TryEnqueue( () =>
{
//Update UX when the watcher stops
bStartWatcherButton.IsEnabled = true;
prWatcherProgressRing.IsActive = false;
});
}
Cuando el usuario selecciona uno de los dispositivos de conversión del cuadro de lista, se genera el evento SelectionChanged . En este controlador se creará la conexión de transmisión y se iniciará la transmisión.
En primer lugar, asegúrese de que el observador de dispositivos esté detenido para que la enumeración de dispositivos no interfiera con la transmisión de medios. Cree una conexión de transmisión llamando a CreateCastingConnection en el objeto CastingDevice seleccionado por el usuario. Agregue controladores de eventos para los eventos StateChanged y ErrorOccurred .
Inicie la conversión multimedia mediante una llamada a RequestStartCastingAsync y pase el origen de conversión devuelto llamando al método MediaPlayer GetAsCastingSource. Por último, haga que el botón de desconexión sea visible para permitir al usuario detener la conversión multimedia.
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;
}
}
En el controlador cambiado de estado, la acción que realice depende del nuevo estado de la conexión de conversión:
- Si el estado es Conectado o Representación, asegúrese de que el control ProgressRing esté inactivo y que el botón de desconexión esté visible.
- Si el estado está Desconectado, anule la selección del dispositivo de conversión actual en el cuadro de lista, haga que el control ProgressRing esté inactivo y oculte el botón de desconexión.
- Si el estado es Conectar, active el control ProgressRing y oculte el botón de desconexión.
- Si el estado es Disconnecting (Desconectar), active el control ProgressRing y oculte el botón de desconexión.
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;
}
});
}
En el controlador del evento ErrorOccurred , actualice la interfaz de usuario para informar al usuario de que se produjo un error de conversión y anule la selección del objeto CastingDevice actual en el cuadro de lista.
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 último, implemente el controlador para el botón de desconexión. Detenga la conversión multimedia y desconecte del dispositivo de conversión llamando al método DisconnectAsync del objeto CastingConnection. Esta llamada debe enviarse al subproceso de la interfaz de usuario llamando a 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();
}
}