Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Поддерживаемые платформы и браузеры


 

Chrome 66+

Firefox 59+

Safari 11.1

Windows

+

+


Mac OS

+

+

+

Android

+

+


iOS

-

-

+

...

Захват видеопотока с HTML5 Canvas и подготовка к его трансляции

1. Для теста используем:

  • демо-сервер demo.flashphoner.com

...

  • веб-приложение

...

https://demo.flashphoner.com/client2/examples/demo/streaming/media_devices_manager/media_device_manager.html

Image Removed

2. В разделе "Send Video" выберите вариант "Canvas"

Image Removed

3. Нажмите кнопку "Start". Начнется трансляция изображения с HTML5 Canvas (красный квадрат), на котором проигрывается тестовый ролик:

Image RemovedImage Added

43. Убедитесь, что поток отправляется на сервер и система работает нормально, откройте chrome://webrtc-internals

Image RemovedImage Added

5. Откройте Two Way Streaming в отдельном окне, нажмите Connect и укажите идентификатор потока, затем нажмите Play.

Image Removed

6. 4. Графики воспроизведения chrome://webrtc-internals

Image RemovedImage Added

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

Ниже описана последовательность вызовов при использовании примера Media DevicesCanvas Streaming

mediacanvas_device_managerstreaming.html

managercanvas_streaming.js


1. Установка соединения с сервером.

Flashphoner.createSession(); code

Code Block
languagejs
themeRDark
    Flashphoner.createSession({urlServer: url}).on(SESSION_STATUS.ESTABLISHED, function(session){
        //session connected, start streaming
        startStreaming(session);
    }).on(SESSION_STATUS.DISCONNECTED, function(){
        setStatus(SESSION_STATUS.DISCONNECTED);
        onStopped();
    }).on(SESSION_STATUS.FAILED, function(){
        setStatus(SESSION_STATUS.FAILED);
        onStopped();
    });

...

ConnectionStatusEvent ESTABLISHED code

Code Block
languagejs
themeRDark
    Flashphoner.createSession({urlServer: url}).on(SESSION_STATUS.ESTABLISHED, function(session){
        //session connected, start streaming
        startStreaming(session);
        ...
    });

32.1. Настройка захвата с элемента HTML5 Canvas

getConstraints(); code

Code Block
languagejs
themeRDark
function    if (constraints.videogetConstraints() {
        if (constraints.customStream) {var constraints;
            constraints.customStreamvar stream = canvas.captureStreamcreateCanvasStream(30);
    constraints = {
      constraints.video =  audio: false;,
        } else {video: false,
            ...
    customStream: stream
    };
    return constraints;
}

4. Публикация потока.

stream.publish(); createCanvasStream():

настройка захвата видео с элемента Canvas  code

Code Block
languagejs
themeRDark
    publishStreamvar canvasContext = sessioncanvas.createStream({getContext("2d");
    var canvasStream   name: streamName,
        display: localVideo,
        cacheLocalResources: true,
        constraints: constraints,
        mediaConnectionConstraints: mediaConnectionConstraints
    }).on(STREAM_STATUS.PUBLISHING, function (publishStream) {= canvas.captureStream(30);
    mockVideoElement =   ...
    }).on(STREAM_STATUS.UNPUBLISHED, function () {document.createElement("video");
    mockVideoElement.src =   '../.
    }).on(STREAM_STATUS.FAILED, function () {./dependencies/media/test_movie.mp4';
        ...
    })mockVideoElement.loop = true;
    publishStream.publish();

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

...

mockVideoElement.muted = true;

отрисовка видео на элементе Canvas с частотой 30 fps code

Code Block
languagejs
themeRDark
    publishStream = session.createStream(mockVideoElement.addEventListener("play", function () {
        name: streamName,
        display: localVideo,var $this = this;
        cacheLocalResources: true,
        constraints: constraints,(function loop() {
        mediaConnectionConstraints: mediaConnectionConstraints
   if }).on(STREAM_STATUS.PUBLISHING, function (publishStream(!$this.paused && !$this.ended) {
        $("#testBtn").prop('disabled', true);
        var video = document.getElementById(publishStream.id())canvasContext.drawImage($this, 0, 0);
        //resize local if resolution is available
        if (video.videoWidth > 0 && video.videoHeight > 0) {setTimeout(loop, 1000 / 30); // drawing at 30fps
            resizeLocalVideo({target: video});
        }
        enableMuteToggles(true)();
    }, 0);

воспроизведение тестового ролика на Canvas code

Code Block
languagejs
themeRDark
   if ($("#muteVideoToggle").is(":checked")) {
            muteVideo();
        }
     mockVideoElement.play();

настройка публикации аудио с Canvas code

Code Block
languagejs
themeRDark
    if ($("#muteAudioToggle#sendAudio").is("':checked"')) {
        mockVideoElement.muted =   muteAudio()false;
        try }{
        //remove resize listener in casevar thisaudioContext video= was cached earlier
        video.removeEventListener('resize', resizeLocalVideonew (window.AudioContext || window.webkitAudioContext)();
        video.addEventListener('resize', resizeLocalVideo);
        setStatus(STREAM_STATUS.PUBLISHING);

        //play preview
        var constraints = } catch (e) {
            audio: $("#playAudio").is(':checked'),
            video: $("#playVideo").is(':checked')console.warn("Failed to create audio context");
        };
        var source if= (constraints.video) {audioContext.createMediaElementSource(mockVideoElement);
        var destination   constraints.video = {
                width: (!$("#receiveDefaultSize").is(":checked")) ? parseInt($('#receiveWidth').val()) : 0,= audioContext.createMediaStreamDestination();
                height: (!$("#receiveDefaultSize").is(":checked")) ? parseInt($('#receiveHeight').val()) : 0,source.connect(destination);
                bitrate: (!$("#receiveDefaultBitrate").is(":checked")) ? $("#receiveBitrate").val() : 0,
                quality: (!$("#receiveDefaultQuality").is(":checked")) ? $('#quality').val() : 0
            };
        }
        previewStream =canvasStream.addTrack(destination.stream.getAudioTracks()[0]);
    }

3. Публикация потока.

stream.publish(); code

Code Block
languagejs
themeRDark
    session.createStream({
            name: streamName,
            display: remoteVideolocalVideo,
            constraintscacheLocalResources: constraintstrue,
        constraints: constraints
    })...
        });on(STREAM_STATUS.PUBLISHING, function (stream) {
        previewStream.play();...
    }).on(STREAM_STATUS.UNPUBLISHED, function () {
        ...
    }).on(STREAM_STATUS.FAILED, function () {
        ...
    });
    publishStream.publish();

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

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

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

StreamStatusEvent, статус PUBLISHING code

Code Block
languagejs
themeRDark
    publishStream = session.createStream({
        name: streamName,
     ...
   display: localVideo,
        cacheLocalResources: true,
        constraints: constraints,
        mediaConnectionConstraints: mediaConnectionConstraints
    }).on(STREAM_STATUS.PUBLISHING, function (publishStreamstream) {
        setStatus("#publishStatus", ...STREAM_STATUS.PUBLISHING);
        previewStream = session.createStream({playStream();
            name: streamName,
            display: remoteVideo,
            constraints: constraints
  onPublishing(stream);
      }).on(STREAM_STATUS.PLAYINGUNPUBLISHED, function (previewStream) {
            ...
        }).on(STREAM_STATUS.STOPPEDFAILED, function () {
        ...
    publishStream}).stoppublish();
        }).on(STREAM_STATUS.FAILED, function 

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

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

stream.stop(); code

Code Block
languagejs
themeRDark
function stopStreaming() {
    ...
        //preview failed, stop publishStream
            if (publishStream.status() == STREAM_STATUS.PUBLISHING) {
                setStatus(STREAM_STATUS.FAILED);
     if (publishStream != null && publishStream.published()) {
           publishStream.stop();
            }
        }stopCanvasStream();
        previewStream.play();}

stopCanvasStream() code

Code Block
languagejs
themeRDark
function stopCanvasStream() {
    }).on(STREAM_STATUS.UNPUBLISHED, function (if(mockVideoElement) {
        ...
mockVideoElement.pause();
        })mockVideoElement.on(STREAM_STATUS.FAILED, function () {removeEventListener('play', null);
        ...
mockVideoElement =   })null;
    publishStream.publish();

...

}
}

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

StreamStatusEvent, статус UNPUBLISHED code

Code Block
languagejs
themeRDark
    publishStream = session.createStream({
        name: streamName,...
        display: localVideo,
        cacheLocalResources: true,
        constraints: constraints,
        mediaConnectionConstraints: mediaConnectionConstraints
    }).on(STREAM_STATUS.PUBLISHING, function (publishStreamstream) {
        ...
    }).on(STREAM_STATUS.UNPUBLISHED, function () {
        setStatus("#publishStatus", STREAM_STATUS.UNPUBLISHED);
        //enable start button
        onStoppeddisconnect();
    }).on(STREAM_STATUS.FAILED, function () {
        ...
    });
    publishStream.publish();

Разработчику

Возможность захвата видеопотока с элемента HTML5 Canvas доступна в WebSDK WCS, начиная с данной версии JavaScript API. Исходный код примера располагается в каталоге examples/demo/streaming/mediacanvas_devices_managerstreaming/.

Данную возможность можно использовать также для захвата собственного видеопотока, отрисовываемого в браузере, например:

...

4) Если публикация потока идет с Windows 10 или Windows 8 и в браузере Google Chrome включено аппаратное ускорение, могут быть проблемы с битрейтом.

Симптомы: качество видео плохое, мутное, битрейт в chrome://webrtc-internals показывает меньше 100 kbps.
Решение: отключите аппаратное ускорение в браузере, переключите браузер или сервер на использование кодека VP8.

 code