mirror of
https://github.com/unshackle-dl/unshackle.git
synced 2026-06-10 03:02:09 +00:00
fix(dash): inherit SegmentTemplate attributes across AdaptationSet/Representation
A SegmentTemplate can sit at both the AdaptationSet and Representation levels, with shared attrs like @timescale only on the outer node. The parser picked one or the other, dropping the outer node when an inner existed - so @timescale defaulted to 1 and only the first segment was emitted. Merge instead: Representation node as base, inheriting any attribute or SegmentTimeline it omits from the AdaptationSet node (per ISO/IEC 23009-1).
This commit is contained in:
@@ -7,7 +7,7 @@ import math
|
|||||||
import re
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
import sys
|
import sys
|
||||||
from copy import copy
|
from copy import deepcopy
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Callable, Optional, Union
|
from typing import Any, Callable, Optional, Union
|
||||||
@@ -587,6 +587,32 @@ class DASH:
|
|||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _merge_segment_templates(adaptation_set: Element, representation: Element) -> Optional[Element]:
|
||||||
|
"""
|
||||||
|
Build the effective SegmentTemplate for a Representation by cascading the
|
||||||
|
AdaptationSet > Representation levels (ISO/IEC 23009-1 5.3.9.1).
|
||||||
|
|
||||||
|
The Representation-level node, when present, is the base; attributes and the
|
||||||
|
SegmentTimeline child it does not declare are inherited from the AdaptationSet-level
|
||||||
|
node. Returns None if no SegmentTemplate exists at either level.
|
||||||
|
"""
|
||||||
|
levels = [node.find("SegmentTemplate") for node in (adaptation_set, representation)]
|
||||||
|
present = [node for node in levels if node is not None]
|
||||||
|
if not present:
|
||||||
|
return None
|
||||||
|
|
||||||
|
merged = deepcopy(present[-1])
|
||||||
|
for ancestor in reversed(present[:-1]):
|
||||||
|
for attr, value in ancestor.attrib.items():
|
||||||
|
if merged.get(attr) is None:
|
||||||
|
merged.set(attr, value)
|
||||||
|
if merged.find("SegmentTimeline") is None:
|
||||||
|
timeline = ancestor.find("SegmentTimeline")
|
||||||
|
if timeline is not None:
|
||||||
|
merged.append(deepcopy(timeline))
|
||||||
|
return merged
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _get_period_segments(
|
def _get_period_segments(
|
||||||
period: Element,
|
period: Element,
|
||||||
@@ -621,9 +647,7 @@ class DASH:
|
|||||||
period_duration = period.get("duration") or manifest.get("mediaPresentationDuration")
|
period_duration = period.get("duration") or manifest.get("mediaPresentationDuration")
|
||||||
init_data: Optional[bytes] = None
|
init_data: Optional[bytes] = None
|
||||||
|
|
||||||
segment_template = representation.find("SegmentTemplate")
|
segment_template = DASH._merge_segment_templates(adaptation_set, representation)
|
||||||
if segment_template is None:
|
|
||||||
segment_template = adaptation_set.find("SegmentTemplate")
|
|
||||||
|
|
||||||
segment_list = representation.find("SegmentList")
|
segment_list = representation.find("SegmentList")
|
||||||
if segment_list is None:
|
if segment_list is None:
|
||||||
@@ -639,7 +663,6 @@ class DASH:
|
|||||||
track_kid: Optional[UUID] = None
|
track_kid: Optional[UUID] = None
|
||||||
|
|
||||||
if segment_template is not None:
|
if segment_template is not None:
|
||||||
segment_template = copy(segment_template)
|
|
||||||
start_number = int(segment_template.get("startNumber") or 1)
|
start_number = int(segment_template.get("startNumber") or 1)
|
||||||
end_number = int(segment_template.get("endNumber") or 0) or None
|
end_number = int(segment_template.get("endNumber") or 0) or None
|
||||||
segment_timeline = segment_template.find("SegmentTimeline")
|
segment_timeline = segment_template.find("SegmentTimeline")
|
||||||
|
|||||||
Reference in New Issue
Block a user