From 52317ca39b8f65e02fd5475fe94e7f7db6d19c76 Mon Sep 17 00:00:00 2001 From: Jerry Yan <792602257@qq.com> Date: Wed, 18 May 2022 09:30:02 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E6=8C=81=E8=AE=BE=E7=BD=AE=E8=A7=86?= =?UTF-8?q?=E9=A2=91=E8=BE=93=E5=87=BA=E4=BD=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config.py | 10 ++++- danmaku_workflow.py | 92 +++++++++++++++++++++++++-------------------- 2 files changed, 60 insertions(+), 42 deletions(-) diff --git a/config.py b/config.py index 93e6d8d..c1f3a7d 100644 --- a/config.py +++ b/config.py @@ -33,6 +33,8 @@ VIDEO_CLIP_OVERFLOW_SEC = 5 BILILIVE_RECORDER_DIRECTORY = "./" # xigua_dir XIGUALIVE_RECORDER_DIRECTORY = "./" +# output_dir +VIDEO_OUTPUT_DIR = "./" def load_config(): @@ -65,10 +67,11 @@ def load_config(): FFMPEG_USE_INTEL_GPU = section.getboolean('intel_gpu', FFMPEG_USE_INTEL_GPU) VIDEO_BITRATE = section.get('bitrate', VIDEO_BITRATE) if config.has_section("recorder"): - global BILILIVE_RECORDER_DIRECTORY, XIGUALIVE_RECORDER_DIRECTORY + global BILILIVE_RECORDER_DIRECTORY, XIGUALIVE_RECORDER_DIRECTORY, VIDEO_OUTPUT_DIR section = config['recorder'] BILILIVE_RECORDER_DIRECTORY = section.get('bili_dir', BILILIVE_RECORDER_DIRECTORY) XIGUALIVE_RECORDER_DIRECTORY = section.get('xigua_dir', XIGUALIVE_RECORDER_DIRECTORY) + VIDEO_OUTPUT_DIR = section.get('output_dir', VIDEO_OUTPUT_DIR) return True @@ -90,6 +93,11 @@ def get_config(): 'intel_gpu': FFMPEG_USE_INTEL_GPU, 'bitrate': VIDEO_BITRATE, }, + 'recorder': { + 'bili_dir': BILILIVE_RECORDER_DIRECTORY, + 'xigua_dir': XIGUALIVE_RECORDER_DIRECTORY, + 'output_dir': VIDEO_OUTPUT_DIR, + }, } return config diff --git a/danmaku_workflow.py b/danmaku_workflow.py index a59fcc6..6c7d67f 100644 --- a/danmaku_workflow.py +++ b/danmaku_workflow.py @@ -12,9 +12,10 @@ from PyQt5 import QtGui from PyQt5.QtCore import Qt, QThread, pyqtSignal from PyQt5.QtWidgets import QWidget, QLabel, QApplication, QFrame, QVBoxLayout, QPushButton, \ QSizePolicy, QMessageBox -from danmaku_xml_helper import get_file_start, diff_danmaku_files +from danmaku_xml_helper import get_file_start, diff_danmaku_files, NoDanmakuException from config import load_config, FFMPEG_EXEC, DANMAKU_FACTORY_EXEC, FFMPEG_USE_INTEL_GPU, FFMPEG_USE_NVIDIA_GPU, \ - VIDEO_BITRATE, VIDEO_CLIP_EACH_SEC, VIDEO_CLIP_OVERFLOW_SEC, VIDEO_RESOLUTION, DANMAKU_SPEED, DEFAULT_FONT_NAME + VIDEO_BITRATE, VIDEO_CLIP_EACH_SEC, VIDEO_CLIP_OVERFLOW_SEC, VIDEO_RESOLUTION, DANMAKU_SPEED, DEFAULT_FONT_NAME, \ + VIDEO_OUTPUT_DIR class Job: @@ -302,11 +303,17 @@ class WorkerThread(QThread): def run_danmaku_encode(self, job: Job): base_danmaku = job.danmaku.pop(0) time_shift = 0 - base_start_ts = get_file_start(base_danmaku) + try: + base_start_ts = get_file_start(base_danmaku) + except NoDanmakuException: + return new_subtitle_name = danmaku_to_subtitle(base_danmaku, time_shift) job.subtitles.append(new_subtitle_name) for danmaku in job.danmaku: - time_shift = diff_danmaku_files(base_danmaku, danmaku) + try: + time_shift = diff_danmaku_files(base_danmaku, danmaku) + except NoDanmakuException: + continue new_subtitle_name = danmaku_to_subtitle(danmaku, time_shift) job.subtitles.append(new_subtitle_name) # 压制 @@ -380,47 +387,44 @@ class WorkerThread(QThread): def multi_gpu_encode_video_with_subtitles(self, 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") - self.encode_video_with_subtitles(orig_filename, subtitles, new_filename) - return [new_filename] - duration = self.get_video_real_duration(orig_filename) - print("[>]Duration:", duration) + self.encode_video_with_subtitles(orig_filename, subtitles, new_fullpath) + return [new_fullpath] + _duration_str = self.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, "-hide_banner", "-progress", "-", "-loglevel", "error", "-y", "-hwaccel", "qsv", "-ss", str((_slices - 1) * 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 - 1) * VIDEO_CLIP_EACH_SEC), - "-f", "mp4", "-preset:v", "fast", "-profile:v", "high", "-level", "4.1", - "-b:v", VIDEO_BITRATE, "-rc:v", "vbr", "-tune:v", "hq", - "-qmin", "10", "-qmax", "32", "-crf", "16", - "-fflags", "+genpts", "-shortest", "-movflags", "faststart", + "-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_filename0 + new_fullpath0 ], **subprocess_args(True)) print("[+]Use Nvidia NvEnc Acceleration") encode_process1 = subprocess.Popen([ FFMPEG_EXEC, "-hide_banner", "-progress", "-", "-loglevel", "error", "-y", - "-t", str((_slices - 1) * VIDEO_CLIP_EACH_SEC + (VIDEO_CLIP_OVERFLOW_SEC * 0.5)), + "-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", "-preset:v", "fast", "-profile:v", "high", "-level", "4.1", - "-b:v", VIDEO_BITRATE, "-rc:v", "vbr", "-tune:v", "hq", - "-qmin", "10", "-qmax", "32", "-crf", "16", - "-fflags", "+genpts", "-shortest", "-movflags", "faststart", + "-c:a", "copy", "-c:v", "h264_nvenc", "-ss", str(VIDEO_CLIP_EACH_SEC * 2), + "-f", "mp4", "-b:v", VIDEO_BITRATE, "-rc:v", "vbr", "-tune:v", "hq", + *_common_ffmpeg_params(), # "-t", "10", - new_filename1 + new_fullpath1 ], **subprocess_args(True)) - threading.Thread(target=self.handle_ffmpeg_output, args=(encode_process0.stdout, True,)).start() - threading.Thread(target=self.handle_ffmpeg_output, args=(encode_process1.stdout,)).start() encode_process0.wait() encode_process1.wait() return [new_filename0, new_filename1] @@ -429,42 +433,40 @@ class WorkerThread(QThread): _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, "-hide_banner", "-progress", "-", "-loglevel", "error", "-y", "-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", "-preset:v", "fast", "-profile:v", "high", "-level", "4.1", - "-b:v", VIDEO_BITRATE, "-rc:v", "vbr", "-tune:v", "hq", - "-qmin", "10", "-qmax", "32", "-crf", "16", - "-fflags", "+genpts", "-shortest", "-movflags", "faststart", + "-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_filename0 + new_fullpath0 ], **subprocess_args(True)) print("[+]Use Nvidia NvEnc Acceleration") encode_process1 = subprocess.Popen([ FFMPEG_EXEC, "-hide_banner", "-progress", "-", "-loglevel", "error", "-y", - "-t", str(_slices * VIDEO_CLIP_EACH_SEC + VIDEO_CLIP_OVERFLOW_SEC * 0.5), + "-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", "-preset:v", "fast", "-profile:v", "high", "-level", "4.1", - "-b:v", VIDEO_BITRATE, "-rc:v", "vbr", "-tune:v", "hq", - "-qmin", "10", "-qmax", "32", "-crf", "16", - "-fflags", "+genpts", "-shortest", "-movflags", "faststart", + "-c:a", "copy", "-c:v", "h264_nvenc", "-ss", str(VIDEO_CLIP_EACH_SEC), + "-f", "mp4", "-b:v", VIDEO_BITRATE, "-rc:v", "vbr", "-tune:v", "hq", + *_common_ffmpeg_params(), # "-t", "10", - new_filename1 + new_fullpath1 ], **subprocess_args(True)) - threading.Thread(target=self.handle_ffmpeg_output, args=(encode_process0.stdout, True,)).start() - threading.Thread(target=self.handle_ffmpeg_output, args=(encode_process1.stdout,)).start() - encode_process0.wait() encode_process1.wait() + encode_process0.wait() return [new_filename1] else: - self.encode_video_with_subtitles(orig_filename, subtitles, new_filename) - return [new_filename] + print("[-]VideoClip to short,", duration) + print("[-]Fallback to normal") + self.encode_video_with_subtitles(orig_filename, subtitles, new_fullpath) + return [new_fullpath] def quick_split_video(self, file): if not os.path.isfile(file): @@ -648,6 +650,14 @@ def check_all_prerequisite(): exit(1) +def _common_ffmpeg_params(): + return ( + "-preset:v", "fast", "-profile:v", "high", "-level", "4.1", + "-qmin", "10", "-qmax", "48", "-crf", "26", + "-fflags", "+genpts", "-shortest" + ) + + def main(): check_all_prerequisite() app = QApplication(sys.argv)