...
Поддерживаемые платформы и браузеры
| Chrome 66+ | Firefox 59+ | Safari 11.1 | |
---|---|---|---|---|
Windows | + | + | ||
Mac OS | + | + | + | |
Android | + | + | ||
iOS | - | - | + |
...
Захват видеопотока с HTML5 Canvas и подготовка к его трансляции
1. Для теста используем:
- демо-сервер demo.flashphoner.com
...
- веб-приложение
...
- Canvas Streaming в браузере Chrome
2. В разделе "Send Video" выберите вариант "Canvas"
3. Нажмите кнопку "Start". Начнется трансляция изображения с HTML5 Canvas (красный квадрат), на котором проигрывается тестовый ролик:
43. Убедитесь, что поток отправляется на сервер и система работает нормально, откройте chrome://webrtc-internals
5. Откройте Two Way Streaming в отдельном окне, нажмите Connect и укажите идентификатор потока, затем нажмите Play.
6. 4. Графики воспроизведения chrome://webrtc-internals
Последовательность выполнения операций (Call Flow)
Ниже описана последовательность вызовов при использовании примера Media DevicesCanvas Streaming
mediacanvas_device_managerstreaming.html
managercanvas_streaming.js
1. Установка соединения с сервером.
Flashphoner.createSession(); code
Code Block | ||||
---|---|---|---|---|
| ||||
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 | ||||
---|---|---|---|---|
| ||||
Flashphoner.createSession({urlServer: url}).on(SESSION_STATUS.ESTABLISHED, function(session){ //session connected, start streaming startStreaming(session); ... }); |
32.1. Настройка захвата с элемента HTML5 Canvas
getConstraints(); code
Code Block | ||||
---|---|---|---|---|
| ||||
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 | ||||
---|---|---|---|---|
| ||||
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 | ||||
---|---|---|---|---|
| ||||
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 | ||||
---|---|---|---|---|
| ||||
if ($("#muteVideoToggle").is(":checked")) { muteVideo(); } mockVideoElement.play(); |
настройка публикации аудио с Canvas code
Code Block | ||||
---|---|---|---|---|
| ||||
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 | ||||
---|---|---|---|---|
| ||||
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 | ||||
---|---|---|---|---|
| ||||
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 | ||||
---|---|---|---|---|
| ||||
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 | ||||
---|---|---|---|---|
| ||||
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 | ||||
---|---|---|---|---|
| ||||
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.