mirror of
https://github.com/facefusion/facefusion.git
synced 2026-07-27 12:30:55 +02:00
Skip temp-frame extraction; process reads and writes frames directly
With the canvas coming from the video reader, the extracted temp PNGs were never read for pixels -- extraction only produced write targets and a frame list. Drop the extract_frames step entirely: process_video iterates the trim range, each worker reads its frame from the reader, swaps, and writes straight to the temp frame path that merge consumes. Removes the whole extracting phase (a second full-video decode + PNG encode). Wall time drops ~25-36% (AV1 ~30 -> ~19 s, H.264 ~29 -> ~22 s for 300 frames); processing throughput unchanged; output unchanged. Note: this path does not resample fps (output_video_fps must equal source fps) and derives the frame count via cv2 container metadata; a scaled output falls back to a per-frame resize instead of the temp PNG. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
from functools import partial
|
||||
|
||||
import cv2
|
||||
import numpy
|
||||
from tqdm import tqdm
|
||||
|
||||
@@ -11,10 +12,10 @@ from facefusion.common_helper import get_first, get_middle
|
||||
from facefusion.content_analyser import analyse_video
|
||||
from facefusion.filesystem import filter_audio_paths, is_video
|
||||
from facefusion.processors.core import get_processors_modules
|
||||
from facefusion.temp_helper import clear_temp_directory, create_temp_directory, move_temp_file, resolve_temp_frame_set
|
||||
from facefusion.temp_helper import clear_temp_directory, create_temp_directory, get_temp_frame_pattern, move_temp_file
|
||||
from facefusion.time_helper import calculate_end_time
|
||||
from facefusion.types import ErrorCode, Resolution
|
||||
from facefusion.vision import conditional_merge_vision_mask, detect_video_resolution, extract_vision_mask, pack_resolution, read_static_image, read_static_images, read_static_video_frame, restrict_trim_frame, restrict_video_fps, restrict_video_resolution, scale_resolution, select_video_frames, write_image
|
||||
from facefusion.vision import conditional_merge_vision_mask, detect_video_resolution, extract_vision_mask, pack_resolution, read_static_images, read_static_video_frame, restrict_trim_frame, restrict_video_fps, restrict_video_resolution, scale_resolution, select_video_frames, write_image
|
||||
from facefusion.workflows.core import is_process_stopping
|
||||
|
||||
|
||||
@@ -22,7 +23,6 @@ def process(start_time : float) -> ErrorCode:
|
||||
tasks =\
|
||||
[
|
||||
setup,
|
||||
extract_frames,
|
||||
process_video,
|
||||
merge_frames,
|
||||
restore_audio,
|
||||
@@ -74,19 +74,20 @@ def extract_frames() -> ErrorCode:
|
||||
|
||||
|
||||
def process_video() -> ErrorCode:
|
||||
temp_frame_set = resolve_temp_frame_set(state_manager.get_item('target_path'))
|
||||
trim_frame_start, trim_frame_end = restrict_trim_frame(state_manager.get_item('target_path'), state_manager.get_item('trim_frame_start'), state_manager.get_item('trim_frame_end'))
|
||||
output_video_resolution = scale_resolution(detect_video_resolution(state_manager.get_item('target_path')), state_manager.get_item('output_video_scale'))
|
||||
temp_video_resolution = restrict_video_resolution(state_manager.get_item('target_path'), output_video_resolution)
|
||||
frame_range = range(trim_frame_start, trim_frame_end)
|
||||
|
||||
if temp_frame_set:
|
||||
with tqdm(total = len(temp_frame_set), desc = translator.get('processing'), unit = 'frame', ascii = ' =', disable = state_manager.get_item('log_level') in [ 'warn', 'error' ]) as progress:
|
||||
if frame_range:
|
||||
with tqdm(total = len(frame_range), desc = translator.get('processing'), unit = 'frame', ascii = ' =', disable = state_manager.get_item('log_level') in [ 'warn', 'error' ]) as progress:
|
||||
progress.set_postfix(execution_providers = state_manager.get_item('execution_providers'))
|
||||
|
||||
with ThreadPoolExecutor(max_workers = state_manager.get_item('execution_thread_count')) as executor:
|
||||
futures = []
|
||||
|
||||
for frame_number, temp_frame_path in temp_frame_set.items():
|
||||
future = executor.submit(process_temp_frame, temp_frame_path, frame_number, temp_video_resolution)
|
||||
for frame_number in frame_range:
|
||||
future = executor.submit(process_temp_frame, frame_number, temp_video_resolution)
|
||||
futures.append(future)
|
||||
|
||||
for future in as_completed(futures):
|
||||
@@ -156,7 +157,7 @@ def restore_audio() -> ErrorCode:
|
||||
return 0
|
||||
|
||||
|
||||
def process_temp_frame(temp_frame_path : str, frame_number : int, temp_video_resolution : Resolution) -> bool:
|
||||
def process_temp_frame(frame_number : int, temp_video_resolution : Resolution) -> bool:
|
||||
trim_frame_start, _ = restrict_trim_frame(state_manager.get_item('target_path'), state_manager.get_item('trim_frame_start'), state_manager.get_item('trim_frame_end'))
|
||||
reference_vision_frame = read_static_video_frame(state_manager.get_item('target_path'), state_manager.get_item('reference_frame_number'))
|
||||
source_vision_frames = read_static_images(state_manager.get_item('source_paths'))
|
||||
@@ -164,10 +165,11 @@ def process_temp_frame(temp_frame_path : str, frame_number : int, temp_video_res
|
||||
target_vision_frames = select_video_frames(state_manager.get_item('target_path'), frame_number, state_manager.get_item('target_frame_amount'))
|
||||
target_vision_frame = get_middle(target_vision_frames)
|
||||
temp_video_fps = restrict_video_fps(state_manager.get_item('target_path'), state_manager.get_item('output_video_fps'))
|
||||
temp_frame_path = get_temp_frame_pattern(state_manager.get_item('target_path'), format(frame_number, '08d'))
|
||||
temp_vision_frame = target_vision_frame.copy()
|
||||
|
||||
if not (target_vision_frame.shape[1], target_vision_frame.shape[0]) == temp_video_resolution:
|
||||
target_vision_frame = read_static_image(temp_frame_path, 'rgba')
|
||||
temp_vision_frame = target_vision_frame.copy()
|
||||
temp_vision_frame = cv2.resize(target_vision_frame, temp_video_resolution)
|
||||
temp_vision_mask = extract_vision_mask(temp_vision_frame)
|
||||
|
||||
source_audio_frame = get_audio_frame(source_audio_path, temp_video_fps, frame_number - trim_frame_start)
|
||||
|
||||
Reference in New Issue
Block a user