Adaptives Streaming

In diesem Artikel wird beschrieben, wie Sie die Wiedergabe von adaptiven Streaming-Multimedia-Inhalten zu einer Universal Windows Platform (UWP)-Anwendung hinzufügen. Diese Funktion unterstützt die Wiedergabe von Http Live Streaming (HLS) und Dynamic Streaming over HTTP (DASH).

Ab Windows 10, Version 1803, wird Smooth Streaming von AdaptiveMediaSource unterstützt. Beachten Sie, dass für Smooth Streaming nur die Codecs H264 und WVC1 unterstützt werden. Für andere Manifesttypen gilt diese Einschränkung nicht.

Eine Liste der unterstützten HLS-Protokoll-Tags finden Sie unter HLS-Tag-Unterstützung.

Eine Liste der unterstützten DASH-Profile finden Sie unter DASH-Profilunterstützung.

Hinweis

Der Code in diesem Artikel wurde aus dem UWP Adaptive Streaming-Beispiel übernommen.

Einfaches adaptives Streaming mit MediaPlayer und MediaPlayerElement

Um adaptive Streaming-Medien in einer UWP-Anwendung wiederzugeben, erstellen Sie ein Uri-Objekt, das auf eine DASH- oder HLS-Manifestdatei verweist. Erstellen Sie eine Instanz der Klasse MediaPlayer. Rufen Sie MediaSource.CreateFromUri auf, um ein neues MediaSource-Objekt zu erstellen, und setzen Sie dieses auf die Source Eigenschaft des MediaPlayer. Rufen Sie Play auf, um die Wiedergabe der Medieninhalte zu starten.

MediaPlayer _mediaPlayer;
System.Uri manifestUri = new Uri("http://amssamples.streaming.mediaservices.windows.net/49b57c87-f5f3-48b3-ba22-c55cfdffa9cb/Sintel.ism/manifest(format=m3u8-aapl)");
_mediaPlayer = new MediaPlayer();
_mediaPlayer.Source = MediaSource.CreateFromUri(manifestUri);
_mediaPlayer.Play();

Das obige Beispiel spielt den Ton des Medieninhalts ab, rendert den Inhalt aber nicht automatisch in Ihrer Benutzeroberfläche. Die meisten Anwendungen, die Videoinhalte wiedergeben, wollen den Inhalt in einer XAML-Seite rendern. Fügen Sie dazu ein MediaPlayerElement Steuerelement zu Ihrer XAML-Seite hinzu.

<MediaPlayerElement x:Name="mediaPlayerElement" HorizontalAlignment="Stretch" AreTransportControlsEnabled="True"/>

Rufen Sie MediaSource.CreateFromUri auf, um eine MediaSource aus dem URI einer DASH- oder HLS-Manifestdatei zu erstellen. Legen Sie dann die Eigenschaft Source des MediaPlayerElements fest. Das MediaPlayerElement wird automatisch ein neues MediaPlayer-Objekt für den Inhalt erstellen. Sie können Play auf dem MediaPlayer aufrufen, um die Wiedergabe des Inhalts zu starten.

System.Uri manifestUri = new Uri("http://amssamples.streaming.mediaservices.windows.net/49b57c87-f5f3-48b3-ba22-c55cfdffa9cb/Sintel.ism/manifest(format=m3u8-aapl)");
mediaPlayerElement.Source = MediaSource.CreateFromUri(manifestUri);
mediaPlayerElement.MediaPlayer.Play();

Hinweis

Ab Windows 10, Version 1607, wird die Verwendung der MediaPlayer-Klasse zum Wiedergeben von Medienelementen empfohlen. MediaPlayerElement ist ein einfaches XAML-Steuerelement, das zum Rendern des Inhalts eines MediaPlayer-Objekts auf einer XAML-Seite verwendet wird. Das MediaElement-Steuerelement wird aus Gründen der Abwärtskompatibilität weiterhin unterstützt. Weitere Informationen zur Verwendung von MediaPlayer und MediaPlayerElement zur Wiedergabe von Medieninhalten finden Sie unter Wiedergabe von Audio und Video mit MediaPlayer. Informationen zur Verwendung von MediaSource und zugehörigen APIs für die Arbeit mit Medieninhalten finden Sie unter Medienelemente, Wiedergabelisten und Titel.

Adaptives Streaming mit AdaptiveMediaSource

Wenn Ihre Anwendung erweiterte adaptive Streaming-Funktionen benötigt, z. B. die Bereitstellung benutzerdefinierter HTTP-Header, die Überwachung der aktuellen Download- und Wiedergabe-Bitraten oder die Anpassung der Verhältnisse, die bestimmen, wann das System die Bitraten des adaptiven Streams umschaltet, verwenden Sie das Objekt AdaptiveMediaSource.

Die APIs für adaptives Streaming befinden sich im Namespace Windows.Media.Streaming.Adaptive. Die Beispiele in diesem Artikel verwenden APIs aus den folgenden Namespaces.

using Windows.Media.Streaming.Adaptive;
using System.Threading.Tasks;
using Windows.Storage.Streams;
using Windows.Media.Playback;
using Windows.Media.Core;

Initialisieren einer AdaptiveMediaSource aus einem URI.

Initialisieren Sie die AdaptiveMediaSource mit dem URI einer adaptiven Streaming-Manifestdatei durch Aufruf von CreateFromUriAsync. Der von dieser Methode zurückgegebene Wert AdaptiveMediaSourceCreationStatus gibt Auskunft darüber, ob die Medienquelle erfolgreich erstellt wurde. Wenn dies der Fall ist, können Sie das Objekt als Streamquelle für Ihren MediaPlayer festlegen, indem Sie ein MediaSource -Objekt erstellen, indem Sie MediaSource.CreateFromAdaptiveMediaSource aufrufen, und es dann der Source-Eigenschaft des MediaPlayers zuweisen. In diesem Beispiel wird die Eigenschaft AvailableBitrates abgefragt, um die maximal unterstützte Bitrate für diesen Stream zu ermitteln, und dieser Wert wird dann als Anfangsbitrate festgelegt. In diesem Beispiel werden auch Handler für die verschiedenen AdaptiveMediaSource Ereignisse registriert, die später in diesem Artikel besprochen werden.

async private void InitializeAdaptiveMediaSource(System.Uri uri)
{
    AdaptiveMediaSourceCreationResult result = await AdaptiveMediaSource.CreateFromUriAsync(uri);

    if (result.Status == AdaptiveMediaSourceCreationStatus.Success)
    {
        ams = result.MediaSource;
        mediaPlayerElement.SetMediaPlayer(new MediaPlayer());
        mediaPlayerElement.MediaPlayer.Source = MediaSource.CreateFromAdaptiveMediaSource(ams);
        mediaPlayerElement.MediaPlayer.Play();


        ams.InitialBitrate = ams.AvailableBitrates.Max<uint>();

        //Register for download requests
        ams.DownloadRequested += DownloadRequested;

        //Register for download failure and completion events
        ams.DownloadCompleted += DownloadCompleted;
        ams.DownloadFailed += DownloadFailed;

        //Register for bitrate change events
        ams.DownloadBitrateChanged += DownloadBitrateChanged;
        ams.PlaybackBitrateChanged += PlaybackBitrateChanged;

        //Register for diagnostic event
        ams.Diagnostics.DiagnosticAvailable += DiagnosticAvailable;
    }
    else
    {
        // Handle failure to create the adaptive media source
        MyLogMessageFunction($"Adaptive source creation failed: {uri} - {result.ExtendedError}");
    }
}

Initialisieren einer AdaptiveMediaSource mit HttpClient

Wenn Sie benutzerdefinierte HTTP-Header für den Abruf der Manifestdatei festlegen müssen, können Sie ein HttpClient-Objekt erstellen, die gewünschten Header festlegen und dann das Objekt in die Überladung von CreateFromUriAsync übergeben.

httpClient = new Windows.Web.Http.HttpClient();
httpClient.DefaultRequestHeaders.TryAppendWithoutValidation("X-CustomHeader", "This is a custom header");
AdaptiveMediaSourceCreationResult result = await AdaptiveMediaSource.CreateFromUriAsync(manifestUri, httpClient);

Das Ereignis DownloadRequested wird ausgelöst, wenn das System im Begriff ist, eine Ressource vom Server abzurufen. Die AdaptiveMediaSourceDownloadRequestedEventArgs, die an den Ereignishandler übergeben wird, stellt Eigenschaften zur Verfügung, die Informationen über die angeforderte Ressource liefern, z. B. den Typ und die URI der Ressource.

Ändern der Eigenschaften von Ressourcenanforderungen mit dem Ereignis DownloadRequested

Sie können den DownloadRequested Ereignishandler verwenden, um die Ressourcenanforderung zu ändern, indem Sie die Eigenschaften des AdaptiveMediaSourceDownloadResult-Objekts aktualisieren, das durch die Ereignis-Args bereitgestellt wird. Im folgenden Beispiel wird der URI, von dem die Ressource abgerufen wird, geändert, indem die Eigenschaften ResourceUri des Ergebnisobjekts aktualisiert werden. Sie können auch den Bytebereich-Offset und die Länge für Mediensegmente umschreiben oder, wie im folgenden Beispiel gezeigt, den Ressourcen-URI ändern, um die vollständige Ressource herunterzuladen, und den Bytebereich-Offset und die Länge auf Null setzen.

Sie können den Inhalt der angeforderten Ressource überschreiben, indem Sie die Eigenschaften Buffer oder InputStream des Ergebnisobjekts festlegen. Im folgenden Beispiel wird der Inhalt der Manifest-Ressource durch die Einstellung der Eigenschaft Puffer ersetzt. Beachten Sie, dass Sie, wenn Sie die Ressourcenanforderung mit Daten aktualisieren, die asynchron abgerufen werden, wie z. B. das Abrufen von Daten von einem Remote-Server oder die asynchrone Benutzerauthentifizierung, AdaptiveMediaSourceDownloadRequestedEventArgs.GetDeferral aufrufen müssen, um einen Aufschub zu erhalten, und dann Complete aufrufen müssen, wenn der Vorgang abgeschlossen ist, um dem System zu signalisieren, dass der Download-Anforderungsvorgang fortgesetzt werden kann.

    private async void DownloadRequested(AdaptiveMediaSource sender, AdaptiveMediaSourceDownloadRequestedEventArgs args)
    {

        // rewrite key URIs to replace http:// with https://
        if (args.ResourceType == AdaptiveMediaSourceResourceType.Key)
        {
            string originalUri = args.ResourceUri.ToString();
            string secureUri = originalUri.Replace("http:", "https:");

            // override the URI by setting property on the result sub object
            args.Result.ResourceUri = new Uri(secureUri);
        }

        if (args.ResourceType == AdaptiveMediaSourceResourceType.Manifest)
        {
            AdaptiveMediaSourceDownloadRequestedDeferral deferral = args.GetDeferral();
            args.Result.Buffer = await CreateMyCustomManifest(args.ResourceUri);
            deferral.Complete();
        }

        if (args.ResourceType == AdaptiveMediaSourceResourceType.MediaSegment)
        {
            var resourceUri = args.ResourceUri.ToString() + "?range=" + 
                args.ResourceByteRangeOffset + "-" + (args.ResourceByteRangeLength - 1);

            // override the URI by setting a property on the result sub object
            args.Result.ResourceUri = new Uri(resourceUri);

            // clear the byte range properties on the result sub object
            args.Result.ResourceByteRangeOffset = null;
            args.Result.ResourceByteRangeLength = null;
        }
    }

Verwenden Sie Bitratenereignisse, um Bitratenänderungen zu verwalten und darauf zu reagieren

Das Objekt AdaptiveMediaSource bietet Ereignisse, mit denen Sie auf Änderungen der Download- oder Wiedergabe-Bitraten reagieren können. In diesem Beispiel werden die aktuellen Bitraten einfach in der Benutzeroberfläche aktualisiert. Beachten Sie, dass Sie die Verhältnisse ändern können, die bestimmen, wann das System die Bitraten des adaptiven Streams umschaltet. Weitere Informationen finden Sie unter der Eigenschaft AdvancedSettings.

private async void DownloadBitrateChanged(AdaptiveMediaSource sender, AdaptiveMediaSourceDownloadBitrateChangedEventArgs args)
{
    await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, new DispatchedHandler(() =>
    {
        txtDownloadBitrate.Text = args.NewValue.ToString();
    }));
}

private async void PlaybackBitrateChanged(AdaptiveMediaSource sender, AdaptiveMediaSourcePlaybackBitrateChangedEventArgs args)
{
    await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, new DispatchedHandler(() =>
    {
        txtPlaybackBitrate.Text = args.NewValue.ToString();
    }));
}

Handhabung von Download-Abschluss- und -Fehlerereignissen

Das Objekt AdaptiveMediaSource löst das Ereignis DownloadFailed aus, wenn der Download einer angeforderten Ressource fehlschlägt. Sie können dieses Ereignis verwenden, um Ihre Benutzeroberfläche als Reaktion auf den Fehler zu aktualisieren. Sie können das Ereignis auch verwenden, um statistische Informationen über den Downloadvorgang und den Fehler zu protokollieren.

Das Objekt AdaptiveMediaSourceDownloadFailedEventArgs, das an den Ereignishandler übergeben wird, enthält Metadaten über den fehlgeschlagenen Ressourcendownload, wie z. B. den Ressourcentyp, den URI der Ressource und die Position innerhalb des Streams, an der der Fehler aufgetreten ist. Die RequestId liefert einen vom System generierten eindeutigen Bezeichner für die Anfrage, der verwendet werden kann, um Statusinformationen über eine einzelne Anfrage über mehrere Ereignisse hinweg zu korrelieren.

Die Eigenschaft Statistics gibt ein AdaptiveMediaSourceDownloadStatistics-Objekt zurück, das detaillierte Informationen über die Anzahl der zum Zeitpunkt des Ereignisses empfangenen Bytes und den Zeitpunkt verschiedener Meilensteine des Downloadvorgangs liefert. Sie können diese Informationen protokollieren, um Leistungsprobleme in Ihrer adaptiven Streaming-Implementierung zu erkennen.

private void DownloadFailed(AdaptiveMediaSource sender, AdaptiveMediaSourceDownloadFailedEventArgs args)
{
    var statistics = args.Statistics;

    MyLogMessageFunction("download failed for: " + args.ResourceType + 
     " - " + args.ResourceUri +
     " – Error:" + args.ExtendedError.HResult +
     " - RequestId" + args.RequestId + 
     " – Position:" + args.Position +
     " - Duration:" + args.ResourceDuration +
     " - ContentType:" + args.ResourceContentType +
     " - TimeToHeadersReceived:" + statistics.TimeToHeadersReceived + 
     " - TimeToFirstByteReceived:" + statistics.TimeToFirstByteReceived + 
     " - TimeToLastByteReceived:" + statistics.TimeToLastByteReceived +
     " - ContentBytesReceivedCount:" + statistics.ContentBytesReceivedCount);

}

Das Ereignis DownloadCompleted tritt ein, wenn ein Ressourcendownload abgeschlossen ist und liefert ähnliche Daten wie das Ereignis DownloadFailed. Auch hier wird eine RequestId für die Korrelation von Ereignissen für eine einzelne Anfrage bereitgestellt. Außerdem wird ein AdaptiveMediaSourceDownloadStatistics-Objekt zur Verfügung gestellt, das die Protokollierung von Download-Statistiken ermöglicht.

private void DownloadCompleted(AdaptiveMediaSource sender, AdaptiveMediaSourceDownloadCompletedEventArgs args)
{
    var statistics = args.Statistics;

    MyLogMessageFunction("download completed for: " + args.ResourceType + " - " +
     args.ResourceUri +
     " – RequestId:" + args.RequestId +
     " – Position:" + args.Position +
     " - Duration:" + args.ResourceDuration +
     " - ContentType:" + args.ResourceContentType +
     " - TimeToHeadersReceived:" + statistics.TimeToHeadersReceived + 
     " - TimeToFirstByteReceived:" + statistics.TimeToFirstByteReceived + 
     " - TimeToLastByteReceived:" + statistics.TimeToLastByteReceived +
     " - ContentBytesReceivedCount:" + statistics.ContentBytesReceivedCount);

}

Erfassen von adaptiven Streaming-Telemetriedaten mit AdaptiveMediaSourceDiagnostics

Die AdaptiveMediaSource stellt eine Diagnostics Eigenschaft zur Verfügung, die ein AdaptiveMediaSourceDiagnostics-Objekt zurückgibt. Verwenden Sie dieses Objekt, um sich für das Ereignis DiagnosticAvailable zu registrieren. Dieses Ereignis ist für die Sammlung von Telemetriedaten gedacht und sollte nicht dazu verwendet werden, das Verhalten der Anwendung zur Laufzeit zu ändern. Dieses Diagnoseereignis wird aus vielen verschiedenen Gründen ausgelöst. Überprüfen Sie die Eigenschaft DiagnosticType des AdaptiveMediaSourceDiagnosticAvailableEventArgs-Objekts, das an das Ereignis übergeben wurde, um den Grund für die Auslösung des Ereignisses zu ermitteln. Mögliche Gründe sind Fehler beim Zugriff auf die angeforderte Ressource und Fehler beim Parsen der Streaming-Manifestdatei. Eine Liste der Situationen, die ein Diagnoseereignis auslösen können, finden Sie unter AdaptiveMediaSourceDiagnosticType. Wie die Argumente für andere adaptive Streaming-Ereignisse bietet das AdaptiveMediaSourceDiagnosticAvailableEventArgs eine RequestId Eigenschaft für die Korrelation von Anforderungsinformationen zwischen verschiedenen Ereignissen.

private void DiagnosticAvailable(AdaptiveMediaSourceDiagnostics sender, AdaptiveMediaSourceDiagnosticAvailableEventArgs args)
{
    MySendTelemetryFunction(args.RequestId, args.Position,
                            args.DiagnosticType, args.SegmentId,
                            args.ResourceType, args.ResourceUri,
                            args.ResourceDuration, args.ResourceContentType,
                            args.ResourceByteRangeOffset,
                            args.ResourceByteRangeLength, 
                            args.Bitrate,
                            args.ExtendedError);

}

Aufschieben der Bindung von adaptiven Streaming-Inhalten für Elemente in einer Wiedergabeliste mithilfe von MediaBinder

Die Klasse MediaBinder ermöglicht es Ihnen, die Bindung von Medieninhalten in einer MediaPlaybackList aufzuschieben. Ab Windows 10, Version 1703, können Sie eine AdaptiveMediaSource als gebundenen Inhalt bereitstellen. Das Verfahren für die zeitversetzte Bindung einer adaptiven Medienquelle ist weitgehend dasselbe wie das Binden anderer Medientypen, das unter Media items, playlists, and tracks beschrieben wird.

Erstellen Sie eine MediaBinder Instanz, legen Sie einen app-definierten Token String fest, um den zu bindenden Inhalt zu identifizieren, und registrieren Sie sich für das Binding Ereignis. Erstellen Sie eine MediaSource aus dem Binder durch den Aufruf MediaSource.CreateFromMediaBinder. Erstellen Sie dann ein MediaPlaybackItem aus der MediaSource und fügen Sie es der Wiedergabeliste hinzu.

_mediaPlaybackList = new MediaPlaybackList();

var binder = new MediaBinder();
binder.Token = "MyBindingToken1";
binder.Binding += Binder_Binding;
_mediaPlaybackList.Items.Add(new MediaPlaybackItem(MediaSource.CreateFromMediaBinder(binder)));

binder = new MediaBinder();
binder.Token = "MyBindingToken2";
binder.Binding += Binder_Binding;
_mediaPlaybackList.Items.Add(new MediaPlaybackItem(MediaSource.CreateFromMediaBinder(binder)));

_mediaPlayer = new MediaPlayer();
_mediaPlayer.Source = _mediaPlaybackList;
mediaPlayerElement.SetMediaPlayer(_mediaPlayer);

Verwenden Sie im Ereignishandler Binding die Token-Zeichenfolge, um den zu bindenden Inhalt zu identifizieren, und erstellen Sie dann die adaptive Medienquelle, indem Sie eine der Überladungen von CreateFromStreamAsync oder CreateFromUriAsync aufrufen. Da es sich hierbei um asynchrone Methoden handelt, sollten Sie zunächst die Methode MediaBindingEventArgs.GetDeferral aufrufen, um das System anzuweisen, auf den Abschluss Ihres Vorgangs zu warten, bevor Sie fortfahren. Legen Sie die adaptive Medienquelle als gebundenen Inhalt fest, indem Sie SetAdaptiveMediaSource aufrufen. Rufen Sie schließlich Deferral.Complete auf, nachdem Ihr Vorgang abgeschlossen ist, um das System anzuweisen, fortzufahren.

private async void Binder_Binding_AdaptiveMediaSource(MediaBinder sender, MediaBindingEventArgs args)
{
    var deferral = args.GetDeferral();

    var contentUri = new Uri($"http://contoso.com/media/{args.MediaBinder.Token}");
    AdaptiveMediaSourceCreationResult result = await AdaptiveMediaSource.CreateFromUriAsync(contentUri);

    if (result.MediaSource != null)
    {
        args.SetAdaptiveMediaSource(result.MediaSource);
    }
    args.SetUri(contentUri);

    deferral.Complete();
}

Wenn Sie Ereignishandler für die gebundene adaptive Medienquelle registrieren möchten, können Sie dies im Handler für das Ereignis CurrentItemChanged der MediaPlaybackList tun. Die Eigenschaft CurrentMediaPlaybackItemChangedEventArgs.NewItem enthält das neue aktuell spielende MediaPlaybackItem in der Liste. Rufen Sie eine Instanz von AdaptiveMediaSource ab, die das neue Element darstellt, indem Sie auf die Eigenschaft Source von MediaPlaybackItem und dann auf die Eigenschaft AdaptiveMediaSource der Medienquelle zugreifen. Diese Eigenschaft ist null, wenn das neue Wiedergabeelement keine AdaptiveMediaSource ist. Daher sollten Sie auf null testen, bevor Sie versuchen, Handler für eines der Ereignisse des Objekts zu registrieren.

private void AMSMediaPlaybackList_CurrentItemChanged(MediaPlaybackList sender, CurrentMediaPlaybackItemChangedEventArgs args)
{
    if (!(args.NewItem is null))
    {
        var ams = args.NewItem.Source.AdaptiveMediaSource;
        if (!(ams is null))
        {
            ams.PlaybackBitrateChanged += Ams_PlaybackBitrateChanged;
        }
    }
}