26 окт. 2016 г.

Изменения в конфигурации системы стриминга видео

Около года назад я описывал самопальную систему стриминга live video с птичьей кормушки из говна и палок вебкамеры, ffmpeg и nginx.

Прошёл год, наука шагнула далеко вперёд, надо описать, что с тех пор изменилось-усовершенствовалось.

Во-первых, от использования ffserver получилось отказаться почти сразу же после написания прошлогодней статьи. «Получилось» — потому что связка ffmpeg+ffserver в настройке и работе, мягко говоря, хрупковата. Поэтому сразу после реализации механизмы были перепилены в сторону упрощения. В качестве сервера дистрибуции потока вместо ffserver стал использоваться nginx. Для этого nginx пришлось пропатчить волшебным патчем, добавляющим поддержку RTMP, HLS и MPEG-DASH. После этого nginx обретает умение принимать видеопоток по RTMP и раскидывать его в файлы, которые потом сам же nginx отдаёт браузерам, понимающим MPEG-DASH либо HLS. Точнее, в случае десктоп-устройств в качестве веб-клиента выступил flash-плеер Bitdash, который в то время (в версии 3.2.0) был доступен бесплатно с некоторыми ограничениями по трафику, которые меня вполне устроили.

Настройки Nginx в части обслуживания потока у меня имеют следующий вид:
nginx.conf:
rtmp {
    server {
        listen [::]:1935;
        application live {
            allow publish <my-source-IP>;
            allow publish <my-backup-source-IP>;
            deny publish all;
            allow play all;
            live on;
            publish_notify on;
            play_restart on;
            hls on;
            hls_path /tmp/hls;
            hls_fragment 10s;
            dash on;
            dash_path /tmp/dash;
        }
    }
}


sites-enabled/myserver.conf:

location /hls {
    root /tmp;
    types {
        application/vnd.apple.mpegurl m3u8;
    }
    add_header Cache-Control no-cache;
}

location /dash {
    root /tmp;
    types {
        application/vnd.apple.mpegurl m3u8;
        application/dash+xml mpd;
    }
    add_header Cache-Control no-cache;
}
Сам поток по-прежнему формируется с использованием ffmpeg, берущего с вебкамеры raw YUV и преобразующего его в, прошу простить меня за это слово, FLV-контейнер с 10-bit H.264 потоком внутри и отдающего его nginx'у с помощью примерно следующей командной строки:

ffmpeg -s 640x360 -f video4linux2 -i /dev/video1 -c:v libx264 \
 -crf 27 -preset slow -bf 8 -g 100 -pix_fmt yuv420p10le -qmin 10 -qmax 43 -aq 1 \
  -b:v 450k -bufsize 1200 -r 20 -an -f flv \
  -vf "drawtext=fontfile=/usr/share/fonts/truetype/freefont/FreeSans.ttf:text='%{localtime} $(cat /tmp/temperature)':fontcolor=white@0.9:fontsize=10:x=510:y=348" "rtmp://birdfeeder.online/live/test.flv live=1"

Upd: как выяснилось, десятибитный поток не понимает никто, кроме хрома. Поэтому вернулись к стандарту:
ffmpeg -s 640x360 -f video4linux2 -i /dev/video1 -c:v libx264 \
 -crf 27 -preset slow -bf 8 -g 100 -pix_fmt yuv420p -qmin 10 -qmax 43 -aq 1 \
  -b:v 450k -bufsize 1200 -r 20 -an -f flv \
  -vf "drawtext=fontfile=/usr/share/fonts/truetype/freefont/FreeSans.ttf:text='%{localtime} $(cat /tmp/temperature)':fontcolor=white@0.9:fontsize=10:x=510:y=348" "rtmp://birdfeeder.online/live/test.flv live=1"

Результирующий поток имеет битрейт в пределах от 200 до 350 килобит в секунду. Файл /tmp/temperature формируется независимо по крону и, увы, для отображения изменений в нём весь ffmpeg приходится периодически перезапускать.


Во-вторых, перед началом нового сезона было решено вновь проверить возможность отказа от использования Adobe Flash. Это, как кажется, вполне удалось. Теперь для показа используется VideoJS-contrib-HLS, а соответствующий код в HTML-файле выглядит так:

<HEAD>
 <link href="https://vjs.zencdn.net/5.8.8/video-js.css" rel="stylesheet">
 <script src="https://vjs.zencdn.net/ie8/1.1.2/videojs-ie8.min.js"></script>
</HEAD>
<BODY>

  <video id=example-video width=640 height=360 class="video-js vjs-default-skin" poster="/images/poster.jpg" controls>
    <source
       src="https://birdfeeder.online/hls/test.m3u8"
       type="application/x-mpegURL">
  </video>
  </center>
  <script src="https://vjs.zencdn.net/5.8.8/video.js"></script>
  <script src="videojs-contrib-hls.min.js"></script>
  <script>
  var player = videojs('example-video');
  player.play();
  </script>
</BODY>



Что не решено:

    1. Не получилось придумать, как выводить изменения температуры. Несмотря на то, что показания термометра фиксируются каждую минуту, обновлять их вывод в кадр приходится путём перезапуска кодировщика. Это делается ежечасно.
    2. Не получилось придумать, как отвадить от кормушки голубей. Несмотря на качающийся подвес конструкции, несмотря на короткий «насест», некоторые из них умудряются балансировать и выгребать из кормушки семечки вниз. Внизу подоконник и стая ждущих собратьев. Результат — к весне подоконник по залежам гуано сравним с лучшими чилийскими птичьими пляжами.