原脚本

#! /bin/bash
ffmpeg -f concat -safe 0 -i f.txt -c copy out.mp4

当使用ffmpeg的concat方式合并视频出现声音异常或画面跳动时,通常是由于源视频的编码参数不一致导致的(如帧率、分辨率、音频采样率等不同)。直接使用-c copy进行流复制会保留原始编码,当参数不匹配时就会出现播放异常。

解决方法是先统一所有视频的编码参数,再进行合并,具体步骤如下:

  1. 首先将所有视频转换为相同编码格式(推荐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
# 对所有视频执行相同操作
  1. 然后创建新的文件列表(如temp.txt),包含转换后的临时文件:
echo "file 'temp1.mp4'" > temp.txt
echo "file 'temp2.mp4'" >> temp.txt
# 添加所有转换后的文件
  1. 最后使用转换后的文件进行合并:
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
    

标签: none

添加新评论