From 65237ed106b497436167633b18cc0c214d492d9a Mon Sep 17 00:00:00 2001 From: Travis Abendshien Date: Sat, 31 Aug 2024 22:29:19 -0700 Subject: [PATCH] fix(ui): seek next valid video frame for thumbs --- tagstudio/src/qt/widgets/collage_icon.py | 21 ++++++++++++++++----- tagstudio/src/qt/widgets/thumb_renderer.py | 21 +++++++++++++++------ 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/tagstudio/src/qt/widgets/collage_icon.py b/tagstudio/src/qt/widgets/collage_icon.py index c73eb7c7..cfbf3bb3 100644 --- a/tagstudio/src/qt/widgets/collage_icon.py +++ b/tagstudio/src/qt/widgets/collage_icon.py @@ -3,6 +3,7 @@ # Created for TagStudio: https://github.com/CyanVoxel/TagStudio import logging +import math import traceback from pathlib import Path @@ -105,12 +106,22 @@ class CollageIconRenderer(QObject): (video.get(cv2.CAP_PROP_FRAME_COUNT) // 2), ) success, frame = video.read() - if not success: - # Depending on the video format, compression, and frame - # count, seeking halfway does not work and the thumb - # must be pulled from the earliest available frame. - video.set(cv2.CAP_PROP_POS_FRAMES, 0) + # NOTE: Depending on the video format, compression, and + # frame count, seeking halfway does not work and the thumb + # must be pulled from the earliest available frame. + MAX_FRAME_SEEK: int = 10 + for i in range( + 0, + min( + MAX_FRAME_SEEK, + math.floor(video.get(cv2.CAP_PROP_FRAME_COUNT)), + ), + ): success, frame = video.read() + if not success: + video.set(cv2.CAP_PROP_POS_FRAMES, i) + else: + break frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) with Image.fromarray(frame, mode="RGB") as pic: if keep_aspect: diff --git a/tagstudio/src/qt/widgets/thumb_renderer.py b/tagstudio/src/qt/widgets/thumb_renderer.py index a32f4914..9a328168 100644 --- a/tagstudio/src/qt/widgets/thumb_renderer.py +++ b/tagstudio/src/qt/widgets/thumb_renderer.py @@ -880,12 +880,21 @@ class ThumbRenderer(QObject): cv2.CAP_PROP_POS_FRAMES, (video.get(cv2.CAP_PROP_FRAME_COUNT) // 2), ) - success, frame = video.read() - if not success: - # Depending on the video format, compression, and frame - # count, seeking halfway does not work and the thumb - # must be pulled from the earliest available frame. - video.set(cv2.CAP_PROP_POS_FRAMES, 0) + # NOTE: Depending on the video format, compression, and + # frame count, seeking halfway does not work and the thumb + # must be pulled from the earliest available frame. + MAX_FRAME_SEEK: int = 10 + for i in range( + 0, + min( + MAX_FRAME_SEEK, math.floor(video.get(cv2.CAP_PROP_FRAME_COUNT)) + ), + ): + success, frame = video.read() + if not success: + video.set(cv2.CAP_PROP_POS_FRAMES, i) + else: + break frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) im = Image.fromarray(frame) except (