如何自动化ffmpeg分割和合并视频的各个部分,并保持音频同步?

问题描述 投票:0回答:1

我有一个 Python 脚本,可以自动将大视频(2 小时)修剪成较小的片段,然后将它们连接起来,而无需重新编码,以保持过程快速。该脚本运行这些 ffmpeg 命令:

import subprocess

# Extract chunks
segments = [(0, 300), (300, 600), (600, 900)]  # example segments in seconds
for i, (start, length) in enumerate(segments):
    subprocess.run([
        "ffmpeg", "-i", "input.mp4", "-ss", str(start), "-t", str(length),
        "-c", "copy", "-reset_timestamps", "1", "-y", f"chunk_{i}.mp4"
    ], check=True)

# Create concat list
with open("list.txt", "w") as f:
    for i in range(len(segments)):
        f.write(f"file 'chunk_{i}.mp4'\n")

# Concatenate
subprocess.run([
    "ffmpeg", "-f", "concat", "-safe", "0",
    "-i", "list.txt", "-c", "copy", "-y", "merged_output.mp4"
], check=True)

所有块都来自相同的源视频,具有相同的编解码器、分辨率和比特率。尽管如此,最终的 merged_output.mp4 有时会出现音频不同步的情况,尤其是在第一个块之后。

我尝试过在 -i 之前使用 -ss 来剪切关键帧,但问题仍然存在。

问题:当通过 ffmpeg 以编程方式分段和合并而不完全重新编码时,如何确保最终连接视频中的正确 A/V 同步?有没有办法调整 ffmpeg 命令或流程以避免音频不同步?

python video ffmpeg
1个回答
0
投票

解决办法是使用mkvmerge,然后复制回mp4

import subprocess
import os

# Define the segments as (start, end) in seconds
segments = [(0, 300), (300, 600), (600, 900)]  # Example segments in seconds
input_file = "input.mp4"
base_name = os.path.splitext(input_file)[0]

# Directory for temporary chunks
temp_dir = "./temp_chunks"
os.makedirs(temp_dir, exist_ok=True)

# Split the input file into chunks using mkvmerge
split_parts = ",".join(f"{start}-{end}" for start, end in segments)
split_file = os.path.join(temp_dir, f"{base_name}_split.mkv")

print(f"Running mkvmerge to split into parts: {split_parts}")
subprocess.run([
    "mkvmerge", "-o", split_file, "--split", f"parts:{split_parts}", input_file
], check=True)

# Check if the split parts exist
part_files = sorted([
    os.path.join(temp_dir, f)
    for f in os.listdir(temp_dir)
    if f.startswith(f"{base_name}_split-") and f.endswith(".mkv")
])

if not part_files:
    print("No split parts found. Exiting.")
    exit(1)

# Merge the parts using mkvmerge
merged_file = f"{base_name}_merged.mkv"
merge_cmd = ["mkvmerge", "-o", merged_file]
merge_cmd.extend(part_files)

print(f"Merging files: {part_files}")
subprocess.run(merge_cmd, check=True)

# Convert the merged MKV file to MP4 using ffmpeg
output_file = f"{base_name}_processed.mp4"
print(f"Converting merged file to MP4: {output_file}")
subprocess.run([
    "ffmpeg", "-i", merged_file, "-c", "copy", "-y", output_file
], check=True)

# Cleanup temporary files
for f in part_files:
    os.remove(f)
os.rmdir(temp_dir)

print(f"Processed video saved to {output_file}")
© www.soinside.com 2019 - 2024. All rights reserved.