Freigeben über


Adaptives Streaming mit PlayReady

In diesem Artikel wird beschrieben, wie Sie einer Universelle Windows-Plattform -App (UWP) adaptives Streaming von Multimediainhalten mit Microsoft PlayReady-Inhaltsschutz hinzufügen.

Dieses Feature unterstützt derzeit die Wiedergabe von Dynamischem Streaming über DASH-Inhalte (Dynamic Streaming over HTTP).

HLS (Http Live Streaming von Apple) wird mit PlayReady nicht unterstützt.

Das reibungslose Streaming wird derzeit auch nicht nativ unterstützt. PlayReady ist jedoch erweiterbar und mithilfe zusätzlicher Code oder Bibliotheken kann PlayReady-geschütztes Smooth-Streaming unterstützt werden, indem Software oder sogar Hardware-DRM (digitale Rechteverwaltung) genutzt wird.

In diesem Artikel werden nur die Aspekte des adaptiven Streamings behandelt, die für PlayReady spezifisch sind. Informationen zum Implementieren von adaptivem Streaming im Allgemeinen finden Sie unter Adaptives Streaming.

In diesem Artikel wird Code aus dem Beispiel für adaptives Streaming im Repository für universelle Windows-Beispiele von Microsoft auf GitHub verwendet. Szenario 4 befasst sich mit der Verwendung des adaptiven Streamings mit PlayReady. Sie können das Repository in einer ZIP-Datei herunterladen, indem Sie zur Stammebene des Repositorys navigieren und die Schaltfläche "ZIP herunterladen" auswählen.

Sie benötigen die folgenden using-Anweisungen :

using LicenseRequest;
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Windows.Foundation.Collections;
using Windows.Media.Protection;
using Windows.Media.Protection.PlayReady;
using Windows.Media.Streaming.Adaptive;
using Windows.UI.Xaml.Controls;

Der LicenseRequest-Namespace stammt aus CommonLicenseRequest.cs, einer PlayReady-Datei, die von Microsoft für Lizenznehmer bereitgestellt wird.

Sie müssen einige globale Variablen deklarieren:

private AdaptiveMediaSource ams = null;
private MediaProtectionManager protectionManager = null;
private string playReadyLicenseUrl = "";
private string playReadyChallengeCustomData = "";

Außerdem möchten Sie die folgende Konstante deklarieren:

private const uint MSPR_E_CONTENT_ENABLING_ACTION_REQUIRED = 0x8004B895;

Einrichten des MediaProtectionManager

Um Ihrer UWP-App PlayReady-Inhaltsschutz hinzuzufügen, müssen Sie ein MediaProtectionManager-Objekt einrichten. Dies geschieht beim Initialisieren des AdaptiveMediaSource-Objekts.

Der folgende Code richtet einen MediaProtectionManager ein:

private void SetUpProtectionManager(ref MediaElement mediaElement)
{
    protectionManager = new MediaProtectionManager();

    protectionManager.ComponentLoadFailed += 
        new ComponentLoadFailedEventHandler(ProtectionManager_ComponentLoadFailed);

    protectionManager.ServiceRequested += 
        new ServiceRequestedEventHandler(ProtectionManager_ServiceRequested);

    PropertySet cpSystems = new PropertySet();

    cpSystems.Add(
        "{F4637010-03C3-42CD-B932-B48ADF3A6A54}", 
        "Windows.Media.Protection.PlayReady.PlayReadyWinRTTrustedInput");

    protectionManager.Properties.Add("Windows.Media.Protection.MediaProtectionSystemIdMapping", cpSystems);

    protectionManager.Properties.Add(
        "Windows.Media.Protection.MediaProtectionSystemId", 
        "{F4637010-03C3-42CD-B932-B48ADF3A6A54}");

    protectionManager.Properties.Add(
        "Windows.Media.Protection.MediaProtectionContainerGuid", 
        "{9A04F079-9840-4286-AB92-E65BE0885F95}");

    mediaElement.ProtectionManager = protectionManager;
}

Dieser Code kann einfach in Ihre App kopiert werden, da er zum Einrichten des Inhaltsschutzes obligatorisch ist.

Das ComponentLoadFailed-Ereignis wird ausgelöst, wenn das Laden von Binärdaten fehlschlägt. Wir müssen einen Ereignishandler hinzufügen, um dies zu behandeln, was signalisiert, dass die Last nicht abgeschlossen wurde:

private void ProtectionManager_ComponentLoadFailed(
    MediaProtectionManager sender, 
    ComponentLoadFailedEventArgs e)
{
    e.Completion.Complete(false);
}

Ebenso müssen wir einen Ereignishandler für das ServiceRequested-Ereignis hinzufügen, das ausgelöst wird, wenn ein Dienst angefordert wird. Dieser Code überprüft, welche Art von Anforderung es ist, und antwortet entsprechend:

private async void ProtectionManager_ServiceRequested(
    MediaProtectionManager sender, 
    ServiceRequestedEventArgs e)
{
    if (e.Request is PlayReadyIndividualizationServiceRequest)
    {
        PlayReadyIndividualizationServiceRequest IndivRequest = 
            e.Request as PlayReadyIndividualizationServiceRequest;

        bool bResultIndiv = await ReactiveIndivRequest(IndivRequest, e.Completion);
    }
    else if (e.Request is PlayReadyLicenseAcquisitionServiceRequest)
    {
        PlayReadyLicenseAcquisitionServiceRequest licenseRequest = 
            e.Request as PlayReadyLicenseAcquisitionServiceRequest;

        LicenseAcquisitionRequest(
            licenseRequest, 
            e.Completion, 
            playReadyLicenseUrl, 
            playReadyChallengeCustomData);
    }
}

Individualisierungsdienstanforderungen

Der folgende Code sendet reaktiv eine PlayReady-Individualisierungsdienstanforderung. Wir übergeben die Anforderung als Parameter an die Funktion. Wir schließen den Anruf in einen Try/Catch-Block ein, und wenn keine Ausnahmen vorhanden sind, sagen wir, dass die Anforderung erfolgreich abgeschlossen wurde:

async Task<bool> ReactiveIndivRequest(
    PlayReadyIndividualizationServiceRequest IndivRequest, 
    MediaProtectionServiceCompletion CompletionNotifier)
{
    bool bResult = false;
    Exception exception = null;

    try
    {
        await IndivRequest.BeginServiceRequest();
    }
    catch (Exception ex)
    {
        exception = ex;
    }
    finally
    {
        if (exception == null)
        {
            bResult = true;
        }
        else
        {
            COMException comException = exception as COMException;
            if (comException != null && comException.HResult == MSPR_E_CONTENT_ENABLING_ACTION_REQUIRED)
            {
                IndivRequest.NextServiceRequest();
            }
        }
    }

    if (CompletionNotifier != null) CompletionNotifier.Complete(bResult);
    return bResult;
}

Alternativ können wir proaktiv eine Individualisierungsdienstanfrage stellen, in diesem Fall rufen wir anstelle des Codeaufrufs die folgende Funktion auf ReactiveIndivRequest ProtectionManager_ServiceRequested:

async void ProActiveIndivRequest()
{
    PlayReadyIndividualizationServiceRequest indivRequest = new PlayReadyIndividualizationServiceRequest();
    bool bResultIndiv = await ReactiveIndivRequest(indivRequest, null);
}

Anforderungen des Lizenzerwerbsdiensts

Wenn es sich bei der Anforderung stattdessen um eine PlayReadyLicenseAcquisitionServiceRequest handelt, rufen wir die folgende Funktion auf, um die PlayReady-Lizenz anzufordern und zu erwerben. Wir teilen dem MediaProtectionServiceCompletion-Objekt mit, dass wir übergeben haben, ob die Anforderung erfolgreich war oder nicht, und wir führen die Anforderung aus:

async void LicenseAcquisitionRequest(
    PlayReadyLicenseAcquisitionServiceRequest licenseRequest, 
    MediaProtectionServiceCompletion CompletionNotifier, 
    string Url, 
    string ChallengeCustomData)
{
    bool bResult = false;
    string ExceptionMessage = string.Empty;

    try
    {
        if (!string.IsNullOrEmpty(Url))
        {
            if (!string.IsNullOrEmpty(ChallengeCustomData))
            {
                System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
                byte[] b = encoding.GetBytes(ChallengeCustomData);
                licenseRequest.ChallengeCustomData = Convert.ToBase64String(b, 0, b.Length);
            }

            PlayReadySoapMessage soapMessage = licenseRequest.GenerateManualEnablingChallenge();

            byte[] messageBytes = soapMessage.GetMessageBody();
            HttpContent httpContent = new ByteArrayContent(messageBytes);

            IPropertySet propertySetHeaders = soapMessage.MessageHeaders;

            foreach (string strHeaderName in propertySetHeaders.Keys)
            {
                string strHeaderValue = propertySetHeaders[strHeaderName].ToString();

                if (strHeaderName.Equals("Content-Type", StringComparison.OrdinalIgnoreCase))
                {
                    httpContent.Headers.ContentType = MediaTypeHeaderValue.Parse(strHeaderValue);
                }
                else
                {
                    httpContent.Headers.Add(strHeaderName.ToString(), strHeaderValue);
                }
            }

            CommonLicenseRequest licenseAcquision = new CommonLicenseRequest();

            HttpContent responseHttpContent = 
                await licenseAcquision.AcquireLicense(new Uri(Url), httpContent);

            if (responseHttpContent != null)
            {
                Exception exResult = licenseRequest.ProcessManualEnablingResponse(
                                         await responseHttpContent.ReadAsByteArrayAsync());

                if (exResult != null)
                {
                    throw exResult;
                }
                bResult = true;
            }
            else
            {
                ExceptionMessage = licenseAcquision.GetLastErrorMessage();
            }
        }
        else
        {
            await licenseRequest.BeginServiceRequest();
            bResult = true;
        }
    }
    catch (Exception e)
    {
        ExceptionMessage = e.Message;
    }

    CompletionNotifier.Complete(bResult);
}

Initialisieren der AdaptiveMediaSource

Schließlich benötigen Sie eine Funktion, um adaptiveMediaSource zu initialisieren, die aus einem bestimmten URI und MediaElement erstellt wurde. Der URI sollte der Link zur Mediendatei (HLS oder DASH) sein. Das MediaElement sollte in Ihrem XAML-Code definiert werden.

async private void InitializeAdaptiveMediaSource(System.Uri uri, MediaElement m)
{
    AdaptiveMediaSourceCreationResult result = await AdaptiveMediaSource.CreateFromUriAsync(uri);
    if (result.Status == AdaptiveMediaSourceCreationStatus.Success)
    {
        ams = result.MediaSource;
        SetUpProtectionManager(ref m);
        m.SetMediaStreamSource(ams);
    }
    else
    {
        // Error handling
    }
}

Sie können diese Funktion in welchem Ereignis der Start des adaptiven Streamings behandelt wird, aufrufen. Beispielsweise in einem Schaltflächenklickereignis.

Weitere Informationen