Криптоключ недоступен - ExoPlayer

Итак, я пытаюсь воспроизвести зашифрованный контент в файле Dash (.mpd), упакованном с помощью Shaka Packager и зашифрованном с помощью метода CENC. Мультимедиа абсолютно нормально воспроизводится на Shaka Player, но я не могу заставить его воспроизводиться на ExoPlayer в Android. Во время игры 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 имеет ограничение Minimum 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);

И команда, использованная при упаковке видео MP4 с использованием Shaka Packager, была следующей:

.\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 Session Manager. Буду очень благодарен за любую помощь.
Заранее спасибо.


person Soumyadeep Ghosh    schedule 20.03.2020    source источник


Ответы (2)


Наиболее вероятная причина заключается в том, что метод LocalMediaDrmCallback ожидает, что ключ и key_id будут в кодировке base64url.

Вы можете скрыть свой ключ и key_id с помощью онлайн-инструмента, такого как:

Вы также можете увидеть программный пример в этом обсуждении проблемы GitHub: https://github.com/google/ExoPlayer/issues/3856#issuecomment-366197586.

person Mick    schedule 23.03.2020

Я потратил много времени на изучение исключения CryptoKey not available Exception.

Я обнаружил, что это исключение происходит с некоторыми неправильными вещами.

  1. MediaDrmCallback - это плохо. При использовании системы ClearKey используйте LocalMediaDrmCallback или подклассы, НЕ МОЖЕТ с сетью.

  2. Ключевой ответ (kid & k) base64url реализует плохо, не включает '/' '=' '\ n' '+'

  3. Некоторые медиафайлы зашифрованы с использованием времени очистки. Мой параметр набора видео - 30 секунд, поэтому всегда происходит исключение, я думаю, что сеанс Android DRM или ключи имеют тайм-аут в памяти.

  4. Конфиги DrmSessionManager заданы неверно. обратите внимание, с setMultiSession он сломает ваш набор.

  5. Я исправляю это исключение с помощью:

    1. setMultiSession(true), true is for one req return one key, don't use "false"
    2. Заменить и реализовать другой MediaDrmCallback, реализовать One Req return One key с помощью Map ‹String, String›

Причины:

  1. Я думаю, что у некоторых устройств или сеансов DRM есть тайм-аут, если у вашего видео есть время очистки, и DRM будет воспроизводить чистый контент и зашифрованный контент. Когда начнется воспроизведение загрузки видео и начнется воспроизведение первого зашифрованного содержимого, сеанс DRM получит ключ дважды. поэтому первый используемый ключ не может загрузить ключ загрузки видео.

  2. Когда файл манифеста DASH содержит некоторые видео с разностным ключом, AUDIO, HD, SD или другим, при низкой или высокой скорости сети воспроизводимое видео будет изменено, и сеанс DRM будет расшифрован с помощью другого ключа, но я думаю, что изменение не будет найти правильный ключ.

  3. Когда я использую setMultiSession (false) - ›это означает Один ответ на запрос Все ключи и просто с LocalMediaDrmCallback (responseJson), мое видео будет воспроизводиться с ошибкой или хорошо, я думаю, что когда-нибудь устройство загрузит json и найдет первый ключ, или в другой раз с плохим ключ.

Я написал код и информацию об этой проблеме на моем веб-сайте: https://blackfire.mobi (китайский), см. чтобы исправить это.

Я думаю, что CryptoKey недоступен. Исключение - это так плохо, и напишите этот ответ за вас.

person Zhang Xiaohe    schedule 12.02.2021