Как эффективно создать лучший палитра GIF из видео прямо из Интернета

778
Matteo Italia

В течение некоторого времени я использовал эту пару команд для преобразования фрагмента видео в анимированный GIF, ffmpegрассчитав для него наилучшую палитру:

ffmpeg -ss $START -i $IN_FILE -t $LENGTH -vf "fps=$FPS,scale=$WIDTH:-1:flags=lanczos,palettegen" palette.png ffmpeg -ss $START -i $IN_FILE -i palette.png -t $LENGTH -filter_complex "fps=$FPS,scale=$WIDTH:-1:flags=lanczos [x]; [x] [1:v] paletteuse" output.gif 

Это очень хорошо работает для локальных файлов, но если я начну использовать удаленные URL-адреса $IN_FILE, он загружает необходимую часть дважды - один раз для генерации палитры, один раз для фактического преобразования.

Предварительная загрузка полного файла вообще не подлежит обсуждению - часто меня интересует очень небольшая последовательность в середине более длинного видео.

Я попытался загрузить только небольшую часть, используя ее -ssи -tсохранив - без перекодирования - во временный файл:

ffmpeg -ss $START -i $IN_URL -t $LENGTH -vc copy -ac none temp.mkv 

В этом случае я избегаю потери пропускной способности (загружается только соответствующая часть файла и только один раз), но поиск уже не точен, так как -ssпри вводе имеет только гранулярность ключевых кадров для поиска при выполнении потокового копирования .

При теоретическом преобразовании в gif можно было бы выполнить дополнительный точный поиск и исправить это, но, похоже, нет способа получить исходную временную метку начала временного файла, сгенерированного выше, поэтому это невозможно рассчитать, где я должен -ssпри перекодировании в GIF. Я пытался поиграть -copy_ts, но ничего хорошего не получилось.

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

Итак: как я могу выполнить преобразование видео с наилучшей палитрой в gif небольшой части потенциально большого сетевого файла, эффективно извлекая его (= загрузить один раз, только соответствующую часть), с точным поиском и без дополнительного перекодирования?

1

1 ответ на вопрос

1
Matteo Italia

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

 .--> palettegen [pal]---. input / | [0:v] -> fps -> scale -> split=2 [a][b] V with `-> [b] fifo [b] -> [b] [pal] paletteuse -> out.gif precise seek 

что переводится как:

ffmpeg -ss $START -I $IN_URL -t $LENGTH -filter_complex "fps=$FPS,scale=$WIDTH:-1:flags=lanczos,split=2 [a][b]; [a] palettegen [pal]; [b] fifo [b]; [b] [pal] paletteuse" out.gif 

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

Редактировать :fifoбыл добавлен благодарякомментарию @Gyan ; это необходимо, потому чтоpalettegenнужно дождаться конца потока, прежде чем генерировать палитру, иpaletteuseне может начать потреблять,[b]прежде чем иметь палитру, следовательно, если видео достаточно велико, буферов по умолчанию для[b]будет недостаточно, иffmpegначнется отбрасывание кадров. Решение состоит в том, чтобы добавитьfifoпосередине для обработки буферизации произвольного размера (необходимо соблюдать осторожность, чтобы не превышать длину видео, так как буферизация всего потока в памяти может облагаться налогом на доступную оперативную память).

(бесстыдный плагин: эту команду я сейчас использую в своем боте tele2gif_bot tube )


Самое главное, это рассказ о понимании команд, которые вы используете ; вторая команда, приведенная в вопросе, уже использовала сложный фильтр графа, но, когда я слепо скопировал его из Интернета, я не пытался понять синтаксис непрозрачного фильтра графа, поэтому мне не пришло в голову, что я просто немного его подправил было бы лучшим решением.

Пользователям может потребоваться буферизовать 2-ю разделенную копию, поскольку palettegen по умолчанию возвращает палитру только после анализа всего потока. paletteuse, otoh, ждет, когда эта палитра начнет обработку. Таким образом, для более длинных потоков, чтобы избежать пропадания кадра из `[b]`, буферизуйте его так: `[b] fifo [b]; [b] [pal] ...` Gyan 6 лет назад 0
@Gyan: это еще одна вещь, которую я не знал, я думал, что фильтры сделали всю необходимую буферизацию сами! Я исправляю это немедленно. Matteo Italia 6 лет назад 0
В новых версиях они делают, вплоть до точки. Но ffmpeg также является потоковым приложением. Таким образом, в действительности существует порог падения. Gyan 6 лет назад 1

Похожие вопросы