FFmpeg: Як ефективно розділити відео?


103

Я хочу розділити велике відео з відео на два менших відео поспіль. Я використовую 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
при використанні "-vcodec copy -acodec copy" це дуже швидко :))
Savas Adar

@Antony, чому ти не встигнеш обидві версії (і не подивишся на монітор пам’яті, як-от htop), і не розкажеш, яка відповідь?
AlcubierreDrive

Перший приклад робить це послідовно, а другий приклад використовує нитки. Обидва будуть робити те саме, ніяких помітних прискорень не повинно відбуватися. Але для спрощення речей ви можете використовувати ffmpeg stream segmenter muxer
Mladen B.

1
Цей приклад виглядає погано неправильно! Документація ffmpeg говорить про параметр -ss: "Якщо використовується як параметр вводу (до -i), в цьому вхідному файлі шукає позицію. Якщо використовується як вихідний варіант (перед назвою вихідного файлу), декодує, але відкидає введення, поки не з'явиться часові позначки досягають позиції. " Ви використовуєте його у вихідному положенні, тому ваш другий рядок витрачає зусилля на декодування та відкидання перші 30 хвилин.
Лучан Віщик

1
@LucianWischik, але використання -ssв якості параметра введення у другому розділі може бути неточним, тому ви не зможете отримати чистий розкол. IMO приклад 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 mpg файли?
Dr.jacky

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

1
Файл результатів у моєму випадку був без відео (лише аудіо). Після деяких експериментів я знайшов душу. Для цього потрібно вказати ключ для "не змінювати якість" -q:v 0.
оклас

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 самостійно, без допомоги скриптів.
Младен Б.

Гарний сценарій. Ви це написали? Це на GitHub? Я хотів би зробити кілька пропозицій :)
озвучує

для mp4 сцени пошкоджені. краще замініть копію на: -vcodec libx264 -acodec aac
kishu

8

На мій досвід, не використовуйте ffmpeg для розділення / приєднання. MP4Box, швидше і легше, ніж ffmpeg. Будь ласка, спробуйте. Наприклад, якщо ви хочете розділити файл MP4 1400mb на дві частини 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

І набагато простіше у використанні, 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 бігає годинами.


-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 .

як тільки ви завантажите своє відео, просто встановіть запуск і зміщення в 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.