使用 AES-128 动态加密和密钥传递服务Use AES-128 dynamic encryption and the key delivery service

Note

不会向媒体服务 v2 添加任何新特性或新功能。No new features or functionality are being added to Media Services v2.
查看最新版本:媒体服务 v3Check out the latest version, Media Services v3. 另请参阅从 v2 到 v3 的迁移指南Also, see migration guidance from v2 to v3

借助媒体服务,可以传送使用 AES 加密的 HTTP Live Streaming (HLS) 和平滑流(使用 128 位加密密钥)。You can use Media Services to deliver HTTP Live Streaming (HLS) and Smooth Streaming encrypted with the AES by using 128-bit encryption keys. 媒体服务还提供密钥传送服务,将加密密钥传送给已授权的用户。Media Services also provides the key delivery service that delivers encryption keys to authorized users. 如果需要媒体服务来加密资产,则需要将加密密钥与资产相关联,并配置密钥的授权策略。If you want Media Services to encrypt an asset, you associate an encryption key with the asset and also configure authorization policies for the key. 当播放器请求流时,媒体服务将使用指定的密钥通过 AES 加密来动态加密内容。When a stream is requested by a player, Media Services uses the specified key to dynamically encrypt your content by using AES encryption. 为了解密流,播放器将从密钥传送服务请求密钥。To decrypt the stream, the player requests the key from the key delivery service. 为了确定用户是否被授权获取密钥,服务将评估你为密钥指定的授权策略。To determine whether the user is authorized to get the key, the service evaluates the authorization policies that you specified for the key.

媒体服务支持通过多种方式对发出密钥请求的用户进行身份验证。Media Services supports multiple ways of authenticating users who make key requests. 内容密钥授权策略可能有一种或多种授权限制:开放或令牌限制。The content key authorization policy can have one or more authorization restrictions, either open or token restrictions. 令牌限制策略必须附带由安全令牌服务 (STS) 颁发的令牌。The token-restricted policy must be accompanied by a token issued by a security token service (STS). 媒体服务支持采用简单 Web 令牌 (SWT) 格式和 JSON Web 令牌 (JWT) 格式的令牌。Media Services supports tokens in the simple web token (SWT) and JSON Web Token (JWT) formats. 有关详细信息,请参阅配置内容密钥授权策略For more information, see Configure the content key's authorization policy.

为了充分利用动态加密,资产必须包含一组多码率 MP4 文件或多码率平滑流源文件。To take advantage of dynamic encryption, you need to have an asset that contains a set of multi-bitrate MP4 files or multi-bitrate Smooth Streaming source files. 还需要为资产配置传送策略(在本文后面部分介绍)。You also need to configure the delivery policy for the asset (described later in this article). 然后,根据在流式处理 URL 中指定的格式,按需流式处理服务器会确保使用选定的协议来传送流。Then, based on the format specified in the streaming URL, the on-demand streaming server ensures that the stream is delivered in the protocol you selected. 因此,需要存储只使用单一存储格式的文件并为其付费。As a result, you need to store and pay only for the files in single storage format. 媒体服务会根据客户端的请求生成并提供适当的响应。Media Services builds and serves the appropriate response based on requests from a client.

本文适合开发受保护媒体传送应用程序的开发人员。This article is useful to developers who work on applications that deliver protected media. 本文介绍如何使用授权策略来配置密钥传送服务,确保只有经过授权的客户端才能接收加密密钥。The article shows you how to configure the key delivery service with authorization policies so that only authorized clients can receive encryption keys. 此外还会介绍如何使用动态加密。It also shows how to use dynamic encryption.

有关如何使用高级加密标准 (AES) 加密内容并传送到 macOS 上的 Safari 的信息,请参阅此博客文章For information on how to encrypt content with the Advanced Encryption Standard (AES) for delivery to Safari on macOS, see this blog post.

AES-128 动态加密和密钥传送服务工作流AES-128 dynamic encryption and key delivery service workflow

使用媒体服务密钥传送服务和动态加密通过 AES 来加密资产时,请执行下述常规步骤:Perform the following general steps when you encrypt your assets with AES by using the Media Services key delivery service and also by using dynamic encryption:

  1. 创建资产并将文件上传到资产Create an asset, and upload files into the asset.

  2. 将包含文件的资产编码为自适应比特率 MP4 集Encode the asset that contains the file to the adaptive bitrate MP4 set.

  3. 创建内容密钥并将其与编码资产相关联Create a content key, and associate it with the encoded asset. 在媒体服务中,内容密钥包含资产的加密密钥。In Media Services, the content key contains the asset's encryption key.

  4. 配置内容密钥授权策略Configure the content key's authorization policy. 必须配置内容密钥授权策略。You must configure the content key authorization policy. 客户端必须符合该策略才能将内容密钥传送到客户端。The client must meet the policy before the content key is delivered to the client.

  5. 为资产配置传送策略Configure the delivery policy for an asset. 传送策略配置包括密钥获取 URL 和初始化矢量 (IV)。The delivery policy configuration includes the key acquisition URL and an initialization vector (IV). (进行加密和解密时,AES-128 要求提供同一个 IV。)配置中还包括传送协议(例如 MPEG-DASH、HLS、平滑流式处理或全部)和动态加密类型(例如信封或无动态加密)。(AES-128 requires the same IV for encryption and decryption.) The configuration also includes the delivery protocol (for example, MPEG-DASH, HLS, Smooth Streaming, or all) and the type of dynamic encryption (for example, envelope or no dynamic encryption).

    可以对同一资产上的不同协议应用不同的策略。You can apply a different policy to each protocol on the same asset. 例如,可以将 PlayReady 加密应用到平滑流/DASH,将 AES 信封应用到 HLS。For example, you can apply PlayReady encryption to Smooth/DASH and an AES envelope to HLS. 将阻止流式处理传送策略中未定义的任何协议。Any protocols that aren't defined in a delivery policy are blocked from streaming. (例如,添加仅将 HLS 指定为协议的单个策略。)如果根本没有定义任何资产传送策略,则属例外。(An example is if you add a single policy that specifies only HLS as the protocol.) The exception is if you have no asset delivery policy defined at all. 此时,允许所有明文形式的协议。Then, all protocols are allowed in the clear.

  6. 创建 OnDemand 定位符以获取流式处理 URL。Create an OnDemand locator to get a streaming URL.

本文还说明了客户端应用程序如何从密钥传送服务请求密钥The article also shows how a client application can request a key from the key delivery service.

可以在文章末尾找到完整的 .NET 示例You can find a complete .NET example at the end of the article.

下图演示了上述工作流。The following image demonstrates the workflow previously described. 在图中,使用令牌进行了身份验证。Here, the token is used for authentication.

使用 AES-128 提供保护

本文余下部分提供了说明、代码示例和主题链接,介绍了如何完成上述任务。The remainder of this article provides explanations, code examples, and links to topics that show you how to achieve the tasks previously described.

当前限制Current limitations

如果添加或更新资产的传送策略,则必须删除现有的定位符并创建新的定位符。If you add or update your asset's delivery policy, you must delete any existing locator and create a new locator.

创建资产并将文件上传到资产Create an asset and upload files into the asset

为了对视频进行管理、编码和流式处理,必须首先将内容上传到媒体服务中。To manage, encode, and stream your videos, you must first upload your content into Media Services. 上传完成后,相关内容即安全地存储在云中供后续处理和流式处理。After it's uploaded, your content is stored securely in the cloud for further processing and streaming.

有关详细信息,请参阅将文件上传到媒体服务帐户For more information, see Upload files into a Media Services account.

将包含文件的资产编码为自适应比特率 MP4 集Encode the asset that contains the file to the adaptive bitrate MP4 set

使用动态加密时,可创建一项资产,其中包含一组多码率 MP4 文件或多比特率平滑流式处理源文件。With dynamic encryption, you create an asset that contains a set of multi-bitrate MP4 files or multi-bitrate Smooth Streaming source files. 然后,按需流式处理服务器会确保以选定的协议按清单或分段请求中的指定格式接收流。Then, based on the specified format in the manifest or fragment request, the on-demand streaming server ensures that you receive the stream in the protocol you selected. 然后,只需存储使用单一存储格式的文件并为其付费。Then, you only need to store and pay for the files in single storage format. 媒体服务会根据客户端的请求生成并提供适当的响应。Media Services builds and serves the appropriate response based on requests from a client. 有关详细信息,请参阅动态打包概述For more information, see Dynamic packaging overview.

Note

创建媒体服务帐户后,一个处于“已停止”状态的默认流式处理终结点会添加到帐户。When your Media Services account is created, a default streaming endpoint is added to your account in the "Stopped" state. 若要开始流式传输内容并利用动态打包和动态加密,传出流式传输内容的流式处理终结点必须处于“正在运行”状态。To start streaming your content and take advantage of dynamic packaging and dynamic encryption, the streaming endpoint from which you want to stream content must be in the "Running" state.

此外,若要使用动态打包和动态加密,资产必须包含一组自适应比特率 MP4 或自适应比特率平滑流式处理文件。Also, to use dynamic packaging and dynamic encryption, your asset must contain a set of adaptive bitrate MP4s or adaptive bitrate Smooth Streaming files.

有关如何编码的说明,请参阅使用 Media Encoder Standard 对资产进行编码For instructions on how to encode, see Encode an asset by using Media Encoder Standard.

创建内容密钥并将其与编码资产相关联Create a content key and associate it with the encoded asset

在媒体服务中,内容密钥包含用于加密资产的密钥。In Media Services, the content key contains the key that you want to encrypt an asset with.

有关详细信息,请参阅创建内容密钥For more information, see Create a content key.

配置内容密钥授权策略Configure the content key's authorization policy

媒体服务支持通过多种方式对发出密钥请求的用户进行身份验证。Media Services supports multiple ways of authenticating users who make key requests. 必须配置内容密钥授权策略。You must configure the content key authorization policy. 客户端(播放器)必须符合该策略才能将密钥传送到客户端。The client (player) must meet the policy before the key can be delivered to the client. 内容密钥授权策略可能受到一种或多种授权限制:开放、令牌限制或 IP 限制。The content key authorization policy can have one or more authorization restrictions, either open, token restriction, or IP restriction.

有关详细信息,请参阅配置内容密钥授权策略For more information, see Configure a content key authorization policy.

配置资产传送策略Configure an asset delivery policy

为资产配置传送策略。Configure the delivery policy for your asset. 资产传送策略配置包括:Some things that the asset delivery policy configuration includes are:

  • 密钥获取 URL。The key acquisition URL.
  • 用于信封加密的初始化矢量 (IV)。The initialization vector (IV) to use for the envelope encryption. 进行加密和解密时,AES-128 要求提供同一个 IV。AES-128 requires the same IV for encryption and decryption.
  • 资产传送协议(例如 MPEG-DASH、HLS、平滑流式处理或所有这些协议)。The asset delivery protocol (for example, MPEG-DASH, HLS, Smooth Streaming, or all).
  • 动态加密类型(例如 AES 信封)或无动态加密。The type of dynamic encryption (for example, AES envelope) or no dynamic encryption.

有关详细信息,请参阅配置资产传送策略For more information, see Configure an asset delivery policy.

创建 OnDemand 流式处理定位符以获取流式处理 URLCreate an OnDemand streaming locator to get a streaming URL

需要为用户提供平滑流式处理、DASH 或 HLS 的流式处理 URL。You need to provide your user with the streaming URL for Smooth Streaming, DASH, or HLS.

Note

如果添加或更新资产的传送策略,则必须删除现有的定位符并创建新的定位符。If you add or update your asset's delivery policy, you must delete any existing locator and create a new locator.

有关如何发布资产和生成流 URL 的说明,请参阅 生成流 URLFor instructions on how to publish an asset and build a streaming URL, see Build a streaming URL.

获取测试令牌Get a test token

获取用于密钥授权策略的基于令牌限制的测试令牌。Get a test token based on the token restriction that was used for the key authorization policy.

    // Deserializes a string containing an Xml representation of a TokenRestrictionTemplate
    // back into a TokenRestrictionTemplate class instance.
    TokenRestrictionTemplate tokenTemplate = 
        TokenRestrictionTemplateSerializer.Deserialize(tokenTemplateString);

    // Generate a test token based on the data in the given TokenRestrictionTemplate.
    //The GenerateTestToken method returns the token without the word "Bearer" in front
    //so you have to add it in front of the token string. 
    string testToken = TokenRestrictionTemplateSerializer.GenerateTestToken(tokenTemplate);
    Console.WriteLine("The authorization token is:\nBearer {0}", testToken);

可以使用 Azure 媒体服务播放器来测试流。You can use the Azure Media Services Player to test your stream.

你的客户端如何从密钥传送服务请求密钥?How can your client request a key from the key delivery service?

在上一步骤中,构造了指向清单文件的 URL。In the previous step, you constructed the URL that points to a manifest file. 客户端需要从流清单文件提取必要的信息,以便向密钥传送服务发出请求。Your client needs to extract the necessary information from the streaming manifest files to make a request to the key delivery service.

清单文件Manifest files

客户端需要从清单文件提取 URL(也包含内容密钥 ID [kid])值。The client needs to extract the URL (that also contains content key ID [kid]) value from the manifest file. 然后,客户端将尝试从密钥传送服务获取加密密钥。The client then tries to get the encryption key from the key delivery service. 客户端还需要提取 IV 值,并使用该值来解密流。The client also needs to extract the IV value and use it to decrypt the stream. 下面的代码片段演示平滑流式处理清单的 <Protection> 元素。The following snippet shows the <Protection> element of the Smooth Streaming manifest:

    <Protection>
      <ProtectionHeader SystemID="B47B251A-2409-4B42-958E-08DBAE7B4EE9">
        <ContentProtection xmlns:sea="urn:mpeg:dash:schema:sea:2012" schemeIdUri="urn:mpeg:dash:sea:2012">
          <sea:SegmentEncryption schemeIdUri="urn:mpeg:dash:sea:aes128-cbc:2013"/>
          <sea:KeySystem keySystemUri="urn:mpeg:dash:sea:keysys:http:2013"/>
          <sea:CryptoPeriod IV="0xD7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7" 
                        keyUriTemplate="https://wamsbayclus001kd-hs.chinacloudapp.cn/HlsHandler.ashx?
                                            kid=da3813af-55e6-48e7-aa9f-a4d6031f7b4d"/>
        </ContentProtection>
      </ProtectionHeader>
    </Protection>

对于 HLS,根清单将划分成段文件。In the case of HLS, the root manifest is broken into segment files.

例如,根清单为:http://test001.origin.mediaservices.chinacloudapi.cn/8bfe7d6f-34e3-4d1a-b289-3e48a8762490/BigBuckBunny.ism/manifest(format=m3u8-aapl)。For example, the root manifest is: http://test001.origin.mediaservices.chinacloudapi.cn/8bfe7d6f-34e3-4d1a-b289-3e48a8762490/BigBuckBunny.ism/manifest(format=m3u8-aapl). 它包含段文件名的列表。It contains a list of segment file names.

. . . 
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=630133,RESOLUTION=424x240,CODECS="avc1.4d4015,mp4a.40.2",AUDIO="audio"
QualityLevels(514369)/Manifest(video,format=m3u8-aapl)
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=965441,RESOLUTION=636x356,CODECS="avc1.4d401e,mp4a.40.2",AUDIO="audio"
QualityLevels(842459)/Manifest(video,format=m3u8-aapl)
…

如果在文本编辑器中打开其中一个段文件(例如,http://test001.origin.mediaservices.chinacloudapi.cn/8bfe7d6f-34e3-4d1a-b289-3e48a8762490/BigBuckBunny.ism/QualityLevels(514369)/Manifest(video,format=m3u8-aapl)),其中会包含 #EXT-X-KEY(表示文件已加密)。If you open one of the segment files in a text editor (for example, http://test001.origin.mediaservices.chinacloudapi.cn/8bfe7d6f-34e3-4d1a-b289-3e48a8762490/BigBuckBunny.ism/QualityLevels(514369)/Manifest(video,format=m3u8-aapl), it contains #EXT-X-KEY, which indicates that the file is encrypted.

#EXTM3U
#EXT-X-VERSION:4
#EXT-X-ALLOW-CACHE:NO
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-TARGETDURATION:9
#EXT-X-KEY:METHOD=AES-128,
URI="https://wamsbayclus001kd-hs.chinacloudapp.cn/HlsHandler.ashx?
     kid=da3813af-55e6-48e7-aa9f-a4d6031f7b4d",
        IV=0XD7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7
#EXT-X-PROGRAM-DATE-TIME:1970-01-01T00:00:00.000+00:00
#EXTINF:8.425708,no-desc
Fragments(video=0,format=m3u8-aapl)
#EXT-X-ENDLIST

Note

如果打算在 Safari 中播放 AES 加密的 HLS,请参阅此博客If you plan to play an AES-encrypted HLS in Safari, see this blog.

从密钥传送服务请求密钥Request the key from the key delivery service

以下代码演示如何使用密钥传送 Uri(从清单提取)和令牌,向媒体服务密钥传送服务发送请求。The following code shows how to send a request to the Media Services key delivery service by using a key delivery Uri (that was extracted from the manifest) and a token. (本文不讨论如何从 STS 获取 SWT。)(This article doesn't explain how to get SWTs from an STS.)

    private byte[] GetDeliveryKey(Uri keyDeliveryUri, string token)
    {
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(keyDeliveryUri);

        request.Method = "POST";
        request.ContentType = "text/xml";
        if (!string.IsNullOrEmpty(token))
        {
            request.Headers[AuthorizationHeader] = token;
        }
        request.ContentLength = 0;

        var response = request.GetResponse();

        var stream = response.GetResponseStream();
        if (stream == null)
        {
            throw new NullReferenceException("Response stream is null");
        }

        var buffer = new byte[256];
        var length = 0;
        while (stream.CanRead && length <= buffer.Length)
        {
            var nexByte = stream.ReadByte();
            if (nexByte == -1)
            {
                break;
            }
            buffer[length] = (byte)nexByte;
            length++;
        }
        response.Close();

        // AES keys must be exactly 16 bytes (128 bits).
        var key = new byte[length];
        Array.Copy(buffer, key, length);
        return key;
    }

在 .NET 中使用 AES-128 保护内容Protect your content with AES-128 by using .NET

创建和配置 Visual Studio 项目Create and configure a Visual Studio project

  1. 设置开发环境,并根据使用 .NET 进行媒体服务开发中所述,在 app.config 文件中填充连接信息。Set up your development environment, and populate the app.config file with connection information, as described in Media Services development with .NET.

  2. 将以下元素添加到 app.config 文件中定义的 appSettings:Add the following elements to appSettings, as defined in your app.config file:

    <add key="Issuer" value="http://testissuer.com"/>
    <add key="Audience" value="urn:test"/>
    

示例Example

使用本部分中所示的代码覆盖 Program.cs 文件中的代码。Overwrite the code in your Program.cs file with the code shown in this section.

Note

不同媒体服务策略的策略数限制为 1,000,000 个(例如,Locator 策略或 ContentKeyAuthorizationPolicy 就是如此)。There is a limit of 1,000,000 policies for different Media Services policies (for example, for Locator policy or ContentKeyAuthorizationPolicy). 如果始终使用相同的天数/访问权限,请使用相同的策略 ID。Use the same policy ID if you always use the same days/access permissions. 例如,适用于需要长期保留使用的定位符的策略(非上传策略)。An example is policies for locators that are intended to remain in place for a long time (non-upload policies). 有关详细信息,请参阅使用媒体服务 .NET SDK 管理资产和相关的实体中的“限制访问策略”部分。For more information, see the "Limit access policies" section in Manage assets and related entities with the Media Services .NET SDK.

请务必将变量更新为指向输入文件所在的文件夹。Make sure to update variables to point to folders where your input files are located.

using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using Microsoft.WindowsAzure.MediaServices.Client;
using System.Threading;
using Microsoft.WindowsAzure.MediaServices.Client.ContentKeyAuthorization;
using Microsoft.WindowsAzure.MediaServices.Client.DynamicEncryption;

namespace DynamicEncryptionWithAES
{
    class Program
    {
        // Read values from the App.config file.
        static string _AADTenantDomain =
            ConfigurationManager.AppSettings["AMSAADTenantDomain"];
        static string _RESTAPIEndpoint =
            ConfigurationManager.AppSettings["AMSRESTAPIEndpoint"];
        static string _AMSClientId =
            ConfigurationManager.AppSettings["AMSClientId"];
        static string _AMSClientSecret =
            ConfigurationManager.AppSettings["AMSClientSecret"];

        // A Uri describing the issuer of the token.  
        // Must match the value in the token for the token to be considered valid.
        private static readonly Uri _sampleIssuer =
            new Uri(ConfigurationManager.AppSettings["Issuer"]);
        // The Audience or Scope of the token.  
        // Must match the value in the token for the token to be considered valid.
        private static readonly Uri _sampleAudience =
            new Uri(ConfigurationManager.AppSettings["Audience"]);

        // Field for service context.
        private static CloudMediaContext _context = null;

        private static readonly string _mediaFiles =
            Path.GetFullPath(@"../..\Media");

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

        static void Main(string[] args)
        {
            AzureAdTokenCredentials tokenCredentials =
                new AzureAdTokenCredentials(_AADTenantDomain,
                    new AzureAdClientSymmetricKey(_AMSClientId, _AMSClientSecret),
                    AzureEnvironments.AzureChinaCloudEnvironment);

            var tokenProvider = new AzureAdTokenProvider(tokenCredentials);

            _context = new CloudMediaContext(new Uri(_RESTAPIEndpoint), tokenProvider);

            bool tokenRestriction = true;
            string tokenTemplateString = null;

            IAsset asset = UploadFileAndCreateAsset(_singleMP4File);
            Console.WriteLine("Uploaded asset: {0}", asset.Id);

            IAsset encodedAsset = EncodeToAdaptiveBitrateMP4Set(asset);
            Console.WriteLine("Encoded asset: {0}", encodedAsset.Id);

            IContentKey key = CreateEnvelopeTypeContentKey(encodedAsset);
            Console.WriteLine("Created key {0} for the asset {1} ", key.Id, encodedAsset.Id);
            Console.WriteLine();

            if (tokenRestriction)
                tokenTemplateString = AddTokenRestrictedAuthorizationPolicy(key);
            else
                AddOpenAuthorizationPolicy(key);

            Console.WriteLine("Added authorization policy: {0}", key.AuthorizationPolicyId);
            Console.WriteLine();

            CreateAssetDeliveryPolicy(encodedAsset, key);
            Console.WriteLine("Created asset delivery policy. \n");
            Console.WriteLine();

            if (tokenRestriction && !String.IsNullOrEmpty(tokenTemplateString))
            {
                // Deserializes a string containing an Xml representation of a TokenRestrictionTemplate
                // back into a TokenRestrictionTemplate class instance.
                TokenRestrictionTemplate tokenTemplate =
                    TokenRestrictionTemplateSerializer.Deserialize(tokenTemplateString);

                // Generate a test token based on the data in the given TokenRestrictionTemplate.
                // Note, you need to pass the key id Guid because we specified 
                // TokenClaim.ContentKeyIdentifierClaim in during the creation of TokenRestrictionTemplate.
                Guid rawkey = EncryptionUtils.GetKeyIdAsGuid(key.Id);

                //The GenerateTestToken method returns the token without the word “Bearer” in front
                //so you have to add it in front of the token string. 
                string testToken = TokenRestrictionTemplateSerializer.GenerateTestToken(tokenTemplate, null, rawkey, DateTime.UtcNow.AddDays(365));

                Console.WriteLine("The authorization token is:\nBearer {0}", testToken);
                Console.WriteLine();
            }
            // You can use the bit.ly/aesplayer Flash player to test the URL 
            // (with open authorization policy). 
            // Paste the URL and click the Update button to play the video. 
            //
            string URL = GetStreamingOriginLocator(encodedAsset);
            Console.WriteLine("Smooth Streaming Url: {0}/manifest", URL);
            Console.WriteLine();
            Console.WriteLine("HLS Url: {0}/manifest(format=m3u8-aapl)", URL);
            Console.WriteLine();

            Console.ReadLine();
        }

        static public IAsset UploadFileAndCreateAsset(string singleFilePath)
        {
            if (!File.Exists(singleFilePath))
            {
                Console.WriteLine("File does not exist.");
                return null;
            }

            var assetName = Path.GetFileNameWithoutExtension(singleFilePath);
            IAsset inputAsset = _context.Assets.Create(assetName, AssetCreationOptions.StorageEncrypted);

            var assetFile = inputAsset.AssetFiles.Create(Path.GetFileName(singleFilePath));

            Console.WriteLine("Created assetFile {0}", assetFile.Name);

            var policy = _context.AccessPolicies.Create(
                                    assetName,
                                    TimeSpan.FromDays(30),
                                    AccessPermissions.Write | AccessPermissions.List);

            var locator = _context.Locators.CreateLocator(LocatorType.Sas, inputAsset, policy);

            Console.WriteLine("Upload {0}", assetFile.Name);

            assetFile.Upload(singleFilePath);
            Console.WriteLine("Done uploading {0}", assetFile.Name);

            locator.Delete();
            policy.Delete();

            return inputAsset;
        }

        static public IAsset EncodeToAdaptiveBitrateMP4Set(IAsset asset)
        {
            // Declare a new job.
            IJob job = _context.Jobs.Create("Media Encoder Standard Job");
            // Get a media processor reference, and pass to it the name of the 
            // processor to use for the specific task.
            IMediaProcessor processor = GetLatestMediaProcessorByName("Media Encoder Standard");

            // Create a task with the encoding details, using a string preset.
            // In this case "H264 Multiple Bitrate 720p" preset is used.
            ITask task = job.Tasks.AddNew("My encoding task",
                processor,
                "H264 Multiple Bitrate 720p",
                TaskOptions.None);

            // Specify the input asset to be encoded.
            task.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 not encrypted. 
            task.OutputAssets.AddNew("Output asset",
                AssetCreationOptions.None);

            job.StateChanged += new EventHandler<JobStateChangedEventArgs>(JobStateChanged);
            job.Submit();
            job.GetExecutionProgressTask(CancellationToken.None).Wait();

            return job.OutputMediaAssets[0];
        }

        private static IMediaProcessor GetLatestMediaProcessorByName(string mediaProcessorName)
        {
            var processor = _context.MediaProcessors.Where(p => p.Name == mediaProcessorName).
            ToList().OrderBy(p => new Version(p.Version)).LastOrDefault();

            if (processor == null)
                throw new ArgumentException(string.Format("Unknown media processor", mediaProcessorName));

            return processor;
        }

        static public IContentKey CreateEnvelopeTypeContentKey(IAsset asset)
        {
            // Create envelope encryption content key
            Guid keyId = Guid.NewGuid();
            byte[] contentKey = GetRandomBuffer(16);

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

            // Associate the key with the asset.
            asset.ContentKeys.Add(key);

            return key;
        }

        static public void AddOpenAuthorizationPolicy(IContentKey contentKey)
        {
            // Create ContentKeyAuthorizationPolicy with Open restrictions 
            // and create authorization policy             
            IContentKeyAuthorizationPolicy policy = _context.
                                    ContentKeyAuthorizationPolicies.
                                    CreateAsync("Open Authorization Policy").Result;

            List<ContentKeyAuthorizationPolicyRestriction> restrictions =
                new List<ContentKeyAuthorizationPolicyRestriction>();

            ContentKeyAuthorizationPolicyRestriction restriction =
                new ContentKeyAuthorizationPolicyRestriction
                {
                    Name = "HLS Open Authorization Policy",
                    KeyRestrictionType = (int)ContentKeyRestrictionType.Open,
                    Requirements = null // no requirements needed for HLS
                };

            restrictions.Add(restriction);

            IContentKeyAuthorizationPolicyOption policyOption =
                _context.ContentKeyAuthorizationPolicyOptions.Create(
                "policy",
                ContentKeyDeliveryType.BaselineHttp,
                restrictions,
                "");

            policy.Options.Add(policyOption);

            // Add ContentKeyAutorizationPolicy to ContentKey
            contentKey.AuthorizationPolicyId = policy.Id;
            IContentKey updatedKey = contentKey.UpdateAsync().Result;
            Console.WriteLine("Adding Key to Asset: Key ID is " + updatedKey.Id);
        }

        public static string AddTokenRestrictedAuthorizationPolicy(IContentKey contentKey)
        {
            string tokenTemplateString = GenerateTokenRequirements();

            IContentKeyAuthorizationPolicy policy = _context.
                                    ContentKeyAuthorizationPolicies.
                                    CreateAsync("HLS token restricted authorization policy").Result;

            List<ContentKeyAuthorizationPolicyRestriction> restrictions =
                    new List<ContentKeyAuthorizationPolicyRestriction>();

            ContentKeyAuthorizationPolicyRestriction restriction =
                    new ContentKeyAuthorizationPolicyRestriction
                    {
                        Name = "Token Authorization Policy",
                        KeyRestrictionType = (int)ContentKeyRestrictionType.TokenRestricted,
                        Requirements = tokenTemplateString
                    };

            restrictions.Add(restriction);

            //You could have multiple options 
            IContentKeyAuthorizationPolicyOption policyOption =
                _context.ContentKeyAuthorizationPolicyOptions.Create(
                    "Token option for HLS",
                    ContentKeyDeliveryType.BaselineHttp,
                    restrictions,
                    null  // no key delivery data is needed for HLS
                    );

            policy.Options.Add(policyOption);

            // Add ContentKeyAutorizationPolicy to ContentKey
            contentKey.AuthorizationPolicyId = policy.Id;
            IContentKey updatedKey = contentKey.UpdateAsync().Result;
            Console.WriteLine("Adding Key to Asset: Key ID is " + updatedKey.Id);

            return tokenTemplateString;
        }

        static public void CreateAssetDeliveryPolicy(IAsset asset, IContentKey key)
        {
            Uri keyAcquisitionUri = key.GetKeyDeliveryUrl(ContentKeyDeliveryType.BaselineHttp);

            string envelopeEncryptionIV = Convert.ToBase64String(GetRandomBuffer(16));

            // The following policy configuration specifies: 
            //   key url that will have KID=<Guid> appended to the envelope and
            //   the Initialization Vector (IV) to use for the envelope encryption.
            Dictionary<AssetDeliveryPolicyConfigurationKey, string> assetDeliveryPolicyConfiguration =
                new Dictionary<AssetDeliveryPolicyConfigurationKey, string>
            {
                        {AssetDeliveryPolicyConfigurationKey.EnvelopeKeyAcquisitionUrl, keyAcquisitionUri.ToString()}
            };

            IAssetDeliveryPolicy assetDeliveryPolicy =
                _context.AssetDeliveryPolicies.Create(
                            "AssetDeliveryPolicy",
                            AssetDeliveryPolicyType.DynamicEnvelopeEncryption,
                            AssetDeliveryProtocol.SmoothStreaming | AssetDeliveryProtocol.HLS | AssetDeliveryProtocol.Dash,
                            assetDeliveryPolicyConfiguration);

            // Add AssetDelivery Policy to the asset
            asset.DeliveryPolicies.Add(assetDeliveryPolicy);
            Console.WriteLine();
            Console.WriteLine("Adding Asset Delivery Policy: " +
                assetDeliveryPolicy.AssetDeliveryPolicyType);
        }

        static public string GetStreamingOriginLocator(IAsset asset)
        {

            // Get a reference to the streaming manifest file from the  
            // collection of files in the asset. 

            var assetFile = asset.AssetFiles.Where(f => f.Name.ToLower().
                                        EndsWith(".ism")).
                                        FirstOrDefault();

            // Create a 30-day readonly access policy. 
            // You cannot create a streaming locator using an AccessPolicy that includes write or delete permissions.            
            IAccessPolicy policy = _context.AccessPolicies.Create("Streaming policy",
                TimeSpan.FromDays(30),
                AccessPermissions.Read);

            // Create a locator to the streaming content on an origin. 
            ILocator originLocator = _context.Locators.CreateLocator(LocatorType.OnDemandOrigin, asset,
                policy,
                DateTime.UtcNow.AddMinutes(-5));

            // Create a URL to the manifest file. 
            return originLocator.Path + assetFile.Name;
        }

        static private string GenerateTokenRequirements()
        {
            TokenRestrictionTemplate template = new TokenRestrictionTemplate(TokenType.SWT);

            template.PrimaryVerificationKey = new SymmetricVerificationKey();
            template.AlternateVerificationKeys.Add(new SymmetricVerificationKey());
            template.Audience = _sampleAudience.ToString();
            template.Issuer = _sampleIssuer.ToString();

            template.RequiredClaims.Add(TokenClaim.ContentKeyIdentifierClaim);

            return TokenRestrictionTemplateSerializer.Serialize(template);
        }

        static private void JobStateChanged(object sender, JobStateChangedEventArgs e)
        {
            Console.WriteLine(string.Format("{0}\n  State: {1}\n  Time: {2}\n\n",
                ((IJob)sender).Name,
                e.CurrentState,
                DateTime.UtcNow.ToString(@"yyyy_M_d__hh_mm_ss")));
        }

        static private byte[] GetRandomBuffer(int size)
        {
            byte[] randomBytes = new byte[size];
            using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())
            {
                rng.GetBytes(randomBytes);
            }

            return randomBytes;
        }
    }
}

媒体服务学习路径Media Services learning paths

媒体服务 v3(最新版本)Media Services v3 (latest)

查看最新版本的 Azure 媒体服务!Check out the latest version of Azure Media Services!

媒体服务 v2(旧版)Media Services v2 (legacy)