Edit in JSFiddle

// How to use:
// - Works only in browsers supporting getUserMedia HTML5 api, chrome, firefox, android. The browser will ask for permission to use access the camera.
// 1. Enter the feed id to publish to.
// 2. Enter either the api key or publish key, for non public feeds, an access key is needed to show the live frame if the api key is not used
// 3. If you're not using the api key and the feed isn't public, enter the accesskey to allow access to the current feed frame.
// 4. Start the webcam and upload frames.

var feedId = "";

var apiKey = "";
var publishKey = "";
var accessKey = ""; // required for only 'current live frame' to work for non-public feeds, only if apiKey is not used

// the time the frame was recorded, this is optional, current time will be used if not specified
var frameTime = "";

var apiBaseUrl = "//www.teleport.nu/api/v1";

// don't cache ajax or content won't be fresh
$.ajaxSetup({
    cache: false
});

var url = apiBaseUrl + "/frame-set?feedid=" + feedId + "&frametime=" + frameTime + "&apikey=" + apiKey + "&publishkey=" + publishKey;

var liveFrameUrl = apiBaseUrl + "/frame-get?feedid=" + feedId + "&sizecode=480p" + "&apikey=" + apiKey + "&accesskey=" + accessKey;

// load the current live frame
if (feedId) {
    $("#liveFrame").attr('src', liveFrameUrl + '&jsfiddlecb=' + Math.random());
}

function uploadFormData(formData) {

    if (!feedId) {
        alert("*** Specify the feed id to publish to. ***");
    }
    // upload the provided form data to Teleport
    $.ajax({
        url: url,
        method: 'POST',
        data: formData,
        async: true,
        cache: false,
        contentType: false,
        enctype: 'multipart/form-data',
        processData: false,
        success: function (data, textStatus, jqXHR) {
            // got the result, just a status code on delete api, http status 200 means upload went ok
            $("#response").html(jqXHR.status);
            // update the live frame image, use the cache bust random parameter to force the browser to hit the server, else the new image may not load
            $("#liveFrame").attr('src', liveFrameUrl + '&jsfiddlecb=' + Math.random());
        },
        error: function (jqxhr, textStatus, error) {
            $("#response").html("Error: " + jqxhr.status + ', ' + textStatus + ', ' + error + ', ' + jqxhr.responseText);
            $("#liveFrame").attr('src', "");
        }
    });
}

// webcam code, should work in chrome, firefox and opera, android

var video = document.querySelector('video');
var canvas = document.querySelector('canvas');
var formData = null;
var localMediaStream = null;

function hasGetUserMedia() {
    return !!(navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia);
}

function startVideo() {
    if (hasGetUserMedia()) {
        // Good to go!
    } else {
        alert('getUserMedia() is not supported in your browser.');
        return;
    }

    navigator.anyGetUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;

    // - resolution selection may not be supported by every browser
    navigator.anyGetUserMedia({
        video: {
            mandatory: {
                minWidth: 1280,
                minHeight: 720,
                maxWidth: 1920,
                maxHeight: 1080
            }
        },
        audio: false
    },

    function (stream) {
        video.src = window.URL.createObjectURL(stream);
        localMediaStream = stream;
        $("#captureButton").removeAttr('disabled');
    }, function (e) {
        console.log('Reeeejected!', e);
    });
}

function captureFrame() {
    if (localMediaStream) {
        canvas.width = video.videoWidth;
        canvas.height = video.videoHeight;
        var ctx = canvas.getContext('2d');
        ctx.drawImage(video, 0, 0);

        canvas.toBlob(function (blob) {
            if (console) {
                console.log(blob);
            }
            formData = new FormData();
            formData.append('file', blob, "jsfiddleimage.jpg");

            $("#uploadButton").removeAttr('disabled');
        }, "image/jpeg");

        //img.src = canvas.toDataUrl();
    }
}

// ui 
//video.addEventListener('click', captureFrame, false);
$("#startVideoButton").click(function () {
    startVideo();
});
$("#stopVideoButton").click(function () {
    if (localMediaStream) {
        localMediaStream.stop();
    }
});
$("#captureButton").click(function () {
    captureFrame();
});
$("#uploadButton").click(function () {
    uploadFormData(formData);
});


// canvas to blob polyfill, browsers don't really support this well
! function (a) {
    "use strict";
    var b = a.HTMLCanvasElement && a.HTMLCanvasElement.prototype,
        c = a.Blob && function () {
            try {
                return Boolean(new Blob)
            } catch (a) {
                return !1
            }
        }(),
        d = c && a.Uint8Array && function () {
            try {
                return 100 === new Blob([new Uint8Array(100)]).size
            } catch (a) {
                return !1
            }
        }(),
        e = a.BlobBuilder || a.WebKitBlobBuilder || a.MozBlobBuilder || a.MSBlobBuilder,
        f = (c || e) && a.atob && a.ArrayBuffer && a.Uint8Array && function (a) {
            var b, f, g, h, i, j;
            for (b = a.split(",")[0].indexOf("base64") >= 0 ? atob(a.split(",")[1]) : decodeURIComponent(a.split(",")[1]), f = new ArrayBuffer(b.length), g = new Uint8Array(f), h = 0; h < b.length; h += 1) g[h] = b.charCodeAt(h);
            return i = a.split(",")[0].split(":")[1].split(";")[0], c ? new Blob([d ? g : f], {
                type: i
            }) : (j = new e, j.append(f), j.getBlob(i))
        };
    a.HTMLCanvasElement && !b.toBlob && (b.mozGetAsFile ? b.toBlob = function (a, c, d) {
        d && b.toDataURL && f ? a(f(this.toDataURL(c, d))) : a(this.mozGetAsFile("blob", c))
    } : b.toDataURL && f && (b.toBlob = function (a, b, c) {
        a(f(this.toDataURL(b, c)))
    })), "function" == typeof define && define.amd ? define(function () {
        return f
    }) : a.dataURLtoBlob = f
}(this);
<b>Teleport webcam frame upload</b>

<!--based on https://github.com/leemachin/say-cheese -->
<br/>
<br/>
<button id="startVideoButton">Start video</button>
<button id="stopVideoButton">Stop video</button>
<br/>Live stream:
<br/>
<video autoplay style="max-height: 160px"></video>
<br/>
<br/>
<input id="captureButton" type="button" value="Capture" disabled />
<br/>Captured frame:
<br/>
<canvas style="max-height: 160px"></canvas>
<br/>
<input id="uploadButton" type="button" value="Upload" disabled />
<br/>
<br/>Upload response:
<div id="response"></div>
<br/>
<br/>Current feed live frame:
<br/>
<img id="liveFrame" src="" style="max-height: 160px" />