支持设置视频输出位置

This commit is contained in:
Jerry Yan 2022-05-18 09:30:02 +08:00
parent b1e065d1f9
commit 52317ca39b
2 changed files with 60 additions and 42 deletions

View File

@ -33,6 +33,8 @@ VIDEO_CLIP_OVERFLOW_SEC = 5
BILILIVE_RECORDER_DIRECTORY = "./" BILILIVE_RECORDER_DIRECTORY = "./"
# xigua_dir # xigua_dir
XIGUALIVE_RECORDER_DIRECTORY = "./" XIGUALIVE_RECORDER_DIRECTORY = "./"
# output_dir
VIDEO_OUTPUT_DIR = "./"
def load_config(): def load_config():
@ -65,10 +67,11 @@ def load_config():
FFMPEG_USE_INTEL_GPU = section.getboolean('intel_gpu', FFMPEG_USE_INTEL_GPU) FFMPEG_USE_INTEL_GPU = section.getboolean('intel_gpu', FFMPEG_USE_INTEL_GPU)
VIDEO_BITRATE = section.get('bitrate', VIDEO_BITRATE) VIDEO_BITRATE = section.get('bitrate', VIDEO_BITRATE)
if config.has_section("recorder"): 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'] section = config['recorder']
BILILIVE_RECORDER_DIRECTORY = section.get('bili_dir', BILILIVE_RECORDER_DIRECTORY) BILILIVE_RECORDER_DIRECTORY = section.get('bili_dir', BILILIVE_RECORDER_DIRECTORY)
XIGUALIVE_RECORDER_DIRECTORY = section.get('xigua_dir', XIGUALIVE_RECORDER_DIRECTORY) XIGUALIVE_RECORDER_DIRECTORY = section.get('xigua_dir', XIGUALIVE_RECORDER_DIRECTORY)
VIDEO_OUTPUT_DIR = section.get('output_dir', VIDEO_OUTPUT_DIR)
return True return True
@ -90,6 +93,11 @@ def get_config():
'intel_gpu': FFMPEG_USE_INTEL_GPU, 'intel_gpu': FFMPEG_USE_INTEL_GPU,
'bitrate': VIDEO_BITRATE, 'bitrate': VIDEO_BITRATE,
}, },
'recorder': {
'bili_dir': BILILIVE_RECORDER_DIRECTORY,
'xigua_dir': XIGUALIVE_RECORDER_DIRECTORY,
'output_dir': VIDEO_OUTPUT_DIR,
},
} }
return config return config

View File

@ -12,9 +12,10 @@ from PyQt5 import QtGui
from PyQt5.QtCore import Qt, QThread, pyqtSignal from PyQt5.QtCore import Qt, QThread, pyqtSignal
from PyQt5.QtWidgets import QWidget, QLabel, QApplication, QFrame, QVBoxLayout, QPushButton, \ from PyQt5.QtWidgets import QWidget, QLabel, QApplication, QFrame, QVBoxLayout, QPushButton, \
QSizePolicy, QMessageBox 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, \ 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: class Job:
@ -302,11 +303,17 @@ class WorkerThread(QThread):
def run_danmaku_encode(self, job: Job): def run_danmaku_encode(self, job: Job):
base_danmaku = job.danmaku.pop(0) base_danmaku = job.danmaku.pop(0)
time_shift = 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) new_subtitle_name = danmaku_to_subtitle(base_danmaku, time_shift)
job.subtitles.append(new_subtitle_name) job.subtitles.append(new_subtitle_name)
for danmaku in job.danmaku: 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) new_subtitle_name = danmaku_to_subtitle(danmaku, time_shift)
job.subtitles.append(new_subtitle_name) 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): 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_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): if not (FFMPEG_USE_NVIDIA_GPU and FFMPEG_USE_INTEL_GPU):
print("[!]Not Enabled Both GPU") print("[!]Not Enabled Both GPU")
self.encode_video_with_subtitles(orig_filename, subtitles, new_filename) self.encode_video_with_subtitles(orig_filename, subtitles, new_fullpath)
return [new_filename] return [new_fullpath]
duration = self.get_video_real_duration(orig_filename) _duration_str = self.get_video_real_duration(orig_filename)
print("[>]Duration:", duration) duration = duration_str_to_float(_duration_str)
if duration > (VIDEO_CLIP_EACH_SEC * 5): if duration > (VIDEO_CLIP_EACH_SEC * 5):
# qsv 压制前2段剩余交由nvenc压制 # qsv 压制前2段剩余交由nvenc压制
_slices = int(duration / VIDEO_CLIP_EACH_SEC) _slices = int(duration / VIDEO_CLIP_EACH_SEC)
new_filename0 = base_ts_to_filename(base_ts + (_slices - 1) * 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_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") print("[+]Use Intel QSV Acceleration")
encode_process0 = subprocess.Popen([ encode_process0 = subprocess.Popen([
FFMPEG_EXEC, "-hide_banner", "-progress", "-", "-loglevel", "error", "-y", FFMPEG_EXEC, "-hide_banner", "-progress", "-", "-loglevel", "error", "-y",
"-hwaccel", "qsv", "-ss", str((_slices - 1) * VIDEO_CLIP_EACH_SEC), "-hwaccel", "qsv", "-ss", str((_slices - 1) * VIDEO_CLIP_EACH_SEC),
"-copyts", "-i", orig_filename, "-vf", "-copyts", "-i", orig_filename, "-vf",
",".join("subtitles=%s" % i for i in subtitles), ",".join("subtitles=%s" % i for i in subtitles),
"-c:a", "copy", "-c:v", "h264_qsv", "-ss", str((_slices - 1) * VIDEO_CLIP_EACH_SEC), "-c:a", "copy", "-c:v", "h264_qsv",
"-f", "mp4", "-preset:v", "fast", "-profile:v", "high", "-level", "4.1", "-f", "mp4", "-b:v", VIDEO_BITRATE, "-rc:v", "vbr", "-tune:v", "hq",
"-b:v", VIDEO_BITRATE, "-rc:v", "vbr", "-tune:v", "hq", *_common_ffmpeg_params(),
"-qmin", "10", "-qmax", "32", "-crf", "16",
"-fflags", "+genpts", "-shortest", "-movflags", "faststart",
# "-t", "10", # "-t", "10",
new_filename0 new_fullpath0
], **subprocess_args(True)) ], **subprocess_args(True))
print("[+]Use Nvidia NvEnc Acceleration") print("[+]Use Nvidia NvEnc Acceleration")
encode_process1 = subprocess.Popen([ encode_process1 = subprocess.Popen([
FFMPEG_EXEC, "-hide_banner", "-progress", "-", "-loglevel", "error", "-y", 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", "-i", orig_filename, "-vf",
",".join("subtitles=%s" % i for i in subtitles), ",".join("subtitles=%s" % i for i in subtitles),
"-c:a", "copy", "-c:v", "h264_nvenc", "-c:a", "copy", "-c:v", "h264_nvenc", "-ss", str(VIDEO_CLIP_EACH_SEC * 2),
"-f", "mp4", "-preset:v", "fast", "-profile:v", "high", "-level", "4.1", "-f", "mp4", "-b:v", VIDEO_BITRATE, "-rc:v", "vbr", "-tune:v", "hq",
"-b:v", VIDEO_BITRATE, "-rc:v", "vbr", "-tune:v", "hq", *_common_ffmpeg_params(),
"-qmin", "10", "-qmax", "32", "-crf", "16",
"-fflags", "+genpts", "-shortest", "-movflags", "faststart",
# "-t", "10", # "-t", "10",
new_filename1 new_fullpath1
], **subprocess_args(True)) ], **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_process0.wait()
encode_process1.wait() encode_process1.wait()
return [new_filename0, new_filename1] return [new_filename0, new_filename1]
@ -429,42 +433,40 @@ class WorkerThread(QThread):
_slices = int(duration / VIDEO_CLIP_EACH_SEC) _slices = int(duration / VIDEO_CLIP_EACH_SEC)
new_filename0 = base_ts_to_filename(base_ts + _slices * VIDEO_CLIP_EACH_SEC, True) new_filename0 = base_ts_to_filename(base_ts + _slices * VIDEO_CLIP_EACH_SEC, True)
new_filename1 = base_ts_to_filename(base_ts) 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") print("[+]Use Intel QSV Acceleration")
encode_process0 = subprocess.Popen([ encode_process0 = subprocess.Popen([
FFMPEG_EXEC, "-hide_banner", "-progress", "-", "-loglevel", "error", "-y", FFMPEG_EXEC, "-hide_banner", "-progress", "-", "-loglevel", "error", "-y",
"-hwaccel", "qsv", "-ss", str(_slices * VIDEO_CLIP_EACH_SEC), "-hwaccel", "qsv", "-ss", str(_slices * VIDEO_CLIP_EACH_SEC),
"-copyts", "-i", orig_filename, "-vf", "-copyts", "-i", orig_filename, "-vf",
",".join("subtitles=%s" % i for i in subtitles), ",".join("subtitles=%s" % i for i in subtitles),
"-c:a", "copy", "-c:v", "h264_qsv", "-ss", str(_slices * VIDEO_CLIP_EACH_SEC), "-c:a", "copy", "-c:v", "h264_qsv",
"-f", "mp4", "-preset:v", "fast", "-profile:v", "high", "-level", "4.1", "-f", "mp4", "-b:v", VIDEO_BITRATE, "-rc:v", "vbr", "-tune:v", "hq",
"-b:v", VIDEO_BITRATE, "-rc:v", "vbr", "-tune:v", "hq", *_common_ffmpeg_params(),
"-qmin", "10", "-qmax", "32", "-crf", "16",
"-fflags", "+genpts", "-shortest", "-movflags", "faststart",
# "-t", "10", # "-t", "10",
new_filename0 new_fullpath0
], **subprocess_args(True)) ], **subprocess_args(True))
print("[+]Use Nvidia NvEnc Acceleration") print("[+]Use Nvidia NvEnc Acceleration")
encode_process1 = subprocess.Popen([ encode_process1 = subprocess.Popen([
FFMPEG_EXEC, "-hide_banner", "-progress", "-", "-loglevel", "error", "-y", 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", "-i", orig_filename, "-vf",
",".join("subtitles=%s" % i for i in subtitles), ",".join("subtitles=%s" % i for i in subtitles),
"-c:a", "copy", "-c:v", "h264_nvenc", "-c:a", "copy", "-c:v", "h264_nvenc", "-ss", str(VIDEO_CLIP_EACH_SEC),
"-f", "mp4", "-preset:v", "fast", "-profile:v", "high", "-level", "4.1", "-f", "mp4", "-b:v", VIDEO_BITRATE, "-rc:v", "vbr", "-tune:v", "hq",
"-b:v", VIDEO_BITRATE, "-rc:v", "vbr", "-tune:v", "hq", *_common_ffmpeg_params(),
"-qmin", "10", "-qmax", "32", "-crf", "16",
"-fflags", "+genpts", "-shortest", "-movflags", "faststart",
# "-t", "10", # "-t", "10",
new_filename1 new_fullpath1
], **subprocess_args(True)) ], **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_process1.wait()
encode_process0.wait()
return [new_filename1] return [new_filename1]
else: else:
self.encode_video_with_subtitles(orig_filename, subtitles, new_filename) print("[-]VideoClip to short,", duration)
return [new_filename] print("[-]Fallback to normal")
self.encode_video_with_subtitles(orig_filename, subtitles, new_fullpath)
return [new_fullpath]
def quick_split_video(self, file): def quick_split_video(self, file):
if not os.path.isfile(file): if not os.path.isfile(file):
@ -648,6 +650,14 @@ def check_all_prerequisite():
exit(1) 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(): def main():
check_all_prerequisite() check_all_prerequisite()
app = QApplication(sys.argv) app = QApplication(sys.argv)