From c92ec3c48774793bf77e689d2470184f87fad343 Mon Sep 17 00:00:00 2001 From: Leo Vasanko Date: Thu, 13 Aug 2026 00:20:07 +0000 Subject: [PATCH] fix(video): make rotation and short/HDR clips convert reliably - Accept a keyframe with pts as well as dts, so all-intra or short HDR clips are not rejected as No frames found. - Round resized video dimensions to multiples of 2 (width) and 4 (height) so planar 4:2:0 YUV rotation always works. - Use abs(frame.rotation) when swapping display dimensions, so both +90 and -90 rotation matrices report the correct orientation. --- mediapreview/backends/video.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/mediapreview/backends/video.py b/mediapreview/backends/video.py index 60521b7..d06cd0f 100644 --- a/mediapreview/backends/video.py +++ b/mediapreview/backends/video.py @@ -15,8 +15,8 @@ try: import av import numpy as np except ImportError: # pragma: no cover - optional video extra - av = None - np = None + av = None # type: ignore[assignment] + np = None # type: ignore[assignment] def _rotate_frame_yuv(frame, k): @@ -78,21 +78,22 @@ def process_video(path, *, maxsize, quality): istream.codec_context.skip_frame = "NONKEY" icontainer.seek((icontainer.duration or 0) // 8) for frame in icontainer.decode(istream): - if frame.dts is not None: + if frame.dts is not None or frame.pts is not None: break else: raise RuntimeError("No frames found in video") - # Resize frame to thumbnail size + # Resize frame to thumbnail size. Keep dimensions even for planar + # 4:2:0 chroma subsampling, which _rotate_frame_yuv expects. # Capture display dimensions before resize (accounting for rotation) disp_w = frame.width disp_h = frame.height - if frame.rotation in (90, 270): + if abs(frame.rotation) in (90, 270): disp_w, disp_h = disp_h, disp_w if frame.width > maxsize or frame.height > maxsize: scale_factor = min(maxsize / frame.width, maxsize / frame.height) - new_width = int(frame.width * scale_factor) - new_height = int(frame.height * scale_factor) + new_width = int(frame.width * scale_factor) // 2 * 2 + new_height = int(frame.height * scale_factor) // 4 * 4 frame = frame.reformat(width=new_width, height=new_height) # Apply display-matrix rotation if present