FFmpegとPythonスクリプトを使って、「すべての無音カット&結合」を自動で実行する手順を備忘録として残しておく
1. 入力ファイルの音量ログ「detect.log」を作成する
ffmpeg -i "input.mp4" -af silencedetect=n=-20dB:d=1.0 -f null - 2> detect.log
上記の引数である無音扱いとする音量の閾値「-20dB」や、無音範囲の秒数「1.0」は適宜調整する
2. 音量ログ「detect.log」をもとに、ファイルをトリミングする「trim_slience.py」を作成する
import re
import subprocess
LOG_FILE = "detect.log"
INPUT_FILE = "input.mp4"
OUTPUT_FILE = "input_trimed.mp4"
# ログを解析し、無音区間を抽出する関数
def parse_silence_log(log_file):
with open(log_file, 'r') as f:
log_data = f.read()
# silence_start と silence_end の時間を抽出する正規表現
start_matches = re.findall(r'silence_start: (\d+\.?\d*)', log_data)
end_matches = re.findall(r'silence_end: (\d+\.?\d*)', log_data)
silence_intervals = []
# startとendのリストの短い方に合わせて処理
for start, end in zip(start_matches, end_matches):
silence_intervals.append((float(start), float(end)))
return silence_intervals
# 非無音区間(残す部分)のリストを生成する関数
def get_non_silence_intervals(silence_intervals, total_duration):
non_silence_intervals = []
current_time = 0.0
for start, end in silence_intervals:
# 現在の時間から無音開始までが、残すべき「音あり」区間
if start > current_time:
non_silence_intervals.append((current_time, start))
# 次の「音あり」区間の開始時間を、無音終了時間にする
current_time = end
# 最後の無音終了時間から動画の最後までも「音あり」区間として追加
if current_time < total_duration:
non_silence_intervals.append((current_time, total_duration))
return non_silence_intervals
# 動画の総時間を取得する関数 (FFprobeを使用)
def get_total_duration(input_file):
# FFprobeで duration のメタデータを取得
cmd = [
'ffprobe', '-v', 'error', '-show_entries', 'format=duration',
'-of', 'default=noprint_wrappers=1:nokey=1', input_file
]
try:
result = subprocess.run(cmd, capture_output=True, text=True, check=True)
return float(result.stdout.strip())
except Exception as e:
print(f"Error getting duration: {e}")
return None
# メイン処理
if __name__ == "__main__":
total_duration = get_total_duration(INPUT_FILE)
if total_duration is None:
exit(1)
silence_intervals = parse_silence_log(LOG_FILE)
non_silence_intervals = get_non_silence_intervals(silence_intervals, total_duration)
if not non_silence_intervals:
print("No non-silent intervals found. Exiting.")
exit(0)
# 結合・カット処理を行うFFmpegコマンドを生成 (select/concatフィルター)
# 複数の区間を結合するための select フィルターの式を生成
select_filters = []
for start, end in non_silence_intervals:
# 'between(t,開始,終了)' を使って、指定区間を選択
select_filters.append(f"between(t,{start},{end})")
# 全ての区間をORで結合
select_expr = '+'.join(select_filters)
# 最終的なFFmpegコマンド
final_command = [
'ffmpeg', '-i', INPUT_FILE,
'-filter_complex', f'[0:v]select=\'{select_expr}\',setpts=N/FRAME_RATE/TB[v];[0:a]aselect=\'{select_expr}\',asetpts=N/SR/TB[a]',
'-map', '[v]', '-map', '[a]',
'-c:v', 'libx264', '-crf', '23', '-preset', 'fast',
'-c:a', 'aac', '-b:a', '192k',
OUTPUT_FILE
]
print("--- 実行するFFmpegコマンド ---")
print(" ".join(final_command))
print("--------------------------")
# 結合コマンドの実行
print("Starting trimming and concatenation...")
try:
subprocess.run(final_command, check=True)
print(f"\n✅ Success! Output saved to: {OUTPUT_FILE}")
except subprocess.CalledProcessError as e:
print(f"\n❌ FFmpeg command failed with error: {e}")
3. 実行する
python trim_slience.py
完了すると無音箇所がカットされて結合されたファイルinput_trim.mp4が作成される