导出 (0) 打印
全部展开

通过静态加密使用 PlayReady 来保护平滑流和 MPEG DASH

更新时间: 2014年8月

如果你要使用 PlayReady 保护内容,可以选择使用动态加密(推荐选项)或静态加密。以下博客讨论了这两个选项:动态加密与静态加密。如果你决定使用动态加密,请参阅使用 PlayReady 动态加密和许可证传送服务

进行静态加密时,你通常会执行以下步骤。如果要从自适应比特率平滑流文件开始,请跳到步骤 4。

  1. 上载一个输入文件(称为夹层文件)。例如,H.264、MP4 或 WMV(有关受支持格式的列表,请参阅 Media Services Encoder 支持的格式)。

  2. 将夹层文件编码为一组自适应比特率 MP4。

  3. 将自适应比特率 MP4 集打包成平滑流。

  4. 加密平滑流。

  5. 创建链接到服务器上的资产的点播定位符。然后构建完整 URL。如为平滑流:{media services account name}.origin.mediaservices.net/{locator ID}/{filename}.ism/Manifest。如为 MPEG DASH:{media services account name}.origin.mediaservices.net/{locator ID}/{filename}.ism/Manifest(format=mpd-time-csf) .

本主题中的示例将夹层文件(在本例中为 MP4)编码为自适应比特率 MP4 文件。然后,它将 MP4 封装为平滑流,并使用 PlayReady 对平滑流进行加密。因此,你能对平滑流或 MPEG DASH 进行流式处理。

Media Services 现在提供传送 Microsoft PlayReady 许可证的服务。本文中的示例显示如何配置 Media Services PlayReady 许可证传送服务(请参见以下代码中定义的 ConfigureLicenseDeliveryService 方法)。有关 Media Services PlayReady 许可证传送服务的详细信息,请参阅使用 PlayReady 动态加密和许可证传送服务

note备注
若要传送使用 PlayReady 加密的 MPEG DASH,请确保通过将 useSencBox 和 adjustSubSamples 属性(在 Azure Media Encryptor 的任务预设主题中说明)设为 true 来使用 CENC 选项。

可以从以下网址下载“PlayReady 静态加密”项目:https://github.com/Azure/azure-media-services-samples

以下主题说明了如何设置 Media Services 部署。

  1. Setup for Development on the Media Services SDK for .NET

    请注意,本主题中的代码使用 Azure Media Services .NET SDK Extensions。Media Services .NET SDK Extensions 是一组扩展方法和帮助器函数,可简化代码,并令使用 Media Services 进行开发变得更加容易。

  2. 使用 Media Services SDK 连接到 Media Services

  1. 使用示例部分所示的代码覆盖 Program.cs 文件中的代码。

    确保更新以下代码,以便指向输入 MP4 文件所在的文件夹,

    以及指向 MediaPackager_MP4ToSmooth.xml 和 MediaEncryptor_PlayReadyProtection.xml 文件所在的位置。MediaPackager_MP4ToSmooth.xmlAzure Media Packager 的任务预设中定义,MediaEncryptor_PlayReadyProtection.xmlAzure Media Encryptor 的任务预设主题中定义。

    note备注
    若要流式处理使用 PlayReady 加密的 MPEG DASH,请确保将 MediaEncryptor_PlayReadyProtection.xml 配置的 useSencBoxadjustSubSamples 属性设置为 true

    private static readonly string _mediaFiles =
    Path.GetFullPath(@"../..\Media");
    
    private static readonly string _singleMP4File =
         Path.Combine(_mediaFiles, @"SingleMP4\BigBuckBunny.mp4");
    
    // XML Configruation files path.
    private static readonly string _configurationXMLFiles = @"../..\Configurations\";
    
    
  2. 构建程序并运行。

示例将执行以下操作:

  1. 引入一个 MP4 文件。

  2. 使用 "H264 Adaptive Bitrate MP4 Set 720p",编码器预设将 MP4 文件编码为多比特率 MP4。然后将多比特率 MP4 打包为平滑流。这些打包任务使用 MediaPackager_MP4ToSmooth.xmlMediaPackager_SmoothToHLS.xml 配置。

  3. 使用 PlayReady 加密平滑流。此任务使用 MediaEncryptor_PlayReadyProtection.xml 配置。

    note备注
    示例定义的 UpdatePlayReadyConfigurationXMLFile 方法可用于动态更新 MediaEncryptor_PlayReadyProtection.xml 文件。如果你有可用的密钥种子,则可以使用 GeneratePlayReadyContentKey 方法基于 keySeedValue 和 KeyId 值生成内容密钥。

  4. 创建 OnDemand 定位符并获取流 URL。

    GetSmoothStreamingUri 和 GetMpegDashUri 扩展方法用以下格式返回流 URL:平滑流为 {media services account name}.origin.mediaservices.net/{locator ID}/{filename}.ism/Manifest,MPEG DASH 为 {media services account name}.origin.mediaservices.net/{locator ID}/{filename}.ism/Manifest(format=mpd-time-csf) 

    可以使用 http://smf.cloudapp.net/healthmonitor  播放器来测试平滑流。可以使用 dashif.org 来测试 DASH 流(选择最新版本的播放器)。

有关详细信息,请参阅代码注释。

using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.WindowsAzure.MediaServices.Client;
using System.Xml.Linq;
using Microsoft.WindowsAzure.MediaServices.Client.ContentKeyAuthorization;
using Microsoft.WindowsAzure.MediaServices.Client.DynamicEncryption;

namespace PlayReadyStaticEncryptAndKeyDeliverySvc
{
    class Program
    {
       
        private static readonly string _mediaFiles =
            Path.GetFullPath(@"../..\Media");

        private static readonly string _singleMP4File =
            Path.Combine(_mediaFiles, @"BigBuckBunny.mp4");

        // XML Configruation files path.
        private static readonly string _configurationXMLFiles = @"../..\Configurations\";


        private static MediaServicesCredentials _cachedCredentials = null;
        private static CloudMediaContext _context = null;

        // Media Services account information.
        private static readonly string _mediaServicesAccountName =
            ConfigurationManager.AppSettings["MediaServiceAccountName"];
        private static readonly string _mediaServicesAccountKey =
            ConfigurationManager.AppSettings["MediaServiceAccountKey"];

        static void Main(string[] args)
        {
            // Create and cache the Media Services credentials in a static class variable.
            _cachedCredentials = new MediaServicesCredentials(
                            _mediaServicesAccountName,
                            _mediaServicesAccountKey);
            // Use the cached credentials to create CloudMediaContext.
            _context = new CloudMediaContext(_cachedCredentials);

            // Encoding and encrypting assets //////////////////////
            // Load a single MP4 file.
            IAsset asset = IngestSingleMP4File(_singleMP4File, AssetCreationOptions.None);

            // Encode an MP4 file to a set of multibitrate MP4s.
            // Then, package a set of MP4s to clear Smooth Streaming.
            IAsset clearSmoothStreamAsset =
                ConvertMP4ToMultibitrateMP4sToSmoothStreaming(asset);

            // Create a common encryption content key that is used 
            // a) to set the key values in the MediaEncryptor_PlayReadyProtection.xml file
            //    that is used for encryption.
            // b) to configure the license delivery service and 
            //
            Guid keyId;
            byte[] contentKey;

            IContentKey key = CreateCommonEncryptionKey(out keyId, out contentKey);

            // The content key authorization policy must be configured by you 
            // and met by the client in order for the PlayReady license
            // to be delivered to the client. 
            // In this example the Media Services PlayReady license delivery service is used.
            ConfigureLicenseDeliveryService(key);

            // Get the Media Services PlayReady license delivery URL.
            // This URL will be assigned to the licenseAcquisitionUrl property 
            // of the MediaEncryptor_PlayReadyProtection.xml file.
            Uri acquisitionUrl = key.GetKeyDeliveryUrl(ContentKeyDeliveryType.PlayReadyLicense);

            // Update the MediaEncryptor_PlayReadyProtection.xml file with the key and URL info.
            UpdatePlayReadyConfigurationXMLFile(keyId, contentKey, acquisitionUrl);


            // Encrypt your clear Smooth Streaming to Smooth Streaming with PlayReady.
            IAsset outputAsset = CreateSmoothStreamEncryptedWithPlayReady(clearSmoothStreamAsset);


            // You can use the http://smf.cloudapp.net/healthmonitor player 
            // to test the smoothStreamURL URL.
            string smoothStreamURL = outputAsset.GetSmoothStreamingUri().ToString();
            Console.WriteLine("Smooth Streaming URL:");
            Console.WriteLine(smoothStreamURL);

            // You can use the http://dashif.org/reference/players/javascript/ player 
            // to test the dashURL URL.
            string dashURL = outputAsset.GetMpegDashUri().ToString();
            Console.WriteLine("MPEG DASH URL:");
            Console.WriteLine(dashURL);
        }

        /// <summary>
        /// Creates a job with 2 tasks: 
        /// 1 task - encodes a single MP4 to multibitrate MP4s,
        /// 2 task - packages MP4s to Smooth Streaming.
        /// </summary>
        /// <returns>The output asset.</returns>
        public static IAsset ConvertMP4ToMultibitrateMP4sToSmoothStreaming(IAsset asset)
        {
            // Create a new job.
            IJob job = _context.Jobs.Create("Convert MP4 to Smooth Streaming.");

            // Add task 1 - Encode single MP4 into multibitrate MP4s.
            IAsset MP4sAsset = EncodeMP4IntoMultibitrateMP4sTask(job, asset);
            // Add task 2 - Package a multibitrate MP4 set to Clear Smooth Stream.
            IAsset packagedAsset = PackageMP4ToSmoothStreamingTask(job, MP4sAsset);

            // Submit the job and wait until it is completed.
            job.Submit();
            job = job.StartExecutionProgressTask(
                j =>
                {
                    Console.WriteLine("Job state: {0}", j.State);
                    Console.WriteLine("Job progress: {0:0.##}%", j.GetOverallProgress());
                },
                CancellationToken.None).Result;

            // Get the output asset that contains the Smooth Streaming asset.
            return job.OutputMediaAssets[1];
        }

        /// <summary>
        /// Encrypts Smooth Stream with PlayReady.
        /// Then creates a Smooth Streaming Url.
        /// </summary>
        /// <param name="clearSmoothAsset">Asset that contains clear Smooth Streaming.</param>
        /// <returns>The output asset.</returns>
        public static IAsset CreateSmoothStreamEncryptedWithPlayReady(IAsset clearSmoothStreamAsset)
        {
            // Create a job.
            IJob job = _context.Jobs.Create("Encrypt to PlayReady Smooth Streaming.");

            // Add task 1 - Encrypt Smooth Streaming with PlayReady 
            IAsset encryptedSmoothAsset =
                EncryptSmoothStreamWithPlayReadyTask(job, clearSmoothStreamAsset);

            // Submit the job and wait until it is completed.
            job.Submit();
            job = job.StartExecutionProgressTask(
                j =>
                {
                    Console.WriteLine("Job state: {0}", j.State);
                    Console.WriteLine("Job progress: {0:0.##}%", j.GetOverallProgress());
                },
                CancellationToken.None).Result;

            // The OutputMediaAssets[0] contains the desired asset.
            _context.Locators.Create(
                LocatorType.OnDemandOrigin,
                job.OutputMediaAssets[0],
                AccessPermissions.Read,
                TimeSpan.FromDays(30));

            return job.OutputMediaAssets[0];
        }

        /// <summary>
        /// Create a common encryption content key that is used 
        /// to set the key values in the MediaEncryptor_PlayReadyProtection.xml file
        /// that is used for encryption.
        /// </summary>
        /// <param name="keyId"></param>
        /// <param name="contentKey"></param>
        /// <returns></returns>
        public static IContentKey CreateCommonEncryptionKey(out Guid keyId, out byte[] contentKey)
        {
            keyId = Guid.NewGuid();
            contentKey = GetRandomBuffer(16);

            IContentKey key = _context.ContentKeys.Create(
                                    keyId,
                                    contentKey,
                                    "ContentKey",
                                    ContentKeyType.CommonEncryption);

            return key;
        }

        /// <summary>
        /// Update your configuration .xml file dynamically.
        /// </summary>
        public static void UpdatePlayReadyConfigurationXMLFile(Guid keyId, byte[] keyValue, Uri licenseAcquisitionUrl)
        {
            string xmlFileName = Path.Combine(_configurationXMLFiles,
                                        @"MediaEncryptor_PlayReadyProtection.xml");

            XNamespace xmlns = "http://schemas.microsoft.com/iis/media/v4/TM/TaskDefinition#";

            // Prepare the encryption task template
            XDocument doc = XDocument.Load(xmlFileName);

            var licenseAcquisitionUrlEl = doc
                    .Descendants(xmlns + "property")
                    .Where(p => p.Attribute("name").Value == "licenseAcquisitionUrl")
                    .FirstOrDefault();
            var contentKeyEl = doc
                    .Descendants(xmlns + "property")
                    .Where(p => p.Attribute("name").Value == "contentKey")
                    .FirstOrDefault();
            var keyIdEl = doc
                    .Descendants(xmlns + "property")
                    .Where(p => p.Attribute("name").Value == "keyId")
                    .FirstOrDefault();

            // Update the "value" property.
            if (licenseAcquisitionUrlEl != null)
                licenseAcquisitionUrlEl.Attribute("value").SetValue(licenseAcquisitionUrl.ToString());

            if (contentKeyEl != null)
                contentKeyEl.Attribute("value").SetValue(Convert.ToBase64String(keyValue));

            if (keyIdEl != null)
                keyIdEl.Attribute("value").SetValue(keyId);

            doc.Save(xmlFileName);
        }

        /// <summary>
        /// Uploads a single file.
        /// </summary>
        /// <param name="fileDir">The location of the files.</param>
        /// <param name="assetCreationOptions">
        ///  You can specify the following encryption options for the AssetCreationOptions.
        ///      None:  no encryption.  
        ///      StorageEncrypted: storage encryption. Encrypts a clear input file 
        ///        before it is uploaded to Azure storage. 
        ///      CommonEncryptionProtected: for Common Encryption Protected (CENC) files. 
        ///        For example, a set of files that are already PlayReady encrypted. 
        ///      EnvelopeEncryptionProtected: for HLS with AES encryption files.
        ///        NOTE: The files must have been encoded and encrypted by Transform Manager. 
        ///     </param>
        /// <returns>Returns an asset that contains a single file.</returns>
        /// </summary>
        /// <returns></returns>
        private static IAsset IngestSingleMP4File(string fileDir, AssetCreationOptions assetCreationOptions)
        {
            // Use the SDK extension method to create a new asset by 
            // uploading a mezzanine file from a local path.
            IAsset asset = _context.Assets.CreateFromFile(
                fileDir,
                assetCreationOptions,
                (af, p) =>
                {
                    Console.WriteLine("Uploading '{0}' - Progress: {1:0.##}%", af.Name, p.Progress);
                });

            return asset;
        }

        /// <summary>
        /// Creates a task to encode to Adaptive Bitrate. 
        /// Adds the new task to a job.
        /// </summary>
        /// <param name="job">The job to which to add the new task.</param>
        /// <param name="asset">The input asset.</param>
        /// <returns>The output asset.</returns>
        private static IAsset EncodeMP4IntoMultibitrateMP4sTask(IJob job, IAsset asset)
        {
            // Get the SDK extension method to  get a reference to the Azure Media Encoder.
            IMediaProcessor encoder = _context.MediaProcessors.GetLatestMediaProcessorByName(
                MediaProcessorNames.WindowsAzureMediaEncoder);

            ITask adpativeBitrateTask = job.Tasks.AddNew("MP4 to Adaptive Bitrate Task",
               encoder,
               "H264 Adaptive Bitrate MP4 Set 720p",
               TaskOptions.None);

            // Specify the input Asset
            adpativeBitrateTask.InputAssets.Add(asset);

            // Add an output asset to contain the results of the job. 
            // This output is specified as AssetCreationOptions.None, which 
            // means the output asset is in the clear (unencrypted).
            IAsset abrAsset = adpativeBitrateTask.OutputAssets.AddNew("Multibitrate MP4s",
                                    AssetCreationOptions.None);

            return abrAsset;
        }

        /// <summary>
        /// Creates a task to convert the MP4 file(s) to a Smooth Streaming asset.
        /// Adds the new task to a job.
        /// </summary>
        /// <param name="job">The job to which to add the new task.</param>
        /// <param name="asset">The input asset.</param>
        /// <returns>The output asset.</returns>
        private static IAsset PackageMP4ToSmoothStreamingTask(IJob job, IAsset asset)
        {
            // Get the SDK extension method to  get a reference to the Azure Media Packager.
            IMediaProcessor packager = _context.MediaProcessors.GetLatestMediaProcessorByName(
                MediaProcessorNames.WindowsAzureMediaPackager);

            // Azure Media Packager does not accept string presets, so load xml configuration
            string smoothConfig = File.ReadAllText(Path.Combine(
                        _configurationXMLFiles,
                        "MediaPackager_MP4toSmooth.xml"));

            // Create a new Task to convert adaptive bitrate to Smooth Streaming.
            ITask smoothStreamingTask = job.Tasks.AddNew("MP4 to Smooth Task",
               packager,
               smoothConfig,
               TaskOptions.None);

            // Specify the input Asset, which is the output Asset from the first task
            smoothStreamingTask.InputAssets.Add(asset);

            // Add an output asset to contain the results of the job. 
            // This output is specified as AssetCreationOptions.None, which 
            // means the output asset is in the clear (unencrypted).
            IAsset smoothOutputAsset =
                smoothStreamingTask.OutputAssets.AddNew("Clear Smooth Stream",
                    AssetCreationOptions.None);

            return smoothOutputAsset;
        }


        /// <summary>
        /// Creates a task to encrypt Smooth Streaming with PlayReady.
        /// Note: To deliver DASH, make sure to set the useSencBox and adjustSubSamples 
        /// configuration properties to true. 
        /// In this example, MediaEncryptor_PlayReadyProtection.xml contains configuration.
        /// </summary>
        /// <param name="job">The job to which to add the new task.</param>
        /// <param name="asset">The input asset.</param>
        /// <returns>The output asset.</returns>
        private static IAsset EncryptSmoothStreamWithPlayReadyTask(IJob job, IAsset asset)
        {
            // Get the SDK extension method to  get a reference to the Azure Media Encryptor.
            IMediaProcessor playreadyProcessor = _context.MediaProcessors.GetLatestMediaProcessorByName(
                MediaProcessorNames.WindowsAzureMediaEncryptor);

            // Read the configuration XML.
            //
            // Note that the configuration defined in MediaEncryptor_PlayReadyProtection.xml
            // is using keySeedValue. It is recommended that you do this only for testing 
            // and not in production. For more information, see 
            // http://msdn.microsoft.com/en-us/library/windowsazure/dn189154.aspx.
            //
            string configPlayReady = File.ReadAllText(Path.Combine(_configurationXMLFiles,
                                        @"MediaEncryptor_PlayReadyProtection.xml"));

            ITask playreadyTask = job.Tasks.AddNew("My PlayReady Task",
               playreadyProcessor,
               configPlayReady,
               TaskOptions.ProtectedConfiguration);

            playreadyTask.InputAssets.Add(asset);

            // Add an output asset to contain the results of the job. 
            // This output is specified as AssetCreationOptions.CommonEncryptionProtected.
            IAsset playreadyAsset = playreadyTask.OutputAssets.AddNew(
                                            "PlayReady Smooth Streaming",
                                            AssetCreationOptions.CommonEncryptionProtected);

            return playreadyAsset;
        }

        /// <summary>
        /// Configures authorization policy for the content key. 
        /// </summary>
        /// <param name="contentKey">The content key.</param>
        static public void ConfigureLicenseDeliveryService(IContentKey contentKey)
        {
            // Create ContentKeyAuthorizationPolicy with Open restrictions 
            // and create authorization policy          

            List<ContentKeyAuthorizationPolicyRestriction> restrictions = new List<ContentKeyAuthorizationPolicyRestriction>
            {
                new ContentKeyAuthorizationPolicyRestriction 
                { 
                    Name = "Open", 
                    KeyRestrictionType = (int)ContentKeyRestrictionType.Open, 
                    Requirements = null
                }
            };

            // Configure PlayReady license template.
            string newLicenseTemplate = ConfigurePlayReadyLicenseTemplate();

            IContentKeyAuthorizationPolicyOption policyOption =
                _context.ContentKeyAuthorizationPolicyOptions.Create("",
                    ContentKeyDeliveryType.PlayReadyLicense,
                        restrictions, newLicenseTemplate);

            IContentKeyAuthorizationPolicy contentKeyAuthorizationPolicy = _context.
                        ContentKeyAuthorizationPolicies.
                        CreateAsync("Deliver Common Content Key with no restrictions").
                        Result;


            contentKeyAuthorizationPolicy.Options.Add(policyOption);

            // Associate the content key authorization policy with the content key.
            contentKey.AuthorizationPolicyId = contentKeyAuthorizationPolicy.Id;
            contentKey = contentKey.UpdateAsync().Result;
        }

        static private string ConfigurePlayReadyLicenseTemplate()
        {
            // The following code configures PlayReady License Template using .NET classes
            // and returns the XML string.

            PlayReadyLicenseResponseTemplate responseTemplate = new PlayReadyLicenseResponseTemplate();
            PlayReadyLicenseTemplate licenseTemplate = new PlayReadyLicenseTemplate();

            responseTemplate.LicenseTemplates.Add(licenseTemplate);

            return MediaServicesLicenseTemplateSerializer.Serialize(responseTemplate);
        }

        static private byte[] GetRandomBuffer(int length)
        {
            var returnValue = new byte[length];

            using (var rng =
                new System.Security.Cryptography.RNGCryptoServiceProvider())
            {
                rng.GetBytes(returnValue);
            }

            return returnValue;
        }
    }
}

另请参阅

显示:
© 2015 Microsoft