Как отобразить статическое изображение, если входной поток заканчивается с помощью ffmpeg?

Я получаю поток по сети с помощью следующей команды ffmpeg:

ffmpeg -i rtmp://server:port/input.stream -f flv rtmp://server2:port/output.stream

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

ffmpeg -loop 1 -i Error.png -i rtmp://server:port/input.stream -filter_complex "[0:v][1:v] overlay=0:0" -f flv rtmp://server2:port/output.stream

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

Что произойдет, если вы измените фильтр с «[0:v][1:v] overlay=0:0» на «[0:v][1:v] overlay=0:0:repeatlast=0»? Repeatlast — это вариант для наложения. ffmpeg.org/ffmpeg-all.html#overlay-1
Комбинация mkfifo и rtmp может быть своего рода решением.

Ответы (1)

TL;DR : Ничего простого. В обоих решениях используется реле, и оно не подходит для реального производства.


На самом деле у вас есть только две возможности, и обе уродливы.

Не существует программного обеспечения с открытым исходным кодом, способного обрабатывать непостоянный поток (GStreamer+forks, FFmpeg, VLC, MPlayer). Каждый из них имеет одинаковое поведение: последний кадр все еще виден, и все останавливается, пока данные не придут снова.

Вариант 1 — Туннелирование + кеш

Вам нужно запустить два FFmpeg и скрипт, использующий FFplay.

Первый FFmpeg тянет поток RTMP. Выходом является локальный порт, и протокол должен быть основан на MPEG-TS. Лучше, если вход настроен на минимальную задержку.

Также нужно оптимизировать запуск FFmpeg: без анализа потока (задать fps в командной строке), ранний старт и т.д.

Второй FFmpeg извлекает локальный поток MPEG-TS и перекодирует поток в новый RTMP. Вам нужно перекодировать его с помощью x264, потому что видеопакеты разорвутся при первом переключении (поэтому вам нужно лучшее качество для исходного потока). Вам нужно увеличить задержку ввода: по умолчанию 3 секунды для FFmpeg, но вам нужно что-то вроде 8 секунд. Ее можно снизить, но только после того, как вы действительно поймете, что происходит и где ваша маржа.

Магия с FFplay.
У вас запущен скрипт, в котором FFmpeg читает исходный RTMP-поток. Когда в потоке больше нет данных, FFplay выдает ошибку и останавливается. Затем скрипт убивает первый экземпляр FFmpeg и запускает новый. Этот FFmpeg является «автономным» потоком. Какой бы вход вы ни хотели, вам нужно закодировать его в формате x264 MPEG-TS на локальный порт. И с тем же fps/размером, что и ваш обычный поток.

В это время второй FFmpeg все еще воспроизводит свой входной кеш. Так что 4 или 5 секунд для запуска «оффлайнового» FFmpeg — не проблема.

В самом цикле скрипта вам нужен новый FFplay. Когда ваш поток возвращается, он убивает автономный FFmpeg и перезапускает обычный.

Кэш ввода выполняет свою работу, а перекодирование очищает поврежденные видеопакеты.

Это работает, но это не правильное решение, например, наложение на FFmpeg, и FFmpeg не останавливается, когда ввод не отвечает/отсутствует/пуст.

Вариант 2 — Программное обеспечение OpenBroadcaster

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

Но есть загвоздка, OBS нужен OpenGL 3.1 (2?) и рабочий стол. Итак, вам нужен настоящий ПК и графический процессор или виртуализируйте рабочий стол с помощью ESXI (я не знаю, делает ли VirtualBox виртуальный графический процессор, совместимый с OpenGL 3.1).

Логика та же, но более дружелюбная.

Единственное хорошее решение

FFmpeg способен обрабатывать все в одном экземпляре. Если вы используете наложения, вы можете разместить автономный слой и исходный поток поверх него. FFmpeg даже знает, как перезапустить поток после его повторной публикации.

Но на самом деле FFmpeg останавливает все, когда один вход отключен/отсутствует/пуст.

Единственное, чего не хватает, — это возможность изменить поведение FFmpeg на входе.

Я попробовал список рассылки разработчиков, но ответа нет. То же самое и с моими предшественниками. «Сообщество» разработчиков FFmpeg не дружелюбно, основано на старых инструментах (лучше не критиковать использование списка рассылки!), и консервативно.

Если у кого-то есть лучшее решение, волшебная программа для простого автономного переключателя, она действительно нужна;)