From dcf5f5630d2bd899dbc3cfb9a491766af382f84b Mon Sep 17 00:00:00 2001 From: Jerry Yan <792602257@qq.com> Date: Thu, 6 Mar 2025 21:37:17 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E4=B8=BB=E5=8A=A8=E5=88=A4=E6=96=AD?= =?UTF-8?q?=E6=98=AF=E5=90=A6=E6=9C=89=E9=9F=B3=E9=A2=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- biz/ffmpeg.py | 1 - entity/ffmpeg.py | 14 ++++++++------ util/ffmpeg.py | 29 +++++++++++++++++++++++++++-- 3 files changed, 35 insertions(+), 9 deletions(-) diff --git a/biz/ffmpeg.py b/biz/ffmpeg.py index f6da84d..ee7d89f 100644 --- a/biz/ffmpeg.py +++ b/biz/ffmpeg.py @@ -45,7 +45,6 @@ def parse_ffmpeg_task(task_info, template_info): output_file = "out_" + str(time.time()) + ".mp4" task = FfmpegTask(tasks, output_file=output_file) overall = template_info.get("overall_template") - task.mute = False task.center_cut = template_info.get("crop_mode", None) task.frame_rate = template_info.get("frame_rate", 25) if overall.get('source', ''): diff --git a/entity/ffmpeg.py b/entity/ffmpeg.py index 0331702..cfea092 100644 --- a/entity/ffmpeg.py +++ b/entity/ffmpeg.py @@ -167,6 +167,7 @@ class FfmpegTask(object): output_args.append("1") video_output_str = "[0:v]" audio_output_str = "" + audio_track_index = 0 effect_index = 0 for input_file in self.input_file: input_args.append("-i") @@ -242,19 +243,18 @@ class FfmpegTask(object): input_index = input_args.count("-i") input_args += MUTE_AUDIO_INPUT filter_args.append(f"[{input_index}:a]acopy[a]") + audio_track_index += 1 audio_output_str = "[a]" else: audio_output_str = "[0:a]" + audio_track_index += 1 for audio in self.audios: input_index = input_args.count("-i") input_args.append("-i") input_args.append(audio.replace("\\", "/")) - if audio_output_str == "": - filter_args.append(f"[{input_index}:a]acopy[a]") - audio_output_str = "[a]" - else: - filter_args.append(f"{audio_output_str}[{input_index}:a]amix[a]") - audio_output_str = "[a]" + audio_track_index += 1 + filter_args.append(f"{audio_output_str}[{input_index}:a]amix[a]") + audio_output_str = "[a]" if audio_output_str: output_args.append("-map") output_args.append(audio_output_str) @@ -276,6 +276,8 @@ class FfmpegTask(object): elif isinstance(input_file, FfmpegTask): f.write("file '" + input_file.get_output_file() + "'\n") input_args += ["-f", "concat", "-safe", "0", "-i", _tmp_file] + from util.ffmpeg import probe_video_audio + self.mute = not probe_video_audio(_tmp_file, "concat") output_args.append("-map") output_args.append("0:v") output_args.append("-c:v") diff --git a/util/ffmpeg.py b/util/ffmpeg.py index 9c537d0..579c12a 100644 --- a/util/ffmpeg.py +++ b/util/ffmpeg.py @@ -16,8 +16,12 @@ def to_annexb(file): if not os.path.exists(file): return file logger.info("ToAnnexb: %s", file) - ffmpeg_process = subprocess.run(["ffmpeg", "-y", "-hide_banner", "-i", file, "-c", "copy", "-bsf:v", "h264_mp4toannexb", - "-f", "mpegts", file+".ts"]) + ffmpeg_process = subprocess.run(["ffmpeg", "-y", "-hide_banner", "-i", file, + "-f", "lavfi", "-i", "anullsrc=cl=stereo:r=48000", + "-map", "0:v", "-map", "1:a", + "-c:v", "copy", "-bsf:v", "h264_mp4toannexb", + "-c:a", "aac", "-b:a", "128k", "-ar", "48000", "-ac", "2", + "-f", "mpegts", file+".ts"]) span.set_attribute("ffmpeg.args", json.dumps(ffmpeg_process.args)) logger.info("ToAnnexb: %s, returned: %s", file, ffmpeg_process.returncode) span.set_attribute("ffmpeg.code", ffmpeg_process.returncode) @@ -128,6 +132,27 @@ def probe_video_info(video_file): return int(width), int(height), float(duration) +def probe_video_audio(video_file, type=None): + tracer = get_tracer(__name__) + with tracer.start_as_current_span("probe_video_audio") as span: + span.set_attribute("video.file", video_file) + args = ["ffprobe", "-hide_banner", "-v", "error", "-select_streams", "a", "-show_entries", "stream=index", "-of", "csv=p=0"] + if type == 'concat': + args.append("-safe") + args.append("0") + args.append("-f") + args.append("concat") + args.append(video_file) + result = subprocess.run(args, stderr=subprocess.STDOUT, **subprocess_args(True)) + span.set_attribute("ffprobe.args", json.dumps(result.args)) + span.set_attribute("ffprobe.code", result.returncode) + logger.info("probe_video_audio: %s", result.stdout.decode('utf-8').strip()) + if result.returncode != 0: + return False + if result.stdout.decode('utf-8').strip() == '': + return False + return True + # Create a set of arguments which make a ``subprocess.Popen`` (and # variants) call work with or without Pyinstaller, ``--noconsole`` or # not, on Windows and Linux. Typical use:: From cf43e6d54915f54660d961aed58821d57ed22bfa Mon Sep 17 00:00:00 2001 From: Jerry Yan <792602257@qq.com> Date: Mon, 10 Mar 2025 10:13:30 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E4=BF=AE=E5=A4=8Damix=E9=99=8D=E4=BD=8E?= =?UTF-8?q?=E5=A3=B0=E9=9F=B3=E7=9A=84=E9=97=AE=E9=A2=98=EF=BC=8C=E4=BF=AE?= =?UTF-8?q?=E5=A4=8Dreencode=5Fto=5Fannexb=E4=B8=8D=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E9=9F=B3=E8=BD=A8=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- entity/ffmpeg.py | 4 ++-- util/ffmpeg.py | 15 ++++++++++----- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/entity/ffmpeg.py b/entity/ffmpeg.py index cfea092..3558ad2 100644 --- a/entity/ffmpeg.py +++ b/entity/ffmpeg.py @@ -253,7 +253,7 @@ class FfmpegTask(object): input_args.append("-i") input_args.append(audio.replace("\\", "/")) audio_track_index += 1 - filter_args.append(f"{audio_output_str}[{input_index}:a]amix[a]") + filter_args.append(f"{audio_output_str}[{input_index}:a]amix=duration=shortest:dropout_transition=0:normalize=0[a]") audio_output_str = "[a]" if audio_output_str: output_args.append("-map") @@ -295,7 +295,7 @@ class FfmpegTask(object): input_args.append("-i") input_args.append(audio.replace("\\", "/")) audio_track_index += 1 - filter_args.append(f"{audio_output_str}[{input_index}:a]amix[a]") + filter_args.append(f"{audio_output_str}[{input_index}:a]amix=duration=shortest:dropout_transition=0:normalize=0[a]") audio_output_str = "[a]" if audio_output_str: output_args.append("-map") diff --git a/util/ffmpeg.py b/util/ffmpeg.py index 579c12a..dd3179b 100644 --- a/util/ffmpeg.py +++ b/util/ffmpeg.py @@ -5,7 +5,7 @@ import subprocess from datetime import datetime from typing import Optional, IO -from entity.ffmpeg import FfmpegTask, ENCODER_ARGS, VIDEO_ARGS, AUDIO_ARGS +from entity.ffmpeg import FfmpegTask, ENCODER_ARGS, VIDEO_ARGS, AUDIO_ARGS, MUTE_AUDIO_INPUT from telemetry import get_tracer logger = logging.getLogger(__name__) @@ -17,9 +17,9 @@ def to_annexb(file): return file logger.info("ToAnnexb: %s", file) ffmpeg_process = subprocess.run(["ffmpeg", "-y", "-hide_banner", "-i", file, - "-f", "lavfi", "-i", "anullsrc=cl=stereo:r=48000", + *MUTE_AUDIO_INPUT, "-map", "0:v", "-map", "1:a", - "-c:v", "copy", "-bsf:v", "h264_mp4toannexb", + "-c:v", "copy", "-bsf:v", "h264_mp4toannexb", "-shortest", "-c:a", "aac", "-b:a", "128k", "-ar", "48000", "-ac", "2", "-f", "mpegts", file+".ts"]) span.set_attribute("ffmpeg.args", json.dumps(ffmpeg_process.args)) @@ -38,8 +38,13 @@ def re_encode_and_annexb(file): if not os.path.exists(file): return file logger.info("ReEncodeAndAnnexb: %s", file) - ffmpeg_process = subprocess.run(["ffmpeg", "-y", "-hide_banner", "-i", file, *VIDEO_ARGS, *AUDIO_ARGS, *ENCODER_ARGS, "-bsf:v", "h264_mp4toannexb", - "-f", "mpegts", file +".ts"]) + ffmpeg_process = subprocess.run(["ffmpeg", "-y", "-hide_banner", "-i", file, + *MUTE_AUDIO_INPUT, + "-map", "0:v", "-map", "1:a", + *VIDEO_ARGS, "-bsf:v", "h264_mp4toannexb", + *AUDIO_ARGS, "-bsf:a", "setts=pts=DTS", + *ENCODER_ARGS, "-shortest", + "-f", "mpegts", file + ".ts"]) span.set_attribute("ffmpeg.args", json.dumps(ffmpeg_process.args)) logger.info("ReEncodeAndAnnexb: %s, returned: %s", file, ffmpeg_process.returncode) span.set_attribute("ffmpeg.code", ffmpeg_process.returncode) From 744fe28421e866ee5083b9908e226323019930c9 Mon Sep 17 00:00:00 2001 From: Jerry Yan <792602257@qq.com> Date: Mon, 10 Mar 2025 15:07:36 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=B1=85=E4=B8=AD?= =?UTF-8?q?=E5=88=87=E5=89=B2=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- entity/ffmpeg.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/entity/ffmpeg.py b/entity/ffmpeg.py index 3558ad2..d296647 100644 --- a/entity/ffmpeg.py +++ b/entity/ffmpeg.py @@ -181,7 +181,7 @@ class FfmpegTask(object): _v_w = pos_json.get('imgWidth', 1) _f_x = pos_json.get('ltX', 0) _f_x2 = pos_json.get('rbX', 0) - _x = f'{float((_f_x2 - _f_x)/(2 * _v_w)) :.4f}*iw' + _x = f'{float((_f_x2 + _f_x)/(2 * _v_w)) :.4f}*iw-ih*ih/(2*iw)' filter_args.append(f"{video_output_str}crop=x={_x}:y=0:w=ih*ih/iw:h=ih[v_cut{effect_index}]") video_output_str = f"[v_cut{effect_index}]" effect_index += 1