Azure Media Services DRM与第三方统一流媒体服务器的集成
概述 我们正在构建一个音乐流应用程序,主要针对Android设备。其主要目的是销售音乐订阅,同时保护我们为最终用户提供的媒体资产,因此DRM解决方案是我们基础设施的核心。我们的设置如下所示: 核心组成部分:Azure Media Services DRM与第三方统一流媒体服务器的集成,azure,drm,azure-media-services,exoplayer,Azure,Drm,Azure Media Services,Exoplayer,概述 我们正在构建一个音乐流应用程序,主要针对Android设备。其主要目的是销售音乐订阅,同时保护我们为最终用户提供的媒体资产,因此DRM解决方案是我们基础设施的核心。我们的设置如下所示: 核心组成部分: 带有Exoplayer的Android移动应用程序 作为流媒体服务器的统一流媒体服务器 Azure媒体服务用于DRM服务 Azure Media Services Sdk中的密钥生成实用程序 以下是我们采取的步骤: 步骤1:编码 我们使用ffmpeg将各种媒体资源编码为不同的mp4比特率输出
- 256kbps
- 192kbps
- 128kbps
- 96kbps
- 64kbps
- 首先,我们使用以下示例输出运行AZURE.NET SDK以生成密钥:
- 然后,我们使用统一流媒体mp4split工具用上面从Azure.NET SDK突出显示的信息加密我们的媒体资产。下面显示了为Widevine许可证加密资产的命令,并提供了有关该命令的更多详细信息
22ABE1FA13CDF844A7460D7DD3A31645 MVEP833L3JMUANVTY3JUQ==的内容键变为
315129F37DCBDE399468DBD3CB7254B9 我们仍然不知道从Azure.NET SDK得到的响应中PSSH值是多少。统一流媒体文档说明如下:
02-07 12:58:58.458 16454-5913/com.google.android.exoplayer2.demo E/OMXMaster: A component of name 'OMX.qcom.audio.decoder.aac' already exists, ignoring this one.
02-07 12:59:02.892 16454-5811/com.google.android.exoplayer2.demo E/ExoPlayerImplInternal: Renderer error.
com.google.android.exoplayer2.ExoPlaybackException
at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.shouldWaitForKeys(MediaCodecRenderer.java:709)
at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.feedInputBuffer(MediaCodecRenderer.java:650)
at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.render(MediaCodecRenderer.java:490)
at com.google.android.exoplayer2.ExoPlayerImplInternal.doSomeWork(ExoPlayerImplInternal.java:464)
at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:300)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:168)
at android.os.HandlerThread.run(HandlerThread.java:61)
at com.google.android.exoplayer2.util.PriorityHandlerThread.run(PriorityHandlerThread.java:40)
Caused by: com.google.android.exoplayer2.drm.DrmSession$DrmSessionException: com.google.android.exoplayer2.upstream.HttpDataSource$InvalidResponseCodeException: Response code: 400
at com.google.android.exoplayer2.drm.DefaultDrmSessionManager.onError(DefaultDrmSessionManager.java:594)
at com.google.android.exoplayer2.drm.DefaultDrmSessionManager.onKeysError(DefaultDrmSessionManager.java:589)
at com.google.android.exoplayer2.drm.DefaultDrmSessionManager.onKeyResponse(DefaultDrmSessionManager.java:549)
at com.google.android.exoplayer2.drm.DefaultDrmSessionManager.access$900(DefaultDrmSessionManager.java:49)
at com.google.android.exoplayer2.drm.DefaultDrmSessionManager$PostResponseHandler.handleMessage(DefaultDrmSessionManager.java:669)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:168)
at android.os.HandlerThread.run(HandlerThread.java:61)
at com.google.android.exoplayer2.util.PriorityHandlerThread.run(PriorityHandlerThread.java:40)
Caused by: com.google.android.exoplayer2.upstream.HttpDataSource$InvalidResponseCodeException: Response code: 400
at com.google.android.exoplayer2.upstream.DefaultHttpDataSource.open(DefaultHttpDataSource.java:212)
at com.google.android.exoplayer2.upstream.DataSourceInputStream.checkOpened(DataSourceInputStream.java:101)
at com.google.android.exoplayer2.upstream.DataSourceInputStream.read(DataSourceInputStream.java:81)
at com.google.android.exoplayer2.upstream.DataSourceInputStream.read(DataSourceInputStream.java:75)
at com.google.android.exoplayer2.util.Util.toByteArray(Util.java:118)
at com.google.android.exoplayer2.drm.HttpMediaDrmCallback.executePost(HttpMediaDrmCallback.java:106)
at com.google.android.exoplayer2.drm.HttpMediaDrmCallback.executeKeyRequest(HttpMediaDrmCallback.java:91)
at com.google.android.exoplayer2.drm.DefaultDrmSessionManager$PostRequestHandler.handleMessage(DefaultDrmSessionManager.java:692)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:168)
at android.os.HandlerThread.run(HandlerThread.java:61)
02-07 12:59:02.896 16454-16454/com.google.android.exoplayer2.demo E/EventLogger: playerFailed [7.76]
com.google.android.exoplayer2.ExoPlaybackException
at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.shouldWaitForKeys(MediaCodecRenderer.java:709)
at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.feedInputBuffer(MediaCodecRenderer.java:650)
at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.render(MediaCodecRenderer.java:490)
at com.google.android.exoplayer2.ExoPlayerImplInternal.doSomeWork(ExoPlayerImplInternal.java:464)
at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:300)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:168)
at android.os.HandlerThread.run(HandlerThread.java:61)
at com.google.android.exoplayer2.util.PriorityHandlerThread.run(PriorityHandlerThread.java:40)
Caused by: com.google.android.exoplayer2.drm.DrmSession$DrmSessionException: com.google.android.exoplayer2.upstream.HttpDataSource$InvalidResponseCodeException: Response code: 400
at com.google.android.exoplayer2.drm.DefaultDrmSessionManager.onError(DefaultDrmSessionManager.java:594)
at com.google.android.exoplayer2.drm.DefaultDrmSessionManager.onKeysError(DefaultDrmSessionManager.java:589)
at com.google.android.exoplayer2.drm.DefaultDrmSessionManager.onKeyResponse(DefaultDrmSessionManager.java:549)
at com.google.android.exoplayer2.drm.DefaultDrmSessionManager.access$900(DefaultDrmSessionManager.java:49)
at com.google.android.exoplayer2.drm.DefaultDrmSessionManager$PostResponseHandler.handleMessage(DefaultDrmSessionManager.java:669)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:168)
at android.os.HandlerThread.run(HandlerThread.java:61)
at com.google.android.exoplayer2.util.PriorityHandlerThread.run(PriorityHandlerThread.java:40)
Caused by: com.google.android.exoplayer2.upstream.HttpDataSource$InvalidResponseCodeException: Response code: 400
at com.google.android.exoplayer2.upstream.DefaultHttpDataSource.open(DefaultHttpDataSource.java:212)
at com.google.android.exoplayer2.upstream.DataSourceInputStream.checkOpened(DataSourceInputStream.java:101)
at com.google.android.exoplayer2.upstream.DataSourceInputStream.read(DataSourceInputStream.java:81)
at com.google.android.exoplayer2.upstream.DataSourceInputStream.read(DataSourceInputStream.java:75)
at com.google.android.exoplayer2.util.Util.toByteArray(Util.java:118)
at com.google.android.exoplayer2.drm.HttpMediaDrmCallback.executePost(HttpMediaDrmCallback.java:106)
at com.google.android.exoplayer2.drm.HttpMediaDrmCallback.executeKeyRequest(HttpMediaDrmCallback.java:91)
at com.google.android.exoplayer2.drm.DefaultDrmSessionManager$PostRequestHandler.handleMessage(DefaultDrmSessionManager.java:692)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:168)
at android.os.HandlerThread.run(HandlerThread.java:61)
许可证服务器提供的DRM特定数据(Widevine PSSH数据)。
可以是Base64字符串,也可以是包含已解码Base64数据的文件。文件名必须包含“.”
请注意,LA_URL(许可证获取URL)不会在“pssh”框中显示,通常在支持Winevine模块化的DASH播放器中硬编码。建议的设置是使用正确的URL
我们正在寻求帮助,以便从我们收到的Azure.NETSDK输出中找出PSSH数据是什么。与此同时,我们一直在使用AUTH_POLICY_ID(转换为Base64)作为mp4split命令中的PSSH
当我们将以上所有内容放在一起时,我们使用的mp4split脚本将变成:
#!/bin/bash
KID=22ABE1FA13CDF844A7460D7DD3A31645
CEK=315129F37DCBDE399468DBD3CB7254B9
LAURL="https://music.keydelivery.mediaservices.windows.net/Widevine/? KID=fae1ab22-cd13-44f8-a746-0d7dd3a31645"
PSSH="Py/sFdlKvkmfibVDG8PewQ=="
mp4split --license-key=usp/license.key -o musicfile.ism \
--mpd.inline_drm \
--widevine.key=${KID}:${CEK} \
--widevine.license_server_url=${LAURL} \
--widevine.drm_specific_data=${PSSH} \
musicfile-64kbps.mp4
aws s3 cp musicfiles.ism s3://output-bucket/
aws s3 cp musicfiles-64kbps.mp4 s3://output-bucket/
注:
{
"name": "Music Tests",
"uri": "http://mozart.musicfiles.com/auth/media/musicfiles.ism/.mpd",
"drm_scheme": "widevine",
"drm_license_url": "https://music.keydelivery.mediaservices.windows.net/Widevine/?KID=fae1ab22-cd13-44f8-a746-0d7dd3a31645"
}
其中:
URI-是我们的统一流媒体服务器端点
DRM_许可证_URI-是我们的Azure.NET SDK提供的widevine服务器url
在上传、编码和加密媒体资产后,我们会在这一阶段出现错误。Android应用程序中的错误如下:
02-07 12:58:58.458 16454-5913/com.google.android.exoplayer2.demo E/OMXMaster: A component of name 'OMX.qcom.audio.decoder.aac' already exists, ignoring this one.
02-07 12:59:02.892 16454-5811/com.google.android.exoplayer2.demo E/ExoPlayerImplInternal: Renderer error.
com.google.android.exoplayer2.ExoPlaybackException
at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.shouldWaitForKeys(MediaCodecRenderer.java:709)
at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.feedInputBuffer(MediaCodecRenderer.java:650)
at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.render(MediaCodecRenderer.java:490)
at com.google.android.exoplayer2.ExoPlayerImplInternal.doSomeWork(ExoPlayerImplInternal.java:464)
at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:300)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:168)
at android.os.HandlerThread.run(HandlerThread.java:61)
at com.google.android.exoplayer2.util.PriorityHandlerThread.run(PriorityHandlerThread.java:40)
Caused by: com.google.android.exoplayer2.drm.DrmSession$DrmSessionException: com.google.android.exoplayer2.upstream.HttpDataSource$InvalidResponseCodeException: Response code: 400
at com.google.android.exoplayer2.drm.DefaultDrmSessionManager.onError(DefaultDrmSessionManager.java:594)
at com.google.android.exoplayer2.drm.DefaultDrmSessionManager.onKeysError(DefaultDrmSessionManager.java:589)
at com.google.android.exoplayer2.drm.DefaultDrmSessionManager.onKeyResponse(DefaultDrmSessionManager.java:549)
at com.google.android.exoplayer2.drm.DefaultDrmSessionManager.access$900(DefaultDrmSessionManager.java:49)
at com.google.android.exoplayer2.drm.DefaultDrmSessionManager$PostResponseHandler.handleMessage(DefaultDrmSessionManager.java:669)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:168)
at android.os.HandlerThread.run(HandlerThread.java:61)
at com.google.android.exoplayer2.util.PriorityHandlerThread.run(PriorityHandlerThread.java:40)
Caused by: com.google.android.exoplayer2.upstream.HttpDataSource$InvalidResponseCodeException: Response code: 400
at com.google.android.exoplayer2.upstream.DefaultHttpDataSource.open(DefaultHttpDataSource.java:212)
at com.google.android.exoplayer2.upstream.DataSourceInputStream.checkOpened(DataSourceInputStream.java:101)
at com.google.android.exoplayer2.upstream.DataSourceInputStream.read(DataSourceInputStream.java:81)
at com.google.android.exoplayer2.upstream.DataSourceInputStream.read(DataSourceInputStream.java:75)
at com.google.android.exoplayer2.util.Util.toByteArray(Util.java:118)
at com.google.android.exoplayer2.drm.HttpMediaDrmCallback.executePost(HttpMediaDrmCallback.java:106)
at com.google.android.exoplayer2.drm.HttpMediaDrmCallback.executeKeyRequest(HttpMediaDrmCallback.java:91)
at com.google.android.exoplayer2.drm.DefaultDrmSessionManager$PostRequestHandler.handleMessage(DefaultDrmSessionManager.java:692)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:168)
at android.os.HandlerThread.run(HandlerThread.java:61)
02-07 12:59:02.896 16454-16454/com.google.android.exoplayer2.demo E/EventLogger: playerFailed [7.76]
com.google.android.exoplayer2.ExoPlaybackException
at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.shouldWaitForKeys(MediaCodecRenderer.java:709)
at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.feedInputBuffer(MediaCodecRenderer.java:650)
at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.render(MediaCodecRenderer.java:490)
at com.google.android.exoplayer2.ExoPlayerImplInternal.doSomeWork(ExoPlayerImplInternal.java:464)
at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:300)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:168)
at android.os.HandlerThread.run(HandlerThread.java:61)
at com.google.android.exoplayer2.util.PriorityHandlerThread.run(PriorityHandlerThread.java:40)
Caused by: com.google.android.exoplayer2.drm.DrmSession$DrmSessionException: com.google.android.exoplayer2.upstream.HttpDataSource$InvalidResponseCodeException: Response code: 400
at com.google.android.exoplayer2.drm.DefaultDrmSessionManager.onError(DefaultDrmSessionManager.java:594)
at com.google.android.exoplayer2.drm.DefaultDrmSessionManager.onKeysError(DefaultDrmSessionManager.java:589)
at com.google.android.exoplayer2.drm.DefaultDrmSessionManager.onKeyResponse(DefaultDrmSessionManager.java:549)
at com.google.android.exoplayer2.drm.DefaultDrmSessionManager.access$900(DefaultDrmSessionManager.java:49)
at com.google.android.exoplayer2.drm.DefaultDrmSessionManager$PostResponseHandler.handleMessage(DefaultDrmSessionManager.java:669)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:168)
at android.os.HandlerThread.run(HandlerThread.java:61)
at com.google.android.exoplayer2.util.PriorityHandlerThread.run(PriorityHandlerThread.java:40)
Caused by: com.google.android.exoplayer2.upstream.HttpDataSource$InvalidResponseCodeException: Response code: 400
at com.google.android.exoplayer2.upstream.DefaultHttpDataSource.open(DefaultHttpDataSource.java:212)
at com.google.android.exoplayer2.upstream.DataSourceInputStream.checkOpened(DataSourceInputStream.java:101)
at com.google.android.exoplayer2.upstream.DataSourceInputStream.read(DataSourceInputStream.java:81)
at com.google.android.exoplayer2.upstream.DataSourceInputStream.read(DataSourceInputStream.java:75)
at com.google.android.exoplayer2.util.Util.toByteArray(Util.java:118)
at com.google.android.exoplayer2.drm.HttpMediaDrmCallback.executePost(HttpMediaDrmCallback.java:106)
at com.google.android.exoplayer2.drm.HttpMediaDrmCallback.executeKeyRequest(HttpMediaDrmCallback.java:91)
at com.google.android.exoplayer2.drm.DefaultDrmSessionManager$PostRequestHandler.handleMessage(DefaultDrmSessionManager.java:692)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:168)
at android.os.HandlerThread.run(HandlerThread.java:61)
Azure媒体服务中的错误代码在此处表示以下响应代码400:
400错误请求请求包含无效信息,请求无效
由于以下原因之一而被拒绝:
-指定了不受支持的API版本。最新
版本,请参阅媒体服务REST API开发的设置-API
未指定媒体服务的版本。有关如何
指定API版本,请参阅使用连接到媒体服务
媒体服务RESTAPI。注
如果您使用.NET或Java SDK连接到媒体服务,
每当您尝试执行某些操作时,都会为您指定API版本
对媒体服务采取行动
- 已指定未定义的属性。属性名称在错误消息中。仅限作为给定对象成员的属性
可以指定实体。请参阅Azure媒体服务REST API参考
获取实体及其属性的列表
- 指定了无效的属性值。属性名称在错误消息中。有关有效的属性类型,请参见上一链接 以及他们的价值观
- 缺少属性值,该值是必需的。
- 指定的URL的一部分包含错误值
- 试图更新WriteOnce属性
- 试图创建一个作业,该作业的输入资产具有未指定或无法确定的主资产文件
- 有人试图掩盖事实
GET https://music.keydelivery.mediaservices.windows.net/Widevine/?KID=fae1ab22-cd13-44f8-a746-0d7dd3a31645
<?xml version="1.0" encoding="utf-8"?> <Error> <Message>License challenge is missing from the request body.</Message> <Code>NoLicenseChallenge</Code> </Error>