From dd359ccbdfd23ce56ddbdda69311f5e426a77bb4 Mon Sep 17 00:00:00 2001 From: "kyj@bowong.ai" Date: Thu, 24 Apr 2025 19:19:50 +0800 Subject: [PATCH] =?UTF-8?q?FIX=20=E5=AF=B9=E5=85=B6=E9=9F=B3=E8=A7=86?= =?UTF-8?q?=E9=A2=91=E9=95=BF=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nodes/video.py | 91 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 68 insertions(+), 23 deletions(-) diff --git a/nodes/video.py b/nodes/video.py index 9a89d61..79f3009 100644 --- a/nodes/video.py +++ b/nodes/video.py @@ -260,35 +260,80 @@ class VideoChangeFPS: CATEGORY = "不忘科技-自定义节点🚩/视频" + def get_media_duration(self, input_file, stream_type="v"): + """获取视频或音频的精确时长(秒)""" + cmd = [ + "ffprobe", "-v", "error", + "-select_streams", f"{stream_type}:0", + "-show_entries", "stream=duration", + "-of", "csv=p=0", + input_file + ] + return float(subprocess.check_output(cmd).decode().strip()) + + def adjust_video_fps(self, input_video, output_temp, target_fps): + """仅调整视频FPS,输出临时文件""" + ff = ffmpy.FFmpeg( + inputs={input_video: None}, + outputs={ + output_temp: f"-y -vf fps={target_fps} -c:v libx264 -c:a aac" + } + ) + print("调整FPS命令:", ff.cmd) + with open("user/ffmpeg.txt", "a") as log: + log.write("\n----" + f"{datetime.now()}----\n" + ff.cmd + "\n========\n") + with open("user/ffmpeg.txt", "a") as log: + ff.run(stdout=log, stderr=log) + + def align_audio_to_video(self, input_video, output_final): + """将音频精确对齐到视频长度""" + video_duration = self.get_media_duration(input_video, "v") + audio_duration = self.get_media_duration(input_video, "a") + print("video_duration:", video_duration, "audio_duration:", audio_duration) + + # 动态选择补静音或剪切 + filter_audio = ( + f"atrim=end={video_duration},asetpts=PTS-STARTPTS" + if audio_duration > video_duration + else f"apad=whole_dur={video_duration},asetpts=PTS-STARTPTS" + ) + + ff = ffmpy.FFmpeg( + inputs={input_video: None}, + outputs={ + output_final: f""" -y + -filter_complex " + [0:v]copy[v]; + [0:a]{filter_audio}[a] + " + -map "[v]" -map "[a]" + -c:v libx264 -c:a aac + """ + } + ) + print("对齐音频命令:", ff.cmd) + with open("user/ffmpeg.txt", "a") as log: + log.write("\n----" + f"{datetime.now()}----\n" + ff.cmd + "\n========\n") + with open("user/ffmpeg.txt", "a") as log: + ff.run(stdout=log, stderr=log) + def changeFps(self, video_path, fps): try: if not (video_path.startswith("/") or video_path.startswith("output/") or video_path[1] == ":"): video_path = "output/" + video_path loguru.logger.info("Processing video: %s" % video_path) + output_temp = ".".join([video_path.split(".")[-2] + "-%dfps-temp" % fps, video_path.split(".")[-1]]) output = ".".join([video_path.split(".")[-2]+"-%dfps" % fps,video_path.split(".")[-1]]) - ff = ffmpy.FFmpeg( - inputs={video_path: ["-loglevel", "info","-y"]}, - outputs={ - output: [ - "-vf", - "fps=%d" % fps, - "-c:v", - "libx264", - "-crf", - "16", - "-preset", - "slow", - "-threads", - "12", - "-c:a", - "copy", - ] - }) - print(ff.cmd) - with open("user/ffmpeg.txt", "a") as log: - log.write("\n----"+f"{datetime.now()}----\n"+ff.cmd+"\n========\n") - with open("user/ffmpeg.txt", "a") as log: - ff.run(stdout=log, stderr=log) + # 分步执行 + self.adjust_video_fps(video_path, output_temp, fps) # 第一步:调整FPS + self.align_audio_to_video(output_temp, output) # 第二步:对齐音频 + + # 校验结果 + final_video_dur = self.get_media_duration(output, "v") + final_audio_dur = self.get_media_duration(output, "a") + print("video_duration:", final_video_dur, "audio_duration:", final_audio_dur) + assert abs(final_video_dur - final_audio_dur) < 0.01, "音视频长度未对齐!" + loguru.logger.success(f"处理成功!视频长度: {final_video_dur:.3f}s, 音频长度: {final_audio_dur:.3f}s") return (output,) except: traceback.print_exc()