Я использую gstreamer для потоковой передачи через пользовательский AppSink, который имитирует UdpSink. Мы делаем это таким образом, чтобы можно было включить прослушивание других портов для некоторых метаданных. Плюс, стандартный UdpSink сломан. В любом случае, я успешно транслировал видео, но пакеты UDP, похоже, не были правильно упакованы. Мне интересно, не пропустил ли я какой-то шаг.
Вот мой конвейер отправки:
filesrc (mpeg TS file) ! displayQueue ! streamTee ! tsdemux ! decoder ! videosink
streamTee ! sendQueue ! udpSink (our custom one)
принимающая сторона:
UdpSrc (custom) ! queue ! mpegtsdemux ! queue ! (mpegdecode || h264decode) ! ... ! videosink
Стриминг работает. Но кажется очень хрупким. Иногда просто останавливается. Много артефактов.
Итак, я попробовал VLC. Я настроил его на потоковую передачу по UDP unicast. Он отлично работает. Я заметил, что VLC отправляет видео не так, как мой конвейер. Я использовал Wireshark для анализа пакетов:
Используемые протоколы: VLC: IP:UDP:MP2T
(а также PET
пакеты PMT
и все остальное, что связано с TS)
Мой:IP:UDP:Data
Похоже, что используемый мной конвейер просто отправляет сырое видео по UDP без какой-либо коррекции ошибок. Что я упускаю? Используемые видео — это .mpg
файлы в кодировке h264 или mpeg.
Я использую gstreamer-java для программирования пользовательских элементов UdpSink и UdpSrc, но не могу использовать gstreamer в консоли для тестирования, так как стандартныйПлагин UdpSink сломанЯ попробовал простой конвейер в виртуальной машине Linux и получил такой же набор пакетов, как и VLC:
gst-launch-0.10 -v videotestsrc ! mpeg2enc ! mpegtsmux ! udpsink host=192.168.2.100 port=1234
решение1
Это просто мысль, я не очень хорошо знаком с gstreamer, поэтому не знаю, как он filesrc
работает, но предполагаю, что он не понимает MPEG-TS. MPEG-TS требует, чтобы пакеты приходили на определенных границах (обычно 188 байт). Я бы попробовал поместить ваш tee после demux, а затем добавить mpegtsmux перед вашим udpSink
.
Я понимаю, что это сделает больше работы, чем действительно необходимо (демультиплексирование только для повторного мультиплексирования), но это гарантирует правильное выравнивание пакетов. Если это сработает и вам нужно будет устранить накладные расходы, вам, возможно, придется рассмотреть возможность внедрения более умного источника файлов.
решение2
Вы близки. Плагин filesrc ничего не знает о содержимом файла, который он считывает. GStreamer должен знать, что данные являются транспортным потоком, чтобы правильно транслировать их. Хотя демультиплексирование и мультиплексирование потока выполняют эту работу, есть способ получше:
Source: gst-launch -v filesrc location=myvideo.ts ! tsparse set-timestamps=true ! udpsink host=192.168.2.100 port=1234
Dest: gst-launch udpsrc caps="video/mpegts, systemstream=(boolean)true, packetsize=(int)188" port=1234 ! tsdemux ! (video decoder) ! autovideosink
Плагин tsparse считывает поток и анализирует информацию о потоке. Он также идентифицирует свой вывод как транспортный поток. Этого самого по себе может быть достаточно для ваших потребностей в потоковой передаче, поскольку позволяет udpsink знать, что данные находятся в пакетах по 188 байт. На принимающей стороне tsdemux необходим для анализа фактического видеопотока. Элемент "set-timestamps" сообщает tsparse о необходимости устанавливать временные метки на исходящих пакетах, чтобы udpsink отправлял каждый кадр вовремя, а не так быстро, как может.
Вы также можете использовать rtpmp2tpay и rptmp2depay, которые пакетируют данные для отправки udpsink. Он также устанавливает имя кодировки на MP2T. Вы можете попробовать оба способа.
Source: gst-launch -v filesrc location=myvideo.ts ! tsparse set-timestamps=true ! rtpmp2tpay ! udpsink host=192.168.2.100 port=1234
Dest: gst-launch udpsrc caps="application/x-rtp, systemstream=(boolean)true, packetsize=(int)188" port=1234 ! rtpmp2tdepay ! tsdemux ! (video decoder) ! autovideosink