From 20b392f760c0fc2b8d980168bcaeac53d0ef6d77 Mon Sep 17 00:00:00 2001 From: Henry Ruhs Date: Mon, 11 May 2026 12:08:05 +0200 Subject: [PATCH] ship libssl and libcrypto in linux (#1095) --- facefusion/libraries/datachannel.py | 124 ++++++++++++++++++++-------- facefusion/libraries/opus.py | 92 ++++++++++++++------- facefusion/libraries/vpx.py | 90 +++++++++++++------- facefusion/types.py | 3 + tests/test_api_stream.py | 3 + 5 files changed, 218 insertions(+), 94 deletions(-) diff --git a/facefusion/libraries/datachannel.py b/facefusion/libraries/datachannel.py index 85313cce..21f394ad 100644 --- a/facefusion/libraries/datachannel.py +++ b/facefusion/libraries/datachannel.py @@ -1,47 +1,97 @@ import ctypes -import os from functools import lru_cache -from typing import Dict, Optional, Tuple +from typing import Optional 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_paths() -> Optional[Tuple[str, str]]: - if is_linux(): - return 'linux/libdatachannel.hash', 'linux/libdatachannel.so' - if is_macos(): - return 'macos/libdatachannel.hash', 'macos/libdatachannel.dylib' - if is_windows(): - return 'windows/datachannel.hash', 'windows/datachannel.dll' - return None +from facefusion.types import LibrarySet @lru_cache -def create_static_library_set() -> Dict[str, DownloadSet]: - library_hash_path, library_source_path = resolve_library_paths() - - return\ - { - 'hashes': +def create_static_library_set() -> Optional[LibrarySet]: + if is_linux(): + return\ { - 'datachannel': + 'hashes': { - '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': - { - 'datachannel': + 'datachannel': + { + 'url': resolve_download_url_by_provider('huggingface', 'libraries-4.0.0-a', 'linux/libdatachannel.hash'), + 'path': resolve_relative_path('../.libraries/libdatachannel.hash') + }, + 'crypto': + { + 'url': resolve_download_url_by_provider('huggingface', 'libraries-4.0.0-a', 'linux/libcrypto.hash'), + 'path': resolve_relative_path('../.libraries/libcrypto.hash') + }, + 'ssl': + { + 'url': resolve_download_url_by_provider('huggingface', 'libraries-4.0.0-a', 'linux/libssl.hash'), + 'path': resolve_relative_path('../.libraries/libssl.hash') + } + }, + 'sources': { - '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)) + 'datachannel': + { + 'url': resolve_download_url_by_provider('huggingface', 'libraries-4.0.0-a', 'linux/libdatachannel.so'), + 'path': resolve_relative_path('../.libraries/libdatachannel.so') + }, + 'crypto': + { + 'url': resolve_download_url_by_provider('huggingface', 'libraries-4.0.0-a', 'linux/libcrypto.so'), + 'path': resolve_relative_path('../.libraries/libcrypto.so') + }, + 'ssl': + { + 'url': resolve_download_url_by_provider('huggingface', 'libraries-4.0.0-a', 'linux/libssl.so'), + 'path': resolve_relative_path('../.libraries/libssl.so') + } } } - } + if is_macos(): + return\ + { + 'hashes': + { + 'datachannel': + { + 'url': resolve_download_url_by_provider('huggingface', 'libraries-4.0.0', 'macos/libdatachannel.hash'), + 'path': resolve_relative_path('../.libraries/libdatachannel.hash') + } + }, + 'sources': + { + 'datachannel': + { + 'url': resolve_download_url_by_provider('huggingface', 'libraries-4.0.0', 'macos/libdatachannel.dylib'), + 'path': resolve_relative_path('../.libraries/libdatachannel.dylib') + } + } + } + if is_windows(): + return\ + { + 'hashes': + { + 'datachannel': + { + 'url': resolve_download_url_by_provider('huggingface', 'libraries-4.0.0', 'macos/datachannel.hash'), + 'path': resolve_relative_path('../.libraries/datachannel.hash') + } + }, + 'sources': + { + 'datachannel': + { + 'url': resolve_download_url_by_provider('huggingface', 'libraries-4.0.0', 'macos/datachannel.dll'), + 'path': resolve_relative_path('../.libraries/datachannel.dll') + } + } + } + + return None def pre_check() -> bool: @@ -53,13 +103,19 @@ def pre_check() -> bool: @lru_cache def create_static_library() -> Optional[ctypes.CDLL]: - library_path = create_static_library_set().get('sources').get('datachannel').get('path') + datachannel_source_path = create_static_library_set().get('sources').get('datachannel').get('path') + crypto_source_path = create_static_library_set().get('sources').get('crypto').get('path') + ssl_source_path = create_static_library_set().get('sources').get('ssl').get('path') + + if datachannel_source_path: + if crypto_source_path and ssl_source_path: + ctypes.CDLL(crypto_source_path) + ctypes.CDLL(ssl_source_path) - if library_path: if is_windows(): - library = ctypes.CDLL(library_path, winmode = 0) + library = ctypes.CDLL(datachannel_source_path, winmode = 0) else: - library = ctypes.CDLL(library_path) + library = ctypes.CDLL(datachannel_source_path) if library: return init_ctypes(library) diff --git a/facefusion/libraries/opus.py b/facefusion/libraries/opus.py index 6b38d187..7e67450d 100644 --- a/facefusion/libraries/opus.py +++ b/facefusion/libraries/opus.py @@ -1,47 +1,79 @@ import ctypes -import os from functools import lru_cache -from typing import Dict, Optional, Tuple +from typing import Optional 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_paths() -> Optional[Tuple[str, str]]: - if is_linux(): - return 'linux/libopus.hash', 'linux/libopus.so' - if is_macos(): - return 'macos/libopus.hash', 'macos/libopus.dylib' - if is_windows(): - return 'windows/opus.hash', 'windows/opus.dll' - return None +from facefusion.types import LibrarySet @lru_cache -def create_static_library_set() -> Dict[str, DownloadSet]: - library_hash_path, library_source_path = resolve_library_paths() - - return\ - { - 'hashes': +def create_static_library_set() -> Optional[LibrarySet]: + if is_linux(): + return\ { - 'opus': + 'hashes': { - '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': + 'opus': + { + 'url': resolve_download_url_by_provider('huggingface', 'libraries-4.0.0', 'linux/libopus.hash'), + 'path': resolve_relative_path('../.libraries/libopus.hash') + } + }, + 'sources': { - '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)) + 'opus': + { + 'url': resolve_download_url_by_provider('huggingface', 'libraries-4.0.0', 'linux/libopus.so'), + 'path': resolve_relative_path('../.libraries/libopus.so') + } } } - } + + if is_macos(): + return\ + { + 'hashes': + { + 'opus': + { + 'url': resolve_download_url_by_provider('huggingface', 'libraries-4.0.0', 'macos/libopus.hash'), + 'path': resolve_relative_path('../.libraries/libopus.hash') + } + }, + 'sources': + { + 'opus': + { + 'url': resolve_download_url_by_provider('huggingface', 'libraries-4.0.0', 'macos/libopus.dylib'), + 'path': resolve_relative_path('../.libraries/libopus.dylib') + } + } + } + + if is_windows(): + return\ + { + 'hashes': + { + 'opus': + { + 'url': resolve_download_url_by_provider('huggingface', 'libraries-4.0.0', 'windows/opus.hash'), + 'path': resolve_relative_path('../.libraries/opus.hash') + } + }, + 'sources': + { + 'opus': + { + 'url': resolve_download_url_by_provider('huggingface', 'libraries-4.0.0', 'windows/opus.dll'), + 'path': resolve_relative_path('../.libraries/opus.dll') + } + } + } + + return None def pre_check() -> bool: diff --git a/facefusion/libraries/vpx.py b/facefusion/libraries/vpx.py index cb59c6b6..b73deaed 100644 --- a/facefusion/libraries/vpx.py +++ b/facefusion/libraries/vpx.py @@ -1,47 +1,77 @@ import ctypes -import os from functools import lru_cache -from typing import Dict, Optional, Tuple +from typing import Optional 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_paths() -> Optional[Tuple[str, str]]: - if is_linux(): - return 'linux/libvpx.hash', 'linux/libvpx.so' - if is_macos(): - return 'macos/libvpx.hash', 'macos/libvpx.dylib' - if is_windows(): - return 'windows/vpx.hash', 'windows/vpx.dll' - return None +from facefusion.types import LibrarySet @lru_cache -def create_static_library_set() -> Dict[str, DownloadSet]: - library_hash_path, library_source_path = resolve_library_paths() - - return\ - { - 'hashes': +def create_static_library_set() -> Optional[LibrarySet]: + if is_linux(): + return\ { - 'vpx': + 'hashes': { - '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': + 'vpx': + { + 'url': resolve_download_url_by_provider('huggingface', 'libraries-4.0.0', 'linux/libvpx.hash'), + 'path': resolve_relative_path('../.libraries/libvpx.hash') + } + }, + 'sources': { - '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)) + 'vpx': + { + 'url': resolve_download_url_by_provider('huggingface', 'libraries-4.0.0', 'linux/libvpx.so'), + 'path': resolve_relative_path('../.libraries/libvpx.so') + } } } - } + if is_macos(): + return\ + { + 'hashes': + { + 'vpx': + { + 'url': resolve_download_url_by_provider('huggingface', 'libraries-4.0.0', 'macos/libvpx.hash'), + 'path': resolve_relative_path('../.libraries/libvpx.hash') + } + }, + 'sources': + { + 'vpx': + { + 'url': resolve_download_url_by_provider('huggingface', 'libraries-4.0.0', 'macos/libvpx.dylib'), + 'path': resolve_relative_path('../.libraries/libvpx.dylib') + } + } + } + if is_windows(): + return\ + { + 'hashes': + { + 'vpx': + { + 'url': resolve_download_url_by_provider('huggingface', 'libraries-4.0.0', 'windows/vpx.hash'), + 'path': resolve_relative_path('../.libraries/vpx.hash') + } + }, + 'sources': + { + 'vpx': + { + 'url': resolve_download_url_by_provider('huggingface', 'libraries-4.0.0', 'windows/vpx.dll'), + 'path': resolve_relative_path('../.libraries/vpx.dll') + } + } + } + + return None def pre_check() -> bool: diff --git a/facefusion/types.py b/facefusion/types.py index a701ff6e..58394eec 100755 --- a/facefusion/types.py +++ b/facefusion/types.py @@ -282,6 +282,9 @@ ModelOptions : TypeAlias = Dict[str, Any] ModelSet : TypeAlias = Dict[str, ModelOptions] ModelInitializer : TypeAlias = NDArray[Any] +LibraryOptions : TypeAlias = Dict[str, Any] +LibrarySet : TypeAlias = Dict[str, LibraryOptions] + ExecutionProvider = Literal['cuda', 'tensorrt', 'rocm', 'migraphx', 'coreml', 'openvino', 'qnn', 'directml', 'cpu'] ExecutionProviderValue = Literal['CPUExecutionProvider', 'CoreMLExecutionProvider', 'CUDAExecutionProvider', 'DmlExecutionProvider', 'OpenVINOExecutionProvider', 'MIGraphXExecutionProvider', 'QNNExecutionProvider', 'ROCMExecutionProvider', 'TensorrtExecutionProvider'] ExecutionProviderSet : TypeAlias = Dict[ExecutionProvider, ExecutionProviderValue] diff --git a/tests/test_api_stream.py b/tests/test_api_stream.py index 1e0ee946..a8496c8d 100644 --- a/tests/test_api_stream.py +++ b/tests/test_api_stream.py @@ -97,6 +97,8 @@ def test_stream_image(test_client : TestClient) -> None: output_bytes = websocket.receive_bytes() output_vision_frame = cv2.imdecode(numpy.frombuffer(output_bytes, numpy.uint8), cv2.IMREAD_COLOR) + # TODO: can we test if bytes have been passed? what does this actual test than just the handshake? + # TODO: compare to the video test - no status code check? assert output_vision_frame.shape == (1024, 1024, 3) @@ -144,6 +146,7 @@ def test_stream_video(test_client : TestClient) -> None: 'Content-Type': 'application/sdp' }) + # TODO: can we test if bytes have been passed? what does this actual test than just the handshake? assert stream_response.status_code == 201 assert stream_response.text