Видео H264 WebRTC, передаваемое из ffmpeg через Janus, очень прерывистое при воспроизведении

Попытка передать видео через следующую цепочку: файл h264 / mp4 в хранилище локальных экземпляров (AWS) -> ffmpeg-> rtp-> Janus на том же экземпляре-> воспроизведение WebRTC (Chrome / mac). В результате видео получается прерывистым, даже если ни один из ресурсов не кажется перегруженным (ЦП / память / пропускная способность сети на любой из задействованных систем). Я также использую сервер Coturn TURN, он тоже вообще не загружается и пропускная способность приличная.

Пробовал переключать кодеки, и это не помогло, кроме vp8, который, пока работал (вроде - волнение все еще было, но очень редко и приемлемо), привело к такому высокому потреблению процессора, что практически это неприемлемо.

ffmpeg -re -stream_loop -1 -i ./short.mp4 -s 426x240 -c:v libx264 -profile:v baseline -b:v 1M -r 24 -g 60 -an -f rtp rtp://127.0.0.1:5004

результирующий SDP:

o=- 0 0 IN IP4 127.0.0.1
s=No Name
c=IN IP4 127.0.0.1
t=0 0
a=tool:libavformat 58.20.100
m=video 5004 RTP/AVP 96
b=AS:1000
a=rtpmap:96 H264/90000
a=fmtp:96 packetization-mode=1

поток настроен с помощью Janus API как

            "janus" : "message",
            "transaction" : 'Transaction',
        "body": {
                "request" : "create",
                "type" : "rtp",
                "id" : newId,
                "name": streamId+newId,
                "audio": false,
                "video": true,
                "description" : streamId+newId,
                "videoport" : 5000+newId*4,
                "videopt" : 96,
                "videortpmap": "H264/90000",
                "secret" : "adminpwd"
            }
        }

Пробовал разные варианты чб, совсем не помогает. Изменение -g (размер GOP) на более низкие значения может сделать прерывистость короче, но более частой. При -g 3 или 4 это приемлемо, но битрейт для приемлемого качества, как и ожидалось, становится безумным.

Ожидаемый результат: видео воспроизводится без рывков.

Моя теория заключается в том, что это может быть одно из следующих:

  • Либо ffmpeg предоставляет данные таким образом, что буфер слишком мал, поэтому иногда Янусу необходимо отправить следующий пакет, пока он еще не готов, что приводит к нехватке буфера и приводит к прерыванию - так что, возможно, есть способ заставить ffmpeg кодировать какой-то короткий ( полсекунды или около того - буфер для регулирования потока). Как?

  • Или H264 слишком плохо работает по UDP, и я ничего не могу сделать. Затем мне пришлось переключиться на TCP, но пока попытки сделать это не увенчались успехом.


person Alexander Novikov    schedule 27.06.2019    source источник


Ответы (2)


Решение оказалось красивым в своей очевидности. ffmpeg отправил поток на Janus как RTP, Janus отправил его дальше зрителям, очевидно, как SRTP, потому что это WebRTC, и он всегда зашифрован. Это добавило к каждому пакету кучу байтов в качестве накладных расходов на шифрование. В некоторых случаях это означало, что пакеты превышали MTU и отбрасывались - каждый раз, когда это происходило, на видео наблюдался видимый рывок.

Простое добавление? Pkt_size = 1300 к выходному URL-адресу RTP ffmpeg устранило проблему.

Спасибо Лоренцо Миньеро из Meetecho за то, что выяснил это.

person Alexander Novikov    schedule 30.06.2019

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

Однако в ffmpeg есть опция, чтобы установить размер буфера мультиплексора равным 0, что хорошо работает. Это:

-max_delay 0

Кроме того, для WebRTC вы хотите отключить b-кадры и добавить SPS-PPS к каждому ключевому кадру:

-bf 0 + global_header -bsf: v "dump_extra = freq = keyframe"

person user1390208    schedule 27.06.2019
comment
Не уверен, что я понял это полностью, но я попробовал это так, как я понял, и это не помогло. Если вы можете связаться со мной наедине, я могу заплатить вам за фактическое решение. - person Alexander Novikov; 27.06.2019
comment
fmpeg -re -stream_loop -1 -i ./short.mp4 -s 852x480 -c:v libx264 -profile:v baseline -b:v 4M -r 24 -g 60 -flags:v +global_header -bsf:v "dump_extra=freq=keyframe" -max_delay 0 -bf 0 -an -f rtp rtp://127.0.0.1:5004 все еще очень неспокойно - person Alexander Novikov; 27.06.2019
comment
Я изменил свой профиль, чтобы вы могли связаться со мной напрямую. Благодарю. это становится срочным, и я все еще не могу заставить его работать :( - person Alexander Novikov; 27.06.2019