Table of Contents |
---|
Описание
Видеопоток захватывается с RTSP-источника, отдающего аудио и видео в поддерживаемых кодеках. Далее видеопоток трансформируется на стороне сервера для воспроизведения в браузерах и мобильных устройствах.
RTSP-источники:
- IP камеры
- Медиасерверы
- Системы наблюдения
- Конференц-серверы
Поддерживаемые кодеки:
- H.264
- VP8
- AAC
- G.711
- Speex
Поддерживаемые платформы и браузеры
| Chrome | Firefox | Safari 11 | Internet Explorer | Edge |
---|---|---|---|---|---|
Windows | + | + | + | + | |
Mac OS | + | + | + | ||
Android | + | + | |||
iOS | - | - | + |
Для управления захватом RTMP-потока используется REST API.
Схема работы
- Браузер соединяется с сервером по протоколу Websocket и отправляет команду play.
- Сервер соединяется с RTSP-источником и отправляет команду play.
- RTSP-источник передает на сервер RTSP-поток.
- Сервер трансформирует поток в WebRTC и отдает поток браузеру.
REST-вызовы
REST-запрос должен быть HTTP/HTTPS POST запросом в таком виде:
- HTTP: http://test.flashphoner.com:9091/rest-api/rtsp/startup
- HTTPS: https://test.flashphoner.com:8888/rest-api/rtsp/startup
Здесь:
- test.flashphoner.com - адрес WCS-сервера
- 9091 - стандартный REST / HTTP порт WCS-сервера
- 8888 - стандартный HTTPS порт
- rest-api - обязательная часть URL
- /rtsp/startup - используемый REST-метод
REST-методы и статусы ответа
REST-метод | Пример тела REST-запроса | Пример тела REST-ответа | Статусы ответа | Описание | |||||||
---|---|---|---|---|---|---|---|---|---|---|---|
/rtsp/startup |
| 409 - Conflict 500 - Internal error
| Извлечь RTMP-поток по указанному URL
| ||||||||
/rtsp/find_all |
| 200 – потоки найдены 404 – потоки не найдены | Найти все извлеченные RTMP-потоки | ||||||||
/rtsp/terminate |
| 200 - поток завершен 404 - поток не найден | Завершить извлеченный RTMP-поток |
Параметры
Имя параметра | Описание | Пример |
---|---|---|
uri | URL RTSP-потока | rtsp://myserver.com/live/myStream |
status | Текущий статус потока | PLAYING |
Настройка
В некоторых случаях, например, если подключение к IP-камере для захвата потока по RTSP производится через VPN, RTSP-клиент должен быть привязан к определенному адресу. Адрес указывается при помощи опции rtsp_client_address в файле настроек flashphoner.properties, например
Code Block | ||||
---|---|---|---|---|
| ||||
rtsp_client_address=172.16.0.3 |
Краткое руководство по тестированию
Захват видеопотока с IP-камеры и трансляция в браузер при помощи REST-запроса /rtsp/startup
1. Для теста используем:
- демо-сервер demo.flashphoner.com;
- браузер Chrome и REST-клиент для отправки запросов на сервер;
- веб-приложение Player для воспроизведения захваченного потока в браузере.
2. Откройте REST-клиент. Отправьте запрос /rtsp/startup, указав в параметрах URL веб-камеры:
3. Убедитесь, что поток захвачен сервером. Для этого отправьте запрос /rtsp/find_all:
4. Откройте веб-приложение Player, укажите в поле "Stream" URL веб-камеры и нажмите Start. Начнется воспроизведение потока в браузере:
5. Отправьте запрос /rtsp/terminate, указав в параметрах URL веб-камеры:
6. Воспроизведение потока прервется с ошибкой:
Захват видеопотока с IP-камеры и трансляция в браузер без использования REST-запроса
1. Для теста используем:
- демо-сервер demo.flashphoner.com;
- веб-приложение Player для захвата и воспроизведения потока
2. Откройте веб-приложение Player, укажите в поле "Stream" URL веб-камеры:
3. Нажмите кнопку "Start". Начнется трансляция захваченного потока.
4. Графики WebRTC internals:
Последовательность выполнения операций (Call Flow)
Ниже описана последовательность вызовов при использовании примера Player
1. Установка соединения с сервером.
Flashphoner.createSession(); code
Code Block | ||||
---|---|---|---|---|
| ||||
Flashphoner.createSession({urlServer: url}).on(SESSION_STATUS.ESTABLISHED, function(session){
setStatus(session.status());
//session connected, start playback
playStream(session);
}).on(SESSION_STATUS.DISCONNECTED, function(){
setStatus(SESSION_STATUS.DISCONNECTED);
onStopped();
}).on(SESSION_STATUS.FAILED, function(){
setStatus(SESSION_STATUS.FAILED);
onStopped();
}); |
2. Получение от сервера события, подтверждающего успешное соединение.
ConnectionStatusEvent ESTABLISHED code
Code Block | ||||
---|---|---|---|---|
| ||||
Flashphoner.createSession({urlServer: url}).on(SESSION_STATUS.ESTABLISHED, function(session){
setStatus(session.status());
//session connected, start playback
playStream(session);
}).on(SESSION_STATUS.DISCONNECTED, function(){
...
}).on(SESSION_STATUS.FAILED, function(){
...
}); |
3. Запрос на воспроизведение потока.
stream.play(); code
Code Block | ||||
---|---|---|---|---|
| ||||
stream = session.createStream(options).on(STREAM_STATUS.PENDING, function(stream) {
var video = document.getElementById(stream.id());
if (!video.hasListeners) {
video.hasListeners = true;
video.addEventListener('playing', function () {
$("#preloader").hide();
});
video.addEventListener('resize', function (event) {
var streamResolution = stream.videoResolution();
if (Object.keys(streamResolution).length === 0) {
resizeVideo(event.target);
} else {
// Change aspect ratio to prevent video stretching
var ratio = streamResolution.width / streamResolution.height;
var newHeight = Math.floor(options.playWidth / ratio);
resizeVideo(event.target, options.playWidth, newHeight);
}
});
}
...
});
stream.play();
|
4. Запрос от WCS к RTSP-источнику на трансляцию потока.
5. Трансляция RTSP-потока
6. Получение от сервера события, подтверждающего успешный захват и проигрывание потока.
StreamStatusEvent, статус PLAYING code
Code Block | ||||
---|---|---|---|---|
| ||||
stream = session.createStream(options).on(STREAM_STATUS.PENDING, function(stream) {
...
}).on(STREAM_STATUS.PLAYING, function(stream) {
$("#preloader").show();
setStatus(stream.status());
onStarted(stream);
...
});
stream.play();
|
7. Отправка аудио-видео потока по WebRTC
8. Остановка воспроизведения потока.
stream.stop(); code
Code Block | ||||
---|---|---|---|---|
| ||||
function onStarted(stream) {
$("#playBtn").text("Stop").off('click').click(function(){
$(this).prop('disabled', true);
stream.stop();
}).prop('disabled', false);
$("#fullScreenBtn").off('click').click(function(){
stream.fullScreen();
}).prop('disabled', false);
$("#volumeControl").slider("enable");
stream.setVolume(currentVolumeValue);
} |
9. Получение от сервера события, подтверждающего остановку воспроизведения потока.
StreamStatusEvent, статус STOPPED code
Code Block | ||||
---|---|---|---|---|
| ||||
stream = session.createStream(options).on(STREAM_STATUS.PENDING, function(stream) { ... }).on(STREAM_STATUS.PLAYING, function(stream) { ... }).on(STREAM_STATUS.STOPPED, function() { setStatus(STREAM_STATUS.STOPPED); onStopped(); }).on(STREAM_STATUS.FAILED, function(stream) { ... }).on(STREAM_STATUS.NOT_ENOUGH_BANDWIDTH, function(stream){ ... }); stream.play(); |
Известные проблемы
1) Поток, содержащий B-фреймы, не воспроизводится либо воспроизводится с артефактами (задержки, подергивания)
Симптомы:
а) поток, передаваемый IP камерой по RTSP, не проигрывается, дает задержки видео или подергивания
б) предупреждения в клиентском логе:
09:32:31,238 WARN 4BitstreamNormalizer - RTMP-pool-10-thread-5 It is B-frame!
Решение: при возможности запрашивать с камеры поток более низкого разрешения, с более низким качеством таким образом, чтобы исключить использование B-фреймов, либо траскодировать данный поток.
2) Соединение с IP-камерой разрывается при ошибке в любом из треков (аудио или видео)
Симптомы: соединение с IP-камерой разрывается, если один из треков вернул ошибку 4**.
Решение: данное поведение включено по умолчанию. Однако, если единичные ошибки не являются критичными и не требуют прекращения трансляции, в файле flashphoner.properties необходимо указать
Code Block | ||||
---|---|---|---|---|
| ||||
rtsp_fail_on_error_track=false
rtp_force_synchronization=true |