mirror of
https://github.com/unshackle-dl/unshackle.git
synced 2026-03-10 08:29:00 +00:00
feat(video): detect interlaced scan type from MPD manifests
This commit is contained in:
@@ -151,6 +151,11 @@ class DASH:
|
||||
if not track_fps and segment_base is not None:
|
||||
track_fps = segment_base.get("timescale")
|
||||
|
||||
scan_type = None
|
||||
scan_type_str = get("scanType")
|
||||
if scan_type_str and scan_type_str.lower() == "interlaced":
|
||||
scan_type = Video.ScanType.INTERLACED
|
||||
|
||||
track_args = dict(
|
||||
range_=self.get_video_range(
|
||||
codecs, findall("SupplementalProperty"), findall("EssentialProperty")
|
||||
@@ -159,6 +164,7 @@ class DASH:
|
||||
width=get("width") or 0,
|
||||
height=get("height") or 0,
|
||||
fps=track_fps or None,
|
||||
scan_type=scan_type,
|
||||
)
|
||||
elif content_type == "audio":
|
||||
track_type = Audio
|
||||
|
||||
@@ -153,7 +153,12 @@ class Episode(Title):
|
||||
# likely a movie or HD source, so it's most likely widescreen so
|
||||
# 16:9 canvas makes the most sense.
|
||||
resolution = int(primary_video_track.width * (9 / 16))
|
||||
name += f" {resolution}p"
|
||||
# Determine scan type suffix - default to "p", use "i" only if explicitly interlaced
|
||||
scan_suffix = "p"
|
||||
scan_type = getattr(primary_video_track, 'scan_type', None)
|
||||
if scan_type and str(scan_type).lower() == "interlaced":
|
||||
scan_suffix = "i"
|
||||
name += f" {resolution}{scan_suffix}"
|
||||
|
||||
# Service (use track source if available)
|
||||
if show_service:
|
||||
|
||||
@@ -88,7 +88,12 @@ class Movie(Title):
|
||||
# likely a movie or HD source, so it's most likely widescreen so
|
||||
# 16:9 canvas makes the most sense.
|
||||
resolution = int(primary_video_track.width * (9 / 16))
|
||||
name += f" {resolution}p"
|
||||
# Determine scan type suffix - default to "p", use "i" only if explicitly interlaced
|
||||
scan_suffix = "p"
|
||||
scan_type = getattr(primary_video_track, 'scan_type', None)
|
||||
if scan_type and str(scan_type).lower() == "interlaced":
|
||||
scan_suffix = "i"
|
||||
name += f" {resolution}{scan_suffix}"
|
||||
|
||||
# Service (use track source if available)
|
||||
if show_service:
|
||||
|
||||
@@ -186,6 +186,10 @@ class Video(Track):
|
||||
# for some reason there's no Dolby Vision info tag
|
||||
raise ValueError(f"The M3U Range Tag '{tag}' is not a supported Video Range")
|
||||
|
||||
class ScanType(str, Enum):
|
||||
PROGRESSIVE = "progressive"
|
||||
INTERLACED = "interlaced"
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*args: Any,
|
||||
@@ -195,6 +199,7 @@ class Video(Track):
|
||||
width: Optional[int] = None,
|
||||
height: Optional[int] = None,
|
||||
fps: Optional[Union[str, int, float]] = None,
|
||||
scan_type: Optional[Video.ScanType] = None,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
"""
|
||||
@@ -232,6 +237,8 @@ class Video(Track):
|
||||
raise TypeError(f"Expected height to be a {int}, not {height!r}")
|
||||
if not isinstance(fps, (str, int, float, type(None))):
|
||||
raise TypeError(f"Expected fps to be a {str}, {int}, or {float}, not {fps!r}")
|
||||
if not isinstance(scan_type, (Video.ScanType, type(None))):
|
||||
raise TypeError(f"Expected scan_type to be a {Video.ScanType}, not {scan_type!r}")
|
||||
|
||||
self.codec = codec
|
||||
self.range = range_ or Video.Range.SDR
|
||||
@@ -256,6 +263,7 @@ class Video(Track):
|
||||
except Exception as e:
|
||||
raise ValueError("Expected fps to be a number, float, or a string as numerator/denominator form, " + str(e))
|
||||
|
||||
self.scan_type = scan_type
|
||||
self.needs_duration_fix = False
|
||||
|
||||
def __str__(self) -> str:
|
||||
|
||||
Reference in New Issue
Block a user