FFmpeg:如何有效地分割视频?


103

我希望将一个大型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的联机帮助,我可以做一个以上的输出中使用刚刚从一个输入文件file 一个行:

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
使用“ -vcodec复制-acodec复制”时非常快:))
Savas Adar

@Antony,您为什么不计时两个版本(并查看诸如的内存监视器htop),然后告诉我们答案是什么?
AlcubierreDrive

第一个示例按顺序执行,而第二个示例使用线程。两者都会做同样的事情,不会出现明显的加速。:但是,为了简单起见,你可以使用的ffmpeg流分割复用器ffmpeg.org/...
姆拉登B.

1
这个例子看起来很错误!ffmpeg文档对-ss选项进行了说明:“当用作输入选项(在-i之前)时,在此输入文件中查找位置。当用作输出选项(在输出文件名之前)时,进行解码但放弃输入,直到时间戳到达位置。” 您在输出位置使用它,因此第二行浪费了解码工作,而浪费了前30分钟。
Lucian Wischik

1
@LucianWischik,但-ss在第二个拆分中用作输入选项可能并不准确,因此您可能无法获得完整的拆分。IMO的OP示例更为正确。
jiggunjer 2015年

Answers:


82

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

经过几次运行和一些数学运算后,我测试了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来进行“快速搜索”,再执行更准确的慢速搜索,这两个命令版本应该更快。


如果TS包含多个节目(DVB-T捕获的电视节目),如何拆分?例如,我有一个包含足球+烹饪+卡通的TS文件。如何将该TS文件拆分为3个mpg文件?
Dr.jacky

我在这里的问题中使用了您的答案(stackoverflow.com/questions/41983940/…),但是它没有用,您认为我做错了什么?
utdev

1
在我的情况下,结果文件中没有视频(只有音频)。经过一些实验,我发现了灵魂。它需要像这样为“不修改质量”指定密钥-q:v 0
oklas

19

这是一个有用的脚本,它可以帮助您自动拆分:使用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

2
与SEARAS一样,您的评论也一样。在绝对需要时以及在没有其他可用选项时,编写批处理文件很有用,因为它不可移植。例如,您将无法在Windows上运行相同的脚本。当存在更多通用/便携式方式时,应避免使用批处理脚本,以节省移植它们所需的时间。由于ffmpeg有多种方法可以解决此问题,因此正确的方法是单独使用ffmpeg,而无需脚本的帮助。
Mladen B.

不错的脚本。你写了吗 在GitHub上吗?我想提一些建议:)
声音

对于mp4,场景已损坏。最好将副本替换为:-vcodec libx264 -acodec aac
kishu

8

以我的经验,不要使用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可以达到目的!
马特

1
如何使用带有多个数字的Mp4Box修剪视频?例如,我需要几秒钟的子剪辑:5-8,21-30,12-18,所以我需要三个输出视频文件。
mhndev '18

而且比容易使用EndTime得多-t
vmassuchetto


2

后一种方法是否可以节省计算时间和内存?

您提供的这两个示例之间没有太大区别。第一个示例分两步依次剪切视频,而第二个示例同时(使用线程)剪切视频。没有特别的提速将是明显的。您可以阅读有关使用FFmpeg创建多个输出的更多信息

此外,您可以使用(在最近的FFmpeg中)流分割器复用器可以:

将流输出到持续时间几乎固定的多个独立文件。可以按照类似于image2的方式设置输出文件名模式。


2

这是一个简单的Windows bat文件,它将传入文件分为50个部分。每个部分的长度为1分钟。对不起,这种愚蠢的脚本。我希望最好有一个哑巴的Windows脚本,而不要根本没有它。也许它可以帮助某人。(基于此站点的“ bat循环文件”。)

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

这实质上是问题(连续ffmpeg命令)中重写为循环的第一个代码段。这没有回答该方法还是单个命令将“节省计算时间和内存”的问题。
培根

1

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

基本流分段器

显然,它会将AVI分成相同大小的段,这意味着这些块不会失去质量或增加内存,或者必须重新计算。

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


-1

这是分割视频的理想方法。我以前做过,对我来说效果很好。

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。问题是,如何有效地从同一个输入文件中提取多个段,而您只提取一个段。我看不出这如何回答问题。
培根

-2

一种简单的方法是将trim选项与基于publitio url的api一起使用

上传视频后,只需在网址(so_2,eo_2)中设置开始偏移和结束偏移,如下所示:

    https://media.publit.io/file/so_2,eo_2/tummy.mp4

这将立即创建长度为2秒和2秒的新视频。您可以按照自己喜欢的方式拆分视频。


问题是,使用哪种方法从输入文件中提取多个片段的两种方法中哪一种更有效ffmpeg?除非您拥有非常非常快的互联网连接,否则我认为必须将整个视频上传到云服务,然后再下载结果,这将大大增加处理时间。即便如此,这仍然没有回答哪一种方式的问题ffmpeg更有效。
培根
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.