feat(video): add thumbnail save toggle

This commit is contained in:
Ryan Meador
2026-06-02 23:43:58 -04:00
parent 2af67b76d0
commit 11096bc0aa
10 changed files with 27 additions and 18 deletions
+2
View File
@@ -33,6 +33,7 @@ class ReqFramepack(BaseModel):
mp4_sf: bool | None = Field(default=False, title="Save SafeTensors", description="Save SafeTensors for the video")
mp4_video: bool | None = Field(default=True, title="Save Video", description="Save video")
mp4_frames: bool | None = Field(default=False, title="Save Frames", description="Save frames for the video")
mp4_thumb: bool | None = Field(default=True, title="Save Thumbnail", description="Save thumbnail for the video")
mp4_opt: str | None = Field(default="crf:16", title="Options", description="Options for the video codec")
mp4_ext: str | None = Field(default="mp4", title="Format", description="Format for the video")
mp4_interpolate: int | None = Field(default=0, title="Interpolation", description="Interpolation for the video")
@@ -109,6 +110,7 @@ def framepack_post(request: ReqFramepack):
mp4_sf=request.mp4_sf,
mp4_video=request.mp4_video,
mp4_frames=request.mp4_frames,
mp4_thumb=request.mp4_thumb,
mp4_opt=request.mp4_opt,
mp4_ext=request.mp4_ext,
mp4_interpolate=request.mp4_interpolate,
+2 -2
View File
@@ -12,7 +12,7 @@ def change_sections(duration, mp4_fps, mp4_interpolate, latent_ws, variant):
return gr.update(value=f'Target video: {num_frames} frames in {num_sections} sections'), gr.update(lines=max(2, 2*num_sections//3))
def create_ui(prompt, negative, styles, _overrides, mp4_fps, mp4_interpolate, mp4_codec, mp4_ext, mp4_opt, mp4_video, mp4_frames, mp4_sf):
def create_ui(prompt, negative, styles, _overrides, mp4_fps, mp4_interpolate, mp4_codec, mp4_ext, mp4_opt, mp4_video, mp4_frames, mp4_sf, mp4_thumb):
with gr.Row():
with gr.Column(variant='compact', elem_id="framepack_settings", elem_classes=['settings-column'], scale=1):
with gr.Row():
@@ -106,7 +106,7 @@ def create_ui(prompt, negative, styles, _overrides, mp4_fps, mp4_interpolate, mp
cfg_scale, cfg_distilled, cfg_rescale,
shift,
use_teacache, use_cfgzero, use_preview,
mp4_fps, mp4_codec, mp4_sf, mp4_video, mp4_frames, mp4_opt, mp4_ext, mp4_interpolate,
mp4_fps, mp4_codec, mp4_sf, mp4_video, mp4_frames, mp4_thumb, mp4_opt, mp4_ext, mp4_interpolate,
attention, vae_type, variant,
vlm_enhance, vlm_model, vlm_system_prompt,
]
+3 -1
View File
@@ -41,7 +41,7 @@ def worker(
cfg_scale, cfg_distilled, cfg_rescale,
shift,
use_teacache, use_cfgzero, use_preview,
mp4_fps, mp4_codec, mp4_sf, mp4_video, mp4_frames, mp4_opt, mp4_ext, mp4_interpolate,
mp4_fps, mp4_codec, mp4_sf, mp4_video, mp4_frames, mp4_thumb, mp4_opt, mp4_ext, mp4_interpolate,
vae_type,
variant,
metadata: dict | None = None,
@@ -343,6 +343,7 @@ def worker(
mp4_sf=mp4_sf,
mp4_video=mp4_video,
mp4_frames=mp4_frames,
mp4_thumb=mp4_thumb,
mp4_interpolate=0,
pbar=pbar,
stream=stream,
@@ -364,6 +365,7 @@ def worker(
mp4_sf=mp4_sf,
mp4_video=mp4_video,
mp4_frames=mp4_frames,
mp4_thumb=mp4_thumb,
mp4_interpolate=0,
pbar=pbar,
stream=stream,
+2 -2
View File
@@ -114,7 +114,7 @@ def unload_model():
yield gr.update(), gr.update(), 'Model unloaded'
def run_framepack(task_id, _ui_state, init_image, end_image, start_weight, end_weight, vision_weight, prompt, system_prompt, optimized_prompt, section_prompt, negative_prompt, styles, seed, resolution, duration, latent_ws, steps, cfg_scale, cfg_distilled, cfg_rescale, shift, use_teacache, use_cfgzero, use_preview, mp4_fps, mp4_codec, mp4_sf, mp4_video, mp4_frames, mp4_opt, mp4_ext, mp4_interpolate, attention, vae_type, variant, vlm_enhance, vlm_model, vlm_system_prompt):
def run_framepack(task_id, _ui_state, init_image, end_image, start_weight, end_weight, vision_weight, prompt, system_prompt, optimized_prompt, section_prompt, negative_prompt, styles, seed, resolution, duration, latent_ws, steps, cfg_scale, cfg_distilled, cfg_rescale, shift, use_teacache, use_cfgzero, use_preview, mp4_fps, mp4_codec, mp4_sf, mp4_video, mp4_frames, mp4_thumb, mp4_opt, mp4_ext, mp4_interpolate, attention, vae_type, variant, vlm_enhance, vlm_model, vlm_system_prompt):
variant = variant or 'bi-directional'
if init_image is None:
init_image = np.zeros((resolution, resolution, 3), dtype=np.uint8)
@@ -181,7 +181,7 @@ def run_framepack(task_id, _ui_state, init_image, end_image, start_weight, end_w
cfg_scale, cfg_distilled, cfg_rescale,
shift,
use_teacache, use_cfgzero, use_preview,
mp4_fps, mp4_codec, mp4_sf, mp4_video, mp4_frames, mp4_opt, mp4_ext, mp4_interpolate,
mp4_fps, mp4_codec, mp4_sf, mp4_video, mp4_frames, mp4_thumb, mp4_opt, mp4_ext, mp4_interpolate,
vae_type, variant,
)
+2
View File
@@ -148,6 +148,7 @@ def run_ltx(task_id,
mp4_video: bool,
mp4_frames: bool,
mp4_sf: bool,
mp4_thumb: bool,
audio_enable: bool,
_overrides,
):
@@ -643,6 +644,7 @@ def run_ltx(task_id,
mp4_sf=mp4_sf,
mp4_video=mp4_video,
mp4_frames=mp4_frames,
mp4_thumb=mp4_thumb,
mp4_interpolate=mp4_interpolate,
aac_sample_rate=aac_sample_rate,
metadata={},
+2 -2
View File
@@ -53,7 +53,7 @@ def _model_change(model_name: str):
)
def create_ui(prompt, negative, styles, overrides, mp4_fps, mp4_interpolate, mp4_codec, mp4_ext, mp4_opt, mp4_video, mp4_frames, mp4_sf):
def create_ui(prompt, negative, styles, overrides, mp4_fps, mp4_interpolate, mp4_codec, mp4_ext, mp4_opt, mp4_video, mp4_frames, mp4_sf, mp4_thumb):
with gr.Row():
with gr.Column(variant='compact', elem_id="ltx_settings", elem_classes=['settings-column'], scale=1):
with gr.Row():
@@ -153,7 +153,7 @@ def create_ui(prompt, negative, styles, overrides, mp4_fps, mp4_interpolate, mp4
refine_enable, refine_strength,
ltx_condition_strength, ltx_init_image, last_image, condition_files, condition_video, condition_video_frames, condition_video_skip,
decode_timestep, image_cond_noise_scale,
mp4_fps, mp4_interpolate, mp4_codec, mp4_ext, mp4_opt, mp4_video, mp4_frames, mp4_sf,
mp4_fps, mp4_interpolate, mp4_codec, mp4_ext, mp4_opt, mp4_video, mp4_frames, mp4_sf, mp4_thumb,
audio_enable,
overrides,
]
+4 -4
View File
@@ -30,24 +30,24 @@ def create_ui():
overrides = ui_common.create_override_inputs('video')
with gr.Tab('Output', id='video-outputs-tab') as _video_outputs_tab:
from modules.video_models import video_ui
mp4_fps, mp4_interpolate, mp4_codec, mp4_ext, mp4_opt, mp4_video, mp4_frames, mp4_sf = video_ui.create_ui_outputs()
mp4_fps, mp4_interpolate, mp4_codec, mp4_ext, mp4_opt, mp4_video, mp4_frames, mp4_sf, mp4_thumb = video_ui.create_ui_outputs()
with gr.Tab('Generic', id='video-core-tab') as video_core_tab:
from modules.video_models import video_ui
engine, model, steps, sampler_index, width, height, frames, seed = video_ui.create_ui(
prompt, negative, styles, overrides,
mp4_fps, mp4_interpolate, mp4_codec, mp4_ext, mp4_opt, mp4_video, mp4_frames, mp4_sf,
mp4_fps, mp4_interpolate, mp4_codec, mp4_ext, mp4_opt, mp4_video, mp4_frames, mp4_sf, mp4_thumb,
)
with gr.Tab('FramePack', id='framepack-tab') as framepack_tab:
from modules.framepack import framepack_ui
framepack_ui.create_ui(
prompt, negative, styles, overrides,
mp4_fps, mp4_interpolate, mp4_codec, mp4_ext, mp4_opt, mp4_video, mp4_frames, mp4_sf,
mp4_fps, mp4_interpolate, mp4_codec, mp4_ext, mp4_opt, mp4_video, mp4_frames, mp4_sf, mp4_thumb,
)
with gr.Tab('LTX', id='ltx-tab') as ltx_tab:
from modules.ltx import ltx_ui
ltx_ui.create_ui(
prompt, negative, styles, overrides,
mp4_fps, mp4_interpolate, mp4_codec, mp4_ext, mp4_opt, mp4_video, mp4_frames, mp4_sf,
mp4_fps, mp4_interpolate, mp4_codec, mp4_ext, mp4_opt, mp4_video, mp4_frames, mp4_sf, mp4_thumb,
)
paste_fields = [
+2 -1
View File
@@ -11,7 +11,7 @@ debug = log.trace if os.environ.get('SD_VIDEO_DEBUG', None) is not None else lam
def generate(*args, **kwargs):
task_id, ui_state, engine, model, prompt, negative, styles, width, height, frames, steps, sampler_index, sampler_shift, dynamic_shift, seed, guidance_scale, guidance_true, init_image, init_strength, last_image, vae_type, vae_tile_frames, mp4_fps, mp4_interpolate, mp4_codec, mp4_ext, mp4_opt, mp4_video, mp4_frames, mp4_sf, vlm_enhance, vlm_model, vlm_system_prompt, override_settings = args
task_id, ui_state, engine, model, prompt, negative, styles, width, height, frames, steps, sampler_index, sampler_shift, dynamic_shift, seed, guidance_scale, guidance_true, init_image, init_strength, last_image, vae_type, vae_tile_frames, mp4_fps, mp4_interpolate, mp4_codec, mp4_ext, mp4_opt, mp4_video, mp4_frames, mp4_sf, mp4_thumb, vlm_enhance, vlm_model, vlm_system_prompt, override_settings = args
if engine is None or model is None or engine == 'None' or model == 'None':
return video_utils.queue_err('model not selected')
@@ -183,6 +183,7 @@ def generate(*args, **kwargs):
mp4_sf=mp4_sf,
mp4_video=mp4_video,
mp4_frames=mp4_frames,
mp4_thumb=mp4_thumb,
mp4_interpolate=mp4_interpolate,
metadata={},
)
+4 -3
View File
@@ -36,7 +36,7 @@ def save_params(p, filename: str | None = None):
if p is None:
dct = {}
else:
# sampler_index, sampler_shift, dynamic_shift, guidance_scale, guidance_true, init_image, init_strength, last_image, vae_type, vae_tile_frames, mp4_fps, mp4_interpolate, mp4_codec, mp4_ext, mp4_opt, mp4_video, mp4_frames, mp4_sf, vlm_enhance, vlm_model, vlm_system_prompt, override_settings = args
# sampler_index, sampler_shift, dynamic_shift, guidance_scale, guidance_true, init_image, init_strength, last_image, vae_type, vae_tile_frames, mp4_fps, mp4_interpolate, mp4_codec, mp4_ext, mp4_opt, mp4_video, mp4_frames, mp4_sf, mp4_thumb, vlm_enhance, vlm_model, vlm_system_prompt, override_settings = args
dct = {
"Prompt": p.prompt,
"Negative prompt": p.negative_prompt,
@@ -227,6 +227,7 @@ def save_video(
mp4_sf: bool = False, # save safetensors
mp4_video: bool = True, # save video
mp4_frames: bool = False, # save frames
mp4_thumb: bool = True, # save thumbnail
mp4_interpolate: int = 0, # rife interpolation
aac_sample_rate: int = 24000, # audio sample rate
stream=None, # async progress reporting stream
@@ -251,7 +252,7 @@ def save_video(
except Exception as e:
log.error(f'Video output: file="{output_video}" write error {e}')
errors.display(e, 'video')
thumb = save_thumbnail(output_video)
thumb = save_thumbnail(output_video) if mp4_thumb else None
return 0, output_video, thumb
if pixels is None:
@@ -322,5 +323,5 @@ def save_video(
log.error(f'Video save: raw={size} {e}')
errors.display(e, 'video')
timer.process.add('save', time.time()-t_save)
thumb = save_thumbnail(output_video) if output_video is not None else None
thumb = save_thumbnail(output_video) if mp4_thumb and output_video is not None else None
return t, output_video, thumb
+4 -3
View File
@@ -101,10 +101,11 @@ def create_ui_outputs():
mp4_video = gr.Checkbox(label='Video save video', value=True, elem_id="video_mp4_video")
mp4_frames = gr.Checkbox(label='Video save frames', value=False, elem_id="video_mp4_frames")
mp4_sf = gr.Checkbox(label='Video save safetensors', value=False, elem_id="video_mp4_sf")
return mp4_fps, mp4_interpolate, mp4_codec, mp4_ext, mp4_opt, mp4_video, mp4_frames, mp4_sf
mp4_thumb = gr.Checkbox(label='Video save thumbnail', value=True, elem_id="video_mp4_thumb")
return mp4_fps, mp4_interpolate, mp4_codec, mp4_ext, mp4_opt, mp4_video, mp4_frames, mp4_sf, mp4_thumb
def create_ui(prompt, negative, styles, overrides, mp4_fps, mp4_interpolate, mp4_codec, mp4_ext, mp4_opt, mp4_video, mp4_frames, mp4_sf):
def create_ui(prompt, negative, styles, overrides, mp4_fps, mp4_interpolate, mp4_codec, mp4_ext, mp4_opt, mp4_video, mp4_frames, mp4_sf, mp4_thumb):
with gr.Row():
with gr.Column(variant='compact', elem_id="video_settings", elem_classes=['settings-column'], scale=1):
with gr.Row():
@@ -172,7 +173,7 @@ def create_ui(prompt, negative, styles, overrides, mp4_fps, mp4_interpolate, mp4
guidance_scale, guidance_true,
init_image, init_strength, last_image,
vae_type, vae_tile_frames,
mp4_fps, mp4_interpolate, mp4_codec, mp4_ext, mp4_opt, mp4_video, mp4_frames, mp4_sf,
mp4_fps, mp4_interpolate, mp4_codec, mp4_ext, mp4_opt, mp4_video, mp4_frames, mp4_sf, mp4_thumb,
vlm_enhance, vlm_model, vlm_system_prompt,
overrides,
]