From 585a7d75da1c360b6754829d9fcb4fb996238d58 Mon Sep 17 00:00:00 2001 From: Henry Ruhs Date: Sat, 25 Jul 2026 11:47:36 +0200 Subject: [PATCH] Cleanup Part1 (#1201) * remove some todos, improve video manager, simplify ffmpeg commands and more * do more * remove thread count for filters --- facefusion/download.py | 3 ++ facefusion/ffmpeg.py | 32 +++++++++------- facefusion/ffmpeg_builder.py | 15 ++------ facefusion/ffprobe.py | 3 ++ facefusion/types.py | 16 +++++--- facefusion/video_manager.py | 52 +++++++++++++------------- facefusion/workflows/core.py | 5 +-- facefusion/workflows/image_to_video.py | 2 +- tests/test_ffmpeg_builder.py | 19 ++++------ tests/test_video_manager.py | 25 +++++++------ 10 files changed, 87 insertions(+), 85 deletions(-) diff --git a/facefusion/download.py b/facefusion/download.py index 8ba0c1e7..d473d613 100644 --- a/facefusion/download.py +++ b/facefusion/download.py @@ -32,6 +32,7 @@ def conditional_download(download_directory_path : str, urls : List[str]) -> Non curl_builder.set_timeout(5), curl_builder.set_retry(5) ) + open_curl(commands) current_size = initial_size progress.set_postfix(download_providers = state_manager.get_item('download_providers'), file_name = download_file_name) @@ -48,6 +49,7 @@ def get_static_download_size(url : str) -> int: curl_builder.ping(url), curl_builder.set_timeout(5) ) + process = open_curl(commands) lines = reversed(process.stdout.readlines()) @@ -66,6 +68,7 @@ def ping_static_url(url : str) -> bool: curl_builder.ping(url), curl_builder.set_timeout(5) ) + process = open_curl(commands) process.communicate() return process.returncode == 0 diff --git a/facefusion/ffmpeg.py b/facefusion/ffmpeg.py index 28f3730a..8034cc61 100644 --- a/facefusion/ffmpeg.py +++ b/facefusion/ffmpeg.py @@ -10,7 +10,7 @@ import facefusion.choices from facefusion import ffmpeg_builder, ffprobe, logger, process_manager, state_manager, translator, vision from facefusion.filesystem import get_file_format, remove_file from facefusion.temp_helper import get_temp_file_path, get_temp_frame_pattern -from facefusion.types import AudioBuffer, AudioEncoder, Command, EncoderSet, Fps, Resolution, UpdateProgress, VideoEncoder, VideoFormat, VideoMetadata +from facefusion.types import AudioBuffer, AudioEncoder, Command, EncoderSet, Fps, Resolution, UpdateProgress, VideoEncoder, VideoFormat, VideoReaderMetadata def run_ffmpeg_with_progress(commands : List[Command], update_progress : UpdateProgress) -> subprocess.Popen[bytes]: @@ -69,24 +69,20 @@ def open_ffmpeg(commands : List[Command]) -> subprocess.Popen[bytes]: return subprocess.Popen(commands, stdin = subprocess.PIPE, stdout = subprocess.PIPE) -#todo: needs review - [decoding] [critical: medium] raw pipe reader with seek based start, spawn moved from the POC video_manager into ffmpeg -#todo: question if this does too much -def create_video_reader(video_path : str, frame_position : int, video_metadata : VideoMetadata) -> subprocess.Popen[bytes]: +def create_video_reader(video_path : str, frame_position : int, video_metadata : VideoReaderMetadata) -> subprocess.Popen[bytes]: commands = ffmpeg_builder.chain( - ffmpeg_builder.set_input_seek(frame_position / video_metadata.get('fps')), + ffmpeg_builder.seek_to(frame_position / video_metadata.get('fps')), ffmpeg_builder.set_input(video_path), - ffmpeg_builder.set_filter_thread_count(4), ffmpeg_builder.restrict_color_transfer(video_metadata.get('color_transfer')), ffmpeg_builder.prevent_frame_drop(), ffmpeg_builder.enforce_pixel_format('bgr24'), ffmpeg_builder.set_output_format('rawvideo'), ffmpeg_builder.cast_stream() ) + return open_ffmpeg(commands) -#todo: needs review - [encoding] [critical: high] pipe writer always converts and tags bt709, temp_pixel_format drives the pipe channels, encoder_thread_count hardcoded to 16 -#todo: question if this does too much def create_video_writer(target_path : str, temp_video_fps : Fps, temp_video_resolution : Resolution, output_video_resolution : Resolution, output_video_fps : Fps) -> subprocess.Popen[bytes]: output_video_encoder = state_manager.get_item('output_video_encoder') output_video_quality = state_manager.get_item('output_video_quality') @@ -94,7 +90,6 @@ def create_video_writer(target_path : str, temp_video_fps : Fps, temp_video_reso temp_video_path = get_temp_file_path(target_path) temp_video_format = cast(VideoFormat, get_file_format(temp_video_path)) output_video_encoder = fix_video_encoder(temp_video_format, output_video_encoder) - encoder_thread_count = 16 commands = ffmpeg_builder.chain( ffmpeg_builder.set_output_format('rawvideo'), @@ -102,10 +97,9 @@ def create_video_writer(target_path : str, temp_video_fps : Fps, temp_video_reso ffmpeg_builder.set_media_resolution(vision.pack_resolution(temp_video_resolution)), ffmpeg_builder.set_input_fps(temp_video_fps), ffmpeg_builder.set_input('pipe:0'), - ffmpeg_builder.set_filter_thread_count(4), ffmpeg_builder.set_media_resolution(vision.pack_resolution(output_video_resolution)), ffmpeg_builder.set_video_encoder(output_video_encoder), - ffmpeg_builder.set_global_thread_count(encoder_thread_count), + ffmpeg_builder.set_thread_count(16), ffmpeg_builder.set_video_tag(output_video_encoder, temp_video_format), ffmpeg_builder.set_video_quality(output_video_encoder, output_video_quality), ffmpeg_builder.set_video_preset(output_video_encoder, output_video_preset), @@ -116,6 +110,7 @@ def create_video_writer(target_path : str, temp_video_fps : Fps, temp_video_reso ffmpeg_builder.set_pixel_format(output_video_encoder), ffmpeg_builder.force_output(temp_video_path) ) + return open_ffmpeg(commands) @@ -160,6 +155,7 @@ def extract_frames(target_path : str, temp_video_resolution : Resolution, temp_v color_transfer = ffprobe.extract_static_video_metadata(target_path).get('color_transfer') extract_frame_total = vision.predict_video_frame_total(target_path, temp_video_fps, trim_frame_start, trim_frame_end) temp_frame_pattern = get_temp_frame_pattern(target_path, '%08d') + commands = ffmpeg_builder.chain( ffmpeg_builder.set_input(target_path), ffmpeg_builder.set_media_resolution(vision.pack_resolution(temp_video_resolution)), @@ -181,24 +177,28 @@ def extract_frames(target_path : str, temp_video_resolution : Resolution, temp_v def copy_image(target_path : str, temp_image_resolution : Resolution) -> bool: temp_image_path = get_temp_file_path(target_path) + commands = ffmpeg_builder.chain( ffmpeg_builder.set_input(target_path), ffmpeg_builder.set_media_resolution(vision.pack_resolution(temp_image_resolution)), ffmpeg_builder.set_image_quality(target_path, 100), ffmpeg_builder.force_output(temp_image_path) ) + return run_ffmpeg(commands).returncode == 0 def finalize_image(target_path : str, output_path : str, output_image_resolution : Resolution) -> bool: output_image_quality = state_manager.get_item('output_image_quality') temp_image_path = get_temp_file_path(target_path) + commands = ffmpeg_builder.chain( ffmpeg_builder.set_input(temp_image_path), ffmpeg_builder.set_media_resolution(vision.pack_resolution(output_image_resolution)), ffmpeg_builder.set_image_quality(target_path, output_image_quality), ffmpeg_builder.force_output(output_path) ) + return run_ffmpeg(commands).returncode == 0 @@ -228,8 +228,8 @@ def restore_audio(target_path : str, output_path : str, trim_frame_start : int, temp_video_format = cast(VideoFormat, get_file_format(temp_video_path)) temp_video_duration = vision.detect_video_duration(temp_video_path) output_video_format = cast(VideoFormat, get_file_format(output_path)) - output_audio_encoder = fix_audio_encoder(temp_video_format, output_audio_encoder) + commands = ffmpeg_builder.chain( ffmpeg_builder.set_input(temp_video_path), ffmpeg_builder.select_media_range(trim_frame_start, trim_frame_end, target_video_fps), @@ -244,6 +244,7 @@ def restore_audio(target_path : str, output_path : str, trim_frame_start : int, ffmpeg_builder.set_faststart(output_video_format), ffmpeg_builder.force_output(output_path) ) + return run_ffmpeg(commands).returncode == 0 @@ -255,8 +256,8 @@ def replace_audio(target_path : str, audio_path : str, output_path : str) -> boo temp_video_format = cast(VideoFormat, get_file_format(temp_video_path)) temp_video_duration = vision.detect_video_duration(temp_video_path) output_video_format = cast(VideoFormat, get_file_format(output_path)) - output_audio_encoder = fix_audio_encoder(temp_video_format, output_audio_encoder) + commands = ffmpeg_builder.chain( ffmpeg_builder.set_input(temp_video_path), ffmpeg_builder.set_input(audio_path), @@ -268,6 +269,7 @@ def replace_audio(target_path : str, audio_path : str, output_path : str) -> boo ffmpeg_builder.set_faststart(output_video_format), ffmpeg_builder.force_output(output_path) ) + return run_ffmpeg(commands).returncode == 0 @@ -279,8 +281,8 @@ def merge_video(target_path : str, temp_video_fps : Fps, output_video_resolution temp_video_path = get_temp_file_path(target_path) temp_video_format = cast(VideoFormat, get_file_format(temp_video_path)) temp_frame_pattern = get_temp_frame_pattern(target_path, '%08d') - output_video_encoder = fix_video_encoder(temp_video_format, output_video_encoder) + commands = ffmpeg_builder.chain( ffmpeg_builder.set_input_fps(temp_video_fps), ffmpeg_builder.set_start_number(trim_frame_start), @@ -316,6 +318,7 @@ def concat_video(output_path : str, temp_output_paths : List[str]) -> bool: output_path = os.path.abspath(output_path) output_video_format = cast(VideoFormat, get_file_format(output_path)) + commands = ffmpeg_builder.chain( ffmpeg_builder.unsafe_concat(), ffmpeg_builder.set_input(concat_video_file.name), @@ -324,6 +327,7 @@ def concat_video(output_path : str, temp_output_paths : List[str]) -> bool: ffmpeg_builder.set_faststart(output_video_format), ffmpeg_builder.force_output(output_path) ) + process = run_ffmpeg(commands) process.communicate() remove_file(concat_video_path) diff --git a/facefusion/ffmpeg_builder.py b/facefusion/ffmpeg_builder.py index eb5cbc6c..a818e225 100644 --- a/facefusion/ffmpeg_builder.py +++ b/facefusion/ffmpeg_builder.py @@ -83,14 +83,10 @@ def unsafe_concat() -> List[Command]: return [ '-f', 'concat', '-safe', '0' ] -#todo: needs review - [seeking] [critical: low] seek based start for the pipe reader -#todo: question to rename set_input_seek to just set_input -def set_input_seek(seek_time : float) -> List[Command]: - return [ '-ss', str(seek_time) ] +def seek_to(time : float) -> List[Command]: + return [ '-ss', str(time)] -#todo: needs review - [decoding] [critical: low] raw output format for pipe io -#todo: question if set_output_format is needed def set_output_format(output_format : str) -> List[Command]: return [ '-f', output_format ] @@ -206,15 +202,10 @@ def set_audio_volume(audio_volume : int) -> List[Command]: #todo: needs review - [encoding] [critical: low] explicit ffmpeg thread cap -def set_global_thread_count(thread_count : int) -> List[Command]: +def set_thread_count(thread_count : int) -> List[Command]: return [ '-threads', str(thread_count) ] -#todo: needs review - [decoding] [critical: low] threads the filter graph, new against the POC -def set_filter_thread_count(thread_count : int) -> List[Command]: - return [ '-filter_threads', str(thread_count) ] - - def set_video_encoder(video_encoder : str) -> List[Command]: return [ '-c:v', video_encoder ] diff --git a/facefusion/ffprobe.py b/facefusion/ffprobe.py index 24af62d4..9ab75956 100644 --- a/facefusion/ffprobe.py +++ b/facefusion/ffprobe.py @@ -32,6 +32,7 @@ def probe_audio_entries(audio_path : str, entries : List[str]) -> Dict[str, str] ffprobe_builder.format_to_key_value(), ffprobe_builder.set_input(audio_path) ) + output, _ = run_ffprobe(commands).communicate() return parse_entries(output) @@ -44,6 +45,7 @@ def probe_video_entries(video_path : str, entries : List[str]) -> Dict[str, str] ffprobe_builder.format_to_key_value(), ffprobe_builder.set_input(video_path) ) + output, _ = run_ffprobe(commands).communicate() return parse_entries(output) @@ -55,6 +57,7 @@ def probe_format_entries(media_path : str, entries : List[str]) -> Dict[str, str ffprobe_builder.format_to_key_value(), ffprobe_builder.set_input(media_path) ) + output, _ = run_ffprobe(commands).communicate() return parse_entries(output) diff --git a/facefusion/types.py b/facefusion/types.py index 7407a821..1e59f849 100755 --- a/facefusion/types.py +++ b/facefusion/types.py @@ -123,23 +123,27 @@ VideoMetadata = TypedDict('VideoMetadata', 'bit_rate' : BitRate, 'color_transfer' : ColorTransfer }) -#todo: needs review - [types] [critical: low] reader and writer state around ffmpeg processes, metadata embedded whole -#todo: question if the body of VideoReader and VideoWriter needs all the keys +VideoReaderMetadata : TypeAlias = VideoMetadata +VideoWriterMetadata = TypedDict('VideoWriterMetadata', +{ + 'fps' : Fps, + 'resolution' : Resolution +}) VideoReader = TypedDict('VideoReader', { 'id' : str, - 'process' : subprocess.Popen[bytes], 'file_path' : str, - 'metadata' : VideoMetadata, + 'process' : subprocess.Popen[bytes], + 'metadata' : VideoReaderMetadata, 'position' : int }) VideoReaderSet : TypeAlias = Dict[str, VideoReader] VideoWriter = TypedDict('VideoWriter', { 'id' : str, - 'process' : subprocess.Popen[bytes], 'file_path' : str, - 'metadata' : VideoMetadata + 'process' : subprocess.Popen[bytes], + 'metadata' : VideoWriterMetadata }) VideoWriterSet : TypeAlias = Dict[str, VideoWriter] VideoPoolSet = TypedDict('VideoPoolSet', diff --git a/facefusion/video_manager.py b/facefusion/video_manager.py index a6716786..8da514ce 100644 --- a/facefusion/video_manager.py +++ b/facefusion/video_manager.py @@ -5,7 +5,7 @@ import numpy from facefusion import ffmpeg, ffprobe, frame_store from facefusion.common_helper import get_first, get_last -from facefusion.types import Fps, Resolution, VideoMetadata, VideoPoolSet, VideoReader, VideoWriter, VisionFrame, VisionFrameSet +from facefusion.types import Fps, Resolution, VideoPoolSet, VideoReader, VideoWriter, VisionFrame, VisionFrameSet VIDEO_POOL_SET : VideoPoolSet =\ { @@ -14,7 +14,6 @@ VIDEO_POOL_SET : VideoPoolSet =\ } -#todo: needs review - [lifecycle] [critical: medium] pooled reader per path is created without lock and only reaped via clear_video_pool def get_reader(video_path : str) -> VideoReader: if video_path not in VIDEO_POOL_SET.get('reader'): video_metadata = ffprobe.extract_static_video_metadata(video_path) @@ -22,8 +21,8 @@ def get_reader(video_path : str) -> VideoReader: VIDEO_POOL_SET['reader'][video_path] =\ { 'id': uuid.uuid4().hex, - 'process': ffmpeg.create_video_reader(video_path, 0, video_metadata), 'file_path': video_path, + 'process': ffmpeg.create_video_reader(video_path, 0, video_metadata), 'metadata': video_metadata, 'position': 0 } @@ -33,10 +32,10 @@ def get_reader(video_path : str) -> VideoReader: #todo: needs review - [seeking] [critical: high] forward skip up to 128 frames by draining the pipe, everything else refreshes the process def conditional_set_video_reader_position(video_reader : VideoReader, frame_position : int) -> None: - skip_margin = 128 skip_total = frame_position - video_reader.get('position') + skip_margin = 128 - if skip_total > 0 and skip_total <= skip_margin: + if 0 < skip_total <= skip_margin: for _ in range(skip_total): read_video_reader_frame(video_reader) @@ -44,10 +43,9 @@ def conditional_set_video_reader_position(video_reader : VideoReader, frame_posi refresh_video_reader(video_reader, frame_position) -#todo: needs review - [seeking] [critical: high] kill and respawn per out of order seek, frequent refreshes stack up on random access def refresh_video_reader(video_reader : VideoReader, frame_position : int) -> None: - video_reader.get('process').kill() - video_reader.get('process').wait() + close_video_reader(video_reader) + video_reader['process'] = ffmpeg.create_video_reader(video_reader.get('file_path'), frame_position, video_reader.get('metadata')) video_reader['position'] = frame_position @@ -93,42 +91,46 @@ def read_video_reader_window(video_reader : VideoReader, frame_start : int, fram return frame_store.select_frame_set(id, frame_start, frame_end) -#todo: needs review - [lifecycle] [critical: low] pooled writer keyed by target_path, metadata forwarded by the caller -def get_writer(target_path : str, video_metadata : VideoMetadata, temp_video_fps : Fps, temp_video_resolution : Resolution, output_video_resolution : Resolution, output_video_fps : Fps) -> VideoWriter: - if target_path not in VIDEO_POOL_SET.get('writer'): - VIDEO_POOL_SET['writer'][target_path] =\ +def close_video_reader(video_reader : VideoReader) -> None: + video_reader.get('process').kill() + video_reader.get('process').wait() + frame_store.clear_frames(video_reader.get('id')) + + +def get_writer(video_path : str, temp_video_fps : Fps, temp_video_resolution : Resolution, output_video_resolution : Resolution, output_video_fps : Fps) -> VideoWriter: + if video_path not in VIDEO_POOL_SET.get('writer'): + VIDEO_POOL_SET['writer'][video_path] =\ { 'id': uuid.uuid4().hex, - 'process': ffmpeg.create_video_writer(target_path, temp_video_fps, temp_video_resolution, output_video_resolution, output_video_fps), - 'file_path': target_path, - 'metadata': video_metadata + 'file_path': video_path, + 'process': ffmpeg.create_video_writer(video_path, temp_video_fps, temp_video_resolution, output_video_resolution, output_video_fps), + 'metadata': + { + 'fps': output_video_fps, + 'resolution': output_video_resolution, + } } - return VIDEO_POOL_SET.get('writer').get(target_path) + return VIDEO_POOL_SET.get('writer').get(video_path) -#todo: needs review - [encoding] [critical: medium] blocking stdin write without backpressure or broken pipe handling -def write_video_writer_frame(video_writer : VideoWriter, vision_frame : VisionFrame) -> None: +def write_video_writer(video_writer : VideoWriter, vision_frame : VisionFrame) -> None: video_writer.get('process').stdin.write(vision_frame.tobytes()) -#todo: needs review - [encoding] [critical: medium] encoder failures only surface via returncode at close time def close_video_writer(video_writer : VideoWriter) -> bool: video_writer.get('process').stdin.close() video_writer.get('process').wait() + return video_writer.get('process').returncode == 0 -#todo: needs review - [lifecycle] [critical: high] kill over terminate, sigterm deadlocks while the pipe is full def clear_video_pool() -> None: for video_reader in VIDEO_POOL_SET.get('reader').values(): - video_reader.get('process').kill() - video_reader.get('process').wait() - frame_store.clear_frames(video_reader.get('id')) + close_video_reader(video_reader) for video_writer in VIDEO_POOL_SET.get('writer').values(): - video_writer.get('process').kill() - video_writer.get('process').wait() + close_video_writer(video_writer) VIDEO_POOL_SET['reader'].clear() VIDEO_POOL_SET['writer'].clear() diff --git a/facefusion/workflows/core.py b/facefusion/workflows/core.py index 1afec3c5..cba1d56f 100644 --- a/facefusion/workflows/core.py +++ b/facefusion/workflows/core.py @@ -5,7 +5,7 @@ import numpy from tqdm import tqdm import facefusion.workflows.image_to_video as image_to_video -from facefusion import ffprobe, logger, process_manager, state_manager, translator, video_manager +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.filesystem import filter_audio_paths @@ -138,8 +138,7 @@ def process_stream_frames() -> ErrorCode: frame_range = range(trim_frame_start, trim_frame_end) if frame_range: - video_metadata = ffprobe.extract_static_video_metadata(state_manager.get_item('target_path')) - video_writer = video_manager.get_writer(state_manager.get_item('target_path'), video_metadata, temp_video_fps, temp_video_resolution, output_video_resolution, state_manager.get_item('output_video_fps')) + video_writer = video_manager.get_writer(state_manager.get_item('target_path'), temp_video_fps, temp_video_resolution, output_video_resolution, state_manager.get_item('output_video_fps')) frame_look_ahead = image_to_video.calculate_frame_look_ahead(temp_video_resolution) 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: diff --git a/facefusion/workflows/image_to_video.py b/facefusion/workflows/image_to_video.py index 13978a4c..827ee097 100644 --- a/facefusion/workflows/image_to_video.py +++ b/facefusion/workflows/image_to_video.py @@ -186,7 +186,7 @@ def write_stream_frame(video_writer : VideoWriter, futures : List[Future[Tuple[i if not future.cancelled(): _, temp_vision_frame = future.result() - video_manager.write_video_writer_frame(video_writer, temp_vision_frame) + video_manager.write_video_writer(video_writer, temp_vision_frame) progress.update() diff --git a/tests/test_ffmpeg_builder.py b/tests/test_ffmpeg_builder.py index c86b7d02..1d9ee6b8 100644 --- a/tests/test_ffmpeg_builder.py +++ b/tests/test_ffmpeg_builder.py @@ -1,7 +1,7 @@ from shutil import which from facefusion import ffmpeg_builder -from facefusion.ffmpeg_builder import chain, concat, convert_color_space, keep_video_alpha, restrict_color_transfer, run, select_frame_range, set_audio_quality, set_audio_sample_size, set_faststart, set_filter_thread_count, set_global_thread_count, set_input_seek, set_output_format, set_stream_mode, set_video_encoder, set_video_fps, set_video_quality, set_video_tag +from facefusion.ffmpeg_builder import chain, concat, convert_color_space, keep_video_alpha, restrict_color_transfer, run, seek_to, select_frame_range, set_audio_quality, set_audio_sample_size, set_faststart, set_output_format, set_stream_mode, set_thread_count, set_video_encoder, set_video_fps, set_video_quality, set_video_tag def test_run() -> None: @@ -41,9 +41,9 @@ def test_set_stream_mode() -> None: assert set_stream_mode('v4l2') == [ '-f', 'v4l2' ] -def test_set_input_seek() -> None: - assert set_input_seek(0.0) == [ '-ss', '0.0' ] - assert set_input_seek(1.5) == [ '-ss', '1.5' ] +def test_seek_to() -> None: + assert seek_to(0.0) == [ '-ss', '0.0' ] + assert seek_to(1.5) == [ '-ss', '1.5' ] def test_set_output_format() -> None: @@ -92,14 +92,9 @@ def test_set_audio_quality() -> None: assert set_audio_quality('flac', 100) == [] -def test_set_global_thread_count() -> None: - assert set_global_thread_count(8) == [ '-threads', '8' ] - assert set_global_thread_count(16) == [ '-threads', '16' ] - - -def test_set_filter_thread_count() -> None: - assert set_filter_thread_count(8) == [ '-filter_threads', '8' ] - assert set_filter_thread_count(16) == [ '-filter_threads', '16' ] +def test_set_thread_count() -> None: + assert set_thread_count(8) == [ '-threads', '8' ] + assert set_thread_count(16) == [ '-threads', '16' ] def test_set_faststart() -> None: diff --git a/tests/test_video_manager.py b/tests/test_video_manager.py index 992c48f4..a75be714 100644 --- a/tests/test_video_manager.py +++ b/tests/test_video_manager.py @@ -9,7 +9,7 @@ from facefusion.download import conditional_download from facefusion.ffprobe import extract_video_metadata from facefusion.frame_store import get_frame_store from facefusion.temp_helper import create_temp_directory, get_temp_file_path -from facefusion.video_manager import clear_video_pool, close_video_writer, conditional_set_video_reader_position, get_reader, get_writer, read_video_reader_frame, read_video_reader_window, refresh_video_reader, write_video_writer_frame +from facefusion.video_manager import clear_video_pool, close_video_writer, conditional_set_video_reader_position, get_reader, get_writer, read_video_reader_frame, read_video_reader_window, refresh_video_reader, write_video_writer from .helper import get_test_example_file, get_test_examples_directory @@ -134,24 +134,23 @@ def test_read_video_reader_window() -> None: #todo: run mutation testing, strip down to the minimum, test with real data def test_get_writer() -> None: target_path = get_test_example_file('target-240p-25fps.mp4') - video_metadata = extract_video_metadata(target_path) create_temp_directory(target_path) - video_writer = get_writer(target_path, video_metadata, 25.0, (426, 226), (426, 226), 25.0) + video_writer = get_writer(target_path, 25.0, (426, 226), (426, 226), 25.0) - assert get_writer(target_path, video_metadata, 25.0, (426, 226), (426, 226), 25.0) is video_writer + assert get_writer(target_path, 25.0, (426, 226), (426, 226), 25.0) is video_writer #todo: needs review - [testing] question if the assertions are good #todo: run mutation testing, strip down to the minimum, test with real data -def test_write_video_writer_frame() -> None: +def test_write_video_writer() -> None: target_path = get_test_example_file('target-240p-25fps.mp4') create_temp_directory(target_path) video_reader = get_reader(target_path) - video_writer = get_writer(target_path, video_reader.get('metadata'), 25.0, (426, 226), (426, 226), 25.0) + video_writer = get_writer(target_path, 25.0, (426, 226), (426, 226), 25.0) for frame_number in range(25): vision_frame = read_video_reader_frame(video_reader) - write_video_writer_frame(video_writer, vision_frame) + write_video_writer(video_writer, vision_frame) assert close_video_writer(video_writer) is True @@ -170,9 +169,9 @@ def test_close_video_writer() -> None: target_path = get_test_example_file('target-240p-30fps.mp4') create_temp_directory(target_path) video_reader = get_reader(target_path) - video_writer = get_writer(target_path, video_reader.get('metadata'), 30.0, (426, 226), (426, 226), 30.0) + video_writer = get_writer(target_path, 30.0, (426, 226), (426, 226), 30.0) vision_frame = read_video_reader_frame(video_reader) - write_video_writer_frame(video_writer, vision_frame) + write_video_writer(video_writer, vision_frame) assert close_video_writer(video_writer) is True @@ -183,13 +182,15 @@ def test_clear_video_pool() -> None: target_path = get_test_example_file('target-240p-25fps.mp4') create_temp_directory(target_path) video_reader = get_reader(target_path) - video_writer = get_writer(target_path, video_reader.get('metadata'), 25.0, (426, 226), (426, 226), 25.0) + video_writer = get_writer(target_path, 25.0, (426, 226), (426, 226), 25.0) + vision_frame = read_video_reader_frame(video_reader) + write_video_writer(video_writer, vision_frame) clear_video_pool() if is_windows(): assert video_reader.get('process').returncode == 1 - assert video_writer.get('process').returncode == 1 if is_linux() or is_macos(): assert video_reader.get('process').returncode == -9 - assert video_writer.get('process').returncode == -9 + + assert video_writer.get('process').returncode == 0