Повторить/зациклить входное видео с помощью ffmpeg?

Я просто хочу зациклить видео mp4 с помощью ffmpeg и сохранить текущие настройки и кодек.

Например, если input.mp4 имеет длину 0:10, и я хотел бы зациклить его 4 раза, чтобы output.mp4 имел длину 0:40, как я могу изменить следующую командную строку, чтобы сделать это?

ffmpeg -i input.mp4 -c copy output.mp4

Я пытался...

ffmpeg -loop 4 -i input.mp4 -c copy output.mp4

... но я получаю сообщение об ошибке «Цикл опций не найден».

Используйте quicktime 7 pro и контейнер mov. Таким образом, вы не получите большего размера файла, чем с открытым исходным кодом.

Ответы (6)

-stream_loopвариант

ffmpeg -stream_loop 3 -i input.mp4 -c copy output.mp4
  • Это позволяет избежать повторного кодирования, поскольку может использовать потоковое копирование .
  • 0означает отсутствие цикла, -1означает бесконечный цикл.
  • Это может не работать с чем-либо старше FFmpeg 4.0.

concat демультиплексор

Демультиплексор concat позволяет вам зацикливать ввод без необходимости повторного кодирования, поскольку он может использовать потоковое копирование .

  1. Сделайте текстовый файл. Содержимое примера текстового файла повторить 4 раза.

     file 'input.mp4'
     file 'input.mp4'
     file 'input.mp4'
     file 'input.mp4'
    
  2. Затем запустите ffmpeg:

     ffmpeg -f concat -i list.txt -c copy output.mp4
    

Если вы хотите добавить дополнительные входы, убедитесь, что все они имеют одинаковые атрибуты.

Автоматически делать list.txtв Linux/macOS

Этот пример такой же, как и выше, но вам не нужно делать вручную list.txt:

for i in {1..4}; do printf "file '%s'\n" input.mp4 >> list.txt; done
ffmpeg -f concat -i list.txt -c copy output.mp4

С наиболее часто используемыми современными оболочками вы даже можете list.txtполностью избежать создания файла. Например, с Баш:

ffmpeg -f concat -i <(for i in {1..4}; do printf "file '%s'\n" input.mp4; done) -c copy output.mp4

Также см:


контурный фильтр

Пример использования петлевого фильтра для повторения 4 циклов, каждый цикл составляет 75 кадров, каждый цикл пропускает первые 25 кадров ввода:

ffmpeg -i input.mp4 -filter_complex "loop=loop=3:size=75:start=25" output.mp4
  • Или используйте сокращение:loop=3:75:25
  • Фильтрация требует повторного кодирования.
  • Этот фильтр помещает все кадры в память .
  • Использование loop=3цикла будет 4 раза.
  • Для бесконечного цикла используйте -1.
  • Вы должны указать количество кадров для цикла (показано как 75 в приведенном выше примере). Максимальное значение 32767.
  • Также см ffmpeg -h filter=loop. .

фильм фильтр

Фильтры фильмов и фильмов имеют параметр цикла:

ffmpeg -f lavfi -i "movie=filename=input.mp4:loop=4,setpts=N/FRAME_RATE/TB" -f lavfi -i "amovie=filename=input.mp4:loop=4,asetpts=N/SR/TB" output.mp4
  • Фильтрация требует повторного кодирования.
  • 1означает отсутствие цикла, 0означает бесконечный цикл.

-loopвариант

Этот -loopпараметр относится к демультиплексору файла изображения и мультиплексору gif , поэтому его нельзя использовать для обычных видеофайлов. Но его можно использовать для бесконечного цикла одного изображения или серии изображений.

одно изображение

В этом примере одно изображение будет повторяться снова и снова, но -t 30продолжительность вывода будет ограничена 30 секундами:

ffmpeg -loop 1 -i input.png -t 30 -vf format=yuv420p output.mp4

-vf format=yuv420pэто из соображений совместимости.

серия изображений

ffmpeg -loop 1 -i %03d.jpg -t 30 -vf format=yuv420p output.mp4

Вывод GIF

Или зациклить GIF:

ffmpeg -i input -loop 3 output.gif

Для вывода GIF также см. Как преобразовать видео в GIF с помощью ffmpeg с приемлемым качеством?

Это нормально работает с файлами mp4?
я получаю эту ошибку> <(for i in {1..4}; do printf "file '%s'\n" input.mp4; done) -bash: /dev/fd/63: Permission denied
@jamesfzhang - я думаю, это потому, что вам нужен абсолютный путь к файлу (как объяснено здесь: trac.ffmpeg.org/wiki/Concatenate ). Чтобы выполнить это, вы можете написать: ffmpeg -safe 0 -f concat -i <(for i in {1..4}; do printf "file '$PWD'/'%s'\n" input.mp4; done ) -c копировать output.mp4
Как по мне, это работает, чтобы повторить полное время видео, не пропуская славы в 4 разаffmpeg -i video.mp4 -filter_complex "loop=4:32767" output.mp4
Этому выпуску уже 4 года и никто не заметил, что ссылка на второй выпуск в -stream_loopразделе ведет на тот же тикет, что и первый...
При работе с изображениями есть ли разница между -i %03d.png -t 30и -t 30 -i %03d.png? Я знаю, что при работе с видео вы обычно хотите -t-ss) перед вводом, чтобы сэкономить время на декодировании, но имеет ли это значение для изображений? Недавно я запускал некоторые команды -tперед вводом, и все работало нормально.
@DigiVisionMedia не должно иметь значения.
Зацикленные части занимают дополнительный размер в выходном видео? Например, если исходный размер видео составляет 1 МБ, loop=loop=3 равняется 3 МБ?

В ffmpeg 2.8.4 следующая команда создает output.mp4, который является повторяющейся копией input.mp4, пока процесс ffmpeg не будет остановлен:

ffmpeg -stream_loop -1 -i input.mp4 -c copy output.mp4

Эта команда не завершится сама по себе, и выходной файл будет расти бесконечно.

Кажется, это самый быстрый способ
Самый быстрый метод — это преуменьшение, этот метод увеличивает многочасовое видео за считанные секунды.
Это очень удобный способ, потому что нет необходимости создавать файл с повторяющимися строками.
Людям нужно изменить значение параметра -stream_loop с -1некоторого положительного целого числа в соответствии с их требованиями. В противном случае файл увеличивается, и система выдает No space left on deviceошибку.
Это должен быть лучший ответ, работающий с первой попытки.
Если вы хотите указать время, добавьте -t 30 , это создаст зацикленное видео с 30 секундами.

По крайней мере, на FFmpeg 2.8.x (но старый тоже должен работать) вы можете использовать lavfiв качестве входного формата и сложного графа фильтров, используя movieи setptsфильтры в качестве аргумента для -iопции.

Следующая команда сделает эту работу за вас:

ffmpeg -re -f lavfi -i "movie=filename=input.mp4:loop=0, setpts=N/(FRAME_RATE*TB)" output.mp4

Нулевые loop=аргументы означают бесконечный цикл. Значения больше нуля задают количество повторов. setptsфильтры, необходимые для настройки PTS для второго и более поздних повторов, в противном случае большинство выходных мультиплексоров выйдет из строя с немонотонным увеличением PTS: цикл не пересчитывает PTS.

Обратите внимание, что использование фильтров, предполагающих обход кадров без декодирования/кодирования, невозможно: фильтры по своей конструкции работают только с декодированными кадрами.

В FFmpeg 2.8.2 введена новая опция -stream_loopввода. На первый взгляд он работает проще и позволяет копировать контент без перекодирования:

ffmpeg -re -stream_loop -1 -i input.mp4 -c copy -y output.mp4

Но он не пересчитывает PTS, и выходной файл неверен. Если вы добавляете фильтр для исправления PTS (см. setpts), вы также должны удалить его -c copy. Только фильтры битового потока могут работать с закодированными пакетами, но нет никаких фильтров битового потока для исправления PTS (см.: https://ffmpeg.org/ffmpeg-bitstream-filters.html )

В любом случае ffmpeg на втором проходе завершается с ошибкой:

input.mp4: Resource temporarily unavailable

Известный обходной путь для меня : использовать контейнер для входного файла без ограничений PTS (контейнер потоковой передачи). Один из них, известный мне, это MPEG-TS. Итак, вы можете просто преобразовать файл MP4 в MPEG-TS:

ffmpeg -i input.mp4 -c copy -bsf:v h264_mp4toannexb -f mpegts input.ts

И используйте следующую команду для создания бесконечного файла:

ffmpeg -re -stream_loop -1 -i input.ts -c copy -strict -2 -bsf:a aac_adtstoasc -y output.mp4

(фильтры битового потока следует использовать только в случае необходимости, на моих образцах это требуется)

В этом случае требуется FFmpeg >= 2.8.2.

Выполнение этой команды выдает ошибку: «[mp4 @ 00000000053fa1a0] Не удалось найти тег для кодека rawvideo в потоке № 0, кодек в настоящее время не поддерживается в контейнере». Если я добавлю -vcodec h264 перед вводом, эта ошибка исчезнет, ​​но кодировщик не выйдет. Предоставление ненулевого счетчика циклов приводит к большому количеству ошибок, но завершает работу. Файл не является допустимым выходным файлом.
В документации для stream_loop говорится: «Цикл 0 означает отсутствие цикла, цикл -1 означает бесконечный цикл».
Кажется, неправильные входные файлы. Не могли бы вы поделиться им? «Цикл 0 означает отсутствие цикла, цикл -1 означает бесконечный цикл». - кажется, я вижу старые документы :-)
Мои были действительными MP4, но я не могу поделиться теми, которые я использовал. Вы можете создать один с помощью ffmpeg, а затем использовать его. Вставьте вывод консоли, если он работает.
Я забыл: фильтры предполагают транскодирование (декодирование/кодирование). По дизайну. Значит надо удалить -c copy. Ответ исправлен.
Приятно знать, но это существенное ограничение, если вам нужно сгенерировать большой цикл.
Добавьте информацию о stream_loop и WA, чтобы исправить проблему с PTS без повторного кодирования. Требуется FFmpeg >= 2.8.2.
@MonahTuk Я считаю, что циклический фильтр работает намного лучше, чем stream_loop (который вызывает короткую паузу для любого файла, который я пробовал), за одним исключением: в тот момент, когда я добавляю циклический фильтр, звук исчезает?
@MikeVersteeg, ты должен проверить файлы. Время от времени разные дорожки в файле имеют немного разную длину или смещение, что может повлиять на мультиплексирование. Также могут возникать проблемы в никогда не используемых версиях FFmpeg. Кроме того, наиболее рабочий случай - использовать контейнер MPEG TS в качестве ввода и вывода.
@echo off

setlocal ENABLEDELAYEDEXPANSION

REM When not there gives file not found message
for /f "tokens=*" %%I in ('dir /b "*.mkv"') do (
    if exist "%%~nI.nl.srt" (
        call :BURN_FILE "%%~nI" "%%I"
    )
    if exist "%%~nI.en.srt" (
        call :BURN_FILE "%%~nI" "%%I"
    ) 
)
for /f "tokens=*" %%I in ('dir /b "*.mp4"') do (
    if exist "%%~nI.nl.srt" (
        call :BURN_FILE "%%~nI" "%%I"
    )
    if exist "%%~nI.en.srt" (
        call :BURN_FILE "%%~nI" "%%I"
    ) 
)
for /f "tokens=*" %%I in ('dir /b "*.webm"') do (
    if exist "%%~nI.nl.srt" (
        call :BURN_FILE "%%~nI" "%%I"
    )
    if exist "%%~nI.en.srt" (
        call :BURN_FILE "%%~nI" "%%I"
    ) 
)

pause

if not exist ORIGINAL mkdir ORIGINAL
move "%%I" ORIGINAL >NUL
move "%%~nI.*" ORIGINAL >NUL

exit /b

:BURN_FILE

    set hoppa=%1
    set input=%2
    echo hoppa=!hoppa!
    echo input=!input!

    ffprobe.exe -v error -select_streams v:0 -show_entries format=bit_rate -of default=nw=1 !input! > bit_rate2.txt
    ffprobe.exe -v error -show_entries format=duration -of default=nw=1 !input! > duration2.txt
    ffprobe.exe -v error -show_entries format=duration -of default=nw=1 intro.wav > duration_intro.txt

    for /F "tokens=*" %%R in (bit_rate2.txt) do (
        for /f "tokens=1,2 delims==" %%a in ("%%R") do set NAME=%%a & set bit_rate=%%b
    )
    for /F "tokens=*" %%R in (duration2.txt) do (
        for /f "tokens=1,2 delims==" %%a in ("%%R") do set NAME=%%a & set duration=%%b
    )
    for /F "tokens=*" %%R in (duration_intro.txt) do (
        for /f "tokens=1,2 delims==" %%a in ("%%R") do set NAME=%%a & set duration_intro=%%b
    )
    for /f "tokens=1 delims=." %%a in ('echo !duration!') do set /a number=%%a
    for /f "tokens=1 delims=." %%a in ('echo !duration_intro!') do set /a number_intro=%%a

    set /A number_offset = !number! - !number_intro! - 1
    set /A number_offset = !number_offset! * 1000

    sof.exe "!hoppa!.nl.srt"

    if not exist DUTCH mkdir DUTCH

    for %%x in ("!hoppa!.nl.srt.fixed") do (
        if not %%~zx == 0 (
            if not  exist "DUTCH/!hoppa!.nl.mp4" (

            ffmpeg -y -hide_banner -i !input! -i intro.wav -i intro.wav -i pacman2.mp4 -loop 20 -filter_complex "[1]adelay=500|500[s1];[1]adelay=!number_offset!|!number_offset![s2];[0][s1][s2]amix=inputs=3;[0:v]scale=1920:1080[j];[3:v]split[m][a];[a]geq='lum(X,Y)',hue=s=0[al];[m][al]alphamerge[ovr];[ovr]scale=150:-1[sml];[j][sml]overlay=main_w-overlay_w-2:main_h-overlay_h-2[l];[l]subtitles='!hoppa!.nl.srt.fixed':force_style='FontName=Mada Black,FontSize=32,BackColour=&HA0000000,BorderStyle=4'[k]" -map "[k]" -map 0:a -strict -2 -c:v h264_nvenc -pix_fmt yuv420p -rc-lookahead 32 -b:v !bit_rate! -ac 2 -ar 44100 -acodec aac -shortest "DUTCH/!hoppa!.nl.PART.mp4"

rem             ffmpeg -y -hide_banner -i !input! -filter_complex "[0:v]scale=1920:1080[j];[j]subtitles='!hoppa!.nl.srt.fixed':force_style='FontName=Mada Black,FontSize=32'[k]" -map "[k]" -map 0:a -strict -2 -c:v h264_nvenc -pix_fmt yuv420p -rc-lookahead 32 -b:v !bit_rate! -ac 2 -ar 44100 -acodec aac "DUTCH/!hoppa!.nl.PART.mp4"
rem             ffmpeg -y -hide_banner -i !input! -filter_complex "[0:v]scale=1920:1080[j];[j]subtitles='!hoppa!.nl.srt.fixed'[k]" -map "[k]" -map 0:a -strict -2 -c:v h264_nvenc -pix_fmt yuv420p -rc-lookahead 32 -b:v !bit_rate! -ac 2 -ar 44100 -acodec aac "DUTCH/!hoppa!.nl.PART.mp4"
rem             ffmpeg -y -hide_banner -i !input! -filter_complex "[0:v]scale=1920:1080[j];[j]subtitles='!hoppa!.nl.srt.fixed'[k]" -map "[k]" -map 0:a -strict -2 -c:v libx264 -preset slow -crf 23 -pix_fmt yuv420p -b:v !bit_rate! -ac 2 -ar 44100 -acodec aac "DUTCH/!hoppa!.nl.PART.mp4"

            ) else (
                echo Already exists: "DUTCH/!hoppa!.nl.mp4" 
            )
        ) else (
            echo Subtitle file empty: !hoppa!.nl.srt.fixed
        )
    )

    if exist "DUTCH/!hoppa!.nl.PART.mp4" rename "DUTCH\!hoppa!.nl.PART.mp4" "!hoppa!.nl.mp4"

rem if not exist SUBTITLES mkdir SUBTITLES
rem if exist "!hoppa!.nl.srt.fixed" move "!hoppa!.nl.srt.fixed" SUBTITLES
rem if exist "!hoppa!.nl.srt" move "!hoppa!.nl.srt" SUBTITLES

rem remark (rem) goto for making second language
goto :ENDING

sof.exe "!hoppa!.en.srt"

if not exist ENGLISH mkdir ENGLISH

for %%x in ("!hoppa!.en.srt.fixed") do (
    if not %%~zx == 0 (
        if not  exist "ENGLISH/!hoppa!.en.mp4" (
            ffmpeg -y -hide_banner -i !input! -filter_complex "[0:v]scale=1920:1080[j];[j]subtitles='!hoppa!.en.srt.fixed'[k]" -map "[k]" -map 0:a -strict -2 -c:v h264_nvenc -pix_fmt yuv420p -rc-lookahead 32 -b:v !bit_rate! -ac 2 -ar 44100 -acodec aac "ENGLISH/!hoppa!.en.PART.mp4"
rem                 ffmpeg -y -hide_banner -i !input! -filter_complex "[0:v]scale=1920:1080[j];[j]subtitles='!hoppa!.en.srt.fixed'[k]" -map "[k]" -map 0:a -strict -2 -c:v libx264 -preset slow -crf 23 -pix_fmt yuv420p -b:v !bit_rate! -ac 2 -ar 44100 -acodec aac "ENGLISH/!hoppa!.en.PART.mp4"
        ) else (
            echo Already exists: "DUTCH/!hoppa!.en.mp4" 
        )
    ) else (
        echo Subtitle file empty: !hoppa!.en.srt.fixed
    )
)

if exist "ENGLISH/!hoppa!.en.PART.mp4" rename "ENGLISH\!hoppa!.en.PART.mp4" "!hoppa!.en.mp4"

rem     if exist "!hoppa!.en.srt.fixed" move "!hoppa!.en.srt.fixed" SUBTITLES >NUL
rem     if exist "!hoppa!.en.srt" move "!hoppa!.en.srt" SUBTITLES >NUL

:ENDING

if not exist ORIGINAL mkdir ORIGINAL
move !input! ORIGINAL >NUL
move "!hoppa!.*" ORIGINAL >NUL

exit /b

Если у вас есть файлы MP4, их можно объединить без потерь, сначала перепаковав их в транспортные потоки MPEG-2. С видео H.264 и аудио AAC можно использовать следующее:

ffmpeg -i input.mp4 -c copy -bsf:v h264_mp4toannexb -f mpegts intermediate.ts
ffmpeg -i "concat:intermediate.ts|intermediate.ts|intermediate.ts|intermediate.ts" -c copy -bsf:a aac_adtstoasc output.mp4

Простой метод, который позволяет избежать проблем, связанных с тем, какие команды работают с какой версией, является «тривиальным решением»:

ffmpeg -i input.mp4 -i input.mp4 -i input.mp4 -i input.mp4 -c copy output.mp4

См. также: https://trac.ffmpeg.org/wiki/Concatenate для множества примеров.

Это не делает никакой конкатенации. Должен использоваться хотя бы один из методов concat: протокол, фильтр или демультиплексор. В этой команде автоматическое сопоставление ffmpeg выберет один поток видео, один аудио и один поток субтитров из числа входных данных. Поскольку они идентичны, это эквивалентно первой команде OP.
Спасибо за тестирование этой Mulvya, так как она отличается от поведения, описанного в документации: ffmpeg.org/ffmpeg.html#Description - Если есть сходство в именах файлов, используйте "-i -i /tmp/test%d.mp4" ( и др.) также возможно.