salominavina commited on
Commit
90ba202
1 Parent(s): efdd9ee

Upload 23 files

Browse files
.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