ffmpeg合并多个视频出现声音和画面异常跳动,声音静音等的解决方法
原脚本
#! /bin/bash
ffmpeg -f concat -safe 0 -i f.txt -c copy out.mp4当使用ffmpeg的concat方式合并视频出现声音异常或画面跳动时,通常是由于源视频的编码参数不一致导致的(如帧率、分辨率、音频采样率等不同)。直接使用-c copy进行流复制会保留原始编码,当参数不匹配时就会出现播放异常。
解决方法是先统一所有视频的编码参数,再进行合并,具体步骤如下:
- 首先将所有视频转换为相同编码格式(推荐H.264视频和AAC音频):
# 转换单个视频示例
ffmpeg -i input1.mp4 -c:v libx264 -c:a aac -strict experimental -y temp1.mp4
ffmpeg -i input2.mp4 -c:v libx264 -c:a aac -strict experimental -y temp2.mp4
# 对所有视频执行相同操作- 然后创建新的文件列表(如
temp.txt),包含转换后的临时文件:
echo "file 'temp1.mp4'" > temp.txt
echo "file 'temp2.mp4'" >> temp.txt
# 添加所有转换后的文件- 最后使用转换后的文件进行合并:
ffmpeg -f concat -safe 0 -i temp.txt -c copy output.mp4这种方法通过先统一编码参数,再进行无损合并,可以解决大部分由于源文件参数不一致导致的音视频同步问题。如果问题仍然存在,可能需要在合并时不使用-c copy,让ffmpeg重新编码一次:
ffmpeg -f concat -safe 0 -i temp.txt -c:v libx264 -c:a aac -strict experimental output.mp4转换过程可能需要一些时间,具体取决于视频数量和大小,但能保证合并后的视频播放正常。
实际运用时,可能还会出现各个视频都使用了不同的编码、音轨导致异常,这里经过了大量的修复版本后,得到最终的版本:
完整脚本:
#!/bin/bash
# 视频合并脚本(调整质量与文件大小)
# 功能:平衡质量与文件大小,避免过度压缩
# ==============================================
# 1. 初始化与参数配置(重点调整CRF值控制压缩率)
# ==============================================
rm -rf temp_converted
rm -f temp_list.txt merged_output.mp4
mkdir -p temp_converted
# 关键参数调整(影响文件大小的核心设置)
CRF_VALUE="18" # 降低CRF值(范围0-51,值越小质量越高/文件越大)
# 建议值:18-23(18接近无损,23平衡,28更高压缩)
FRAME_RATE="30"
KEYFRAME_INTERVAL="60"
VIDEO_RES="1080x1920"
AUDIO_BITRATE="192k" # 适当提高音频码率(从128k→192k)
AUDIO_SAMPLERATE="48000"
AUDIO_CHANNELS="1"
OUTPUT_FILE="merged_output.mp4"
# ==============================================
# 2. 检查MP4文件
# ==============================================
mp4_files=$(ls *.mp4 2>/dev/null | sort -V)
if [ -z "$mp4_files" ]; then
echo -e "\033[31m[!] 未找到MP4文件!\033[0m"
exit 1
fi
file_count=$(echo "$mp4_files" | wc -l)
echo -e "\033[32m[+] 找到 $file_count 个文件\033[0m"
# ==============================================
# 3. 批量转换(使用调整后的质量参数)
# ==============================================
count=1
for file in $mp4_files; do
echo -e "\033[34m[*] [进度 $count/$file_count] 处理:$file\033[0m"
ffmpeg -hide_banner -loglevel error \
-i "$file" \
-map 0:v:0 -map 0:a:0 \
-sn -dn \
-c:v libx264 -crf $CRF_VALUE -preset medium \
-r "$FRAME_RATE" \
-g "$KEYFRAME_INTERVAL" \
-sc_threshold 0 \
-s "$VIDEO_RES" \
-c:a aac -b:a "$AUDIO_BITRATE" \
-ar "$AUDIO_SAMPLERATE" \
-ac "$AUDIO_CHANNELS" \
-async 1000 \
-vsync cfr \
-y "temp_converted/temp_$count.mp4"
if [ $? -ne 0 ]; then
echo -e "\033[31m[!] 处理失败:$file\033[0m"
exit 1
fi
((count++))
done
# ==============================================
# 4. 生成合并列表与合并
# ==============================================
echo -e "\n\033[34m[*] 生成合并列表...\033[0m"
for ((i=1; i<count; i++)); do
echo "file 'temp_converted/temp_$i.mp4'" >> temp_list.txt
done
echo -e "\n\033[34m[*] 合并视频...\033[0m"
ffmpeg -hide_banner -loglevel error \
-f concat -safe 0 -i temp_list.txt \
-c:v libx264 -crf $CRF_VALUE -preset medium \
-c:a aac -b:a "$AUDIO_BITRATE" \
-ar "$AUDIO_SAMPLERATE" \
-ac "$AUDIO_CHANNELS" \
-async 1000 \
-vsync cfr \
-y "$OUTPUT_FILE"
# ==============================================
# 5. 结果提示
# ==============================================
if [ $? -eq 0 ] && [ -f "$OUTPUT_FILE" ]; then
file_size=$(du -sh "$OUTPUT_FILE" | awk '{print $1}')
echo -e "\n\033[32m[+] 合并完成!\033[0m"
echo -e "文件:$(pwd)/$OUTPUT_FILE"
echo -e "大小:$file_size"
else
echo -e "\033[31m[!] 合并失败\033[0m"
exit 1
fi
版权属于:Joyber
本文链接:https://blog.qqvbc.com/default/1339.html
转载时须注明出处及本声明