mirror of
https://github.com/facefusion/facefusion.git
synced 2026-07-27 12:30:55 +02:00
Reuse the decoded window frame as the swap canvas
process_temp_frame read the target frame twice per output frame: once from the video (the detection window) and once from the extracted temp PNG (the swap canvas). They are the same frame N. The window centre is already decoded in the reader, so use it as the canvas and only fall back to the temp PNG when the reader resolution differs from the temp resolution (scaled output). Removes one full-frame decode per output frame. AV1 ~22 -> ~26 fps and H.264 ~20 -> ~23 fps -- matching and slightly beating 3.6.1, because a frame copy is cheaper than a PNG decode. The canvas now comes from the raw pipe decode instead of the PNG decode of the same frame (sub-visual ~1 LSB difference in passthrough regions); detection is unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -7,13 +7,13 @@ from tqdm import tqdm
|
||||
from facefusion import ffmpeg
|
||||
from facefusion import logger, process_manager, state_manager, translator, video_manager
|
||||
from facefusion.audio import create_empty_audio_frame, get_audio_frame, get_voice_frame
|
||||
from facefusion.common_helper import get_first
|
||||
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.time_helper import calculate_end_time
|
||||
from facefusion.types import ErrorCode
|
||||
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.workflows.core import is_process_stopping
|
||||
|
||||
@@ -75,6 +75,8 @@ def extract_frames() -> ErrorCode:
|
||||
|
||||
def process_video() -> ErrorCode:
|
||||
temp_frame_set = resolve_temp_frame_set(state_manager.get_item('target_path'))
|
||||
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)
|
||||
|
||||
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:
|
||||
@@ -84,7 +86,7 @@ def process_video() -> ErrorCode:
|
||||
futures = []
|
||||
|
||||
for frame_number, temp_frame_path in temp_frame_set.items():
|
||||
future = executor.submit(process_temp_frame, temp_frame_path, frame_number)
|
||||
future = executor.submit(process_temp_frame, temp_frame_path, frame_number, temp_video_resolution)
|
||||
futures.append(future)
|
||||
|
||||
for future in as_completed(futures):
|
||||
@@ -154,14 +156,18 @@ def restore_audio() -> ErrorCode:
|
||||
return 0
|
||||
|
||||
|
||||
def process_temp_frame(temp_frame_path : str, frame_number : int) -> bool:
|
||||
def process_temp_frame(temp_frame_path : str, 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'))
|
||||
source_audio_path = get_first(filter_audio_paths(state_manager.get_item('source_paths')))
|
||||
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_vision_frame = read_static_image(temp_frame_path, 'rgba')
|
||||
|
||||
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_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