FFMPEG производительность нескольких выходов (один экземпляр против нескольких экземпляров)

2831
shalin

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

Вот сценарии, которые я пытаюсь описать в википедии ffmpeg для создания нескольких выходов. https://trac.ffmpeg.org/wiki/Creating%20multiple%20outputs

Сценарий 1 (с использованием одного экземпляра ffmpeg)

ffmpeg -i input.mp4 \

-фильтр: v обрезать = iw / 2: ih / 2: 0: 0 -c: v libx264 -b: v 5M out_1.mp4 \

-фильтр: v обрезать = iw / 2: ih / 2: iw / 2: 0 -c: v libx264 -b: v 5M out_2.mp4 \

-фильтр: v обрезать = iw / 2: ih / 2: 0: ih / 2 -c: v libx264 -b: v 5M out_3.mp4

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

Сценарий 2 (использование нескольких экземпляров ffmpeg и, следовательно, трех отдельных процессов)

ffmpeg -i input.mp4 -filter: v crop = iw / 2: ih / 2: 0: 0 -c: v libx264 -b: v 5M out_1.mp4

ffmpeg -i input.mp4 -filter: v crop = iw / 2: ih / 2: iw / 2: 0 -c: v libx264 -b: v 5M out_2.mp4

ffmpeg -i input.mp4 -filter: v crop = iw / 2: ih / 2: 0: ih / 2 -c: v libx264 -b: v 5M out_3.mp4

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

Теперь, с точки зрения производительности fps, я вижу, что сценарий 2 работает лучше. Он также использует процессор по максимуму (загрузка процессора более 95%). В сценарии 1 меньше кадров в секунду, а загрузка ЦП намного ниже (около 65%). Кроме того, в этом случае, когда я увеличиваю количество потоков, которые должны быть закодированы, загрузка ЦП не увеличивается линейно. это почти в 1,5 раза, когда я иду от одного потока к двум. Но после этого приращения очень низкие (вероятно, 10% и даже меньше с большим количеством потоков).

Итак, мой вопрос: я хочу использовать один экземпляр ffmpeg, потому что он позволяет избежать многократного декодирования, а также, потому что мой ввод может быть как 4K или даже больше. Что я должен сделать, чтобы улучшить загрузку ЦП (> 90%) и, следовательно, улучшить производительность fps? Кроме того, почему загрузка ЦП не увеличивается линейно с количеством потоков, которые должны быть закодированы? Почему один экземпляр ffmpeg не работает так же хорошо, как несколько экземпляров? Мне кажется, что с одним экземпляром ffmpeg все кодировки действительно не работают параллельно.

Изменить: Вот самый простой способ, которым я могу воспроизвести и объяснить проблему, если все не так ясно. Имейте в виду, что это только для экспериментальных целей, чтобы понять проблему.

Одиночный экземпляр: ffmpeg -y -i input.mp4 -c: v libx264 -x264opts threads = 1 -b: v 1M -f ноль - -c: v libx264 -x264opts потоков = 1 -b: v 1M -f ноль - - c: v libx264 -x264opts threads = 1 -b: v 1M -f ноль -

Несколько экземпляров: ffmpeg -y -i input.mp4 -c: v libx264 -x264opts threads = 1 -b: v 1M -f ноль - | ffmpeg -y -i input.mp4 -c: v libx264 -x264opts threads = 1 -b: v 1M -f ноль - | ffmpeg -y -i input.mp4 -c: v libx264 -x264opts threads = 1 -b: v 1M -f ноль -

Обратите внимание, что я ограничиваю x264 одним потоком. В случае одного экземпляра я бы ожидал, что ffmpeg сгенерирует 1 поток кодирования для каждого кодирования x264 и выполнит их параллельно. Но я вижу, что полностью используется только одно ядро ​​процессора, что заставляет меня поверить, что одновременно выполняется только один сеанс кодирования. С другой стороны, в случае нескольких экземпляров, я вижу, что три ядра процессора полностью используются, что, я думаю, означает, что все три кодировки работают параллельно.

Я действительно надеюсь, что некоторые эксперты могут подключиться и помочь с этим.

5
Кстати, я провел обширный поиск по вышеуказанной теме, и ни один из постов не говорит о том, почему отдельный экземпляр не работает так хорошо. самый близкий пост, который я мог найти, был этот (https://stackoverflow.com/questions/12465914/how-to-optimize-ffmpeg-w-x264-for-multiple-bitrate-output-files), но без вида детали, которые я ищу. shalin 6 лет назад 0

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

1
aergistal

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

Идея состоит в том, чтобы сделать преобразование формата пикселя один раз, если это возможно, например:

-filter_complex '[0:v]format=yuv420p, split=3[s1][s2][s3]' \ -map '[s1]' ... \ -map '[s2]' ... \ -map '[s3]' ... \ 

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

По другим причинам смотрите небольшую заметку внизу вики :

Параллельное кодирование

Вывод и повторное кодирование несколько раз в одном и том же процессе FFmpeg обычно замедляют работу до «самого медленного кодера» в вашем списке. Некоторые кодировщики (например, libx264) выполняют свое кодирование «в потоке и в фоновом режиме», поэтому они эффективно допускают параллельное кодирование, однако аудиокодирование может быть последовательным и стать узким местом и т. Д. Похоже, что если у вас есть какие-либо последовательные кодировки, FFmpeg будет рассматривать его как «настоящий серийный», и, следовательно, ваш FFmpeg может использовать не все доступные ядра.

0
Akumaburn

Я сам заметил это с небольшим размером видео / буфера по умолчанию.

Попробуйте увеличить размер буфера до 50M или до половины размера файла, в зависимости от того, что меньше.

Также обратите внимание, что параметр bufsize обозначается в единицах k, так что это будет что-то вроде -bufsize 50000k

поэтому я изменил командную строку, добавив bufsize следующим образом: ffmpeg -i input.mp4 -filter: v crop = iw / 2: ih / 2: 0: 0 -c: v libx264 -b: v 5M ** - bufsize 50000k ** out_1.mp4 -фильтр: v обрезать = iw / 2: ih / 2: iw / 2: 0 -c: v libx264 -b: v 5M ** - bufsize 50000k ** out_2.mp4 -фильтр: v crop = iw / 2: ih / 2: 0: ih / 2 -c: v libx264 -b: v 5M ** - bufsize 50000k ** out_3.mp4 **, но я не вижу какого-либо улучшения производительности fps или процессора использование ** shalin 6 лет назад 0
Странно, но использование процессора значительно улучшилось с увеличением размера буфера. Какова продолжительность вашего видеофайла / размер файла? Akumaburn 6 лет назад 0
Я пробовал это в зависимости от размера файла (от 100 МБ до 1 ГБ) и длительности (от 1 минуты до 10 минут). Я действительно не понимаю, почему размер файла / продолжительность будет иметь какое-либо влияние на это. Разрешение входного кадра, которое я пробовал, составляет 1080p, 4K и выше. shalin 6 лет назад 1
Я проверял это сам, непосредственно с libx264, хотя и не через командную строку ffmpeg. Может быть, ffmpeg ожидает другой формат? Что произойдет, если вы попробуете -bufsize 50M, какая разница? Akumaburn 6 лет назад 0
0
flolilolilo

Я не могу воспроизвести вашу проблему. Настроить:

  • Последний Zeranoe static-build
  • Win10 pro
  • Процессор Intel i5-4210U (4 ядра, без HT)
  • 8 ГБ оперативной памяти DDR3
  • R / W к внутреннему SSD реактора Мушкина 1 ТБ
  • Видео для воспроизведения: http://ftp.halifax.rwth-aachen.de/blender/demo/movies/ToS/ToS-4k-1920.mov ( -ss 00:01:00.000 -to 00:01:25.000потому что рендеринг всего этого, очевидно, займет вечность)

Мой код в Powershell:

# Measure time of FFMPEG process $time = Measure-Command{ ffmpeg -ss 00:01:00.000 -i .\ToS-4k-1920.mov ` -to 00:00:25.000 -c:v libx264 -b:v 5M -y .\out_1.mp4 ` -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_2.mp4 ` -to 00:00:25.000 -vf "crop=iw/2:ih/2:0:ih/2" -c:v libx264 -b:v 5M -y .\out_3.mp4 ` -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_4.mp4 ` -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_5.mp4 ` -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_6.mp4 ` -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_7.mp4 ` -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_8.mp4 ` -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_9.mp4 ` -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_10.mp4 ` -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_11.mp4 ` -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_12.mp4 ` -to 00:00:25.000 -vf "crop=iw/2:ih/2:0:0" -c:v libx264 -b:v 5M -y .\out_13.mp4 ` -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_14.mp4 ` -to 00:00:25.000 -vf "crop=iw/2:ih/2:0:ih/2" -c:v libx264 -b:v 5M -y .\out_15.mp4 ` -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_16.mp4 ` -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_17.mp4 ` -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_18.mp4 ` -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_19.mp4 ` -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_20.mp4 ` -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_21.mp4 ` -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_22.mp4 ` -to 00:00:25.000 -c:v libx264 -b:v 5M -y .\out_23.mp4 ` -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_24.mp4 }  Write-Host "Time spent: $time" 

Результат:

  • $time: 00: 05: 52.7747482
  • Скорость ffmpeg: speed=0.0711x

Оба значения кажутся мне разумными.

Даже 24 параллельных выхода здесь не показывают никаких проблем - процессор остается на уровне> 95% для всего процесса, почти не используется SSD (<5%) и ~ 75% оперативной памяти (на холостом ходу ~ 30% используются). (Проверенные вручную значения через Task-Manager)

Так что здесь есть несколько возможностей:

  • Вы используете старую версию FFmpeg
  • Что-то еще (HDD, RAM) является узким местом
  • Что-то не так с вашим файлом - я думаю, вряд ли
  • Что-то не так с вашим процессором - столь же маловероятно, поскольку вы заявляете, что он работает на полную мощность при использовании нескольких экземпляров ffmpeg)
  • попробуйте разные значения -threadsв вашем коде и посмотрите, будет ли это иметь значение.
Я использую облачный экземпляр Google с 64 процессорами и 416 ГБ оперативной памяти. Таким образом, мы можем легко исключить проблемы с процессором, оперативной памятью, жесткими дисками и т. Д. Я использовал это некоторое время, и у него очень стабильная и надежная производительность для всех тестов. У меня была версия FFMPEG, которой было около 6 месяцев, и я также попробовал последнюю версию 3.3.2, но это не помогло. Кроме того, я попытался изменить количество потоков без какого-либо успеха. shalin 6 лет назад 0
Теперь вернемся к основному обсуждению, я попытался запустить вашу командную строку. При этом я получаю около 12 кадров в секунду при загрузке процессора менее 50%. Но когда я запускаю каждое кодирование как отдельный процесс ffmpeg, я могу приблизиться к 30 кадрам в секунду при почти 100% загрузке процессора. Помните, что у меня 64 ядра, поэтому рабочая нагрузка должна быть действительно параллельной и требовать значительных вычислительных ресурсов для полного использования. В вашем случае легко достичь 100% процессора, потому что у вас всего 4 ядра. shalin 6 лет назад 1
Конечно, вы правы в том, что мои 4-ядерные установки не сопоставимы с вашими 64-ядерными - извините, я полностью пропустил предложение, объясняющее это. Примерно через 72 часа я смог протестировать его на процессоре i7-5820k, но я думаю, что это тоже не совсем сравнимо и потому бесполезно. Вы пробовали это с вышеупомянутым файлом? Кроме того, `-an` что-то меняет? Кроме этого, у меня нет идей - извините ... flolilolilo 6 лет назад 0
да, я попробовал это с файлом, который вы мне дали. также -не ничего не меняет. Спасибо, что уделили нам время на это. shalin 6 лет назад 0
Кстати, если у вас есть время, вы можете зайти в раздел «Правка» моего первоначального вопроса и попробовать оба варианта с вашим входным файлом. Я уверен, что вы можете воспроизвести то, что я пытаюсь объяснить, на вашей 4-х базовой платформе. shalin 6 лет назад 0
Я проверил это и могу воспроизвести проблему с `-x264opts threads = 1`, однако этого следует ожидать, так как это уменьшает потоки. Как правило, следует использовать 1 поток на ядро ​​(или более). Я позволил PowerShell создать несколько CSV с начальным и конечным временем тестов и RAM- + CPU-stats - это огромная куча данных. Я подал его на диаграмму в Excel и обнаружил, что: a) потоки `x264opts` более" эффективны ", чем` -threads`; б) все, что выше 1 потока, по крайней мере, имеет шансы получить 100% ЦП; в) больше потоков = больше используемой оперативной памяти d) авто (то есть ничего не сообщая о потоках) работает довольно хорошо. flolilolilo 6 лет назад 0
(больше не могу редактировать мой последний комментарий). Но я знаю, что вы это знаете. Я был бы очень рад распространить свои результаты тестов (тем временем, я даже запустил их на своих 5820k), но я не знаю, как это сделать в рамках superuser.com, так как одна диаграмма должна быть 200cm Широкий, чтобы увидеть что-то ... flolilolilo 6 лет назад 0

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