From 98aa3ef38bdc76a7e3089cde230fa8b50b09befa Mon Sep 17 00:00:00 2001 From: Nirvana Date: Fri, 16 Jan 2026 15:19:40 +0100 Subject: [PATCH] Reformat --- .../base/utils/mp4_parser.py | 56 ++++++++++++++----- 1 file changed, 43 insertions(+), 13 deletions(-) diff --git a/lib/streaming_providers/base/utils/mp4_parser.py b/lib/streaming_providers/base/utils/mp4_parser.py index 698e614..fb6faec 100644 --- a/lib/streaming_providers/base/utils/mp4_parser.py +++ b/lib/streaming_providers/base/utils/mp4_parser.py @@ -105,14 +105,15 @@ class MP4PSSHExtractor: if box_type == b'tenc': # Parse tenc box + logger.debug(f"Found tenc box at offset {offset}, size {box_size}") tenc_kid = MP4PSSHExtractor._parse_tenc_box(data[offset:offset + box_size]) if tenc_kid and tenc_kid not in kids: kids.append(tenc_kid) logger.debug(f"Found KID from tenc box: {tenc_kid}") elif box_size > 8: # Recursively search inside container boxes - # Check if this is a container box (moov, trak, mdia, minf, stbl, sinf, schi) - container_boxes = {b'moov', b'trak', b'mdia', b'minf', b'stbl', b'sinf', b'schi'} + # Check if this is a container box (moov, trak, mdia, minf, stbl, sinf, schi, encv) + container_boxes = {b'moov', b'trak', b'mdia', b'minf', b'stbl', b'stsd', b'encv', b'sinf', b'schi'} if box_type in container_boxes: # Recursively search inside the container inner_data = data[offset + 8:offset + box_size] @@ -132,8 +133,9 @@ class MP4PSSHExtractor: def _parse_tenc_box(tenc_bytes: bytes) -> Optional[str]: """Parse a tenc box and extract the default key ID""" try: - # Minimum tenc box size is 28 bytes (short form) or 32 bytes (full) - if len(tenc_bytes) < 28: + # Minimum tenc box size is 20 bytes for version 0 + if len(tenc_bytes) < 20: + logger.debug(f"tenc box too small: {len(tenc_bytes)} bytes") return None # Parse box header @@ -141,34 +143,62 @@ class MP4PSSHExtractor: box_type = tenc_bytes[4:8] if box_type != b'tenc': + logger.debug(f"Not a tenc box, type: {box_type}") return None version = tenc_bytes[8] + logger.debug(f"tenc box version: {version}") + + # According to ISO/IEC 23001-7, tenc box structure: + # Bytes 0-3: size + # Bytes 4-7: 'tenc' + # Byte 8: version + # Bytes 9-11: flags + # Byte 12: is_encrypted (bit 0) + reserved (bits 1-7) + # Byte 13: default_iv_size + # Bytes 14-29: default_KID (16 bytes) - # Determine KID offset based on version if version == 0: - # Version 0: flags (3 bytes) + reserved/is_encrypted (1 byte) + default_iv_size (1 byte) - # KID starts at byte 14 + # For version 0, KID is at offset 14 kid_offset = 14 else: - # Version 1: more complex structure - # For now, assume similar offset + # Version 1 has additional fields kid_offset = 14 + # Skip optional fields if version == 1 + # Byte 14: pattern + # Byte 15: crypt_byte_block + # Byte 16: skip_byte_block + if version == 1 and len(tenc_bytes) >= 32: + kid_offset = 17 + if kid_offset + 16 > len(tenc_bytes): + logger.debug(f"tenc box too small for KID: {len(tenc_bytes)} bytes, need {kid_offset + 16}") return None kid_bytes = tenc_bytes[kid_offset:kid_offset + 16] - kid_uuid = str(uuid.UUID(bytes=kid_bytes)) - # Convert to lowercase without dashes (same format as PSSH KIDs) - clean_kid = kid_uuid.replace("-", "").lower() - return clean_kid + # Debug: print hex of KID bytes + hex_kid = kid_bytes.hex() + logger.debug(f"Raw KID bytes: {hex_kid}") + + # Format as UUID + try: + kid_uuid = str(uuid.UUID(bytes=kid_bytes)) + # Convert to lowercase without dashes (same format as PSSH KIDs) + clean_kid = kid_uuid.replace("-", "").lower() + logger.debug(f"Parsed KID: {clean_kid} (UUID: {kid_uuid})") + return clean_kid + except Exception as e: + logger.debug(f"Failed to parse KID bytes as UUID: {e}") + # Fallback: just return hex + return hex_kid except Exception as e: logger.debug(f"Failed to parse tenc box: {e}") return None + # [Keep the rest of the methods the same as before...] @staticmethod def _extract_from_moov(moov_data: bytes) -> List[PSSHData]: """Extract PSSH boxes from moov container"""