Stream Local Snapshot¶
Пример, демонстрирующий получение снапшота опубликованного потока в браузере¶
В данном примере показано, как получить снапшот потока, опубликованного на Web Call Server, локально в браузере.
На скриншоте ниже был получен снапшот публикуемого потока.
После начала публикации видео с камеры воспроизводится в Local
элементе слева.
После клика на кнопке Take a snapshot
c HTML5 видео элемента захватывается снапшот, который в случае успешного получения будет отображен в Snapshot
элементе справа.
Код примера¶
Код данного примера находится на WCS-сервере по следующему пути:
/usr/local/FlashphonerWebCallServer/client2/examples/demo/streaming/stream-local-snapshot
- stream-local-snapshot.css - файл стилей
- stream-locall-snapshot.html - страница примера
- stream-local-snapshot.js - скрипт, обеспечивающий работу примера
Тестировать данный пример можно по следующему адресу:
https://host:8888/client2/examples/demo/streaming/stream-local-snapshot/stream-local-snapshot.html
Здесь host - адрес WCS-сервера.
Работа с кодом примера¶
Для разбора кода возьмем версию файла stream-local-snapshot.js
с хешем ecbadc3
, которая находится здесь и доступна для скачивания в соответствующей сборке 2.0.212.
1. Инициализация API¶
Flashphoner.init()
code
2. Инициализация элементов страницы и запоминание размеров картинки просмотра снапшота¶
localVideo = document.getElementById("localVideo");
snapshotImg = document.getElementById("snapshotImg");
canvas = document.getElementById("canvas");
//preview size
snapshotImgSize = {
w: snapshotImg.width,
h: snapshotImg.height
};
Здесь
localVideo
-div
, в котором создается видеоэлемент для захвата потокаsnapshotImg
-img
элемент для просмотра картинки снапшотаcanvas
- элемент для отрисовки захваченного изображения и преобразования в PNGsnapshotImgSize
- структура для хранения размеров картинки просмотра снапшота
3. Подключение к серверу¶
Flashphoner.createSession()
code
Flashphoner.createSession({urlServer: url}).on(SESSION_STATUS.ESTABLISHED, function(session){
...
}).on(SESSION_STATUS.DISCONNECTED, function(){
...
}).on(SESSION_STATUS.FAILED, function(){
...
});
4. Получение от сервера события, подтверждающего успешное соединение¶
ConnectionStatusEvent ESTABLISHED
code
Flashphoner.createSession({urlServer: url}).on(SESSION_STATUS.ESTABLISHED, function(session){
//session connected, start streaming
startStreaming(session);
}).on(SESSION_STATUS.DISCONNECTED, function(){
...
}).on(SESSION_STATUS.FAILED, function(){
...
});
5. Публикация видеопотока¶
Session.createStream()
, Stream.publish()
code
При создании потока передаются параметры:
streamName
- имя видеопотокаlocalVideo
-div
элемент, в котором будет отображаться видео с камеры
session.createStream({
name: streamName,
display: localVideo,
cacheLocalResources: true,
receiveVideo: false,
receiveAudio: false
...
}).publish();
6. Получение от сервера события, подтверждающего успешную публикацию¶
StreamStatusEvent PUBLISHING
code
session.createStream({
...
}).on(STREAM_STATUS.PUBLISHING, function(publishStream){
setStatus(STREAM_STATUS.PUBLISHING);
onPublishing(publishStream);
}).on(STREAM_STATUS.UNPUBLISHED, function(){
...
}).on(STREAM_STATUS.FAILED, function(){
...
}).publish();
7. Вызов функции захвата снапшота по нажатию кнопки¶
8. Отрисовка кадра, захваченного из видео, на канвасе, и преобразование в PNG¶
function snapshot(stream) {
let video = document.getElementById(stream.id());
let canvasContext = canvas.getContext("2d");
if (video === undefined) {
console.log("Failed to get video item for stream " + stream.name);
} else {
let videoSize = {
w: video.videoWidth,
h: video.videoHeight
};
// Draw snapshot on hidden canvas in full video size
canvas.width = videoSize.w;
canvas.height = videoSize.h;
canvasContext.drawImage(video, 0, 0, canvas.width, canvas.height);
let data = canvas.toDataURL('image/png');
if (data === undefined) {
console.log("Failed to get image data from canvas");
} else {
...
}
}
}
9. Масштабирование картинки снапшота для предварительного просмотра и добавление данных в img
элемент¶
function snapshot(stream) {
let video = document.getElementById(stream.id());
let canvasContext = canvas.getContext("2d");
if (video === undefined) {
console.log("Failed to get video item for stream " + stream.name);
} else {
...
if (data === undefined) {
console.log("Failed to get image data from canvas");
} else {
// Downscale snapshot preview keeping video aspect ratio
let previewSize;
previewSize = downScaleToFitSize(videoSize.w, videoSize.h, snapshotImgSize.w, snapshotImgSize.h);
console.log("previewSize: " + previewSize.w + "x" + previewSize.h);
snapshotImg.style.width = previewSize.w + "px";
snapshotImg.style.height = previewSize.h + "px";
// Snapshot preview vertical align
let margin = 0;
if (snapshotImgSize.h - previewSize.h > 1) {
margin = Math.floor((snapshotImgSize.h - previewSize.h) / 2);
}
snapshotImg.style.margin = margin + "px auto";
// Set image data to snapshot page item. "Open image in new tab" or "Save image as" will open full size snapshot
snapshotImg.setAttribute('src', data);
}
}
}
10. Служебная функция для масштабирования изображения¶
function downScaleToFitSize(videoWidth, videoHeight, dstWidth, dstHeight) {
let newWidth, newHeight;
let videoRatio = videoWidth / videoHeight;
let dstRatio = dstWidth / dstHeight;
if (dstRatio > videoRatio) {
newHeight = dstHeight;
newWidth = Math.floor(videoRatio * dstHeight);
} else {
newWidth = dstWidth;
newHeight = Math.floor(dstWidth / videoRatio);
}
return {
w: newWidth,
h: newHeight
};
}
11. Остановка публикации видеопотока¶
Stream.stop()
code
function onPublishing(stream) {
$("#publishBtn").text("Stop").off('click').click(function(){
$(this).prop('disabled', true);
stream.stop();
}).prop('disabled', false);
...
}
12. Получение от сервера события, подтверждающего успешную остановку публикации¶
StreamStatusEvent UNPUBLISHED code