video-dev / hls.js

HLS.js is a JavaScript library that plays HLS in browsers with support for MSE.
https://hlsjs.video-dev.org/demo
Other
14.66k stars 2.56k forks source link

DRM Video Playback in Samsung Tizen TV #4962

Closed Shihab-Github closed 1 week ago

Shihab-Github commented 1 year ago

What do you want to do with Hls.js?

I have a video streaming web application and I've used hlsjs for playing video. It can play drm protected videos on web browser but it fails to play drm protected video on Samsung Tizen tv. What happens is, the app does not throw any error but it just gets stuck in the player. I am using widevine drm.

What have you tried so far?

I have followed the code from hls documentation. It looks like this:

getDrmLicense(single_movie, function () { PLAYER.player_options.emeEnabled = true; PLAYER.player_options.widevineLicenseUrl = drm_license_url; PLAYER.start(url, bongo_id, true); });

robwalch commented 1 year ago

I have a video streaming web application and I've used hlsjs for playing video. It can play drm protected videos on web browser but it fails to play drm protected video on Samsung Tizen tv.

You can contribute to DRM work-in-progress by building, testing, and providing feedback on #4930

robwalch commented 1 year ago

If you'd like to report this as a bug, please fill out the Bug Report Template as part of your issue, making sure to include:

If the issue is related to your stream, and you cannot share the stream, please include all the information we would need to reproduce the issue. This includes how to generate a stream that reproduces the issue.

JaroslavHerber commented 1 year ago

Any reason you don't use Samsungs build-in AVPlay ? It supports a lot more Codecs than HLS.js https://developer.samsung.com/smarttv/develop/api-references/samsung-product-api-references/avplay-api.html

robwalch commented 1 year ago

Hi @Shihab-Github,

What happens is, the app does not throw any error but it just gets stuck in the player. I am using widevine drm.

There's also #5018 which may address error handling for your use-case. You can test these changes using the netlify/hls-js-dev/deploy-preview checks at the bottom of the PR.

grabofus commented 2 weeks ago

Hi @robwalch, I've ran into a potentially related issue, but it seems to be limited to Tizen 2017 Widevine only. (Although it being this specific might be why this couldn't be reproduced before).

I think it's been introduced as part of this PR, which was merged a few weeks before this issue got raised: https://github.com/video-dev/hls.js/pull/4861

From what I've found so far it seems like there is a deadlock in the player at this Promise.all() call: https://github.com/video-dev/hls.js/blob/5705fe26c81848fbfda3e0a8b2df7724f1e2e120/src/controller/base-stream-controller.ts#L874 Tizen 2017 doesn't seem to fire the keystatuseschange event until any video is buffered, which causes the keyLoadingPromise promise to hang, which holds back the video from being buffered.

https://sample-videos-zyrkp2nj.s3.eu-west-1.amazonaws.com/test-20240828/index.html https://sample-videos-zyrkp2nj.s3.eu-west-1.amazonaws.com/test-20240828/index.fixed.html I've created two sample pages with latest (1.5.11) hls.js version with this slight difference, and the TV is now able to play the stream. image

Could you provide some context as to why we need to await the keyLoadingPromise prior to pushing the video, and if you have any potential solutions?

Thank you!

Edit: I realize this issue currently lacks the necessary fields from Bug Report Template, but one of the Checklist items was to make sure to no duplicate issues that already exist here. Would you like me to raise a separate issue with all the required info?

robwalch commented 2 weeks ago

Hi @grabofus,

Would you like me to raise a separate issue with all the required info?

No worries. Your description fits the title and gives the issue something we can act on so unless @Shihab-Github responds with reproduction steps, we can proceed here.

I've created two sample pages with latest (1.5.11) hls.js version with this slight difference, and the TV is now able to play the stream.

The latest release is 1.5.15. Have you tried it? There are some improvements for playlists and media with Widevine and PlayReady keys.

We do not want to change or reverse the changes made in #4861 to process keys and segments in parallel.

The keyLoadingPromise Promise is blocked by the keyUsablePromise in eme-controller:

https://github.com/video-dev/hls.js/blob/5705fe26c81848fbfda3e0a8b2df7724f1e2e120/src/controller/eme-controller.ts#L842-L869

A change will be needed to eme-controller in loadKey to return a promise that resolves earlier or a larger change to generateRequestWithPreferredKeySession: Promise<MediaKeySessionContext> | never and parts of the controller that that would impact to handle key-status changes outside of the the session context promise.

https://github.com/video-dev/hls.js/blob/5705fe26c81848fbfda3e0a8b2df7724f1e2e120/src/controller/eme-controller.ts#L420-L459

robwalch commented 2 weeks ago

A change will be needed to eme-controller in loadKey to return a promise that resolves earlier

Here's an example:

diff --git a/src/controller/eme-controller.ts b/src/controller/eme-controller.ts
index dfa30d249..c76ca89de 100644
--- a/src/controller/eme-controller.ts
+++ b/src/controller/eme-controller.ts
@@ -426,38 +426,41 @@ class EMEController extends Logger implements ComponentAPI {

     this.log(`Starting session for key ${keyDetails}`);

-    let keySessionContextPromise = this.keyIdToKeySessionPromise[keyId];
-    if (!keySessionContextPromise) {
-      keySessionContextPromise = this.keyIdToKeySessionPromise[keyId] =
-        this.getKeySystemForKeyPromise(decryptdata).then(
-          ({ keySystem, mediaKeys }) => {
+    let keyContextPromise = this.keyIdToKeySessionPromise[keyId];
+    if (!keyContextPromise) {
+      keyContextPromise = this.getKeySystemForKeyPromise(decryptdata).then(
+        ({ keySystem, mediaKeys }) => {
+          this.throwIfDestroyed();
+          this.log(
+            `Handle encrypted media sn: ${data.frag.sn} ${data.frag.type}: ${data.frag.level} using key ${keyDetails}`,
+          );
+
+          return this.attemptSetMediaKeys(keySystem, mediaKeys).then(() => {
             this.throwIfDestroyed();
-            this.log(
-              `Handle encrypted media sn: ${data.frag.sn} ${data.frag.type}: ${data.frag.level} using key ${keyDetails}`,
-            );
-
-            return this.attemptSetMediaKeys(keySystem, mediaKeys).then(() => {
-              this.throwIfDestroyed();
-              const keySessionContext = this.createMediaKeySessionContext({
-                keySystem,
-                mediaKeys,
-                decryptdata,
-              });
-              const scheme = 'cenc';
-              return this.generateRequestWithPreferredKeySession(
-                keySessionContext,
-                scheme,
-                decryptdata.pssh,
-                'playlist-key',
-              );
+            return this.createMediaKeySessionContext({
+              keySystem,
+              mediaKeys,
+              decryptdata,
             });
-          },
-        );
+          });
+        },
+      );
+
+      const keySessionContextPromise = (this.keyIdToKeySessionPromise[keyId] =
+        keyContextPromise.then((keySessionContext) => {
+          const scheme = 'cenc';
+          return this.generateRequestWithPreferredKeySession(
+            keySessionContext,
+            scheme,
+            decryptdata.pssh,
+            'playlist-key',
+          );
+        }));

       keySessionContextPromise.catch((error) => this.handleError(error));
     }

-    return keySessionContextPromise;
+    return keyContextPromise;
   }

   private throwIfDestroyed(message = 'Invalid state'): void | never {

Does this resolve the issue for you?

grabofus commented 2 weeks ago

The latest release is 1.5.15. Have you tried it? There are some improvements for playlists and media with Widevine and PlayReady keys.

You're right, my comment was incorrect. The demo page I've provided uses 1.5.15 and the issue is reproducible there.

I'll try the suggested change out soon

grabofus commented 2 weeks ago

@robwalch your proposed change works on the TV! 🚀 thank you for the quick response!

robwalch commented 2 weeks ago

@robwalch your proposed change works on the TV! 🚀 thank you for the quick response!

Hi @grabofus. Great! Would you mind submitting a PR with the change so that we can get that in v1.6?

grabofus commented 2 weeks ago

PR raised ~