From 4b71fef0c1e29c89f06389b6db81cd578d028f12 Mon Sep 17 00:00:00 2001 From: Gubolin Date: Sun, 10 Aug 2014 20:04:52 +0200 Subject: add camera streaming blocks (fix #460) --- threads.js | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) (limited to 'threads.js') diff --git a/threads.js b/threads.js index 3324ac6..cb6dab7 100644 --- a/threads.js +++ b/threads.js @@ -1,5 +1,5 @@ /* - + threads.js a tail call optimized blocks-based programming language interpreter @@ -2732,6 +2732,73 @@ Process.prototype.doPlayNoteForSecs = function (pitch, secs) { this.pushContext(); }; +// Process camera streaming primitives + +Process.prototype.doStreamCamera = function () { + var myself = this; + var video = this.context.activeStream || null; + + var stage = this.homeContext.receiver.parentThatIsA(StageMorph); + if (!stage.trailsCanvas) { + stage.trailsCanvas = newCanvas(stage.dimensions); + } + + if (video === null) { + video = document.createElement('video'); + video.width = stage.dimensions.x; + video.height = stage.dimensions.y; + + this.context.activeStream = video; + + var videoObject = {'video': true, 'audio': false}; + + if (navigator.getUserMedia) { + navigator.getUserMedia(videoObject, function (stream) { + video.src = stream; + video.play(); + }, this.handleError); // TODO: improve error handling + } else if (navigator.webkitGetUserMedia) { + navigator.webkitGetUserMedia(videoObject, function (stream) { + video.src = window.webkitURL.createObjectURL(stream); + video.play(); + }, this.handleError); + } else if (navigator.mozGetUserMedia) { + navigator.mozGetUserMedia(videoObject, function (stream) { + video.src = window.URL.createObjectURL(stream); + video.play(); + }, this.handleError); + } + } else { + var canvas = stage.trailsCanvas; + var context = canvas.getContext('2d'); + + if (video.readyState !== 0) { + try { + context.drawImage(video, 0, 0, video.width, video.height); + stage.changed(); + } catch (e) { + if (e.name !== 'NS_ERROR_NOT_AVAILABLE') { + // https://bugzilla.mozilla.org/show_bug.cgi?id=879717 + throw e; + } + } + } + } + this.pushContext('doYield'); + this.pushContext(); +}; + +Process.prototype.doStopCamera = function () { + var stage = this.homeContext.receiver.parentThatIsA(StageMorph); + if (stage) { + stage.threads.processes.forEach(function (thread) { + if (thread.context.activeStream) { + thread.popContext(); + } + }); + } +}; + // Process constant input options Process.prototype.inputOption = function (dta) { @@ -2808,6 +2875,7 @@ Process.prototype.reportFrameCount = function () { startValue initial value for interpolated operations activeAudio audio buffer for interpolated operations, don't persist activeNote audio oscillator for interpolated ops, don't persist + activeStream video element for camera streaming, don't persist isLambda marker for return ops isImplicitLambda marker for return ops isCustomBlock marker for return ops @@ -2835,6 +2903,7 @@ function Context( this.startTime = null; this.activeAudio = null; this.activeNote = null; + this.activeStream = null; this.isLambda = false; // marks the end of a lambda this.isImplicitLambda = false; // marks the end of a C-shaped slot this.isCustomBlock = false; // marks the end of a custom block's stack -- cgit v1.3.1 From e55c5e035a46c2a3353ce3f21bca3daf6b3fee6c Mon Sep 17 00:00:00 2001 From: Gubolin Date: Tue, 12 Aug 2014 11:32:26 +0200 Subject: add simple motion detection --- blocks.js | 1 + objects.js | 1 + threads.js | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 83 insertions(+), 1 deletion(-) (limited to 'threads.js') diff --git a/blocks.js b/blocks.js index 2e297ab..5f67107 100644 --- a/blocks.js +++ b/blocks.js @@ -6571,6 +6571,7 @@ InputSlotMorph.prototype.messagesReceivedMenu = function () { InputSlotMorph.prototype.collidablesMenu = function () { var dict = { 'mouse-pointer' : ['mouse-pointer'], + 'camera motion' : ['camera motion'], edge : ['edge'], 'pen trails' : ['pen trails'] }, diff --git a/objects.js b/objects.js index 06bab19..37d66b2 100644 --- a/objects.js +++ b/objects.js @@ -4268,6 +4268,7 @@ StageMorph.prototype.init = function (globals) { this.paletteCache = {}; // not to be serialized (!) this.lastAnswer = ''; // last user input, do not persist this.activeSounds = []; // do not persist + this.lastCameraCanvas = null; this.trailsCanvas = null; this.isThreadSafe = false; diff --git a/threads.js b/threads.js index cb6dab7..4c70bd5 100644 --- a/threads.js +++ b/threads.js @@ -2355,6 +2355,24 @@ Process.prototype.objectTouchingObject = function (thisObj, name) { } else { stage = thisObj.parentThatIsA(StageMorph); if (stage) { + if (this.inputOption(name) === 'camera motion') { + var motionCanvas = this.getCameraMotion(); + + var x = thisObj.xPosition() + 210, y = 170 - thisObj.yPosition(); + // ouch! hardcoded ^ ^ + var motionData = motionCanvas.getContext('2d').getImageData( + x, y, thisObj.width(), thisObj.height()); + var i = 0, average = 0; + while (i < (motionData.data.length * 0.25)) { + average += (motionData.data[i*4] + motionData.data[i*4+1] + + motionData.data[i*4+2]) / 3; + ++i; + } + average = Math.round(average / (motionData.data.length * 0.25)); + if (average > 10) { + return true; + } + } if (this.inputOption(name) === 'edge' && !stage.bounds.containsRectangle(thisObj.bounds)) { return true; @@ -2768,12 +2786,29 @@ Process.prototype.doStreamCamera = function () { video.play(); }, this.handleError); } + stage.lastCameraCanvas = newCanvas(stage.dimensions); } else { var canvas = stage.trailsCanvas; var context = canvas.getContext('2d'); - if (video.readyState !== 0) { + if (video.readyState == 4) { try { + // https://stackoverflow.com/questions/23840880/check-whether-canvas-is-black + // check whether lastCameraCanvas is white -> copy video canvas + // otherwise you would have a 'motion' when the first camera picture is loaded + var tmp = document.createElement('canvas'), + ctx = tmp.getContext('2d'), result; + tmp.width = tmp.height = 1; + ctx.drawImage(stage.lastCameraCanvas, 0, 0, 1, 1); + result = ctx.getImageData(0, 0, 1, 1); + if (result.data[0] + result.data[1] + result.data[2] + + result.data[3] === 0) { + stage.lastCameraCanvas.getContext('2d'). + drawImage(video, 0, 0, video.width, video.height); + } else { + var dest = stage.lastCameraCanvas.getContext('2d'); + dest.drawImage(stage.trailsCanvas, 0, 0); + } context.drawImage(video, 0, 0, video.width, video.height); stage.changed(); } catch (e) { @@ -2799,6 +2834,51 @@ Process.prototype.doStopCamera = function () { } }; +Process.prototype.getCameraMotion = function () { + // see https://www.adobe.com/devnet/html5/articles/javascript-motion-detection.html + fastAbs = function (value) // faster, but less acurate + { return (value ^ (value >> 31)) - (value >> 31); }; + + threshold = function (value) + { return (value > 0x15) ? 0xFF : 0; }; + + diff = function (target, data1, data2) { + if (data1.length != data2.length) return null; + var i = 0; + while (i < (data1.length * 0.25)) { + var average1 = (data1[4*i] + data1[4*i+1] + data1[4*i+2]) / 3; + var average2 = (data2[4*i] + data2[4*i+1] + data2[4*i+2]) / 3; + var diff = threshold(fastAbs(average1 - average2)); + target[4*i] = diff; + target[4*i+1] = diff; + target[4*i+2] = diff; + target[4*i+3] = 0xFF; + ++i; + } + }; + + var stage = this.homeContext.receiver.parentThatIsA(StageMorph); + if (!stage.trailsCanvas || !stage.lastCameraCanvas) { + var canv = newCanvas(stage.dimensions); + var ctx = canv.getContext('2d'); + ctx.fill(); + return canv; + } + + var canvasSource = stage.trailsCanvas; + var contextSource = canvasSource.getContext('2d'); + var width = canvasSource.width, + height = canvasSource.height; + var sourceData = contextSource.getImageData(0, 0, width, height); + var lastImageData = + stage.lastCameraCanvas.getContext('2d').getImageData(0, 0, width, height); + var blendedData = contextSource.createImageData(width, height); + var blendedCanvas = newCanvas(stage.dimensions); + diff(blendedData.data, sourceData.data, lastImageData.data); + blendedCanvas.getContext('2d').putImageData(blendedData, 0, 0); + return blendedCanvas; +}; + // Process constant input options Process.prototype.inputOption = function (dta) { -- cgit v1.3.1 From 6560149027b29c4e2844e3bd52e8731379fb1b91 Mon Sep 17 00:00:00 2001 From: Gubolin Date: Wed, 13 Aug 2014 13:35:14 +0200 Subject: add motion reporters --- blocks.js | 1 - objects.js | 16 +++++++++++++ threads.js | 80 ++++++++++++++++++++++++++++++++++++++++++++++++-------------- 3 files changed, 78 insertions(+), 19 deletions(-) (limited to 'threads.js') diff --git a/blocks.js b/blocks.js index 5f67107..2e297ab 100644 --- a/blocks.js +++ b/blocks.js @@ -6571,7 +6571,6 @@ InputSlotMorph.prototype.messagesReceivedMenu = function () { InputSlotMorph.prototype.collidablesMenu = function () { var dict = { 'mouse-pointer' : ['mouse-pointer'], - 'camera motion' : ['camera motion'], edge : ['edge'], 'pen trails' : ['pen trails'] }, diff --git a/objects.js b/objects.js index 37d66b2..9eba6a8 100644 --- a/objects.js +++ b/objects.js @@ -785,6 +785,18 @@ SpriteMorph.prototype.initBlocks = function () { category: 'sensing', spec: 'color %clr is touching %clr ?' }, + reportCameraMotion: { + only: SpriteMorph, + type: 'predicate', + category: 'sensing', + spec: 'camera motion at my position?' + }, + reportCameraDirection: { + only: SpriteMorph, + type: 'reporter', + category: 'sensing', + spec: 'camera motion direction' + }, colorFiltered: { dev: true, type: 'reporter', @@ -1868,6 +1880,9 @@ SpriteMorph.prototype.blockTemplates = function (category) { blocks.push(block('reportTouchingColor')); blocks.push(block('reportColorIsTouchingColor')); blocks.push('-'); + blocks.push(block('reportCameraMotion')); + blocks.push(block('reportCameraDirection')); + blocks.push('-'); blocks.push(block('doAsk')); blocks.push(watcherToggle('getLastAnswer')); blocks.push(block('getLastAnswer')); @@ -4269,6 +4284,7 @@ StageMorph.prototype.init = function (globals) { this.lastAnswer = ''; // last user input, do not persist this.activeSounds = []; // do not persist this.lastCameraCanvas = null; + this.lastCameraMotion = new Point(0, 0); this.trailsCanvas = null; this.isThreadSafe = false; diff --git a/threads.js b/threads.js index 4c70bd5..03625d9 100644 --- a/threads.js +++ b/threads.js @@ -2355,24 +2355,6 @@ Process.prototype.objectTouchingObject = function (thisObj, name) { } else { stage = thisObj.parentThatIsA(StageMorph); if (stage) { - if (this.inputOption(name) === 'camera motion') { - var motionCanvas = this.getCameraMotion(); - - var x = thisObj.xPosition() + 210, y = 170 - thisObj.yPosition(); - // ouch! hardcoded ^ ^ - var motionData = motionCanvas.getContext('2d').getImageData( - x, y, thisObj.width(), thisObj.height()); - var i = 0, average = 0; - while (i < (motionData.data.length * 0.25)) { - average += (motionData.data[i*4] + motionData.data[i*4+1] - + motionData.data[i*4+2]) / 3; - ++i; - } - average = Math.round(average / (motionData.data.length * 0.25)); - if (average > 10) { - return true; - } - } if (this.inputOption(name) === 'edge' && !stage.bounds.containsRectangle(thisObj.bounds)) { return true; @@ -2442,6 +2424,62 @@ Process.prototype.reportColorIsTouchingColor = function (color1, color2) { return false; }; +Process.prototype.reportCameraMotion = function () { + var thisObj = this.blockReceiver(); + var motionCanvas = this.getCameraMotion(); + + var x = thisObj.xPosition() + 210, y = 170 - thisObj.yPosition(); + // ouch! hardcoded ^ ^ + var motionData = motionCanvas.getContext('2d').getImageData( + x, y, thisObj.width(), thisObj.height()); + var i = 0, average = 0; + while (i < (motionData.data.length * 0.25)) { + average += (motionData.data[i*4] + + motionData.data[i*4+1] + motionData.data[i*4+2]) / 3; + ++i; + } + average = Math.round(average / (motionData.data.length * 0.25)); + if (average > 10) { + return true; + } else { + return false; + } +}; + +Process.prototype.reportCameraDirection = function () { + var stage = this.homeContext.receiver.parentThatIsA(StageMorph); + var motionCanvas = this.getCameraMotion(); + var canv = document.createElement('canvas'), + ctx = canv.getContext('2d'); + var data = motionCanvas.getContext('2d') + .getImageData(0, 0, motionCanvas.width, motionCanvas.height); + // scale, saves some time + canv.width = motionCanvas.width / 10; + canv.height = motionCanvas.height / 10; + ctx.drawImage(motionCanvas, 0, 0, canv.width, canv.height); + var yval = 0, xval = 0, cnt = 0; + var motion, imageData = ctx.getImageData(0, 0, canv.width, canv.height); + // find the geometric center of the moving object + for (var j = 0; j < canv.height; j++) { + for (var k = 0; k < canv.width; k++) { + motion = imageData.data[(j*canv.width+k)*4]; + yval += j * motion; + xval += k * motion; + cnt += motion; + } + } + // calculate the angle between this center and the last one + var resultX = Math.round(xval / cnt / 1) * 1; + var resultY = Math.round(yval / cnt / 1) * 1; + var diff = (resultX + resultY) - + (stage.lastCameraMotion.x - stage.lastCameraMotion.y); + var deg = 0; + deg = degrees(Math.atan2(resultX - stage.lastCameraMotion.x, + stage.lastCameraMotion.y - resultY)); + stage.lastCameraMotion = new Point(resultX, resultY); + return deg; +}; + Process.prototype.reportDistanceTo = function (name) { var thisObj = this.blockReceiver(), thatObj, @@ -2753,6 +2791,12 @@ Process.prototype.doPlayNoteForSecs = function (pitch, secs) { // Process camera streaming primitives Process.prototype.doStreamCamera = function () { + if ((Date.now() - this.context.startTime) < 3000) { + // 20 FPS is enough + this.pushContext('doYield'); + this.pushContext(); + return; + } var myself = this; var video = this.context.activeStream || null; -- cgit v1.3.1 From 35974d8b61d0658ddb5af8907c4bb0512fc3feb7 Mon Sep 17 00:00:00 2001 From: Gubolin Date: Sun, 17 Aug 2014 17:50:58 +0200 Subject: tidy up the camera block code --- threads.js | 108 +++++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 63 insertions(+), 45 deletions(-) (limited to 'threads.js') diff --git a/threads.js b/threads.js index 03625d9..8e2be3f 100644 --- a/threads.js +++ b/threads.js @@ -2426,20 +2426,9 @@ Process.prototype.reportColorIsTouchingColor = function (color1, color2) { Process.prototype.reportCameraMotion = function () { var thisObj = this.blockReceiver(); - var motionCanvas = this.getCameraMotion(); - - var x = thisObj.xPosition() + 210, y = 170 - thisObj.yPosition(); - // ouch! hardcoded ^ ^ - var motionData = motionCanvas.getContext('2d').getImageData( - x, y, thisObj.width(), thisObj.height()); - var i = 0, average = 0; - while (i < (motionData.data.length * 0.25)) { - average += (motionData.data[i*4] + - motionData.data[i*4+1] + motionData.data[i*4+2]) / 3; - ++i; - } - average = Math.round(average / (motionData.data.length * 0.25)); - if (average > 10) { + var motionCanvas = this.getCameraMotionCanvas(); + var motion = this.getCameraMotion(motionCanvas, thisObj); + if (motion > 10) { return true; } else { return false; @@ -2447,37 +2436,14 @@ Process.prototype.reportCameraMotion = function () { }; Process.prototype.reportCameraDirection = function () { - var stage = this.homeContext.receiver.parentThatIsA(StageMorph); - var motionCanvas = this.getCameraMotion(); - var canv = document.createElement('canvas'), - ctx = canv.getContext('2d'); - var data = motionCanvas.getContext('2d') - .getImageData(0, 0, motionCanvas.width, motionCanvas.height); - // scale, saves some time - canv.width = motionCanvas.width / 10; - canv.height = motionCanvas.height / 10; - ctx.drawImage(motionCanvas, 0, 0, canv.width, canv.height); - var yval = 0, xval = 0, cnt = 0; - var motion, imageData = ctx.getImageData(0, 0, canv.width, canv.height); - // find the geometric center of the moving object - for (var j = 0; j < canv.height; j++) { - for (var k = 0; k < canv.width; k++) { - motion = imageData.data[(j*canv.width+k)*4]; - yval += j * motion; - xval += k * motion; - cnt += motion; - } + var thisObj = this.blockReceiver(); + var motionCanvas = this.getCameraMotionCanvas(); + var motion = this.getCameraMotion(motionCanvas, thisObj); + if (motion > 10) { + return this.getCameraDirection(motionCanvas); + } else { + return 0; } - // calculate the angle between this center and the last one - var resultX = Math.round(xval / cnt / 1) * 1; - var resultY = Math.round(yval / cnt / 1) * 1; - var diff = (resultX + resultY) - - (stage.lastCameraMotion.x - stage.lastCameraMotion.y); - var deg = 0; - deg = degrees(Math.atan2(resultX - stage.lastCameraMotion.x, - stage.lastCameraMotion.y - resultY)); - stage.lastCameraMotion = new Point(resultX, resultY); - return deg; }; Process.prototype.reportDistanceTo = function (name) { @@ -2855,6 +2821,10 @@ Process.prototype.doStreamCamera = function () { } context.drawImage(video, 0, 0, video.width, video.height); stage.changed(); + + var motionCanvas = this.getCameraMotionCanvas(); + this.getCameraDirection(motionCanvas); + // dry-run to update lastCameraMotion } catch (e) { if (e.name !== 'NS_ERROR_NOT_AVAILABLE') { // https://bugzilla.mozilla.org/show_bug.cgi?id=879717 @@ -2878,7 +2848,7 @@ Process.prototype.doStopCamera = function () { } }; -Process.prototype.getCameraMotion = function () { +Process.prototype.getCameraMotionCanvas = function () { // see https://www.adobe.com/devnet/html5/articles/javascript-motion-detection.html fastAbs = function (value) // faster, but less acurate { return (value ^ (value >> 31)) - (value >> 31); }; @@ -2923,6 +2893,54 @@ Process.prototype.getCameraMotion = function () { return blendedCanvas; }; +Process.prototype.getCameraMotion = function (motionCanvas, thisObj) { + var x = thisObj.xPosition() + 210, y = 170 - thisObj.yPosition(); + // ouch! hardcoded ^ ^ + var motionData = motionCanvas.getContext('2d').getImageData( + x, y, thisObj.width(), thisObj.height()); + var i = 0, average = 0; + while (i < (motionData.data.length * 0.25)) { + average += (motionData.data[i*4] + + motionData.data[i*4+1] + motionData.data[i*4+2]) / 3; + ++i; + } + average = Math.round(average / (motionData.data.length * 0.25)); + return average; +}; + +Process.prototype.getCameraDirection = function (motionCanvas) { + var stage = this.homeContext.receiver.parentThatIsA(StageMorph); + var canv = document.createElement('canvas'), + ctx = canv.getContext('2d'); + var data = motionCanvas.getContext('2d') + .getImageData(0, 0, motionCanvas.width, motionCanvas.height); + // scale, saves some time + canv.width = motionCanvas.width / 10; + canv.height = motionCanvas.height / 10; + ctx.drawImage(motionCanvas, 0, 0, canv.width, canv.height); + var yval = 0, xval = 0, cnt = 0; + var motion, imageData = ctx.getImageData(0, 0, canv.width, canv.height); + // find the geometric center of the moving object + for (var j = 0; j < canv.height; j++) { + for (var k = 0; k < canv.width; k++) { + motion = imageData.data[(j*canv.width+k)*4]; + yval += j * motion; + xval += k * motion; + cnt += motion; + } + } + // calculate the angle between this center and the last one + var resultX = Math.round(xval / cnt); + var resultY = Math.round(yval / cnt); + var diff = (resultX + resultY) - + (stage.lastCameraMotion.x - stage.lastCameraMotion.y); + var deg = 0; + deg = degrees(Math.atan2(resultX - stage.lastCameraMotion.x, + stage.lastCameraMotion.y - resultY)); + stage.lastCameraMotion = new Point(resultX, resultY); + return deg; +}; + // Process constant input options Process.prototype.inputOption = function (dta) { -- cgit v1.3.1 From 849e666a236c5037265b1c620bc536ec889dafae Mon Sep 17 00:00:00 2001 From: Gubolin Date: Sun, 17 Aug 2014 18:07:12 +0200 Subject: camera block bugfixes --- threads.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'threads.js') diff --git a/threads.js b/threads.js index 8e2be3f..39537c0 100644 --- a/threads.js +++ b/threads.js @@ -2821,10 +2821,6 @@ Process.prototype.doStreamCamera = function () { } context.drawImage(video, 0, 0, video.width, video.height); stage.changed(); - - var motionCanvas = this.getCameraMotionCanvas(); - this.getCameraDirection(motionCanvas); - // dry-run to update lastCameraMotion } catch (e) { if (e.name !== 'NS_ERROR_NOT_AVAILABLE') { // https://bugzilla.mozilla.org/show_bug.cgi?id=879717 @@ -2841,8 +2837,10 @@ Process.prototype.doStopCamera = function () { var stage = this.homeContext.receiver.parentThatIsA(StageMorph); if (stage) { stage.threads.processes.forEach(function (thread) { - if (thread.context.activeStream) { - thread.popContext(); + if (thread.context) { + if (thread.context.activeStream) { + thread.popContext(); + } } }); } -- cgit v1.3.1 From 672dba7c414e027c899bb51892367cfc7e5976e4 Mon Sep 17 00:00:00 2001 From: Gubolin Date: Sun, 17 Aug 2014 18:15:31 +0200 Subject: add IE camera block support --- threads.js | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) (limited to 'threads.js') diff --git a/threads.js b/threads.js index 39537c0..44b01f1 100644 --- a/threads.js +++ b/threads.js @@ -2780,21 +2780,17 @@ Process.prototype.doStreamCamera = function () { var videoObject = {'video': true, 'audio': false}; - if (navigator.getUserMedia) { - navigator.getUserMedia(videoObject, function (stream) { - video.src = stream; + navigator.getUserMedia_ = (navigator.getUserMedia || + navigator.webkitGetUserMedia || + navigator.mozGetUserMedia || + navigator.msGetUserMedia); + + if (!! navigator.getUserMedia_) { + navigator.getUserMedia_(videoObject, function (stream) { + window.URL_ = window.URL || window.webkitURL; + video.src = window.URL_.createObjectURL(stream); video.play(); }, this.handleError); // TODO: improve error handling - } else if (navigator.webkitGetUserMedia) { - navigator.webkitGetUserMedia(videoObject, function (stream) { - video.src = window.webkitURL.createObjectURL(stream); - video.play(); - }, this.handleError); - } else if (navigator.mozGetUserMedia) { - navigator.mozGetUserMedia(videoObject, function (stream) { - video.src = window.URL.createObjectURL(stream); - video.play(); - }, this.handleError); } stage.lastCameraCanvas = newCanvas(stage.dimensions); } else { -- cgit v1.3.1 From b17afbc1aa1e25309c58f493511a0615e020af7f Mon Sep 17 00:00:00 2001 From: Gubolin Date: Sun, 17 Aug 2014 18:29:13 +0200 Subject: add camera streaming predicate --- threads.js | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) (limited to 'threads.js') diff --git a/threads.js b/threads.js index 44b01f1..2d03fc7 100644 --- a/threads.js +++ b/threads.js @@ -2424,26 +2424,33 @@ Process.prototype.reportColorIsTouchingColor = function (color1, color2) { return false; }; +Process.prototype.reportStreamingCamera = function () { + var stage = this.homeContext.receiver.parentThatIsA(StageMorph); + return stage.streamingCamera; +}; + Process.prototype.reportCameraMotion = function () { - var thisObj = this.blockReceiver(); - var motionCanvas = this.getCameraMotionCanvas(); - var motion = this.getCameraMotion(motionCanvas, thisObj); - if (motion > 10) { - return true; - } else { - return false; + if (this.reportStreamingCamera()) { + var thisObj = this.blockReceiver(); + var motionCanvas = this.getCameraMotionCanvas(); + var motion = this.getCameraMotion(motionCanvas, thisObj); + if (motion > 10) { + return true; + } } + return false; }; Process.prototype.reportCameraDirection = function () { - var thisObj = this.blockReceiver(); - var motionCanvas = this.getCameraMotionCanvas(); - var motion = this.getCameraMotion(motionCanvas, thisObj); - if (motion > 10) { - return this.getCameraDirection(motionCanvas); - } else { - return 0; + if (this.reportStreamingCamera()) { + var thisObj = this.blockReceiver(); + var motionCanvas = this.getCameraMotionCanvas(); + var motion = this.getCameraMotion(motionCanvas, thisObj); + if (motion > 10) { + return this.getCameraDirection(motionCanvas); + } } + return 0; }; Process.prototype.reportDistanceTo = function (name) { @@ -2771,6 +2778,8 @@ Process.prototype.doStreamCamera = function () { stage.trailsCanvas = newCanvas(stage.dimensions); } + stage.streamingCamera = false; + if (video === null) { video = document.createElement('video'); video.width = stage.dimensions.x; @@ -2817,6 +2826,7 @@ Process.prototype.doStreamCamera = function () { } context.drawImage(video, 0, 0, video.width, video.height); stage.changed(); + stage.streamingCamera = true; } catch (e) { if (e.name !== 'NS_ERROR_NOT_AVAILABLE') { // https://bugzilla.mozilla.org/show_bug.cgi?id=879717 @@ -2832,6 +2842,7 @@ Process.prototype.doStreamCamera = function () { Process.prototype.doStopCamera = function () { var stage = this.homeContext.receiver.parentThatIsA(StageMorph); if (stage) { + stage.streamingCamera = false; stage.threads.processes.forEach(function (thread) { if (thread.context) { if (thread.context.activeStream) { -- cgit v1.3.1 From d3be78cbedce2d9990c1efe6abf304dde69ba19a Mon Sep 17 00:00:00 2001 From: Gubolin Date: Sun, 17 Aug 2014 18:44:47 +0200 Subject: improve camera block error handling --- threads.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'threads.js') diff --git a/threads.js b/threads.js index 2d03fc7..eda8fc7 100644 --- a/threads.js +++ b/threads.js @@ -2778,6 +2778,11 @@ Process.prototype.doStreamCamera = function () { stage.trailsCanvas = newCanvas(stage.dimensions); } + error = function (msg) { + var err = { name: 'Camera', message: msg }; + myself.handleError(err); + }; + stage.streamingCamera = false; if (video === null) { @@ -2799,7 +2804,9 @@ Process.prototype.doStreamCamera = function () { window.URL_ = window.URL || window.webkitURL; video.src = window.URL_.createObjectURL(stream); video.play(); - }, this.handleError); // TODO: improve error handling + }, error); + } else { + error('getUserMedia not supported'); } stage.lastCameraCanvas = newCanvas(stage.dimensions); } else { -- cgit v1.3.1