При подготовке потока для воспроизведения DASH точки произвольного доступа должны быть в одно и то же время исходного потока во всех потоках. Обычный способ сделать это - принудительно установить фиксированную частоту кадров и фиксированную длину GOP (то есть ключевой кадр каждые N кадров).
В FFmpeg фиксированная частота кадров проста (-r НОМЕР).
Но для фиксированных местоположений ключевых кадров (длина GOP) есть три метода ... какой из них "правильный"? Документация FFmpeg разочаровывающе расплывчата по этому вопросу.
Способ 1: возиться с аргументами libx264
-c:v libx264 -x264opts keyint=GOPSIZE:min-keyint=GOPSIZE:scenecut=-1
Кажется, что есть некоторые споры, следует ли отключить сценарное отключение или нет, так как неясно, перезапускается ли «счетчик» ключевого кадра, когда происходит вырезка сцены.
Способ 2: установка фиксированного размера GOP:
-g GOP_LEN_IN_FRAMES
К сожалению, это только задокументировано в документации FFMPEG, и, следовательно, эффект этого аргумента очень неясен.
Способ 3: вставлять ключевой кадр каждые N секунд ( может быть? ):
-force_key_frames expr:gte(t,n_forced*GOP_LEN_IN_SECONDS)
Это является явным образом задокументировано. Но до сих пор неясно, перезапускается ли «счетчик времени» после каждого ключевого кадра. Например, в ожидаемой 5-секундной GOP, если scenecut
ключевой кадр введен через 3 секунды с помощью libx264, будет ли следующий ключевой кадр спустя 5 секунд или через 2 секунды?
Фактически, документация FFmpeg различает эту -g
опцию и опцию, но на самом деле это не говорит о том, как эти две опции выше всего отличаются друг от друга (очевидно, -g
для этого потребуется фиксированная частота кадров).
Какой правильный?
Казалось бы, что -force_key_frames
будет лучше , так как это не потребует фиксированной частоты кадров. Однако для этого необходимо, чтобы
- соответствует спецификации GOP в H.264 ( если есть )
- он ГАРАНТИРУЕТ, что в фиксированной каденции будет ключевой кадр, независимо от ключевых
scenecut
кадров libx264 .
Также может показаться, что это -g
не может работать без принудительной установки фиксированной частоты кадров ( -r
) , поскольку нет гарантии, что несколько прогонов ffmpeg
с разными аргументами кодека обеспечат одинаковую мгновенную частоту кадров в каждом разрешении. Фиксированная частота кадров может снизить производительность сжатия (ВАЖНО в сценарии DASH!).
Наконец, метод только кажется , как взломать . Я надеюсь против надежды, что это не правильный ответ.keyint
Ссылки:
Пример использования -force_key_frames
метода
источник
ffprobe -i input.mp4 -select_streams v -show_frames -of csv -show_entries frame=pict_type
, затем раскрасив ячейки. Боюсь, что нет публичных обсуждений, но я посмотрю, смогу ли я найти некоторые ссылки, которые я нашел тогда.-force_key_frames expr:gte(t,n_forced*GOP_LEN_IN_SECONDS)
формой? Я только попробовал это и обнаружил, что, хотя в потоке были дополнительные I-кадры, он, похоже, соблюдал мое правило. Программа PERL будет следовать за «ответом», поскольку вы, очевидно, не можете использовать разметку в комментариях.-force_key_frames
у меня ничего не получалось, и поэтому я больше никогда не пробовал. Это было больше года назад. Возможно, это была ошибка. Я попробую еще раз скоро.Вот мои пятьдесят центов за дело.
Генерируйте фреймы только с желаемыми интервалами.
Пример 1:
Создайте фреймы, как и ожидалось, вот так:
Способ 2 амортизируется. Пропущены.
Пример 2
Создайте iframes немного по-другому:
Как вы можете видеть, он помещает фреймы каждые 2 секунды И на сцену (секунды с плавающей частью), что, на мой взгляд, важно для сложности видеопотока.
Размеры сгенерированных файлов практически одинаковы. Очень странно, что даже с большим количеством ключевых кадров в методе 3 он генерирует иногда меньше файлов, чем стандартный алгоритм библиотеки x264.
Для генерации файлов с несколькими битрейтами для потока HLS мы выбираем метод три. Он идеально согласован с 2 секундами между чанками, у них есть iframe в начале каждого чанка, и у них есть дополнительные iframe на сложных сценах, что обеспечивает лучший опыт для пользователей, которые имеют устаревшие устройства и не могут воспроизводить высокие профили x264.
Надеюсь, это кому-нибудь поможет.
источник
Таким образом, ответ выглядит так:
libx264
работоспособность , но он специфичен и стоит за счет исключения очень полезнойscenecut
опции вlibx264
.-g
кажется, не рекомендуется. Он не работает, не определен явно в документации, не найден в справке и не используется в коде. Проверка кода показывает, что эта-g
опция, вероятно, предназначена для потоков MPEG-2 (есть даже разделы кода, ссылающиеся на PAL и NTSC!).Также:
Скрипт для
-force_key_frames
вариантаВот короткая программа на Perl, которую я использовал для проверки частоты вращения I-кадров на основе вывода из предложения slhck's ffprobe. Кажется, чтобы убедиться, что
-force_key_frames
метод также будет работать, и имеет дополнительное преимущество учетаscenecut
кадров. Я абсолютно не представляю, как FFMPEG делает эту работу, или я просто так повезло, потому что мои потоки оказываются хорошо подготовленными.В моем случае я кодировал со скоростью 30 кадров в секунду с ожидаемым размером GOP 6 секунд или 180 кадров. Я использовал 180 в качестве аргумента gopsize, чтобы эта программа проверяла I-кадр при каждом кратном 180, но установка его в 181 (или любое другое число, не кратное 180) заставила его жаловаться.
источник
force_key_frames
, он как бы портит алгоритм распределения битов x264, поэтому он может дать вам худшее качество, чем просто установка фиксированного интервала ключевых кадров.-g
, вы говорите: «Кажется, он не работает, и не используется в коде». Я проверил и входg
хранится вavctx->gop_size
и что libx264 использует его:x4->params.i_keyint_max = avctx->gop_size;
. Когда я проверяю этот сгенерированный тестовый файл:,ffmpeg -i a-test-file.mp4 -g 37 -t 15 gtest.mp4
я точно получаю ключевые кадры0,37,74,111,148,185,222,259,296,333,370
. GOP может быть прерван, если смена сцены вызвана, и для этого-sc_threshold
может быть установлено, что также подхватывается x264.Я хотел добавить сюда некоторую информацию, так как мой поиск в Google потянул это обсуждение довольно много в моем стремлении найти информацию о попытке найти способ сегментировать мою DASH-кодировку так, как я хотел, и ни одна из найденных мной сведений не была полностью правильной.
Первые несколько заблуждений, чтобы избавиться от:
Не все I-кадры одинаковы. Есть большие рамки "я" и маленькие рамки "я". Или использовать правильную терминологию, I-кадры IDR и I-кадры не-IDR. I-кадры IDR (иногда называемые «ключевыми кадрами») создадут новую GOP. Кадры без IDR не будут. Их удобно иметь внутри GOP, где происходит смена сцены.
-x264opts keyint=GOPSIZE:min-keyint=GOPSIZE
← Это не делает то, что вы думаете, что делает. Это заняло у меня некоторое время, чтобы понять. Оказывается,min-keyint
это ограничено в коде. Это не может быть больше, чем(keyint / 2) + 1
. Таким образом, присвоение одного и того же значения этим двум переменным приводит к тому,min-keyint
что при кодировании значение будет сбито наполовину.Вот в чем дело: вырезка сцены действительно великолепна, особенно в видео, где есть быстрые переходы. Он сохраняет его красивым и четким, поэтому я не хочу его отключать, но в то же время я не мог получить фиксированный размер GOP, пока он был включен. Я хотел включить вырезку сцены, но использовать только I-кадры без IDR. Но это не сработало. Пока я не выяснил (из большого количества чтения) о заблуждении № 2.
Оказывается, мне нужно
keyint
было удвоить желаемый размер GOP. Это означает, чтоmin-keyint
можно установить желаемый размер GOP (без внутреннего кода, обрезающего его пополам), что предотвращает обнаружение среза сцены от использования I-кадров IDR внутри размера GOP, поскольку количество кадров с момента последнего I-кадра IDR равно всегда меньше чемmin-keyinit
.И, наконец, установка
force_key_frame
параметра отменяет двойной размерkeyint
. Итак, вот что работает:Я предпочитаю сегменты по 2 секунды, поэтому мой GOPSIZE = Framerate * 2
Вы можете проверить, используя ffprobe:
В сгенерированном CSV-файле каждая строка сообщит вам
frame, [is_an_IDR_?], [frame_type], [frame_number]
:В результате вы должны видеть I-кадры IDR только с фиксированными
GOPSIZE
интервалами, в то время как все другие I-кадры являются I-кадрами не-IDR, вставленными по мере необходимости при обнаружении перехода сцены.источник
Кажется, что этот синтаксис не всегда работает. Я довольно много тестировал наш VOD-контент, а также живой контент (дампы файлов), и иногда scenecut не работает и запускает промежуточный iframe:
Синтаксис для преобразования с повышением частоты i50-> p50, 2-х секундный переход / сегмент, IDR в начале, промежуточные фреймы при необходимости
источник
У Twitch есть пост об этом. Они объясняют, что решили использовать собственную программу по нескольким причинам; одна из них заключалась в том, что ffmpeg не позволяет запускать разные экземпляры x264 в разных потоках, а вместо этого посвящает все указанные потоки одному кадру в одном выводе, прежде чем переходить к следующему выводу.
Если вы не делаете потоковую передачу в реальном времени, у вас больше роскоши. «Правильный» способ - это, вероятно, кодировать в одном разрешении только с размером GOP, указанным с -g, а затем кодировать другие разрешения, заставляя ключевые кадры в тех же местах.
Если вы хотите это сделать, вы можете использовать ffprobe, чтобы получить время ключевого кадра, а затем использовать сценарий оболочки или реальный язык программирования, чтобы преобразовать это в команду ffmpeg.
Но для большей части контента очень мало различий между наличием одного ключевого кадра каждые 5 секунд и двух ключевых кадров каждые 5 секунд (один принудительный, а другой из сцены). Это примерно средний размер I-кадра по сравнению с размером P-кадров и B-кадров. Если вы используете x264 с типичными настройками (единственная причина, по которой я думаю, что вы должны что-то сделать, чтобы повлиять на них, это если вы установите -qmin, как плохой способ запретить x264 использовать битрейт для простого контента; это ограничивает все типы кадров одним и тем же значением Я думаю) и получу такой результат, как средний размер I-кадра 46 кБ, P-кадр 24 кБ, B-кадр 17 кБ (в два раза меньше P-кадров), а затем дополнительный I-кадр каждую секунду со скоростью 30 кадров в секунду только 3% увеличение размера файла. Разница между h264 и h263 может состоять из 3% снижений, но одно не очень важно.
Для других типов контента размеры фреймов будут другими. Чтобы быть справедливым, речь идет о временной сложности, а не пространственной сложности, поэтому это не просто легкий контент против жесткого контента. Но, как правило, сайты потокового видео имеют ограничение по битрейту, а контент с относительно большими I-кадрами - это простой контент, который будет кодироваться с высоким качеством независимо от того, сколько дополнительных ключевых кадров добавлено. Это расточительно, но эти отходы обычно не будут замечены. Наиболее бесполезным случаем, вероятно, является видео, представляющее собой статичное изображение, сопровождающее песню, где каждый ключевой кадр точно такой же.
Одна вещь, в которой я не уверен, это то, как принудительные ключевые кадры взаимодействуют с ограничителем скорости, установленным с -maxrate и -bufsize. Я думаю, что даже у YouTube недавно были проблемы с правильной настройкой параметров буфера для обеспечения постоянного качества. Если вы просто используете настройки среднего битрейта, как это видно на некоторых сайтах (поскольку вы можете проверить параметры x264 в заголовке / атоме mov с помощью шестнадцатеричного редактора), тогда модель буфера не является проблемой, но если вы При работе с пользовательским контентом средняя скорость передачи битов побуждает пользователей добавлять черный экран в конце своего видео.
Параметр -g в Ffmpeg или любой другой используемый вами параметр кодировщика сопоставляется с параметром, специфичным для кодировщика. Таким образом, ключ -x264-params = GOPSIZE эквивалентен ключу -g GOPSIZE.
Одна из проблем, связанных с использованием обнаружения сцен, заключается в том, что вы предпочитаете ключевые кадры рядом с конкретными номерами по любой причине. Если вы определяете ключевые кадры каждые 5 секунд и используете обнаружение сцены, и происходит изменение сцены на 4,5, то это должно быть обнаружено, но тогда следующий ключевой кадр будет на 9,5. Если время будет увеличиваться, как это, вы можете получить ключевые кадры в 42,5, 47,5, 52,5 и т. Д. Вместо 40, 45, 50, 55. И наоборот, если в 5,5 произойдет изменение сцены, то будет ключевой кадр на 5 и 5,5 будет слишком рано для другого. Ffmpeg не позволяет вам указать «создайте ключевой кадр здесь, если в течение следующих 30 кадров не произойдет смена сцены». Однако тот, кто понимает C, может добавить эту опцию.
Для видео с переменной частотой кадров, когда вы не транслируете в прямом эфире, как Twitch, вы должны иметь возможность использовать изменения сцены без постоянного преобразования в постоянную частоту кадров. Если вы используете фильтр 'select' в ffmpeg и используете константу 'scene' в выражении, то вывод отладки (-v debug или несколько раз нажмите '+' во время кодирования) показывает номер изменения сцены. Вероятно, это отличается от числа, используемого x264, и не так полезно, но все же может быть полезным.
Процедура, вероятно, будет состоять в том, чтобы сделать тестовое видео, которое предназначено только для изменений ключевого кадра, но, возможно, может быть использовано для данных контроля скорости при использовании 2-проходного. (Не уверен, что сгенерированные данные вообще полезны для разных разрешений и настроек; данные дерева макроблоков не будут.) Преобразуйте их в видео с постоянной частотой кадров, но посмотрите эту ошибку о заикании вывода при уменьшении частоты кадров вдвое, если вы когда-нибудь решите использовать фильтр fps для других целей. Запустите его через x264 с нужным ключевым кадром и настройками GOP.
Затем просто используйте это время ключевого кадра с исходным видео с переменной частотой кадров.
Если вы допускаете совершенно сумасшедший пользовательский контент с 20-секундным промежутком между кадрами, то для кодирования с переменной частотой кадров вы можете разделить вывод, использовать фильтр fps, каким-то образом использовать фильтр выбора (возможно, создать действительно длинное выражение, которое имеет каждый ключевой кадр) ... или, возможно, вы можете использовать тестовое видео в качестве входных данных и либо декодировать только ключевые кадры, если эта опция ffmpeg работает, либо использовать фильтр выбора для выбора ключевых кадров. Затем масштабируйте его до нужного размера (для этого есть даже фильтр scale2ref) и наложите на него оригинальное видео. Затем используйте фильтр чередования, чтобы объединить эти обязательные ключевые кадры с исходным видео. Если это приводит к двум кадрам, которые находятся на расстоянии 0,001 секунды друг от друга, что не мешает фильтру чередования, то решите эту проблему самостоятельно с помощью другого фильтра выбора. Работа с ограничениями кадрового буфера для фильтра чередования может быть главной проблемой здесь. Все это может работать: использовать какой-то фильтр для буферизации более плотного потока (fifo filter?); обращайтесь к входному файлу несколько раз, чтобы он декодировался более одного раза, и кадры не нужно сохранять; использовать фильтр streamselect, который я никогда не делал, точно в моменты ключевых кадров; улучшить фильтр чередования, изменив его поведение по умолчанию или добавив опцию для вывода самого старого кадра в буфер вместо удаления кадра. что я никогда не делал, точно в моменты ключевых кадров; улучшить фильтр чередования, изменив его поведение по умолчанию или добавив опцию для вывода самого старого кадра в буфер вместо удаления кадра. что я никогда не делал, точно в моменты ключевых кадров; улучшить фильтр чередования, изменив его поведение по умолчанию или добавив опцию для вывода самого старого кадра в буфер вместо удаления кадра.
источник