HTML5, getUserMedia a práce s kamerou

Má váš počítač webkameru? Pak k ní můžete přistupovat i z webové aplikace. Tedy, pokud jí to dovolíte. Ukážeme vám, jak na to, a můžete si to rovnou vyzkoušet.
Nálepky:
Tento článek je překladem tutoriálu getUserMedia #1 – Camera Access z webu Web Apprentice a jeho autorem je Rob Jones. Překlad je zde uveden s laskavým svolením autora.
Úvod
HTML5 obsahuje důležitou a zajímavou novinku, pomocí které může prohlížeč přistupovat k mikrofonu a webkameře na vašem zařízení – navigator.getUserMedia
.
Metoda getUserMedia není zatím implementována ve všech prohlížečích, ovšem to se brzy zlepší…
V prosinci 2013, kdy vznikl tento text, byl getUserMedia podporován jen v prohlížečích Google Chrome a Mozilla Firefox. Aktuální podporu najdete na caniuse.com.
Pro tuhle novinku najdeme jistě hromadu využití – od zábavných, jako je získání vaší podobizny a aplikování rozličných filtrů, až po záznam řeči a video konference.
Tento tutoriál vám předvede, jak pomocí getUserMedia
přistupovat ke kameře a jak z ní získat fotografický snímek.
Naše demo obsahuje dvě okna – živé video nahoře a z něj sejmutou fotografii dole.
Krok za krokem
1: Zprvu uvidíte v našem demu dva prázdné obdélníky a tři tlačítka.
2: Když kliknete na Start Video, tak se vás prohlížeč zeptá, zda povolíte stránce přístup ke kameře. V Google Chrome se objeví panel podobný tomu na obrázku s tlačítky Deny a Allow napravo.
V Mozilla Firefoxu se zobrazí následující dialog. Kliknutím na Share Selected Device povolíte přístup.
3: Za okamžik se vám zobrazí živé video z vaší webkamery v horním okně. Obě okna se přízpůsobí na šířku definovanou ve skriptu.
4: Klikněte na Capture Photo, kdykoliv budete chtít z videa sejmout fotografický snímek.
5: Stop Video zastaví video a vypne kameru. Můžete kameru opět spustit a zase ji zastavit, kolikrát budete chtít.
Co se děje v kódu
Náš kód má tři části – HTML značku video, které je zprvu prázdné, tři tlačítka a canvas element, zprvu také prázdný.
<video id="video"></video>
<div id="controls">
<button id="start_button">Start Video</button>
<button id="stop_button">Stop Video</button>
<button id="capture_button">Capture Photo</button>
</div>
<canvas id="canvas"></canvas>
Style blok zajistí vycentrování prvků na stránce a vykreslení okrajů kolem nich, abychom je viděli i na začátku, když jsou ještě prázdné.
Náš skript pro zjednodušení používá jQuery, které musíme načíst, než se začne vykonávat náš skript.
Protože metoda getUserMedia není zatím plně podporována, připojují k ní výrobci prohlížečů vendor prefix webkit, moz atd. Hack na začátku našeho skriptu mu umožní, aby fungoval v různých prohlížečích.
navigator.getUserMedia = ( navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia);
Náš skript si nadefinuje několik globálních proměnných, které v něm budeme používat, a pak definuje funkci ready, která se spustí po nahrání stránky.
Dále skript definuje obslužné funkce pro naše tři tlačítka. Callback pro Start Video tlačítko zavolá navigator.getUserMedia
a zapne webkameru.
Metoda navigator.getUserMedia
přijímá tři argumenty. Prvním je hash, který v našem případě určuje, že chceme přistupovat k videu, ale nikoliv ke zvuku. Tím druhým je funkce, která bude zavolána, když getUserMedia
získá přístup ke kameře. Je zavolána s argumentem stream, který reprezentuje vstup z kamery. Tato funkce propojí stream
se src
vlastností objektu video
. Toto propojení je pro Firefox a Chrome trochu odlišné. Ve Firefoxu se připojuje na vlastnost mozSrcObject
, v Chrome na vlastnost src
. Volání url.createObjectURL(stream)
obslouží případ, kdy je stream javascriptovým blobem – datovou strukturou, kterou se nebudu pro zjednodušení v tomto tutoriálu zabývat.
Dále je stream
pro další použití zkopírován do globální proměnné mediaStream
. A konečně video.play()
spustí zobrazování video vstupu na stránce v našem prvku <video>
.
Třetím argumentem metody navigator.getUserMedia
je funkce, která je zavolána, pokud nastane problém v připojování videostreamu. Celé volání tedy vypadá následovně:
navigator.getUserMedia(
{
video: true,
audio: false
},
function(stream) {
if (navigator.mozGetUserMedia) {
video.mozSrcObject = stream;
} else {
var url = window.URL || window.webkitURL;
video.src = url ? url.createObjectURL(stream) : stream;
}
mediaStream = stream;
video.play();
},
function(error) {
console.log("ERROR: " + error);
}
);
Protože se rozměry videa mohou od zařízení k zařízení lišit a protože chceme mít rozměry našeho okna pod kontrolou, musíme nastavit velikost našim prvkům video
a canvas
. Ovšem k těmto rozměrům získáme přístup až po připojení našeho zdroje videa…
Nastavení provedeme v obslužné funkci události prvku video
takto: $("video").on('canplay', function(e) { ...}.
Událost canplay
je vyvolána, když je video nahrané a může být spuštěno. Když k tomu dojde poprvé, načteme vlastnosti videoHeight
a videoWidth
zdroje a použijeme je pro určení rozměrů našeho výstupního okna.
Ve Firefoxu bylo nutné nastavit velikost canvasu již v obslužné funkci pro tlačítko Capture – netuším proč.
V tuto chvíli by již mělo video běžet a zobrazovat se v našem prvku video
a měli byste vidět indikátor na panelu prohlížeče a také na vaší kameře, které oznamují, že kamera běží.
Video by běželo tak dlouho, dokud zůstane stránka v prohlížeči otevřená. To je dle mě příliš obtěžující, proto vždy přidávám možnost video zastavit. Callback tlačítka Stop jednoduše zavolá metodu stop
objektu mediaStream
, který jsme si vytvořili dříve. Video bude zastaveno, ale jeho poslední snímek zůstane zobrazen.
Třetí tlačítko nám umožňuje sejmout aktuální snímek videa. Používá k tomu metodu drawImage
, která je součástí canvas API, a umí získávat data z různých zdrojů, včetně prvku video
. Jednoduše tuto funkci zavoláme spolu s rozměry canvasu a ona již zajistí získání snímku – šikovné a jednoduché.
Ještě si ukážeme náš celý kód pohromadě:
<video id="video"></video>
<br>
<div id="controls">
<button id="start_button">Start Video</button>
<button id="stop_button">Stop Video</button>
<button id="capture_button">Capture Photo</button>
</div>
<br>
<canvas id="canvas"></canvas>
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<style>
button {
font-size: 16pt;
}
#controls {
margin-left: auto;
margin-right: auto;
display: block;
text-align: center;
}
#canvas {
margin-left: auto;
margin-right: auto;
display: block;
background-color: #eee;
border: 1px solid black;
}
#video {
margin-left: auto;
margin-right: auto;
display: block;
border: 1px solid black;
}
</style>
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<script>
// Hack pro obsloužení vendor prefixů
navigator.getUserMedia = ( navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia);
var video = document.querySelector('video');
var canvas = document.querySelector('canvas');
var ctx;
var width = 480;
var height = 0;
var mediaStream;
var streaming;
$(document).ready(function() {
if(!navigator.getUserMedia) {
alert("Pardon - váš prohlížež nepodporuje getUserMedia - zkuste Chrome nebo Firefox");
}
ctx = canvas.getContext("2d");
// obsluha tlačítka pro Start videa
$("body").on('click', "#start_button",function(e) {
e.preventDefault();
navigator.getUserMedia(
{
video: true,
audio: false
},
function(stream) {
if (navigator.mozGetUserMedia) {
video.mozSrcObject = stream;
} else {
var url = window.URL || window.webkitURL;
video.src = url ? url.createObjectURL(stream) : stream;
}
mediaStream = stream;
video.play();
},
function(error) {
console.log("ERROR: " + error);
}
);
});
// obsluha tlačítka Stop
$("body").on('click', "#stop_button", function(e) {
e.preventDefault();
mediaStream.stop();
});
// obsluha Image Capture tlačítka
$("body").on('click', "#capture_button", function(e) {
e.preventDefault();
// ?? Kvůli Firefoxu jsem musel přidat resize canvasu
height = video.videoHeight / (video.videoWidth / width);
canvas.setAttribute('width', width);
canvas.setAttribute('height', height);
ctx.drawImage(video, 0, 0, width, height);
});
// Získá rozměry video streamu, který je připraven k přehrávání,
$("video").on('canplay', function(e) {
if (!streaming) {
height = video.videoHeight / (video.videoWidth / width);
video.setAttribute('width', width);
video.setAttribute('height', height);
streaming = true;
}
});
});
</script>
Další informace
- Mozilla dokumentace k Navigator.getUserMedia
- Mozilla tutoriál pro Web Cam Access
- getUserMedia tutoriál od by Iana Devlina
Demo a výsledný kód
- celý kód najdete na GitHubu
- funkční demo k článku
firefox 26 na ubuntu a nejede to
Jak na Ubuntu, to netuším, každopádně na Firefoxu 26 mi to jelo. Skončí to už na detekci navigator.getUsetMedia při načtení stránky nebo až při otevírání streamu? Druhý případ by měl vypsat chybu do JS console, zkuste se tam podívat.
v konzoli par chyb je ale ty pochazi od jquery
jinak pekne to rozjelo procik ale kamera se nezapla, u skype jede.
Nějak nechápu větu:
… pokud správně koukám, tak prvním parametrem je objekt.
Správně je obojí. Hash neboli asociativní pole je v JavaScriptu také objektem.
Do JS terminologie nevidim uplne moc, ale neni to spis hashtable, nez hash? Ono pretezovani pojmu by melo mit sve hranice, a myslim, ze hash uz ma vyznamu dost i tak =)
Ten význam jsem si nevymyslel já (viz wikipedia). A v anglickém originále textu je použito
hash
. Myslím, že se to používá často, ale možná je to v technické češtině spíš hovorové – překvapilo mě, že to někoho mate.neznaj, on se ten vyraz v cestine vazne moc nepouziva, zvlast u lidi kteri nepotkaly perl
Dobrý den, nejsem programátor. Při aplikaci kodu v roce 2018 dostanu na console hlášku: Uncaught TypeError: Failed to execute ‚createObjectURL‘ on ‚URL‘: No function was found that matched the signature provided.
Asi createObjectURL není pro media stream více podporován. Je možné kod aktualizovat?