如何用FFmpeg将MP4文件分割为大小均等的多个小文件
如何用FFmpeg将MP4文件分割为大小均等的多个小文件
我完全懂你遇到的糟心事——用segment按固定时间分割MP4时,要么因为录制时帧率波动大,要么因为视频内容复杂度忽高忽低,导致每个片段的体积差得离谱,有的甚至能差25倍。这时候按文件大小分割才是更靠谱的方案,你尝试的脚本思路找对了,我来帮你梳理完整的实现和使用细节:
一、按文件大小分割的Shell脚本
这个脚本会先计算原视频的比特率,再根据你设定的单片段大小反推近似分割时长,最后循环调用FFmpeg完成分割,能最大程度保证每个片段的体积接近你设定的上限:
#!/bin/sh # Short script to split videos by filesize using ffmpeg by LukeLR if [ $# -ne 3 ]; then echo 'Illegal number of parameters. Needs 3 parameters:' echo 'Usage:' echo './split-video.sh FILE SIZELIMIT "FFMPEG_ARGS"' echo echo 'Parameters:' echo ' - FILE: Name of the video file to split' echo ' - SIZELIMIT: Maximum file size of each part (in bytes)' echo ' - FFMPEG_ARGS: Additional arguments to pass to each ffmpeg-call' echo ' (video format and quality options etc.)' exit 1 fi FILE="$1" SIZELIMIT="$2" FFMPEG_ARGS="$3" # 获取原视频总时长 DURATION=$(ffmpeg -i "$FILE" 2>&1 | grep -oE 'Duration: [0-9:.]+' | cut -d ' ' -f 2 | tr -d ,) # 将时长转换为总秒数 HOURS=$(echo "$DURATION" | cut -d ':' -f 1) MINUTES=$(echo "$DURATION" | cut -d ':' -f 2) SECONDS=$(echo "$DURATION" | cut -d ':' -f 3) TOTAL_SECONDS=$(echo "$HOURS*3600 + $MINUTES*60 + $SECONDS" | bc) # 计算原视频的近似比特率 FILESIZE=$(stat -c%s "$FILE") BITRATE=$(echo "$FILESIZE * 8 / $TOTAL_SECONDS" | bc) # 反推每个片段的近似时长 SEGMENT_DURATION=$(echo "$SIZELIMIT * 8 / $BITRATE" | bc) # 循环分割视频 START_TIME=0 PART=1 while [ $START_TIME -lt $TOTAL_SECONDS ]; do ffmpeg -ss "$START_TIME" -t "$SEGMENT_DURATION" -i "$FILE" $FFMPEG_ARGS "part_$(printf "%03d" $PART).mp4" START_TIME=$(echo "$START_TIME + $SEGMENT_DURATION" | bc) PART=$((PART + 1)) done
二、脚本使用步骤
- 保存并授权:把上面的代码存为
split-video.sh,然后给脚本加上执行权限:chmod +x split-video.sh - 参数说明:
FILE:要分割的源MP4文件路径,比如你的../data/2024-06-02_12-34-51.mp4SIZELIMIT:每个片段的最大字节数,比如要每个片段约50MB,就换算成50*1024*1024=52428800FFMPEG_ARGS:FFmpeg的编码/封装参数,如果你想跳过重新编码(节省时间),直接用-c copy -map 0就行
- 示例命令:
比如把你的源视频分割成每个50MB的片段,且保留原编码格式:./split-video.sh ../data/2024-06-02_12-34-51.mp4 52428800 "-c copy -map 0"
三、小提醒
- 因为视频关键帧的限制,实际分割后的片段大小可能会有小幅误差(不会差太多),如果追求极致精准,需要先给视频重新编码并插入均匀的关键帧,但会增加耗时。
- 如果你用的是macOS,脚本里的
stat -c%s "$FILE"要改成stat -f%z "$FILE",不然获取不到文件大小。 - 如果设定的
SIZELIMIT超过原视频总大小,脚本只会生成一个完整的片段。
备注:内容来源于stack exchange,提问作者GBPU
相关产品推荐
相关产品推荐

