2023-09-24 21:36:57 +08:00
import os
import sys
2024-08-16 21:03:14 +08:00
# single thread doubles cuda performance - needs to be set before torch import
if any ( arg . startswith ( ' --execution-provider ' ) for arg in sys . argv ) :
os . environ [ ' OMP_NUM_THREADS ' ] = ' 1 '
# reduce tensorflow log level
os . environ [ ' TF_CPP_MIN_LOG_LEVEL ' ] = ' 2 '
2023-09-24 21:36:57 +08:00
import warnings
2024-08-16 21:03:14 +08:00
from typing import List
2023-09-24 21:36:57 +08:00
import platform
import signal
import shutil
import argparse
import torch
import onnxruntime
import tensorflow
import modules . globals
import modules . metadata
import modules . ui as ui
from modules . processors . frame . core import get_frame_processors_modules
2024-08-16 21:03:14 +08:00
from modules . utilities import has_image_extension , is_image , is_video , detect_fps , create_video , extract_frames , get_temp_frame_paths , restore_audio , create_temp , move_temp , clean_temp , normalize_output_path
2024-08-16 13:47:12 +08:00
2024-08-16 21:03:14 +08:00
if ' ROCMExecutionProvider ' in modules . globals . execution_providers :
2024-08-15 12:15:53 -04:00
del torch
2024-08-16 21:03:14 +08:00
warnings . filterwarnings ( ' ignore ' , category = FutureWarning , module = ' insightface ' )
warnings . filterwarnings ( ' ignore ' , category = UserWarning , module = ' torchvision ' )
2023-09-24 21:36:57 +08:00
def parse_args ( ) - > None :
signal . signal ( signal . SIGINT , lambda signal_number , frame : destroy ( ) )
program = argparse . ArgumentParser ( )
2024-08-16 21:03:14 +08:00
program . add_argument ( ' -s ' , ' --source ' , help = ' select an source image ' , dest = ' source_path ' )
program . add_argument ( ' -t ' , ' --target ' , help = ' select an target image or video ' , dest = ' target_path ' )
program . add_argument ( ' -o ' , ' --output ' , help = ' select output file or directory ' , dest = ' output_path ' )
program . add_argument ( ' --frame-processor ' , help = ' pipeline of frame processors ' , dest = ' frame_processor ' , default = [ ' face_swapper ' ] , choices = [ ' face_swapper ' , ' face_enhancer ' ] , nargs = ' + ' )
program . add_argument ( ' --keep-fps ' , help = ' keep original fps ' , dest = ' keep_fps ' , action = ' store_true ' , default = False )
program . add_argument ( ' --keep-audio ' , help = ' keep original audio ' , dest = ' keep_audio ' , action = ' store_true ' , default = True )
program . add_argument ( ' --keep-frames ' , help = ' keep temporary frames ' , dest = ' keep_frames ' , action = ' store_true ' , default = False )
program . add_argument ( ' --many-faces ' , help = ' process every face ' , dest = ' many_faces ' , action = ' store_true ' , default = False )
2024-08-21 02:02:00 +07:00
program . add_argument ( ' --nsfw-filter ' , help = ' filter the NSFW image or video ' , dest = ' nsfw_filter ' , action = ' store_true ' , default = False )
2024-09-10 14:28:33 +05:30
program . add_argument ( ' --map-faces ' , help = ' map source target faces ' , dest = ' map_faces ' , action = ' store_true ' , default = False )
2024-12-24 09:51:32 +03:30
program . add_argument ( ' --mouth-mask ' , help = ' mask the mouth region ' , dest = ' mouth_mask ' , action = ' store_true ' , default = False )
2024-08-16 21:03:14 +08:00
program . add_argument ( ' --video-encoder ' , help = ' adjust output video encoder ' , dest = ' video_encoder ' , default = ' libx264 ' , choices = [ ' libx264 ' , ' libx265 ' , ' libvpx-vp9 ' ] )
program . add_argument ( ' --video-quality ' , help = ' adjust output video quality ' , dest = ' video_quality ' , type = int , default = 18 , choices = range ( 52 ) , metavar = ' [0-51] ' )
2025-01-07 14:04:18 +08:00
program . add_argument ( ' -l ' , ' --lang ' , help = ' Ui language ' , default = " en " )
2024-08-22 00:35:05 +07:00
program . add_argument ( ' --live-mirror ' , help = ' The live camera display as you see it in the front-facing camera frame ' , dest = ' live_mirror ' , action = ' store_true ' , default = False )
program . add_argument ( ' --live-resizable ' , help = ' The live camera frame is resizable ' , dest = ' live_resizable ' , action = ' store_true ' , default = False )
2024-08-16 21:03:14 +08:00
program . add_argument ( ' --max-memory ' , help = ' maximum amount of RAM in GB ' , dest = ' max_memory ' , type = int , default = suggest_max_memory ( ) )
program . add_argument ( ' --execution-provider ' , help = ' execution provider ' , dest = ' execution_provider ' , default = [ ' cpu ' ] , choices = suggest_execution_providers ( ) , nargs = ' + ' )
program . add_argument ( ' --execution-threads ' , help = ' number of execution threads ' , dest = ' execution_threads ' , type = int , default = suggest_execution_threads ( ) )
program . add_argument ( ' -v ' , ' --version ' , action = ' version ' , version = f ' { modules . metadata . name } { modules . metadata . version } ' )
# register deprecated args
2023-09-24 21:36:57 +08:00
program . add_argument ( ' -f ' , ' --face ' , help = argparse . SUPPRESS , dest = ' source_path_deprecated ' )
program . add_argument ( ' --cpu-cores ' , help = argparse . SUPPRESS , dest = ' cpu_cores_deprecated ' , type = int )
program . add_argument ( ' --gpu-vendor ' , help = argparse . SUPPRESS , dest = ' gpu_vendor_deprecated ' )
program . add_argument ( ' --gpu-threads ' , help = argparse . SUPPRESS , dest = ' gpu_threads_deprecated ' , type = int )
args = program . parse_args ( )
modules . globals . source_path = args . source_path
modules . globals . target_path = args . target_path
2024-08-16 21:03:14 +08:00
modules . globals . output_path = normalize_output_path ( modules . globals . source_path , modules . globals . target_path , args . output_path )
2023-09-24 21:36:57 +08:00
modules . globals . frame_processors = args . frame_processor
modules . globals . headless = args . source_path or args . target_path or args . output_path
modules . globals . keep_fps = args . keep_fps
modules . globals . keep_audio = args . keep_audio
modules . globals . keep_frames = args . keep_frames
modules . globals . many_faces = args . many_faces
2024-12-24 09:40:06 +03:30
modules . globals . mouth_mask = args . mouth_mask
2024-08-21 02:02:00 +07:00
modules . globals . nsfw_filter = args . nsfw_filter
2024-09-10 04:37:58 +05:30
modules . globals . map_faces = args . map_faces
2023-09-24 21:36:57 +08:00
modules . globals . video_encoder = args . video_encoder
modules . globals . video_quality = args . video_quality
2024-08-22 00:35:05 +07:00
modules . globals . live_mirror = args . live_mirror
modules . globals . live_resizable = args . live_resizable
2023-09-24 21:36:57 +08:00
modules . globals . max_memory = args . max_memory
modules . globals . execution_providers = decode_execution_providers ( args . execution_provider )
modules . globals . execution_threads = args . execution_threads
2025-01-07 14:04:18 +08:00
modules . globals . lang = args . lang
2023-09-24 21:36:57 +08:00
2024-08-16 21:03:14 +08:00
#for ENHANCER tumbler:
if ' face_enhancer ' in args . frame_processor :
modules . globals . fp_ui [ ' face_enhancer ' ] = True
else :
modules . globals . fp_ui [ ' face_enhancer ' ] = False
2024-08-14 17:52:42 +02:00
2024-08-16 21:03:14 +08:00
# translate deprecated args
2023-09-24 21:36:57 +08:00
if args . source_path_deprecated :
print ( ' \033 [33mArgument -f and --face are deprecated. Use -s and --source instead. \033 [0m ' )
modules . globals . source_path = args . source_path_deprecated
2024-08-16 21:03:14 +08:00
modules . globals . output_path = normalize_output_path ( args . source_path_deprecated , modules . globals . target_path , args . output_path )
2023-09-24 21:36:57 +08:00
if args . cpu_cores_deprecated :
print ( ' \033 [33mArgument --cpu-cores is deprecated. Use --execution-threads instead. \033 [0m ' )
modules . globals . execution_threads = args . cpu_cores_deprecated
if args . gpu_vendor_deprecated == ' apple ' :
print ( ' \033 [33mArgument --gpu-vendor apple is deprecated. Use --execution-provider coreml instead. \033 [0m ' )
modules . globals . execution_providers = decode_execution_providers ( [ ' coreml ' ] )
if args . gpu_vendor_deprecated == ' nvidia ' :
print ( ' \033 [33mArgument --gpu-vendor nvidia is deprecated. Use --execution-provider cuda instead. \033 [0m ' )
modules . globals . execution_providers = decode_execution_providers ( [ ' cuda ' ] )
if args . gpu_vendor_deprecated == ' amd ' :
2024-08-16 21:03:14 +08:00
print ( ' \033 [33mArgument --gpu-vendor amd is deprecated. Use --execution-provider cuda instead. \033 [0m ' )
2023-09-24 21:36:57 +08:00
modules . globals . execution_providers = decode_execution_providers ( [ ' rocm ' ] )
if args . gpu_threads_deprecated :
print ( ' \033 [33mArgument --gpu-threads is deprecated. Use --execution-threads instead. \033 [0m ' )
modules . globals . execution_threads = args . gpu_threads_deprecated
def encode_execution_providers ( execution_providers : List [ str ] ) - > List [ str ] :
2024-08-16 21:03:14 +08:00
return [ execution_provider . replace ( ' ExecutionProvider ' , ' ' ) . lower ( ) for execution_provider in execution_providers ]
2023-09-24 21:36:57 +08:00
def decode_execution_providers ( execution_providers : List [ str ] ) - > List [ str ] :
2024-08-16 21:03:14 +08:00
return [ provider for provider , encoded_execution_provider in zip ( onnxruntime . get_available_providers ( ) , encode_execution_providers ( onnxruntime . get_available_providers ( ) ) )
if any ( execution_provider in encoded_execution_provider for execution_provider in execution_providers ) ]
2023-09-24 21:36:57 +08:00
def suggest_max_memory ( ) - > int :
2024-08-16 21:03:14 +08:00
if platform . system ( ) . lower ( ) == ' darwin ' :
return 4
return 16
2023-09-24 21:36:57 +08:00
def suggest_execution_providers ( ) - > List [ str ] :
return encode_execution_providers ( onnxruntime . get_available_providers ( ) )
def suggest_execution_threads ( ) - > int :
2024-08-16 21:03:14 +08:00
if ' DmlExecutionProvider ' in modules . globals . execution_providers :
2023-09-24 21:36:57 +08:00
return 1
2024-08-16 21:03:14 +08:00
if ' ROCMExecutionProvider ' in modules . globals . execution_providers :
2023-09-24 21:36:57 +08:00
return 1
return 8
def limit_resources ( ) - > None :
2024-08-16 21:03:14 +08:00
# prevent tensorflow memory leak
2023-09-24 21:36:57 +08:00
gpus = tensorflow . config . experimental . list_physical_devices ( ' GPU ' )
for gpu in gpus :
tensorflow . config . experimental . set_memory_growth ( gpu , True )
2024-08-16 21:03:14 +08:00
# limit memory usage
2023-09-24 21:36:57 +08:00
if modules . globals . max_memory :
memory = modules . globals . max_memory * 1024 * * 3
if platform . system ( ) . lower ( ) == ' darwin ' :
2024-08-16 21:03:14 +08:00
memory = modules . globals . max_memory * 1024 * * 6
if platform . system ( ) . lower ( ) == ' windows ' :
2023-09-24 21:36:57 +08:00
import ctypes
kernel32 = ctypes . windll . kernel32
kernel32 . SetProcessWorkingSetSize ( - 1 , ctypes . c_size_t ( memory ) , ctypes . c_size_t ( memory ) )
else :
import resource
2024-08-16 21:03:14 +08:00
resource . setrlimit ( resource . RLIMIT_DATA , ( memory , memory ) )
2023-09-24 21:36:57 +08:00
def release_resources ( ) - > None :
2024-08-16 21:03:14 +08:00
if ' CUDAExecutionProvider ' in modules . globals . execution_providers :
2023-09-24 21:36:57 +08:00
torch . cuda . empty_cache ( )
def pre_check ( ) - > bool :
if sys . version_info < ( 3 , 9 ) :
update_status ( ' Python version is not supported - please upgrade to 3.9 or higher. ' )
return False
if not shutil . which ( ' ffmpeg ' ) :
update_status ( ' ffmpeg is not installed. ' )
return False
return True
def update_status ( message : str , scope : str = ' DLC.CORE ' ) - > None :
print ( f ' [ { scope } ] { message } ' )
2024-08-16 21:03:14 +08:00
if not modules . globals . headless :
2023-09-24 21:36:57 +08:00
ui . update_status ( message )
def start ( ) - > None :
for frame_processor in get_frame_processors_modules ( modules . globals . frame_processors ) :
if not frame_processor . pre_start ( ) :
return
2024-08-21 02:02:00 +07:00
update_status ( ' Processing... ' )
2024-08-16 21:03:14 +08:00
# process image to image
2023-09-24 21:36:57 +08:00
if has_image_extension ( modules . globals . target_path ) :
2024-08-21 02:02:00 +07:00
if modules . globals . nsfw_filter and ui . check_and_ignore_nsfw ( modules . globals . target_path , destroy ) :
return
try :
shutil . copy2 ( modules . globals . target_path , modules . globals . output_path )
except Exception as e :
print ( " Error copying file: " , str ( e ) )
2024-08-16 21:03:14 +08:00
for frame_processor in get_frame_processors_modules ( modules . globals . frame_processors ) :
update_status ( ' Progressing... ' , frame_processor . NAME )
frame_processor . process_image ( modules . globals . source_path , modules . globals . output_path , modules . globals . output_path )
release_resources ( )
if is_image ( modules . globals . target_path ) :
update_status ( ' Processing to image succeed! ' )
else :
update_status ( ' Processing to image failed! ' )
return
# process image to videos
2024-08-21 02:02:00 +07:00
if modules . globals . nsfw_filter and ui . check_and_ignore_nsfw ( modules . globals . target_path , destroy ) :
return
2024-09-10 04:37:58 +05:30
if not modules . globals . map_faces :
update_status ( ' Creating temp resources... ' )
create_temp ( modules . globals . target_path )
update_status ( ' Extracting frames... ' )
extract_frames ( modules . globals . target_path )
2023-09-24 21:36:57 +08:00
temp_frame_paths = get_temp_frame_paths ( modules . globals . target_path )
for frame_processor in get_frame_processors_modules ( modules . globals . frame_processors ) :
2024-08-16 21:03:14 +08:00
update_status ( ' Progressing... ' , frame_processor . NAME )
2023-09-24 21:36:57 +08:00
frame_processor . process_video ( modules . globals . source_path , temp_frame_paths )
release_resources ( )
2024-08-16 21:03:14 +08:00
# handles fps
2023-09-24 21:36:57 +08:00
if modules . globals . keep_fps :
update_status ( ' Detecting fps... ' )
fps = detect_fps ( modules . globals . target_path )
update_status ( f ' Creating video with { fps } fps... ' )
create_video ( modules . globals . target_path , fps )
else :
update_status ( ' Creating video with 30.0 fps... ' )
create_video ( modules . globals . target_path )
2024-08-16 21:03:14 +08:00
# handle audio
2023-09-24 21:36:57 +08:00
if modules . globals . keep_audio :
if modules . globals . keep_fps :
update_status ( ' Restoring audio... ' )
else :
update_status ( ' Restoring audio might cause issues as fps are not kept... ' )
restore_audio ( modules . globals . target_path , modules . globals . output_path )
else :
move_temp ( modules . globals . target_path , modules . globals . output_path )
2024-08-16 21:03:14 +08:00
# clean and validate
clean_temp ( modules . globals . target_path )
if is_video ( modules . globals . target_path ) :
update_status ( ' Processing to video succeed! ' )
else :
update_status ( ' Processing to video failed! ' )
2023-09-24 21:36:57 +08:00
2024-08-21 02:02:00 +07:00
def destroy ( to_quit = True ) - > None :
2023-09-24 21:36:57 +08:00
if modules . globals . target_path :
clean_temp ( modules . globals . target_path )
2024-08-21 02:02:00 +07:00
if to_quit : quit ( )
2023-09-24 21:36:57 +08:00
def run ( ) - > None :
2024-08-16 21:03:14 +08:00
parse_args ( )
if not pre_check ( ) :
return
for frame_processor in get_frame_processors_modules ( modules . globals . frame_processors ) :
if not frame_processor . pre_check ( ) :
2023-09-24 21:36:57 +08:00
return
2024-08-16 21:03:14 +08:00
limit_resources ( )
if modules . globals . headless :
start ( )
else :
2025-01-07 14:04:18 +08:00
window = ui . init ( start , destroy , modules . globals . lang )
2024-08-16 21:03:14 +08:00
window . mainloop ( )