Optimizing the performance of html5 video manipulation I've been working on an html5 canvas video player with a lot of fun little extras and ui toys, the main one being a chroma key (green screen) effect that allows the user to key out different colors or ranges of color while the video is playing. 

I seem to have hit a snag in the recommended chroma key method. It works, but it is a really heavy process and can tax the cpu to the point where the video will look choppy if the user is running other applications in the background. 

Here is the stripped down code I'm using for the chroma key effect:

   &lt;video id="sourceVid" controls="true"&gt;
        &lt;source src="http://s3.amazonaws.com/dfc_attachments/public/documents/3185373/AAA.webm" /&gt;
    &lt;/video&gt;
    &lt;canvas id="hCanvas"&gt;&lt;/canvas&gt;
    &lt;canvas id="dCanvas"&gt;&lt;/canvas&gt;

    &lt;script type="text/javascript"&gt;
        var doc = document;
        var sourceVid = doc.getElementById("sourceVid");
        var hCanvas = doc.getElementById("hCanvas");
        var dCanvas = doc.getElementById("dCanvas");
        var hContext = hCanvas.getContext("2d");
        var dContext = dCanvas.getContext("2d");

                    sourceVid.addEventListener('loadeddata', function() {
                        hCanvas.setAttribute('width', sourceVid.offsetWidth);
                        dCanvas.setAttribute('width', sourceVid.offsetWidth);
                        hCanvas.setAttribute('height', sourceVid.offsetHeight);
                        dCanvas.setAttribute('height', sourceVid.offsetHeight);
                    }, false);

        sourceVid.addEventListener('play', function() {
            runAnalysis();
        });

        var runAnalysis = function() {
            if (sourceVid.paused || sourceVid.ended) {
                return
            }
            frameFix();
            if (window.requestAnimationFrame) {
                requestAnimationFrame(runAnalysis);
            } else {
                setTimeout(runAnalysis, 0);
            }
        };

        var frameFix = function() {

            hContext.drawImage(sourceVid, 0, 0, sourceVid.videoWidth, sourceVid.videoHeight);

            var frame = hContext.getImageData(0, 0, sourceVid.videoWidth, sourceVid.videoHeight);

            var length = frame.data.length;
            for (var i = 0; i &lt; length; i++) {
                var r = frame.data[i * 4 + 0];
                var g = frame.data[i * 4 + 1];
                var b = frame.data[i * 4 + 2];

                if (g &gt;= 0 &amp;&amp; g &lt; 100 &amp;&amp; r &gt;= 0 &amp;&amp; r &lt; 100 &amp;&amp; b &gt;= 0 &amp;&amp; b &lt; 100) {
                    frame.data[i * 4 + 3] = 0;
                }
            }
            dContext.putImageData(frame, 0, 0);
            return
        };


Live Demo

Hoping to find ways to further optimize this for performance.
After back and forth with ChrisW and yourself, it seems I found a glaring bug

    var frameFix = function() {

        hContext.drawImage(sourceVid, 0, 0, sourceVid.videoWidth, sourceVid.videoHeight);

        var frame = hContext.getImageData(0, 0, sourceVid.videoWidth, sourceVid.videoHeight);

        var length = frame.data.length;
        for (var i = 0; i &lt; length; i++) {
            var r = frame.data[i * 4 + 0];
            var g = frame.data[i * 4 + 1];
            var b = frame.data[i * 4 + 2];

            if (g &gt;= 0 &amp;&amp; g &lt; 100 &amp;&amp; r &gt;= 0 &amp;&amp; r &lt; 100 &amp;&amp; b &gt;= 0 &amp;&amp; b &lt; 100) {
                frame.data[i * 4 + 3] = 0;
            }
        }
        dContext.putImageData(frame, 0, 0);
        return
    };


Since in frame.data you have 4 data points per pixel, you only need to go as far as frame.data.length / 4, this should make your code 4 times faster.

This observation with ChrisW's common sense observations makes for:

var frameFix = function() 
{
  hContext.drawImage(sourceVid, 0, 0, sourceVid.videoWidth, sourceVid.videoHeight);

  var frame  = hContext.getImageData(0, 0, sourceVid.videoWidth, sourceVid.videoHeight),
      data   = frame.data,
      length = data.length, i;

  for (i = 0; i &lt; length; i += 4) 
    if (data[i] &lt; 100 &amp;&amp; data[i + 1] &lt; 100 &amp;&amp; data[i + 2] &lt; 100) 
      data[i + 3] = 0;

  dContext.putImageData(frame, 0, 0);
};