Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 8 Next »

WCS предоставляет возможность захвата медиапотока из файла MP4, расположенного на локальном диске сервера (Video on Demand, VOD). Полученный поток можно воспроизвести, ретранслировать, управлять им, как любым потоком на WCS-сервере. Прежде всего, данная возможность предназначена для воспроизведения записанных ранее трансляций в браузере или мобильном приложении клиента.

Описание

Для захвата VOD из файла в качестве имени потока при вызове функции session.createStream() должна быть указана ссылка на файл в виде:

vod://sample.mp4

где sample.mp4 - имя файла, который должен находиться в каталоге /usr/local/FlashphonerWebCallServer/media/

В случае, если файл с таким именем отсутствует, сервер вернет сообщение StreamStatusEvent FAILED, в поле "info" которого будет указан диагноз "File not found".

Поток, созданный таким образом, предназначен для трансляции одному пользователю (персональный VOD). В случае, если необходимо организовать полноценную онлайн-трансляцию, следует указать ссылку на файл в виде:

vod-live://sample.mp4

К такому потоку могут подключиться одновременно несколько пользователей в реальном времени.

Поддерживаемые форматы и кодеки

  • Контейнер: MP4
  • Видео: H.264
  • Аудио: AAC

Схема работы


  1. Браузер соединяется с сервером по протоколу Websocket и отправляет команду publish.
  2. Браузер захватывает микрофон и камеру и отправляет WebRTC поток H.264 + AAC на сервер с параметром record: true.
  3. WCS-сервер записывает поток в файл.
  4. Браузер останавливает публикацию.
  5. Второй браузер устанавливает соединение по Websocket, создает поток с указанием имени файла и отправляет команду play.
  6. Второй браузер получает WebRTC поток и воспроизводит этот поток на странице.

Краткое руководство по тестированию

1. Для теста используем веб-приложение Player для воспроизведения файла.

2. Загрузите файл в каталог /usr/local/FlashphonerWebCallServer/media/

3. Откройте веб-приложение Player, укажите в поле Stream имя файла:


4. Нажмите Start. Начнется воспроизведение файла:


5. Нажмите Stop для остановки воспроизведения.

6. Удалите файл из каталог /usr/local/FlashphonerWebCallServer/media/

7. Нажмите Start. Отобразится статус FAILED и сообщение "File not found":

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

Ниже описана последовательность вызовов при использовании:

примера Stream Recording для публикации потока и записи файла

recording.html

recording.js

примера Player для воспроизведения VOD-потока

player.html

player.js


1. Установка соединения с сервером для публикации и записи потока.

Flashphoner.createSession(); code

    Flashphoner.createSession({urlServer: url}).on(SESSION_STATUS.ESTABLISHED, function(session){
        ...
    });


2. Получение от сервера события, подтверждающего успешное соединение.

ConnectionStatusEvent ESTABLISHED code

    Flashphoner.createSession({urlServer: url}).on(SESSION_STATUS.ESTABLISHED, function(session){
        setStatus(session.status());
        //session connected, start playback
        publishStream(session);
    }).on(SESSION_STATUS.DISCONNECTED, function(){
        ...
    }).on(SESSION_STATUS.FAILED, function(){
        ...
    });


3. Публикация потока с указанием признака записи:

stream.publish(); code

    session.createStream({
        name: streamName,
        display: localVideo,
        record: true,
        receiveVideo: false,
        receiveAudio: false
        ...
    }).publish();


4. Получение от сервера события, подтверждающего успешную публикацию потока.

StreamStatusEvent, статус PUBLISHING code

    session.createStream({
        name: streamName,
        display: localVideo,
        record: true,
        receiveVideo: false,
        receiveAudio: false
    }).on(STREAM_STATUS.PUBLISHING, function(stream) {
        setStatus(stream.status());
        onStarted(stream);
    }).on(STREAM_STATUS.UNPUBLISHED, function(stream) {
        ...
    }).on(STREAM_STATUS.FAILED, function(stream) {
        ...
    }).publish();


5. Отправка аудио-видео потока по WebRTC

6. Остановка публикации потока.

stream.stop(); code

function onStarted(stream) {
    $("#publishBtn").text("Stop").off('click').click(function(){
        $(this).prop('disabled', true);
        stream.stop();
    }).prop('disabled', false);
}

7. Получение от сервера события, подтверждающего остановку публикации потока.

StreamStatusEvent, статус UNPUBLISHED code

    session.createStream({
        name: streamName,
        display: localVideo,
        record: true,
        receiveVideo: false,
        receiveAudio: false
    }).on(STREAM_STATUS.PUBLISHING, function(stream) {
        ...
    }).on(STREAM_STATUS.UNPUBLISHED, function(stream) {
        setStatus(stream.status());
        showDownloadLink(stream.getRecordInfo());
        onStopped();
    }).on(STREAM_STATUS.FAILED, function(stream) {
        ...
    }).publish();


8. Установка соединения с сервером для воспроизведения потока.

Flashphoner.createSession(); code

    Flashphoner.createSession({urlServer: url}).on(SESSION_STATUS.ESTABLISHED, function(session){
        ...
    });


9. Получение от сервера события, подтверждающего успешное соединение.

ConnectionStatusEvent ESTABLISHED code

    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(){
        ...
    });


10. Воспроизведение потока.

stream.play(); code

    if (Flashphoner.getMediaProviders()[0] === "MSE" && mseCutByIFrameOnly) {
        options.mediaConnectionConstraints = {
            cutByIFrameOnly: mseCutByIFrameOnly
        }
    }
    if (resolution_for_wsplayer) {
        options.playWidth = resolution_for_wsplayer.playWidth;
        options.playHeight = resolution_for_wsplayer.playHeight;
    } else if (resolution) {
        options.playWidth = resolution.split("x")[0];
        options.playHeight = resolution.split("x")[1];
    }
    stream = session.createStream(options).on(STREAM_STATUS.PENDING, function(stream) {
        ...
    });
    stream.play();


11. Получение от сервера события, подтверждающего успешное воспроизведение потока.

StreamStatusEvent, статус PLAYING code

    stream = session.createStream(options).on(STREAM_STATUS.PENDING, function(stream) {
        ...
    }).on(STREAM_STATUS.PLAYING, function(stream) {
        $("#preloader").show();
        setStatus(stream.status());
        onStarted(stream);
    }).on(STREAM_STATUS.STOPPED, function() {
        ...
    }).on(STREAM_STATUS.FAILED, function(stream) {
        ...
    }).on(STREAM_STATUS.NOT_ENOUGH_BANDWIDTH, function(stream){
        ...
    });
    stream.play();


12. Прием аудио-видео потока по Websocket и воспроизведение по WebRTC

13. Остановка воспроизведения потока.

stream.stop(); code

function onStarted(stream) {
    $("#playBtn").text("Stop").off('click').click(function(){
        $(this).prop('disabled', true);
        stream.stop();
    }).prop('disabled', false);
    ...
}


14. Получение от сервера события, подтверждающего остановку воспроизведения потока.

StreamStatusEvent, статус STOPPED code

    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

vod_live_loop=true

Захват файла, размещенного на AWS

Поток может быть захвачен из файла, размещенного на AWS в хранилище S3. В отличие от VOD захвата файла с локального диска, файл, размещенный на внешнем хранилище, загружается и воспроизводится последовательно.

Для захвата VOD из файла на AWS в качестве имени потока при вызове функции session.createStream() должна быть указана ссылка на файл в виде:

vod://s3/bucket/sample.mp4

где

  • bucket - имя корзины S3
  • sample.mp4 - имя файла

Схема работы

1. Браузер запрашивает захват потока из файла на AWS

2. WCS сервер направляет запрос AWS

3. Файл загружается на WCS сервер

4. WebRTC поток из файла передается в браузер для воспроизведения

Настройка

Для загрузки файлов из AWS необходимо указать в файле настроек flashphoner.properties данные для доступа к хранилищу S3

aws_s3_credentials=zone;login;hash

Чтобы захватывать поток из файла во время его загрузки, необходимо указать следующую настройку

vod_mp4_container_new=true

Требования к формату файлов

Заголовок (moov) должен всегда располагаться перед данными (mdat). Примерная структура файла должна быть такой:

Atom ftyp @ 0 of size: 32, ends @ 32
Atom moov @ 32 of size: 357961, ends @ 357993
     Atom mvhd @ 40 of size: 108, ends @ 148
     Atom trak @ 148 of size: 127708, ends @ 127856
         Atom tkhd @ 156 of size: 92, ends @ 248
         Atom edts @ 248 of size: 48, ends @ 296
             Atom elst @ 256 of size: 40, ends @ 296
         Atom mdia @ 296 of size: 127560, ends @ 127856
             Atom mdhd @ 304 of size: 32, ends @ 336
             Atom hdlr @ 336 of size: 45, ends @ 381
             Atom minf @ 381 of size: 127475, ends @ 127856
                 Atom vmhd @ 389 of size: 20, ends @ 409
                 Atom dinf @ 409 of size: 36, ends @ 445
                     Atom dref @ 417 of size: 28, ends @ 445
                         Atom url  @ 433 of size: 12, ends @ 445
                 Atom stbl @ 445 of size: 127411, ends @ 127856
                     Atom stsd @ 453 of size: 171, ends @ 624
                         Atom avc1 @ 469 of size: 155, ends @ 624
                             Atom avcC @ 555 of size: 53, ends @ 608
                             Atom pasp @ 608 of size: 16, ends @ 624			 ~
                     Atom stts @ 624 of size: 24, ends @ 648
                     Atom stss @ 648 of size: 568, ends @ 1216
                     Atom stsc @ 1216 of size: 28, ends @ 1244
                     Atom stsz @ 1244 of size: 63308, ends @ 64552
                     Atom stco @ 64552 of size: 63304, ends @ 127856
     Atom trak @ 127856 of size: 230039, ends @ 357895
         Atom tkhd @ 127864 of size: 92, ends @ 127956
         Atom edts @ 127956 of size: 36, ends @ 127992
             Atom elst @ 127964 of size: 28, ends @ 127992
         Atom mdia @ 127992 of size: 229903, ends @ 357895
             Atom mdhd @ 128000 of size: 32, ends @ 128032
             Atom hdlr @ 128032 of size: 45, ends @ 128077
             Atom minf @ 128077 of size: 229818, ends @ 357895
                 Atom smhd @ 128085 of size: 16, ends @ 128101
                 Atom dinf @ 128101 of size: 36, ends @ 128137
                     Atom dref @ 128109 of size: 28, ends @ 128137
                         Atom url  @ 128125 of size: 12, ends @ 128137
                 Atom stbl @ 128137 of size: 229758, ends @ 357895
                     Atom stsd @ 128145 of size: 106, ends @ 128251
                         Atom mp4a @ 128161 of size: 90, ends @ 128251
                             Atom esds @ 128197 of size: 54, ends @ 128251
                     Atom stts @ 128251 of size: 32, ends @ 128283
                     Atom stsc @ 128283 of size: 47500, ends @ 175783
                     Atom stsz @ 175783 of size: 118804, ends @ 294587
                     Atom stco @ 294587 of size: 63308, ends @ 357895
     Atom udta @ 357895 of size: 98, ends @ 357993
         Atom meta @ 357903 of size: 90, ends @ 357993
             Atom hdlr @ 357915 of size: 33, ends @ 357948
             Atom ilst @ 357948 of size: 45, ends @ 357993
                 Atom ©too @ 357956 of size: 37, ends @ 357993
                     Atom data @ 357964 of size: 29, ends @ 357993
Atom free @ 357993 of size: 8, ends @ 358001
Atom mdat @ 358001 of size: 212741950, ends @ 213099951

Управление 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

{
 "uri":"vod://sample.mp4"
 "localStreamName": "test"
}

409 - Conflict

500 - Internal error


Захватить поток из указанного файла


/vod/find
{
 "localStreamName": "test"

}
[
    {
        "localMediaSessionId": "29ec3236-1093-42bb-88d6-d4ac37af3ac0",
        "localStreamName": "test",
        "uri": "vod://sample.mp4",
        "status": "PROCESSED_LOCAL",
        "hasAudio": true,
        "hasVideo": true,
        "record": false
    }
]

200 – потоки найдены

404 – потоки не найдены

Найти VOD-потоки по указанному критерию

/vod/find_all


[
    {
        "localMediaSessionId": "29ec3236-1093-42bb-88d6-d4ac37af3ac0",
        "localStreamName": "test",
        "uri": "vod://sample.mp4",
        "status": "PROCESSED_LOCAL",
        "hasAudio": true,
        "hasVideo": true,
        "record": false
    }
]

200 – потоки найдены

404 – потоки не найдены

Найти все VOD-потоки

/vod/terminate

{
 "uri":"vod://sample.mp4"
 "localStreamName": "test"
}

200 - поток завершен

404 - поток не найден

Завершить VOD-поток

Параметры

Имя параметра

Описание

Пример

uri

Имя файла для захвата потока

vod://sample.mp4
localStreamNameИмя создаваемого потока
test

status

Текущий статус потока

PROCESSED_LOCAL
localMediaSessionIdИдентификатор медиасессии
29ec3236-1093-42bb-88d6-d4ac37af3ac0
hasAudioВ потоке есть аудио
true
hasVideoВ потоке есть видео
true
recordПоток записывается
false

Известные проблемы

1) AAC фреймы типа 0 не поддерживаются декодером и будут игнорироваться при воспроизведении захваченного потока

При этом в клиентском логе будут выведены предупреждения:

10:13:06,815 WARN AAC - AudioProcessor-c6c22de8-a129-43b2-bf67-1f433a814ba9 Dropping AAC frame that starts with 0, 119056e500
  • No labels