diff --git a/workflow/video.py b/workflow/video.py index 4f97bb4..958e276 100644 --- a/workflow/video.py +++ b/workflow/video.py @@ -24,151 +24,108 @@ def get_video_real_duration(filename): def multi_gpu_encode_video_with_subtitles(orig_filename: str, subtitles: list[str], base_ts: float): - new_filename = base_ts_to_filename(base_ts) - new_fullpath = os.path.join(VIDEO_OUTPUT_DIR, new_filename) - if not (FFMPEG_USE_NVIDIA_GPU and FFMPEG_USE_INTEL_GPU): - print("[!]Not Enabled Both GPU") - encode_video_with_subtitles(orig_filename, subtitles, new_fullpath) - return [new_fullpath] _duration_str = get_video_real_duration(orig_filename) duration = duration_str_to_float(_duration_str) - if duration > (VIDEO_CLIP_EACH_SEC * 5): - # qsv 压制前2段,剩余交由nvenc压制 - _slices = int(duration / VIDEO_CLIP_EACH_SEC) - new_filename0 = base_ts_to_filename(base_ts + (_slices - 1) * VIDEO_CLIP_EACH_SEC) - new_filename1 = base_ts_to_filename(base_ts) - new_fullpath0 = os.path.join(VIDEO_OUTPUT_DIR, new_filename0) - new_fullpath1 = os.path.join(VIDEO_OUTPUT_DIR, new_filename1) - print("[+]Use Intel QSV Acceleration") - encode_process0 = subprocess.Popen([ - FFMPEG_EXEC, *_common_ffmpeg_setting(), - "-hwaccel", "qsv", "-ss", str((_slices - 1) * VIDEO_CLIP_EACH_SEC), - "-copyts", "-i", orig_filename, "-vf", - ",".join("subtitles=%s" % i for i in subtitles), - "-ss", str((_slices - 1) * VIDEO_CLIP_EACH_SEC), - "-c:a", "copy", "-c:v", "h264_qsv", - "-f", "mp4", "-b:v", VIDEO_BITRATE, "-rc:v", "vbr", "-tune:v", "hq", - *_common_ffmpeg_params(), - # "-t", "10", - new_fullpath0 - ]) - print("[+]Use Nvidia NvEnc Acceleration") - encode_process1 = subprocess.Popen([ - FFMPEG_EXEC, *_common_ffmpeg_setting(), - "-t", str((_slices - 1) * VIDEO_CLIP_EACH_SEC + (VIDEO_CLIP_OVERFLOW_SEC * 0.8)), - "-i", orig_filename, "-vf", - ",".join("subtitles=%s" % i for i in subtitles), - "-c:a", "copy", "-c:v", "h264_nvenc", - "-f", "mp4", "-b:v", VIDEO_BITRATE, "-rc:v", "vbr", "-tune:v", "hq", - *_common_ffmpeg_params(), - # "-t", "10", - new_fullpath1 - ]) - encode_process0.wait() - encode_process1.wait() - return [new_filename0, new_filename1] - elif duration > (VIDEO_CLIP_EACH_SEC * 3): - # 至少也要能切2片,才用双GPU加速 - _slices = int(duration / VIDEO_CLIP_EACH_SEC) - new_filename0 = base_ts_to_filename(base_ts + _slices * VIDEO_CLIP_EACH_SEC, True) - new_filename1 = base_ts_to_filename(base_ts) - new_fullpath0 = os.path.join(VIDEO_OUTPUT_DIR, new_filename0) - new_fullpath1 = os.path.join(VIDEO_OUTPUT_DIR, new_filename1) - print("[+]Use Intel QSV Acceleration") - encode_process0 = subprocess.Popen([ - FFMPEG_EXEC, *_common_ffmpeg_setting(), - "-hwaccel", "qsv", "-ss", str(_slices * VIDEO_CLIP_EACH_SEC), - "-copyts", "-i", orig_filename, "-vf", - ",".join("subtitles=%s" % i for i in subtitles), - "-c:a", "copy", "-c:v", "h264_qsv", - "-ss", str(_slices * VIDEO_CLIP_EACH_SEC), - "-f", "mp4", "-b:v", VIDEO_BITRATE, "-rc:v", "vbr", "-tune:v", "hq", - *_common_ffmpeg_params(), - # "-t", "10", - new_fullpath0 - ]) - print("[+]Use Nvidia NvEnc Acceleration") - encode_process1 = subprocess.Popen([ - FFMPEG_EXEC, *_common_ffmpeg_setting(), - "-t", str(_slices * VIDEO_CLIP_EACH_SEC + (VIDEO_CLIP_OVERFLOW_SEC * 0.8)), - "-i", orig_filename, "-vf", - ",".join("subtitles=%s" % i for i in subtitles), - "-c:a", "copy", "-c:v", "h264_nvenc", - "-f", "mp4", "-b:v", VIDEO_BITRATE, "-rc:v", "vbr", "-tune:v", "hq", - *_common_ffmpeg_params(), - # "-t", "10", - new_fullpath1 - ]) - encode_process1.wait() - encode_process0.wait() - return [new_filename1] - else: - print("[-]VideoClip to short,", duration) - print("[-]Fallback to normal") - encode_video_with_subtitles(orig_filename, subtitles, new_fullpath) - return [new_fullpath] - - -def encode_video_with_subtitles(orig_filename: str, subtitles: list[str], new_filename: str): - if FFMPEG_USE_NVIDIA_GPU: - print("[+]Use Nvidia NvEnc Acceleration") - encode_process = subprocess.Popen([ - FFMPEG_EXEC, *_common_ffmpeg_setting(), - "-i", orig_filename, "-vf", - ",".join("subtitles=%s" % i for i in subtitles) + ",hwupload_cuda", - "-c:a", "copy", "-c:v", "h264_nvenc", - "-f", "mp4", "-b:v", VIDEO_BITRATE, "-rc:v", "vbr", "-tune:v", "hq", - *_common_ffmpeg_params(), - # "-t", "10", - new_filename - ], stdout=subprocess.PIPE) - elif FFMPEG_USE_INTEL_GPU: - if platform.system().lower() == "windows": - print("[+]Use Intel QSV Acceleration") - encode_process = subprocess.Popen([ - FFMPEG_EXEC, *_common_ffmpeg_setting(), - "-hwaccel", "qsv", "-i", orig_filename, "-vf", - ",".join("subtitles=%s" % i for i in subtitles), - "-c:a", "copy", "-c:v", "h264_qsv", - "-f", "mp4", "-b:v", VIDEO_BITRATE, "-rc:v", "vbr", "-tune:v", "hq", - *_common_ffmpeg_params(), - # "-t", "10", - new_filename - ], stdout=subprocess.PIPE) + current_sec = 0 + while current_sec < duration: + if (current_sec + VIDEO_CLIP_OVERFLOW_SEC * 2) > duration: + print("[-]Less than 2 overflow sec, skip") + break + new_filename = base_ts_to_filename(base_ts + current_sec, True) + new_fullpath = os.path.join(VIDEO_OUTPUT_DIR, new_filename) + print("CUR_FN", new_filename, "BIAS_T", current_sec) + if FFMPEG_USE_NVIDIA_GPU: + process = get_encode_process_use_nvenc(orig_filename, subtitles, new_fullpath, + current_sec, VIDEO_CLIP_EACH_SEC + VIDEO_CLIP_OVERFLOW_SEC) + elif FFMPEG_USE_INTEL_GPU: + process = get_encode_process_use_intel(orig_filename, subtitles, new_fullpath, + current_sec, VIDEO_CLIP_EACH_SEC + VIDEO_CLIP_OVERFLOW_SEC) else: - print("[+]Use Intel VAAPI Acceleration") - encode_process = subprocess.Popen([ - FFMPEG_EXEC, *_common_ffmpeg_setting(), - "-hwaccel", "vaapi", "-i", orig_filename, "-vf", - ",".join("subtitles=%s" % i for i in subtitles) + ",hwupload", - "-c:a", "copy", "-c:v", "h264_vaapi", - "-f", "mp4", "-b:v", VIDEO_BITRATE, "-rc:v", "vbr", "-tune:v", "hq", - *_common_ffmpeg_params(), - # "-t", "10", - new_filename - ], stdout=subprocess.PIPE) - else: - print("[+]Use CPU Encode") + process = get_encode_process_use_cpu(orig_filename, subtitles, new_fullpath, + current_sec, VIDEO_CLIP_EACH_SEC + VIDEO_CLIP_OVERFLOW_SEC) + handle_ffmpeg_output(process.stdout) + process.wait() + current_sec += VIDEO_CLIP_EACH_SEC + + +def get_encode_process_use_nvenc(orig_filename: str, subtitles: list[str], new_filename: str, + skip: float = 0, duration: float = 0): + print("[+]Use Nvidia NvEnc Acceleration") + encode_process = subprocess.Popen([ + FFMPEG_EXEC, *_common_ffmpeg_setting(), + "-ss", str(skip), "-copyts", "-t", str(duration), + "-i", orig_filename, "-vf", + ",".join("subtitles=%s" % i for i in subtitles) + ",hwupload_cuda", + "-ss", str(skip), + "-c:a", "copy", "-c:v", "h264_nvenc", + "-f", "mp4", "-b:v", VIDEO_BITRATE, "-rc:v", "vbr", "-tune:v", "hq", + *_common_ffmpeg_params(), + # "-t", "10", + new_filename + ], stdout=subprocess.PIPE) + return encode_process + + +def get_encode_process_use_intel(orig_filename: str, subtitles: list[str], new_filename: str, + skip: float = 0, duration: float = 0): + if platform.system().lower() == "windows": + print("[+]Use Intel QSV Acceleration") encode_process = subprocess.Popen([ FFMPEG_EXEC, *_common_ffmpeg_setting(), - "-i", orig_filename, "-vf", + "-ss", str(skip), "-copyts", "-t", str(duration), + "-hwaccel", "qsv", "-i", orig_filename, "-vf", ",".join("subtitles=%s" % i for i in subtitles), - "-c:a", "copy", "-c:v", "h264", - "-f", "mp4", "-b:v", VIDEO_BITRATE, + "-ss", str(skip), + "-c:a", "copy", "-c:v", "h264_qsv", + "-f", "mp4", "-b:v", VIDEO_BITRATE, "-rc:v", "vbr", "-tune:v", "hq", *_common_ffmpeg_params(), # "-t", "10", new_filename ], stdout=subprocess.PIPE) - handle_ffmpeg_output(encode_process.stdout) - return encode_process.wait() + else: + print("[+]Use Intel VAAPI Acceleration") + encode_process = subprocess.Popen([ + FFMPEG_EXEC, *_common_ffmpeg_setting(), + "-ss", str(skip), "-copyts", "-t", str(duration), + "-hwaccel", "vaapi", "-i", orig_filename, "-vf", + ",".join("subtitles=%s" % i for i in subtitles) + ",hwupload", + "-ss", str(skip), + "-c:a", "copy", "-c:v", "h264_vaapi", + "-f", "mp4", "-b:v", VIDEO_BITRATE, "-rc:v", "vbr", "-tune:v", "hq", + *_common_ffmpeg_params(), + # "-t", "10", + new_filename + ], stdout=subprocess.PIPE) + return encode_process -def handle_ffmpeg_output(stderr: IO[bytes]) -> str: +def get_encode_process_use_cpu(orig_filename: str, subtitles: list[str], new_filename: str, + skip: float = 0, duration: float = 0): + print("[+]Use CPU Encode") + encode_process = subprocess.Popen([ + FFMPEG_EXEC, *_common_ffmpeg_setting(), + "-ss", str(skip), "-copyts", "-t", str(duration), + "-i", orig_filename, "-vf", + ",".join("subtitles=%s" % i for i in subtitles), + "-ss", str(skip), + "-c:a", "copy", "-c:v", "h264", + "-f", "mp4", "-b:v", VIDEO_BITRATE, + *_common_ffmpeg_params(), + # "-t", "10", + new_filename + ], stdout=subprocess.PIPE) + return encode_process + + +def handle_ffmpeg_output(stdout: IO[bytes]) -> str: out_time = "0:0:0.0" speed = "0" + if stdout is None: + print("[!]STDOUT is null") + return out_time _i = 0 while True: - line = stderr.readline() + line = stdout.readline() if line == b"": break if line.strip() == b"progress=end": @@ -221,7 +178,7 @@ def quick_split_video(file): def _common_ffmpeg_setting(): return ( - "-y", "-hide_banner", "-progress", "-", "-loglevel", "error", + "-y", "-hide_banner", "-progress", "-", "-loglevel", "error", "-sub_charenc", "UTF-8" ) diff --git a/workflow/worker.py b/workflow/worker.py index 076af7e..edd2914 100644 --- a/workflow/worker.py +++ b/workflow/worker.py @@ -2,7 +2,7 @@ import os.path from exception.danmaku import DanmakuException from workflow.danmaku import get_file_start, diff_danmaku_files, danmaku_to_subtitle -from workflow.video import multi_gpu_encode_video_with_subtitles, quick_split_video +from workflow.video import multi_gpu_encode_video_with_subtitles def do_workflow(video_file, danmaku_base_file, *danmaku_files): @@ -26,7 +26,7 @@ def do_workflow(video_file, danmaku_base_file, *danmaku_files): print("弹幕文件", danmaku_file, "异常") continue print(result) - file_need_split = multi_gpu_encode_video_with_subtitles(video_file, result, start_ts) + multi_gpu_encode_video_with_subtitles(video_file, result, start_ts) # clean files for file in result: if os.path.isfile(file):