fix(drm): add track ID fallback for mp4decrypt CBCS zero-KID content

Some CBCS-encrypted content has an all-zeros default_KID in the tenc box while the real KID is only in the PSSH boxes. mp4decrypt matches keys against the tenc KID, so it silently skips decryption when the provided KID doesn't match. This adds a track ID-based key fallback when a zero KID is detected, matching the existing shaka-packager zero-KID fallback behavior.
This commit is contained in:
Andy
2026-03-25 14:36:26 -06:00
parent d4bc095f96
commit 23466cae8b
2 changed files with 38 additions and 0 deletions

View File

@@ -356,6 +356,25 @@ class PlayReady:
key_hex = key if isinstance(key, str) else key.hex() key_hex = key if isinstance(key, str) else key.hex()
key_args.extend(["--key", f"{kid_hex}:{key_hex}"]) key_args.extend(["--key", f"{kid_hex}:{key_hex}"])
# Also pass keys by track ID as fallback for CBCS content where the
# tenc box may have an all-zeros default_KID (common with HLS/FairPlay),
# causing mp4decrypt to fail matching KID-based keys silently.
if self.content_keys:
first_key = next(iter(self.content_keys.values()))
first_key_hex = first_key if isinstance(first_key, str) else first_key.hex()
try:
with open(path, "rb") as f:
header = f.read(200_000)
tenc_idx = header.find(b"tenc")
if tenc_idx >= 0:
tenc_data = header[tenc_idx + 4:] # after box type
version = tenc_data[0]
default_kid = tenc_data[8:24] if version >= 1 else tenc_data[6:22]
if default_kid == b"\x00" * 16:
key_args.extend(["--key", f"1:{first_key_hex}"])
except OSError:
pass
cmd = [ cmd = [
str(binaries.Mp4decrypt), str(binaries.Mp4decrypt),
"--show-progress", "--show-progress",

View File

@@ -276,6 +276,25 @@ class Widevine:
key_hex = key if isinstance(key, str) else key.hex() key_hex = key if isinstance(key, str) else key.hex()
key_args.extend(["--key", f"{kid_hex}:{key_hex}"]) key_args.extend(["--key", f"{kid_hex}:{key_hex}"])
# Also pass keys by track ID as fallback for CBCS content where the
# tenc box may have an all-zeros default_KID (common with HLS/FairPlay),
# causing mp4decrypt to fail matching KID-based keys silently.
if self.content_keys:
first_key = next(iter(self.content_keys.values()))
first_key_hex = first_key if isinstance(first_key, str) else first_key.hex()
try:
with open(path, "rb") as f:
header = f.read(200_000)
tenc_idx = header.find(b"tenc")
if tenc_idx >= 0:
tenc_data = header[tenc_idx + 4:] # after box type
version = tenc_data[0]
default_kid = tenc_data[8:24] if version >= 1 else tenc_data[6:22]
if default_kid == b"\x00" * 16:
key_args.extend(["--key", f"1:{first_key_hex}"])
except OSError:
pass
cmd = [ cmd = [
str(binaries.Mp4decrypt), str(binaries.Mp4decrypt),
"--show-progress", "--show-progress",