Exoplayer: Play ClearKey DRM encrypted video from local storage

Created on 17 Nov 2020  路  6Comments  路  Source: google/ExoPlayer

[REQUIRED] Searched documentation and issues

[REQUIRED] Question

I have implemented video playback using ClearKey DRM in my app. The keys required are available offline so I'm using LocalMediaDrmCallback for creating DRM callback and the online playback working fine.
For download and offline playback, I am aware of ExoPlayer's caching mechanism but I'm using a third party download manager which downloads the encrypted video from server as it is.
When I tried to play the downloaded video from local storage it throws IllegalStateException.

This is how I created DrmSessionManager

 fun buildDrmSessionManager(uuid: UUID, multiSession: Boolean, id:String, value:String): DefaultDrmSessionManager<FrameworkMediaCrypto?> {
        val drmCallback = LocalMediaDrmCallback("{\"keys\":[{\"kty\":\"oct\",\"k\":\"${value}\",\"kid\":\"${id}\"}],\"type\":\"temporary\"}".toByteArray())
        val mediaDrm = FrameworkMediaDrm.newInstance(uuid)
        return DefaultDrmSessionManager(uuid, mediaDrm, drmCallback, null, multiSession)
    }

Code for creating MediaSource from local storage

val dataSourceFactory: DataSource.Factory = FileDataSource.Factory()
val drmSessionManager = buildDrmSessionManager(UUID, false, "key_id", "key")
val videoSource: MediaSource = ProgressiveMediaSource.Factory(dataSourceFactory)
                    .setDrmSessionManager(drmSessionManager)
                    .createMediaSource(videoUriLocalStorage)

Is this approach correct ?
Is it possible to play the DRM videos from local storage ?

question

Most helpful comment

I've dug a bit more into this and found a couple of things:

Firstly, your media file doesn't have a pssh box which is where the encryption info should be - this means that when it's played standalone (i.e. without a DASH/HLS manifest, which can carry the pssh info separately), ExoPlayer doesn't know that it's encrypted (and also doesn't know what key ID to try and use to decrypt it). This results in ExoPlayer trying to play the media without using the DrmSessionManager you're providing - causing the failure you see.

Secondly there was a bug in ProgressiveMediaPeriod in version 2.11.4 meaning it didn't set some DRM-related fields on Format correctly. This was fixed in https://github.com/google/ExoPlayer/commit/4736a102f875c4a8b7ac53e7c9d75fe85032d7e7 which is available from 2.11.5 onwards.

So I think you need to do two things:

  • Fix your media to include a pssh box - I'm not an MP4Box or shaka expert, so I'm afraid that's outside the scope of what I can help you with.
  • Upgrade to at least 2.11.5 (this is hopefully fairly painless)

Once you've done both those things, it'll hopefully work.


My instructions above about using shaka packager to create a file don't work btw - I'll remove them from the comment. I didn't realise it was automatically adding 5s of clear lead and I wasn't playing the video past 5s before concluding it worked. I only spotted this when accidentally changing the keys and seeing it still play - sorry for misleading you there.

All 6 comments

There isn't enough information here to help you.

When I tried to play the downloaded video from local storage it throws IllegalStateException.

It would be useful to see a full stack trace to understand where this is coming from. We also need to know what version of ExoPlayer you're using.

Is it possible to play the DRM videos from local storage ?

Yes it's possible.

The fastest way for us to help is if you can provide a minimal reproducible example that demonstrates the problem in a way that we can build locally.

This could be an Android Studio project on GitHub, or zipped up and sent to dev.[email protected] using a subject in the format "Issue #1234", where "#1234" should be replaced with your issue number. Please also update this issue to indicate you鈥檝e done this.

Thanks for your reply @icbaker
I have created a sample repo for the issue : https://github.com/ruthwikkk/DRMOffline. Please check

Thanks for the sample project, I can reproduce the error you're seeing.

I don't know for sure, but I think the keys you're passing might be incorrect? I see the same error when I replace the key and key ID in your project with nonsense values.

How did you create your encrypted MP4? Maybe try encrypting a new video from scratch using shaka?

Thanks for your reply @icbaker

The same file when steaming from server working fine. I used the same key_id and key for online playback.

I encrypted the Mp4 using Mp4Box.

MP4Box -crypt drm_file.xml input_video.mp4 -out enc_video.mp4

the XML file used

<GPACDRM type="CENC AES-CTR">
<CrypTrack IsEncrypted="1" constant_IV_size="16" constant_IV="0x0a610676cb88f302d10ac8bc66e039ed" saiSavedBox="senc">
    <key KID="0x5846270325df6d8756b397fbb53c07db" value="0xa08524c412bed0841246a7879922863e"/>
  </CrypTrack>
</GPACDRM>

I've dug a bit more into this and found a couple of things:

Firstly, your media file doesn't have a pssh box which is where the encryption info should be - this means that when it's played standalone (i.e. without a DASH/HLS manifest, which can carry the pssh info separately), ExoPlayer doesn't know that it's encrypted (and also doesn't know what key ID to try and use to decrypt it). This results in ExoPlayer trying to play the media without using the DrmSessionManager you're providing - causing the failure you see.

Secondly there was a bug in ProgressiveMediaPeriod in version 2.11.4 meaning it didn't set some DRM-related fields on Format correctly. This was fixed in https://github.com/google/ExoPlayer/commit/4736a102f875c4a8b7ac53e7c9d75fe85032d7e7 which is available from 2.11.5 onwards.

So I think you need to do two things:

  • Fix your media to include a pssh box - I'm not an MP4Box or shaka expert, so I'm afraid that's outside the scope of what I can help you with.
  • Upgrade to at least 2.11.5 (this is hopefully fairly painless)

Once you've done both those things, it'll hopefully work.


My instructions above about using shaka packager to create a file don't work btw - I'll remove them from the comment. I didn't realise it was automatically adding 5s of clear lead and I wasn't playing the video past 5s before concluding it worked. I only spotted this when accidentally changing the keys and seeing it still play - sorry for misleading you there.

Yes it's working now.
Thanks for your suggestions @icbaker

I have updated ExoPlayer to 2.11.5, then changed the video generation script.
I'm posting the changed script for reference.

<GPACDRM type="CENC AES-CTR">
  <DRMInfo type="pssh" version="1">
    <BS ID128="1077efecc0b24d02ace33c1e52e2fb4b"/>
    <BS bits="32" value="1"/>
    <BS ID128="cd7eb9ff88f34caeb06185b00024e4c2"/>
  </DRMInfo>
  <CrypTrack IV_size="8" first_IV="0xbb5738fe08f11341" isEncrypted="1" saiSavedBox="senc" trackID="1">
    <key KID="0xcd7eb9ff88f34caeb06185b00024e4c2" value="0x63cb5f7184dd4b689a5c5ff11ee6a328"/>
  </CrypTrack>
</GPACDRM>
Was this page helpful?
0 / 5 - 0 ratings

Related issues

petitTrung picture petitTrung  路  3Comments

qeadsw picture qeadsw  路  3Comments

eneim picture eneim  路  3Comments

Ufosek picture Ufosek  路  3Comments

mkaflowski picture mkaflowski  路  3Comments