-
Notifications
You must be signed in to change notification settings - Fork 77
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[DONE] - FFMPEG use GPU #1168
base: develop
Are you sure you want to change the base?
[DONE] - FFMPEG use GPU #1168
Changes from all commits
0298e29
eb0b54f
b6ab0f2
9ad7f03
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -45,6 +45,18 @@ | |
FFMPEG_DRESSING_SCALE, | ||
FFMPEG_DRESSING_CONCAT, | ||
) | ||
from encoding_gpu_settings import ( | ||
FFMPEG_USE_GPU, | ||
FFMPEG_CMD_GPU, | ||
FFMPEG_PRESET_GPU, | ||
FFMPEG_LEVEL_GPU, | ||
FFMPEG_INPUT_GPU, | ||
FFMPEG_LIBX_GPU, | ||
FFMPEG_MP4_ENCODE_GPU, | ||
FFMPEG_HLS_COMMON_PARAMS_GPU, | ||
FFMPEG_HLS_ENCODE_PARAMS_GPU, | ||
FFMPEG_CREATE_THUMBNAIL_GPU | ||
) | ||
else: | ||
from .encoding_utils import ( | ||
get_dressing_position_value, | ||
|
@@ -83,6 +95,18 @@ | |
FFMPEG_DRESSING_SCALE, | ||
FFMPEG_DRESSING_CONCAT, | ||
) | ||
from .encoding_gpu_settings import ( | ||
FFMPEG_USE_GPU, | ||
FFMPEG_CMD_GPU, | ||
FFMPEG_PRESET_GPU, | ||
FFMPEG_LEVEL_GPU, | ||
FFMPEG_INPUT_GPU, | ||
FFMPEG_LIBX_GPU, | ||
FFMPEG_MP4_ENCODE_GPU, | ||
FFMPEG_HLS_COMMON_PARAMS_GPU, | ||
FFMPEG_HLS_ENCODE_PARAMS_GPU, | ||
FFMPEG_CREATE_THUMBNAIL_GPU | ||
) | ||
|
||
|
||
__author__ = "Nicolas CAN <[email protected]>" | ||
|
@@ -100,23 +124,36 @@ | |
try: | ||
from django.conf import settings | ||
|
||
FFMPEG_USE_GPU = getattr(settings, "FFMPEG_USE_GPU", FFMPEG_USE_GPU) | ||
FFMPEG_CMD = getattr(settings, "FFMPEG_CMD", FFMPEG_CMD) | ||
FFMPEG_CMD_GPU = getattr(settings, "FFMPEG_CMD_GPU", FFMPEG_CMD_GPU) | ||
FFPROBE_CMD = getattr(settings, "FFPROBE_CMD", FFPROBE_CMD) | ||
FFPROBE_GET_INFO = getattr(settings, "FFPROBE_GET_INFO", FFPROBE_GET_INFO) | ||
FFMPEG_CRF = getattr(settings, "FFMPEG_CRF", FFMPEG_CRF) | ||
FFMPEG_PRESET = getattr(settings, "FFMPEG_PRESET", FFMPEG_PRESET) | ||
FFMPEG_PRESET_GPU = getattr(settings, "FFMPEG_PRESET_GPU", FFMPEG_PRESET_GPU) | ||
FFMPEG_PROFILE = getattr(settings, "FFMPEG_PROFILE", FFMPEG_PROFILE) | ||
FFMPEG_LEVEL = getattr(settings, "FFMPEG_LEVEL", FFMPEG_LEVEL) | ||
FFMPEG_LEVEL_GPU = getattr(settings, "FFMPEG_LEVEL_GPU", FFMPEG_LEVEL_GPU) | ||
FFMPEG_HLS_TIME = getattr(settings, "FFMPEG_HLS_TIME", FFMPEG_HLS_TIME) | ||
FFMPEG_INPUT = getattr(settings, "FFMPEG_INPUT", FFMPEG_INPUT) | ||
FFMPEG_INPUT_GPU = getattr(settings, "FFMPEG_INPUT_GPU", FFMPEG_INPUT_GPU) | ||
FFMPEG_LIBX = getattr(settings, "FFMPEG_LIBX", FFMPEG_LIBX) | ||
FFMPEG_LIBX_GPU = getattr(settings, "FFMPEG_LIBX_GPU", FFMPEG_LIBX_GPU) | ||
FFMPEG_MP4_ENCODE = getattr(settings, "FFMPEG_MP4_ENCODE", FFMPEG_MP4_ENCODE) | ||
FFMPEG_MP4_ENCODE_GPU = getattr(settings, "FFMPEG_MP4_ENCODE_GPU", FFMPEG_MP4_ENCODE_GPU) | ||
FFMPEG_HLS_COMMON_PARAMS = getattr( | ||
settings, "FFMPEG_HLS_COMMON_PARAMS", FFMPEG_HLS_COMMON_PARAMS | ||
) | ||
FFMPEG_HLS_COMMON_PARAMS_GPU = getattr( | ||
settings, "FFMPEG_HLS_COMMON_PARAMS_GPU", FFMPEG_HLS_COMMON_PARAMS_GPU | ||
) | ||
FFMPEG_HLS_ENCODE_PARAMS = getattr( | ||
settings, "FFMPEG_HLS_ENCODE_PARAMS", FFMPEG_HLS_ENCODE_PARAMS | ||
) | ||
FFMPEG_HLS_ENCODE_PARAMS_GPU = getattr( | ||
settings, "FFMPEG_HLS_ENCODE_PARAMS_GPU", FFMPEG_HLS_ENCODE_PARAMS_GPU | ||
) | ||
FFMPEG_MP3_ENCODE = getattr(settings, "FFMPEG_MP3_ENCODE", FFMPEG_MP3_ENCODE) | ||
FFMPEG_M4A_ENCODE = getattr(settings, "FFMPEG_M4A_ENCODE", FFMPEG_M4A_ENCODE) | ||
FFMPEG_NB_THREADS = getattr(settings, "FFMPEG_NB_THREADS", FFMPEG_NB_THREADS) | ||
|
@@ -128,6 +165,9 @@ | |
FFMPEG_CREATE_THUMBNAIL = getattr( | ||
settings, "FFMPEG_CREATE_THUMBNAIL", FFMPEG_CREATE_THUMBNAIL | ||
) | ||
FFMPEG_CREATE_THUMBNAIL_GPU = getattr( | ||
settings, "FFMPEG_CREATE_THUMBNAIL_GPU", FFMPEG_CREATE_THUMBNAIL_GPU | ||
) | ||
FFMPEG_EXTRACT_SUBTITLE = getattr( | ||
settings, "FFMPEG_EXTRACT_SUBTITLE", FFMPEG_EXTRACT_SUBTITLE | ||
) | ||
|
@@ -304,8 +344,8 @@ def create_output_dir(self): | |
os.makedirs(output_dir) | ||
self.output_dir = output_dir | ||
|
||
def get_mp4_command(self) -> str: | ||
mp4_command = "%s " % FFMPEG_CMD | ||
def get_mp4_command(self, use_gpu: bool = False) -> str: | ||
mp4_command = "%s " % (FFMPEG_CMD_GPU if use_gpu else FFMPEG_CMD) | ||
list_rendition = get_list_rendition() | ||
# remove rendition if encode_mp4 == False | ||
for rend in list_rendition.copy(): | ||
|
@@ -319,14 +359,14 @@ def get_mp4_command(self) -> str: | |
"nb_threads": FFMPEG_NB_THREADS, | ||
} | ||
output_file = os.path.join(self.output_dir, "%sp.mp4" % first_item[0]) | ||
mp4_command += FFMPEG_MP4_ENCODE % { | ||
mp4_command += (FFMPEG_MP4_ENCODE_GPU if use_gpu else FFMPEG_MP4_ENCODE) % { | ||
"cut": self.get_subtime(self.cutting_start, self.cutting_stop), | ||
"map_audio": "-map 0:a:0" if len(self.list_audio_track) > 0 else "", | ||
"libx": FFMPEG_LIBX, | ||
"libx": (FFMPEG_LIBX_GPU if use_gpu else FFMPEG_LIBX), | ||
"height": first_item[0], | ||
"preset": FFMPEG_PRESET, | ||
"preset": (FFMPEG_PRESET_GPU if use_gpu else FFMPEG_PRESET), | ||
"profile": FFMPEG_PROFILE, | ||
"level": FFMPEG_LEVEL, | ||
"level": (FFMPEG_LEVEL_GPU if use_gpu else FFMPEG_LEVEL), | ||
"crf": FFMPEG_CRF, | ||
"maxrate": first_item[1]["maxrate"], | ||
"bufsize": first_item[1]["maxrate"], | ||
|
@@ -348,14 +388,14 @@ def get_mp4_command(self) -> str: | |
) | ||
if in_height >= resolution_threshold: | ||
output_file = os.path.join(self.output_dir, "%sp.mp4" % rend) | ||
mp4_command += FFMPEG_MP4_ENCODE % { | ||
mp4_command += (FFMPEG_MP4_ENCODE_GPU if use_gpu else FFMPEG_MP4_ENCODE) % { | ||
"cut": self.get_subtime(self.cutting_start, self.cutting_stop), | ||
"map_audio": "-map 0:a:0" if len(self.list_audio_track) > 0 else "", | ||
"libx": FFMPEG_LIBX, | ||
"libx": (FFMPEG_LIB_GPU if use_gpu else FFMPEG_LIBX), | ||
"height": min(rend, in_height), | ||
"preset": FFMPEG_PRESET, | ||
"preset": (FFMPEG_PRESET_GPU if use_gpu else FFMPEG_PRESET), | ||
"profile": FFMPEG_PROFILE, | ||
"level": FFMPEG_LEVEL, | ||
"level": (FFMPEG_LEVEL_GPU if use_gpu else FFMPEG_LEVEL), | ||
"crf": FFMPEG_CRF, | ||
"maxrate": list_rendition[rend]["maxrate"], | ||
"bufsize": list_rendition[rend]["maxrate"], | ||
|
@@ -365,19 +405,19 @@ def get_mp4_command(self) -> str: | |
self.list_mp4_files[rend] = output_file | ||
return mp4_command | ||
|
||
def get_hls_command(self) -> str: | ||
hls_command = "%s " % FFMPEG_CMD | ||
def get_hls_command(self, use_gpu: bool = False) -> str: | ||
hls_command = "%s " % (FFMPEG_CMD_GPU if use_gpu else FFMPEG_CMD) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Il manque également la documentation |
||
list_rendition = get_list_rendition() | ||
hls_command += FFMPEG_INPUT % { | ||
"input": self.video_file, | ||
"nb_threads": FFMPEG_NB_THREADS, | ||
} | ||
hls_common_params = FFMPEG_HLS_COMMON_PARAMS % { | ||
hls_common_params = (FFMPEG_HLS_COMMON_PARAMS_GPU if use_gpu else FFMPEG_HLS_COMMON_PARAMS) % { | ||
"cut": self.get_subtime(self.cutting_start, self.cutting_stop), | ||
"libx": FFMPEG_LIBX, | ||
"preset": FFMPEG_PRESET, | ||
"libx": (FFMPEG_LIBX_GPU if use_gpu else FFMPEG_LIBX), | ||
"preset": (FFMPEG_PRESET_GPU if use_gpu else FFMPEG_PRESET), | ||
"profile": FFMPEG_PROFILE, | ||
"level": FFMPEG_LEVEL, | ||
"level": (FFMPEG_LEVEL_GPU if use_gpu else FFMPEG_LEVEL), | ||
"crf": FFMPEG_CRF, | ||
} | ||
hls_command += hls_common_params | ||
|
@@ -389,7 +429,7 @@ def get_hls_command(self) -> str: | |
if in_height >= resolution_threshold or index == 0: | ||
output_file = os.path.join(self.output_dir, "%sp.m3u8" % rend) | ||
hls_command += hls_common_params | ||
hls_command += FFMPEG_HLS_ENCODE_PARAMS % { | ||
hls_command += (FFMPEG_HLS_ENCODE_PARAMS_GPU if use_gpu else FFMPEG_HLS_ENCODE_PARAMS) % { | ||
"height": min(rend, in_height), | ||
"maxrate": list_rendition[rend]["maxrate"], | ||
"bufsize": list_rendition[rend]["maxrate"], | ||
|
@@ -511,20 +551,38 @@ def encode_video_dressing(self): | |
|
||
def encode_video_part(self): | ||
"""Encode the video part of a file.""" | ||
mp4_command = self.get_mp4_command() | ||
return_value, return_msg = launch_cmd(mp4_command) | ||
self.add_encoding_log("mp4_command", mp4_command, return_value, return_msg) | ||
if not return_value: | ||
self.error_encoding = True | ||
def _run_mp4_command(use_gpu: bool = False) -> bool: | ||
mp4_command = self.get_mp4_command(use_gpu=use_gpu) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. manque une petite Pydoc à chaque nouvelle fonction, au format |
||
return_value, return_msg = launch_cmd(mp4_command) | ||
self.add_encoding_log(f"mp4_command{'_gpu' if use_gpu else ''}", mp4_command, return_value, return_msg) | ||
return return_value | ||
return_value = _run_mp4_command(use_gpu=FFMPEG_USE_GPU) | ||
if FFMPEG_USE_GPU: | ||
if not return_value: | ||
if not _run_mp4_command(use_gpu=False): | ||
self.error_encoding = True | ||
else: | ||
if not return_value: | ||
self.error_encoding = True | ||
|
||
if self.duration == 0: | ||
list_rendition = get_list_rendition() | ||
first_item = list_rendition.popitem(last=False) | ||
self.fix_duration(self.list_mp4_files[first_item[0]]) | ||
hls_command = self.get_hls_command() | ||
return_value, return_msg = launch_cmd(hls_command) | ||
if return_value: | ||
self.create_main_livestream() | ||
self.add_encoding_log("hls_command", hls_command, return_value, return_msg) | ||
|
||
def _run_hls_command(use_gpu: bool = False) -> bool: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Documentation manquante |
||
hls_command = self.get_hls_command(use_gpu=use_gpu) | ||
return_value, return_msg = launch_cmd(hls_command) | ||
self.add_encoding_log(f"hls_command{'_gpu' if use_gpu else ''}", hls_command, return_value, return_msg) | ||
return return_value | ||
return_value = _run_hls_command(use_gpu=FFMPEG_USE_GPU) | ||
if FFMPEG_USE_GPU: | ||
if not return_value: | ||
if _run_hls_command(use_gpu=False): | ||
self.create_main_livestream() | ||
else: | ||
if return_value: | ||
self.create_main_livestream() | ||
|
||
def create_main_livestream(self): | ||
list_rendition = get_list_rendition() | ||
|
@@ -605,16 +663,16 @@ def get_extract_thumbnail_command(self) -> str: | |
self.list_thumbnail_files[img] = output_file | ||
return thumbnail_command | ||
|
||
def get_create_thumbnail_command(self) -> str: | ||
thumbnail_command = "%s " % FFMPEG_CMD | ||
def get_create_thumbnail_command(self, use_gpu: bool = False) -> str: | ||
thumbnail_command = "%s " % (FFMPEG_CMD_GPU if use_gpu else FFMPEG_CMD) | ||
first_item = self.get_first_item() | ||
input_file = self.list_mp4_files[first_item[0]] | ||
thumbnail_command += FFMPEG_INPUT % { | ||
"input": input_file, | ||
"nb_threads": FFMPEG_NB_THREADS, | ||
} | ||
output_file = os.path.join(self.output_dir, "thumbnail") | ||
thumbnail_command += FFMPEG_CREATE_THUMBNAIL % { | ||
thumbnail_command += (FFMPEG_CREATE_THUMBNAIL_GPU if use_gpu else FFMPEG_CREATE_THUMBNAIL) % { | ||
"duration": self.duration, | ||
"nb_thumbnail": FFMPEG_NB_THUMBNAIL, | ||
"output": output_file, | ||
|
@@ -707,11 +765,18 @@ def encode_image_part(self): | |
"extract_thumbnail_command", thumbnail_command, return_value, return_msg | ||
) | ||
elif self.is_video(): | ||
thumbnail_command = self.get_create_thumbnail_command() | ||
return_value, return_msg = launch_cmd(thumbnail_command) | ||
self.add_encoding_log( | ||
"create_thumbnail_command", thumbnail_command, return_value, return_msg | ||
) | ||
def _run_thumbnail_command(use_gpu: bool = False) -> bool: | ||
thumbnail_command = self.get_create_thumbnail_command(use_gpu=use_gpu) | ||
return_value, return_msg = launch_cmd(thumbnail_command) | ||
self.add_encoding_log( | ||
f"create_thumbnail_command{'_gpu' if use_gpu else ''}", thumbnail_command, return_value, return_msg | ||
) | ||
return return_value | ||
return_value = _run_thumbnail_command(use_gpu=FFMPEG_USE_GPU) | ||
if FFMPEG_USE_GPU: | ||
if not return_value: | ||
_run_thumbnail_command(use_gpu=False) | ||
|
||
# on ne fait pas d'overview pour les videos de moins de 10 secondes | ||
# (laisser les 10sec inclus pour laisser les tests passer) --> OK | ||
if self.is_video() and self.duration >= 10: | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
# manage setting to encode video with gpu | ||
FFMPEG_USE_GPU = False | ||
FFMPEG_CMD_GPU = "ffmpeg -hwaccel_device 0 -hwaccel_output_format cuda -hwaccel cuda" | ||
FFMPEG_PRESET_GPU = "p6" | ||
FFMPEG_LEVEL_GPU = 0 | ||
|
||
FFMPEG_INPUT_GPU = '-hide_banner -threads %(nb_threads)s -i "%(input)s" ' | ||
|
||
FFMPEG_LIBX_GPU = "h264_nvenc" | ||
FFMPEG_MP4_ENCODE_GPU = ( | ||
'%(cut)s -map 0:v:0 %(map_audio)s -c:v %(libx)s -vf "scale_cuda=-2:%(height)s:interp_algo=bicubic:format=yuv420p" ' | ||
+ "-preset %(preset)s -profile:v %(profile)s " | ||
+ "-level %(level)s " | ||
+ "-forced-idr 1 " | ||
+ "-b:v %(maxrate)s -maxrate %(maxrate)s -bufsize %(bufsize)s -rc vbr -rc-lookahead 20 -bf 1 " | ||
+ '-force_key_frames "expr:gte(t,n_forced*1)" ' | ||
+ '-c:a aac -ar 48000 -b:a %(ba)s -movflags faststart -y -fps_mode passthrough "%(output)s" ' | ||
) | ||
FFMPEG_HLS_COMMON_PARAMS_GPU = ( | ||
"%(cut)s " | ||
+ "-c:v %(libx)s -preset %(preset)s -profile:v %(profile)s " | ||
+ "-level %(level)s " | ||
+ "-forced-idr 1 " | ||
+ '-force_key_frames "expr:gte(t,n_forced*1)" ' | ||
+ "-c:a aac -ar 48000 " | ||
) | ||
FFMPEG_HLS_ENCODE_PARAMS_GPU = ( | ||
'-vf "scale_cuda=-2:%(height)s:interp_algo=bicubic:format=yuv420p" -b:v %(maxrate)s -maxrate %(maxrate)s -bufsize %(bufsize)s -b:a:0 %(ba)s -rc vbr -rc-lookahead 20 -bf 1 ' | ||
+ "-hls_playlist_type vod -hls_time %(hls_time)s -hls_flags single_file " | ||
+ '-master_pl_name "livestream%(height)s.m3u8" ' | ||
+ '-y "%(output)s" ' | ||
) | ||
|
||
FFMPEG_CREATE_THUMBNAIL_GPU = ( | ||
'-vf "select=between(t\,0\,%(duration)s)*eq(pict_type\,PICT_TYPE_I),thumbnail_cuda=2,scale_cuda=-2:720:interp_algo=bicubic:format=yuv420p,hwdownload,format=yuv420p" -frames:v %(nb_thumbnail)s -vsync vfr "%(output)s_%%04d.png"' | ||
) | ||
|
||
#FFMPEG_CREATE_OVERVIEW_GPU = ( | ||
# " -vsync vfr -vf fps=(%(image_count)s/%(duration)s),scale_cuda=%(width)s:%(height)s:interp_algo=bicubic:format=yuv420p,hwdownload,tile=%(image_count)sx1,format=yuv420p -frames:v 1 '%(output)s' " | ||
#) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Il manque la documentation