diff --git a/facefusion/vision.py b/facefusion/vision.py index 41986d5f..6f74b5cd 100644 --- a/facefusion/vision.py +++ b/facefusion/vision.py @@ -119,11 +119,21 @@ def predict_video_frame_total(video_path : str, fps : Fps, trim_frame_start : in if is_video(video_path): video_fps = detect_video_fps(video_path) trim_frame_start, trim_frame_end = restrict_trim_video_frame(video_path, trim_frame_start, trim_frame_end) - extract_frame_total = (trim_frame_end - trim_frame_start) * fps / video_fps - return math.floor(extract_frame_total) + extract_frame_start = resolve_extract_frame_index(video_fps, fps, trim_frame_start) + extract_frame_end = resolve_extract_frame_index(video_fps, fps, trim_frame_end) + + return extract_frame_end - extract_frame_start return 0 +def resolve_extract_frame_index(video_fps : Fps, fps : Fps, frame_index : int) -> int: + return math.floor(frame_index * fps / video_fps + 0.5) + + +def resolve_target_frame_index(video_fps : Fps, fps : Fps, frame_index : int) -> int: + return math.ceil((frame_index + 0.5) * video_fps / fps) - 1 + + def detect_video_fps(video_path : str) -> Optional[Fps]: if is_video(video_path): return ffprobe.extract_static_video_metadata(video_path).get('fps') diff --git a/facefusion/workflows/core.py b/facefusion/workflows/core.py index 7f03f4e8..4d394c0d 100644 --- a/facefusion/workflows/core.py +++ b/facefusion/workflows/core.py @@ -11,7 +11,7 @@ from facefusion.filesystem import filter_audio_paths, get_file_extension, has_au from facefusion.processors.core import get_processors_modules from facefusion.temp_helper import clear_temp_directory, create_temp_directory, resolve_temp_frame_set from facefusion.types import AudioFrame, ErrorCode, VisionFrame, WorkflowMode -from facefusion.vision import conditional_merge_vision_mask, extract_vision_mask, read_static_image, read_static_images, read_static_video_frame, restrict_trim_video_frame, restrict_video_fps, select_video_frames, write_image +from facefusion.vision import conditional_merge_vision_mask, detect_video_fps, extract_vision_mask, read_static_image, read_static_images, read_static_video_frame, resolve_extract_frame_index, resolve_target_frame_index, restrict_trim_video_frame, restrict_video_fps, select_video_frames, write_image def detect_workflow_mode() -> WorkflowMode: @@ -94,7 +94,13 @@ def conditional_get_reference_vision_frame() -> VisionFrame: def conditional_get_target_vision_frames(frame_index : int) -> List[VisionFrame]: if state_manager.get_item('workflow_mode') in [ 'image-to-video', 'image-to-video:frames' ]: - return select_video_frames(state_manager.get_item('target_path'), frame_index, state_manager.get_item('target_frame_amount')) + trim_frame_start, _ = restrict_trim_video_frame(state_manager.get_item('target_path'), state_manager.get_item('trim_frame_start'), state_manager.get_item('trim_frame_end')) + temp_video_fps = restrict_video_fps(state_manager.get_item('target_path'), state_manager.get_item('output_video_fps')) + video_fps = detect_video_fps(state_manager.get_item('target_path')) + temp_frame_index = resolve_extract_frame_index(video_fps, temp_video_fps, trim_frame_start) + frame_index - trim_frame_start + video_frame_index = resolve_target_frame_index(video_fps, temp_video_fps, temp_frame_index) + + return select_video_frames(state_manager.get_item('target_path'), video_frame_index, state_manager.get_item('target_frame_amount')) return [ read_static_image(state_manager.get_item('target_path')) ] diff --git a/facefusion/workflows/to_video.py b/facefusion/workflows/to_video.py index 8fc6c676..83236b15 100644 --- a/facefusion/workflows/to_video.py +++ b/facefusion/workflows/to_video.py @@ -13,8 +13,8 @@ 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.types import ErrorCode, Fps, Resolution, VisionFrame -from facefusion.vision import detect_image_resolution, detect_video_resolution, pack_resolution, read_static_video_frame, restrict_trim_video_frame, restrict_video_fps, restrict_video_resolution, scale_resolution, select_video_frames -from facefusion.workflows.core import is_process_stopping, process_temp_vision_frame +from facefusion.vision import detect_image_resolution, detect_video_resolution, pack_resolution, predict_video_frame_total, read_static_video_frame, restrict_trim_video_frame, restrict_video_fps, restrict_video_resolution, scale_resolution +from facefusion.workflows.core import conditional_get_target_vision_frames, is_process_stopping, process_temp_vision_frame def analyse_video() -> ErrorCode: @@ -43,7 +43,7 @@ def create_temp_frames() -> ErrorCode: def process_memory_frame(frame_index : int, temp_video_resolution : Resolution, output_video_resolution : Resolution) -> VisionFrame: - target_vision_frames = select_video_frames(state_manager.get_item('target_path'), frame_index, state_manager.get_item('target_frame_amount')) + target_vision_frames = conditional_get_target_vision_frames(frame_index) target_vision_frame = get_middle(target_vision_frames) temp_vision_frame = target_vision_frame.copy() @@ -69,7 +69,8 @@ def process_memory_frames() -> ErrorCode: 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) temp_video_fps = restrict_video_fps(state_manager.get_item('target_path'), state_manager.get_item('output_video_fps')) - temp_frame_range = range(trim_frame_start, trim_frame_end) + temp_frame_total = predict_video_frame_total(state_manager.get_item('target_path'), temp_video_fps, trim_frame_start, trim_frame_end) + temp_frame_range = range(trim_frame_start, trim_frame_start + temp_frame_total) if temp_frame_range: video_writer = video_manager.get_writer(state_manager.get_item('output_path'), temp_video_fps, output_video_resolution, output_video_resolution, state_manager.get_item('output_video_fps')) diff --git a/tests/test_cli_age_modifier.py b/tests/test_cli_age_modifier.py index 3ea1a48b..3683fc25 100644 --- a/tests/test_cli_age_modifier.py +++ b/tests/test_cli_age_modifier.py @@ -3,9 +3,11 @@ import sys import pytest +import facefusion.choices from facefusion import ffmpeg, ffmpeg_builder, process_manager from facefusion.download import conditional_download from facefusion.jobs.job_manager import clear_jobs, init_jobs +from facefusion.types import WorkflowStrategy from .assert_helper import get_test_example_file, get_test_examples_directory, get_test_jobs_directory, get_test_output_path, is_test_output_file, is_test_output_sequence, prepare_test_output_directory @@ -36,22 +38,25 @@ def before_each() -> None: prepare_test_output_directory() -def test_modify_age_to_image() -> None: - commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-image', '--jobs-path', get_test_jobs_directory(), '--processors', 'age_modifier', '--age-modifier-direction', '100', '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_path('test-age-face-to-image.jpg') ] +@pytest.mark.parametrize('workflow_strategy', facefusion.choices.workflow_strategies) +def test_modify_age_to_image(workflow_strategy : WorkflowStrategy) -> None: + commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-image', '--workflow-strategy', workflow_strategy, '--jobs-path', get_test_jobs_directory(), '--processors', 'age_modifier', '--age-modifier-direction', '100', '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_path('test-age-face-to-image.jpg') ] assert subprocess.run(commands).returncode == 0 assert is_test_output_file('test-age-face-to-image.jpg') is True -def test_modify_age_to_video() -> None: - commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-video', '--jobs-path', get_test_jobs_directory(), '--processors', 'age_modifier', '--age-modifier-direction', '100', '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_path('test-age-face-to-video.mp4'), '--trim-frame-end', '1' ] +@pytest.mark.parametrize('workflow_strategy', facefusion.choices.workflow_strategies) +def test_modify_age_to_video(workflow_strategy : WorkflowStrategy) -> None: + commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-video', '--workflow-strategy', workflow_strategy, '--jobs-path', get_test_jobs_directory(), '--processors', 'age_modifier', '--age-modifier-direction', '100', '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_path('test-age-face-to-video.mp4'), '--trim-frame-end', '1' ] assert subprocess.run(commands).returncode == 0 assert is_test_output_file('test-age-face-to-video.mp4') is True -def test_modify_age_to_video_as_frames() -> None: - commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-video:frames', '--jobs-path', get_test_jobs_directory(), '--processors', 'age_modifier', '--age-modifier-direction', '100', '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_path('test-age-face-to-video-as-frames'), '--trim-frame-end', '1' ] +@pytest.mark.parametrize('workflow_strategy', facefusion.choices.workflow_strategies) +def test_modify_age_to_video_as_frames(workflow_strategy : WorkflowStrategy) -> None: + commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-video:frames', '--workflow-strategy', workflow_strategy, '--jobs-path', get_test_jobs_directory(), '--processors', 'age_modifier', '--age-modifier-direction', '100', '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_path('test-age-face-to-video-as-frames'), '--trim-frame-end', '1' ] assert subprocess.run(commands).returncode == 0 assert is_test_output_sequence(get_test_output_path('test-age-face-to-video-as-frames')) is True diff --git a/tests/test_cli_background_remover.py b/tests/test_cli_background_remover.py index 5a631dc6..a38b2d04 100644 --- a/tests/test_cli_background_remover.py +++ b/tests/test_cli_background_remover.py @@ -3,9 +3,11 @@ import sys import pytest +import facefusion.choices from facefusion import ffmpeg, ffmpeg_builder, process_manager from facefusion.download import conditional_download from facefusion.jobs.job_manager import clear_jobs, init_jobs +from facefusion.types import WorkflowStrategy from .assert_helper import get_test_example_file, get_test_examples_directory, get_test_jobs_directory, get_test_output_path, is_test_output_file, is_test_output_sequence, prepare_test_output_directory @@ -37,22 +39,25 @@ def before_each() -> None: prepare_test_output_directory() -def test_remove_background_to_image() -> None: - commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-image', '--jobs-path', get_test_jobs_directory(), '--processors', 'background_remover', '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_path('test-remove-background-to-image.jpg') ] +@pytest.mark.parametrize('workflow_strategy', facefusion.choices.workflow_strategies) +def test_remove_background_to_image(workflow_strategy : WorkflowStrategy) -> None: + commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-image', '--workflow-strategy', workflow_strategy, '--jobs-path', get_test_jobs_directory(), '--processors', 'background_remover', '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_path('test-remove-background-to-image.jpg') ] assert subprocess.run(commands).returncode == 0 assert is_test_output_file('test-remove-background-to-image.jpg') is True -def test_remove_background_to_video() -> None: - commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-video', '--jobs-path', get_test_jobs_directory(), '--processors', 'background_remover', '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_path('test-remove-background-to-video.mp4'), '--trim-frame-end', '1' ] +@pytest.mark.parametrize('workflow_strategy', facefusion.choices.workflow_strategies) +def test_remove_background_to_video(workflow_strategy : WorkflowStrategy) -> None: + commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-video', '--workflow-strategy', workflow_strategy, '--jobs-path', get_test_jobs_directory(), '--processors', 'background_remover', '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_path('test-remove-background-to-video.mp4'), '--trim-frame-end', '1' ] assert subprocess.run(commands).returncode == 0 assert is_test_output_file('test-remove-background-to-video.mp4') is True -def test_remove_background_to_video_as_frames() -> None: - commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-video:frames', '--jobs-path', get_test_jobs_directory(), '--processors', 'background_remover', '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_path('test-remove-background-to-video-as-frames'), '--trim-frame-end', '1' ] +@pytest.mark.parametrize('workflow_strategy', facefusion.choices.workflow_strategies) +def test_remove_background_to_video_as_frames(workflow_strategy : WorkflowStrategy) -> None: + commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-video:frames', '--workflow-strategy', workflow_strategy, '--jobs-path', get_test_jobs_directory(), '--processors', 'background_remover', '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_path('test-remove-background-to-video-as-frames'), '--trim-frame-end', '1' ] assert subprocess.run(commands).returncode == 0 assert is_test_output_sequence(get_test_output_path('test-remove-background-to-video-as-frames')) is True diff --git a/tests/test_cli_expression_restorer.py b/tests/test_cli_expression_restorer.py index b8d1b417..e19d280e 100644 --- a/tests/test_cli_expression_restorer.py +++ b/tests/test_cli_expression_restorer.py @@ -3,9 +3,11 @@ import sys import pytest +import facefusion.choices from facefusion import ffmpeg, ffmpeg_builder, process_manager from facefusion.download import conditional_download from facefusion.jobs.job_manager import clear_jobs, init_jobs +from facefusion.types import WorkflowStrategy from .assert_helper import get_test_example_file, get_test_examples_directory, get_test_jobs_directory, get_test_output_path, is_test_output_file, is_test_output_sequence, prepare_test_output_directory @@ -36,22 +38,25 @@ def before_each() -> None: prepare_test_output_directory() -def test_restore_expression_to_image() -> None: - commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-image', '--jobs-path', get_test_jobs_directory(), '--processors', 'expression_restorer', '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_path('test-restore-expression-to-image.jpg') ] +@pytest.mark.parametrize('workflow_strategy', facefusion.choices.workflow_strategies) +def test_restore_expression_to_image(workflow_strategy : WorkflowStrategy) -> None: + commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-image', '--workflow-strategy', workflow_strategy, '--jobs-path', get_test_jobs_directory(), '--processors', 'expression_restorer', '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_path('test-restore-expression-to-image.jpg') ] assert subprocess.run(commands).returncode == 0 assert is_test_output_file('test-restore-expression-to-image.jpg') is True -def test_restore_expression_to_video() -> None: - commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-video', '--jobs-path', get_test_jobs_directory(), '--processors', 'expression_restorer', '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_path('test-restore-expression-to-video.mp4'), '--trim-frame-end', '1' ] +@pytest.mark.parametrize('workflow_strategy', facefusion.choices.workflow_strategies) +def test_restore_expression_to_video(workflow_strategy : WorkflowStrategy) -> None: + commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-video', '--workflow-strategy', workflow_strategy, '--jobs-path', get_test_jobs_directory(), '--processors', 'expression_restorer', '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_path('test-restore-expression-to-video.mp4'), '--trim-frame-end', '1' ] assert subprocess.run(commands).returncode == 0 assert is_test_output_file('test-restore-expression-to-video.mp4') is True -def test_restore_expression_to_video_as_frames() -> None: - commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-video:frames', '--jobs-path', get_test_jobs_directory(), '--processors', 'expression_restorer', '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_path('test-restore-expression-to-video-as-frames'), '--trim-frame-end', '1' ] +@pytest.mark.parametrize('workflow_strategy', facefusion.choices.workflow_strategies) +def test_restore_expression_to_video_as_frames(workflow_strategy : WorkflowStrategy) -> None: + commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-video:frames', '--workflow-strategy', workflow_strategy, '--jobs-path', get_test_jobs_directory(), '--processors', 'expression_restorer', '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_path('test-restore-expression-to-video-as-frames'), '--trim-frame-end', '1' ] assert subprocess.run(commands).returncode == 0 assert is_test_output_sequence(get_test_output_path('test-restore-expression-to-video-as-frames')) is True diff --git a/tests/test_cli_face_debugger.py b/tests/test_cli_face_debugger.py index 3631062d..f55d0b4a 100644 --- a/tests/test_cli_face_debugger.py +++ b/tests/test_cli_face_debugger.py @@ -3,9 +3,11 @@ import sys import pytest +import facefusion.choices from facefusion import ffmpeg, ffmpeg_builder, process_manager from facefusion.download import conditional_download from facefusion.jobs.job_manager import clear_jobs, init_jobs +from facefusion.types import WorkflowStrategy from .assert_helper import get_test_example_file, get_test_examples_directory, get_test_jobs_directory, get_test_output_path, is_test_output_file, is_test_output_sequence, prepare_test_output_directory @@ -37,22 +39,25 @@ def before_each() -> None: prepare_test_output_directory() -def test_debug_face_to_image() -> None: - commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-image', '--jobs-path', get_test_jobs_directory(), '--processors', 'face_debugger', '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_path('test-debug-face-to-image.jpg') ] +@pytest.mark.parametrize('workflow_strategy', facefusion.choices.workflow_strategies) +def test_debug_face_to_image(workflow_strategy : WorkflowStrategy) -> None: + commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-image', '--workflow-strategy', workflow_strategy, '--jobs-path', get_test_jobs_directory(), '--processors', 'face_debugger', '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_path('test-debug-face-to-image.jpg') ] assert subprocess.run(commands).returncode == 0 assert is_test_output_file('test-debug-face-to-image.jpg') is True -def test_debug_face_to_video() -> None: - commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-video', '--jobs-path', get_test_jobs_directory(), '--processors', 'face_debugger', '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_path('test-debug-face-to-video.mp4'), '--trim-frame-end', '1' ] +@pytest.mark.parametrize('workflow_strategy', facefusion.choices.workflow_strategies) +def test_debug_face_to_video(workflow_strategy : WorkflowStrategy) -> None: + commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-video', '--workflow-strategy', workflow_strategy, '--jobs-path', get_test_jobs_directory(), '--processors', 'face_debugger', '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_path('test-debug-face-to-video.mp4'), '--trim-frame-end', '1' ] assert subprocess.run(commands).returncode == 0 assert is_test_output_file('test-debug-face-to-video.mp4') is True -def test_debug_face_to_video_as_frames() -> None: - commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-video:frames', '--jobs-path', get_test_jobs_directory(), '--processors', 'face_debugger', '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_path('test-debug-face-to-video-as-frames'), '--trim-frame-end', '1' ] +@pytest.mark.parametrize('workflow_strategy', facefusion.choices.workflow_strategies) +def test_debug_face_to_video_as_frames(workflow_strategy : WorkflowStrategy) -> None: + commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-video:frames', '--workflow-strategy', workflow_strategy, '--jobs-path', get_test_jobs_directory(), '--processors', 'face_debugger', '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_path('test-debug-face-to-video-as-frames'), '--trim-frame-end', '1' ] assert subprocess.run(commands).returncode == 0 assert is_test_output_sequence(get_test_output_path('test-debug-face-to-video-as-frames')) is True diff --git a/tests/test_cli_face_editor.py b/tests/test_cli_face_editor.py index 11db41f6..42cde089 100644 --- a/tests/test_cli_face_editor.py +++ b/tests/test_cli_face_editor.py @@ -3,9 +3,11 @@ import sys import pytest +import facefusion.choices from facefusion import ffmpeg, ffmpeg_builder, process_manager from facefusion.download import conditional_download from facefusion.jobs.job_manager import clear_jobs, init_jobs +from facefusion.types import WorkflowStrategy from .assert_helper import get_test_example_file, get_test_examples_directory, get_test_jobs_directory, get_test_output_path, is_test_output_file, is_test_output_sequence, prepare_test_output_directory @@ -37,22 +39,25 @@ def before_each() -> None: prepare_test_output_directory() -def test_edit_face_to_image() -> None: - commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-image', '--jobs-path', get_test_jobs_directory(), '--processors', 'face_editor', '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_path('test-edit-face-to-image.jpg') ] +@pytest.mark.parametrize('workflow_strategy', facefusion.choices.workflow_strategies) +def test_edit_face_to_image(workflow_strategy : WorkflowStrategy) -> None: + commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-image', '--workflow-strategy', workflow_strategy, '--jobs-path', get_test_jobs_directory(), '--processors', 'face_editor', '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_path('test-edit-face-to-image.jpg') ] assert subprocess.run(commands).returncode == 0 assert is_test_output_file('test-edit-face-to-image.jpg') is True -def test_edit_face_to_video() -> None: - commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-video', '--jobs-path', get_test_jobs_directory(), '--processors', 'face_editor', '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_path('test-edit-face-to-video.mp4'), '--trim-frame-end', '1' ] +@pytest.mark.parametrize('workflow_strategy', facefusion.choices.workflow_strategies) +def test_edit_face_to_video(workflow_strategy : WorkflowStrategy) -> None: + commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-video', '--workflow-strategy', workflow_strategy, '--jobs-path', get_test_jobs_directory(), '--processors', 'face_editor', '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_path('test-edit-face-to-video.mp4'), '--trim-frame-end', '1' ] assert subprocess.run(commands).returncode == 0 assert is_test_output_file('test-edit-face-to-video.mp4') is True -def test_edit_face_to_video_as_frames() -> None: - commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-video:frames', '--jobs-path', get_test_jobs_directory(), '--processors', 'face_editor', '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_path('test-edit-face-to-video-as-frames'), '--trim-frame-end', '1' ] +@pytest.mark.parametrize('workflow_strategy', facefusion.choices.workflow_strategies) +def test_edit_face_to_video_as_frames(workflow_strategy : WorkflowStrategy) -> None: + commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-video:frames', '--workflow-strategy', workflow_strategy, '--jobs-path', get_test_jobs_directory(), '--processors', 'face_editor', '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_path('test-edit-face-to-video-as-frames'), '--trim-frame-end', '1' ] assert subprocess.run(commands).returncode == 0 assert is_test_output_sequence(get_test_output_path('test-edit-face-to-video-as-frames')) is True diff --git a/tests/test_cli_face_enhancer.py b/tests/test_cli_face_enhancer.py index 39c980aa..78605460 100644 --- a/tests/test_cli_face_enhancer.py +++ b/tests/test_cli_face_enhancer.py @@ -3,9 +3,11 @@ import sys import pytest +import facefusion.choices from facefusion import ffmpeg, ffmpeg_builder, process_manager from facefusion.download import conditional_download from facefusion.jobs.job_manager import clear_jobs, init_jobs +from facefusion.types import WorkflowStrategy from .assert_helper import get_test_example_file, get_test_examples_directory, get_test_jobs_directory, get_test_output_path, is_test_output_file, is_test_output_sequence, prepare_test_output_directory @@ -37,22 +39,25 @@ def before_each() -> None: prepare_test_output_directory() -def test_enhance_face_to_image() -> None: - commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-image', '--jobs-path', get_test_jobs_directory(), '--processors', 'face_enhancer', '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_path('test-enhance-face-to-image.jpg') ] +@pytest.mark.parametrize('workflow_strategy', facefusion.choices.workflow_strategies) +def test_enhance_face_to_image(workflow_strategy : WorkflowStrategy) -> None: + commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-image', '--workflow-strategy', workflow_strategy, '--jobs-path', get_test_jobs_directory(), '--processors', 'face_enhancer', '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_path('test-enhance-face-to-image.jpg') ] assert subprocess.run(commands).returncode == 0 assert is_test_output_file('test-enhance-face-to-image.jpg') is True -def test_enhance_face_to_video() -> None: - commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-video', '--jobs-path', get_test_jobs_directory(), '--processors', 'face_enhancer', '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_path('test-enhance-face-to-video.mp4'), '--trim-frame-end', '1' ] +@pytest.mark.parametrize('workflow_strategy', facefusion.choices.workflow_strategies) +def test_enhance_face_to_video(workflow_strategy : WorkflowStrategy) -> None: + commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-video', '--workflow-strategy', workflow_strategy, '--jobs-path', get_test_jobs_directory(), '--processors', 'face_enhancer', '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_path('test-enhance-face-to-video.mp4'), '--trim-frame-end', '1' ] assert subprocess.run(commands).returncode == 0 assert is_test_output_file('test-enhance-face-to-video.mp4') is True -def test_enhance_face_to_video_as_frames() -> None: - commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-video:frames', '--jobs-path', get_test_jobs_directory(), '--processors', 'face_enhancer', '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_path('test-enhance-face-to-video-as-frames'), '--trim-frame-end', '1' ] +@pytest.mark.parametrize('workflow_strategy', facefusion.choices.workflow_strategies) +def test_enhance_face_to_video_as_frames(workflow_strategy : WorkflowStrategy) -> None: + commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-video:frames', '--workflow-strategy', workflow_strategy, '--jobs-path', get_test_jobs_directory(), '--processors', 'face_enhancer', '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_path('test-enhance-face-to-video-as-frames'), '--trim-frame-end', '1' ] assert subprocess.run(commands).returncode == 0 assert is_test_output_sequence(get_test_output_path('test-enhance-face-to-video-as-frames')) is True diff --git a/tests/test_cli_face_swapper.py b/tests/test_cli_face_swapper.py index 8242cbed..582098b8 100644 --- a/tests/test_cli_face_swapper.py +++ b/tests/test_cli_face_swapper.py @@ -3,9 +3,11 @@ import sys import pytest +import facefusion.choices from facefusion import ffmpeg, ffmpeg_builder, process_manager from facefusion.download import conditional_download from facefusion.jobs.job_manager import clear_jobs, init_jobs +from facefusion.types import WorkflowStrategy from .assert_helper import get_test_example_file, get_test_examples_directory, get_test_jobs_directory, get_test_output_path, is_test_output_file, is_test_output_sequence, prepare_test_output_directory @@ -37,22 +39,25 @@ def before_each() -> None: prepare_test_output_directory() -def test_swap_face_to_image() -> None: - commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-image', '--jobs-path', get_test_jobs_directory(), '--processors', 'face_swapper', '-s', get_test_example_file('source.jpg'), '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_path('test-swap-face-to-image.jpg') ] +@pytest.mark.parametrize('workflow_strategy', facefusion.choices.workflow_strategies) +def test_swap_face_to_image(workflow_strategy : WorkflowStrategy) -> None: + commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-image', '--workflow-strategy', workflow_strategy, '--jobs-path', get_test_jobs_directory(), '--processors', 'face_swapper', '-s', get_test_example_file('source.jpg'), '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_path('test-swap-face-to-image.jpg') ] assert subprocess.run(commands).returncode == 0 assert is_test_output_file('test-swap-face-to-image.jpg') is True -def test_swap_face_to_video() -> None: - commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-video', '--jobs-path', get_test_jobs_directory(), '--processors', 'face_swapper', '-s', get_test_example_file('source.jpg'), '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_path('test-swap-face-to-video.mp4'), '--trim-frame-end', '1' ] +@pytest.mark.parametrize('workflow_strategy', facefusion.choices.workflow_strategies) +def test_swap_face_to_video(workflow_strategy : WorkflowStrategy) -> None: + commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-video', '--workflow-strategy', workflow_strategy, '--jobs-path', get_test_jobs_directory(), '--processors', 'face_swapper', '-s', get_test_example_file('source.jpg'), '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_path('test-swap-face-to-video.mp4'), '--trim-frame-end', '1' ] assert subprocess.run(commands).returncode == 0 assert is_test_output_file('test-swap-face-to-video.mp4') is True -def test_swap_face_to_video_as_frames() -> None: - commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-video:frames', '--jobs-path', get_test_jobs_directory(), '--processors', 'face_swapper', '-s', get_test_example_file('source.jpg'), '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_path('test-swap-face-to-video-as-frames'), '--trim-frame-end', '1' ] +@pytest.mark.parametrize('workflow_strategy', facefusion.choices.workflow_strategies) +def test_swap_face_to_video_as_frames(workflow_strategy : WorkflowStrategy) -> None: + commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-video:frames', '--workflow-strategy', workflow_strategy, '--jobs-path', get_test_jobs_directory(), '--processors', 'face_swapper', '-s', get_test_example_file('source.jpg'), '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_path('test-swap-face-to-video-as-frames'), '--trim-frame-end', '1' ] assert subprocess.run(commands).returncode == 0 assert is_test_output_sequence(get_test_output_path('test-swap-face-to-video-as-frames')) is True diff --git a/tests/test_cli_frame_colorizer.py b/tests/test_cli_frame_colorizer.py index caa353c3..8b9a3b2b 100644 --- a/tests/test_cli_frame_colorizer.py +++ b/tests/test_cli_frame_colorizer.py @@ -3,9 +3,11 @@ import sys import pytest +import facefusion.choices from facefusion import ffmpeg, ffmpeg_builder, process_manager from facefusion.download import conditional_download from facefusion.jobs.job_manager import clear_jobs, init_jobs +from facefusion.types import WorkflowStrategy from .assert_helper import get_test_example_file, get_test_examples_directory, get_test_jobs_directory, get_test_output_path, is_test_output_file, is_test_output_sequence, prepare_test_output_directory @@ -51,22 +53,25 @@ def before_each() -> None: prepare_test_output_directory() -def test_colorize_frame_to_image() -> None: - commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-image', '--jobs-path', get_test_jobs_directory(), '--processors', 'frame_colorizer', '-t', get_test_example_file('target-240p-0sat.jpg'), '-o', get_test_output_path('test_colorize-frame-to-image.jpg') ] +@pytest.mark.parametrize('workflow_strategy', facefusion.choices.workflow_strategies) +def test_colorize_frame_to_image(workflow_strategy : WorkflowStrategy) -> None: + commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-image', '--workflow-strategy', workflow_strategy, '--jobs-path', get_test_jobs_directory(), '--processors', 'frame_colorizer', '-t', get_test_example_file('target-240p-0sat.jpg'), '-o', get_test_output_path('test_colorize-frame-to-image.jpg') ] assert subprocess.run(commands).returncode == 0 assert is_test_output_file('test_colorize-frame-to-image.jpg') is True -def test_colorize_frame_to_video() -> None: - commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-video', '--jobs-path', get_test_jobs_directory(), '--processors', 'frame_colorizer', '-t', get_test_example_file('target-240p-0sat.mp4'), '-o', get_test_output_path('test-colorize-frame-to-video.mp4'), '--trim-frame-end', '1' ] +@pytest.mark.parametrize('workflow_strategy', facefusion.choices.workflow_strategies) +def test_colorize_frame_to_video(workflow_strategy : WorkflowStrategy) -> None: + commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-video', '--workflow-strategy', workflow_strategy, '--jobs-path', get_test_jobs_directory(), '--processors', 'frame_colorizer', '-t', get_test_example_file('target-240p-0sat.mp4'), '-o', get_test_output_path('test-colorize-frame-to-video.mp4'), '--trim-frame-end', '1' ] assert subprocess.run(commands).returncode == 0 assert is_test_output_file('test-colorize-frame-to-video.mp4') is True -def test_colorize_frame_to_video_as_frames() -> None: - commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-video:frames', '--jobs-path', get_test_jobs_directory(), '--processors', 'frame_colorizer', '-t', get_test_example_file('target-240p-0sat.mp4'), '-o', get_test_output_path('test-colorize-frame-to-video-as-frames'), '--trim-frame-end', '1' ] +@pytest.mark.parametrize('workflow_strategy', facefusion.choices.workflow_strategies) +def test_colorize_frame_to_video_as_frames(workflow_strategy : WorkflowStrategy) -> None: + commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-video:frames', '--workflow-strategy', workflow_strategy, '--jobs-path', get_test_jobs_directory(), '--processors', 'frame_colorizer', '-t', get_test_example_file('target-240p-0sat.mp4'), '-o', get_test_output_path('test-colorize-frame-to-video-as-frames'), '--trim-frame-end', '1' ] assert subprocess.run(commands).returncode == 0 assert is_test_output_sequence(get_test_output_path('test-colorize-frame-to-video-as-frames')) is True diff --git a/tests/test_cli_frame_enhancer.py b/tests/test_cli_frame_enhancer.py index 9fdceaad..0c557402 100644 --- a/tests/test_cli_frame_enhancer.py +++ b/tests/test_cli_frame_enhancer.py @@ -3,9 +3,11 @@ import sys import pytest +import facefusion.choices from facefusion import ffmpeg, ffmpeg_builder, process_manager from facefusion.download import conditional_download from facefusion.jobs.job_manager import clear_jobs, init_jobs +from facefusion.types import WorkflowStrategy from .assert_helper import get_test_example_file, get_test_examples_directory, get_test_jobs_directory, get_test_output_path, is_test_output_file, is_test_output_sequence, prepare_test_output_directory @@ -37,22 +39,25 @@ def before_each() -> None: prepare_test_output_directory() -def test_enhance_frame_to_image() -> None: - commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-image', '--jobs-path', get_test_jobs_directory(), '--processors', 'frame_enhancer', '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_path('test-enhance-frame-to-image.jpg') ] +@pytest.mark.parametrize('workflow_strategy', facefusion.choices.workflow_strategies) +def test_enhance_frame_to_image(workflow_strategy : WorkflowStrategy) -> None: + commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-image', '--workflow-strategy', workflow_strategy, '--jobs-path', get_test_jobs_directory(), '--processors', 'frame_enhancer', '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_path('test-enhance-frame-to-image.jpg') ] assert subprocess.run(commands).returncode == 0 assert is_test_output_file('test-enhance-frame-to-image.jpg') is True -def test_enhance_frame_to_video() -> None: - commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-video', '--jobs-path', get_test_jobs_directory(), '--processors', 'frame_enhancer', '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_path('test-enhance-frame-to-video.mp4'), '--trim-frame-end', '1' ] +@pytest.mark.parametrize('workflow_strategy', facefusion.choices.workflow_strategies) +def test_enhance_frame_to_video(workflow_strategy : WorkflowStrategy) -> None: + commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-video', '--workflow-strategy', workflow_strategy, '--jobs-path', get_test_jobs_directory(), '--processors', 'frame_enhancer', '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_path('test-enhance-frame-to-video.mp4'), '--trim-frame-end', '1' ] assert subprocess.run(commands).returncode == 0 assert is_test_output_file('test-enhance-frame-to-video.mp4') is True -def test_enhance_frame_to_video_as_frames() -> None: - commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-video:frames', '--jobs-path', get_test_jobs_directory(), '--processors', 'frame_enhancer', '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_path('test-enhance-frame-to-video-as-frames'), '--trim-frame-end', '1' ] +@pytest.mark.parametrize('workflow_strategy', facefusion.choices.workflow_strategies) +def test_enhance_frame_to_video_as_frames(workflow_strategy : WorkflowStrategy) -> None: + commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-video:frames', '--workflow-strategy', workflow_strategy, '--jobs-path', get_test_jobs_directory(), '--processors', 'frame_enhancer', '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_path('test-enhance-frame-to-video-as-frames'), '--trim-frame-end', '1' ] assert subprocess.run(commands).returncode == 0 assert is_test_output_sequence(get_test_output_path('test-enhance-frame-to-video-as-frames')) is True diff --git a/tests/test_cli_lip_syncer.py b/tests/test_cli_lip_syncer.py index e918bf78..19681eb9 100644 --- a/tests/test_cli_lip_syncer.py +++ b/tests/test_cli_lip_syncer.py @@ -3,9 +3,11 @@ import sys import pytest +import facefusion.choices from facefusion import ffmpeg, ffmpeg_builder, process_manager from facefusion.download import conditional_download from facefusion.jobs.job_manager import clear_jobs, init_jobs +from facefusion.types import WorkflowStrategy from .assert_helper import get_test_example_file, get_test_examples_directory, get_test_jobs_directory, get_test_output_path, is_test_output_file, is_test_output_sequence, prepare_test_output_directory @@ -38,29 +40,33 @@ def before_each() -> None: prepare_test_output_directory() -def test_sync_lip_to_image() -> None: - commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'audio-to-image:video', '--jobs-path', get_test_jobs_directory(), '--processors', 'lip_syncer', '-s', get_test_example_file('source.mp3'), '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_path('test_sync_lip_to_image.mp4') ] +@pytest.mark.parametrize('workflow_strategy', facefusion.choices.workflow_strategies) +def test_sync_lip_to_image(workflow_strategy : WorkflowStrategy) -> None: + commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'audio-to-image:video', '--workflow-strategy', workflow_strategy, '--jobs-path', get_test_jobs_directory(), '--processors', 'lip_syncer', '-s', get_test_example_file('source.mp3'), '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_path('test_sync_lip_to_image.mp4') ] assert subprocess.run(commands).returncode == 0 assert is_test_output_file('test_sync_lip_to_image.mp4') is True -def test_sync_lip_to_image_as_frames() -> None: - commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'audio-to-image:frames', '--jobs-path', get_test_jobs_directory(), '--processors', 'lip_syncer', '-s', get_test_example_file('source.mp3'), '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_path('test_sync_lip_to_image_as_frames') ] +@pytest.mark.parametrize('workflow_strategy', facefusion.choices.workflow_strategies) +def test_sync_lip_to_image_as_frames(workflow_strategy : WorkflowStrategy) -> None: + commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'audio-to-image:frames', '--workflow-strategy', workflow_strategy, '--jobs-path', get_test_jobs_directory(), '--processors', 'lip_syncer', '-s', get_test_example_file('source.mp3'), '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_path('test_sync_lip_to_image_as_frames') ] assert subprocess.run(commands).returncode == 0 assert is_test_output_sequence(get_test_output_path('test_sync_lip_to_image_as_frames')) is True -def test_sync_lip_to_video() -> None: - commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-video', '--jobs-path', get_test_jobs_directory(), '--processors', 'lip_syncer', '-s', get_test_example_file('source.mp3'), '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_path('test_sync_lip_to_video.mp4'), '--trim-frame-end', '1' ] +@pytest.mark.parametrize('workflow_strategy', facefusion.choices.workflow_strategies) +def test_sync_lip_to_video(workflow_strategy : WorkflowStrategy) -> None: + commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-video', '--workflow-strategy', workflow_strategy, '--jobs-path', get_test_jobs_directory(), '--processors', 'lip_syncer', '-s', get_test_example_file('source.mp3'), '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_path('test_sync_lip_to_video.mp4'), '--trim-frame-end', '1' ] assert subprocess.run(commands).returncode == 0 assert is_test_output_file('test_sync_lip_to_video.mp4') is True -def test_sync_lip_to_video_as_frames() -> None: - commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-video:frames', '--jobs-path', get_test_jobs_directory(), '--processors', 'lip_syncer', '-s', get_test_example_file('source.mp3'), '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_path('test_sync_lip_to_video_as_frames'), '--trim-frame-end', '1' ] +@pytest.mark.parametrize('workflow_strategy', facefusion.choices.workflow_strategies) +def test_sync_lip_to_video_as_frames(workflow_strategy : WorkflowStrategy) -> None: + commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-video:frames', '--workflow-strategy', workflow_strategy, '--jobs-path', get_test_jobs_directory(), '--processors', 'lip_syncer', '-s', get_test_example_file('source.mp3'), '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_path('test_sync_lip_to_video_as_frames'), '--trim-frame-end', '1' ] assert subprocess.run(commands).returncode == 0 assert is_test_output_sequence(get_test_output_path('test_sync_lip_to_video_as_frames')) is True diff --git a/tests/test_cli_output_fps.py b/tests/test_cli_output_fps.py new file mode 100644 index 00000000..aec6b65f --- /dev/null +++ b/tests/test_cli_output_fps.py @@ -0,0 +1,72 @@ +import subprocess +import sys + +import numpy +import pytest + +from facefusion import ffmpeg, ffmpeg_builder, process_manager +from facefusion.download import conditional_download +from facefusion.jobs.job_manager import clear_jobs, init_jobs +from facefusion.types import Fps, WorkflowStrategy +from facefusion.vision import count_video_frame_total, detect_video_fps, read_video_frame +from .assert_helper import get_test_example_file, get_test_examples_directory, get_test_jobs_directory, get_test_output_path, prepare_test_output_directory + + +@pytest.fixture(scope = 'module', autouse = True) +def before_all() -> None: + process_manager.start() + conditional_download(get_test_examples_directory(), + [ + 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/source.jpg', + 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/target-240p.mp4' + ]) + + for output_video_fps in [ 30, 60 ]: + ffmpeg.run_ffmpeg( + ffmpeg_builder.chain( + ffmpeg_builder.set_input(get_test_example_file('target-240p.mp4')), + ffmpeg_builder.select_frame_range(0, 30, output_video_fps), + ffmpeg_builder.set_video_encoder('libx264'), + ffmpeg_builder.enforce_pixel_format('yuv420p'), + [ + '-crf', + '0', + '-an' + ], + ffmpeg_builder.force_output(get_test_example_file('target-240p-30frames-' + str(output_video_fps) + 'fps.mp4')) + ) + ) + + +@pytest.fixture(scope = 'function', autouse = True) +def before_each() -> None: + clear_jobs(get_test_jobs_directory()) + init_jobs(get_test_jobs_directory()) + prepare_test_output_directory() + + +@pytest.mark.parametrize('workflow_strategy, output_video_fps, trim_frame_end, output_video_frame_total', +[ + ('disk', 30, 30, 36), + ('memory', 30, 30, 36), + ('disk', 60, 30, 72), + ('memory', 60, 30, 72) +]) +def test_output_video_fps(workflow_strategy : WorkflowStrategy, output_video_fps : Fps, trim_frame_end : int, output_video_frame_total : int) -> None: + actual_file_path = get_test_output_path('test-output-video-fps-actual-' + workflow_strategy + '-' + str(output_video_fps) + '.mp4') + expect_file_path = get_test_output_path('test-output-video-fps-expect-' + workflow_strategy + '-' + str(output_video_fps) + '.mp4') + actual_commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-video', '--workflow-strategy', workflow_strategy, '--jobs-path', get_test_jobs_directory(), '-s', get_test_example_file('source.jpg'), '-t', get_test_example_file('target-240p.mp4'), '-o', actual_file_path, '--trim-frame-end', str(trim_frame_end), '--output-video-fps', str(output_video_fps) ] + expect_commands = [ sys.executable, 'facefusion.py', 'run', '--workflow-mode', 'image-to-video', '--workflow-strategy', workflow_strategy, '--jobs-path', get_test_jobs_directory(), '-s', get_test_example_file('source.jpg'), '-t', get_test_example_file('target-240p-30frames-' + str(output_video_fps) + 'fps.mp4'), '-o', expect_file_path ] + + assert subprocess.run(actual_commands).returncode == 0 + assert subprocess.run(expect_commands).returncode == 0 + + assert detect_video_fps(actual_file_path) == output_video_fps + assert count_video_frame_total(actual_file_path) == output_video_frame_total + assert count_video_frame_total(expect_file_path) == output_video_frame_total + + for frame_index in range(output_video_frame_total): + actual_vision_frame = read_video_frame(actual_file_path, frame_index) + expect_vision_frame = read_video_frame(expect_file_path, frame_index) + + assert numpy.array_equal(actual_vision_frame, expect_vision_frame) is True diff --git a/tests/test_ffmpeg.py b/tests/test_ffmpeg.py index 9389f14f..8c7f88c1 100644 --- a/tests/test_ffmpeg.py +++ b/tests/test_ffmpeg.py @@ -11,6 +11,7 @@ from facefusion.ffprobe import probe_audio_entries, probe_video_entries from facefusion.filesystem import copy_file, is_image from facefusion.temp_helper import clear_temp_directory, create_temp_directory, get_temp_file_path, resolve_temp_frame_paths from facefusion.types import EncoderSet +from facefusion.vision import predict_video_frame_total from .assert_helper import get_test_example_file, get_test_examples_directory, get_test_output_path, prepare_test_output_directory @@ -119,6 +120,7 @@ def test_extract_frames() -> None: assert extract_frames(target_path, output_path, (452, 240), 30.0, trim_frame_start, trim_frame_end) is True assert len(resolve_temp_frame_paths(state_manager.get_temp_path(), output_path, state_manager.get_item('temp_frame_format'))) == frame_total + assert predict_video_frame_total(target_path, 30.0, trim_frame_start, trim_frame_end) == frame_total clear_temp_directory(state_manager.get_temp_path(), output_path) diff --git a/tests/test_vision.py b/tests/test_vision.py index a499c7b3..f5d208a4 100644 --- a/tests/test_vision.py +++ b/tests/test_vision.py @@ -4,7 +4,7 @@ import pytest from facefusion import ffmpeg, ffmpeg_builder, process_manager from facefusion.download import conditional_download -from facefusion.vision import calculate_histogram_difference, count_video_frame_total, detect_image_resolution, detect_video_duration, detect_video_fps, detect_video_resolution, match_frame_color, normalize_resolution, pack_resolution, predict_video_frame_total, read_image, read_video_frame, restrict_image_resolution, restrict_trim_video_frame, restrict_video_fps, restrict_video_resolution, scale_resolution, select_video_frames, unpack_resolution, write_image +from facefusion.vision import calculate_histogram_difference, count_video_frame_total, detect_image_resolution, detect_video_duration, detect_video_fps, detect_video_resolution, match_frame_color, normalize_resolution, pack_resolution, predict_video_frame_total, read_image, read_video_frame, resolve_extract_frame_index, resolve_target_frame_index, restrict_image_resolution, restrict_trim_video_frame, restrict_video_fps, restrict_video_resolution, scale_resolution, select_video_frames, unpack_resolution, write_image from .assert_helper import get_test_example_file, get_test_examples_directory, get_test_output_path, prepare_test_output_directory @@ -154,9 +154,25 @@ def test_predict_video_frame_total() -> None: assert predict_video_frame_total(get_test_example_file('target-240p-25fps.mp4'), 12.5, 0, 100) == 50 assert predict_video_frame_total(get_test_example_file('target-240p-25fps.mp4'), 25, 0, 100) == 100 assert predict_video_frame_total(get_test_example_file('target-240p-25fps.mp4'), 25, 0, 200) == 200 + assert predict_video_frame_total(get_test_example_file('target-240p-25fps.mp4'), 6.25, 0, 270) == 68 + assert predict_video_frame_total(get_test_example_file('target-240p-30fps.mp4'), 9.49, 40, 200) == 50 assert predict_video_frame_total('invalid', 25, 0, 100) == 0 +def test_resolve_extract_frame_index() -> None: + assert resolve_extract_frame_index(25, 12.5, 100) == 50 + assert resolve_extract_frame_index(25, 25, 100) == 100 + assert resolve_extract_frame_index(25, 6.25, 270) == 68 + assert resolve_extract_frame_index(30, 9.49, 40) == 13 + + +def test_resolve_target_frame_index() -> None: + assert resolve_target_frame_index(25, 12.5, 50) == 100 + assert resolve_target_frame_index(25, 25, 100) == 100 + assert resolve_target_frame_index(25, 6.25, 1) == 5 + assert resolve_target_frame_index(30, 9.49, 13) == 42 + + def test_detect_video_fps() -> None: assert detect_video_fps(get_test_example_file('target-240p-25fps.mp4')) == 25.0 assert detect_video_fps(get_test_example_file('target-240p-30fps.mp4')) == 30.0