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.