Spaces:
Configuration error
Configuration error
salominavina
commited on
Commit
•
90ba202
1
Parent(s):
efdd9ee
Upload 23 files
Browse files- .install/LICENSE.md +3 -0
- .install/facefusion.ico +0 -0
- .install/facefusion.nsi +183 -0
- tests/__init__.py +0 -0
- tests/test_audio.py +26 -0
- tests/test_cli_face_debugger.py +31 -0
- tests/test_cli_face_enhancer.py +32 -0
- tests/test_cli_face_swapper.py +31 -0
- tests/test_cli_frame_colorizer.py +32 -0
- tests/test_cli_frame_enhancer.py +31 -0
- tests/test_cli_lip_syncer.py +32 -0
- tests/test_common_helper.py +15 -0
- tests/test_config.py +96 -0
- tests/test_download.py +23 -0
- tests/test_execution.py +27 -0
- tests/test_face_analyser.py +103 -0
- tests/test_ffmpeg.py +113 -0
- tests/test_filesystem.py +91 -0
- tests/test_memory.py +8 -0
- tests/test_normalizer.py +30 -0
- tests/test_process_manager.py +22 -0
- tests/test_vision.py +109 -0
- tests/test_wording.py +7 -0
.install/LICENSE.md
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
CC BY-NC license
|
2 |
+
|
3 |
+
Copyright (c) 2024 Henry Ruhs
|
.install/facefusion.ico
ADDED
.install/facefusion.nsi
ADDED
@@ -0,0 +1,183 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
!include MUI2.nsh
|
2 |
+
!include nsDialogs.nsh
|
3 |
+
!include LogicLib.nsh
|
4 |
+
|
5 |
+
RequestExecutionLevel admin
|
6 |
+
ManifestDPIAware true
|
7 |
+
|
8 |
+
Name 'FaceFusion 2.6.1'
|
9 |
+
OutFile 'FaceFusion_2.6.1.exe'
|
10 |
+
|
11 |
+
!define MUI_ICON 'facefusion.ico'
|
12 |
+
|
13 |
+
!insertmacro MUI_PAGE_DIRECTORY
|
14 |
+
Page custom InstallPage PostInstallPage
|
15 |
+
!insertmacro MUI_PAGE_INSTFILES
|
16 |
+
!insertmacro MUI_LANGUAGE English
|
17 |
+
|
18 |
+
Var UseDefault
|
19 |
+
Var UseCuda
|
20 |
+
Var UseDirectMl
|
21 |
+
Var UseOpenVino
|
22 |
+
|
23 |
+
Function .onInit
|
24 |
+
StrCpy $INSTDIR 'C:\FaceFusion'
|
25 |
+
FunctionEnd
|
26 |
+
|
27 |
+
Function InstallPage
|
28 |
+
nsDialogs::Create 1018
|
29 |
+
!insertmacro MUI_HEADER_TEXT 'Choose Your Accelerator' 'Choose your accelerator based on the graphics card.'
|
30 |
+
|
31 |
+
${NSD_CreateRadioButton} 0 40u 100% 10u 'Default'
|
32 |
+
Pop $UseDefault
|
33 |
+
|
34 |
+
${NSD_CreateRadioButton} 0 55u 100% 10u 'CUDA (NVIDIA)'
|
35 |
+
Pop $UseCuda
|
36 |
+
|
37 |
+
${NSD_CreateRadioButton} 0 70u 100% 10u 'DirectML (AMD, Intel, NVIDIA)'
|
38 |
+
Pop $UseDirectMl
|
39 |
+
|
40 |
+
${NSD_CreateRadioButton} 0 85u 100% 10u 'OpenVINO (Intel)'
|
41 |
+
Pop $UseOpenVino
|
42 |
+
|
43 |
+
${NSD_Check} $UseDefault
|
44 |
+
|
45 |
+
nsDialogs::Show
|
46 |
+
FunctionEnd
|
47 |
+
|
48 |
+
Function PostInstallPage
|
49 |
+
${NSD_GetState} $UseDefault $UseDefault
|
50 |
+
${NSD_GetState} $UseCuda $UseCuda
|
51 |
+
${NSD_GetState} $UseDirectMl $UseDirectMl
|
52 |
+
${NSD_GetState} $UseOpenVino $UseOpenVino
|
53 |
+
FunctionEnd
|
54 |
+
|
55 |
+
Function Destroy
|
56 |
+
${If} ${Silent}
|
57 |
+
Quit
|
58 |
+
${Else}
|
59 |
+
Abort
|
60 |
+
${EndIf}
|
61 |
+
FunctionEnd
|
62 |
+
|
63 |
+
Section 'Prepare Your Platform'
|
64 |
+
DetailPrint 'Install GIT'
|
65 |
+
inetc::get 'https://github.com/git-for-windows/git/releases/download/v2.45.2.windows.1/Git-2.45.2-64-bit.exe' '$TEMP\Git.exe'
|
66 |
+
ExecWait '$TEMP\Git.exe /CURRENTUSER /VERYSILENT /DIR=$LOCALAPPDATA\Programs\Git' $0
|
67 |
+
Delete '$TEMP\Git.exe'
|
68 |
+
|
69 |
+
${If} $0 > 0
|
70 |
+
DetailPrint 'Git installation aborted with error code $0'
|
71 |
+
Call Destroy
|
72 |
+
${EndIf}
|
73 |
+
|
74 |
+
DetailPrint 'Uninstall Conda'
|
75 |
+
ExecWait '$LOCALAPPDATA\Programs\Miniconda3\Uninstall-Miniconda3.exe /S _?=$LOCALAPPDATA\Programs\Miniconda3'
|
76 |
+
RMDir /r '$LOCALAPPDATA\Programs\Miniconda3'
|
77 |
+
|
78 |
+
DetailPrint 'Install Conda'
|
79 |
+
inetc::get 'https://repo.anaconda.com/miniconda/Miniconda3-py310_24.3.0-0-Windows-x86_64.exe' '$TEMP\Miniconda3.exe'
|
80 |
+
ExecWait '$TEMP\Miniconda3.exe /InstallationType=JustMe /AddToPath=1 /S /D=$LOCALAPPDATA\Programs\Miniconda3' $1
|
81 |
+
Delete '$TEMP\Miniconda3.exe'
|
82 |
+
|
83 |
+
${If} $1 > 0
|
84 |
+
DetailPrint 'Conda installation aborted with error code $1'
|
85 |
+
Call Destroy
|
86 |
+
${EndIf}
|
87 |
+
SectionEnd
|
88 |
+
|
89 |
+
Section 'Download Your Copy'
|
90 |
+
SetOutPath $INSTDIR
|
91 |
+
|
92 |
+
DetailPrint 'Download Your Copy'
|
93 |
+
RMDir /r $INSTDIR
|
94 |
+
nsExec::Exec '$LOCALAPPDATA\Programs\Git\cmd\git.exe clone https://github.com/facefusion/facefusion --branch 2.6.1 .'
|
95 |
+
SectionEnd
|
96 |
+
|
97 |
+
Section 'Setup Your Environment'
|
98 |
+
DetailPrint 'Setup Your Environment'
|
99 |
+
nsExec::Exec '$LOCALAPPDATA\Programs\Miniconda3\Scripts\conda.exe init --all'
|
100 |
+
nsExec::Exec '$LOCALAPPDATA\Programs\Miniconda3\Scripts\conda.exe create --name facefusion python=3.10 --yes'
|
101 |
+
SectionEnd
|
102 |
+
|
103 |
+
Section 'Create Install Batch'
|
104 |
+
SetOutPath $INSTDIR
|
105 |
+
|
106 |
+
FileOpen $0 install-ffmpeg.bat w
|
107 |
+
FileOpen $1 install-accelerator.bat w
|
108 |
+
FileOpen $2 install-application.bat w
|
109 |
+
|
110 |
+
FileWrite $0 '@echo off && conda activate facefusion && conda install conda-forge::ffmpeg=7.0.1 --yes'
|
111 |
+
${If} $UseCuda == 1
|
112 |
+
FileWrite $1 '@echo off && conda activate facefusion && conda install cudatoolkit=11.8 cudnn=8.9.2.26 conda-forge::gputil=1.4.0 conda-forge::zlib-wapi --yes'
|
113 |
+
FileWrite $2 '@echo off && conda activate facefusion && python install.py --onnxruntime cuda-11.8'
|
114 |
+
${ElseIf} $UseDirectMl == 1
|
115 |
+
FileWrite $2 '@echo off && conda activate facefusion && python install.py --onnxruntime directml'
|
116 |
+
${ElseIf} $UseOpenVino == 1
|
117 |
+
FileWrite $1 '@echo off && conda activate facefusion && conda install conda-forge::openvino=2023.1.0 --yes'
|
118 |
+
FileWrite $2 '@echo off && conda activate facefusion && python install.py --onnxruntime openvino'
|
119 |
+
${Else}
|
120 |
+
FileWrite $2 '@echo off && conda activate facefusion && python install.py --onnxruntime default'
|
121 |
+
${EndIf}
|
122 |
+
|
123 |
+
FileClose $0
|
124 |
+
FileClose $1
|
125 |
+
FileClose $2
|
126 |
+
SectionEnd
|
127 |
+
|
128 |
+
Section 'Install Your FFmpeg'
|
129 |
+
SetOutPath $INSTDIR
|
130 |
+
|
131 |
+
DetailPrint 'Install Your FFmpeg'
|
132 |
+
nsExec::ExecToLog 'install-ffmpeg.bat'
|
133 |
+
SectionEnd
|
134 |
+
|
135 |
+
Section 'Install Your Accelerator'
|
136 |
+
SetOutPath $INSTDIR
|
137 |
+
|
138 |
+
DetailPrint 'Install Your Accelerator'
|
139 |
+
nsExec::ExecToLog 'install-accelerator.bat'
|
140 |
+
SectionEnd
|
141 |
+
|
142 |
+
Section 'Install The Application'
|
143 |
+
SetOutPath $INSTDIR
|
144 |
+
|
145 |
+
DetailPrint 'Install The Application'
|
146 |
+
nsExec::ExecToLog 'install-application.bat'
|
147 |
+
SectionEnd
|
148 |
+
|
149 |
+
Section 'Create Run Batch'
|
150 |
+
SetOutPath $INSTDIR
|
151 |
+
FileOpen $0 run.bat w
|
152 |
+
FileWrite $0 '@echo off && conda activate facefusion && python run.py %*'
|
153 |
+
FileClose $0
|
154 |
+
SectionEnd
|
155 |
+
|
156 |
+
Section 'Register The Application'
|
157 |
+
DetailPrint 'Register The Application'
|
158 |
+
|
159 |
+
CreateDirectory $SMPROGRAMS\FaceFusion
|
160 |
+
CreateShortcut '$SMPROGRAMS\FaceFusion\FaceFusion.lnk' $INSTDIR\run.bat '--open-browser' $INSTDIR\.install\facefusion.ico
|
161 |
+
CreateShortcut '$SMPROGRAMS\FaceFusion\FaceFusion Benchmark.lnk' $INSTDIR\run.bat '--ui-layouts benchmark --open-browser' $INSTDIR\.install\facefusion.ico
|
162 |
+
CreateShortcut '$SMPROGRAMS\FaceFusion\FaceFusion Webcam.lnk' $INSTDIR\run.bat '--ui-layouts webcam --open-browser' $INSTDIR\.install\facefusion.ico
|
163 |
+
|
164 |
+
CreateShortcut $DESKTOP\FaceFusion.lnk $INSTDIR\run.bat '--open-browser' $INSTDIR\.install\facefusion.ico
|
165 |
+
|
166 |
+
WriteUninstaller $INSTDIR\Uninstall.exe
|
167 |
+
|
168 |
+
WriteRegStr HKLM SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\FaceFusion DisplayName 'FaceFusion'
|
169 |
+
WriteRegStr HKLM SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\FaceFusion DisplayVersion '2.6.0'
|
170 |
+
WriteRegStr HKLM SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\FaceFusion Publisher 'Henry Ruhs'
|
171 |
+
WriteRegStr HKLM SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\FaceFusion InstallLocation $INSTDIR
|
172 |
+
WriteRegStr HKLM SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\FaceFusion UninstallString $INSTDIR\uninstall.exe
|
173 |
+
SectionEnd
|
174 |
+
|
175 |
+
Section 'Uninstall'
|
176 |
+
nsExec::Exec '$LOCALAPPDATA\Programs\Miniconda3\Scripts\conda.exe env remove --name facefusion --yes'
|
177 |
+
|
178 |
+
Delete $DESKTOP\FaceFusion.lnk
|
179 |
+
RMDir /r $SMPROGRAMS\FaceFusion
|
180 |
+
RMDir /r $INSTDIR
|
181 |
+
|
182 |
+
DeleteRegKey HKLM SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\FaceFusion
|
183 |
+
SectionEnd
|
tests/__init__.py
ADDED
File without changes
|
tests/test_audio.py
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import subprocess
|
2 |
+
import pytest
|
3 |
+
|
4 |
+
from facefusion.audio import get_audio_frame, read_static_audio
|
5 |
+
from facefusion.download import conditional_download
|
6 |
+
|
7 |
+
|
8 |
+
@pytest.fixture(scope = 'module', autouse = True)
|
9 |
+
def before_all() -> None:
|
10 |
+
conditional_download('.assets/examples',
|
11 |
+
[
|
12 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples/source.mp3'
|
13 |
+
])
|
14 |
+
subprocess.run([ 'ffmpeg', '-i', '.assets/examples/source.mp3', '.assets/examples/source.wav' ])
|
15 |
+
|
16 |
+
|
17 |
+
def test_get_audio_frame() -> None:
|
18 |
+
assert get_audio_frame('.assets/examples/source.mp3', 25) is not None
|
19 |
+
assert get_audio_frame('.assets/examples/source.wav', 25) is not None
|
20 |
+
assert get_audio_frame('invalid', 25) is None
|
21 |
+
|
22 |
+
|
23 |
+
def test_read_static_audio() -> None:
|
24 |
+
assert len(read_static_audio('.assets/examples/source.mp3', 25)) == 280
|
25 |
+
assert len(read_static_audio('.assets/examples/source.wav', 25)) == 280
|
26 |
+
assert read_static_audio('invalid', 25) is None
|
tests/test_cli_face_debugger.py
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import subprocess
|
2 |
+
import sys
|
3 |
+
import pytest
|
4 |
+
|
5 |
+
from facefusion.download import conditional_download
|
6 |
+
|
7 |
+
|
8 |
+
@pytest.fixture(scope = 'module', autouse = True)
|
9 |
+
def before_all() -> None:
|
10 |
+
conditional_download('.assets/examples',
|
11 |
+
[
|
12 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples/source.jpg',
|
13 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples/target-240p.mp4'
|
14 |
+
])
|
15 |
+
subprocess.run([ 'ffmpeg', '-i', '.assets/examples/target-240p.mp4', '-vframes', '1', '.assets/examples/target-240p.jpg' ])
|
16 |
+
|
17 |
+
|
18 |
+
def test_debug_face_to_image() -> None:
|
19 |
+
commands = [ sys.executable, 'run.py', '--frame-processors', 'face_debugger', '-t', '.assets/examples/target-240p.jpg', '-o', '.assets/examples/test_debug_face_to_image.jpg', '--headless' ]
|
20 |
+
run = subprocess.run(commands, stdout = subprocess.PIPE, stderr = subprocess.STDOUT)
|
21 |
+
|
22 |
+
assert run.returncode == 0
|
23 |
+
assert 'image succeed' in run.stdout.decode()
|
24 |
+
|
25 |
+
|
26 |
+
def test_debug_face_to_video() -> None:
|
27 |
+
commands = [ sys.executable, 'run.py', '--frame-processors', 'face_debugger', '-t', '.assets/examples/target-240p.mp4', '-o', '.assets/examples/test_debug_face_to_video.mp4', '--trim-frame-end', '10', '--headless' ]
|
28 |
+
run = subprocess.run(commands, stdout = subprocess.PIPE, stderr = subprocess.STDOUT)
|
29 |
+
|
30 |
+
assert run.returncode == 0
|
31 |
+
assert 'video succeed' in run.stdout.decode()
|
tests/test_cli_face_enhancer.py
ADDED
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import subprocess
|
2 |
+
import sys
|
3 |
+
import pytest
|
4 |
+
|
5 |
+
from facefusion.download import conditional_download
|
6 |
+
|
7 |
+
|
8 |
+
@pytest.fixture(scope = 'module', autouse = True)
|
9 |
+
def before_all() -> None:
|
10 |
+
conditional_download('.assets/examples',
|
11 |
+
[
|
12 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples/source.jpg',
|
13 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples/target-240p.mp4'
|
14 |
+
])
|
15 |
+
subprocess.run([ 'ffmpeg', '-i', '.assets/examples/target-240p.mp4', '-vframes', '1', '.assets/examples/target-240p.jpg' ])
|
16 |
+
|
17 |
+
|
18 |
+
def test_enhance_face_to_image() -> None:
|
19 |
+
commands = [ sys.executable, 'run.py', '--frame-processors', 'face_enhancer', '-t', '.assets/examples/target-240p.jpg', '-o', '.assets/examples/test_enhance_face_to_image.jpg', '--headless' ]
|
20 |
+
run = subprocess.run(commands, stdout = subprocess.PIPE, stderr = subprocess.STDOUT)
|
21 |
+
|
22 |
+
assert run.returncode == 0
|
23 |
+
assert 'image succeed' in run.stdout.decode()
|
24 |
+
|
25 |
+
|
26 |
+
def test_enhance_face_to_video() -> None:
|
27 |
+
commands = [ sys.executable, 'run.py', '--frame-processors', 'face_enhancer', '-t', '.assets/examples/target-240p.mp4', '-o', '.assets/examples/test_enhance_face_to_video.mp4', '--trim-frame-end', '10', '--headless' ]
|
28 |
+
run = subprocess.run(commands, stdout = subprocess.PIPE, stderr = subprocess.STDOUT)
|
29 |
+
|
30 |
+
assert run.returncode == 0
|
31 |
+
assert 'video succeed' in run.stdout.decode()
|
32 |
+
|
tests/test_cli_face_swapper.py
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import subprocess
|
2 |
+
import sys
|
3 |
+
import pytest
|
4 |
+
|
5 |
+
from facefusion.download import conditional_download
|
6 |
+
|
7 |
+
|
8 |
+
@pytest.fixture(scope = 'module', autouse = True)
|
9 |
+
def before_all() -> None:
|
10 |
+
conditional_download('.assets/examples',
|
11 |
+
[
|
12 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples/source.jpg',
|
13 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples/target-240p.mp4'
|
14 |
+
])
|
15 |
+
subprocess.run([ 'ffmpeg', '-i', '.assets/examples/target-240p.mp4', '-vframes', '1', '.assets/examples/target-240p.jpg' ])
|
16 |
+
|
17 |
+
|
18 |
+
def test_swap_face_to_image() -> None:
|
19 |
+
commands = [ sys.executable, 'run.py', '--frame-processors', 'face_swapper', '-s', '.assets/examples/source.jpg', '-t', '.assets/examples/target-240p.jpg', '-o', '.assets/examples/test_swap_face_to_image.jpg', '--headless' ]
|
20 |
+
run = subprocess.run(commands, stdout = subprocess.PIPE, stderr = subprocess.STDOUT)
|
21 |
+
|
22 |
+
assert run.returncode == 0
|
23 |
+
assert 'image succeed' in run.stdout.decode()
|
24 |
+
|
25 |
+
|
26 |
+
def test_swap_face_to_video() -> None:
|
27 |
+
commands = [ sys.executable, 'run.py', '--frame-processors', 'face_swapper', '-s', '.assets/examples/source.jpg', '-t', '.assets/examples/target-240p.mp4', '-o', '.assets/examples/test_swap_face_to_video.mp4', '--trim-frame-end', '10', '--headless' ]
|
28 |
+
run = subprocess.run(commands, stdout = subprocess.PIPE, stderr = subprocess.STDOUT)
|
29 |
+
|
30 |
+
assert run.returncode == 0
|
31 |
+
assert 'video succeed' in run.stdout.decode()
|
tests/test_cli_frame_colorizer.py
ADDED
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import subprocess
|
2 |
+
import sys
|
3 |
+
import pytest
|
4 |
+
|
5 |
+
from facefusion.download import conditional_download
|
6 |
+
|
7 |
+
|
8 |
+
@pytest.fixture(scope = 'module', autouse = True)
|
9 |
+
def before_all() -> None:
|
10 |
+
conditional_download('.assets/examples',
|
11 |
+
[
|
12 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples/source.jpg',
|
13 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples/target-240p.mp4'
|
14 |
+
])
|
15 |
+
subprocess.run([ 'ffmpeg', '-i', '.assets/examples/target-240p.mp4', '-vframes', '1', '-vf', 'hue=s=0', '.assets/examples/target-240p-0sat.jpg' ])
|
16 |
+
subprocess.run([ 'ffmpeg', '-i', '.assets/examples/target-240p.mp4', '-vf', 'hue=s=0', '.assets/examples/target-240p-0sat.mp4' ])
|
17 |
+
|
18 |
+
|
19 |
+
def test_colorize_frame_to_image() -> None:
|
20 |
+
commands = [ sys.executable, 'run.py', '--frame-processors', 'frame_colorizer', '-t', '.assets/examples/target-240p-0sat.jpg', '-o', '.assets/examples/test_colorize_frame_to_image.jpg', '--headless' ]
|
21 |
+
run = subprocess.run(commands, stdout = subprocess.PIPE, stderr = subprocess.STDOUT)
|
22 |
+
|
23 |
+
assert run.returncode == 0
|
24 |
+
assert 'image succeed' in run.stdout.decode()
|
25 |
+
|
26 |
+
|
27 |
+
def test_colorize_frame_to_video() -> None:
|
28 |
+
commands = [ sys.executable, 'run.py', '--frame-processors', 'frame_colorizer', '-t', '.assets/examples/target-240p-0sat.mp4', '-o', '.assets/examples/test_colorize_frame_to_video.mp4', '--trim-frame-end', '10', '--headless' ]
|
29 |
+
run = subprocess.run(commands, stdout = subprocess.PIPE, stderr = subprocess.STDOUT)
|
30 |
+
|
31 |
+
assert run.returncode == 0
|
32 |
+
assert 'video succeed' in run.stdout.decode()
|
tests/test_cli_frame_enhancer.py
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import subprocess
|
2 |
+
import sys
|
3 |
+
import pytest
|
4 |
+
|
5 |
+
from facefusion.download import conditional_download
|
6 |
+
|
7 |
+
|
8 |
+
@pytest.fixture(scope = 'module', autouse = True)
|
9 |
+
def before_all() -> None:
|
10 |
+
conditional_download('.assets/examples',
|
11 |
+
[
|
12 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples/source.jpg',
|
13 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples/target-240p.mp4'
|
14 |
+
])
|
15 |
+
subprocess.run([ 'ffmpeg', '-i', '.assets/examples/target-240p.mp4', '-vframes', '1', '.assets/examples/target-240p.jpg' ])
|
16 |
+
|
17 |
+
|
18 |
+
def test_enhance_frame_to_image() -> None:
|
19 |
+
commands = [ sys.executable, 'run.py', '--frame-processors', 'frame_enhancer', '-t', '.assets/examples/target-240p.jpg', '-o', '.assets/examples/test_enhance_frame_to_image.jpg', '--headless' ]
|
20 |
+
run = subprocess.run(commands, stdout = subprocess.PIPE, stderr = subprocess.STDOUT)
|
21 |
+
|
22 |
+
assert run.returncode == 0
|
23 |
+
assert 'image succeed' in run.stdout.decode()
|
24 |
+
|
25 |
+
|
26 |
+
def test_enhance_frame_to_video() -> None:
|
27 |
+
commands = [ sys.executable, 'run.py', '--frame-processors', 'frame_enhancer', '-t', '.assets/examples/target-240p.mp4', '-o', '.assets/examples/test_enhance_frame_to_video.mp4', '--trim-frame-end', '10', '--headless' ]
|
28 |
+
run = subprocess.run(commands, stdout = subprocess.PIPE, stderr = subprocess.STDOUT)
|
29 |
+
|
30 |
+
assert run.returncode == 0
|
31 |
+
assert 'video succeed' in run.stdout.decode()
|
tests/test_cli_lip_syncer.py
ADDED
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import subprocess
|
2 |
+
import sys
|
3 |
+
import pytest
|
4 |
+
|
5 |
+
from facefusion.download import conditional_download
|
6 |
+
|
7 |
+
|
8 |
+
@pytest.fixture(scope = 'module', autouse = True)
|
9 |
+
def before_all() -> None:
|
10 |
+
conditional_download('.assets/examples',
|
11 |
+
[
|
12 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples/source.jpg',
|
13 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples/source.mp3',
|
14 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples/target-240p.mp4'
|
15 |
+
])
|
16 |
+
subprocess.run([ 'ffmpeg', '-i', '.assets/examples/target-240p.mp4', '-vframes', '1', '.assets/examples/target-240p.jpg' ])
|
17 |
+
|
18 |
+
|
19 |
+
def test_sync_lip_to_image() -> None:
|
20 |
+
commands = [ sys.executable, 'run.py', '--frame-processors', 'lip_syncer', '-s', '.assets/examples/source.mp3', '-t', '.assets/examples/target-240p.jpg', '-o', '.assets/examples/test_sync_lip_to_image.jpg', '--headless' ]
|
21 |
+
run = subprocess.run(commands, stdout = subprocess.PIPE, stderr = subprocess.STDOUT)
|
22 |
+
|
23 |
+
assert run.returncode == 0
|
24 |
+
assert 'image succeed' in run.stdout.decode()
|
25 |
+
|
26 |
+
|
27 |
+
def test_sync_lip_to_video() -> None:
|
28 |
+
commands = [ sys.executable, 'run.py', '--frame-processors', 'lip_syncer', '-s', '.assets/examples/source.mp3', '-t', '.assets/examples/target-240p.mp4', '-o', '.assets/examples/test_sync_lip_to_video.mp4', '--trim-frame-end', '10', '--headless' ]
|
29 |
+
run = subprocess.run(commands, stdout = subprocess.PIPE, stderr = subprocess.STDOUT)
|
30 |
+
|
31 |
+
assert run.returncode == 0
|
32 |
+
assert 'video succeed' in run.stdout.decode()
|
tests/test_common_helper.py
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from facefusion.common_helper import create_metavar, create_int_range, create_float_range
|
2 |
+
|
3 |
+
|
4 |
+
def test_create_metavar() -> None:
|
5 |
+
assert create_metavar([ 1, 2, 3, 4, 5 ]) == '[1-5]'
|
6 |
+
|
7 |
+
|
8 |
+
def test_create_int_range() -> None:
|
9 |
+
assert create_int_range(0, 2, 1) == [ 0, 1, 2 ]
|
10 |
+
assert create_float_range(0, 1, 1) == [ 0, 1 ]
|
11 |
+
|
12 |
+
|
13 |
+
def test_create_float_range() -> None:
|
14 |
+
assert create_float_range(0.0, 1.0, 0.5) == [ 0.0, 0.5, 1.0 ]
|
15 |
+
assert create_float_range(0.0, 1.0, 0.05) == [ 0.0, 0.05, 0.10, 0.15, 0.20, 0.25, 0.30, 0.35, 0.40, 0.45, 0.50, 0.55, 0.60, 0.65, 0.70, 0.75, 0.80, 0.85, 0.90, 0.95, 1.0 ]
|
tests/test_config.py
ADDED
@@ -0,0 +1,96 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from configparser import ConfigParser
|
2 |
+
import pytest
|
3 |
+
|
4 |
+
from facefusion import config
|
5 |
+
|
6 |
+
|
7 |
+
@pytest.fixture(scope = 'module', autouse = True)
|
8 |
+
def before_all() -> None:
|
9 |
+
config.CONFIG = ConfigParser()
|
10 |
+
config.CONFIG.read_dict(
|
11 |
+
{
|
12 |
+
'str':
|
13 |
+
{
|
14 |
+
'valid': 'a',
|
15 |
+
'unset': ''
|
16 |
+
},
|
17 |
+
'int':
|
18 |
+
{
|
19 |
+
'valid': '1',
|
20 |
+
'unset': ''
|
21 |
+
},
|
22 |
+
'float':
|
23 |
+
{
|
24 |
+
'valid': '1.0',
|
25 |
+
'unset': ''
|
26 |
+
},
|
27 |
+
'bool':
|
28 |
+
{
|
29 |
+
'valid': 'True',
|
30 |
+
'unset': ''
|
31 |
+
},
|
32 |
+
'str_list':
|
33 |
+
{
|
34 |
+
'valid': 'a b c',
|
35 |
+
'unset': ''
|
36 |
+
},
|
37 |
+
'int_list':
|
38 |
+
{
|
39 |
+
'valid': '1 2 3',
|
40 |
+
'unset': ''
|
41 |
+
},
|
42 |
+
'float_list':
|
43 |
+
{
|
44 |
+
'valid': '1.0 2.0 3.0',
|
45 |
+
'unset': ''
|
46 |
+
}
|
47 |
+
})
|
48 |
+
|
49 |
+
|
50 |
+
def test_get_str_value() -> None:
|
51 |
+
assert config.get_str_value('str.valid') == 'a'
|
52 |
+
assert config.get_str_value('str.unset', 'b') == 'b'
|
53 |
+
assert config.get_str_value('str.unset') is None
|
54 |
+
assert config.get_str_value('str.invalid') is None
|
55 |
+
|
56 |
+
|
57 |
+
def test_get_int_value() -> None:
|
58 |
+
assert config.get_int_value('int.valid') == 1
|
59 |
+
assert config.get_int_value('int.unset', '1') == 1
|
60 |
+
assert config.get_int_value('int.unset') is None
|
61 |
+
assert config.get_int_value('int.invalid') is None
|
62 |
+
|
63 |
+
|
64 |
+
def test_get_float_value() -> None:
|
65 |
+
assert config.get_float_value('float.valid') == 1.0
|
66 |
+
assert config.get_float_value('float.unset', '1.0') == 1.0
|
67 |
+
assert config.get_float_value('float.unset') is None
|
68 |
+
assert config.get_float_value('float.invalid') is None
|
69 |
+
|
70 |
+
|
71 |
+
def test_get_bool_value() -> None:
|
72 |
+
assert config.get_bool_value('bool.valid') is True
|
73 |
+
assert config.get_bool_value('bool.unset', 'False') is False
|
74 |
+
assert config.get_bool_value('bool.unset') is None
|
75 |
+
assert config.get_bool_value('bool.invalid') is None
|
76 |
+
|
77 |
+
|
78 |
+
def test_get_str_list() -> None:
|
79 |
+
assert config.get_str_list('str_list.valid') == [ 'a', 'b', 'c' ]
|
80 |
+
assert config.get_str_list('str_list.unset', 'c b a') == [ 'c', 'b', 'a' ]
|
81 |
+
assert config.get_str_list('str_list.unset') is None
|
82 |
+
assert config.get_str_list('str_list.invalid') is None
|
83 |
+
|
84 |
+
|
85 |
+
def test_get_int_list() -> None:
|
86 |
+
assert config.get_int_list('int_list.valid') == [ 1, 2, 3 ]
|
87 |
+
assert config.get_int_list('int_list.unset', '3 2 1') == [ 3, 2, 1 ]
|
88 |
+
assert config.get_int_list('int_list.unset') is None
|
89 |
+
assert config.get_int_list('int_list.invalid') is None
|
90 |
+
|
91 |
+
|
92 |
+
def test_get_float_list() -> None:
|
93 |
+
assert config.get_float_list('float_list.valid') == [ 1.0, 2.0, 3.0 ]
|
94 |
+
assert config.get_float_list('float_list.unset', '3.0 2.0 1.0') == [ 3.0, 2.0, 1.0 ]
|
95 |
+
assert config.get_float_list('float_list.unset') is None
|
96 |
+
assert config.get_float_list('float_list.invalid') is None
|
tests/test_download.py
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import pytest
|
2 |
+
|
3 |
+
from facefusion.download import conditional_download, get_download_size, is_download_done
|
4 |
+
|
5 |
+
|
6 |
+
@pytest.fixture(scope = 'module', autouse = True)
|
7 |
+
def before_all() -> None:
|
8 |
+
conditional_download('.assets/examples',
|
9 |
+
[
|
10 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples/target-240p.mp4'
|
11 |
+
])
|
12 |
+
|
13 |
+
|
14 |
+
def test_get_download_size() -> None:
|
15 |
+
assert get_download_size('https://github.com/facefusion/facefusion-assets/releases/download/examples/target-240p.mp4') == 191675
|
16 |
+
assert get_download_size('https://github.com/facefusion/facefusion-assets/releases/download/examples/target-360p.mp4') == 370732
|
17 |
+
assert get_download_size('invalid') == 0
|
18 |
+
|
19 |
+
|
20 |
+
def test_is_download_done() -> None:
|
21 |
+
assert is_download_done('https://github.com/facefusion/facefusion-assets/releases/download/examples/target-240p.mp4', '.assets/examples/target-240p.mp4') is True
|
22 |
+
assert is_download_done('https://github.com/facefusion/facefusion-assets/releases/download/examples/target-240p.mp4', 'invalid') is False
|
23 |
+
assert is_download_done('invalid', 'invalid') is False
|
tests/test_execution.py
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from facefusion.execution import encode_execution_providers, decode_execution_providers, has_execution_provider, apply_execution_provider_options
|
2 |
+
|
3 |
+
|
4 |
+
def test_encode_execution_providers() -> None:
|
5 |
+
assert encode_execution_providers([ 'CPUExecutionProvider' ]) == [ 'cpu' ]
|
6 |
+
|
7 |
+
|
8 |
+
def test_decode_execution_providers() -> None:
|
9 |
+
assert decode_execution_providers([ 'cpu' ]) == [ 'CPUExecutionProvider' ]
|
10 |
+
|
11 |
+
|
12 |
+
def test_has_execution_provider() -> None:
|
13 |
+
assert has_execution_provider('CPUExecutionProvider') is True
|
14 |
+
assert has_execution_provider('InvalidExecutionProvider') is False
|
15 |
+
|
16 |
+
|
17 |
+
def test_multiple_execution_providers() -> None:
|
18 |
+
execution_provider_with_options =\
|
19 |
+
[
|
20 |
+
'CPUExecutionProvider',
|
21 |
+
('CUDAExecutionProvider',
|
22 |
+
{
|
23 |
+
'device_id': '1',
|
24 |
+
'cudnn_conv_algo_search': 'DEFAULT'
|
25 |
+
})
|
26 |
+
]
|
27 |
+
assert apply_execution_provider_options('1', [ 'CPUExecutionProvider', 'CUDAExecutionProvider' ]) == execution_provider_with_options
|
tests/test_face_analyser.py
ADDED
@@ -0,0 +1,103 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import subprocess
|
2 |
+
import pytest
|
3 |
+
|
4 |
+
import facefusion.globals
|
5 |
+
from facefusion.download import conditional_download
|
6 |
+
from facefusion.face_analyser import pre_check, clear_face_analyser, get_one_face
|
7 |
+
from facefusion.typing import Face
|
8 |
+
from facefusion.vision import read_static_image
|
9 |
+
|
10 |
+
|
11 |
+
@pytest.fixture(scope = 'module', autouse = True)
|
12 |
+
def before_all() -> None:
|
13 |
+
conditional_download('.assets/examples',
|
14 |
+
[
|
15 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples/source.jpg'
|
16 |
+
])
|
17 |
+
subprocess.run([ 'ffmpeg', '-i', '.assets/examples/source.jpg', '-vf', 'crop=iw*0.8:ih*0.8', '.assets/examples/source-80crop.jpg' ])
|
18 |
+
subprocess.run([ 'ffmpeg', '-i', '.assets/examples/source.jpg', '-vf', 'crop=iw*0.7:ih*0.7', '.assets/examples/source-70crop.jpg' ])
|
19 |
+
subprocess.run([ 'ffmpeg', '-i', '.assets/examples/source.jpg', '-vf', 'crop=iw*0.6:ih*0.6', '.assets/examples/source-60crop.jpg' ])
|
20 |
+
|
21 |
+
|
22 |
+
@pytest.fixture(autouse = True)
|
23 |
+
def before_each() -> None:
|
24 |
+
facefusion.globals.face_detector_score = 0.5
|
25 |
+
facefusion.globals.face_landmarker_score = 0.5
|
26 |
+
facefusion.globals.face_recognizer_model = 'arcface_inswapper'
|
27 |
+
clear_face_analyser()
|
28 |
+
|
29 |
+
|
30 |
+
def test_get_one_face_with_retinaface() -> None:
|
31 |
+
facefusion.globals.face_detector_model = 'retinaface'
|
32 |
+
facefusion.globals.face_detector_size = '320x320'
|
33 |
+
|
34 |
+
pre_check()
|
35 |
+
source_paths =\
|
36 |
+
[
|
37 |
+
'.assets/examples/source.jpg',
|
38 |
+
'.assets/examples/source-80crop.jpg',
|
39 |
+
'.assets/examples/source-70crop.jpg',
|
40 |
+
'.assets/examples/source-60crop.jpg'
|
41 |
+
]
|
42 |
+
for source_path in source_paths:
|
43 |
+
source_frame = read_static_image(source_path)
|
44 |
+
face = get_one_face(source_frame)
|
45 |
+
|
46 |
+
assert isinstance(face, Face)
|
47 |
+
|
48 |
+
|
49 |
+
def test_get_one_face_with_scrfd() -> None:
|
50 |
+
facefusion.globals.face_detector_model = 'scrfd'
|
51 |
+
facefusion.globals.face_detector_size = '640x640'
|
52 |
+
|
53 |
+
pre_check()
|
54 |
+
source_paths =\
|
55 |
+
[
|
56 |
+
'.assets/examples/source.jpg',
|
57 |
+
'.assets/examples/source-80crop.jpg',
|
58 |
+
'.assets/examples/source-70crop.jpg',
|
59 |
+
'.assets/examples/source-60crop.jpg'
|
60 |
+
]
|
61 |
+
for source_path in source_paths:
|
62 |
+
source_frame = read_static_image(source_path)
|
63 |
+
face = get_one_face(source_frame)
|
64 |
+
|
65 |
+
assert isinstance(face, Face)
|
66 |
+
|
67 |
+
|
68 |
+
def test_get_one_face_with_yoloface() -> None:
|
69 |
+
facefusion.globals.face_detector_model = 'yoloface'
|
70 |
+
facefusion.globals.face_detector_size = '640x640'
|
71 |
+
|
72 |
+
pre_check()
|
73 |
+
source_paths =\
|
74 |
+
[
|
75 |
+
'.assets/examples/source.jpg',
|
76 |
+
'.assets/examples/source-80crop.jpg',
|
77 |
+
'.assets/examples/source-70crop.jpg',
|
78 |
+
'.assets/examples/source-60crop.jpg'
|
79 |
+
]
|
80 |
+
for source_path in source_paths:
|
81 |
+
source_frame = read_static_image(source_path)
|
82 |
+
face = get_one_face(source_frame)
|
83 |
+
|
84 |
+
assert isinstance(face, Face)
|
85 |
+
|
86 |
+
|
87 |
+
def test_get_one_face_with_yunet() -> None:
|
88 |
+
facefusion.globals.face_detector_model = 'yunet'
|
89 |
+
facefusion.globals.face_detector_size = '640x640'
|
90 |
+
|
91 |
+
pre_check()
|
92 |
+
source_paths =\
|
93 |
+
[
|
94 |
+
'.assets/examples/source.jpg',
|
95 |
+
'.assets/examples/source-80crop.jpg',
|
96 |
+
'.assets/examples/source-70crop.jpg',
|
97 |
+
'.assets/examples/source-60crop.jpg'
|
98 |
+
]
|
99 |
+
for source_path in source_paths:
|
100 |
+
source_frame = read_static_image(source_path)
|
101 |
+
face = get_one_face(source_frame)
|
102 |
+
|
103 |
+
assert isinstance(face, Face)
|
tests/test_ffmpeg.py
ADDED
@@ -0,0 +1,113 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import glob
|
2 |
+
import subprocess
|
3 |
+
import pytest
|
4 |
+
|
5 |
+
import facefusion.globals
|
6 |
+
from facefusion import process_manager
|
7 |
+
from facefusion.filesystem import get_temp_directory_path, create_temp, clear_temp
|
8 |
+
from facefusion.download import conditional_download
|
9 |
+
from facefusion.ffmpeg import extract_frames, read_audio_buffer
|
10 |
+
|
11 |
+
|
12 |
+
@pytest.fixture(scope = 'module', autouse = True)
|
13 |
+
def before_all() -> None:
|
14 |
+
process_manager.start()
|
15 |
+
conditional_download('.assets/examples',
|
16 |
+
[
|
17 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples/source.jpg',
|
18 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples/source.mp3',
|
19 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples/target-240p.mp4'
|
20 |
+
])
|
21 |
+
subprocess.run([ 'ffmpeg', '-i', '.assets/examples/source.mp3', '.assets/examples/source.wav' ])
|
22 |
+
subprocess.run([ 'ffmpeg', '-i', '.assets/examples/target-240p.mp4', '-vf', 'fps=25', '.assets/examples/target-240p-25fps.mp4' ])
|
23 |
+
subprocess.run([ 'ffmpeg', '-i', '.assets/examples/target-240p.mp4', '-vf', 'fps=30', '.assets/examples/target-240p-30fps.mp4' ])
|
24 |
+
subprocess.run([ 'ffmpeg', '-i', '.assets/examples/target-240p.mp4', '-vf', 'fps=60', '.assets/examples/target-240p-60fps.mp4' ])
|
25 |
+
|
26 |
+
|
27 |
+
@pytest.fixture(scope = 'function', autouse = True)
|
28 |
+
def before_each() -> None:
|
29 |
+
facefusion.globals.trim_frame_start = None
|
30 |
+
facefusion.globals.trim_frame_end = None
|
31 |
+
facefusion.globals.temp_frame_format = 'jpg'
|
32 |
+
|
33 |
+
|
34 |
+
def test_extract_frames() -> None:
|
35 |
+
target_paths =\
|
36 |
+
[
|
37 |
+
'.assets/examples/target-240p-25fps.mp4',
|
38 |
+
'.assets/examples/target-240p-30fps.mp4',
|
39 |
+
'.assets/examples/target-240p-60fps.mp4'
|
40 |
+
]
|
41 |
+
|
42 |
+
for target_path in target_paths:
|
43 |
+
temp_directory_path = get_temp_directory_path(target_path)
|
44 |
+
create_temp(target_path)
|
45 |
+
|
46 |
+
assert extract_frames(target_path, '452x240', 30.0) is True
|
47 |
+
assert len(glob.glob1(temp_directory_path, '*.jpg')) == 324
|
48 |
+
|
49 |
+
clear_temp(target_path)
|
50 |
+
|
51 |
+
|
52 |
+
def test_extract_frames_with_trim_start() -> None:
|
53 |
+
facefusion.globals.trim_frame_start = 224
|
54 |
+
data_provider =\
|
55 |
+
[
|
56 |
+
('.assets/examples/target-240p-25fps.mp4', 55),
|
57 |
+
('.assets/examples/target-240p-30fps.mp4', 100),
|
58 |
+
('.assets/examples/target-240p-60fps.mp4', 212)
|
59 |
+
]
|
60 |
+
|
61 |
+
for target_path, frame_total in data_provider:
|
62 |
+
temp_directory_path = get_temp_directory_path(target_path)
|
63 |
+
create_temp(target_path)
|
64 |
+
|
65 |
+
assert extract_frames(target_path, '452x240', 30.0) is True
|
66 |
+
assert len(glob.glob1(temp_directory_path, '*.jpg')) == frame_total
|
67 |
+
|
68 |
+
clear_temp(target_path)
|
69 |
+
|
70 |
+
|
71 |
+
def test_extract_frames_with_trim_start_and_trim_end() -> None:
|
72 |
+
facefusion.globals.trim_frame_start = 124
|
73 |
+
facefusion.globals.trim_frame_end = 224
|
74 |
+
data_provider =\
|
75 |
+
[
|
76 |
+
('.assets/examples/target-240p-25fps.mp4', 120),
|
77 |
+
('.assets/examples/target-240p-30fps.mp4', 100),
|
78 |
+
('.assets/examples/target-240p-60fps.mp4', 50)
|
79 |
+
]
|
80 |
+
|
81 |
+
for target_path, frame_total in data_provider:
|
82 |
+
temp_directory_path = get_temp_directory_path(target_path)
|
83 |
+
create_temp(target_path)
|
84 |
+
|
85 |
+
assert extract_frames(target_path, '452x240', 30.0) is True
|
86 |
+
assert len(glob.glob1(temp_directory_path, '*.jpg')) == frame_total
|
87 |
+
|
88 |
+
clear_temp(target_path)
|
89 |
+
|
90 |
+
|
91 |
+
def test_extract_frames_with_trim_end() -> None:
|
92 |
+
facefusion.globals.trim_frame_end = 100
|
93 |
+
data_provider =\
|
94 |
+
[
|
95 |
+
('.assets/examples/target-240p-25fps.mp4', 120),
|
96 |
+
('.assets/examples/target-240p-30fps.mp4', 100),
|
97 |
+
('.assets/examples/target-240p-60fps.mp4', 50)
|
98 |
+
]
|
99 |
+
|
100 |
+
for target_path, frame_total in data_provider:
|
101 |
+
temp_directory_path = get_temp_directory_path(target_path)
|
102 |
+
create_temp(target_path)
|
103 |
+
|
104 |
+
assert extract_frames(target_path, '426x240', 30.0) is True
|
105 |
+
assert len(glob.glob1(temp_directory_path, '*.jpg')) == frame_total
|
106 |
+
|
107 |
+
clear_temp(target_path)
|
108 |
+
|
109 |
+
|
110 |
+
def test_read_audio_buffer() -> None:
|
111 |
+
assert isinstance(read_audio_buffer('.assets/examples/source.mp3', 1, 1), bytes)
|
112 |
+
assert isinstance(read_audio_buffer('.assets/examples/source.wav', 1, 1), bytes)
|
113 |
+
assert read_audio_buffer('.assets/examples/invalid.mp3', 1, 1) is None
|
tests/test_filesystem.py
ADDED
@@ -0,0 +1,91 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import shutil
|
2 |
+
import pytest
|
3 |
+
|
4 |
+
from facefusion.common_helper import is_windows
|
5 |
+
from facefusion.download import conditional_download
|
6 |
+
from facefusion.filesystem import get_file_size, is_file, is_directory, is_audio, has_audio, is_image, has_image, is_video, filter_audio_paths, filter_image_paths, list_directory, sanitize_path_for_windows
|
7 |
+
|
8 |
+
|
9 |
+
@pytest.fixture(scope = 'module', autouse = True)
|
10 |
+
def before_all() -> None:
|
11 |
+
conditional_download('.assets/examples',
|
12 |
+
[
|
13 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples/source.jpg',
|
14 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples/source.mp3',
|
15 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples/target-240p.mp4'
|
16 |
+
])
|
17 |
+
shutil.copyfile('.assets/examples/source.jpg', '.assets/examples/söurce.jpg')
|
18 |
+
|
19 |
+
|
20 |
+
def test_get_file_size() -> None:
|
21 |
+
assert get_file_size('.assets/examples/source.jpg') > 0
|
22 |
+
assert get_file_size('invalid') == 0
|
23 |
+
|
24 |
+
|
25 |
+
def test_is_file() -> None:
|
26 |
+
assert is_file('.assets/examples/source.jpg') is True
|
27 |
+
assert is_file('.assets/examples') is False
|
28 |
+
assert is_file('invalid') is False
|
29 |
+
|
30 |
+
|
31 |
+
def test_is_directory() -> None:
|
32 |
+
assert is_directory('.assets/examples') is True
|
33 |
+
assert is_directory('.assets/examples/source.jpg') is False
|
34 |
+
assert is_directory('invalid') is False
|
35 |
+
|
36 |
+
|
37 |
+
def test_is_audio() -> None:
|
38 |
+
assert is_audio('.assets/examples/source.mp3') is True
|
39 |
+
assert is_audio('.assets/examples/source.jpg') is False
|
40 |
+
assert is_audio('invalid') is False
|
41 |
+
|
42 |
+
|
43 |
+
def test_has_audio() -> None:
|
44 |
+
assert has_audio([ '.assets/examples/source.mp3' ]) is True
|
45 |
+
assert has_audio([ '.assets/examples/source.mp3', '.assets/examples/source.jpg' ]) is True
|
46 |
+
assert has_audio([ '.assets/examples/source.jpg', '.assets/examples/source.jpg' ]) is False
|
47 |
+
assert has_audio([ 'invalid' ]) is False
|
48 |
+
|
49 |
+
|
50 |
+
def test_is_image() -> None:
|
51 |
+
assert is_image('.assets/examples/source.jpg') is True
|
52 |
+
assert is_image('.assets/examples/target-240p.mp4') is False
|
53 |
+
assert is_image('invalid') is False
|
54 |
+
|
55 |
+
|
56 |
+
def test_has_image() -> None:
|
57 |
+
assert has_image([ '.assets/examples/source.jpg' ]) is True
|
58 |
+
assert has_image([ '.assets/examples/source.jpg', '.assets/examples/source.mp3' ]) is True
|
59 |
+
assert has_image([ '.assets/examples/source.mp3', '.assets/examples/source.mp3' ]) is False
|
60 |
+
assert has_image([ 'invalid' ]) is False
|
61 |
+
|
62 |
+
|
63 |
+
def test_is_video() -> None:
|
64 |
+
assert is_video('.assets/examples/target-240p.mp4') is True
|
65 |
+
assert is_video('.assets/examples/source.jpg') is False
|
66 |
+
assert is_video('invalid') is False
|
67 |
+
|
68 |
+
|
69 |
+
def test_filter_audio_paths() -> None:
|
70 |
+
assert filter_audio_paths([ '.assets/examples/source.jpg', '.assets/examples/source.mp3' ]) == [ '.assets/examples/source.mp3' ]
|
71 |
+
assert filter_audio_paths([ '.assets/examples/source.jpg', '.assets/examples/source.jpg' ]) == []
|
72 |
+
assert filter_audio_paths([ 'invalid' ]) == []
|
73 |
+
|
74 |
+
|
75 |
+
def test_filter_image_paths() -> None:
|
76 |
+
assert filter_image_paths([ '.assets/examples/source.jpg', '.assets/examples/source.mp3' ]) == [ '.assets/examples/source.jpg' ]
|
77 |
+
assert filter_image_paths([ '.assets/examples/source.mp3', '.assets/examples/source.mp3' ]) == []
|
78 |
+
assert filter_audio_paths([ 'invalid' ]) == []
|
79 |
+
|
80 |
+
|
81 |
+
def test_list_directory() -> None:
|
82 |
+
assert list_directory('.assets/examples')
|
83 |
+
assert list_directory('.assets/examples/source.jpg') is None
|
84 |
+
assert list_directory('invalid') is None
|
85 |
+
|
86 |
+
|
87 |
+
@pytest.mark.skip()
|
88 |
+
def test_sanitize_path_for_windows() -> None:
|
89 |
+
if is_windows():
|
90 |
+
assert sanitize_path_for_windows('.assets/examples/söurce.jpg') == 'ASSETS~1/examples/SURCE~1.JPG'
|
91 |
+
assert sanitize_path_for_windows('invalid') is None
|
tests/test_memory.py
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from facefusion.common_helper import is_linux, is_macos
|
2 |
+
from facefusion.memory import limit_system_memory
|
3 |
+
|
4 |
+
|
5 |
+
def test_limit_system_memory() -> None:
|
6 |
+
assert limit_system_memory(4) is True
|
7 |
+
if is_linux() or is_macos():
|
8 |
+
assert limit_system_memory(1024) is False
|
tests/test_normalizer.py
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from facefusion.common_helper import is_linux, is_macos
|
2 |
+
from facefusion.normalizer import normalize_output_path, normalize_padding, normalize_fps
|
3 |
+
|
4 |
+
|
5 |
+
def test_normalize_output_path() -> None:
|
6 |
+
if is_linux() or is_macos():
|
7 |
+
assert normalize_output_path('.assets/examples/target-240p.mp4', '.assets/examples/target-240p.mp4') == '.assets/examples/target-240p.mp4'
|
8 |
+
assert normalize_output_path('.assets/examples/target-240p.mp4', '.assets/examples').startswith('.assets/examples/target-240p')
|
9 |
+
assert normalize_output_path('.assets/examples/target-240p.mp4', '.assets/examples').endswith('.mp4')
|
10 |
+
assert normalize_output_path('.assets/examples/target-240p.mp4', '.assets/examples/output.mp4') == '.assets/examples/output.mp4'
|
11 |
+
assert normalize_output_path('.assets/examples/target-240p.mp4', '.assets/examples/invalid') is None
|
12 |
+
assert normalize_output_path('.assets/examples/target-240p.mp4', '.assets/invalid/output.mp4') is None
|
13 |
+
assert normalize_output_path('.assets/examples/target-240p.mp4', 'invalid') is None
|
14 |
+
assert normalize_output_path('.assets/examples/target-240p.mp4', None) is None
|
15 |
+
assert normalize_output_path(None, '.assets/examples/output.mp4') is None
|
16 |
+
|
17 |
+
|
18 |
+
def test_normalize_padding() -> None:
|
19 |
+
assert normalize_padding([ 0, 0, 0, 0 ]) == (0, 0, 0, 0)
|
20 |
+
assert normalize_padding([ 1 ]) == (1, 1, 1, 1)
|
21 |
+
assert normalize_padding([ 1, 2 ]) == (1, 2, 1, 2)
|
22 |
+
assert normalize_padding([ 1, 2, 3 ]) == (1, 2, 3, 2)
|
23 |
+
assert normalize_padding(None) is None
|
24 |
+
|
25 |
+
|
26 |
+
def test_normalize_fps() -> None:
|
27 |
+
assert normalize_fps(0.0) == 1.0
|
28 |
+
assert normalize_fps(25.0) == 25.0
|
29 |
+
assert normalize_fps(61.0) == 60.0
|
30 |
+
assert normalize_fps(None) is None
|
tests/test_process_manager.py
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from facefusion.process_manager import set_process_state, is_processing, is_stopping, is_pending, start, stop, end
|
2 |
+
|
3 |
+
|
4 |
+
def test_start() -> None:
|
5 |
+
set_process_state('pending')
|
6 |
+
start()
|
7 |
+
|
8 |
+
assert is_processing()
|
9 |
+
|
10 |
+
|
11 |
+
def test_stop() -> None:
|
12 |
+
set_process_state('processing')
|
13 |
+
stop()
|
14 |
+
|
15 |
+
assert is_stopping()
|
16 |
+
|
17 |
+
|
18 |
+
def test_end() -> None:
|
19 |
+
set_process_state('processing')
|
20 |
+
end()
|
21 |
+
|
22 |
+
assert is_pending()
|
tests/test_vision.py
ADDED
@@ -0,0 +1,109 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import subprocess
|
2 |
+
import pytest
|
3 |
+
|
4 |
+
from facefusion.download import conditional_download
|
5 |
+
from facefusion.vision import detect_image_resolution, restrict_image_resolution, create_image_resolutions, get_video_frame, count_video_frame_total, detect_video_fps, restrict_video_fps, detect_video_resolution, restrict_video_resolution, create_video_resolutions, normalize_resolution, pack_resolution, unpack_resolution
|
6 |
+
|
7 |
+
|
8 |
+
@pytest.fixture(scope = 'module', autouse = True)
|
9 |
+
def before_all() -> None:
|
10 |
+
conditional_download('.assets/examples',
|
11 |
+
[
|
12 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples/source.jpg',
|
13 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples/target-240p.mp4',
|
14 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples/target-1080p.mp4'
|
15 |
+
])
|
16 |
+
subprocess.run([ 'ffmpeg', '-i', '.assets/examples/target-240p.mp4', '-vframes', '1', '.assets/examples/target-240p.jpg' ])
|
17 |
+
subprocess.run([ 'ffmpeg', '-i', '.assets/examples/target-1080p.mp4', '-vframes', '1', '.assets/examples/target-1080p.jpg' ])
|
18 |
+
subprocess.run([ 'ffmpeg', '-i', '.assets/examples/target-240p.mp4', '-vframes', '1', '-vf', 'transpose=0', '.assets/examples/target-240p-90deg.jpg' ])
|
19 |
+
subprocess.run([ 'ffmpeg', '-i', '.assets/examples/target-1080p.mp4', '-vframes', '1', '-vf', 'transpose=0', '.assets/examples/target-1080p-90deg.jpg' ])
|
20 |
+
subprocess.run([ 'ffmpeg', '-i', '.assets/examples/target-240p.mp4', '-vf', 'fps=25', '.assets/examples/target-240p-25fps.mp4' ])
|
21 |
+
subprocess.run([ 'ffmpeg', '-i', '.assets/examples/target-240p.mp4', '-vf', 'fps=30', '.assets/examples/target-240p-30fps.mp4' ])
|
22 |
+
subprocess.run([ 'ffmpeg', '-i', '.assets/examples/target-240p.mp4', '-vf', 'fps=60', '.assets/examples/target-240p-60fps.mp4' ])
|
23 |
+
subprocess.run([ 'ffmpeg', '-i', '.assets/examples/target-240p.mp4', '-vf', 'transpose=0', '.assets/examples/target-240p-90deg.mp4' ])
|
24 |
+
subprocess.run([ 'ffmpeg', '-i', '.assets/examples/target-1080p.mp4', '-vf', 'transpose=0', '.assets/examples/target-1080p-90deg.mp4' ])
|
25 |
+
|
26 |
+
|
27 |
+
def test_detect_image_resolution() -> None:
|
28 |
+
assert detect_image_resolution('.assets/examples/target-240p.jpg') == (426, 226)
|
29 |
+
assert detect_image_resolution('.assets/examples/target-240p-90deg.jpg') == (226, 426)
|
30 |
+
assert detect_image_resolution('.assets/examples/target-1080p.jpg') == (2048, 1080)
|
31 |
+
assert detect_image_resolution('.assets/examples/target-1080p-90deg.jpg') == (1080, 2048)
|
32 |
+
assert detect_image_resolution('invalid') is None
|
33 |
+
|
34 |
+
|
35 |
+
def test_restrict_image_resolution() -> None:
|
36 |
+
assert restrict_image_resolution('.assets/examples/target-1080p.jpg', (426, 226)) == (426, 226)
|
37 |
+
assert restrict_image_resolution('.assets/examples/target-1080p.jpg', (2048, 1080)) == (2048, 1080)
|
38 |
+
assert restrict_image_resolution('.assets/examples/target-1080p.jpg', (4096, 2160)) == (2048, 1080)
|
39 |
+
|
40 |
+
|
41 |
+
def test_create_image_resolutions() -> None:
|
42 |
+
assert create_image_resolutions((426, 226)) == [ '106x56', '212x112', '320x170', '426x226', '640x340', '852x452', '1064x564', '1278x678', '1492x792', '1704x904' ]
|
43 |
+
assert create_image_resolutions((226, 426)) == [ '56x106', '112x212', '170x320', '226x426', '340x640', '452x852', '564x1064', '678x1278', '792x1492', '904x1704' ]
|
44 |
+
assert create_image_resolutions((2048, 1080)) == [ '512x270', '1024x540', '1536x810', '2048x1080', '3072x1620', '4096x2160', '5120x2700', '6144x3240', '7168x3780', '8192x4320' ]
|
45 |
+
assert create_image_resolutions((1080, 2048)) == [ '270x512', '540x1024', '810x1536', '1080x2048', '1620x3072', '2160x4096', '2700x5120', '3240x6144', '3780x7168', '4320x8192' ]
|
46 |
+
assert create_image_resolutions(None) == []
|
47 |
+
|
48 |
+
|
49 |
+
def test_get_video_frame() -> None:
|
50 |
+
assert get_video_frame('.assets/examples/target-240p-25fps.mp4') is not None
|
51 |
+
assert get_video_frame('invalid') is None
|
52 |
+
|
53 |
+
|
54 |
+
def test_count_video_frame_total() -> None:
|
55 |
+
assert count_video_frame_total('.assets/examples/target-240p-25fps.mp4') == 270
|
56 |
+
assert count_video_frame_total('.assets/examples/target-240p-30fps.mp4') == 324
|
57 |
+
assert count_video_frame_total('.assets/examples/target-240p-60fps.mp4') == 648
|
58 |
+
assert count_video_frame_total('invalid') == 0
|
59 |
+
|
60 |
+
|
61 |
+
def test_detect_video_fps() -> None:
|
62 |
+
assert detect_video_fps('.assets/examples/target-240p-25fps.mp4') == 25.0
|
63 |
+
assert detect_video_fps('.assets/examples/target-240p-30fps.mp4') == 30.0
|
64 |
+
assert detect_video_fps('.assets/examples/target-240p-60fps.mp4') == 60.0
|
65 |
+
assert detect_video_fps('invalid') is None
|
66 |
+
|
67 |
+
|
68 |
+
def test_restrict_video_fps() -> None:
|
69 |
+
assert restrict_video_fps('.assets/examples/target-1080p.mp4', 20.0) == 20.0
|
70 |
+
assert restrict_video_fps('.assets/examples/target-1080p.mp4', 25.0) == 25.0
|
71 |
+
assert restrict_video_fps('.assets/examples/target-1080p.mp4', 60.0) == 25.0
|
72 |
+
|
73 |
+
|
74 |
+
def test_detect_video_resolution() -> None:
|
75 |
+
assert detect_video_resolution('.assets/examples/target-240p.mp4') == (426, 226)
|
76 |
+
assert detect_video_resolution('.assets/examples/target-240p-90deg.mp4') == (226, 426)
|
77 |
+
assert detect_video_resolution('.assets/examples/target-1080p.mp4') == (2048, 1080)
|
78 |
+
assert detect_video_resolution('.assets/examples/target-1080p-90deg.mp4') == (1080, 2048)
|
79 |
+
assert detect_video_resolution('invalid') is None
|
80 |
+
|
81 |
+
|
82 |
+
def test_restrict_video_resolution() -> None:
|
83 |
+
assert restrict_video_resolution('.assets/examples/target-1080p.mp4', (426, 226)) == (426, 226)
|
84 |
+
assert restrict_video_resolution('.assets/examples/target-1080p.mp4', (2048, 1080)) == (2048, 1080)
|
85 |
+
assert restrict_video_resolution('.assets/examples/target-1080p.mp4', (4096, 2160)) == (2048, 1080)
|
86 |
+
|
87 |
+
|
88 |
+
def test_create_video_resolutions() -> None:
|
89 |
+
assert create_video_resolutions((426, 226)) == [ '426x226', '452x240', '678x360', '904x480', '1018x540', '1358x720', '2036x1080', '2714x1440', '4072x2160', '8144x4320' ]
|
90 |
+
assert create_video_resolutions((226, 426)) == [ '226x426', '240x452', '360x678', '480x904', '540x1018', '720x1358', '1080x2036', '1440x2714', '2160x4072', '4320x8144' ]
|
91 |
+
assert create_video_resolutions((2048, 1080)) == [ '456x240', '682x360', '910x480', '1024x540', '1366x720', '2048x1080', '2730x1440', '4096x2160', '8192x4320' ]
|
92 |
+
assert create_video_resolutions((1080, 2048)) == [ '240x456', '360x682', '480x910', '540x1024', '720x1366', '1080x2048', '1440x2730', '2160x4096', '4320x8192' ]
|
93 |
+
assert create_video_resolutions(None) == []
|
94 |
+
|
95 |
+
|
96 |
+
def test_normalize_resolution() -> None:
|
97 |
+
assert normalize_resolution((2.5, 2.5)) == (2, 2)
|
98 |
+
assert normalize_resolution((3.0, 3.0)) == (4, 4)
|
99 |
+
assert normalize_resolution((6.5, 6.5)) == (6, 6)
|
100 |
+
|
101 |
+
|
102 |
+
def test_pack_resolution() -> None:
|
103 |
+
assert pack_resolution((1, 1)) == '0x0'
|
104 |
+
assert pack_resolution((2, 2)) == '2x2'
|
105 |
+
|
106 |
+
|
107 |
+
def test_unpack_resolution() -> None:
|
108 |
+
assert unpack_resolution('0x0') == (0, 0)
|
109 |
+
assert unpack_resolution('2x2') == (2, 2)
|
tests/test_wording.py
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from facefusion import wording
|
2 |
+
|
3 |
+
|
4 |
+
def test_get() -> None:
|
5 |
+
assert wording.get('python_not_supported')
|
6 |
+
assert wording.get('help.source')
|
7 |
+
assert wording.get('invalid') is None
|