2012-04-28 2 views
3

Я пытаюсь выяснить, как указать конкретный список изображений, которые нужно преобразовать в видео. Я знаю, что мы можем сделать что-то вроде:Как указать список неупорядоченных изображений?

ffmpeg -i image_04%d.png 

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

Как я могу указать правильную последовательность ввода? Я по сути вызываю ffmpeg из кода, а не из командной строки. Таким образом, любые идеи об изменениях в коде также приветствуются.

Спасибо!

ответ

0

Ну, решение заключалось в том, чтобы исправить класс image2, чтобы поддерживать список с номерами, которые нужно выбрать. Затем я предоставил ffmpeg шаблон входного файла вместе с массивом чисел с указанным порядком для чтения ввода. Это сработало отлично.

+0

Но как вы передаете массив с номерами в ffmpeg? – Jimmy

+0

Эй @ Джимми, я на самом деле не помню, что я тогда делал. Я помню, как модифицировал исходный код ffmpeg для поддержки передачи числа чисел. Однако эта идея была ужасной и неэффективной. Я закончил писать код с нуля, который использует ffmpeg в качестве кодера. Насколько я знаю, нет простого способа. – Jona

+0

Спасибо за ответ, интересно, символические ссылки могут быть простым способом сделать это. Вы пробовали это? – Jimmy

0

Ваше приложение может создавать символические ссылки, начиная с 0001, которые уважают порядок исходных кадров, а затем передают эту последовательность в ffmpeg. Как только видео будет завершено, удалите символические ссылки, и все готово.

+0

Ах! Очень интересный подход. Android NDK Я считаю, есть поддержка для этого ... Ммм ... Мне нужно глубже вникать в вашу идею. :) – Jona

+0

см. Ответ выше для рабочего скрипта, который делает то, что предлагает Кевин –

2

Вот сценарий по идее Кевина, который работает для меня. Возможно, вы захотите заменить шаблон имени файла (shot * .png) и имя выходного файла movie.mp4. Все файлы frame_ ... удаляются скриптом по завершении.

# script to create movie from multiple png files 
# taken in choronoligcal order 

# start at 0 
count=0 
# take all files named shot - something ordered by date 
for f in `ls -rt shot*.png` 
do 
    # get the index in 0000 format 
    printf -v counts "%04d" $count 
    # link file to a frame_0000 named symbolic link 
    ln -s $f frame_$counts.png 
    # increment counter 
    count=`expr $count + 1` 
done 
# create movie 
# slowed down by factor 5 
# ffmpeg -f image2 -i frame_%04d.png -vcodec mpeg4 -vf "setpts=5*PTS" movie.mp4 
ffmpeg -i frame_%04d.png movie.mp4 
# remove the links 
rm frame_*.png 
0

Допустим, у нас есть список имен файлов в правильном порядке, как это:

frames=(
    "5K1OCNKToUu.png" "kJuKFQS0Fgnp.png" "00v4U4JTyUn.png" "3sg9sDwPZoX.png" 
    "1KsuEk9mboa9.png" "qNrI8zlRBmW.png" "MOvSca3wlPsP.png" "5rXcxfGQXunY.png" 
    "hjruIcoN0aTn.jpg" "OhRttnWtKy.png" "e2Qj8jCixc.png" "Uze2H7vzrt4.png" 
    "n14qhmjiBW3.png" "ZDMvY4g1hzgS.png" "ibnb7MxELyGp.png" "9c8QGWmBEDNg.png" 
    "STQT0t7oqPEK.png" "jI7UvpbLDWPc.png" "6clazeaUAJHv.png" "ylJ40r9uMK9d.png" 
    "RICq5KV00P6.png" "zjCLrappFMPq.png" "TJQTDv313KBo.png" "Gu3pLpWylsuo.png" 
    "Ksym4SB6VYNv.png" "rIyj0LJIjBVX.png" "pSUm2J8xYU.png" "Rnsr0H0m7p9A.png" 
    "x4vVomlOolxt.png" "2W1QURLQUyE8.png" "m3JgtDzQ0VgE.png" "CrjN9TVJKMAU.png" 
    "IO6pnF83ivqo.png" "hY15nsYDvr4h.png" "1GagDdBM9L7.png" 
) 

, и мы хотим создать анимированный GIF из них с определенной частотой кадров, например, FPS=30. Это можно сделать, как в других ответах, путем создания символических ссылок, например. названный 001.png к 035.png, а затем использовать:

ffmpeg -i 03%d.png 

Другой способ использовать ffmpeg «s concat-feature. К сожалению, это немного проще сказать, чем сделать, потому что функция ожидает видеопотоков, то есть изображения должны быть закольцованы до тех пор, пока это необходимо.

Команда сцепить три изображения с 500мс между ними заключается в следующем:

ffmpeg -f concat -safe 0 -i <(cat <<EOF 
file '$(pwd)/1KsuEk9mboa9.png' 
duration 0.5 
file '$(pwd)/hjruIcoN0aTn.png' 
duration 0.5 
file '$(pwd)/n14qhmjiBW3.png' 
duration 0.5 
EOF 
) -framerate 2 out.gif 

Испытано с ffmpeg version 3.0.1-3.

Объяснение:

  • concat demuxer ожидает файл со списком относительных имен файлов предваряется ключевым словом file. Чтобы не загромождать текущий рабочий каталог (или, возможно, у нас нет прав на запись), мы используем подпрограмму процесса <(...).Но это создает файл в /dev/fd/ и если используются относительные имена файлов, то это приводит к сообщениям об ошибках, как это:

    [concat @ 0xc181c0] Impossible to open '/dev/fd/5K1OCNKToUu.png' 
    

    Вот почему абсолютный путь дается. Но абсолютные пути не разрешены по умолчанию, в результате чего:

    [concat @ 0x17da1c0] Unsafe file name '/home/5K1OCNKToUu.png' 
    

    Для solve что -safe 0 используется.

  • При попытке указать частоту входного кадра с -r

    ffmpeg -f concat -safe 0 -r 2 -i <(cat <<EOF 
    file '$(pwd)/1KsuEk9mboa9.png' 
    file '$(pwd)/hjruIcoN0aTn.png' 
    file '$(pwd)/n14qhmjiBW3.png' 
    EOF 
    ) -framerate 2 out.gif 
    

    ошибок, как это происходит:

    [concat @ 0x1458220] DTS -230575710986777 < 0 out of order 
    DTS -230575710986777, next:40000 st:0 invalid dropping 
    PTS -230575710986777, next:40000 invalid dropping st:0 
    

    Результирующий GIF работает как ожидается, в любом случае. Использование опции durationconcat явно разрешает эти предупреждения/ошибки.

    Примечание комментарий для -r

    В качестве опции ввода, игнорировать любые временные метки, хранящиеся в файле и вместо генерировать временные метки, предполагая постоянную частоту кадров кадров в секунду. Этот не совпадает с опцией -framerate, используемой для некоторых форматов ввода , таких как image2 или v4l2 (в старых версиях FFmpeg она была прежней). Если есть сомнения, используйте -framerate вместо входного параметра -r.

    Мой взгляд на это, что вышеуказанные предупреждения от CONCAT, которые уведомляют о том, что он не мог найти длину игры для изображений, не приводят к плохому поведению, потому что фреймрейт вынужден после предупреждения Concat с -r, который работает, но может и не быть предназначенным способом. Я бы использовал это только при ручном написании команд ffmpeg, но не в скриптах.

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

function makeGif() { 
    local targetName=$1; shift 
    local FPS=$1; shift 
    # concat doesn't recognize .33 as returned by bc by default 
    local delay=$(bc <<< "scale=5; x=1/$FPS; if (x<1) print 0; x") 
    local list 
    for file in [email protected]; do 
     list+=$(printf "\nfile '$(pwd)/$file'\nduration $delay") 
    done 
    ffmpeg -f concat -safe 0 -i <(cat <<< "$list") -r $FPS "$targetName".gif 
    #ffmpeg -f concat -safe 0 -i <(cat <<< "$list") -r $FPS -c:v libx264 -crf 5 -pix_fmt yuv420p "$targetName".mkv 
} 
makeGif out 30 ${frames[@]} 

раскомментировать строки в коде выше, даст H264 закодированные MKV.

Гетерогенные типы изображений

Если список изображений содержит изображения различных типов, например, заменив hjruIcoN0aTn.png на hjruIcoN0aTn.jpg в frames, то это использование concat не будет работать. Изображения в других форматах, чем первые указания будут сброшены и бросать ошибки как:

[png @ 0x1ec8260] Invalid PNG signature 0xFFD8FFE000104A46. 
Error while decoding stream #0:0: Invalid data found when processing input 

В этом случае вам придется использовать concat filter вместо простого демультиплексора.Команда с тремя файлами из выше будет тогда быть изменен следующим образом:

ffmpeg \ 
-f image2 -loop 1 -thread_queue_size 4096 -framerate 30 -t 0.5 -i "$(pwd)/1KsuEk9mboa9.png" \ 
-f image2 -loop 1 -thread_queue_size 4096 -framerate 30 -t 0.5 -i "$(pwd)/hjruIcoN0aTn.jpg" \ 
-f image2 -loop 1 -thread_queue_size 4096 -framerate 30 -t 0.5 -i "$(pwd)/n14qhmjiBW3.png" \ 
-filter_complex 'concat=n=3:v=1 [vmerged]' \ 
-map '[vmerged]' -r 30 out.gif 

Объяснение:

  • Каждые опции, используемые объясняется очень хорошо here. Обратите внимание, что опция -framerate специфична для image importer и по крайней мере технически отличается от -r, практически в этом случае они дают одинаковые результаты.

  • -thread_queue_size представляется необходимым, поскольку мы расширяем одно изображение в течение довольно длительного 500мс, в результате этих сообщений об ошибке:

    [image2 @ 0x18856e0] Thread message queue blocking; consider raising the thread_queue_size option (current value: 8) 
    [image2 @ 0x188a100] Thread message queue blocking; consider raising the thread_queue_size option (current value: 8) 
    [image2 @ 0x188b9e0] Thread message queue blocking; consider raising the thread_queue_size option (current value: 8) 
    

    Описание варианта дал мне повод думать, что слишком большой задержка виновата:

    размер -thread_queue_size (вход) Этот параметр устанавливает максимальное число пакетов, поставленных в очередь при чтении из файла или устройства. При низких потоках с задержкой/высокой скоростью передачи, пакеты могут быть отброшены, если они не будут прочитаны своевременно; повышение этого значения может избежать этого.

Собираем все это в сценарий еще раз:

function makeGif() { 
    local targetName=$1; shift 
    local FPS=$1; shift 
    local delay=$(bc <<< "scale=5; x=1/$FPS; if (x<1) print 0; x") 
    local list=() 
    local nFiles=0 
    for file in [email protected]; do 
     list+=(-f image2 -loop 1 -thread_queue_size 4096 -framerate $FPS -t $delay -i "$(pwd)/$file") 
     nFiles=$((nFiles+1)) 
    done 
    ffmpeg ${list[@]} -filter_complex "concat=n=$nFiles:v=1 [vmerged]" -map '[vmerged]' -r $FPS "$targetName".gif 
    #ffmpeg ${list[@]} -filter_complex "concat=n=$nFiles:v=1 [vmerged]" -map '[vmerged]' -r $FPS -c:v libx264 -crf 5 -pix_fmt yuv420p "$targetName".mkv 
} 
makeGif out 30 ${frames[@]} 

По какой-то очень странной причине вышеприведенная команда не работает, как это !!!. В моем случае она упала 33 из 35 кадров, указанных без предупреждения или сообщения об ошибке:

frame= 2 fps=0.0 q=-0.0 Lsize=  2kB time=00:00:00.07 bitrate= 179.7kbits/s dup=0 drop=33 speed=0.155x 

Причина, по которой это странно в том, что она прекрасно работает как предназначены для двойной задержки, т.е. каждое изображение показано 2 кадра, т.е. изменение 1/$FPS в 2/$FPS:

frame= 70 fps=0.0 q=-0.0 Lsize=  701kB time=00:00:02.33 bitrate=2465.4kbits/s speed= 2.9x 

Этот факт говорит о простом обходном пути: кодирование с двойной частотой кадров и отображать каждое изображение в течение 2 кадров. Но это расточительно и не очень выгодно.

+0

Вы можете использовать частоту кадров с concat demuxer '-f concat -framerate N -i ...' – Mulvya

+0

@Mulvya Кажется, что это не работает с моей версией ffmpeg. Я получаю 'Option framerate not found.' при смене' ffmpeg -f concat -safe 0' на 'ffmpeg -f concat -framerate $ FPS -safe 0' в моем ответе. (FPS = 30) – mxmlnkn

+0

Нет, вы правы. Я забыл. Я думал о image2pipe. – Mulvya

Смежные вопросы