Поделиться через


Приведение мультимедиа

В этой статье показано, как привести носитель к удаленным устройствам из универсального приложения Для Windows.

Встроенная приведение мультимедиа с помощью MediaPlayerElement

Самый простой способ приведения мультимедиа из универсального приложения Windows — использовать встроенную возможность приведения элемента управления MediaPlayerElement .

Чтобы разрешить пользователю открывать видеофайл в элементе управления MediaPlayerElement , добавьте в проект следующие пространства имен.

using Windows.Storage;
using Windows.Storage.Pickers;
using Windows.Storage.Streams;
using Windows.Media.Core;

В XAML-файле приложения добавьте MediaPlayerElement и задайте значение True Для AreTransportControlsEnabled.

<MediaPlayerElement Name="mediaPlayerElement"  MinHeight="100" MaxWidth="600" HorizontalAlignment="Stretch" AreTransportControlsEnabled="True"/>

Добавьте кнопку, чтобы разрешить пользователю инициировать выбор файла.

<Button x:Name="openButton" Click="openButton_Click" Content="Open"/>

В обработчике событий Click для кнопки создайте новый экземпляр FileOpenPicker, добавьте типы видеофайлов в коллекцию FileTypeFilter и задайте начальное расположение библиотеки видео пользователя.

Вызовите pickSingleFileAsync , чтобы запустить диалоговое окно выбора файлов. При возврате этого метода результатом является объект StorageFile, представляющий видеофайл. Убедитесь, что файл не имеет значения NULL, что будет, если пользователь отменяет операцию выбора. Вызовите метод OpenAsync файла, чтобы получить IRandomAccessStream для файла. Наконец, создайте объект MediaSource из выбранного файла, вызвав CreateFromStorageFile и назначив его свойству Source объекта MediaPlayerElement, чтобы сделать видеофайл источником видео для элемента управления.

private async void openButton_Click(object sender, RoutedEventArgs e)
{
    //Create a new picker
    FileOpenPicker filePicker = new FileOpenPicker();

    //Add filetype filters.  In this case wmv and mp4.
    filePicker.FileTypeFilter.Add(".wmv");
    filePicker.FileTypeFilter.Add(".mp4");

    //Set picker start location to the video library
    filePicker.SuggestedStartLocation = PickerLocationId.VideosLibrary;

    //Retrieve file from picker
    StorageFile file = await filePicker.PickSingleFileAsync();

    //If we got a file, load it into the media lement
    if (file != null)
    {
        mediaPlayerElement.Source = MediaSource.CreateFromStorageFile(file);
        mediaPlayerElement.MediaPlayer.Play();
    }
}

После загрузки видео в MediaPlayerElement пользователь может просто нажать кнопку приведения на элементы управления транспортом, чтобы запустить встроенное диалоговое окно, позволяющее выбрать устройство, к которому будет приведение загруженного носителя.

Кнопка приведения мультимедиа

Примечание.

Начиная с Windows 10 версии 1607, рекомендуется использовать класс MediaPlayer для воспроизведения элементов мультимедиа. MediaPlayerElement — это упрощенный элемент управления XAML, используемый для отрисовки содержимого MediaPlayer на странице XAML. Элемент управления MediaElement продолжает поддерживаться для обратной совместимости. Дополнительные сведения об использовании MediaPlayer и MediaPlayerElement для воспроизведения содержимого мультимедиа см. в разделе "Воспроизведение звука и видео" с помощью MediaPlayer. Сведения об использовании MediaSource и связанных API для работы с содержимым мультимедиа см. в разделе "Элементы мультимедиа", списки воспроизведения и треки.

Приведение мультимедиа с помощью CastingDevicePicker

Второй способ приведения носителя к устройству — использовать CastingDevicePicker. Чтобы использовать этот класс, включите пространство имен Windows.Media.Casting в проект.

using Windows.Media.Casting;

Объявите переменную-член для объекта CastingDevicePicker .

CastingDevicePicker castingPicker;

При инициализации страницы создайте новый экземпляр средства выбора приведения и задайте для свойства Filter значение SupportVideo , чтобы указать, что устройства приведения, перечисленные в средстве выбора, должны поддерживать видео. Зарегистрируйте обработчик для события CastingDeviceSelected , который возникает при выборе устройства для приведения.

//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;

В XAML-файле добавьте кнопку, чтобы разрешить пользователю запускать средство выбора.

<Button x:Name="castPickerButton" Content="Cast Button" Click="castPickerButton_Click"/>

В обработчике событий Click для кнопки вызовите TransformToVisual, чтобы получить преобразование элемента пользовательского интерфейса относительно другого элемента. В этом примере преобразование — это позиция кнопки выбора приведения относительно визуального корня окна приложения. Вызовите метод Show объекта CastingDevicePicker, чтобы запустить диалоговое окно выбора приведения. Укажите расположение и размеры кнопки выбора приведения, чтобы система пролетела из кнопки, нажатой пользователем.

private void castPickerButton_Click(object sender, RoutedEventArgs e)
{
    //Retrieve the location of the casting button
    GeneralTransform transform = castPickerButton.TransformToVisual(Window.Current.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, castPickerButton.ActualWidth, castPickerButton.ActualHeight),
        Windows.UI.Popups.Placement.Above);
}

В обработчике событий CastingDeviceSelected вызовите метод CreateCastingConnection свойства SelectedCastingDevice события args, который представляет устройство приведения, выбранное пользователем. Регистрируйте обработчики для событий ErrorOccurred и StateChanged. Наконец, вызовите метод RequestStartCastingAsync, чтобы начать приведение, передав результат в метод GetAsCastingSource элемента управления MediaPlayerElement элемента управления MediaPlayer, чтобы указать, что приведение мультимедиа является содержимым MediaPlayer, связанного с MediaPlayerElement.

Примечание.

Подключение к приведение должно быть инициировано в потоке пользовательского интерфейса. Так как castingDeviceSelected не вызывается в потоке пользовательского интерфейса, необходимо поместить эти вызовы внутри вызова CoreDispatcher.RunAsync, что приводит к их вызову в потоке пользовательского интерфейса.

private async void CastingPicker_CastingDeviceSelected(CastingDevicePicker sender, CastingDeviceSelectedEventArgs args)
{
    //Casting must occur from the UI thread.  This dispatches the casting calls to the UI thread.
    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, 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());
    });
}

В обработчиках событий ErrorOccurred и StateChanged необходимо обновить пользовательский интерфейс, чтобы сообщить пользователю о текущем состоянии приведения. Эти события подробно рассматриваются в следующем разделе по созданию настраиваемого средства выбора устройств приведения.

private async void Connection_StateChanged(CastingConnection sender, object args)
{
    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
    {
        ShowMessageToUser("Casting Connection State Changed: " + sender.State);
    });
}

private async void Connection_ErrorOccurred(CastingConnection sender, CastingConnectionErrorOccurredEventArgs args)
{
    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
    {
        ShowMessageToUser("Casting Connection State Changed: " + sender.State);
    });
}

Приведение мультимедиа с помощью настраиваемого средства выбора устройств

В следующем разделе описывается, как создать собственный пользовательский интерфейс средства выбора устройств приведения, перечислив устройства приведения и инициируя подключение из кода.

Чтобы перечислить доступные устройства приведения, включите пространство имен Windows.Devices.Enumeration в проект.

using Windows.Devices.Enumeration;

Добавьте следующие элементы управления на страницу XAML для реализации удручаемого пользовательского интерфейса для этого примера:

<Button x:Name="startWatcherButton" Content="Watcher Button" Click="startWatcherButton_Click"/>
<ProgressRing x:Name="watcherProgressRing" IsActive="False"/>
<ListBox x:Name="castingDevicesListBox" MaxWidth="300" HorizontalAlignment="Left" SelectionChanged="castingDevicesListBox_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="disconnectButton" Content="Disconnect" Click="disconnectButton_Click" Visibility="Collapsed"/>

В коде позади объявите переменные-члены для DeviceWatcher и CastingConnection.

DeviceWatcher deviceWatcher;
CastingConnection castingConnection;

В обработчике click для startWatcherButton сначала обновите пользовательский интерфейс, отключив кнопку и активируя кольцо выполнения во время перечисления устройств. Снимите список устройств приведения.

Затем создайте наблюдатель за устройствами, вызвав DeviceInformation.CreateWatcher. Этот метод можно использовать для просмотра множества различных типов устройств. Укажите, что необходимо отслеживать устройства, поддерживающие приведение видео с помощью строки селектора устройств, возвращаемой CastingDevice.GetDeviceSelector.

Наконец, зарегистрируйте обработчики событий для событий Added, Removed, EnumerationCompleted и Stopped.

private void startWatcherButton_Click(object sender, RoutedEventArgs e)
{
    startWatcherButton.IsEnabled = false;
    watcherProgressRing.IsActive = true;

    castingDevicesListBox.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();
}

Событие "Добавлено " возникает при обнаружении нового устройства наблюдателем. В обработчике этого события создайте объект CastingDevice, вызвав CastingDevice.FromIdAsync и передав идентификатор обнаруженного устройства приведения, который содержится в объекте DeviceInformation, переданном обработчику.

Добавьте CastingDevice в литье устройства ListBox, чтобы пользователь смог выбрать его. Из-за элемента ItemTemplate , определенного в XAML, свойство FriendlyName будет использоваться в качестве текста элемента в поле списка. Так как этот обработчик событий не вызывается в потоке пользовательского интерфейса, необходимо обновить пользовательский интерфейс из вызова CoreDispatcher.RunAsync.

private async void DeviceWatcher_Added(DeviceWatcher sender, DeviceInformation args)
{
    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () =>
    {
        //Add each discovered device to our listbox
        CastingDevice addedDevice = await CastingDevice.FromIdAsync(args.Id);
        castingDevicesListBox.Items.Add(addedDevice);
    });
}

Событие "Удалено " возникает, когда наблюдатель обнаруживает, что устройство приведения больше не присутствует. Сравните свойство id объекта Added, переданного в обработчик, с идентификатором каждого добавленного в коллекции элементов списка. Если идентификатор совпадает, удалите этот объект из коллекции. Опять же, так как пользовательский интерфейс обновляется, этот вызов должен выполняться из вызова RunAsync .

private async void DeviceWatcher_Removed(DeviceWatcher sender, DeviceInformationUpdate args)
{
    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
    {
        foreach (CastingDevice currentDevice in castingDevicesListBox.Items)
        {
            if (currentDevice.Id == args.Id)
            {
                castingDevicesListBox.Items.Remove(currentDevice);
            }
        }
    });
}

Событие EnumerationCompleted возникает, когда наблюдатель завершит обнаружение устройств. В обработчике этого события обновите пользовательский интерфейс, чтобы пользователь знал, что перечисление устройств завершено и остановите наблюдатель за устройством, вызвав stop.

private async void DeviceWatcher_EnumerationCompleted(DeviceWatcher sender, object args)
{
    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
    {
        //If enumeration completes, update UI and transition watcher to the stopped state
        ShowMessageToUser("Watcher completed enumeration of devices");
        deviceWatcher.Stop();
    });
}

Событие "Остановлено" возникает, когда наблюдатель за устройством завершит остановку. В обработчике этого события остановите элемент управления ProgressRing и повторно зарегистрируеме startWatcherButton, чтобы пользователь смог перезапустить процесс перечисления устройств.

private async void DeviceWatcher_Stopped(DeviceWatcher sender, object args)
{
    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
    {
        //Update UX when the watcher stops
        startWatcherButton.IsEnabled = true;
        watcherProgressRing.IsActive = false;
    });
}

Когда пользователь выбирает один из устройств приведения из списка, вызывается событие SelectionChanged. В этом обработчике будет создано приведение и будет запущено приведение.

Во-первых, убедитесь, что наблюдатель за устройствами остановлен, чтобы перечисление устройств не влияло на приведение мультимедиа. Создайте подключение приведения путем вызова CreateCastingConnection в объекте CastingDevice, выбранном пользователем. Добавьте обработчики событий для событий StateChanged и ErrorOccurred.

Запустите приведение мультимедиа путем вызова RequestStartCastingAsync, передавая источник приведения, возвращенный путем вызова метода GetAsCastingSource метода MediaPlayer. Наконец, нажмите кнопку отключения, чтобы разрешить пользователю остановить приведение мультимедиа.

private async void castingDevicesListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    if (castingDevicesListBox.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)castingDevicesListBox.SelectedItem).CreateCastingConnection();

        //Register for events
        castingConnection.ErrorOccurred += Connection_ErrorOccurred;
        castingConnection.StateChanged += Connection_StateChanged;

        //Cast the loaded video to the selected casting device.
        await castingConnection.RequestStartCastingAsync(mediaPlayerElement.MediaPlayer.GetAsCastingSource());
        disconnectButton.Visibility = Visibility.Visible;
    }
}

В обработчике измененного состояния действие зависит от нового состояния подключения приведения:

  • Если состояние подключено или отрисовка, убедитесь, что элемент управления ProgressRing неактивен и кнопка отключения отображается.
  • Если состояние отключено, отмените выбор текущего устройства приведения в списке, неактивный элемент управления ProgressRing и скрытие кнопки отключения.
  • Если состояние подключено, сделайте элемент управления ProgressRing активным и скройте кнопку отключения.
  • Если состояние отключено, сделайте элемент управления ProgressRing активным и скройте кнопку отключения.
private async void Connection_StateChanged(CastingConnection sender, object args)
{
    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
    {
        //Update the UX based on the casting state
        if (sender.State == CastingConnectionState.Connected || sender.State == CastingConnectionState.Rendering)
        {
            disconnectButton.Visibility = Visibility.Visible;
            watcherProgressRing.IsActive = false;
        }
        else if (sender.State == CastingConnectionState.Disconnected)
        {
            disconnectButton.Visibility = Visibility.Collapsed;
            castingDevicesListBox.SelectedItem = null;
            watcherProgressRing.IsActive = false;
        }
        else if (sender.State == CastingConnectionState.Connecting)
        {
            disconnectButton.Visibility = Visibility.Collapsed;
            ShowMessageToUser("Connecting");
            watcherProgressRing.IsActive = true;
        }
        else
        {
            //Disconnecting is the remaining state
            disconnectButton.Visibility = Visibility.Collapsed;
            watcherProgressRing.IsActive = true;
        }
    });
}

В обработчике события ErrorOccurred обновите пользовательский интерфейс, чтобы сообщить пользователю, что произошла ошибка приведения и отмените выбор текущего объекта CastingDevice в списке.

private async void Connection_ErrorOccurred(CastingConnection sender, CastingConnectionErrorOccurredEventArgs args)
{
    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
    {
        //Clear the selection in the listbox on an error
        ShowMessageToUser("Casting Error: " + args.Message);
        castingDevicesListBox.SelectedItem = null;
    });
}

Наконец, реализуйте обработчик для кнопки отключения. Остановите приведение мультимедиа и отключите устройство приведения, вызвав метод DisconnectAsync объекта CastingConnection. Этот вызов необходимо отправить в поток пользовательского интерфейса, вызвав CoreDispatcher.RunAsync.

private async void disconnectButton_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();
    }
}