1

В течение некоторого времени я использовал эту пару команд для преобразования фрагмента видео в анимированный 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

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

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


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

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .