mirror of
https://github.com/vladmandic/automatic
synced 2026-09-19 09:14:35 +02:00
refactor(video): carry output resolution on the video result
Both runners round the requested resolution and the two-stage LTX path derives its own, so the request never recorded what came out. Read it off the decoded frames instead.
This commit is contained in:
@@ -29,6 +29,8 @@ class VideoResult:
|
||||
has_audio: bool
|
||||
still: bool
|
||||
processed: processing.Processed
|
||||
width: int = 0 # what was generated, which is not what was requested whenever a runner rounds or a model picks
|
||||
height: int = 0
|
||||
|
||||
|
||||
def resolve_model(engine: str | None, model: str | None) -> tuple[models_def.Model, bool]:
|
||||
@@ -302,7 +304,8 @@ def run(selected: models_def.Model, *,
|
||||
|
||||
if getattr(p, 'video_still', False):
|
||||
stills = processed.images[:1] # already trimmed in process_decode; defensive
|
||||
return VideoResult(images=stills, video_path=None, thumb_path=None, num_frames=len(stills), fps=0.0, has_audio=False, still=True, processed=processed)
|
||||
still_w, still_h = video_utils.pixel_size(stills, fallback=(p.width, p.height))
|
||||
return VideoResult(images=stills, video_path=None, thumb_path=None, num_frames=len(stills), fps=0.0, has_audio=False, still=True, processed=processed, width=still_w, height=still_h)
|
||||
|
||||
if hasattr(processed, 'images') and processed.images is not None:
|
||||
pixels = video_save.images_to_tensor(processed.images)
|
||||
@@ -341,8 +344,9 @@ def run(selected: models_def.Model, *,
|
||||
mp4_interpolate=mp4_interpolate,
|
||||
metadata={},
|
||||
)
|
||||
out_w, out_h = video_utils.pixel_size(processed.images, fallback=(p.width, p.height))
|
||||
del pixels
|
||||
return VideoResult(images=processed.images, video_path=video_file, thumb_path=thumb_file, num_frames=num_frames, fps=float(save_fps), has_audio=waveform is not None, still=False, processed=processed)
|
||||
return VideoResult(images=processed.images, video_path=video_file, thumb_path=thumb_file, num_frames=num_frames, fps=float(save_fps), has_audio=waveform is not None, still=False, processed=processed, width=out_w, height=out_h)
|
||||
|
||||
|
||||
def generate(task_id, ui_state,
|
||||
|
||||
@@ -73,6 +73,26 @@ def has_torchaudio():
|
||||
return False
|
||||
|
||||
|
||||
def pixel_size(pixels, fallback: tuple[int, int] = (0, 0)) -> tuple[int, int]:
|
||||
"""Width and height of decoded frames, whether they arrive as PIL images or as a tensor.
|
||||
|
||||
The runners request a resolution and the model answers with another one often enough that
|
||||
the request is not a usable substitute, so read it off the pixels and keep the fallback for
|
||||
the case where nothing was decoded at all.
|
||||
"""
|
||||
if isinstance(pixels, list):
|
||||
return pixels[0].size if len(pixels) > 0 and hasattr(pixels[0], 'size') else fallback
|
||||
ndim = getattr(pixels, 'ndim', None)
|
||||
if ndim == 5: # NCTHW
|
||||
return int(pixels.shape[-1]), int(pixels.shape[-2])
|
||||
if ndim == 4: # NHWC
|
||||
return int(pixels.shape[2]), int(pixels.shape[1])
|
||||
shape = getattr(pixels, 'shape', None)
|
||||
if shape is not None and len(shape) >= 2:
|
||||
return int(shape[-1]), int(shape[-2])
|
||||
return fallback
|
||||
|
||||
|
||||
def classify_extension(fn: str):
|
||||
"""Media kind of a filename, None when the extension is not one sdnext reads."""
|
||||
lower = str(fn).lower()
|
||||
|
||||
Reference in New Issue
Block a user