...
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(); |
Циклический захват потока из файла
Для трансляций vod-live поддерживается циклический захват потока, после окончания файла захват начинается сначала. Эта возможность включается настройкой в файле flashphoner.properties
Code Block | ||
---|---|---|
| ||
vod_live_loop=true |
Захват файла, размещенного на AWS
Поток может быть захвачен из файла, размещенного на AWS в хранилище S3. В отличие от VOD захвата файла с локального диска, файл, размещенный на внешнем хранилище, загружается и воспроизводится последовательно.
Для захвата VOD из файла на AWS в качестве имени потока при вызове функции session.createStream() должна быть указана ссылка на файл в виде:
Code Block | ||||
---|---|---|---|---|
| ||||
vod://s3/bucket/sample.mp4 |
где
- bucket - имя корзины S3
- sample.mp4 - имя файла
Схема работы
1. Браузер запрашивает захват потока из файла на AWS
2. WCS сервер направляет запрос AWS
3. Файл загружается на WCS сервер
4. WebRTC поток из файла передается в браузер для воспроизведения
Настройка
Для загрузки файлов из AWS необходимо указать в файле настроек flashphoner.properties данные для доступа к хранилищу S3
Code Block | ||
---|---|---|
| ||
aws_s3_credentials=zone;login;hash |
Чтобы захватывать поток из файла во время его загрузки, необходимо указать следующую настройку
Code Block | ||
---|---|---|
| ||
vod_mp4_container_new=true |
Требования к формату файлов
Заголовок (moov) должен всегда располагаться перед данными (mdat). Примерная структура файла должна быть такой:
Code Block | ||
---|---|---|
| ||
Atom ftyp @ 0 of size: 32, ends @ 32
Atom moov @ 32 of size: 357961, ends @ 357993
...
Atom free @ 357993 of size: 8, ends @ 358001
Atom mdat @ 358001 of size: 212741950, ends @ 213099951 |
Проверить структуру файла можно при помощи утилиты AtomicParsley
Code Block | ||||
---|---|---|---|---|
| ||||
AtomicParsley file.mp4 -T 1 |
При необходимости, структуру файла можно исправить при помощи ffmpeg без перекодирования
Code Block | ||||
---|---|---|---|---|
| ||||
ffmpeg -i bad.mp4 -acodec copy -vcodec copy -movflags +faststart good.mp4 |
Управление VOD при помощи REST API
REST-запрос должен быть HTTP/HTTPS POST запросом в таком виде:
- HTTP: http://test.flashphoner.com:8081/rest-api/vod/startup
- HTTPS: https://test.flashphoner.com:8444/rest-api/vod/startup
Здесь:
- test.flashphoner.com - адрес WCS-сервера
- 8081 - стандартный REST / HTTP порт WCS-сервера
- 8444 - стандартный HTTPS порт
- rest-api - обязательная часть URL
- /vod/startup - используемый REST-метод
REST-методы и статусы ответа
REST-метод | Пример тела REST-запроса | Пример тела REST-ответа | Статусы ответа | Описание | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
/vod/startup |
| 409 - Conflict 500 - Internal error | Захватить поток из указанного файла | |||||||||||||||
/vod/find |
|
| 200 – потоки найдены 404 – потоки не найдены | Найти VOD-потоки по указанному критерию | ||||||||||||||
/vod/find_all |
| 200 – потоки найдены 404 – потоки не найдены | Найти все VOD-потоки | |||||||||||||||
/vod/terminate |
| 200 - поток завершен 404 - поток не найден | Завершить VOD-поток |
Параметры
Имя параметра | Описание | Пример |
---|---|---|
uri | Имя файла для захвата потока | vod://sample.mp4 |
localStreamName | Имя создаваемого потока | test |
status | Текущий статус потока | PROCESSED_LOCAL |
localMediaSessionId | Идентификатор медиасессии | 29ec3236-1093-42bb-88d6-d4ac37af3ac0 |
hasAudio | В потоке есть аудио | true |
hasVideo | В потоке есть видео | true |
record | Поток записывается | false |
Ограничения
Запрос /rest-api/vod/startup может применяться только для создания VOD live трансляций. При этом, запросы find, find_all и terminate могут быть применены как к VOD, так и к VOD live трансляциям.
Настройка продолжительности публикации VOD потока после отключения подписчиков
По умолчанию, VOD поток остается опубликованным на сервере в течение 30 секунд после отключения последнего подписчика, при условии, что продолжительность файла превышает этот интервал. Данное время может быть изменено при помощи настройки
Code Block | ||
---|---|---|
| ||
vod_stream_timeout=60000 |
В этом случае, VOD поток останется опубликованным в течение 60 секунд.
Известные проблемы
1. AAC фреймы типа 0 не поддерживаются декодером на базе ffmpeg и будут игнорироваться при воспроизведении захваченного потока
Симптомы: предупреждения в клиентском логе:
Code Block | ||||
---|---|---|---|---|
| ||||
10:13:06,815 WARN AAC - AudioProcessor-c6c22de8-a129-43b2-bf67-1f433a814ba9 Dropping AAC frame that starts with 0, 119056e500 |
Решение: переключиться на использование FDK AAC декодера
Code Block | ||
---|---|---|
| ||
use_fdk_aac=true |
2. Файлы, содержащие B-фреймы, могут проигрываться неплавно, с фризами или артефактами
Симптомы: периодические фризы, артефакты при проигрывании файла через VOD, предупреждения в клиентском логе
Code Block | ||
---|---|---|
| ||
09:32:31,238 WARN 4BitstreamNormalizer - RTMP-pool-10-thread-5 It is B-frame! |
Решение: перекодировать файл таким образом, чтобы исключить B-фреймы, например
Code Block | ||||
---|---|---|---|---|
| ||||
ffmpeg -i bad.mp4 -preset ultrafast -acodec copy -vcodec h264 -g 24 -bf 0 good.mp4 |
3. При захвате VOD из продолжительного файла процесс сервера может завершиться с Out of memory при превышении максимального числа областей виртуальной памяти (vm.max_map_count)
Симптомы: процесс сервера завершается; "Map failed" в серверном логе и в error*.log
Code Block | ||
---|---|---|
| ||
19:30:53,277 ERROR DefaultMp4SampleList - Thread-34 java.io.IOException: Map failed
at sun.nio.ch.FileChannelImpl.map(FileChannelImpl.java:940)
at com.googlecode.mp4parser.FileDataSourceImpl.map(FileDataSourceImpl.java:62)
at com.googlecode.mp4parser.BasicContainer.getByteBuffer(BasicContainer.java:223)
at com.googlecode.mp4parser.authoring.samples.DefaultMp4SampleList$SampleImpl.asByteBuffer(DefaultMp4SampleList.java:204)
at com.flashphoner.media.F.A.A.A$1.A(Unknown Source)
at com.flashphoner.media.M.B.C.D(Unknown Source)
at com.flashphoner.server.C.A.B.A(Unknown Source)
at com.flashphoner.server.C.A.B.C(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.OutOfMemoryError: Map failed
at sun.nio.ch.FileChannelImpl.map0(Native Method)
at sun.nio.ch.FileChannelImpl.map(FileChannelImpl.java:937)
... 8 more
|
Code Block | ||
---|---|---|
| ||
Event: 1743.157 Thread 0x00007fc480375000 Exception <a 'java/lang/OutOfMemoryError': Map failed> (0x00000000a1d750b0) thrown at [/HUDSON/workspace/8-2-build-linux-amd64/jdk8u161/10277/hotspot/src/share/vm/prims/jni.cpp, line 735] |
Решение: увеличить максимальное число областей виртуальной памяти
Code Block | ||||
---|---|---|---|---|
| ||||
sysctl -w vm.max_map_count=262144 |