WebRTC стриминг в виртуальной реальности и вокруг нее


    Виртуальная реальность нынче на пике моды. Оборудование, что во времена "Газонокосильщика" было уделом сумасшедших ученых гиков с большими деньгами от Минобороны, сейчас и простому человеку по карману, а те, у кого карман совсем пуст, могут собрать VR-гарнитуру из картона и смартфона по множеству рецептов.


    И пользы VR может принести гораздо больше. чем 3-4-5-6-7-далее-по-вкусу-D кинотеатр. Допустим, Вы проживаете в Москве и хотите вложить честно заработанные ресурсы в самую твердую из валют — недвижимость где-нибудь на берегу Средиземного моря. Как известно, выбирать жилье лучше на месте и самостоятельно, но что, если Вы не можете уделить этому достаточно времени? Вот здесь и нужна виртуальная реальность. Представьте: агент устанавливает специальную камеру в комнате, и Вы, не сходя с любимого кресла, можете эту комнату осмотреть, покрутить головой и даже на потолок с плафоном 18 века "Греческие боги предаются разврату отдохновению" глянуть!


    Затем, все так же не сходя с места, Вы интересуетесь, а чему же предаются Ваши чада в детском саду? И снова: камера в игровой комнате, и Вы с эффектом присутствия можете осмотреть все углы, куда Ваши чада расставлены прячутся.


    Ну а мы разберемся, как сделать, чтобы в подобных случаях все работало, и риэлтеры дети не успели разбежаться.


    Нюансы VR-картинки


    "Василий Иванович, объясните, что же такое нюанс?"
    "Видите ли, Петр..."
    Из диалога двух выдающихся джентльменов


    Технически, VR-медиапоток не отличается от обыкновенного: дорожка видео плюс дорожка аудио. Но есть нюанс.


    VR-поток предполагает стерео-картинку. Специальная камера смотрит в мир двумя широко, на 180 градусов, открытыми глазами объективами, примерно, как этот робот



    картинки склеиваются в один кадр,



    поэтому на устройстве зрителя должен работать специальный плеер, который из двух картинок сделает одну. Как видно, соотношение сторон кадра составляет 2:1, по FullHD картинке на каждый глаз.


    Нюансы VR-трансляции


    Да-да-да, могу все мели
    Счесть, как пальцы на руке
    Песенка из классического кино


    Итак, речь идет о трансляции 4K потоков с высоким битрейтом. Что у нас есть? А есть у нас RTMP и WebRTC.


    RTMP — дешево, надежно и практично. Под капотом использует TCP, что полезно при не очень хороших каналах. Есть разнообразные программные решения для публикующего клиента, как платные, так и бесплатные. Но, при всех достоинствах, RTMP дает высокие задержки. В одной из предыдущих статей мы отмечали задержку в 2-3 секунды для потока 720p. В каких-то случаях задержки приемлемы, но виртуальность будет уже немного отставать от реальности, и дети уже успеют разбежаться.


    WebRTC — стильно, модно, молодежно. При хороших каналах задержки измеряются миллисекундами, реальность останется реальностью. Но есть нюансы.


    Во-первых, по умолчанию WebRTC бегает поверх UDP, что при малейших ухудшениях качества канала приводит к потерям. А для 4K потока любой чих на канале — уже ухудшение. С этим можно справиться, перейдя на TCP транспорт, но дальше нас подстерегает...


    Во-вторых, WebRTC транслируется из браузера, а мы с вами знаем, какой браузер сейчас самый популярный на планете (спойлер — давно не IE6). И в этом популярном браузере, причем на уровне движка, зашит максимальный битрейт публикации 2500 кбит/с. Этого вполне достаточно по мнению Google для FullHD, но маловато для 4K, и если битрейт не разогнать до 5 — 10 Мбит/с, зрители увидят вместо виртуальной реальности движущиеся акварельные пятна. К счастью, есть специальные настройки для разгона битрейта, которые работают во всех большинстве браузеров на движке Chromium. Затем, преодолев это препятствие, мы упремся...


    В третьих, мы упремся в пропускную способность каналов. Чтобы публиковать и играть VR-картинку, при упомянутом выше битрейте клиенту потребуются каналы от 20 Мбит, а лучше от 50, а еще лучше от 100 Мбит, причем в обе стороны — и на загрузку, и на выгрузку. Причем это должны быть не те параметры, о которых рассказывает провайдер в рекламных буклетах, а реальная пропускная способность от клиента до сервера. Кстати, здесь можно прочитать, как ее можно измерить без iperf и знания командной строки. На стороне сервера, таким образом, желательно иметь 10 Гбит, если рассчитывать на большое количество потоков.


    Ну и в четвертых, что следует из требований к каналам. Транскодирование 4K потока займет слишком много ресурсов процессора на сервере. Поэтому нужно либо выбирать царь-сервер, что накладно по бюджету, либо использовать кодирование на видеокартах, что также весьма затратно, либо избегать транскодирования. То есть ни в коем случае не менять разрешение, частоту кадров и битрейт потоков при трансляции.


    Итак, все мели сочтены, теперь


    Давайте попробуем


    Что тут думать, трясти надо!
    Персонаж из детского мультика


    Возьмем:



    Устанавливаем камеру на столе или штативе



    Подключаем к ПК по USB 3.0 с питанием 1A, как для внешних дисков



    Надо сказать, камера весьма чувствительна к оборудованию, и если на ноутбуке 2 порта USB 3.0, с одним из них она вполне может отказаться работать. Кабель для подключения также должен быть не совсем китайским, все пины, предусмотренные стандартом, должны быть на месте. И даже при идеальном подключении, камера может выдавать помеху, как старый пузатый телевизор в грозу. Зато для Windows 10 драйверов не требуется, честный Plug-n-Play.


    На стороне сервера установим необходимые границы битрейта


    webrtc_cc_min_bitrate=5000000
    webrtc_cc_max_bitrate=10000000

    Откроем в браузере Chrome страницу примера, позволяющего выставить нужные параметры для захвата потока с камеры, и установим


    • разрешение 3072x1536
    • FPS 24 (при трансляции из браузера камера поддерживает только такой FPS)
    • транспорт TCP

    и настроим параметры SDP для того, чтобы браузер не резал нам осетра битрейт, на стороне клиента


    x-google-max-bitrate=10000;x-google-min-bitrate=5000

    или на стороне сервера (в этом случае настройки будут действовать для всех публикующих клиентов)


    webrtc_sdp_min_bitrate_bps=5000000
    webrtc_sdp_max_bitrate_bps=10000000


    Опубликуем поток с камеры



    Теперь попробуем проиграть поток обычным WebRTC плеером



    Все хорошо… Почти. Виртуальность какая-то не совсем виртуальная. Что ж, теперь играем этот же поток в специальном плеере, внедренном на страницу



    Так гораздо лучше (и котики есть). Если играть поток на мобильном устройстве или в VR-очках, можно покрутить головой, а мы в браузере на ПК покрутим мышкой. Где-то в этой комнате спрятался ребенок. Посмотрим налево



    Теперь направо



    И вверх



    А где же малыш? Да вот он, за шторкой прячется. Но котик все видит!


    Кода, нужно больше кода!


    На стороне клиента кода немного.


    Публикуем поток со страницы браузера


    session.createStream({
        name: streamName,
        display: localVideo,
        cacheLocalResources: true,
        transport: "TCP",
        sdpHook: rewriteSdp,
        constraints: {
            audio:true,
            video: {
                width: 3072,
                height: 1536,
                frameRate: 24
            }
        }
    }).publish();

    Функция замены параметров SDP браузера


    function rewriteSdp(sdp) {
        var sdpStringFind = "a=fmtp:(.*) (.*)";
        var sdpStringReplace = "a=fmtp:$1 $2;x-google-max-bitrate=10000;x-google-min-bitrate=5000";
        var newSDP = sdp.sdpString.toString();
        newSDP = newSDP.replace(new RegExp(sdpStringFind,"g"), sdpStringReplace);
        return newSDP;
    }

    Пример страницы с VR-плеером


    <!DOCTYPE html>
    <html>
        <head>
            <title>WebRTC Delight</title>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
               <script type="text/javascript" src="../../../../flashphoner.js"></script>
               <script type="text/javascript" src="../../dependencies/jquery/jquery-1.12.0.js"></script>
               <script type="text/javascript" src="../../dependencies/js/utils.js"></script>
               <script src="dl8-player.js" async></script>
            <meta name="dl8-custom-format" content='{"name": "STEREO_TERPON","base":"STEREO_MESH","params":{"uri": "03198702.json"}}'>
        </head>
        <body>       
            <div style="width: 50%;" id="display">
                <dl8-live-video id="remoteVideo" format="STEREO_TERPON">
                   \<source>
                </dl8-live-video>
            </div>
            <input class="form-control" type="text" id="playStream" placeholder="Stream Name">
            <button id="playBtn" type="button" class="btn btn-default" disabled>Play</button>
            <button id="stopBtn" type="button" class="btn btn-default" disabled>Stop</button>
            <script>
                Flashphoner.init({flashMediaProviderSwfLocation: '../../../../media-provider.swf'});
                var SESSION_STATUS = Flashphoner.constants.SESSION_STATUS;
                var STREAM_STATUS = Flashphoner.constants.STREAM_STATUS;
                var STREAM_STATUS_INFO = Flashphoner.constants.STREAM_STATUS_INFO;
                var playBtn = document.getElementById('playBtn');
                var display = document.getElementById('display');
                var dl8video = null;
                var url = setURL();
                document.addEventListener('x-dl8-evt-ready', function () {
                    dl8video = document.getElementById('remoteVideo');
                    $('#playBtn').prop('disabled', false).click(function() {
                        playStream();
                    });
                });
                function playStream() {
                $('#playBtn').prop('disabled', true);
                $('#stopBtn').prop('disabled', false);
                var video = dl8video.contentElement;
                Flashphoner.createSession({urlServer: url}).on(SESSION_STATUS.ESTABLISHED, function (session) {
                    var session = Flashphoner.getSessions()[0];
                    session.createStream({
                        name: document.getElementById('playStream').value,
                        display: display,
                        remoteVideo: video,
                        transport: "TCP"
                    }).on(STREAM_STATUS.PLAYING, function (stream) {
                        dl8video.start();
                        $('#stopBtn').prop('disabled', false).click(function() {
                             $('#playBtn').prop('disabled', false);
                             $('#stopBtn').prop('disabled', true);
                             stream.stop();
                             dl8video.exit();
                        });
                    }).play();
                }) 
                }
            </script>
        </body>
    </html>

    Обычно при создании стрима для плеера (вызов session.createStream()) мы передаем div-элемент, в который будет вмонтирован video-элемент для воспроизведения стрима по WebRTC. Но VR-плеер использует свой video-элемент, и нам нужно каким-то образом пробросить его в код используемого API. Для этого мы напрямую передаем video-элемент стороннего плеера в функцию session.createStream() параметром remoteVideo


    В качестве серверной части используется demo.flashphoner.com, примеры веб-приложений доступны в подвале по ссылкам.


    Удачи в осмотре на месте, не сходя с места!


    Ссылки


    1. Индикатор качества канала серверного WebRTC через TCP — Контроль качества каналов от клиента до сервера
    2. Видеотрансляции с веб-камеры браузера или мобильного устройства — WebRTC стриминг из браузера
    3. Документация по использованию WCS совместно с VR-плеером
    4. WCS — сервер для передачи VR 360 видео по WebRTC
    Flashphoner
    Компания
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 5

      +1
      «Виртуальная реальность нынче на пике моды» — виртуальная реальность сейчас как раз в упадке. У меня виртульные очки лежат без дела и уже не интересны, у многих моих приятелей тоже, многие их уже продали, время через которое все это надоедает и становиться не интересно примерно — 1 мес., Игр с хорошей графикой нет. Настоящих 3D фильмов с полным погружением (то есть с возможностью обзора 360 градусов) нет и не предвидятся, слишком трудоемкой производство, видимо, а просто ролики-360, смотреть быстро надоедает.
        +1
        в ВР играх графика не главное, главное погружение и управление. Какая у Вас гарнитура?
        Гарнитуру под конец этого года раскупили как горячие пирожки. В Америке распродали полностью окулус квест и валв индекс. Видимо из-за анонса ХЛ: Алекс.
          0
          А порно ролики?
            0
            Порно ролики -360 есть, но ведь понимаете ниша несколько специфическая
          0
          Спасибо, очень интересно. А про недвижимость или детей в саду — есть тестовые истории уже?

          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

          Самое читаемое