Přejít k navigační liště

Zdroják » JavaScript » HTML5, getUserMedia a práce s kamerou

HTML5, getUserMedia a práce s kamerou

Články JavaScript

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.

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.

Demo 1 screenshot for this tutorial

Krok za krokem

1: Zprvu uvidíte v našem demu dva prázdné obdélníky a tři tlačítka.

Image 1 for this tutorial

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 DenyAllow napravo.

Image 2 for this tutorial

V Mozilla Firefoxu se zobrazí následující dialog. Kliknutím na Share Selected Device povolíte přístup.

Image 3 for this tutorial

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.

Image 4 for this tutorial

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 videocanvas. 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 videoHeightvideoWidth 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>   &nbsp;
<button id="stop_button">Stop Video</button>     &nbsp;
<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

Demo a výsledný kód

Komentáře

Subscribe
Upozornit na
guest
9 Komentářů
Nejstarší
Nejnovější Most Voted
Inline Feedbacks
View all comments
Karel

firefox 26 na ubuntu a nejede to

Karel

v konzoli par chyb je ale ty pochazi od jquery
jinak pekne to rozjelo procik ale kamera se nezapla, u skype jede.

Martin

Nějak nechápu větu:

Prvním je hash, který v našem případě určuje, že chceme přistupovat k videu, ale nikoliv ke zvuku

… pokud správně koukám, tak prvním parametrem je objekt.

Martin Pecka

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 =)

Karel

neznaj, on se ten vyraz v cestine vazne moc nepouziva, zvlast u lidi kteri nepotkaly perl

Vladimir

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?

Enum a statická analýza kódu

Mám jednu univerzální radu pro začínající programátorty. V učení sice neexistují rychlé zkratky, ovšem tuhle radu můžete snadno začít používat a zrychlit tak tempo učení. Tou tajemnou ingrediencí je statická analýza kódu. Ukážeme si to na příkladu enum.

Pocta C64

Za prvopočátek své programátorské kariéry vděčím počítači Commodore 64. Tehdy jsem genialitu návrhu nemohl docenit. Dnes dokážu lehce nahlédnout pod pokličku. Chtěl bych se o to s vámi podělit a vzdát mu hold.