FFmpeg:如何有效地分割视频?
Posted
技术标签:
【中文标题】FFmpeg:如何有效地分割视频?【英文标题】:FFmpeg: How to split video efficiently? 【发布时间】:2011-08-04 19:57:23 【问题描述】:我希望将一个大的 avi 视频分成两个较小的连续视频。我正在使用 ffmpeg。
一种方法是两次运行ffmpeg:
ffmpeg -i input.avi -vcodec copy -acodec copy -ss 00:00:00 -t 00:30:00 output1.avi
ffmpeg -i input.avi -vcodec copy -acodec copy -ss 00:30:00 -t 00:30:00 output2.avi
但是根据 ffmpeg 的手册页,我可以只使用 一个 行从一个输入文件生成多个输出文件:
ffmpeg -i input.avi -vcodec copy -acodec copy -ss 00:00:00 -t 00:30:00 output1.avi \
-vcodec copy -acodec copy -ss 00:30:00 -t 00:30:00 output2.avi
我的问题是,后一种方法是否节省了计算时间和内存?
【问题讨论】:
当使用“-vcodec copy -acodec copy”时速度非常快:)) @Antony,你为什么不给两个版本都计时(看看内存监视器,比如htop
),然后告诉我们答案是什么?
第一个示例按顺序执行,而第二个示例使用线程。两者都会做同样的事情,不会出现明显的加速。但为了简单起见,您可以使用 ffmpeg 流分段器复用器:ffmpeg.org/…
这个例子看起来大错特错! ffmpeg 文档说明了 -ss 选项:“当用作输入选项时(在 -i 之前),在此输入文件中查找位置。当用作输出选项时(在输出文件名之前),解码但丢弃输入,直到时间戳到达位置。”您在输出位置使用它,因此您的第二行浪费了解码和丢弃前 30 分钟的精力。
@LucianWischik 但在第二次拆分中使用 -ss
作为输入选项可能不准确,因此您可能无法获得干净的拆分。 IMO OP 的例子更正确。
【参考方案1】:
根据我的经验,不要使用 ffmpeg 进行拆分/加入。
MP4Box,比 ffmpeg 更快更轻。请试一试。
例如,如果您想将一个 1400mb 的 MP4 文件分成两部分,一个 700mb,您可以使用以下 cmdl:
MP4Box -splits 716800 input.mp4
例如,用于连接您可以使用的两个文件:
MP4Box -cat file1.mp4 -cat file2.mp4 output.mp4
或者如果您需要按时间拆分,请使用-splitx StartTime:EndTime
:
MP4Box -add input.mp4 -splitx 0:15 -new split.mp4
【讨论】:
这正是我所需要的!当我使用 ffmpeg 进行剪辑时,剪辑没有从关键帧开始,并且在结尾处有奇怪的冻结。使用 MP4Box -splitz 成功了! 如何使用 Mp4Box 修剪多个数字的视频?例如,我需要在几秒钟内获得子剪辑:5 - 8、21 - 30、12 - 18 所以我需要三个输出视频文件。 而且EndTime
比-t
更容易使用。
比 vlc 或 ffmpeg 最好和快速的解决方案。谢谢
MP4Box 只是稍微好一点。我不推荐它。一位用户写道:“当我使用 ffmpeg 进行剪辑时,剪辑没有从关键帧开始”。这可能是由于使用了-c copy
。如果您希望视频从正确的帧开始,则可能需要重新编码。所以在 OP 中没有 -c copy
或 -vcodec copy
。例如:ffmpeg -i in.mp4 -ss 00:00:00.46 out.mp4 -y
。 ***.com/questions/49846095 指出这可能是相关的:“由于视频压缩的工作原理(P 和 B 帧不能独立存在),这些方法都不会完全准确。”【参考方案2】:
这是分割视频的完美方式。我以前做过,对我来说效果很好。
ffmpeg -i C:\xampp\htdocs\videoCutting\movie.mp4 -ss 00:00:00 -t 00:00:05 -async 1 C:\xampp\htdocs\videoCutting\SampleVideoNew.mp4
(用于 cmd)。
shell_exec('ffmpeg -i C:\xampp\htdocs\videoCutting\movie.mp4 -ss 00:00:00 -t 00:00:05 -async 1 C:\xampp\htdocs\videoCutting\SampleVideoNew.mp4')
(用于 php)。
请按照此操作,我相信它会完美运行。
【讨论】:
为什么这是分割视频的“完美方式”?就像问题中的命令行一样,您传递的是-i
,然后是-ss
和-t
。但是,问题是关于如何有效地从同一个输入文件中提取多个段,而您只提取一个段。我不明白这是如何回答这个问题的。【参考方案3】:
一种简单的方法是使用带有publitio url-based api 的修剪选项。
上传视频后,只需在 url (so_2,eo_2) 中设置起始偏移量和结束偏移量,如下所示:
https://media.publit.io/file/so_2,eo_2/tummy.mp4
这将立即创建从第 2 秒和 2 秒开始的新视频。您可以随意使用这种方式分割视频。
【讨论】:
问题是用ffmpeg
从输入文件中提取多个段的两种方法中哪一种更有效。除非您拥有非常非常快的互联网连接,否则我认为必须将整个视频上传到云服务然后下载结果会显着增加处理时间。即便如此,这仍然不能回答 ffmpeg
哪种方法更有效的问题。【参考方案4】:
这是一个简单的 Windows bat 文件,用于将传入的文件分成 50 个部分。每个部分的长度为 1 分钟。对不起这么愚蠢的脚本。我希望拥有一个愚蠢的 Windows 脚本而不是根本没有它会更好。也许它可以帮助某人。 (基于此站点的“bat file for loop”。)
set var=0
@echo off
:start
set lz=
if %var% EQU 50 goto end
if %var% LEQ 9 set lz=0
echo part %lz%%var%
ffmpeg -ss 00:%lz%%var%:00 -t 00:01:00 -i %1 -acodec copy -vcodec copy %2_%lz%%var%.mp4
set /a var+=1
goto start
:end
echo var has reached %var%.
exit
【讨论】:
这本质上是将问题中的第一个代码 sn-p(连续的ffmpeg
命令)重写为循环。这并没有回答该方法或单个命令是否会“节省计算时间和内存”的问题。【参考方案5】:
ffmpeg wiki 链接回此页面,参考“如何有效分割视频”。我不相信这个页面能回答这个问题,所以我按照@AlcubierreDrive 的建议做了……
echo "Two commands"
time ffmpeg -v quiet -y -i input.ts -vcodec copy -acodec copy -ss 00:00:00 -t 00:30:00 -sn test1.mkv
time ffmpeg -v quiet -y -i input.ts -vcodec copy -acodec copy -ss 00:30:00 -t 01:00:00 -sn test2.mkv
echo "One command"
time ffmpeg -v quiet -y -i input.ts -vcodec copy -acodec copy -ss 00:00:00 -t 00:30:00 \
-sn test3.mkv -vcodec copy -acodec copy -ss 00:30:00 -t 01:00:00 -sn test4.mkv
哪些输出...
Two commands
real 0m16.201s
user 0m1.830s
sys 0m1.301s
real 0m43.621s
user 0m4.943s
sys 0m2.908s
One command
real 0m59.410s
user 0m5.577s
sys 0m3.939s
经过几次运行和一些数学运算后,我测试了一个标清和高清文件。
Two commands SD 0m53.94 #2 wins
One command SD 0m49.63
Two commands SD 0m55.00
One command SD 0m52.26 #1 wins
Two commands SD 0m58.60 #2 wins
One command SD 0m58.61
Two commands SD 0m54.60
One command SD 0m50.51 #1 wins
Two commands SD 0m53.94
One command SD 0m49.63 #1 wins
Two commands SD 0m55.00
One command SD 0m52.26 #1 wins
Two commands SD 0m58.71
One command SD 0m58.61 #1 wins
Two commands SD 0m54.63
One command SD 0m50.51 #1 wins
Two commands SD 1m6.67s #2 wins
One command SD 1m20.18
Two commands SD 1m7.67
One command SD 1m6.72 #1 wins
Two commands SD 1m4.92
One command SD 1m2.24 #1 wins
Two commands SD 1m1.73
One command SD 0m59.72 #1 wins
Two commands HD 4m23.20
One command HD 3m40.02 #1 wins
Two commands SD 1m1.30
One command SD 0m59.59 #1 wins
Two commands HD 3m47.89
One command HD 3m29.59 #1 wins
Two commands SD 0m59.82
One command SD 0m59.41 #1 wins
Two commands HD 3m51.18
One command HD 3m30.79 #1 wins
标清文件 = 1.35GB DVB传输流高清文件 = 3.14GB DVB传输流
结论
如果您正在处理 HD,则单个命令更好,它与手册 cmets 关于在输入文件后使用 -ss 进行“慢速搜索”一致。 SD 文件的差异可以忽略不计。
两个命令版本应该更快,方法是在输入文件前添加另一个 -ss 用于“快速搜索”,然后是更准确的慢速搜索。
【讨论】:
如果TS包含多个节目(DVB-T捕获的电视节目),如何拆分?例如,我有一个包含足球 + 烹饪 + 卡通的 TS 文件。如何将此 TS 文件拆分为 3 个 mpg 文件? 我在我的问题中使用了你的答案 (***.com/questions/41983940/…) 但它不起作用,你认为我做错了什么? 在我的情况下,结果文件没有视频(只有音频)。经过一些实验,我找到了灵魂。它需要像-q:v 0
这样为“不修改质量”指定密钥。【参考方案6】:
没有测试ist,但这看起来很有希望:
Basic stream segmenter
这显然是将 AVI 分成相同大小的段,这意味着这些块不会降低质量或增加内存或必须重新计算。
它还使用编解码器副本——这是否意味着它可以处理非常大的流?因为这是我的问题,所以我想分解我的 avi,这样我就可以使用过滤器来消除失真。但是一个完整的 avi 会运行几个小时。
【讨论】:
【参考方案7】:后一种方法会节省计算时间和内存吗?
您提供的这两个示例之间没有太大区别。第一个示例分两步按顺序剪切视频,而第二个示例同时进行(使用线程)。没有特别明显的加速。你可以阅读更多关于creating multiple outputs with FFmpeg
此外,您可以使用(在最近的 FFmpeg 中)是 stream segmenter muxer,它可以:
将流输出到多个几乎固定持续时间的单独文件。输出文件名模式可以设置为类似于image2。
【讨论】:
【参考方案8】:这是一个有用的脚本,它可以帮助你自动拆分:A script for splitting videos using ffmpeg
#!/bin/bash
# Written by Alexis Bezverkhyy <alexis@grapsus.net> in 2011
# This is free and unencumbered software released into the public domain.
# For more information, please refer to <http://unlicense.org/>
function usage
echo "Usage : ffsplit.sh input.file chunk-duration [output-filename-format]"
echo -e "\t - input file may be any kind of file reconginzed by ffmpeg"
echo -e "\t - chunk duration must be in seconds"
echo -e "\t - output filename format must be printf-like, for example myvideo-part-%04d.avi"
echo -e "\t - if no output filename format is given, it will be computed\
automatically from input filename"
IN_FILE="$1"
OUT_FILE_FORMAT="$3"
typeset -i CHUNK_LEN
CHUNK_LEN="$2"
DURATION_HMS=$(ffmpeg -i "$IN_FILE" 2>&1 | grep Duration | cut -f 4 -d ' ')
DURATION_H=$(echo "$DURATION_HMS" | cut -d ':' -f 1)
DURATION_M=$(echo "$DURATION_HMS" | cut -d ':' -f 2)
DURATION_S=$(echo "$DURATION_HMS" | cut -d ':' -f 3 | cut -d '.' -f 1)
let "DURATION = ( DURATION_H * 60 + DURATION_M ) * 60 + DURATION_S"
if [ "$DURATION" = '0' ] ; then
echo "Invalid input video"
usage
exit 1
fi
if [ "$CHUNK_LEN" = "0" ] ; then
echo "Invalid chunk size"
usage
exit 2
fi
if [ -z "$OUT_FILE_FORMAT" ] ; then
FILE_EXT=$(echo "$IN_FILE" | sed 's/^.*\.\([a-zA-Z0-9]\+\)$/\1/')
FILE_NAME=$(echo "$IN_FILE" | sed 's/^\(.*\)\.[a-zA-Z0-9]\+$/\1/')
OUT_FILE_FORMAT="$FILE_NAME-%03d.$FILE_EXT"
echo "Using default output file format : $OUT_FILE_FORMAT"
fi
N='1'
OFFSET='0'
let 'N_FILES = DURATION / CHUNK_LEN + 1'
while [ "$OFFSET" -lt "$DURATION" ] ; do
OUT_FILE=$(printf "$OUT_FILE_FORMAT" "$N")
echo "writing $OUT_FILE ($N/$N_FILES)..."
ffmpeg -i "$IN_FILE" -vcodec copy -acodec copy -ss "$OFFSET" -t "$CHUNK_LEN" "$OUT_FILE"
let "N = N + 1"
let "OFFSET = OFFSET + CHUNK_LEN"
done
【讨论】:
与 SEARAS 的评论相同。当绝对需要并且没有其他可用选项时,编写批处理文件很有用,因为它不可移植。例如,您将无法在 Windows 上运行相同的脚本。当有更多通用/可移植方式时,应避免使用批处理脚本,以节省移植它们所需的时间。由于 ffmpeg 有多种方法可以解决此问题,因此正确的方法是单独使用 ffmpeg,无需脚本的帮助。 不错的脚本。你写了吗?是在 GitHub 上吗?我想提出一些建议:) 对于 mp4,场景已损坏。更好地将副本替换为:-vcodec libx264 -acodec aac 链接失效 最好在这里修复一行: > #let "DURATION = ( DURATION_H * 60 + DURATION_M ) * 60 + DURATION_S" > DURATION=$( echo "($DURATION_H * 60 + $DURATION_M ) * 60 + $DURATION_S" | bc) 我这里有一个错误,这是一个更好的计算方法【参考方案9】:http://ffmpeg.org/trac/ffmpeg/wiki/Seeking%20with%20FFmpeg 也可能对您有用。 ffmpeg 也有一个可以工作的段复用器。
无论如何,我的猜测是将它们组合成一个命令会节省时间。
【讨论】:
以上是关于FFmpeg:如何有效地分割视频?的主要内容,如果未能解决你的问题,请参考以下文章