androidx / media

Jetpack Media3 support libraries for media use cases, including ExoPlayer, an extensible media player for Android
https://developer.android.com/media/media3
Apache License 2.0
1.55k stars 373 forks source link

ExoPlayer ClearKey Issue #777

Closed flashworldnet closed 10 months ago

flashworldnet commented 10 months ago

I have a sample dash video stream which does not work with the ExoPlayer with ClearKey. But it does work without an issue in the JW Stream Tester (Link) with ClearKey. I have mentioned below the stream link and the keys.

Stream Link: https://cdnapisec.kaltura.com/p/2433871/sp/243387100/playManifest/protocol/https//entryId/1_pgssezc1/format/mpegdash/tags/mbr/f/a.mpd

Key ID: a07c5d499dcead0fb416fed5913967be Key: caee457911302478487e6680bf0b3d1b

Hoping for a solution.

Thank you

icbaker commented 10 months ago

Please provide the code you're using to configure ExoPlayer for this clearkey playback.

Note that you need to be careful to use URL safe base64 when encoding your keys (see also https://github.com/google/ExoPlayer/issues/4075#issuecomment-378270594). In particular your Key ID converts to the following non-URL-safe base64 (source) oHxdSZ3OrQ+0Fv7VkTlnvg==, but the + should be a - in a URL-safe base64 string (and the padding = are not required/should be removed).

flashworldnet commented 10 months ago

Thanks for the reply.

This is my code. I tried the Key ID both ways.

val drmCallback = LocalMediaDrmCallback("{\"keys\":[{\"kty\":\"oct\",\"k\":\"yu5FeREwJHhIfmaAvws9Gw\",\"kid\":\"oHxdSZ3OrQ-0Fv7VkTlnvg\"}],'type':\"temporary\"}".toByteArray())
val drmSessionManager = DefaultDrmSessionManager.Builder()
    .setPlayClearSamplesWithoutKeys(true)
    .setMultiSession(false)
    .setKeyRequestParameters(HashMap())
    .setUuidAndExoMediaDrmProvider(C.CLEARKEY_UUID, FrameworkMediaDrm.DEFAULT_PROVIDER)
    .build(drmCallback)
DashMediaSource.Factory(DownloadUtil.getHttpDataSourceFactory(requireContext()))
    .setDrmSessionManagerProvider { drmSessionManager }
    .createMediaSource(dashMediaItem)

The error I'm getting is this.

WVCdm-DrmFactory     E  Widevine Drm HAL: failed to create drm plugin, invalid crypto scheme
DrmHalAidl           E  uuid=[e2719d58a985b3c9 781ab030af78d30e] Failed to make drm plugin: 4
icbaker commented 10 months ago

The provided code is incomplete - please also include the interactions with ExoPlayer and details of what dashMediaItem looks like.

icbaker commented 10 months ago

You may also want to take a look at this (untested) example: https://github.com/androidx/media/issues/780#issuecomment-1787345578

flashworldnet commented 10 months ago

The provided code is incomplete - please also include the interactions with ExoPlayer and details of what dashMediaItem looks like.

This is the complete code.

val dashMediaItem = MediaItem.Builder()
     .setUri("https://cdnapisec.kaltura.com/p/2433871/sp/243387100/playManifest/protocol/https//entryId/1_pgssezc1/format/mpegdash/tags/mbr/f/a.mpd")
     .setMimeType(MimeTypes.APPLICATION_MPD)
     .setMediaMetadata(MediaMetadata.Builder().setTitle(defaultVideoTitle).build())
     .setTag(MediaItemTag(-1, defaultVideoTitle))
     .build()

val trackSelector = DefaultTrackSelector(requireContext())
val loadControl = DefaultLoadControl()

val drmCallback = LocalMediaDrmCallback("{\"keys\":[{\"kty\":\"oct\",\"k\":\"yu5FeREwJHhIfmaAvws9Gw\",\"kid\":\"oHxdSZ3OrQ-0Fv7VkTlnvg\"}],'type':\"temporary\"}".toByteArray())
val drmSessionManager = DefaultDrmSessionManager.Builder()
    .setPlayClearSamplesWithoutKeys(true)
    .setMultiSession(false)
    .setKeyRequestParameters(HashMap())
    .setUuidAndExoMediaDrmProvider(C.CLEARKEY_UUID, FrameworkMediaDrm.DEFAULT_PROVIDER)
    .build(drmCallback)
val mediaSource = DashMediaSource.Factory(DownloadUtil.getHttpDataSourceFactory(requireContext()))
    .setDrmSessionManagerProvider { drmSessionManager }
    .createMediaSource(dashMediaItem)

val simpleExoPlayer = ExoPlayer.Builder(requireContext())
    .setTrackSelector(trackSelector)
    .setLoadControl(loadControl)
    .setSeekForwardIncrementMs(10000L)
    .setSeekBackIncrementMs(10000L)
    .build()

val playerView = view.findViewById(R.id.player_view)
playerView.player = simpleExoPlayer
simpleExoPlayer.setMediaSource(mediaSource, true)
simpleExoPlayer.prepare()
simpleExoPlayer.play()
icbaker commented 10 months ago

Some observations:

In the DASH manifest you've linked, the ClearKey <ContentProtection schemeIdUri="urn:mpeg:dash:mp4protection:2011" value="cenc"/> nodes are missing the required default_KID parameter. See https://github.com/google/ExoPlayer/issues/9169#issuecomment-878297192.


In your JSON clearkey response you're using single quotes around type. I believe JSON requires double-quotes around keys:

Property names must be double-quoted strings

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON#objects_and_arrays

trinme commented 10 months ago

For those who have issue playing dash media with clearkey cause by no supported DRM or no default_KID can try this out. Create CustomDashManifetParser class that extend to DashManifestParser. Then override parseContentProtection value. Add your code to feed default_KID if no default value found. Then on player activity create mediasource using DashMediaSource and setManifetParser with CustomDashManifestParser earlier.

flashworldnet commented 10 months ago

For those who have issue playing dash media with clearkey cause by no supported DRM or no default_KID can try this out. Create CustomDashManifetParser class that extend to DashManifestParser. Then override parseContentProtection value. Add your code to feed default_KID if no default value found. Then on player activity create mediasource using DashMediaSource and setManifetParser with CustomDashManifestParser earlier.

Thanks for the reply. I will try this

Is there any example like this which I can refer?

trinme commented 10 months ago

You may also want to take a look at this (untested) example: #780 (comment)

Just as the example given above, add something like this.

String defaultKid = "TODO"
String clearkeyJsonResponse = "TODO";
DrmSessionManager clearkeyDrmSessionManager =
    new DefaultDrmSessionManager.Builder()
        .setUuidAndExoMediaDrmProvider(C.CLEARKEY_UUID, FrameworkMediaDrm.DEFAULT_PROVIDER)
        .build(
            new LocalMediaDrmCallback(clearkeyJsonResponse.getBytes(StandardCharsets.UTF_8)));
ExoPlayer player =
    new ExoPlayer.Builder(/* context= */ this)
        .setMediaSourceFactory(
            new DashMediaSource.Factory(new DefaultDashChunkSource.Factory(dataSourceFactory), dataSourceFactory)
                        .setManifestParser(new ClearkeyDashManifestParser(defaultKid))
                        .setDrmSessionManagerProvider(mediaItem -> clearkeyDrmSessionManager))
        .build();

String mpdUrl = "TODO";
player.addMediaItem(
    new MediaItem.Builder()
        .setUri(mpdUrl)
        .setDrmConfiguration(new MediaItem.DrmConfiguration.Builder(C.CLEARKEY_UUID).build())
        .build());
AmarnathCJD commented 10 months ago

https://github.com/androidx/media/issues/780#issuecomment-1793499036

please check this:)

flashworldnet commented 10 months ago

You may also want to take a look at this (untested) example: #780 (comment)

Just as the example given above, add something like this.

String defaultKid = "TODO"
String clearkeyJsonResponse = "TODO";
DrmSessionManager clearkeyDrmSessionManager =
    new DefaultDrmSessionManager.Builder()
        .setUuidAndExoMediaDrmProvider(C.CLEARKEY_UUID, FrameworkMediaDrm.DEFAULT_PROVIDER)
        .build(
            new LocalMediaDrmCallback(clearkeyJsonResponse.getBytes(StandardCharsets.UTF_8)));
ExoPlayer player =
    new ExoPlayer.Builder(/* context= */ this)
        .setMediaSourceFactory(
            new DashMediaSource.Factory(new DefaultDashChunkSource.Factory(dataSourceFactory), dataSourceFactory)
                        .setManifestParser(new ClearkeyDashManifestParser(defaultKid))
                        .setDrmSessionManagerProvider(mediaItem -> clearkeyDrmSessionManager))
        .build();

String mpdUrl = "TODO";
player.addMediaItem(
    new MediaItem.Builder()
        .setUri(mpdUrl)
        .setDrmConfiguration(new MediaItem.DrmConfiguration.Builder(C.CLEARKEY_UUID).build())
        .build());

I figured it out and it worked. Thanks for the help. Closing the issue.