diff --git a/facefusion/workflows/audio_to_image.py b/facefusion/workflows/audio_to_image.py index 9bbe6d98..b99a190b 100644 --- a/facefusion/workflows/audio_to_image.py +++ b/facefusion/workflows/audio_to_image.py @@ -1,18 +1,12 @@ -from concurrent.futures import ThreadPoolExecutor, as_completed from functools import partial -from tqdm import tqdm - from facefusion import content_analyser, ffmpeg, logger, process_manager, state_manager, translator from facefusion.audio import restrict_trim_audio_frame from facefusion.common_helper import get_first -from facefusion.filesystem import filter_audio_paths, is_video -from facefusion.processors.core import get_processors_modules -from facefusion.temp_helper import move_temp_file, resolve_temp_frame_paths -from facefusion.time_helper import calculate_end_time +from facefusion.filesystem import filter_audio_paths from facefusion.types import ErrorCode -from facefusion.vision import detect_image_resolution, pack_resolution, restrict_image_resolution, restrict_trim_video_frame, scale_resolution -from facefusion.workflows.core import clear, is_process_stopping, process_temp_frame, setup +from facefusion.vision import detect_image_resolution, restrict_image_resolution, scale_resolution +from facefusion.workflows.core import clear, finalize_video, is_process_stopping, merge_frames, process_video, restore_audio, setup def process(start_time : float) -> ErrorCode: @@ -22,7 +16,7 @@ def process(start_time : float) -> ErrorCode: clear, setup, create_temp_frames, - process_image, + process_video, merge_frames, restore_audio, partial(finalize_video, start_time), @@ -63,78 +57,3 @@ def create_temp_frames() -> ErrorCode: logger.error(translator.get('spawning_frames_failed'), __name__) return 1 return 0 - - -def process_image() -> ErrorCode: - temp_frame_paths = resolve_temp_frame_paths(state_manager.get_temp_path(), state_manager.get_item('output_path'), state_manager.get_item('temp_frame_format')) - - if temp_frame_paths: - with tqdm(total = len(temp_frame_paths), 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 enumerate(temp_frame_paths): - future = executor.submit(process_temp_frame, temp_frame_path, frame_number) - futures.append(future) - - for future in as_completed(futures): - if is_process_stopping(): - for __future__ in futures: - __future__.cancel() - - if not future.cancelled(): - future.result() - progress.update() - - for processor_module in get_processors_modules(state_manager.get_item('processors')): - processor_module.post_process() - - if is_process_stopping(): - return 4 - else: - logger.error(translator.get('temp_frames_not_found'), __name__) - return 1 - return 0 - - -def merge_frames() -> ErrorCode: - trim_frame_start, trim_frame_end = restrict_trim_video_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_image_resolution(state_manager.get_item('target_path')), state_manager.get_item('output_image_scale')) - - logger.info(translator.get('merging_video').format(resolution = pack_resolution(output_video_resolution), fps = state_manager.get_item('output_video_fps')), __name__) - if ffmpeg.merge_video(state_manager.get_item('target_path'), state_manager.get_item('output_path'), state_manager.get_item('output_video_fps'), output_video_resolution, trim_frame_start, trim_frame_end): - logger.debug(translator.get('merging_video_succeeded'), __name__) - else: - if is_process_stopping(): - return 4 - logger.error(translator.get('merging_video_failed'), __name__) - return 1 - return 0 - - -def restore_audio() -> ErrorCode: - if state_manager.get_item('output_audio_volume') == 0: - logger.info(translator.get('skipping_audio'), __name__) - move_temp_file(state_manager.get_temp_path(), state_manager.get_item('output_path')) - else: - source_audio_path = get_first(filter_audio_paths(state_manager.get_item('source_paths'))) - if source_audio_path: - if ffmpeg.replace_audio(source_audio_path, state_manager.get_item('output_path')): - logger.debug(translator.get('replacing_audio_succeeded'), __name__) - else: - if is_process_stopping(): - return 4 - logger.warn(translator.get('replacing_audio_skipped'), __name__) - move_temp_file(state_manager.get_temp_path(), state_manager.get_item('output_path')) - return 0 - - -def finalize_video(start_time : float) -> ErrorCode: - if is_video(state_manager.get_item('output_path')): - logger.info(translator.get('processing_video_succeeded').format(seconds = calculate_end_time(start_time)), __name__) - else: - logger.error(translator.get('processing_video_failed'), __name__) - return 1 - return 0 diff --git a/facefusion/workflows/core.py b/facefusion/workflows/core.py index e8b4edd5..55f96894 100644 --- a/facefusion/workflows/core.py +++ b/facefusion/workflows/core.py @@ -1,13 +1,18 @@ -import numpy +from concurrent.futures import ThreadPoolExecutor, as_completed -from facefusion import logger, process_manager, state_manager, translator +import numpy +from tqdm import tqdm + +from facefusion import ffmpeg, 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.filesystem import filter_audio_paths +from facefusion.filesystem import filter_audio_paths, is_video +from facefusion.media_helper import restrict_trim_frame from facefusion.processors.core import get_processors_modules -from facefusion.temp_helper import clear_temp_directory, create_temp_directory -from facefusion.types import AudioFrame, ErrorCode, VisionFrame -from facefusion.vision import conditional_merge_vision_mask, extract_vision_mask, read_static_image, read_static_images, read_static_video_frame, restrict_video_fps, write_image +from facefusion.temp_helper import clear_temp_directory, create_temp_directory, move_temp_file, resolve_temp_frame_paths +from facefusion.time_helper import calculate_end_time +from facefusion.types import AudioFrame, ErrorCode, Fps, VisionFrame +from facefusion.vision import conditional_merge_vision_mask, detect_image_resolution, extract_vision_mask, pack_resolution, read_static_image, read_static_images, read_static_video_frame, restrict_video_fps, scale_resolution, write_image def is_process_stopping() -> bool: @@ -65,6 +70,17 @@ def conditional_get_reference_vision_frame() -> VisionFrame: return read_static_image(state_manager.get_item('target_path')) +def conditional_restrict_video_fps() -> Fps: + if state_manager.get_item('workflow') == 'image-to-video': + return restrict_video_fps(state_manager.get_item('target_path'), state_manager.get_item('output_video_fps')) + return state_manager.get_item('output_video_fps') + + +def conditional_clear_video_pool() -> None: + if state_manager.get_item('workflow') == 'image-to-video': + video_manager.clear_video_pool() + + def process_temp_frame(temp_frame_path : str, frame_number : int) -> bool: reference_vision_frame = conditional_get_reference_vision_frame() source_vision_frames = read_static_images(state_manager.get_item('source_paths')) @@ -88,3 +104,95 @@ def process_temp_frame(temp_frame_path : str, frame_number : int) -> bool: temp_vision_frame = conditional_merge_vision_mask(temp_vision_frame, temp_vision_mask) return write_image(temp_frame_path, temp_vision_frame) + + +def process_video() -> ErrorCode: + temp_frame_paths = resolve_temp_frame_paths(state_manager.get_temp_path(), state_manager.get_item('output_path'), state_manager.get_item('temp_frame_format')) + + if temp_frame_paths: + with tqdm(total = len(temp_frame_paths), 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 enumerate(temp_frame_paths): + future = executor.submit(process_temp_frame, temp_frame_path, frame_number) + futures.append(future) + + for future in as_completed(futures): + if is_process_stopping(): + for __future__ in futures: + __future__.cancel() + + if not future.cancelled(): + future.result() + progress.update() + + for processor_module in get_processors_modules(state_manager.get_item('processors')): + processor_module.post_process() + + if is_process_stopping(): + return 4 + else: + logger.error(translator.get('temp_frames_not_found'), __name__) + return 1 + return 0 + + +def merge_frames() -> ErrorCode: + temp_frame_paths = resolve_temp_frame_paths(state_manager.get_temp_path(), state_manager.get_item('output_path'), state_manager.get_item('temp_frame_format')) + trim_frame_start, trim_frame_end = restrict_trim_frame(len(temp_frame_paths), state_manager.get_item('trim_frame_start'), state_manager.get_item('trim_frame_end')) + output_video_resolution = scale_resolution(detect_image_resolution(get_first(temp_frame_paths)), state_manager.get_item('output_video_scale')) + temp_video_fps = conditional_restrict_video_fps() + + logger.info(translator.get('merging_video').format(resolution = pack_resolution(output_video_resolution), fps = state_manager.get_item('output_video_fps')), __name__) + if ffmpeg.merge_video(state_manager.get_item('target_path'), state_manager.get_item('output_path'), temp_video_fps, output_video_resolution, trim_frame_start, trim_frame_end): + logger.debug(translator.get('merging_video_succeeded'), __name__) + else: + if is_process_stopping(): + return 4 + logger.error(translator.get('merging_video_failed'), __name__) + return 1 + return 0 + + +def restore_audio() -> ErrorCode: + temp_frame_paths = resolve_temp_frame_paths(state_manager.get_temp_path(), state_manager.get_item('output_path'), state_manager.get_item('temp_frame_format')) + trim_frame_start, trim_frame_end = restrict_trim_frame(len(temp_frame_paths), state_manager.get_item('trim_frame_start'), state_manager.get_item('trim_frame_end')) + + if state_manager.get_item('output_audio_volume') == 0: + logger.info(translator.get('skipping_audio'), __name__) + move_temp_file(state_manager.get_temp_path(), state_manager.get_item('output_path')) + else: + source_audio_path = get_first(filter_audio_paths(state_manager.get_item('source_paths'))) + if source_audio_path: + if ffmpeg.replace_audio(source_audio_path, state_manager.get_item('output_path')): + conditional_clear_video_pool() + logger.debug(translator.get('replacing_audio_succeeded'), __name__) + else: + conditional_clear_video_pool() + if is_process_stopping(): + return 4 + logger.warn(translator.get('replacing_audio_skipped'), __name__) + move_temp_file(state_manager.get_temp_path(), state_manager.get_item('output_path')) + else: + if ffmpeg.restore_audio(state_manager.get_item('target_path'), state_manager.get_item('output_path'), trim_frame_start, trim_frame_end): + conditional_clear_video_pool() + logger.debug(translator.get('restoring_audio_succeeded'), __name__) + else: + conditional_clear_video_pool() + if is_process_stopping(): + return 4 + logger.warn(translator.get('restoring_audio_skipped'), __name__) + move_temp_file(state_manager.get_temp_path(), state_manager.get_item('output_path')) + return 0 + + +def finalize_video(start_time : float) -> ErrorCode: + if is_video(state_manager.get_item('output_path')): + logger.info(translator.get('processing_video_succeeded').format(seconds = calculate_end_time(start_time)), __name__) + else: + logger.error(translator.get('processing_video_failed'), __name__) + return 1 + return 0 diff --git a/facefusion/workflows/image_to_video.py b/facefusion/workflows/image_to_video.py index 18a5a863..4b982541 100644 --- a/facefusion/workflows/image_to_video.py +++ b/facefusion/workflows/image_to_video.py @@ -1,17 +1,9 @@ -from concurrent.futures import ThreadPoolExecutor, as_completed from functools import partial -from tqdm import tqdm - -from facefusion import content_analyser, ffmpeg, logger, process_manager, state_manager, translator, video_manager -from facefusion.common_helper import get_first -from facefusion.filesystem import filter_audio_paths, is_video -from facefusion.processors.core import get_processors_modules -from facefusion.temp_helper import move_temp_file, resolve_temp_frame_paths -from facefusion.time_helper import calculate_end_time +from facefusion import content_analyser, ffmpeg, logger, process_manager, state_manager, translator from facefusion.types import ErrorCode from facefusion.vision import detect_video_resolution, pack_resolution, restrict_trim_video_frame, restrict_video_fps, restrict_video_resolution, scale_resolution -from facefusion.workflows.core import clear, is_process_stopping, process_temp_frame, setup +from facefusion.workflows.core import clear, finalize_video, is_process_stopping, merge_frames, process_video, restore_audio, setup def process(start_time : float) -> ErrorCode: @@ -64,93 +56,3 @@ def create_temp_frames() -> ErrorCode: logger.error(translator.get('extracting_frames_failed'), __name__) return 1 return 0 - - -def process_video() -> ErrorCode: - temp_frame_paths = resolve_temp_frame_paths(state_manager.get_temp_path(), state_manager.get_item('output_path'), state_manager.get_item('temp_frame_format')) - - if temp_frame_paths: - with tqdm(total = len(temp_frame_paths), 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 enumerate(temp_frame_paths): - future = executor.submit(process_temp_frame, temp_frame_path, frame_number) - futures.append(future) - - for future in as_completed(futures): - if is_process_stopping(): - for __future__ in futures: - __future__.cancel() - - if not future.cancelled(): - future.result() - progress.update() - - for processor_module in get_processors_modules(state_manager.get_item('processors')): - processor_module.post_process() - - if is_process_stopping(): - return 4 - else: - logger.error(translator.get('temp_frames_not_found'), __name__) - return 1 - return 0 - - -def merge_frames() -> ErrorCode: - trim_frame_start, trim_frame_end = restrict_trim_video_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_fps = restrict_video_fps(state_manager.get_item('target_path'), state_manager.get_item('output_video_fps')) - - logger.info(translator.get('merging_video').format(resolution = pack_resolution(output_video_resolution), fps = state_manager.get_item('output_video_fps')), __name__) - if ffmpeg.merge_video(state_manager.get_item('target_path'), state_manager.get_item('output_path'), temp_video_fps, output_video_resolution, trim_frame_start, trim_frame_end): - logger.debug(translator.get('merging_video_succeeded'), __name__) - else: - if is_process_stopping(): - return 4 - logger.error(translator.get('merging_video_failed'), __name__) - return 1 - return 0 - - -def restore_audio() -> ErrorCode: - trim_frame_start, trim_frame_end = restrict_trim_video_frame(state_manager.get_item('target_path'), state_manager.get_item('trim_frame_start'), state_manager.get_item('trim_frame_end')) - - if state_manager.get_item('output_audio_volume') == 0: - logger.info(translator.get('skipping_audio'), __name__) - move_temp_file(state_manager.get_temp_path(), state_manager.get_item('output_path')) - else: - source_audio_path = get_first(filter_audio_paths(state_manager.get_item('source_paths'))) - if source_audio_path: - if ffmpeg.replace_audio(source_audio_path, state_manager.get_item('output_path')): - video_manager.clear_video_pool() - logger.debug(translator.get('replacing_audio_succeeded'), __name__) - else: - video_manager.clear_video_pool() - if is_process_stopping(): - return 4 - logger.warn(translator.get('replacing_audio_skipped'), __name__) - move_temp_file(state_manager.get_temp_path(), state_manager.get_item('output_path')) - else: - if ffmpeg.restore_audio(state_manager.get_item('target_path'), state_manager.get_item('output_path'), trim_frame_start, trim_frame_end): - video_manager.clear_video_pool() - logger.debug(translator.get('restoring_audio_succeeded'), __name__) - else: - video_manager.clear_video_pool() - if is_process_stopping(): - return 4 - logger.warn(translator.get('restoring_audio_skipped'), __name__) - move_temp_file(state_manager.get_temp_path(), state_manager.get_item('output_path')) - return 0 - - -def finalize_video(start_time : float) -> ErrorCode: - if is_video(state_manager.get_item('output_path')): - logger.info(translator.get('processing_video_succeeded').format(seconds = calculate_end_time(start_time)), __name__) - else: - logger.error(translator.get('processing_video_failed'), __name__) - return 1 - return 0