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

Но согласно man-странице 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
при использовании "-vcodec copy -acodec copy" это очень быстро :))
Савас Адар

@Antony, почему бы вам не рассчитать время обеих версий (и посмотреть на монитор памяти, например htop), и не сказать нам, каков ответ?
AlcubierreDrive

В первом примере это делается последовательно, а во втором - потоки. Оба будут делать то же самое, заметного ускорения не должно произойти. Но для упрощения вы можете использовать ffmpeg stream segmenter muxer: ffmpeg.org/…
Mladen B.

1
Этот пример выглядит совершенно неверным! В документации ffmpeg говорится о параметре -ss: «При использовании в качестве параметра ввода (до -i) ищет в этом входном файле позицию. При использовании в качестве параметра вывода (перед именем файла вывода) декодирует, но отбрасывает ввод до тех пор, пока отметки времени достигают позиции ". Вы используете его в позиции вывода, поэтому ваша вторая строка тратит усилия на декодирование и отбрасывает первые 30 минут.
Люсьен Вишик

1
@LucianWischik, но использование в -ssкачестве параметра ввода во втором разбиении может быть неточным, поэтому вы не можете получить чистое разбиение. ИМО вернее пример OP.
jiggunjer

Ответы:


82

Вики 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,35 ГБ транспортного потока DVB
Файл HD = 3,14 ГБ транспортного потока DVB

Вывод

Единственная команда лучше, если вы работаете с HD, это согласуется с комментариями руководства по использованию -ss после входного файла для выполнения «медленного поиска». Файлы SD имеют незначительную разницу.

Версия с двумя командами должна быть быстрее, добавив еще одну -ss перед входным файлом для «быстрого поиска», за которым следует более точный медленный поиск.


Если TS содержат несколько программ (телепрограммы, снятые с помощью DVB-T), как можно их разделить? Например, у меня есть файл TS, содержащий футбол + кулинария + мультфильм. Как я могу разделить этот файл TS на 3 файла на галлон?
Доктор Джеки

Я использовал ваш ответ в своем вопросе здесь ( stackoverflow.com/questions/41983940/… ), но он не сработал. Как вы думаете, что я делаю не так?
utdev 01

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 ААС
Кисю

8

По моему опыту, не используйте ffmpeg для разделения / соединения. MP4Box быстрее и легче, чем ffmpeg. Пожалуйста, попробуйте. Например, если вы хотите разделить файл MP4 размером 1400 МБ на две части по 700 МБ, вы можете использовать следующую команду: 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 01

И пользоваться им намного проще, EndTimeчем -t.
vmassuchetto


2

экономит ли более поздний подход время вычислений и память?

Между этими двумя приведенными вами примерами нет большой разницы. В первом примере видео обрезается последовательно, в 2 этапа, а во втором примере - одновременно (с использованием потоков). Особого разгона не будет. Вы можете узнать больше о создании нескольких выходов с помощью FFmpeg

Более того, вы можете использовать (в недавнем FFmpeg) мультиплексор сегментера потока, который может:

выводить потоки в несколько отдельных файлов почти фиксированной продолжительности. Шаблон выходного имени файла может быть установлен аналогично image2 .


2

Вот простой файл bat Windows для разделения входящего файла на 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команды), переписанный в виде цикла. Это не отвечает на вопрос, будет ли этот подход или отдельная команда «сэкономить время вычислений и память».
BACON

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. Однако вопрос заключается в том, как эффективно извлечь несколько сегментов из одного входного файла, в то время как вы извлекаете только один сегмент. Я не понимаю, как это отвечает на вопрос.
BACON

-2

один простой способ - использовать опцию обрезки с api на основе url-адресов publitio .

как только вы загрузите видео, просто установите начальное и конечное смещения в url (so_2, eo_2) следующим образом:

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

это мгновенно создаст новые видео, начиная со 2-й секунды и продолжительностью 2 секунды. вы можете разделить видео так, как вам нравится.


Возникает вопрос, какой из двух подходов более эффективен для извлечения нескольких сегментов из входного файла с помощью ffmpeg. Если у вас нет действительно очень быстрого интернет-соединения, я думаю, что необходимость загрузить все видео в облачную службу, а затем загрузить результаты, значительно увеличит время обработки. Тем не менее , это еще не дает ответа на вопрос о том, какой подход сffmpeg более эффективным.
BACON
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.