使用 ffmpeg 按大小分割视频文件 [关闭]
Posted
技术标签:
【中文标题】使用 ffmpeg 按大小分割视频文件 [关闭]【英文标题】:Using ffmpeg to split video files by size [closed] 【发布时间】:2016-11-10 14:28:02 【问题描述】:我正在尝试使用 ffmpeg 编写一个批处理文件,以自动执行多余的日常任务,即从以 4gb 块(这是大多数 DSLR 相机和 GoPro 的标准)记录的工作中获取素材,并将剪辑分割成 2gb 文件流媒体目的。这个想法是让脚本检查外部驱动器 FOOTAGE 的文件夹 @import 并在 2gb 之后拆分文件(因为最大大小为 4gb,这将减少多次拆分的需要)。
我也在尝试修改拆分文件的文件名,因此 FILE1 为 4gb,它拆分为 FILE1_1 和 FILE1_2,分别为 2gb。我所尝试的一切都只是将原始文件复制到两个新的相同文件中 - 没有拆分或任何东西。
在进行了一些谷歌搜索并阅读了此处的一些答案后,我找到了这篇文章,但它基于持续时间,而不是大小(以不同质量水平录制视频片段使这毫无意义):Split into equal parts and convert many mp4 videos using ffmpeg
有人可以帮我解决这个问题吗?我没有遇到任何可用的解决方案,使用我理解的方法,使用 -fs limit_size,我真的很想了解它是如何工作的。
更新:也发现了这个,但它已经四年没有更新了,我没有看到任何关于拆分的内容会被证明有帮助:
https://github.com/kcm1700/VideoSplitter/blob/master/
【问题讨论】:
【参考方案1】:我也遇到了同样的问题,在这里没有找到解决方案后,我为该工作编写了一个快速的 bash 脚本。
特点:
使用 ffmpeg 的-fs
-flag 来限制文件大小
检查生成的视频部分的长度并计算下一部分的开始位置
列举视频部分
根据需要继续处理尽可能多的部分以包含整个源文件。
允许自定义 ffmpeg 参数也可以一次性降低分辨率和质量。
它只需要三个参数:源文件名、每个部分所需的文件大小和 ffmpeg 所需的参数。
将文件拆分为 64MB 部分的示例调用:
./split-video.sh huge-video.mov 64000000 "-c:v libx264 -crf 23 -c:a copy -vf scale=960:-1"
最后是脚本的源码:
#!/bin/bash
# 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 of the source video
DURATION=$(ffprobe -i "$FILE" -show_entries format=duration -v quiet -of default=noprint_wrappers=1:nokey=1|cut -d. -f1)
# Duration that has been encoded so far
CUR_DURATION=0
# Filename of the source video (without extension)
BASENAME="$FILE%.*"
# Extension for the video parts
#EXTENSION="$FILE##*."
EXTENSION="mp4"
# Number of the current video part
i=1
# Filename of the next video part
NEXTFILENAME="$BASENAME-$i.$EXTENSION"
echo "Duration of source video: $DURATION"
# Until the duration of all partial videos has reached the duration of the source video
while [[ $CUR_DURATION -lt $DURATION ]]; do
# Encode next part
echo ffmpeg -i "$FILE" -ss "$CUR_DURATION" -fs "$SIZELIMIT" $FFMPEG_ARGS "$NEXTFILENAME"
ffmpeg -ss "$CUR_DURATION" -i "$FILE" -fs "$SIZELIMIT" $FFMPEG_ARGS "$NEXTFILENAME"
# Duration of the new part
NEW_DURATION=$(ffprobe -i "$NEXTFILENAME" -show_entries format=duration -v quiet -of default=noprint_wrappers=1:nokey=1|cut -d. -f1)
# Total duration encoded so far
CUR_DURATION=$((CUR_DURATION + NEW_DURATION))
i=$((i + 1))
echo "Duration of $NEXTFILENAME: $NEW_DURATION"
echo "Part No. $i starts at $CUR_DURATION"
NEXTFILENAME="$BASENAME-$i.$EXTENSION"
done
希望,这会有所帮助:)
【讨论】:
我可以知道您提供的此解决方案是否会降低块的视频质量? ffmpeg 菜鸟在这里 这完全取决于您传递的FFMPEG_ARGS
(第三个参数)。如果你什么都不传递,ffmpeg 会根据你的输出容器自动选择设置,这很可能意味着它会重新压缩内容,导致不必要的 CPU 负载和质量损失。因此建议至少将-c copy
作为该脚本的第三个参数传递,因为这将指示ffmpeg 复制视频和音频数据而不复制它。这使得转换速度更快(唯一的限制是硬盘速度),同时保持原始质量。
谢谢。自从发表此评论以来,我对 FFMPEG 有了更多的了解。我当时用过这个脚本,但是遇到了一些麻烦,不记得了,我再看一遍。
你的剧本太棒了!我认为默认行为应该是未修改的副本,并且没有重新编码。
这个脚本只制作了第一部分并且失败了。获取持续时间的ffprobe
命令为源文件和第一部分文件返回相同的持续时间。因为那个while循环只执行一次。【参考方案2】:
您可以使用 mp4box 在一个命令中执行此操作。
mp4box -splits 2000000 filename.mp4
splits
参数的值以千字节为单位。由于存在关键帧,片段不会正好是 2GB。
【讨论】:
我以为是字节?那不是 2MB 吗? 不,它以 kB 为单位。 当我尝试这个工具时,它把视频分成了 3 个部分,而它只需要 2 个部分。最后一段是120kb。前一部分剩余超过 100 MB 的可用空间。 这个命令不起作用。它只创建 1 个文件,其大小在参数上设置 取决于关键帧的位置。【参考方案3】:一个想法是使用带有选项 -fs 的 ffmpeg。这将限制文件大小。输出文件的大小略大于请求的文件大小。
这只会创建一个文件。但是你可以建立一个循环,直到整个文件被分割。
首先创建文件的一部分,然后检查它的长度:
ffprobe -i input.file -show_format -v quiet | sed -n 's/duration=//p'
然后使用 -ss 启动另一个具有偏移量的文件
之后进行另一轮编码,直到整个文件被分割。您还可以对音频和视频使用流式复制
【讨论】:
你能发布一个使用 -fs 和 -ss 的脚本示例吗?以上是关于使用 ffmpeg 按大小分割视频文件 [关闭]的主要内容,如果未能解决你的问题,请参考以下文章
我想用ffmpeg命令行转换一个视频文件,视、音频编码格式不变,只是将画面旋转90度,请问命令行该如何写?