Адаптивная потоковая передача с помощью PlayReady
В этой статье описывается, как добавить адаптивную потоковую передачу мультимедиа с помощью защиты содержимого Microsoft PlayReady в приложение универсальная платформа Windows (UWP).
Эта функция в настоящее время поддерживает воспроизведение динамической потоковой передачи по содержимому HTTP (DASH).
HLS (Потоковая передача HTTP в Apple) не поддерживается с PlayReady.
Плавная потоковая передача в настоящее время также не поддерживается в собственном коде; Однако PlayReady расширяем и с помощью дополнительных кодов или библиотек, защищенных PlayReady Smooth Streaming, можно поддерживать, использовать программное обеспечение или даже аппаратное drM (управление цифровыми правами).
В этой статье рассматриваются только аспекты адаптивной потоковой передачи, относящиеся к PlayReady. Сведения о реализации адаптивной потоковой передачи в целом см. в разделе "Адаптивная потоковая передача".
В этой статье используется код из примера адаптивной потоковой передачи в репозитории универсальных примеров Microsoft в GitHub. Сценарий 4 связан с использованием адаптивной потоковой передачи с PlayReady. Репозиторий можно скачать в ZIP-файле, перейдя на корневой уровень репозитория и нажав кнопку "Скачать ZIP ".
Вам потребуются следующие инструкции using :
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;
Пространство имен LicenseRequest осуществляется из CommonLicenseRequest.cs, файла PlayReady, предоставленного корпорацией Майкрософт для лицензий.
Необходимо объявить несколько глобальных переменных:
private AdaptiveMediaSource ams = null;
private MediaProtectionManager protectionManager = null;
private string playReadyLicenseUrl = "";
private string playReadyChallengeCustomData = "";
Вы также хотите объявить следующую константу:
private const uint MSPR_E_CONTENT_ENABLING_ACTION_REQUIRED = 0x8004B895;
Настройка MediaProtectionManager
Чтобы добавить защиту содержимого PlayReady в приложение UWP, необходимо настроить объект MediaProtectionManager . Это можно сделать при инициализации объекта AdaptiveMediaSource .
Следующий код настраивает MediaProtectionManager:
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;
}
Этот код можно просто скопировать в приложение, так как это обязательно для настройки защиты содержимого.
Событие ComponentLoadFailed запускается при сбое загрузки двоичных данных. Необходимо добавить обработчик событий для обработки этого, сигналируя о том, что загрузка не завершена:
private void ProtectionManager_ComponentLoadFailed(
MediaProtectionManager sender,
ComponentLoadFailedEventArgs e)
{
e.Completion.Complete(false);
}
Аналогичным образом необходимо добавить обработчик событий для события ServiceRequested , который запускается при запросе службы. Этот код проверяет тип запроса и отвечает соответствующим образом:
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);
}
}
Запросы службы инициализации
Следующий код реактивно делает запрос службы инициализации PlayReady. Мы передаваем запрос в качестве параметра функции. Мы окружаем вызов в блоке try/catch, и если нет исключений, мы говорим, что запрос выполнен успешно:
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;
}
Кроме того, мы можем заранее сделать запрос на службу персонализации, в этом случае мы вызываем следующую функцию вместо вызова ReactiveIndivRequest
кода в ProtectionManager_ServiceRequested
:
async void ProActiveIndivRequest()
{
PlayReadyIndividualizationServiceRequest indivRequest = new PlayReadyIndividualizationServiceRequest();
bool bResultIndiv = await ReactiveIndivRequest(indivRequest, null);
}
Запросы на получение лицензий
Если вместо этого запрос был PlayReadyLicenseAcquisitionServiceRequest, мы вызываем следующую функцию, чтобы запросить и получить лицензию PlayReady. Мы сообщаем объект MediaProtectionServiceCompletion, который мы передали в том, был ли запрос успешным или нет, и мы завершаем запрос:
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);
}
Инициализация AdaptiveMediaSource
Наконец, вам потребуется функция для инициализации AdaptiveMediaSource, созданной из заданного URI и MediaElement. Uri должен быть ссылкой на файл мультимедиа (HLS или DASH); MediaElement должен быть определен в XAML.
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
}
}
Эту функцию можно вызвать в любом случае, когда оно обрабатывает начало адаптивной потоковой передачи; Например, в событии нажатия кнопки.