支持设置视频输出位置
This commit is contained in:
parent
b1e065d1f9
commit
52317ca39b
10
config.py
10
config.py
@ -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
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user