RTSP та WebRTC

У мене вже був пост про RTMP, тепер буде про RTSP.

Це я відкрив для себе офігезний проект MediaMTX. Там в документації вже є все потрібне. Але про всяк випадок зберу докупи свої знахідки, щоб не забути.

Загальна концепція: є передавач відеопотоку, є отримувач, між ними є медіасервер. Це може бути три різних компа. Може два, якщо медіасервер запустити там же, де й передавач. Для перших експериментів, нехай це буде один localhost.

Моя мета: дивитися через веб-камеру на блимаючий світлодіод, ха-ха.

Запуск сервера

Запускаю MediaMTX в Docker, якось так, як описано в документації. (Звісно, замість 192.168.xx.xx вказую свою IP-адресу в локальній мережі). Це достатньо надійний варіант.

docker run --rm -it \
  -e MTX_RTSPTRANSPORTS=tcp \
  -e MTX_WEBRTCADDITIONALHOSTS=192.168.xx.xx \
  -p 8554:8554 \
  -p 1935:1935 \
  -p 8888:8888 \
  -p 8889:8889 \
  -p 8890:8890/udp \
  -p 8189:8189/udp \
  bluenviron/mediamtx:1

Або, якщо можу собі дозволити, то запускаю ось так:

docker run --rm -it --network=host bluenviron/mediamtx:1

Також я запускав готові бінарники MediaMTX на своїй старенькій Raspberry Pi Model 2. Ок норм.

Трансляція RTSP

Штатна документація пропонує запускати ffmpeg прямо під час запуску MediaMTX. Мені більше до смаку тримати медіасервер постійно запущеним, а трансляції розпочинати окремою командою.

Ось варіант команди, який транслює відео з веб-камери, використовуючи кодек H.264:

ffmpeg -f v4l2 -framerate 30 -video_size 640x480 -i /dev/video0 \
  -pix_fmt yuv420p -c:v libx264 -preset ultrafast -b:v 600k \
  -tune zerolatency -bf 0 -g 15 -keyint_min 30 \
  -f rtsp rtsp://localhost:8554/mystream

Або те саме з апаратним прискоренням через VAAPI:

ffmpeg -f v4l2 -framerate 30 -video_size 640x480 -i /dev/video0 \
  -c:v h264_vaapi -vaapi_device /dev/dri/renderD128 \
  -vf 'format=nv12,hwupload' -qp 24 -quality 1 -bf 0 -g 30 \
  -f rtsp rtsp://localhost:8554/mystream

Тут всюди 640×480, бо звичайні веб-камери майже ніколи не дають 30 кадрів на секунду на більших розмірах картинки. Чесно, мені для моїх задач той HD чи FullHD не дуже потрібний, а от відсутність гальм справді важлива.

Звісно, замість localhost може бути потрібна IP-адреса. Також шлях /mystream — це на ваш вибір, щоб якось вказати даний конкретний відеопотік. Через один медіасервер може одночасно йти декілька різних відеопотоків з різними шляхами.

Можна робити трансляцію з VP8, але не сьогодні, бо моя відеокарта не робе апаратне прискорення кодування саме для VP8 (ну або я не знайшов як), а софтварний енкодер жере проц. Після експериментів і роздумів, я вирішив зупинитися на H.264 як на оптимальному варіанті.

Перегляд RTSP

Ну, наприклад, можна якось так:

ffplay \
  -fflags nobuffer \
  -flags low_delay \
  -framedrop \
  -probesize 32 \
  -analyzeduration 0 \
  -sync ext \
  -rtsp_transport udp \
  rtsp://localhost:8554/mystream

Або так:

mpv rtsp://localhost:8554/mystream --profile=low-latency --untimed

Перегляд WebRTC

Просто відкриваю в браузері http://localhost:8889/mystream/ і бачу там відео. Магія!

Є певний нюанс з кодеками. Chrome/Chromium нормально грає H.264, а Firefox його грати не хоче. Треба полізти в about:config, знайти там media.webrtc.hw.h264.enabled і увімкнути його. Саме через це я експериментував з VP8, але вирішив що не на часі.

Вбудувати стрім у довільну веб-сторінку

Теж все робиться просто і зрозуміло, як в документації:

<iframe src="http://localhost:8889/mystream" scrolling="no"></iframe>

Можна додати CSS за смаком:

<iframe
 src="http://localhost:8889/mystream"
 style="border: none;
        aspect-ratio: 4 / 3;
        width: 100%;
        height: 100%;
        max-width: 100vw;
        max-height: 100vh"
 scrolling="no"></iframe>

Для дашборда Node-RED можна створити UI Template node і прямо туди це все покласти. Власне, саме задля цього я занурився у ці нетрі: дуже захотілося поєднати телеметрію та елементи керування моїх саморобних IoT проектів з живим відео. І це заслуговує окремого поста.

Додаткова краса

Коли трансляція не ведеться, можна показувати щось красиве, наприклад телевізійну тест-таблицю SMPTE чи Philips. Для цього треба з картинки зробити відео довжиною, гммм, 1 секунду.

wget https://upload.wikimedia.org/wikipedia/commons/6/66/SMPTE_Color_Bars.svg
rsvg-convert SMPTE_Color_Bars.svg -w 640 -h 480 > smpte.png
ffmpeg -loop 1 -framerate 30 -t 1 -i smpte.png -c:v libx264 -pix_fmt yuv420p smpte.mp4

Або так:

wget https://upload.wikimedia.org/wikipedia/commons/a/aa/Philips_PM5544.svg
rsvg-convert Philips_PM5544.svg -w 640 -h 480 > pm5544.png
ffmpeg -loop 1 -framerate 30 -t 1 -i pm5544.png -c:v libx264 -pix_fmt yuv420p pm5544.mp4

Власне, далі треба буде лізти в конфігураційний файл mediamtx.yml, і якщо у вас MediaMTX все ще запускається через Docker, то вам доведеться з цим розбиратися окремо.

Просто дописую в кінець таку секцію:

paths:
  mystream:
    alwaysAvailable: true
    alwaysAvailableFile: "pm5544.mp4"

Проброс портів

Якщо є бажання поділитися своєю трансляцією в WebRTC з усім світом, то треба буде десь на роутері налаштувати port forwarding:

  • 8889/TCP → 192.168.xx.xx:8889
  • 8189/UDP → 192.168.xx.xx:8189

Далі дивлюся трансляцію так само, тільки в якості хоста вказую реальну IP-адресу.

Відкриті питання

Треба буде розібратися з питаннями безпеки:

  1. Обмежити можливість трансляції, дозволити лише «кому треба»
  2. Обмежити можливість перегляду (JWT?)
  3. Убезпечити транспорт WebRTC від MitM (https?)

Треба більше RTFM.

Треба всерйоз подумати, як би то його точніше виміряти затримку. Візуально бачу що вона відрізняється для різних конфігурацій, зокрема для різних кодеків і різних транспортів. Можливо, параметри запуску ffmpeg та ffplay можна ще вдосконалити.

Висновки

Маю офігенний інструмент в своєму арсеналі, от!