From ccde0f2014ce4e5646eadab715c4b5c6771e9e90 Mon Sep 17 00:00:00 2001 From: Austin Mroz Date: Mon, 16 Dec 2024 15:09:47 -0600 Subject: [PATCH] Add preview rate option. After accounting for the loss of in-between frames from their temporal vae's, both mochi and ltxv have a target frame rate that is close to 8. Given the difficulty of conveying the discrepancy of in-between frames and the hard diminishing returns of processing too many previews on execution rate, it was very tempting to leave this option off entirely. I have decided to include anyways under the consideration that it would be easier to explain to a user why changing a setting didn't work the way they expect than to explain why the setting doesn't exist at all. --- videohelpersuite/latent_preview.py | 13 ++++++++----- web/js/VHS.core.js | 15 +++++++++++++++ 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/videohelpersuite/latent_preview.py b/videohelpersuite/latent_preview.py index e8ccc57..831fda3 100644 --- a/videohelpersuite/latent_preview.py +++ b/videohelpersuite/latent_preview.py @@ -12,10 +12,11 @@ serv = server.PromptServer.instance from .utils import hook class WrappedPreviewer(latent_preview.LatentPreviewer): - def __init__(self, dltp): + def __init__(self, dltp, rate=8): self.first_preview = True self.last_time = 0 self.c_index = 0 + self.rate = rate self.decode_latent_to_preview = dltp def decode_latent_to_preview_image(self, preview_format, x0): if x0.ndim == 5: @@ -24,8 +25,8 @@ class WrappedPreviewer(latent_preview.LatentPreviewer): x0 = x0.reshape((-1,)+x0.shape[-3:]) num_images = x0.size(0) new_time = time.time() - num_previews = int((new_time - self.last_time) * 8) - self.last_time = self.last_time + num_previews/8 + num_previews = int((new_time - self.last_time) * self.rate) + self.last_time = self.last_time + num_previews/self.rate if num_previews > num_images: num_previews = num_images if self.first_preview: @@ -46,7 +47,7 @@ class WrappedPreviewer(latent_preview.LatentPreviewer): sub_image.save(message, format="JPEG", quality=95, compress_level=1) serv.send_sync(server.BinaryEventTypes.PREVIEW_IMAGE, message.getvalue(), serv.client_id) - self.c_index = (self.c_index +1) % num_images + self.c_index = (self.c_index + 1) % num_images return None @hook(latent_preview, 'get_previewer') @@ -56,9 +57,11 @@ def get_latent_video_previewer(device, latent_format, *args, **kwargs): try: prev_setting = next(serv.prompt_queue.currently_running.values().__iter__())[3] \ ['extra_pnginfo']['workflow']['extra'].get('VHS_latentpreview', False) + rate_setting = next(serv.prompt_queue.currently_running.values().__iter__())[3] \ + ['extra_pnginfo']['workflow']['extra'].get('VHS_latentpreviewrate', 8) except: #For safety since there's lots of keys, any of which can fail prev_setting = False if not prev_setting or not hasattr(previewer, "decode_latent_to_preview"): return previewer - return WrappedPreviewer(previewer.decode_latent_to_preview) + return WrappedPreviewer(previewer.decode_latent_to_preview, rate_setting) diff --git a/web/js/VHS.core.js b/web/js/VHS.core.js index 5f8dee5..be942a8 100755 --- a/web/js/VHS.core.js +++ b/web/js/VHS.core.js @@ -1334,6 +1334,20 @@ app.ui.settings.addSetting({ } }, }); +app.ui.settings.addSetting({ + id: "VHS.LatentPreviewRate", + name: "🎥🅥🅗🅢 Playback keyframe rate.", + type: "boolean", + type: 'number', + attrs: { + min: 1, + step: 1, + max: 60 + }, + tooltip: + 'When dragging and resizing nodes while holding shift they will be aligned to the grid, this controls the size of that grid.', + defaultValue: 8, +}); app.registerExtension({ name: "VideoHelperSuite.Core", @@ -1615,6 +1629,7 @@ app.registerExtension({ } } res.workflow.extra['VHS_latentpreview'] = app.ui.settings.getSettingValue("VHS.LatentPreview", false) + res.workflow.extra['VHS_latentpreviewrate'] = app.ui.settings.getSettingValue("VHS.LatentPreviewRate", 8) return res } app.graphToPrompt = graphToPrompt