В современном мире повсеместно распространены различные IP камеры видеонаблюдения, которые бывают самыми разными. От тех, которые работают в режиме видеорегистратора, до тех, которые могут вести онлайн трансляции в реальном или приближенном к реальному времени. Подобные трансляции можно размещать на сайте для привлечения клиентов и это может пригодиться не только компаниям работающим в сфере близкой к IT и блогерам. Застройщики предлагают виртуальные экскурсии по строящимся домам, салоны красоты показывают в реальном времени процесс работы мастеров, автосалоны могут проводить виртуальные тест-драйвы и презентации. Таким образом они показывают продукт «лицом» и это очень положительно отражается на спросе.

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

Популярные социальные платформы YouTube и Facebook будут хорошим выбором, если вы хотите увеличить взаимодействие со своими клиентами с помощью live трансляций. Они умеют принимать видеопотоки по протоколу RTMP (RTMPS) и видео с YouTube достаточно легко встроить в свой сайт. Остается самая малость — передать поток с IP камеры.

schema RTSP RTMP-republishing Youtube WCS browser

Как известно, многие IP камеры отдают видеопоток по проколу RTSP. RTSP – это потоковый протокол реального времени. Браузеры не поддерживают работу с протоколом RTSP напрямую, поэтому нужно промежуточное звено, которое позволит преобразовать видеопоток к виду, который может быть воспроизведен браузером. YouTube и Facebook так же не поддерживают работу с RTSP потоком.

Если у вас всего одна IP камера для Live трансляции, то можно воспользоваться десктопной программой, с помощью которой захватить RTSP видеопоток и ретранслировать его по протоколу RTMP.

schema RTSP app RTMP-republishing Youtube WCS browser

Задача несколько усложняется, если вам нужно внедрить сервис онлайн стриминга с нескольких IP камер одновременно. Десктопные приложения часто либо не умеют работать боле чем с одной камерой, либо требуют значительного увеличения процессорных мощностей, либо имеют лицензионные ограничения по количеству камер и зрителей. В таком случае как нельзя кстати будет серверное решение, которое позволит не только захватывать видеопоток с IP камеры и стримить его на YouTube и Facebook, но и отслеживать статус потоков, централизованно запускать и останавливать трансляции и управлять стеком камер. Для сервера можно написать собственные скрипты, которые позволят автоматизировать многие задачи Live трансляций.

Web Call Server 5.2 (далее WCS) как раз может быть таким решением.

WCS получает RTSP видео поток от камеры видеонаблюдения и ретранслирует его в формате, который понятен браузеру.

schema RTSP-server RTMP-republishing Youtube WCS browser

Одним из плюсов решения на базе WCS, кроме ретрансляции RTSP в RTMP (RTMPS) можно назвать возможность управления с помощью REST API.

Например с помощью запроса:

/rtsp/startup

— можно захватить видеопоток от IP камеры.

/rtsp/find_all

— позволит получить список захваченных сервером RTSP потоков.

Запрос для завершения RTSP сессии выглядит так:

/rtsp/terminate

Захватом и ретрансляцией видеопотоков можно управлять или с помощью простого браузера и любого удобного REST клиента, или с помощью минимального количества строчек кода встроить функционал управления сервером в свой web проект.

Давайте подробно рассмотрим, как это можно сделать.

Небольшой мануал, как с помощью минимального кода организовать Live трансляцию на YouTube и Facebook

В качестве серверной части мы используем demo.flashphoner.com. Для быстрого развертывания своего WCS сервера воспользуйтесь этой инструкцией или запустите один из виртуальных инстансов на Amazon, DigitalOcean или в Docker.

Предполагается, что у вас имеется подтвержденный аккаунт на YouTube и вы уже создали трансляцию в YouTube Studio, а так же создали прямую видеотрансляцию в своем аккаунте на Facebook.

Для работы Live трансляций на YouTube и Facebook нужно указать в файле настроек WCS flashphoner.properties следующие строки:

rtmp_transponder_stream_name_prefix=

– убирает все префиксы для ретранслируемого потока.

rtmp_transponder_full_url=true

– В значении «true» игнорирует параметр «streamName» и использует RTMP адрес для ретрансляции потока в том виде, в котором его указал пользователь.

flashphoner_properties_RTSP-RTMP-republishing-Youtube-WCS-browser

Теперь, когда все подготовительные действия выполнены, перейдем к программированию. Разместим в HTML файле минимально необходимые элементы

1. Подключаем скрипты основного API и JS скрипт для работы live трансляции, который мы создадим чуть позже:

<script type="text/javascript" src="../../../../flashphoner.js"></script>
<script type="text/javascript" src="rtsp-to-rtmp-min.js"></script>

2. Инициализируем API на загрузку web-страницы:

<body onload="init_page()">

3. Добавляем нужные элементы и кнопки – поля для ввода уникальных кодов потоков для YouTube и Facebook, кнопку для републикации RTSP потока, div элемент для вывода текущего статуса работы программы и кнопку для остановки републикации:

<input id="streamKeyYT" type="text" placeholder="YouTube Stream key"/>
<input id="streamKeyFB" type="text" placeholder="FaceBook Stream key"/>
<button id="repubBtn">Start republish</button>
<div id="republishStatus"></div>
<br>
<button id="stopBtn">Stop republish</button>

Затем переходим к созданию JS скрипта для работы републикации RTSP. Скрипт представляет собой мини REST клиент.

1. Создаем константы.

Константа «url», в которую записываем адрес для запросов REST API. Замените «demo.flashphoner.com» на адрес своего WCS.

Константа «rtspStream» — указываем RTSP адрес потока с IP камеры. Мы для примера используем RTSP поток с виртуальной камеры.

var url = "https://demo.flashphoner.com:8444/rest-api";
var rtspStream = "rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mov"

2. Функция «init_page()» инициализирует основной API при загрузке web — страницы. Так же в этой функции прописываем соответствие кнопок вызываемым функциям и вызываем функцию «getStream», которая захватывает RTSP видеопоток с IP камеры:

   function init_page() {
       Flashphoner.init({});	
   	repubBtn.onclick = streamToYouTube;
   	stopBtn.onclick = stopStream;
   	getStream();
   }

3. Функция «getStream()» отправляет на WCS REST запрос «/rtsp/startup» который захватывает видеопоток RTSP адрес которого был записан в константу «rtspStream»

   function getStream() {
       fetchUrl = url + "/rtsp/startup";
       const options = {
           method: "POST",
           headers: {
               "Content-Type": "application/json"
           },
           body: JSON.stringify({
               "uri": rtspStream
           }),
       }
       fetch(fetchUrl, options);
   	console.log("Stream Captured");
   }

4. Функция «streamToYouTube()» републикует захваченный видеопоток в Live трансляцию на YouTube:

   function streamToYouTube() {
   	fetchUrl = url + "/push/startup";
   	const options = {
           method: "POST",
           headers: {
               "Content-Type": "application/json"
           },
           body: JSON.stringify({
               "streamName": rtspStream,
   			"rtmpUrl": "rtmp://a.rtmp.youtube.com/live2/"+document.getElementById("streamKeyYT").value
           }),
       }
       fetch(fetchUrl, options);
   	streamToFB()
   }

Эта функция отправляет на WCS REST вызов «/push/startup» в параметрах которого передаются следующие значения:

  • «streamName» — имя потока, который мы захватили с IP камеры. Имя потока соответствует его RTSP адресу, который мы записали в константу «rtspStream»;
  • «rtmpUrl» — URL сервера + уникальный код потока. Эти данные выдаются при создании Live трансляции в YouTube Studio. В нашем примере мы жестко закрепили URL в коде, вы можете добавить для него еще одно поле на свою web страницу. Уникальный код потока указывается в поле «streamKeyYT» на нашей Web странице.

 

5. Функция «streamToFB» републикует захваченный видеопоток в Live трансляцию на Facebook:

   function streamToFB() {
   	fetchUrl = url + "/push/startup";
   	const options = {
           method: "POST",
           headers: {
               "Content-Type": "application/json"
           },
           body: JSON.stringify({
               "streamName": rtspStream,
   			"rtmpUrl": "rtmps://live-api-s.facebook.com:443/rtmp/"+document.getElementById("streamKeyFB").value
           }),
       }
       fetch(fetchUrl, options);
   	document.getElementById("republishStatus").textContent = "Stream republished";
   }

Эта функция так же отправляет на WCS REST вызов «/push/startup» в параметрах которого передаются значения:

  • «streamName» — имя потока, который мы захватили с IP камеры. Имя потока соответствует его RTSP адресу, который мы записали в константу «rtspStream»;
  • «rtmpUrl» — URL сервера + уникальный код потока. Эти данные можно найти на странице Live трансляции в Facebook в секции Live API. Url сервера в этой функции мы указали в коде, как и для функции републикации на YouTube. Уникальный код потока берем из поля «streamKeyFB» на Web странице.

 

6. Функция «stopStream()» отправляет RTSP запрос «/rtsp/terminate» который прекращает захват потока с IP камеры на WCS и соответственно прекращает публикации на YouTube и Facebook:

   function stopStream() {
   	fetchUrl = url + "/rtsp/terminate";
       const options = {
           method: "POST",
           headers: {
               "Content-Type": "application/json"
           },
           body: JSON.stringify({
               "uri": document.getElementById("rtspLink").value
           }),
       }
       fetch(fetchUrl, options);
   	document.getElementById("captureStatus").textContent = null;
   	document.getElementById("republishStatus").textContent = null;
   	document.getElementById("stopStatus").textContent = "Stream stopped";
   }

Полные коды HTML и JS файлов рассмотрим немного ниже.

Итак. Сохраняем файлы и пробуем запустить.

Последовательность действий для тестирования

1. Создаем Live трансляцию в YouTube Studio. Копируем уникальный код видеопотока:

create_live_stream_RTSP-RTMP-republishing-Youtube-WCS-browser

2. Открываем созданную ранее HTML страницу. Указываем в первом поле уникальный код видеопотока, который мы скопировали на YouTube:

streamkey_youtube_RTSP-RTMP-republishing-Youtube-WCS-browser

3. Создаем Live трансляцию в своем аккаунте на Facebook. Копируем уникальный код видеопотока.

create_live_stream_facebook_RTSP-RTMP-republishing-Youtube-WCS-browser

4. Возвращаемся на нашу web страничку, вставляем скопированный код во второе поле и нажимаем кнопку «Start republish»

rebublish_stream_RTSP-RTMP-republishing-Youtube-WCS-browser

5. Теперь проверяем работу нашей републикации. Снова переходим в YouTube Studio и на Facebook, ждем несколько секунд и получаем превью потока.

preview_stream_RTSP-RTMP-republishing-Youtube-WCS-browser

6. Для завершения републикации нажмите кнопку «Stop»

stop_stream_RTSP-RTMP-republishing-Youtube-WCS-browser

Теперь, как и обещали, исходные коды примера полностью:

Листинг HTML файла «rtsp-to-rtmp-min.html»

<!DOCTYPE html>
<html lang="en">
<head>
    <script type="text/javascript" src="../../../../flashphoner.js"></script>
    <script type="text/javascript" src="rtsp-to-rtmp-min.js"></script>
</head>

<body onload="init_page()">
	<input id="streamKeyYT" type="text" placeholder="YouTube Stream key"/>
	<input id="streamKeyFB" type="text" placeholder="Facebook Stream key"/>
	<button id="repubBtn">Start republish</button>
	<div id="republishStatus"></div>
	<br>
	<button id="stopBtn">Stop republish</button>
	
</body>
</html>

Листинг JS файла «rtsp-to-rtmp-min.js»:

var url = "https://demo.flashphoner.com:8444/rest-api";
var rtspStream = "rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mov"

function init_page() {
    Flashphoner.init({});	
	repubBtn.onclick = streamToYouTube;
	stopBtn.onclick = stopStream;
	getStream();
}

function getStream() {
    fetchUrl = url + "/rtsp/startup";
    const options = {
        method: "POST",
        headers: {
            "Content-Type": "application/json"
        },
        body: JSON.stringify({
            "uri": rtspStream
        }),
    }
    fetch(fetchUrl, options);
	console.log("Stream Captured");
}

function streamToYouTube() {
	fetchUrl = url + "/push/startup";
	const options = {
        method: "POST",
        headers: {
            "Content-Type": "application/json"
        },
        body: JSON.stringify({
            "streamName": rtspStream,
			"rtmpUrl": "rtmp://a.rtmp.youtube.com/live2/"+document.getElementById("streamKeyYT").value
        }),
    }
    fetch(fetchUrl, options);
	streamToFB()
}

function streamToFB() {
	fetchUrl = url + "/push/startup";
	const options = {
        method: "POST",
        headers: {
            "Content-Type": "application/json"
        },
        body: JSON.stringify({
            "streamName": rtspStream,
			"rtmpUrl": "rtmps://live-api-s.facebook.com:443/rtmp/"+document.getElementById("streamKeyFB").value
        }),
    }
    fetch(fetchUrl, options);
	document.getElementById("republishStatus").textContent = "Stream republished";
}

function stopStream() {
	fetchUrl = url + "/rtsp/terminate";
    const options = {
        method: "POST",
        headers: {
            "Content-Type": "application/json"
        },
        body: JSON.stringify({
            "uri": rtspStream
        }),
    }
    fetch(fetchUrl, options);
	document.getElementById("republishStatus").textContent = "Stream stopped";
}

Для минимальной реализации требуется совсем немного кода. Конечно для итогового внедрения функционала еще потребуется небольшая доработка напильником — добавить стили на web страницу и разные проверки на валидность данных в код JS скрипта. Но это работает.

Удачного стриминга!