diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1fad1e40..6ac6f77c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,6 +36,7 @@ jobs: - run: python install.py --onnxruntime default --skip-conda - run: pip install pytest - run: pip install pytest-mock + - run: pip install pytest-timeout - run: pip install httpx - run: pip install python-multipart - run: pytest diff --git a/facefusion.py b/facefusion.py index 223d8534..cbbe69bb 100755 --- a/facefusion.py +++ b/facefusion.py @@ -4,8 +4,9 @@ import os os.environ['OMP_NUM_THREADS'] = '1' -from facefusion import conda, core +from facefusion import core, environment if __name__ == '__main__': - conda.setup() + environment.setup_conda() + environment.setup_platform() core.cli() diff --git a/facefusion/apis/stream_helper.py b/facefusion/apis/stream_helper.py index b8f719f8..7057ee94 100644 --- a/facefusion/apis/stream_helper.py +++ b/facefusion/apis/stream_helper.py @@ -64,7 +64,7 @@ def create_vpx_encoder(width : int, height : int, bitrate : int) -> Optional[cty struct.pack_into('I', config_buffer, 128, 50) context_buffer = ctypes.create_string_buffer(512) - if vpx_library.vpx_codec_enc_init_ver(context_buffer, ctypes.byref(vp8_iface), config_buffer, 0, 37) == 0: + if vpx_library.vpx_codec_enc_init_ver(context_buffer, ctypes.byref(vp8_iface), config_buffer, 0, 39) == 0: vpx_library.vpx_codec_control_(context_buffer, 13, ctypes.c_int(16)) vpx_library.vpx_codec_control_(context_buffer, 12, ctypes.c_int(3)) vpx_library.vpx_codec_control_(context_buffer, 27, ctypes.c_int(10)) @@ -115,7 +115,6 @@ def create_opus_encoder(sample_rate : int, channels : int) -> Optional[ctypes.c_ encoder = opus_library.opus_encoder_create(sample_rate, channels, 2049, ctypes.byref(error)) if error.value == 0: - opus_library.opus_encoder_ctl(encoder, 4002, 64000) return encoder return None @@ -190,7 +189,7 @@ def encode_audio_chunk(opus_encoder : ctypes.c_void_p, session_id : SessionId, p while len(pcm_buffer) >= frame_samples: chunk = pcm_buffer[:frame_samples] pcm_buffer = pcm_buffer[frame_samples:] - pcm_pointer = ctypes.cast(chunk.ctypes.data, ctypes.c_void_p) + pcm_pointer = chunk.ctypes.data_as(ctypes.POINTER(ctypes.c_float)) audio_buffer = encode_opus(opus_encoder, pcm_pointer, 960) if audio_buffer: @@ -230,17 +229,18 @@ async def handle_video_stream(websocket : WebSocket) -> None: access_token = extract_access_token(websocket.scope) session_id = session_manager.find_session_id(access_token) session_context.set_session_id(session_id) - source_paths = state_manager.get_item('source_paths') await websocket.accept(subprotocol = subprotocol) - if session_id and source_paths: + if session_id: stream_frames = receive_stream_frames(websocket) - first_frame_type, first_frame_buffer = await anext(stream_frames, (0, b'')) first_vision_frame = None - if first_frame_type == 1: - first_vision_frame = cv2.imdecode(numpy.frombuffer(first_frame_buffer, numpy.uint8), cv2.IMREAD_COLOR) + # TODO: audio frames may arrive before video due to ScriptProcessor firing faster than canvas toBlob + async for first_frame_type, first_frame_buffer in stream_frames: + if first_frame_type == 1: + first_vision_frame = cv2.imdecode(numpy.frombuffer(first_frame_buffer, numpy.uint8), cv2.IMREAD_COLOR) + break if numpy.any(first_vision_frame): resolution : Resolution = (first_vision_frame.shape[1], first_vision_frame.shape[0]) diff --git a/facefusion/core.py b/facefusion/core.py index 4a261c91..a71c29a5 100755 --- a/facefusion/core.py +++ b/facefusion/core.py @@ -16,6 +16,7 @@ from facefusion.filesystem import get_file_extension, has_audio, has_image, has_ from facefusion.filesystem import get_file_name, resolve_file_paths, resolve_file_pattern from facefusion.jobs import job_helper, job_manager, job_runner from facefusion.jobs.job_list import compose_job_list +from facefusion.libraries import datachannel as datachannel_module, opus as opus_module, vpx as vpx_module from facefusion.processors.core import get_processors_modules from facefusion.program import create_program from facefusion.program_helper import validate_args @@ -104,13 +105,16 @@ def pre_check() -> bool: def common_pre_check() -> bool: common_modules =\ [ + datachannel_module, content_analyser, face_classifier, face_detector, face_landmarker, face_masker, face_recognizer, - voice_extractor + opus_module, + voice_extractor, + vpx_module ] content_analyser_content = inspect.getsource(content_analyser).encode() diff --git a/facefusion/conda.py b/facefusion/environment.py similarity index 61% rename from facefusion/conda.py rename to facefusion/environment.py index ab8bd586..e5d88ac8 100644 --- a/facefusion/conda.py +++ b/facefusion/environment.py @@ -2,10 +2,10 @@ import os import sys from typing import List -from facefusion.common_helper import is_linux, is_windows +from facefusion.common_helper import is_linux, is_macos, is_windows -def setup() -> None: +def setup_conda() -> None: conda_prefix = os.getenv('CONDA_PREFIX') conda_ready = os.getenv('CONDA_READY') @@ -39,3 +39,24 @@ def setup() -> None: library_paths.append(os.getenv('PATH')) os.environ['PATH'] = os.pathsep.join(library_paths) os.environ['CONDA_READY'] = '1' + + +def setup_platform() -> None: + homebrew_path = os.environ.get('HOMEBREW_PREFIX') + system_ready = os.getenv('SYSTEM_READY') + + if homebrew_path and not system_ready: + if is_macos(): + library_paths =\ + [ + os.path.join(homebrew_path, 'lib'), + os.path.join(homebrew_path, 'opt', 'openssl@3', 'lib') + ] + library_paths = list(filter(os.path.isdir, library_paths)) + + if library_paths: + if os.getenv('DYLD_LIBRARY_PATH'): + library_paths.append(os.getenv('DYLD_LIBRARY_PATH')) + os.environ['DYLD_LIBRARY_PATH'] = os.pathsep.join(library_paths) + os.environ['SYSTEM_READY'] = '1' + os.execv(sys.executable, [ sys.executable ] + sys.argv) diff --git a/facefusion/libraries/amd_smi.py b/facefusion/libraries/amd_smi.py index f78c8708..4875d5d4 100644 --- a/facefusion/libraries/amd_smi.py +++ b/facefusion/libraries/amd_smi.py @@ -1,22 +1,15 @@ import ctypes +import ctypes.util from functools import lru_cache from typing import List, Optional -from facefusion.common_helper import is_linux - - -def resolve_library_file() -> Optional[str]: - if is_linux(): - return 'libamd_smi.so' - return None - @lru_cache def create_static_library() -> Optional[ctypes.CDLL]: - library_file = resolve_library_file() + library_path = ctypes.util.find_library('amd_smi') - if library_file: - library = ctypes.CDLL(library_file) + if library_path: + library = ctypes.CDLL(library_path) if library: return init_ctypes(library) diff --git a/facefusion/libraries/datachannel.py b/facefusion/libraries/datachannel.py index be580833..85313cce 100644 --- a/facefusion/libraries/datachannel.py +++ b/facefusion/libraries/datachannel.py @@ -56,7 +56,10 @@ def create_static_library() -> Optional[ctypes.CDLL]: library_path = create_static_library_set().get('sources').get('datachannel').get('path') if library_path: - library = ctypes.CDLL(library_path) + if is_windows(): + library = ctypes.CDLL(library_path, winmode = 0) + else: + library = ctypes.CDLL(library_path) if library: return init_ctypes(library) diff --git a/facefusion/libraries/nvidia_ml.py b/facefusion/libraries/nvidia_ml.py index 32544cc2..8f98a2bc 100644 --- a/facefusion/libraries/nvidia_ml.py +++ b/facefusion/libraries/nvidia_ml.py @@ -1,24 +1,15 @@ import ctypes +import ctypes.util from functools import lru_cache from typing import List, Optional -from facefusion.common_helper import is_linux, is_windows - - -def resolve_library_file() -> Optional[str]: - if is_linux(): - return 'libnvidia-ml.so.1' - if is_windows(): - return 'nvml.dll' - return None - @lru_cache def create_static_library() -> Optional[ctypes.CDLL]: - library_file = resolve_library_file() + library_path = ctypes.util.find_library('nvidia-ml') or ctypes.util.find_library('nvml') - if library_file: - library = ctypes.CDLL(library_file) + if library_path: + library = ctypes.CDLL(library_path) if library: return init_ctypes(library) diff --git a/facefusion/libraries/opus.py b/facefusion/libraries/opus.py index 1adb6abb..6b38d187 100644 --- a/facefusion/libraries/opus.py +++ b/facefusion/libraries/opus.py @@ -1,26 +1,65 @@ import ctypes +import os from functools import lru_cache -from typing import Optional +from typing import Dict, Optional, Tuple from facefusion.common_helper import is_linux, is_macos, is_windows +from facefusion.download import conditional_download_hashes, conditional_download_sources, resolve_download_url_by_provider +from facefusion.filesystem import resolve_relative_path +from facefusion.types import DownloadSet -def resolve_library_file() -> Optional[str]: +def resolve_library_paths() -> Optional[Tuple[str, str]]: if is_linux(): - return 'libopus.so.0' + return 'linux/libopus.hash', 'linux/libopus.so' if is_macos(): - return 'libopus.dylib' + return 'macos/libopus.hash', 'macos/libopus.dylib' if is_windows(): - return 'opus.dll' + return 'windows/opus.hash', 'windows/opus.dll' return None @lru_cache -def create_static_library() -> Optional[ctypes.CDLL]: - library_file = resolve_library_file() +def create_static_library_set() -> Dict[str, DownloadSet]: + library_hash_path, library_source_path = resolve_library_paths() - if library_file: - library = ctypes.CDLL(library_file) + return\ + { + 'hashes': + { + 'opus': + { + 'url': resolve_download_url_by_provider('huggingface', 'libraries-4.0.0', library_hash_path), + 'path': resolve_relative_path('../.libraries/' + os.path.basename(library_hash_path)) + } + }, + 'sources': + { + 'opus': + { + 'url': resolve_download_url_by_provider('huggingface', 'libraries-4.0.0', library_source_path), + 'path': resolve_relative_path('../.libraries/' + os.path.basename(library_source_path)) + } + } + } + + +def pre_check() -> bool: + library_hash_set = create_static_library_set().get('hashes') + library_source_set = create_static_library_set().get('sources') + + return conditional_download_hashes(library_hash_set) and conditional_download_sources(library_source_set) + + +@lru_cache +def create_static_library() -> Optional[ctypes.CDLL]: + library_path = create_static_library_set().get('sources').get('opus').get('path') + + if library_path: + if is_windows(): + library = ctypes.CDLL(library_path, winmode = 0) + else: + library = ctypes.CDLL(library_path) if library: return init_ctypes(library) @@ -32,13 +71,10 @@ def init_ctypes(library : ctypes.CDLL) -> ctypes.CDLL: library.opus_encoder_create.argtypes = [ ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.POINTER(ctypes.c_int) ] library.opus_encoder_create.restype = ctypes.c_void_p - library.opus_encode_float.argtypes = [ ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int, ctypes.c_char_p, ctypes.c_int ] + library.opus_encode_float.argtypes = [ ctypes.c_void_p, ctypes.POINTER(ctypes.c_float), ctypes.c_int, ctypes.c_char_p, ctypes.c_int ] library.opus_encode_float.restype = ctypes.c_int library.opus_encoder_destroy.argtypes = [ ctypes.c_void_p ] library.opus_encoder_destroy.restype = None - library.opus_encoder_ctl.argtypes = [ ctypes.c_void_p, ctypes.c_int, ctypes.c_int ] - library.opus_encoder_ctl.restype = ctypes.c_int - return library diff --git a/facefusion/libraries/rocm_core.py b/facefusion/libraries/rocm_core.py index a6459b5c..e2eef8a7 100644 --- a/facefusion/libraries/rocm_core.py +++ b/facefusion/libraries/rocm_core.py @@ -1,22 +1,15 @@ import ctypes +import ctypes.util from functools import lru_cache from typing import Optional -from facefusion.common_helper import is_linux - - -def resolve_library_file() -> Optional[str]: - if is_linux(): - return 'librocm-core.so' - return None - @lru_cache def create_static_library() -> Optional[ctypes.CDLL]: - library_file = resolve_library_file() + library_path = ctypes.util.find_library('rocm-core') - if library_file: - library = ctypes.CDLL(library_file) + if library_path: + library = ctypes.CDLL(library_path) if library: return init_ctypes(library) diff --git a/facefusion/libraries/vpx.py b/facefusion/libraries/vpx.py index 8a62cf4e..cb59c6b6 100644 --- a/facefusion/libraries/vpx.py +++ b/facefusion/libraries/vpx.py @@ -1,26 +1,65 @@ import ctypes +import os from functools import lru_cache -from typing import Optional +from typing import Dict, Optional, Tuple from facefusion.common_helper import is_linux, is_macos, is_windows +from facefusion.download import conditional_download_hashes, conditional_download_sources, resolve_download_url_by_provider +from facefusion.filesystem import resolve_relative_path +from facefusion.types import DownloadSet -def resolve_library_file() -> Optional[str]: +def resolve_library_paths() -> Optional[Tuple[str, str]]: if is_linux(): - return 'libvpx.so' + return 'linux/libvpx.hash', 'linux/libvpx.so' if is_macos(): - return 'libvpx.dylib' + return 'macos/libvpx.hash', 'macos/libvpx.dylib' if is_windows(): - return 'vpx.dll' + return 'windows/vpx.hash', 'windows/vpx.dll' return None @lru_cache -def create_static_library() -> Optional[ctypes.CDLL]: - library_file = resolve_library_file() +def create_static_library_set() -> Dict[str, DownloadSet]: + library_hash_path, library_source_path = resolve_library_paths() - if library_file: - library = ctypes.CDLL(library_file) + return\ + { + 'hashes': + { + 'vpx': + { + 'url': resolve_download_url_by_provider('huggingface', 'libraries-4.0.0', library_hash_path), + 'path': resolve_relative_path('../.libraries/' + os.path.basename(library_hash_path)) + } + }, + 'sources': + { + 'vpx': + { + 'url': resolve_download_url_by_provider('huggingface', 'libraries-4.0.0', library_source_path), + 'path': resolve_relative_path('../.libraries/' + os.path.basename(library_source_path)) + } + } + } + + +def pre_check() -> bool: + library_hash_set = create_static_library_set().get('hashes') + library_source_set = create_static_library_set().get('sources') + + return conditional_download_hashes(library_hash_set) and conditional_download_sources(library_source_set) + + +@lru_cache +def create_static_library() -> Optional[ctypes.CDLL]: + library_path = create_static_library_set().get('sources').get('vpx').get('path') + + if library_path: + if is_windows(): + library = ctypes.CDLL(library_path, winmode = 0) + else: + library = ctypes.CDLL(library_path) if library: return init_ctypes(library) diff --git a/tests/test_api_assets.py b/tests/test_api_assets.py index 8abfe7d0..f01241a9 100644 --- a/tests/test_api_assets.py +++ b/tests/test_api_assets.py @@ -20,6 +20,7 @@ def before_all() -> None: 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/source.mp3', 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/target-240p.mp4' ]) + subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', get_test_example_file('target-240p.jpg') ]) diff --git a/tests/test_api_state.py b/tests/test_api_state.py index 1d3ce0ca..b1912353 100644 --- a/tests/test_api_state.py +++ b/tests/test_api_state.py @@ -49,6 +49,7 @@ def before_all() -> None: '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' ]) + subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', get_test_example_file('target-240p.jpg') ]) diff --git a/tests/test_api_stream.py b/tests/test_api_stream.py index 49efad3d..4db57fb2 100644 --- a/tests/test_api_stream.py +++ b/tests/test_api_stream.py @@ -12,7 +12,6 @@ from facefusion.apis import asset_store from facefusion.apis.core import create_api from facefusion.core import common_pre_check, processors_pre_check from facefusion.download import conditional_download -from facefusion.libraries import datachannel as datachannel_module from .assert_helper import get_test_example_file, get_test_examples_directory from .stream_helper import create_sdp_offer, open_websocket_stream @@ -39,7 +38,6 @@ def before_all() -> None: common_pre_check() processors_pre_check() - datachannel_module.pre_check() conditional_download(get_test_examples_directory(), [ diff --git a/tests/test_audio.py b/tests/test_audio.py index df134b8a..26a9529d 100644 --- a/tests/test_audio.py +++ b/tests/test_audio.py @@ -14,6 +14,7 @@ def before_all() -> None: [ 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/source.mp3' ]) + subprocess.run([ 'ffmpeg', '-i', get_test_example_file('source.mp3'), get_test_example_file('source.wav') ]) diff --git a/tests/test_cli_age_modifier.py b/tests/test_cli_age_modifier.py index 37cd27c8..9ebfc004 100644 --- a/tests/test_cli_age_modifier.py +++ b/tests/test_cli_age_modifier.py @@ -14,6 +14,7 @@ def before_all() -> None: [ 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/target-240p.mp4' ]) + subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', get_test_example_file('target-240p.jpg') ]) diff --git a/tests/test_cli_background_remover.py b/tests/test_cli_background_remover.py index a54a1375..54dfc0be 100644 --- a/tests/test_cli_background_remover.py +++ b/tests/test_cli_background_remover.py @@ -15,6 +15,7 @@ def before_all() -> None: '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' ]) + subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', get_test_example_file('target-240p.jpg') ]) diff --git a/tests/test_cli_batch_runner.py b/tests/test_cli_batch_runner.py index 96469662..11749a7c 100644 --- a/tests/test_cli_batch_runner.py +++ b/tests/test_cli_batch_runner.py @@ -14,6 +14,7 @@ def before_all() -> None: [ 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/target-240p.mp4' ]) + subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', get_test_example_file('target-240p-batch-1.jpg') ]) subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '2', get_test_example_file('target-240p-batch-2.jpg') ]) diff --git a/tests/test_cli_expression_restorer.py b/tests/test_cli_expression_restorer.py index 65c54012..d3bc325a 100644 --- a/tests/test_cli_expression_restorer.py +++ b/tests/test_cli_expression_restorer.py @@ -14,6 +14,7 @@ def before_all() -> None: [ 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/target-240p.mp4' ]) + subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', get_test_example_file('target-240p.jpg') ]) diff --git a/tests/test_cli_face_debugger.py b/tests/test_cli_face_debugger.py index a02c62af..4d855bdb 100644 --- a/tests/test_cli_face_debugger.py +++ b/tests/test_cli_face_debugger.py @@ -15,6 +15,7 @@ def before_all() -> None: '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' ]) + subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', get_test_example_file('target-240p.jpg') ]) diff --git a/tests/test_cli_face_editor.py b/tests/test_cli_face_editor.py index bac693a3..558dee8b 100644 --- a/tests/test_cli_face_editor.py +++ b/tests/test_cli_face_editor.py @@ -15,6 +15,7 @@ def before_all() -> None: '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' ]) + subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', get_test_example_file('target-240p.jpg') ]) diff --git a/tests/test_cli_face_enhancer.py b/tests/test_cli_face_enhancer.py index f2d94901..274cc5cb 100644 --- a/tests/test_cli_face_enhancer.py +++ b/tests/test_cli_face_enhancer.py @@ -15,6 +15,7 @@ def before_all() -> None: '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' ]) + subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', get_test_example_file('target-240p.jpg') ]) diff --git a/tests/test_cli_face_swapper.py b/tests/test_cli_face_swapper.py index eb441122..7f1400ee 100644 --- a/tests/test_cli_face_swapper.py +++ b/tests/test_cli_face_swapper.py @@ -15,6 +15,7 @@ def before_all() -> None: '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' ]) + subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', get_test_example_file('target-240p.jpg') ]) diff --git a/tests/test_cli_frame_colorizer.py b/tests/test_cli_frame_colorizer.py index 33e09475..866aa403 100644 --- a/tests/test_cli_frame_colorizer.py +++ b/tests/test_cli_frame_colorizer.py @@ -15,6 +15,7 @@ def before_all() -> None: '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' ]) + subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', '-vf', 'hue=s=0', get_test_example_file('target-240p-0sat.jpg') ]) subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vf', 'hue=s=0', get_test_example_file('target-240p-0sat.mp4') ]) diff --git a/tests/test_cli_frame_enhancer.py b/tests/test_cli_frame_enhancer.py index 0f9182aa..ac3777e8 100644 --- a/tests/test_cli_frame_enhancer.py +++ b/tests/test_cli_frame_enhancer.py @@ -15,6 +15,7 @@ def before_all() -> None: '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' ]) + subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', get_test_example_file('target-240p.jpg') ]) diff --git a/tests/test_cli_job_manager.py b/tests/test_cli_job_manager.py index 78b4a70c..78ff1227 100644 --- a/tests/test_cli_job_manager.py +++ b/tests/test_cli_job_manager.py @@ -15,6 +15,7 @@ def before_all() -> None: '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' ]) + subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', get_test_example_file('target-240p.jpg') ]) diff --git a/tests/test_cli_job_runner.py b/tests/test_cli_job_runner.py index 02376c1a..f0f1d77f 100644 --- a/tests/test_cli_job_runner.py +++ b/tests/test_cli_job_runner.py @@ -15,6 +15,7 @@ def before_all() -> None: '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' ]) + subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', get_test_example_file('target-240p.jpg') ]) diff --git a/tests/test_cli_lip_syncer.py b/tests/test_cli_lip_syncer.py index 8bf3318d..40564c71 100644 --- a/tests/test_cli_lip_syncer.py +++ b/tests/test_cli_lip_syncer.py @@ -16,6 +16,7 @@ def before_all() -> None: 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/source.mp3', 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/target-240p.mp4' ]) + subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', get_test_example_file('target-240p.jpg') ]) diff --git a/tests/test_cli_output_scale.py b/tests/test_cli_output_scale.py index 5dc99f7d..731921cb 100644 --- a/tests/test_cli_output_scale.py +++ b/tests/test_cli_output_scale.py @@ -17,6 +17,7 @@ def before_all() -> None: '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' ]) + subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', get_test_example_file('target-240p.jpg') ]) diff --git a/tests/test_face_analyser.py b/tests/test_face_analyser.py index e1333c64..f0f4a7b8 100644 --- a/tests/test_face_analyser.py +++ b/tests/test_face_analyser.py @@ -12,13 +12,6 @@ from .assert_helper import get_test_example_file, get_test_examples_directory @pytest.fixture(scope = 'module', autouse = True) def before_all() -> None: - conditional_download(get_test_examples_directory(), - [ - 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/source.jpg' - ]) - subprocess.run([ 'ffmpeg', '-i', get_test_example_file('source.jpg'), '-vf', 'crop=iw*0.8:ih*0.8', get_test_example_file('source-80crop.jpg') ]) - subprocess.run([ 'ffmpeg', '-i', get_test_example_file('source.jpg'), '-vf', 'crop=iw*0.7:ih*0.7', get_test_example_file('source-70crop.jpg') ]) - subprocess.run([ 'ffmpeg', '-i', get_test_example_file('source.jpg'), '-vf', 'crop=iw*0.6:ih*0.6', get_test_example_file('source-60crop.jpg') ]) state_manager.init_item('execution_device_ids', [ 0 ]) state_manager.init_item('execution_providers', [ 'cpu' ]) state_manager.init_item('download_providers', [ 'github' ]) @@ -27,10 +20,20 @@ def before_all() -> None: state_manager.init_item('face_detector_score', 0.5) state_manager.init_item('face_landmarker_model', 'many') state_manager.init_item('face_landmarker_score', 0.5) + face_classifier.pre_check() face_landmarker.pre_check() face_recognizer.pre_check() + conditional_download(get_test_examples_directory(), + [ + 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/source.jpg' + ]) + + subprocess.run([ 'ffmpeg', '-i', get_test_example_file('source.jpg'), '-vf', 'crop=iw*0.8:ih*0.8', get_test_example_file('source-80crop.jpg') ]) + subprocess.run([ 'ffmpeg', '-i', get_test_example_file('source.jpg'), '-vf', 'crop=iw*0.7:ih*0.7', get_test_example_file('source-70crop.jpg') ]) + subprocess.run([ 'ffmpeg', '-i', get_test_example_file('source.jpg'), '-vf', 'crop=iw*0.6:ih*0.6', get_test_example_file('source-60crop.jpg') ]) + @pytest.fixture(autouse = True) def before_each() -> None: diff --git a/tests/test_ffmpeg.py b/tests/test_ffmpeg.py index 8a44cfb5..aed468a5 100644 --- a/tests/test_ffmpeg.py +++ b/tests/test_ffmpeg.py @@ -18,12 +18,22 @@ from .assert_helper import get_test_example_file, get_test_examples_directory, g @pytest.fixture(scope = 'module', autouse = True) def before_all() -> None: process_manager.start() + state_manager.init_item('temp_path', tempfile.gettempdir()) + state_manager.init_item('temp_frame_format', 'png') + state_manager.init_item('output_audio_encoder', 'aac') + state_manager.init_item('output_audio_quality', 100) + state_manager.init_item('output_audio_volume', 100) + state_manager.init_item('output_video_encoder', 'libx264') + state_manager.init_item('output_video_quality', 100) + state_manager.init_item('output_video_preset', 'ultrafast') + 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/source.mp3', 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/target-240p.mp4' ]) + subprocess.run([ 'ffmpeg', '-i', get_test_example_file('source.mp3'), get_test_example_file('source.wav') ]) subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vf', 'fps=25', get_test_example_file('target-240p-25fps.mp4') ]) subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vf', 'fps=30', get_test_example_file('target-240p-30fps.mp4') ]) @@ -34,14 +44,6 @@ def before_all() -> None: subprocess.run([ 'ffmpeg', '-i', get_test_example_file('source.mp3'), '-i', get_test_example_file('target-240p.mp4'), '-ar', '48000', get_test_example_file('target-240p-48khz.mp4') ]) subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-c:v', 'libx265', '-an', '-movflags', '+faststart', get_test_example_file('target-240p-h265.mp4') ]) - state_manager.init_item('temp_path', tempfile.gettempdir()) - state_manager.init_item('temp_frame_format', 'png') - state_manager.init_item('output_audio_encoder', 'aac') - state_manager.init_item('output_audio_quality', 100) - state_manager.init_item('output_audio_volume', 100) - state_manager.init_item('output_video_encoder', 'libx264') - state_manager.init_item('output_video_quality', 100) - state_manager.init_item('output_video_preset', 'ultrafast') @pytest.fixture(scope = 'function', autouse = True) diff --git a/tests/test_ffprobe.py b/tests/test_ffprobe.py index 7ab83bc7..5e672ed3 100644 --- a/tests/test_ffprobe.py +++ b/tests/test_ffprobe.py @@ -11,11 +11,13 @@ from .assert_helper import get_test_example_file, get_test_examples_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.mp3', 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/target-240p.mp4' ]) + subprocess.run([ 'ffmpeg', '-i', get_test_example_file('source.mp3'), '-t', '1.9', '-ar', '48000', '-ac', '2', get_test_example_file('source-48000khz-2ch.wav') ]) subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-t', '1', get_test_example_file('target-240p-1s.mov') ]) diff --git a/tests/test_inference_manager.py b/tests/test_inference_manager.py index 07550337..1dfbaa4c 100644 --- a/tests/test_inference_manager.py +++ b/tests/test_inference_manager.py @@ -12,6 +12,7 @@ def before_all() -> None: state_manager.init_item('execution_device_ids', [ 0 ]) state_manager.init_item('execution_providers', [ 'cpu' ]) state_manager.init_item('download_providers', [ 'github' ]) + content_analyser.pre_check() diff --git a/tests/test_job_runner.py b/tests/test_job_runner.py index e7c8dc6a..eef2c64d 100644 --- a/tests/test_job_runner.py +++ b/tests/test_job_runner.py @@ -18,6 +18,7 @@ def before_all() -> None: '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' ]) + subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', get_test_example_file('target-240p.jpg') ]) diff --git a/tests/test_library_datachannel.py b/tests/test_library_datachannel.py new file mode 100644 index 00000000..c379c596 --- /dev/null +++ b/tests/test_library_datachannel.py @@ -0,0 +1,19 @@ +import ctypes + +import pytest + +from facefusion import environment, state_manager +from facefusion.libraries import datachannel as datachannel_module + + +@pytest.fixture(scope = 'module', autouse = True) +def before_all() -> None: + state_manager.init_item('download_providers', [ 'github', 'huggingface' ]) + + environment.setup_platform() + + datachannel_module.pre_check() + + +def test_create_static_library() -> None: + assert isinstance(datachannel_module.create_static_library(), ctypes.CDLL) diff --git a/tests/test_library_opus.py b/tests/test_library_opus.py new file mode 100644 index 00000000..5cca63a6 --- /dev/null +++ b/tests/test_library_opus.py @@ -0,0 +1,23 @@ +import ctypes + +import pytest + +from facefusion import state_manager +from facefusion.libraries import opus as opus_module + + +@pytest.fixture(scope = 'module', autouse = True) +def before_all() -> None: + state_manager.init_item('download_providers', [ 'github', 'huggingface' ]) + + opus_module.pre_check() + + +def test_create_static_library() -> None: + assert isinstance(opus_module.create_static_library(), ctypes.CDLL) + + +def test_create_opus_encoder() -> None: + opus_library = opus_module.create_static_library() + + assert isinstance(opus_library, ctypes.CDLL) diff --git a/tests/test_library_vpx.py b/tests/test_library_vpx.py new file mode 100644 index 00000000..af49b61e --- /dev/null +++ b/tests/test_library_vpx.py @@ -0,0 +1,23 @@ +import ctypes + +import pytest + +from facefusion import state_manager +from facefusion.libraries import vpx as vpx_module + + +@pytest.fixture(scope = 'module', autouse = True) +def before_all() -> None: + state_manager.init_item('download_providers', [ 'github', 'huggingface' ]) + + vpx_module.pre_check() + + +def test_create_static_library() -> None: + assert isinstance(vpx_module.create_static_library(), ctypes.CDLL) + + +def test_create_vpx_encoder() -> None: + vpx_library = vpx_module.create_static_library() + + assert isinstance(vpx_library, ctypes.CDLL) diff --git a/tests/test_rtc.py b/tests/test_rtc.py index d20ee1c4..bbc1513b 100644 --- a/tests/test_rtc.py +++ b/tests/test_rtc.py @@ -2,14 +2,18 @@ from typing import List import pytest -from facefusion import rtc -from facefusion.libraries import datachannel as datachannel_module +from facefusion import rtc, state_manager +from facefusion.libraries import datachannel as datachannel_module, opus as opus_module, vpx as vpx_module from facefusion.types import RtcPeer -@pytest.fixture(scope = 'module') +@pytest.fixture(scope = 'module', autouse = True) def before_all() -> None: + state_manager.init_item('download_providers', [ 'github', 'huggingface' ]) + datachannel_module.pre_check() + opus_module.pre_check() + vpx_module.pre_check() # TODO: add test_parse_sdp_payload_types @@ -18,8 +22,6 @@ def test_build_media_description() -> None: assert rtc.build_media_description('video', 96, 'VP8/90000', 'recvonly', 0) == b'm=video 9 UDP/TLS/RTP/SAVPF 96\r\na=rtpmap:96 VP8/90000\r\na=rtcp-fb:96 nack\r\na=rtcp-fb:96 nack pli\r\na=recvonly\r\na=mid:0\r\na=rtcp-mux\r\n' -# TODO: enable again -@pytest.mark.skip def test_create_peer_connection() -> None: peer_connection = rtc.create_peer_connection() datachannel_library = datachannel_module.create_static_library() @@ -28,8 +30,6 @@ def test_create_peer_connection() -> None: assert datachannel_library.rtcDeletePeerConnection(peer_connection) == 0 -# TODO: enable again -@pytest.mark.skip def test_add_audio_track() -> None: peer_connection = rtc.create_peer_connection() @@ -38,8 +38,6 @@ def test_add_audio_track() -> None: datachannel_module.create_static_library().rtcDeletePeerConnection(peer_connection) -# TODO: enable again -@pytest.mark.skip def test_add_video_track() -> None: peer_connection = rtc.create_peer_connection() @@ -48,8 +46,6 @@ def test_add_video_track() -> None: datachannel_module.create_static_library().rtcDeletePeerConnection(peer_connection) -# TODO: enable again -@pytest.mark.skip def test_negotiate_sdp() -> None: datachannel_library = datachannel_module.create_static_library() @@ -73,8 +69,6 @@ def test_negotiate_sdp() -> None: assert datachannel_library.rtcDeletePeerConnection(receiver_connection) == 0 -# TODO: enable again -@pytest.mark.skip def test_delete_peers() -> None: datachannel_library = datachannel_module.create_static_library() peer_connection = rtc.create_peer_connection() diff --git a/tests/test_rtc_store.py b/tests/test_rtc_store.py index 1f8c789c..de7ae6b8 100644 --- a/tests/test_rtc_store.py +++ b/tests/test_rtc_store.py @@ -1,11 +1,16 @@ import pytest -from facefusion.libraries import datachannel as datachannel_module +from facefusion import state_manager +from facefusion.libraries import datachannel as datachannel_module, opus as opus_module, vpx as vpx_module -@pytest.fixture(scope = 'module') +@pytest.fixture(scope = 'module', autouse = True) def before_all() -> None: + state_manager.init_item('download_providers', [ 'github', 'huggingface' ]) + datachannel_module.pre_check() + opus_module.pre_check() + vpx_module.pre_check() # TODO: test create_rtc_stream, get_rtc_stream, destroy_rtc_stream lifecycle diff --git a/tests/test_temp_helper.py b/tests/test_temp_helper.py index 7ac3739f..7be93708 100644 --- a/tests/test_temp_helper.py +++ b/tests/test_temp_helper.py @@ -11,12 +11,13 @@ from .assert_helper import get_test_example_file, get_test_examples_directory @pytest.fixture(scope = 'module', autouse = True) def before_all() -> None: + state_manager.init_item('temp_path', tempfile.gettempdir()) + state_manager.init_item('temp_frame_format', 'png') + conditional_download(get_test_examples_directory(), [ 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/target-240p.mp4' ]) - state_manager.init_item('temp_path', tempfile.gettempdir()) - state_manager.init_item('temp_frame_format', 'png') def test_get_temp_file_path() -> None: diff --git a/tests/test_vision.py b/tests/test_vision.py index 30d72f04..c85d4a04 100644 --- a/tests/test_vision.py +++ b/tests/test_vision.py @@ -15,6 +15,7 @@ def before_all() -> None: 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/target-240p.mp4', 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/target-1080p.mp4' ]) + subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', get_test_example_file('target-240p.jpg') ]) subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', get_test_example_file('目标-240p.webp') ]) subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-1080p.mp4'), '-vframes', '1', get_test_example_file('target-1080p.jpg') ])