1ripon1's picture
Upload folder using huggingface_hub
7344bef verified
Raw
History Blame Contribute Delete
9.88 kB
from __future__ import annotations
from dataclasses import dataclass
from pathlib import Path
import gradio as gr
from shared.utils.audio_video import extract_audio_tracks
from shared.utils.utils import get_video_info_details
from shared.utils.video_decode import resolve_media_binary
from shared.utils.virtual_media import build_virtual_media_path
from . import common
from . import frame_planning as frames
from . import media_io as media
from . import output_paths
from . import process_metadata
from . import video_buffers as video
class ProcessInfoExit(Exception):
def __init__(self, message: str, *, output_path: str | None = None) -> None:
super().__init__(message)
self.message = message
self.output_path = output_path
@dataclass(frozen=True)
class PreparedRun:
verbose_level: int
start_frame: int
end_frame_exclusive: int
fps_float: float
total_source_frames: int
processing_fps: float
selected_audio_track: int | None
frame_plan_rules: frames.FramePlanRules
budget_resolution: str
chunk_frames: int
overlap_frames: int
full_plans: list[frames.ChunkPlan]
requested_unique_frames: int
requested_source_segment: str
output_path: str
resume_existing_output: bool
ffmpeg_path: str
ffprobe_path: str
output_container: str
merged_continuation_signatures: list[dict]
def get_mmgp_verbose_level() -> int:
try:
from mmgp import offload
return int(getattr(offload, "default_verboseLevel", 0) or 0)
except Exception:
return 0
def prepare_run(
*,
plugin,
get_model_def,
process_name: str,
process_display_name: str,
source_path: str,
output_path: str,
output_resolution: str,
active_target_ratio: str,
continue_enabled: bool,
source_audio_track: str,
chunk_size_seconds: float,
sliding_window_overlap: int,
start_seconds: float,
end_seconds: float | None,
model_type: str,
process_is_hdr: bool,
uses_builtin_outpaint_ui: bool,
system_handler=None,
system_target_control: str = "",
) -> PreparedRun:
verbose_level = get_mmgp_verbose_level()
try:
metadata = get_video_info_details(source_path)
except Exception as exc:
raise gr.Error(f"Unable to read source video metadata: {source_path}") from exc
start_frame, end_frame_exclusive, fps_float, total_source_frames = video.compute_selected_frame_range(metadata, start_seconds, end_seconds)
processing_fps = video.get_processing_fps(fps_float)
try:
audio_track_count = int(extract_audio_tracks(source_path, query_only=True))
except Exception as exc:
raise gr.Error(f"Unable to inspect source audio tracks in: {source_path}") from exc
selected_audio_track = None
if len(source_audio_track) > 0:
if not source_audio_track.isdigit() or int(source_audio_track) <= 0:
raise gr.Error("Source Audio must be Auto or a whole track number.")
if audio_track_count <= 0:
raise gr.Error("Source video contains no audio track. Leave Source Audio empty.")
selected_audio_track = int(source_audio_track)
elif audio_track_count > 0:
selected_audio_track = 1
if selected_audio_track is not None and (selected_audio_track <= 0 or selected_audio_track > audio_track_count):
raise gr.Error(f"Source Audio must be between 1 and {audio_track_count}.")
if system_handler is None:
frame_plan_rules = frames.get_frame_plan_rules(model_type, get_model_def)
budget_resolution = output_paths.choose_resolution(output_resolution)
output_resolution_token = output_resolution
else:
frame_plan_rules = frames.FramePlanRules(frame_step=int(getattr(system_handler, "frame_step", 1)), minimum_requested_frames=int(getattr(system_handler, "minimum_requested_frames", 1)))
budget_resolution = ""
output_resolution_token = system_handler.output_resolution_token(system_target_control) if hasattr(system_handler, "output_resolution_token") else output_resolution
try:
chunk_frames = frames.normalize_chunk_frames(chunk_size_seconds, processing_fps, frame_step=frame_plan_rules.frame_step, minimum_requested_frames=frame_plan_rules.minimum_requested_frames)
if system_handler is not None:
get_overlap_frames = getattr(system_handler, "get_overlap_frames", None)
overlap_frames = int(get_overlap_frames(chunk_frames)) if callable(get_overlap_frames) else int(getattr(system_handler, "overlap_frames", 0))
else:
overlap_frames = frames.normalize_overlap_frames(sliding_window_overlap, frame_step=frame_plan_rules.frame_step)
except frames.FramePlanningError as exc:
raise gr.Error(str(exc)) from exc
if overlap_frames >= chunk_frames:
raise gr.Error(f"Sliding Window Overlap must stay below the computed chunk size ({chunk_frames} frame(s)).")
selected_unique_frames = end_frame_exclusive - start_frame
try:
full_plans = frames.build_chunk_plan(
start_frame,
end_frame_exclusive,
total_source_frames,
chunk_frames,
frame_step=frame_plan_rules.frame_step,
minimum_requested_frames=frame_plan_rules.minimum_requested_frames,
overlap_frames=overlap_frames,
)
except frames.FramePlanningError as exc:
raise gr.Error(str(exc)) from exc
requested_unique_frames = frames.count_planned_unique_frames(full_plans)
requested_source_segment = build_virtual_media_path(source_path, start_frame=start_frame, end_frame=start_frame + requested_unique_frames - 1, audio_track_no=selected_audio_track)
default_output_container = media.normalize_container_name(plugin.server_config.get("video_container", "mp4"))
requested_output_path = str(output_paths.build_requested_output_path(source_path, output_path, process_display_name, active_target_ratio, output_resolution_token, start_seconds, end_seconds, has_outpaint=uses_builtin_outpaint_ui, default_container=default_output_container))
if continue_enabled:
existing_identity = process_metadata.read_output_identity(requested_output_path)
identity_mismatch_message = process_metadata.get_output_identity_mismatch_message(requested_output_path, process_name=process_display_name, source_path=source_path, source_segment=requested_source_segment)
if identity_mismatch_message is not None:
system_supports_continue_cache = system_handler is not None and (not callable(getattr(system_handler, "supports_continue_cache_for_target", None)) or system_handler.supports_continue_cache_for_target(system_target_control))
can_resume_from_system_state = existing_identity is None and system_supports_continue_cache and callable(getattr(system_handler, "can_resume_without_output_metadata", None)) and system_handler.can_resume_without_output_metadata(requested_output_path)
if not can_resume_from_system_state:
raise ProcessInfoExit(identity_mismatch_message, output_path=requested_output_path)
common.plugin_info(f"Existing output has no readable WanGP metadata, but the system process can continue from its cache or decoded output tail: {requested_output_path}")
resolved_output_path, resume_existing_output = output_paths.resolve_output_path(source_path, output_path, process_display_name, active_target_ratio, output_resolution_token, start_seconds, end_seconds, continue_enabled, has_outpaint=uses_builtin_outpaint_ui, default_container=default_output_container, notify=common.plugin_info)
try:
Path(resolved_output_path).parent.mkdir(parents=True, exist_ok=True)
except OSError as exc:
raise gr.Error(f"Unable to create the output folder for: {resolved_output_path}") from exc
dropped_tail_frames = selected_unique_frames - requested_unique_frames
if dropped_tail_frames > 0:
common.plugin_info(f"Dropping the last {dropped_tail_frames} source frame(s) so the selected range fits the current model chunk shape.")
ffmpeg_path = resolve_media_binary("ffmpeg")
if ffmpeg_path is None:
raise gr.Error("ffmpeg binary not found.")
ffprobe_path = resolve_media_binary("ffprobe")
if ffprobe_path is None:
raise gr.Error("ffprobe binary not found.")
output_container = media.normalize_container_name(Path(resolved_output_path).suffix.lstrip(".") or plugin.server_config.get("video_container", "mp4"))
output_video_codec = "libx265_8" if process_is_hdr else plugin.server_config.get("video_output_codec", "libx264_8")
media.validate_output_codec_container(output_video_codec, output_container, output_path=resolved_output_path)
if selected_audio_track is not None:
media.validate_audio_copy_container(ffprobe_path, source_path, output_container, selected_audio_track)
return PreparedRun(
verbose_level=verbose_level,
start_frame=start_frame,
end_frame_exclusive=end_frame_exclusive,
fps_float=fps_float,
total_source_frames=total_source_frames,
processing_fps=processing_fps,
selected_audio_track=selected_audio_track,
frame_plan_rules=frame_plan_rules,
budget_resolution=budget_resolution,
chunk_frames=chunk_frames,
overlap_frames=overlap_frames,
full_plans=full_plans,
requested_unique_frames=requested_unique_frames,
requested_source_segment=requested_source_segment,
output_path=resolved_output_path,
resume_existing_output=resume_existing_output,
ffmpeg_path=ffmpeg_path,
ffprobe_path=ffprobe_path,
output_container=output_container,
merged_continuation_signatures=process_metadata.read_merged_continuation_signatures(resolved_output_path),
)