Я просто хочу зациклить видео 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
... но я получаю сообщение об ошибке «Цикл опций не найден».
-stream_loop
вариантffmpeg -stream_loop 3 -i input.mp4 -c copy output.mp4
0
означает отсутствие цикла, -1
означает бесконечный цикл.Демультиплексор concat позволяет вам зацикливать ввод без необходимости повторного кодирования, поскольку он может использовать потоковое копирование .
Сделайте текстовый файл. Содержимое примера текстового файла повторить 4 раза.
file 'input.mp4'
file 'input.mp4'
file 'input.mp4'
file 'input.mp4'
Затем запустите 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
.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:
ffmpeg -i input -loop 3 output.gif
Для вывода GIF также см. Как преобразовать видео в GIF с помощью ffmpeg с приемлемым качеством?
> <(for i in {1..4}; do printf "file '%s'\n" input.mp4; done) -bash: /dev/fd/63: Permission denied
ffmpeg -i video.mp4 -filter_complex "loop=4:32767" output.mp4
-stream_loop
разделе ведет на тот же тикет, что и первый...-i %03d.png -t 30
и -t 30 -i %03d.png
? Я знаю, что при работе с видео вы обычно хотите -t
(и -ss
) перед вводом, чтобы сэкономить время на декодировании, но имеет ли это значение для изображений? Недавно я запускал некоторые команды -t
перед вводом, и все работало нормально.В ffmpeg 2.8.4 следующая команда создает output.mp4, который является повторяющейся копией input.mp4, пока процесс ffmpeg не будет остановлен:
ffmpeg -stream_loop -1 -i input.mp4 -c copy output.mp4
Эта команда не завершится сама по себе, и выходной файл будет расти бесконечно.
-1
некоторого положительного целого числа в соответствии с их требованиями. В противном случае файл увеличивается, и система выдает No space left on device
ошибку.По крайней мере, на 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.
-c copy
. Ответ исправлен.@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 для множества примеров.
Дмитрий Мышков