加密密钥不可用 - ExoPlayer
Crypto Key not Available - ExoPlayer
所以我正在尝试播放 Dash 文件 (.mpd) 中的加密内容,该内容使用 Shaka Packager 打包并使用 CENC 方法加密。媒体在 Shaka Player 上播放非常好,但我无法在 Android 的 ExoPlayer 上播放它。播放时,Logcat 显示以下错误:
Caused by: android.media.MediaCodec$CryptoException: Crypto key not available
at android.media.MediaCodec.native_queueSecureInputBuffer(Native Method)
at android.media.MediaCodec.queueSecureInputBuffer(MediaCodec.java:2699)
at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.feedInputBuffer(MediaCodecRenderer.java:1188)
at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.render(MediaCodecRenderer.java:719)
at com.google.android.exoplayer2.ExoPlayerImplInternal.doSomeWork(ExoPlayerImplInternal.java:599)
at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:329)
at android.os.Handler.dispatchMessage(Handler.java:103)
at android.os.Looper.loop(Looper.java:237)
at android.os.HandlerThread.run(HandlerThread.java:67)
Build.Gradle 的最小 Sdk 限制为 API 21,因此签出,使用的代码是:
player = new SimpleExoPlayer.Builder(this).build();
ep.setPlayer(player);
DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(this, Util.getUserAgent(this, "AppName"));
Uri uri = Uri.parse(Tools.baseAddress+"VIDEO/"+i.getStringExtra("ModuleID")+"/index.php").buildUpon().appendQueryParameter("token", Tools.token).build();
String keyString = "{\"keys\":[{\"kty\":\"oct\",\"k\":\"76a6c65c5ea762046bd749a2e632ccbb\",\"kid\":\"a7e61c373e219033c21091fa607bf3b8\"}],'type':\"temporary\"}";
LocalMediaDrmCallback drmCallback = new LocalMediaDrmCallback(keyString.getBytes());
DrmSessionManager manager=null;
manager = new DefaultDrmSessionManager.Builder()
.setPlayClearSamplesWithoutKeys(true)
.setMultiSession(false)
.setUuidAndExoMediaDrmProvider(C.CLEARKEY_UUID, FrameworkMediaDrm.DEFAULT_PROVIDER)
.build(drmCallback);
MediaSource dashMediaSource = new DashMediaSource.Factory(dataSourceFactory).setDrmSessionManager(manager).createMediaSource(uri);
player = new SimpleExoPlayer.Builder(this).build();
ep.setPlayer(player);
player.prepare(dashMediaSource);
并且使用 Shaka Packager 打包 MP4 视频时使用的命令是:
.\packager input=videoplayback.mp4,stream=video,output=video.mp4 input=videoplayback.mp4,stream=audio,output=audio.mp4 --enable_raw_key_encryption --keys key_id=a7e61c373e219033c21091fa607bf3b8:key=76a6c65c5ea762046bd749a2e632ccbb --clear_lead 0 --mpd_output dash.mpd
我不确定密钥格式是否正确或 DRM 会话管理器是否已正确初始化。
如果有任何帮助,我将不胜感激。
提前致谢。
最可能的原因是 LocalMediaDrmCallback 方法需要密钥,并且 key_id 采用 base64url 编码。
您可以使用以下在线工具将您的密钥和 key_id 隐藏到此:
您还可以在此 GitHub 问题讨论中看到一个编程示例:https://github.com/google/ExoPlayer/issues/3856#issuecomment-366197586
我花了很长时间研究“CryptoKey 不可用”异常。
我发现这个异常发生在一些错误的事情上。
MediaDrmCallback 有问题。使用 ClearKey 系统时,使用 LocalMediaDrmCallback 或 sub 类,不能使用网络。
key response (kid & k) base64url实现不好,不包括'/' '=' '\n' '+'
一些媒体文件用clearlead时间加密,我的视频设置参数是30s所以它总是发生异常,我认为Android DRM会话或密钥在内存中超时。
DrmSessionManager 配置设置错误。注意“setMultiSession”它会破坏你的设置。
我用以下方法修复了这个异常:
- setMultiSession(true),true是针对一个reqreturn一键,不要用"false"
- 替换实现其他MediaDrmCallback,用Map
实现“One Req return One key”
原因:
我认为某些设备或 DRM 会话实现超时,如果您的视频有清晰的引导时间,DRM 将播放清晰内容和加密内容。当 Video load 开始播放和第一个加密内容播放时,DRM session 将获得两次 Key。所以使用的第一个键无法加载视频加载键。
当您的 DASH manifest 文件包含一些具有不同密钥的视频,AUDIO,HD,SD 或其他,当网络速度低或高时,播放的视频将改变并且 DRM 会话将与其他视频一起解密键,但我认为更改将找不到正确的键。
当我使用 setMultiSession(false) -> 这意味着“一个请求响应所有键”,并且使用 LocalMediaDrmCallback(responseJson) 时,我的视频会播放错误或播放良好,我想一些时间设备加载 json 并找到第一个密钥,或者其他时候用错误的密钥。
我已经在我的网站上写了一些关于这个问题的代码和信息:https://blackfire.mobi(中文),看看它来解决这个问题。
我认为“CryptoKey 不可用”异常非常严重,因此为您写下此回复。
所以我正在尝试播放 Dash 文件 (.mpd) 中的加密内容,该内容使用 Shaka Packager 打包并使用 CENC 方法加密。媒体在 Shaka Player 上播放非常好,但我无法在 Android 的 ExoPlayer 上播放它。播放时,Logcat 显示以下错误:
Caused by: android.media.MediaCodec$CryptoException: Crypto key not available
at android.media.MediaCodec.native_queueSecureInputBuffer(Native Method)
at android.media.MediaCodec.queueSecureInputBuffer(MediaCodec.java:2699)
at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.feedInputBuffer(MediaCodecRenderer.java:1188)
at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.render(MediaCodecRenderer.java:719)
at com.google.android.exoplayer2.ExoPlayerImplInternal.doSomeWork(ExoPlayerImplInternal.java:599)
at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:329)
at android.os.Handler.dispatchMessage(Handler.java:103)
at android.os.Looper.loop(Looper.java:237)
at android.os.HandlerThread.run(HandlerThread.java:67)
Build.Gradle 的最小 Sdk 限制为 API 21,因此签出,使用的代码是:
player = new SimpleExoPlayer.Builder(this).build();
ep.setPlayer(player);
DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(this, Util.getUserAgent(this, "AppName"));
Uri uri = Uri.parse(Tools.baseAddress+"VIDEO/"+i.getStringExtra("ModuleID")+"/index.php").buildUpon().appendQueryParameter("token", Tools.token).build();
String keyString = "{\"keys\":[{\"kty\":\"oct\",\"k\":\"76a6c65c5ea762046bd749a2e632ccbb\",\"kid\":\"a7e61c373e219033c21091fa607bf3b8\"}],'type':\"temporary\"}";
LocalMediaDrmCallback drmCallback = new LocalMediaDrmCallback(keyString.getBytes());
DrmSessionManager manager=null;
manager = new DefaultDrmSessionManager.Builder()
.setPlayClearSamplesWithoutKeys(true)
.setMultiSession(false)
.setUuidAndExoMediaDrmProvider(C.CLEARKEY_UUID, FrameworkMediaDrm.DEFAULT_PROVIDER)
.build(drmCallback);
MediaSource dashMediaSource = new DashMediaSource.Factory(dataSourceFactory).setDrmSessionManager(manager).createMediaSource(uri);
player = new SimpleExoPlayer.Builder(this).build();
ep.setPlayer(player);
player.prepare(dashMediaSource);
并且使用 Shaka Packager 打包 MP4 视频时使用的命令是:
.\packager input=videoplayback.mp4,stream=video,output=video.mp4 input=videoplayback.mp4,stream=audio,output=audio.mp4 --enable_raw_key_encryption --keys key_id=a7e61c373e219033c21091fa607bf3b8:key=76a6c65c5ea762046bd749a2e632ccbb --clear_lead 0 --mpd_output dash.mpd
我不确定密钥格式是否正确或 DRM 会话管理器是否已正确初始化。
如果有任何帮助,我将不胜感激。
提前致谢。
最可能的原因是 LocalMediaDrmCallback 方法需要密钥,并且 key_id 采用 base64url 编码。
您可以使用以下在线工具将您的密钥和 key_id 隐藏到此:
您还可以在此 GitHub 问题讨论中看到一个编程示例:https://github.com/google/ExoPlayer/issues/3856#issuecomment-366197586
我花了很长时间研究“CryptoKey 不可用”异常。
我发现这个异常发生在一些错误的事情上。
MediaDrmCallback 有问题。使用 ClearKey 系统时,使用 LocalMediaDrmCallback 或 sub 类,不能使用网络。
key response (kid & k) base64url实现不好,不包括'/' '=' '\n' '+'
一些媒体文件用clearlead时间加密,我的视频设置参数是30s所以它总是发生异常,我认为Android DRM会话或密钥在内存中超时。
DrmSessionManager 配置设置错误。注意“setMultiSession”它会破坏你的设置。
我用以下方法修复了这个异常:
- setMultiSession(true),true是针对一个reqreturn一键,不要用"false"
- 替换实现其他MediaDrmCallback,用Map
原因:
我认为某些设备或 DRM 会话实现超时,如果您的视频有清晰的引导时间,DRM 将播放清晰内容和加密内容。当 Video load 开始播放和第一个加密内容播放时,DRM session 将获得两次 Key。所以使用的第一个键无法加载视频加载键。
当您的 DASH manifest 文件包含一些具有不同密钥的视频,AUDIO,HD,SD 或其他,当网络速度低或高时,播放的视频将改变并且 DRM 会话将与其他视频一起解密键,但我认为更改将找不到正确的键。
当我使用 setMultiSession(false) -> 这意味着“一个请求响应所有键”,并且使用 LocalMediaDrmCallback(responseJson) 时,我的视频会播放错误或播放良好,我想一些时间设备加载 json 并找到第一个密钥,或者其他时候用错误的密钥。
我已经在我的网站上写了一些关于这个问题的代码和信息:https://blackfire.mobi(中文),看看它来解决这个问题。
我认为“CryptoKey 不可用”异常非常严重,因此为您写下此回复。