From e15a9d947bc12841362c06389aad79f6fe925a36 Mon Sep 17 00:00:00 2001 From: imeepos Date: Mon, 9 Feb 2026 15:49:50 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=20ffmpeg=20=E5=90=88?= =?UTF-8?q?=E5=B9=B6=E8=A7=86=E9=A2=91=20=E5=B0=BA=E5=AF=B8=E4=B8=8D?= =?UTF-8?q?=E5=AF=B9=E6=9C=89=E9=BB=91=E8=BE=B9=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BowongModalFunctions/utils/VideoUtils.py | 68 +++++++++++++++----- 1 file changed, 53 insertions(+), 15 deletions(-) diff --git a/src/BowongModalFunctions/utils/VideoUtils.py b/src/BowongModalFunctions/utils/VideoUtils.py index 7a09ed2..1b563d0 100644 --- a/src/BowongModalFunctions/utils/VideoUtils.py +++ b/src/BowongModalFunctions/utils/VideoUtils.py @@ -514,6 +514,26 @@ class VideoUtils: total_videos = len(media_paths) if total_videos == 0: raise ValueError("没有可以合并的视频源") + + # 自动检测所有视频的宽高和音频流,找出最大值 + max_width = 0 + max_height = 0 + has_audio = [] + for media_path in media_paths: + width, height = await VideoUtils.ffprobe_video_size_async(media_path) + max_width = max(max_width, width) + max_height = max(max_height, height) + # 检查是否有音频流 + metadata = VideoUtils.ffprobe_media_metadata(media_path) + audio_exists = any(stream.codec_type == "audio" for stream in metadata.streams) + has_audio.append(audio_exists) + logger.info(f"{media_path} - 音频流: {'存在' if audio_exists else '不存在'}") + + # 使用检测到的最大宽高作为目标尺寸 + target_width = max_width + target_height = max_height + logger.info(f"检测到最大分辨率: {target_width}x{target_height}") + if not output_path: output_path = FileUtils.file_path_extend(media_paths[0], "concat") os.makedirs(os.path.dirname(output_path), exist_ok=True) @@ -523,18 +543,22 @@ class VideoUtils: ffmpeg_cmd.input(input_path) # 2. 统一所有视频的格式、分辨率和帧率 for i in range(total_videos): - filter_complex.extend( - [ - # 先缩放到统一分辨率,然后设置帧率和格式 - f"[{i}:v]scale={target_width}:{target_height}:force_original_aspect_ratio=decrease," - f"pad={target_width}:{target_height}:(ow-iw)/2:(oh-ih)/2," - f"setsar=1:1," # 新增强制设置SAR - f"fps=30,format=yuv420p[v{i}]", - # 修改音频过滤器,确保输出为AAC兼容格式 - # f"[{i}:a]aformat=sample_fmts=fltp:sample_rates=44100:channel_layouts=stereo[a{i}]", - f"[{i}:a]aformat=sample_fmts=s16:sample_rates=44100:channel_layouts=stereo[a{i}]", - ] + # 视频流处理 + filter_complex.append( + f"[{i}:v]scale={target_width}:{target_height}:force_original_aspect_ratio=increase," + f"crop={target_width}:{target_height}," + f"setsar=1:1," + f"fps=30,format=yuv420p[v{i}]" ) + # 音频流处理:如果有音频则使用原音频,否则生成静默音频 + if has_audio[i]: + filter_complex.append( + f"[{i}:a]aformat=sample_fmts=s16:sample_rates=44100:channel_layouts=stereo[a{i}]" + ) + else: + filter_complex.append( + f"anullsrc=channel_layout=stereo:sample_rate=44100[a{i}]" + ) # 3. 准备处理后的视频流和音频流的连接字符串 video_streams = "".join(f"[v{i}]" for i in range(total_videos)) audio_streams = "".join(f"[a{i}]" for i in range(total_videos)) @@ -930,6 +954,20 @@ class VideoUtils: total_videos = len(media_paths) if total_videos == 0: raise ValueError("没有可以合并的视频源") + + # 自动检测所有视频的宽高,找出最大值 + max_width = 0 + max_height = 0 + for media_path in media_paths: + width, height = await VideoUtils.ffprobe_video_size_async(media_path) + max_width = max(max_width, width) + max_height = max(max_height, height) + + # 使用检测到的最大宽高作为目标尺寸 + target_width = max_width + target_height = max_height + logger.info(f"检测到最大分辨率: {target_width}x{target_height}") + if not output_path: output_path = FileUtils.file_path_extend(media_paths[0], "concat_video_only") os.makedirs(os.path.dirname(output_path), exist_ok=True) @@ -940,10 +978,10 @@ class VideoUtils: # 2. 统一所有视频的格式、分辨率和帧率(仅处理视频流) for i in range(total_videos): filter_complex.append( - # 先缩放到统一分辨率,然后设置帧率和格式 - f"[{i}:v]scale={target_width}:{target_height}:force_original_aspect_ratio=decrease," - f"pad={target_width}:{target_height}:(ow-iw)/2:(oh-ih)/2," - f"setsar=1:1," # 强制设置SAR + # 放大到目标尺寸并裁剪,保持不变形 + f"[{i}:v]scale={target_width}:{target_height}:force_original_aspect_ratio=increase," + f"crop={target_width}:{target_height}," + f"setsar=1:1," f"fps=30,format=yuv420p[v{i}]" )