mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-24 21:04:40 +01:00
Improves thumbnail extraction reliability
Enhances thumbnail extraction by retrying without seeking if the initial attempt fails. This addresses issues where the generated thumbnail file is either missing or empty. It also calculates the seek position more accurately and avoid seeking for very short videos.
This commit is contained in:
parent
c1d7cde34d
commit
ca12d13a40
1 changed files with 51 additions and 14 deletions
|
|
@ -486,25 +486,37 @@ class ExtractThumbnail(pyblish.api.InstancePlugin):
|
|||
# Set video input attributes
|
||||
max_int = str(2147483647)
|
||||
video_data = get_ffprobe_data(video_file_path, logger=self.log)
|
||||
# Use duration of the individual streams since it is returned with
|
||||
# higher decimal precision than 'format.duration'. We need this
|
||||
# more precise value for calculating the correct amount of frames
|
||||
# for higher FPS ranges or decimal ranges, e.g. 29.97 FPS
|
||||
duration = max(
|
||||
float(stream.get("duration", 0))
|
||||
for stream in video_data["streams"]
|
||||
if stream.get("codec_type") == "video"
|
||||
)
|
||||
|
||||
# Get duration or use a safe default (single frame)
|
||||
duration = 0
|
||||
for stream in video_data["streams"]:
|
||||
if stream.get("codec_type") == "video":
|
||||
stream_duration = float(stream.get("duration", 0))
|
||||
if stream_duration > duration:
|
||||
duration = stream_duration
|
||||
|
||||
# For very short videos, just use the first frame
|
||||
# Calculate seek position safely
|
||||
seek_position = 0
|
||||
if duration > 0.1: # Only use timestamp calculation for videos longer than 0.1 seconds
|
||||
seek_position = duration * self.duration_split
|
||||
|
||||
# Build command args
|
||||
cmd_args = [
|
||||
"-y",
|
||||
"-ss", str(duration * self.duration_split),
|
||||
"-i", video_file_path,
|
||||
"-analyzeduration", max_int,
|
||||
"-probesize", max_int,
|
||||
"-frames:v", "1"
|
||||
]
|
||||
|
||||
# Only add -ss if we're seeking to a specific position
|
||||
if seek_position > 0:
|
||||
cmd_args.insert(1, "-ss")
|
||||
cmd_args.insert(2, str(seek_position))
|
||||
|
||||
# Ensure we extract exactly one frame
|
||||
cmd_args.extend(["-frames:v", "1"])
|
||||
|
||||
# add output file path
|
||||
cmd_args.append(output_thumb_file_path)
|
||||
|
||||
|
|
@ -517,9 +529,34 @@ class ExtractThumbnail(pyblish.api.InstancePlugin):
|
|||
# run subprocess
|
||||
self.log.debug("Executing: {}".format(" ".join(cmd)))
|
||||
run_subprocess(cmd, logger=self.log)
|
||||
self.log.debug(
|
||||
"Thumbnail created: {}".format(output_thumb_file_path))
|
||||
return output_thumb_file_path
|
||||
|
||||
# Verify the output file was created
|
||||
if os.path.exists(output_thumb_file_path) and os.path.getsize(output_thumb_file_path) > 0:
|
||||
self.log.debug(
|
||||
"Thumbnail created: {}".format(output_thumb_file_path))
|
||||
return output_thumb_file_path
|
||||
else:
|
||||
self.log.warning(
|
||||
"Output file was not created or is empty: {}".format(output_thumb_file_path))
|
||||
|
||||
# Fallback to extracting the first frame without seeking
|
||||
if "-ss" in cmd_args:
|
||||
self.log.debug("Trying fallback without seeking")
|
||||
# Remove -ss and its value
|
||||
ss_index = cmd_args.index("-ss")
|
||||
cmd_args.pop(ss_index) # Remove -ss
|
||||
cmd_args.pop(ss_index) # Remove the timestamp value
|
||||
|
||||
# Create new command and try again
|
||||
cmd = get_ffmpeg_tool_args("ffmpeg", *cmd_args)
|
||||
self.log.debug("Fallback command: {}".format(" ".join(cmd)))
|
||||
run_subprocess(cmd, logger=self.log)
|
||||
|
||||
if os.path.exists(output_thumb_file_path) and os.path.getsize(output_thumb_file_path) > 0:
|
||||
self.log.debug("Fallback thumbnail created: {}".format(output_thumb_file_path))
|
||||
return output_thumb_file_path
|
||||
|
||||
return None
|
||||
except RuntimeError as error:
|
||||
self.log.warning(
|
||||
"Failed intermediate thumb source using ffmpeg: {}".format(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue