Публикация MPEG-TS RTP потока¶
Описание¶
В сборке 5.2.1193 добавлена возможность публикации MPEG-TS RTP потока по UDP на WCS, а в сборке 5.2.1253 MPEG-TS поток может быть опубликован по SRT. Данный способ может быть удобен для публикации H264+AAC потока из программного или аппаратного кодировщика, поддерживающего MPEG-TS. В сборке 5.2.1577 добавлена возможность публикации H265+AAC потока.
Протокол SRT является более надежным по сравнению с UDP, поэтому по возможности рекомендуется использовать SRT для публикации MPEG-TS.
Поддержка кодеков¶
- Video: H264, H265 (начиная со сборки 5.2.1577)
- Audio: AAC
Схема работы¶
- Публикующий клиент отправляет REST API запрос
/mpegts/startup
- Публикующий клиент получает ответ
200 OK
c URI для публикации потока - Поток публикуется на WCS по указанному URI
- Браузер устанавливает соединение по Websocket и отправляет команду
playStream
- Браузер получает WebRTC поток и воспроизводит этот поток на странице
Тестирование¶
- Для теста используем:
- WCS сервер
- ffmpeg для публикации MPEG-TS потока
-
веб-приложение Player в браузере Chrome для воспроизведения потока
-
Отправляем запрос
/mpegts/startup
с указанием имени потокаtest
SRT:
UDP:curl -H "Content-Type: application/json" -X POST http://test1.flashphoner.com:8081/rest-api/mpegts/startup -d '{"localStreamName":"test","transport":"srt"}'
Здесьcurl -H "Content-Type: application/json" -X POST http://test1.flashphoner.com:8081/rest-api/mpegts/startup -d '{"localStreamName":"test","transport":"udp"}'
test1.flashphoner.com
- адрес WCS сервера -
Получаем от сервера ответ
200 OK
SRT:
UDP:{ "localMediaSessionId": "32ec1a8e-7df4-4484-9a95-e7eddc45c508", "localStreamName": "test", "uri": "srt://test1.flashphoner.com:31014", "status": "CONNECTED", "hasAudio": false, "hasVideo": false, "record": false, "transport": "SRT", "cdn": false, "timeout": 90000, "maxTimestampDiff": 1, "allowedList": [] }
{ "localMediaSessionId": "32ec1a8e-7df4-4484-9a95-e7eddc45c508", "localStreamName": "test", "uri": "udp://test1.flashphoner.com:31014", "status": "CONNECTED", "hasAudio": false, "hasVideo": false, "record": false, "transport": "UDP", "cdn": false, "timeout": 90000, "maxTimestampDiff": 1, "allowedList": [] }
-
Публикуем MPEG-TS поток по указанному URI
SRT:
UDP:ffmpeg -re -i bunny360p.mp4 -c:v libx264 -c:a aac -b:a 160k -bsf:v h264_mp4toannexb -keyint_min 60 -profile:v baseline -preset veryfast -f mpegts "srt://test1.flashphoner.com:31014"
-
Открываем веб-приложение Player. Укажите в поле
Stream
имя потокаtest
и нажмите кнопкуStart
. Начнется трансляция опубликованного потока
Настройки¶
Остановка публикации при отсутствии медиаданных¶
По умолчанию, публикация MPEG-TS потока будет остановлена на стороне сервера, если сервер не получает медиаданных в течение 90 секунд. Это время задается настройкой в миллисекундах
Отключение подписчиков при остановке передачи данных от публикующего клиента¶
Если публикующий клиент по какой-то причине остановил передачу медиаданных, а затем возобновил (например, перезапустил ffmpeg), нарушается последовательность временных меток кадров потока. Такой поток не может быть корректно воспроизведен по WebRTC. В связи с этим, если зафиксировано нарушение последовательности временных меток для публикуемого MPEG TS потока, все подписчики принудительно отключаются, и должны заново подключиться к нему. Максимально допустимое изменение двух соседних временных меток задается настройкой в секундах
REST API¶
REST-запрос должен быть HTTP/HTTPS POST запросом в таком виде:
- HTTP:
http://test.flashphoner.com:8081/rest-api/mpegts/startup
- HTTPS:
https://test.flashphoner.com:8444/rest-api/mpegts/startup
Здесь:
test.flashphoner.com
- адрес WCS-сервера8081
- стандартный REST / HTTP порт WCS-сервера8444
- стандартный HTTPS портrest-api
- обязательная часть URL/mpegts/startup
- используемый REST-метод
REST-методы и статусы ответа¶
/mpegts/startup¶
Начать публикацию MPEG-TS потока
Request example¶
POST /rest-api/mpegts/startup HTTP/1.1
Host: localhost:8081
Content-Type: application/json
{
"localStreamName":"test",
"transport":"srt",
"hasAudio": true,
"hasVideo": true
}
Response example¶
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Type: application/json
{
"localMediaSessionId": "32ec1a8e-7df4-4484-9a95-e7eddc45c508",
"localStreamName": "test",
"uri": "srt://192.168.1.39:31014",
"status": "CONNECTED",
"hasAudio": false,
"hasVideo": false,
"record": false,
"transport": "SRT",
"cdn": false,
"timeout": 90000,
"maxTimestampDiff": 1,
"allowedList": []
}
Return codes¶
Code | Reason |
---|---|
200 | OK |
409 | Conflict |
500 | Internal error |
/mpegts/find¶
Найти MPEG-TS поток по заданным критериям
Request example¶
POST /rest-api/mpegts/find HTTP/1.1
Host: localhost:8081
Content-Type: application/json
{
"localStreamName":"test",
"uri": "srt://192.168.1.39:31014"
}
Response example¶
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Type: application/json
[
{
"localMediaSessionId": "32ec1a8e-7df4-4484-9a95-e7eddc45c508",
"localStreamName": "test",
"uri": "srt://192.168.1.39:31014",
"status": "PROCESSED_LOCAL",
"hasAudio": false,
"hasVideo": false,
"record": false,
"transport": "SRT",
"cdn": false,
"timeout": 90000,
"maxTimestampDiff": 1,
"allowedList": []
}
]
Return codes¶
Code | Reason |
---|---|
200 | OK |
404 | Not found |
500 | Internal error |
/mpegts/find_all¶
Найти все опубликованные MPEG-TS потоки
Request example¶
Response example¶
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Type: application/json
[
{
"localMediaSessionId": "32ec1a8e-7df4-4484-9a95-e7eddc45c508",
"localStreamName": "test",
"uri": "srt://192.168.1.39:31014",
"status": "PROCESSED_LOCAL",
"hasAudio": false,
"hasVideo": false,
"record": false,
"transport": "SRT",
"cdn": false,
"timeout": 90000,
"maxTimestampDiff": 1,
"allowedList": []
}
]
Return codes¶
Code | Reason |
---|---|
200 | OK |
404 | Not found |
500 | Internal error |
/mpegts/terminate¶
Завершить MPEG-TS поток
Request example¶
POST /rest-api/mpegts/find_all HTTP/1.1
Host: localhost:8081
Content-Type: application/json
{
"localStreamName":"test"
}
Response example¶
Return codes¶
Code | Reason |
---|---|
200 | OK |
404 | Not found |
500 | Internal error |
Параметры¶
Параметр | Описание | Пример |
---|---|---|
localStreamName | Имя, которое будет присвоено опубликованному потоку | test |
transport | Используемый транспорт | srt |
uri | URI для публикации потока | srt://192.168.1.39:31014 |
localMediaSessionId | Идентификатор медиасессии потока | 32ec1a8e-7df4-4484-9a95-e7eddc45c508 |
status | Статус потока | CONNECTED |
hasAudio | Поток содержит аудио | true |
hasVideo | Поток содержит видео | true |
record | Поток записывается | false |
timeout | Максимальное время ожидания медиаданных, мс | 90000 |
maxTimestampDiff | Максимально допустимое изменение метки времени, с | 1 |
allowedList | Список адресов, с который разрешена публикация потока | ["192.168.1.0/24"] |
Публикация только аудио или только видео¶
Начиная со сборки 5.2.1253, можно начать публикацию только видео или только аудио потока, указав соответствующий параметр REST API запроса /mpegts/startup
- поток только с видео
- поток только с аудио
Публикация аудио с различными частотами дискретизации¶
По умолчанию, для публикации MPEG-TS используются следующие параметры видео и аудио
v=0
o=- 1988962254 1988962254 IN IP4 0.0.0.0
c=IN IP4 0.0.0.0
t=0 0
a=sdplang:en
m=audio 1 RTP/AVP 102
a=rtpmap:102 mpeg4-generic/44100/2
a=sendonly
m=video 1 RTP/AVP 119
a=rtpmap:119 H264/90000
a=sendonly
Видео должно быть опубликовано в кодеке H264 с частотой дискретизации 90000 Гц, аудио должно быть опубликовано в кодеке AAC с частотой дискретизации 44100 Гц и двумя каналами.
При необходимости, можно указать поддержку нескольких частот дискретизации аудио, либо поддержку одноканального звука. Для этого необходимо:
-
Cоздать в каталоге
/usr/local/FlashphonerWebCallServer/conf
файлmpegts_agent.sdp
-
Добавить в файл необходимое описание параметров SDP
например
-
Установить нужные права и перезапустить WCS, чтобы применить изменения
Возобновление публикации после остановки¶
Под каждую публикацию MPEG-TS выделяется отдельный UDP порт, который ждет входящего соединения (для SRT) и трафика от клиента. В целях безопасности, начиная со сборки 5.2.1299, если клиент остановил публикацию, поток на сервере останавливается, и повторно к тому же самому порту подключиться нельзя. Зрители в этом случае получают событие STREAM_STATUS.FAILED
. Чтобы возобновить публикацию, должен быть использован новый REST API запрос для создания на сервере нового потока, при необходимости с тем же именем.
Ограничение адресов клиентов, с который разрешена публикация¶
В сборке 5.2.1314 добавлена возможность задать список адресов, с которых разрешена публикация MPEG-TS, указав соответствующий параметр REST API запроса /mpegts/startup
{
"localStreamName":"mpegts-stream",
"transport":"udp",
"allowedList": [
"192.168.0.100",
"172.16.0.1/24"
]
}
В списке могут быть как точные адреса, так и маски адресов. Если такой список содержится в запросе, то опубликовать поток можно будет только с клиентов, чьи адреса соответствуют списку.
Публикация H265¶
В сборке 5.2.1577 добавлена возможность публикации MPEG-TS потока H265+AAC. Для этого в файле mpegts_agent.sdp
должен быть указан видео кодек H265:
v=0
o=- 1988962254 1988962254 IN IP4 0.0.0.0
c=IN IP4 0.0.0.0
t=0 0
a=sdplang:en
m=audio 1 RTP/AVP 102
a=rtpmap:102 mpeg4-generic/48000/2
a=sendonly
m=video 1 RTP/AVP 119
a=rtpmap:119 H265/90000
a=sendonly
Также H265 должен быть добавлен в список поддерживаемых кодеков
и в списки исключений
codecs_exclude_sip=mpeg4-generic,flv,mpv,h265
codecs_exclude_sip_rtmp=opus,g729,g722,mpeg4-generic,vp8,mpv,h265
codecs_exclude_sfu=alaw,ulaw,g729,speex16,g722,mpeg4-generic,telephone-event,flv,mpv,h265
Публикация H265 при помощи ffmpeg
ffmpeg -re -i source.mp4 -c:v libx265 -c:a aac -ar 48000 -ac 2 -b:a 160k -bsf:v hevc_mp4toannexb -keyint_min 120 -profile:v main -preset veryfast -x265-params crf=23:bframes=0 -f mpegts "srt://test.flashphoner.com:31014"
Warinig
При проигрывании H265 потока любым способом на сервере включается транскодинг из H265 в H264 или VP8!
Резервирование портов для публикации MPEG-TS¶
В сборке 5.2.2046 добавлена возможность резервировать определенные порты для публикации MPEG-TS (SRT или UDP). При этом для публикации не требуется отправлять REST API запросы.
Порты резервируются из диапазона
Параметры публикации MPEG-TS настраиваются в файле /usr/local/FlashphonerWebCallServer/conf/mpegts_ingest.yml
streams:
srtStream1:
port: 42002
transport: srt
timeout: 10000
hasAudio: true
hasVideo: true
maxTimeStampDiff: 90000
allowedList: ["192.168.1.0/24","192.168.23.83"]
udpStream2:
port: 42004
transport: udp
timeout: 10000
hasAudio: false
hasVideo: true
maxTimeStampDiff: 90000
allowedList:
- 192.168.1.0/24
- 192.168.23.83
Здесь:
srtStream1
,udpStream1
- зарезервированное имя потокаport
- четный порт из диапазонаmpegts_reserved_port_from
-mpegts_reserved_port_to
transport
- транспорт:srt
илиudp
timeout
- интервал ожидания медиаданных, мсhasAudio
- поток публикуется с аудиоhasVideo
- поток публикуется с видеоmaxTimeStampDiff
- максимально допустимое различие между метками времени двух пакетов подряд, мсallowedList
- список адресов клиентов, с которых разрешена публикация
Зарезервированные потоки существуют на сервере постоянно и отображаются в результатах REST API запросов /stream/find
, /mpegts/find_all
. Если публикации на зарезервированный порт нет, зрители не смогут проиграть такой поток с сервера.
Для публикации достаточно указать порт, REST запрос /mpegts/startup
отправлять не нужно:
ffmpeg -re -i bunny360p.mp4 -c:v libx264 -c:a aac -b:a 160k -bsf:v h264_mp4toannexb -keyint_min 60 -profile:v baseline -preset veryfast -f mpegts "srt://test1.flashphoner.com:42002"
Известные проблемы¶
1. Публикующий кодировщик может не знать о завершении публикации на стороне сервера¶
Если публикация MPEG-TS потока по UDP была остановлена на стороне сервера по REST API /mpegts/terminate
, публикующий кодировщик продолжает отправлять медиаданные
Симптомы
При остановке публикации MPEG-TS потока на сервере ffmpeg продолжает отправлять данные по UDP
Решение
Для UDP это ожидаемое поведение, поскольку самим протоколом не предусмотрены никакие оповещения отправляющей стороны о том. что порт, принимающий данные, уже закрыт. Используйте протокол SRT, в котором данный случай обрабатывается корректно, и публикующий клиент останавливается.