Как стать автором
Обновить

Потоковое видео: вещание с N810

Время на прочтение3 мин
Количество просмотров7.5K
Захотелось забросить свою нокию высоко в небо и посмотреть, как мы выглядим с высоты птичьего полёта.
Как забросить — понятно: самый простой вариант — взять воздушный змей побольше.
Как посмотреть — вопрос немного озадачил.
Что выяснилось:
  • gstreamer предоставляет набор плагинов, которые можно связывать в цепочки, подавая выход одного на вход другого. Среди плагинов есть простые базовые элементы: ввод/вывод из файлов ({file,fd}{src,sink}) и по сети ({tcp{client,server},udp}{src,sink}), захват видео через интерфейс video for linux (v4l2src), вывод видео средствами X (ximagesink). Есть кодировщики и декодировщики множества мультимедийных форматов — я поэкспериментировал с mpeg4video, h263 и theora. Есть средства формирования и разбора потоков RTP. Есть средства автоматического определения формата потока и декодирования (decodebin).
  • довольно свежий gstreamer входит в стандартную прошивку OS2008. Для полноты консольной радости нужно установить пакет gstreamer-tools, содержащий утилиты gst-launch и gst-inspect.

Отлично.

Первая попытка


[n810]$ gst-launch -v v4l2src ! \
    capsfilter caps="video/x-raw-yuv, format=(fourcc)UYVY, framerate=(fraction)8/1, width=(int)640, height=(int)480" ! \
    autovideosink

Фильтр capsfilter задает параметры видеозахвата. Их можно менять в разумных пределах, если видео невозможно захватить с такими параметрами, gstreamer пишет ближайшие допустимые.

Передача по сети


Хорошо было бы теперь передать это по сети. Простейший вариант выглядит так (IP машины desktop 192.168.1.254):

[desktop]$ gst-launch -v tcpserversrc host=0.0.0.0 protocol=gdp ! autovideosink

[n810]$ gst-launch -v v4l2src ! \
    capsfilter caps="video/x-raw-yuv, format=(fourcc)UYVY, framerate=(fraction)8/1, width=(int)320, height=(int)240" ! \
    tcpclientsink host=192.168.1.254 protocol=gdp

Параметр protocol=gdp добавляет к данным передаваемым по сети формат потока: дело в том, что в цепочку могут быть объединены только фильтры, имеющие выход и вход совместимого формата. tcp*src с этим параметром на приемной стороне имеет на выходе тот же формат, что и tcp*sink на передающей стороне на входе.

Простое решение, но через wifi работает тяжко: 7 мегабит, 600 пакетов в секунду — ощутимая нагрузка. 640х480 уже заметно тормозит.

Очевидно, следующий шаг — добавить сжатие.


Пусть это будет mpeg4:

[desktop]$ gst-launch -v tcpserversrc host=0.0.0.0 protocol=gdp ! decodebin ! autovideosink

[n810]$ gst-launch -v v4l2src ! \
    capsfilter caps="video/x-raw-yuv, format=(fourcc)UYVY, framerate=(fraction)8/1, width=(int)320, height=(int)240" ! \
    hantro4200enc ! tcpclientsink host=192.168.1.254 protocol=gdp

Отлично, всё в mpeg-кубиках, но 110 килобит и 30 пакетов в секунду (:
Какие еще существенные минусы этой схемы? TCP/IP: потеря пакетов приводит к повторной передаче уже неактуальной картинки, а значит к задержкам. А разрыв соединения лечится только перезапуском сервера и клиента.

RTP


Значит нужно прикрутить RTP:

[desktop]$ gst-launch -v gstrtpbin name=rtpbin \
    udpsrc caps="application/x-rtp,media=(string)video,clock-rate=(int)90000,encoding-name=(string)H263" port=5000 ! \
    rtpbin.recv_rtp_sink_0 rtpbin. ! \
    rtph263depay ! decodebin ! autovideosink

[n810]$ gst-launch -v gstrtpbin name=rtpbin \
  v4l2src ! \
  capsfilter caps="video/x-raw-yuv, format=(fourcc)UYVY, framerate=(fraction)8/1, width=(int)320, height=(int)240" ! \
  hantro4200enc stream-type=5 bit-rate=512 ! rtph263pay ! \
  rtpbin.send_rtp_sink_0 rtpbin.send_rtp_src_0 ! \
  udpsink port=5000 host=192.168.1.254

Что изменилось?
  • mpeg4 превратился в h263. Почему-то ffmpeg с десктопной машины не смог расшифровать присылаемые кадры от hantro4200. На передающей стороне это выразилось параметром stream-type=5. Чтобы было меньше кубиков добавился bit-rate=512.
  • Добавился rtpbin, используемый через именованные входы и выходы — наше видео идет по нулевому каналу. Конверсию сжатого видеопотока в RTP и обратно выполнили rtph263pay и rtph263depay.
  • tcp превратился в udp. На приемной стороне caps="..." вобрал в себя недостающую для восстановления потока информацию; эту строчку напечатал rtph263pay на передающей стороне.

Какой эффект?
  • Временная потеря связи не рвет соединения. Соединения-то нет (:
  • Просмотр можно останавливать и перезапускать. На сервер видео это никак не влияет.
  • Опоздавшие кадры не тормозят показ кадров пришедших вовремя.


Что осталось?


  • Непонятные трения между кодировщиками: mpeg4video через RTP не просматривается. Сжатие с помощью theora требует конверсии цветов, но цепочка
    v4l2src ! capsfilter ! ffmpegcolorspace ! theoraenc
    дает на выходе черный квадрат. При этом просмотр видео закодированного theora проблем не вызывает.
  • Может быть прикрутить multicasting. В моей конфигурации он конечно пока не нужен. Но было бы забавно посмотреть.
  • Сегодня в Питере дождь. Для змея погода нелётная. Ждём солнца и ветра (:


Справка по плагинам gstreamer на официальном сайте: gstreamer.freedesktop.org/documentation
Список установленных плагинов и справка по их параметрам — gst-inspect

P.S. Получилась эдакая хвалебная ода gstreamer'у. Откровенно порадовал инструмент (:
Теги:
Хабы:
Всего голосов 34: ↑29 и ↓5+24
Комментарии25

Публикации

Истории

Ближайшие события

15 – 16 ноября
IT-конференция Merge Skolkovo
Москва
22 – 24 ноября
Хакатон «AgroCode Hack Genetics'24»
Онлайн
28 ноября
Конференция «TechRec: ITHR CAMPUS»
МоскваОнлайн
25 – 26 апреля
IT-конференция Merge Tatarstan 2025
Казань