2011-04-13 302 views
70

我希望将大型avi视频分成两个较小的连续视频。我正在使用ffmpeg。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 

我的问题是,后面的方法是否节省了计算时间和内存?

+3

stackoverflow.com用于编程相关的问题。尝试superuser.com(这个问题可能会移到那里,只需要更多的移动投票)。 – 2011-04-13 15:33:41

+0

那么它可以节省时间吗? – rogerdpack 2011-09-27 18:29:00

+2

当使用“-vcodec副本-acodec副本”它是非常快:)) – 2012-05-02 20:39:55

回答

54

ffmpeg维基链接参考“如何高效地分割视频”链接回到此页面。我不相信这个页面可以回答这个问题,所以我就像@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 

我测试了SD & HD文件,几运行&一点数学之后。

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 

SD文件 = 1.35GB DVB传输流
HD文件 = 3.14GB DVB传输流

结论

单指令是更好,如果你正在处理HD,它同意在输入文件之后使用-ss进行“慢搜寻”的手册评论。 SD文件的差异可以忽略不计。

这两个命令版本应该更快,在输入文件之前添加另一个-ss,以进行“快速搜索”,然后进行更准确的慢搜索。

+3

完美工作,赞美你的努力! – Kartos 2014-01-03 03:22:03

+0

如果TS包含多个节目(由DVB-T捕获的电视节目),如何分割?例如,我有一个包含足球+烹饪+卡通的TS文件。如何将此TS文件分割为3 mpg文件? – 2015-07-20 12:35:13

+0

我在这里用我的问题的答案(http://stackoverflow.com/questions/41983940/ffmpeg-disassemble-video-into-parts)但它没有工作,你认为我做错了什么? – utdev 2017-02-01 15:58:14

-5

事实证明,在后面的情况下文件大小将与时间片成比例地等效。

+2

我不确定这会回答提问者提出的问题:他担心计算时间和内存,而不是文件大小。 – 2012-11-12 19:40:36

15

这里是一个有用的脚本,它可以帮助你自动分割:A script for splitting videos using ffmpeg

#!/bin/bash 
  
# Written by Alexis Bezverkhyy <[email protected]> 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 
+1

对于你来说,SEARAS同样也有评论。编写批处理文件在绝对需要时以及当您没有其他选项可用时非常有用,因为它不可移植。例如,您将无法在Windows上运行相同的脚本。当有更多的通用/便携式方法时,应避免使用批处理脚本,以节省移植它们所需的时间。由于ffmpeg有多种方法来解决这个问题,所以正确的方法是单独使用ffmpeg,而不需要脚本的帮助。 – 2013-08-24 10:00:53

+2

tnx脚本) – gaRex 2015-12-23 19:17:05

+0

尼斯脚本。你写了吗?它在GitHub上吗?我想提出一些建议:) – user3155368 2017-01-21 04:41:07

1

并在后一种方法节省计算时间和内存?

您提供的这两个示例之间没有太大的区别。第一个示例按2个步骤顺序剪切视频,而第二个示例同时剪裁视频(使用线程)。没有特别的加速将是显而易见的。你可以阅读更多关于creating multiple outputs with FFmpeg

更进一步,你可以使用(在最近的FFmpeg)什么是stream segmenter muxer它可以:

输出流的数量近固定时长的单独的文件。输出文件名称模式可以以类似于image2的方式设置。

0

没有测试IST,但是这看起来很有希望:

Basic stream segmenter

这显然是分裂成AVI大小相同,这意味着这些细分大块不松质量或增加内存或必须重新计算。

它也使用编解码器副本 - 这是否意味着它可以处理非常大的流?因为这是我的问题,我想分解我的AVI,所以我可以使用过滤器来摆脱失真。但是整个avi运行数小时。

3

根据我的经验,不要使用ffmpeg进行拆分/连接。 MP4Box,比ffmpeg更快更轻。请尝试。 比如,如果你想要一个1400MB MP4文件分割成两个部分,你可以使用下面的CMDL一个700MB: MP4Box -splits 716800 input.mp4 例如,用于连接两个文件,你可以使用:

MP4Box -cat file1.mp4 -cat file2.mp4 output.mp4 
+0

这正是我需要的!当我用ffmpeg剪辑时,剪辑没有从关键帧开始,并且在结尾处有奇怪的冻结。使用MP4Box -splitz取得了诀窍! – matt 2016-12-12 00:12:44

2

下面是一个简单的Windows BAT文件将传入文件分成50个部分。每个部分的长度均为1分钟。对不起,这种愚蠢的脚本。我希望最好有一个愚蠢的Windows脚本,而不是根本没有它。也许它有助于某人。 (基于来自本网站的“bat 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