Часто возникает отправить файл в виде стрима в сеть или преобразовать (перекодировать, масштабировать) некий входной видео-поток. Естество наше просит обратиться к каким-либо «свободным» (бесплатным) продуктам… поскольку оно ж ничего не стоит. И на поверхности тут лежит такое «явление» как ffmpeg.
Не будем греха таить, ffmpeg великолепный open-source продукт для медиа-траскодирования и стриминга. Он настолько хорош, что лежит в основе таких продуктов как CasparCG или fluesonic… и даже зашивается в железо бюджетных аппаратных стримеров,… например таких:
Нам доводилось пользоваться таким стримером и нам очень понравилось (как-то спокойнее работается чем с «софтовым» вариантом на базе PC или Raspberry). Но как говаривал Евстратий Палыч Мыльников своим филерам в «Статском советнике»: «А штуковина то в мелочах….»
И мелочь тут такая… ffmpeg ни при каких условиях не позволяет формировать файл или поток с постоянным битрейтом в кодеке h264 — то бишь в режиме CBR. Возможно кто-то скажет, что «это не правда» или «вы плохо читали форумы»… да, в настройках библиотеки x264 имеется ряд атрибутов, которые, вроде как (хотя на официальном сайте ffmpeg написано, что в их системе нет «native CBR mode»), должны устанавливать режим постоянного битрейта. В частности предлагается, например, использовать такую комбинацию параметров кодирования:
-x264opts nal-hrd=cbr:force-cfr=1 -b:v 2500k -minrate 2500k -maxrate 2500k -bufsize 100k
где:
nal-hrd=cbr — устанавливает эталонный декодера в режим CBR;
force-cfr=1 — принудительная генерация метки времени с постоянной частотой кадров;
-b:v — битрейт видео;
-minrate -maxrate — устанавливаются в то же значение что и общий битрейт;
-bufsize — размер буфера верификатора (VBV), рассчитывается для кодирования с ограниченным размером кадра по формуле (bufsize = bitrate / framerate).
Все это верно, но как ни старайся на статичных картинках или при затемнении между программами ffmpeg «жаждет» оптимизировать поток и снижает битрейт практически «до нуля». Кто-то резонно заметит «ну и Бог с ним…»
Так-то оно так, но при передаче потока на головную станцию кабельного тв желательно (а для некоторых моделей даже обязательно), чтобы битрейт был постоянный. Также при передаче IP-сетями по протоколу HTTP при помощи программы Cesbo Astra возникают «ложные обрывы» — срабатывание переключения Astra на резервный источник или выдачу Error'ов когда битрейт снижается ниже определенного уровня. Это «не есть хорошо» т.к. в эти моменты изображение или останавливается, или исчезает, или «рассыпается, чихает и заикается».
Что с этим делать?
По сути единственным разумным способом является наполнение потока стаффингами (NULL-TS пакетами), которые не содержат никакой полезной информации.
Закономерен вопрос: «Как наполнить поток стаффингами».
Вариант первый:…
Ряд сборок библиотеки x264 от ffmpeg имеет нативный атрибут -muxrate, который позволяет при мультиплексировании собирать поток с заданным битрейтом. Таким образом сам ffmpeg должен донаполнять сигнал NULL-TS пакетами. Однако очень многие сборки библиотек ffmpeg не обрабатывают атрибут -muxrate должным образом и требуемый эффект не достигается.
На помощь приходит второй подход:..
Данный метод требует наличия «на борту» медиасервера Cesbo Astra (последней бесплатной версии 4.* достаточно для решения данной задачи).
Суть подхода заключается в создании udp-кольца с наполнением потока стаффингами. Общую логическую схему можно изобразить таким образом:
где:
input — вход с ffmpeg'а;
Astra1 — первый рестример наполняющий поток стаффингами;
udp-output — промежуточный вывод фиктивного udp-потока с атрибутами sync&cbrX
Astra2 — второй рестример направляющий поток в необходимый формат (например HTTP);
input — выход в сеть;
Файл конфигурации первого рестримера будет иметь примерно следующее содержание:
make_channel({
name = "Make CBR",
input = {
"udp://192.168.1.1@239.0.0.1:1234", // входной поток без стаффингов
},
output = {
"udp://192.168.1.1@239.0.0.1:1235#sync&cbr=3", // «фиктивный» поток
}})
В свою очередь конфигурация второго рестримера может быть следующей:
make_channel({
name = "Channel CBR",
input = {
"udp://192.168.1.1@239.0.0.1:1235", // «фиктивный» поток
},
output = {
"http://0:8080/channel", // выходной поток со стаффингами
}})
Результатом работы данной цепочки будет медиапоток битрейт которого не будет опускаться ниже 3-х Мегабит в секунду и, соответственно, «ложных обрывов» на приеме быть не должно.
Кстати, для упрощения схемы, файлы конфигурации можно объединить и использовать одно запущенное приложение. Cesbo Astra отлично отрабатывает схему в виде петли, реализующей принцип «вещаю сам в себя»:
Важно помнить, что стаффинги идут в мультплексированном сигнале как отдельный элементарный поток со значением PID 8191. Поэтому в случае если вы производите переназначение меток программ или элементарных потоков (делаете «маппинг PID'ов») Cesbo Astra произведет отброс стаффингов и пересборку мультплекса без них, поэтому следует не забывать производить перезаполнение потока стаффингами после различных работ по модификации значений атрибутов мультиплексированных сигналов.