From 7bba6d9858c63a06570c6013d16a9f4c5ea3ab63 Mon Sep 17 00:00:00 2001 From: couz74 Date: Wed, 10 Jun 2020 10:02:56 +0200 Subject: [PATCH 1/9] feature: Add preview from gphoto Change-Id: Idd63d19ca60913bf5dc89f3d7ed17eacfa9545e8 --- api/takeVideo.php | 35 +++++++++++++ src/js/core.js | 131 +++++++++++++++++++++++++++++----------------- 2 files changed, 118 insertions(+), 48 deletions(-) create mode 100644 api/takeVideo.php diff --git a/api/takeVideo.php b/api/takeVideo.php new file mode 100644 index 000000000..8b66e3ba6 --- /dev/null +++ b/api/takeVideo.php @@ -0,0 +1,35 @@ + 2) { + return true; + } + } catch(Exception $e) { + + } + + return false; +} + +if ($_POST['play'] === "true" ) { + $pid = exec('gphoto2 --stdout --capture-movie | ffmpeg -i - -vcodec rawvideo -pix_fmt yuv420p -threads 0 -f v4l2 /dev/video0 > /dev/null 2>&1 & echo $!', $out); + sleep(3); + die(json_encode([ + 'isRunning' => isRunning($pid), + 'pid' => $pid - 1 + ])); +} elseif($_POST['play'] === "false") { + exec('kill -15 '.$_POST['pid']); + die(json_encode([ + 'isRunning' => isRunning($_POST['pid']), + 'pid' => $_POST['pid'] + ])); +} diff --git a/src/js/core.js b/src/js/core.js index 55760595f..e1c28ac0a 100644 --- a/src/js/core.js +++ b/src/js/core.js @@ -26,9 +26,9 @@ const photoBooth = (function () { takingPic = false, nextCollageNumber = 0, currentCollageFile = '', - imgFilter = config.default_imagefilter; - - let ioClient; + imgFilter = config.default_imagefilter, + ioClient, + pid; const modal = { open: function (selector) { @@ -154,42 +154,55 @@ const photoBooth = (function () { api.stopVideo('preview'); } - if (!navigator.mediaDevices) { - return; - } - - const getMedia = - navigator.mediaDevices.getUserMedia || - navigator.mediaDevices.webkitGetUserMedia || - navigator.mediaDevices.mozGetUserMedia || - false; + const dataVideo = { + play: 'true' + }; - if (!getMedia) { + if (!navigator.mediaDevices) { return; } - if (config.previewCamFlipHorizontal) { - $('#video--view').addClass('flip-horizontal'); - $('#video--preview').addClass('flip-horizontal'); - } + jQuery + .post('api/takeVideo.php', dataVideo) + .done(function (result) { + console.log('Start webcam', result); + pid = result.pid; + const getMedia = + navigator.mediaDevices.getUserMedia || + navigator.mediaDevices.webkitGetUserMedia || + navigator.mediaDevices.mozGetUserMedia || + false; + + if (!getMedia) { + return; + } - getMedia - .call(navigator.mediaDevices, webcamConstraints) - .then(function (stream) { - if (mode === 'preview') { - $('#video--preview').show(); - videoPreview.srcObject = stream; - api.stream = stream; - wrapper.css('background-image', 'none'); - wrapper.css('background-color', 'transparent'); - } else { - $('#video--view').show(); - videoView.srcObject = stream; + if (config.previewCamFlipHorizontal) { + $('#video--view').addClass('flip-horizontal'); + $('#video--preview').addClass('flip-horizontal'); } - api.stream = stream; + + getMedia + .call(navigator.mediaDevices, webcamConstraints) + .then(function (stream) { + if (mode === 'preview') { + $('#video--preview').show(); + videoPreview.srcObject = stream; + api.stream = stream; + wrapper.css('background-image', 'none'); + wrapper.css('background-color', 'transparent'); + } else { + $('#video--view').show(); + videoView.srcObject = stream; + } + api.stream = stream; + }) + .catch(function (error) { + console.log('Could not get user media: ', error); + }); }) - .catch(function (error) { - console.log('Could not get user media: ', error); + .fail(function (xhr, status, result) { + console.log('Could not start webcam', result); }); }; @@ -205,6 +218,28 @@ const photoBooth = (function () { } }; + api.stopVideoAndTakePic = function (data) { + if (api.stream) { + const dataVideo = { + play: 'false', + pid: pid + }; + + jQuery + .post('api/takeVideo.php', dataVideo) + .done(function (result) { + console.log('Stop webcam', result); + const track = api.stream.getTracks()[0]; + track.stop(); + $('#video--view').hide(); + api.callTakePicApi(data); + }) + .fail(function (xhr, status, result) { + console.log('Could not stop webcam', result); + }); + } + }; + api.thrill = function (photoStyle) { api.closeNav(); api.reset(); @@ -261,13 +296,7 @@ const photoBooth = (function () { .appendTo('.cheese'); } - if (config.preview_mode === 'device_cam' && config.previewCamTakesPic && !api.stream && !config.dev) { - console.log('No preview by device cam available!'); - - api.errorPic({ - error: 'No preview by device cam available!' - }); - } else if (config.no_cheese) { + if (config.no_cheese) { api.takePic(photoStyle); } else { setTimeout(() => { @@ -286,14 +315,7 @@ const photoBooth = (function () { ioClient.emit('photobooth-socket', 'in progress'); } - if (config.preview_mode === 'device_cam') { - if (config.previewCamTakesPic && !config.dev) { - videoSensor.width = videoView.videoWidth; - videoSensor.height = videoView.videoHeight; - videoSensor.getContext('2d').drawImage(videoView, 0, 0); - } - api.stopVideo('view'); - } else if (config.preview_mode === 'url') { + if (config.preview_mode === 'url') { $('#ipcam--view').removeClass('streaming'); $('#ipcam--view').hide(); } @@ -312,6 +334,19 @@ const photoBooth = (function () { loader.css('background', config.colors.panel); loader.css('background-color', config.colors.panel); + if (config.preview_mode === 'device_cam') { + if (config.previewCamTakesPic && !config.dev) { + videoSensor.width = videoView.videoWidth; + videoSensor.height = videoView.videoHeight; + videoSensor.getContext('2d').drawImage(videoView, 0, 0); + } + api.stopVideoAndTakePic(data); + } else { + api.callTakePicApi(data); + } + }; + + api.callTakePicApi = function (data) { jQuery .post('api/takePic.php', data) .done(function (result) { @@ -360,7 +395,7 @@ const photoBooth = (function () { currentCollageFile = ''; nextCollageNumber = 0; - api.processPic(photoStyle, result); + api.processPic(data.style, result); } }) .fail(function (xhr, status, result) { From 39d0059b9671bb0dc47e6004a87a9ca64adee87c Mon Sep 17 00:00:00 2001 From: Andreas Blaesius Date: Sat, 14 Nov 2020 10:37:54 +0100 Subject: [PATCH 2/9] restore compatibility with preview from device cam Change-Id: Id2d48621529cea2733c64102658c1d47ef5a7cda --- api/admin.php | 2 +- config/config.inc.php | 2 +- lib/configsetup.inc.php | 3 +- src/js/core.js | 130 ++++++++++++++++++++++++++-------------- 4 files changed, 88 insertions(+), 49 deletions(-) diff --git a/api/admin.php b/api/admin.php index 6eccbb72e..bc53d680f 100644 --- a/api/admin.php +++ b/api/admin.php @@ -93,7 +93,7 @@ $newConfig['login_password'] = NULL; } - if ($newConfig['preview_mode'] != 'device_cam') { + if ($newConfig['preview_mode'] != 'device_cam' && $newConfig['preview_mode'] != 'gphoto') { $newConfig['previewCamTakesPic'] = false; } diff --git a/config/config.inc.php b/config/config.inc.php index e8b3e5765..cfa7856fd 100644 --- a/config/config.inc.php +++ b/config/config.inc.php @@ -79,7 +79,7 @@ // P R E V I E W // Please read https://github.com/andi34/photobooth/wiki/FAQ#how-to-use-a-live-stream-as-background-at-countdown -// possible preview_mode values: none, device_cam, url +// possible preview_mode values: none, device_cam, url, gphoto $config['preview_mode'] = 'none'; $config['previewCamTakesPic'] = false; $config['previewCamFlipHorizontal'] = true; diff --git a/lib/configsetup.inc.php b/lib/configsetup.inc.php index 449a4f46a..032f607eb 100644 --- a/lib/configsetup.inc.php +++ b/lib/configsetup.inc.php @@ -367,7 +367,8 @@ 'options' => [ 'none' => 'None', 'device_cam' => 'from device cam', - 'url' => 'from URL' + 'url' => 'from URL', + 'gphoto' => 'from gphoto2' ], 'value' => $config['preview_mode'] ], diff --git a/src/js/core.js b/src/js/core.js index e1c28ac0a..8d481527e 100644 --- a/src/js/core.js +++ b/src/js/core.js @@ -162,48 +162,76 @@ const photoBooth = (function () { return; } - jQuery - .post('api/takeVideo.php', dataVideo) - .done(function (result) { - console.log('Start webcam', result); - pid = result.pid; - const getMedia = - navigator.mediaDevices.getUserMedia || - navigator.mediaDevices.webkitGetUserMedia || - navigator.mediaDevices.mozGetUserMedia || - false; - - if (!getMedia) { - return; - } + if (config.preview_mode === 'gphoto') { + jQuery + .post('api/takeVideo.php', dataVideo) + .done(function (result) { + console.log('Start webcam', result); + pid = result.pid; + const getMedia = + navigator.mediaDevices.getUserMedia || + navigator.mediaDevices.webkitGetUserMedia || + navigator.mediaDevices.mozGetUserMedia || + false; + + if (!getMedia) { + return; + } - if (config.previewCamFlipHorizontal) { - $('#video--view').addClass('flip-horizontal'); - $('#video--preview').addClass('flip-horizontal'); - } + if (config.previewCamFlipHorizontal) { + $('#video--view').addClass('flip-horizontal'); + $('#video--preview').addClass('flip-horizontal'); + } - getMedia - .call(navigator.mediaDevices, webcamConstraints) - .then(function (stream) { - if (mode === 'preview') { - $('#video--preview').show(); - videoPreview.srcObject = stream; - api.stream = stream; - wrapper.css('background-image', 'none'); - wrapper.css('background-color', 'transparent'); - } else { + getMedia + .call(navigator.mediaDevices, webcamConstraints) + .then(function (stream) { $('#video--view').show(); videoView.srcObject = stream; - } + api.stream = stream; + }) + .catch(function (error) { + console.log('Could not get user media: ', error); + }); + }) + .fail(function (xhr, status, result) { + console.log('Could not start webcam', result); + }); + } else { + const getMedia = + navigator.mediaDevices.getUserMedia || + navigator.mediaDevices.webkitGetUserMedia || + navigator.mediaDevices.mozGetUserMedia || + false; + + if (!getMedia) { + return; + } + + if (config.previewCamFlipHorizontal) { + $('#video--view').addClass('flip-horizontal'); + $('#video--preview').addClass('flip-horizontal'); + } + + getMedia + .call(navigator.mediaDevices, webcamConstraints) + .then(function (stream) { + if (mode === 'preview') { + $('#video--preview').show(); + videoPreview.srcObject = stream; api.stream = stream; - }) - .catch(function (error) { - console.log('Could not get user media: ', error); - }); - }) - .fail(function (xhr, status, result) { - console.log('Could not start webcam', result); - }); + wrapper.css('background-image', 'none'); + wrapper.css('background-color', 'transparent'); + } else { + $('#video--view').show(); + videoView.srcObject = stream; + } + api.stream = stream; + }) + .catch(function (error) { + console.log('Could not get user media: ', error); + }); + } }; api.stopVideo = function (mode) { @@ -261,7 +289,7 @@ const photoBooth = (function () { photoStyle = 'collage'; } - if (config.preview_mode === 'device_cam') { + if (config.preview_mode === 'device_cam' || config.preview_mode === 'gphoto') { api.startVideo('view'); } else if (config.preview_mode === 'url') { $('#ipcam--view').show(); @@ -296,7 +324,13 @@ const photoBooth = (function () { .appendTo('.cheese'); } - if (config.no_cheese) { + if (config.preview_mode === 'device_cam' && config.previewCamTakesPic && !api.stream && !config.dev) { + console.log('No preview by device cam available!'); + + api.errorPic({ + error: 'No preview by device cam available!' + }); + } else if (config.no_cheese) { api.takePic(photoStyle); } else { setTimeout(() => { @@ -315,7 +349,16 @@ const photoBooth = (function () { ioClient.emit('photobooth-socket', 'in progress'); } - if (config.preview_mode === 'url') { + if (config.preview_mode === 'device_cam' || config.preview_mode === 'gphoto') { + if (config.previewCamTakesPic && !config.dev) { + videoSensor.width = videoView.videoWidth; + videoSensor.height = videoView.videoHeight; + videoSensor.getContext('2d').drawImage(videoView, 0, 0); + } + if (config.preview_mode === 'device_cam') { + api.stopVideo('view'); + } + } else if (config.preview_mode === 'url') { $('#ipcam--view').removeClass('streaming'); $('#ipcam--view').hide(); } @@ -334,12 +377,7 @@ const photoBooth = (function () { loader.css('background', config.colors.panel); loader.css('background-color', config.colors.panel); - if (config.preview_mode === 'device_cam') { - if (config.previewCamTakesPic && !config.dev) { - videoSensor.width = videoView.videoWidth; - videoSensor.height = videoView.videoHeight; - videoSensor.getContext('2d').drawImage(videoView, 0, 0); - } + if (config.preview_mode === 'gphoto') { api.stopVideoAndTakePic(data); } else { api.callTakePicApi(data); From 05947d93d286fb243fa274cf7a78abf9e792fcfe Mon Sep 17 00:00:00 2001 From: Andreas Blaesius Date: Sat, 14 Nov 2020 13:53:18 +0100 Subject: [PATCH 3/9] Only kill gphoto preview if a stream is running --- src/js/core.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/core.js b/src/js/core.js index 8d481527e..162838d3d 100644 --- a/src/js/core.js +++ b/src/js/core.js @@ -377,7 +377,7 @@ const photoBooth = (function () { loader.css('background', config.colors.panel); loader.css('background-color', config.colors.panel); - if (config.preview_mode === 'gphoto') { + if (config.preview_mode === 'gphoto' && api.stream) { api.stopVideoAndTakePic(data); } else { api.callTakePicApi(data); From 7549a9d7a7ca3d81ea9cff79e7d25c61bef0afc1 Mon Sep 17 00:00:00 2001 From: Andreas Blaesius Date: Sun, 15 Nov 2020 12:06:15 +0100 Subject: [PATCH 4/9] Move preview commands to adminpanel, use "killall" Change-Id: Ie2869b7e1ad3f442ad8c4a37c11174988c31f93e --- api/takeVideo.php | 6 ++++-- config/config.inc.php | 2 ++ lib/config.php | 10 ++++++++++ lib/configsetup.inc.php | 12 ++++++++++++ resources/lang/en.json | 4 ++++ 5 files changed, 32 insertions(+), 2 deletions(-) diff --git a/api/takeVideo.php b/api/takeVideo.php index 8b66e3ba6..c7c72eeeb 100644 --- a/api/takeVideo.php +++ b/api/takeVideo.php @@ -20,14 +20,16 @@ function isRunning($pid) { } if ($_POST['play'] === "true" ) { - $pid = exec('gphoto2 --stdout --capture-movie | ffmpeg -i - -vcodec rawvideo -pix_fmt yuv420p -threads 0 -f v4l2 /dev/video0 > /dev/null 2>&1 & echo $!', $out); + $cmd = sprintf($config['preview']['cmd']); + $pid = exec($cmd, $out); sleep(3); die(json_encode([ 'isRunning' => isRunning($pid), 'pid' => $pid - 1 ])); } elseif($_POST['play'] === "false") { - exec('kill -15 '.$_POST['pid']); + $killcmd = sprintf($config['preview']['killcmd']); + exec($killcmd); die(json_encode([ 'isRunning' => isRunning($_POST['pid']), 'pid' => $_POST['pid'] diff --git a/config/config.inc.php b/config/config.inc.php index cfa7856fd..81dfb9a3f 100644 --- a/config/config.inc.php +++ b/config/config.inc.php @@ -229,6 +229,8 @@ $config['print']['msg'] = null; $config['exiftool']['cmd'] = null; $config['exiftool']['msg'] = null; +$config['preview']['cmd'] = null; +$config['preview']['killcmd'] = null; // R E M O T E B U Z Z E R diff --git a/lib/config.php b/lib/config.php index d164de2cf..b4165166d 100644 --- a/lib/config.php +++ b/lib/config.php @@ -18,6 +18,10 @@ 'exiftool' => [ 'cmd' => '', 'msg' => '', + ], + 'preview' => [ + 'cmd' => '', + 'killcmd' => '', ] ], 'linux' => [ @@ -32,6 +36,10 @@ 'exiftool' => [ 'cmd' => 'exiftool -overwrite_original -TagsFromFile %s %s', 'msg' => '', + ], + 'preview' => [ + 'cmd' => 'gphoto2 --stdout --capture-movie | ffmpeg -i - -vcodec rawvideo -pix_fmt yuv420p -threads 0 -f v4l2 /dev/video0 > /dev/null 2>&1 & echo $!', + 'killcmd' => 'killall gphoto2', ] ], ]; @@ -65,6 +73,8 @@ $config['print']['msg'] = $cmds[$os]['print']['msg']; $config['exiftool']['cmd'] = $cmds[$os]['exiftool']['cmd']; $config['exiftool']['msg'] = $cmds[$os]['exiftool']['msg']; +$config['preview']['cmd'] = $cmds[$os]['preview']['cmd']; +$config['preview']['killcmd'] = $cmds[$os]['preview']['killcmd']; $config['collage_limit'] = 4; diff --git a/lib/configsetup.inc.php b/lib/configsetup.inc.php index 032f607eb..bb460ba46 100644 --- a/lib/configsetup.inc.php +++ b/lib/configsetup.inc.php @@ -1064,6 +1064,18 @@ 'placeholder' => 'exiftool_msg', 'name' => 'exiftool[msg]', 'value' => htmlentities($config['exiftool']['msg']) + ], + 'preview_cmd' => [ + 'type' => 'input', + 'placeholder' => 'preview_cmd', + 'name' => 'preview[cmd]', + 'value' => htmlentities($config['preview']['cmd']) + ], + 'preview_killcmd' => [ + 'type' => 'input', + 'placeholder' => 'preview_killcmd', + 'name' => 'preview[killcmd]', + 'value' => htmlentities($config['preview']['killcmd']) ] ], 'remotebuzzer' => [ diff --git a/resources/lang/en.json b/resources/lang/en.json index 581a3acec..4a1169fd2 100644 --- a/resources/lang/en.json +++ b/resources/lang/en.json @@ -17,6 +17,8 @@ "commands": "Commands", "commands_exiftool_cmd": "EXIFtool command", "commands_exiftool_msg": "Success message for EXIF preservation", + "commands_preview_cmd": "Command to generate a live preview", + "commands_preview_killcmd": "Command to kill live preview", "commands_print_cmd": "Print command", "commands_print_msg": "Success message for print", "commands_take_picture_cmd": "Take picture command", @@ -121,6 +123,8 @@ "manual_chroma_keying": "If enabled, chromakeying can be accessed from gallery for your pictures.", "manual_commands_exiftool_cmd": "EXIFtool command line which is executed after taking a picture if \"Preserve EXIF data\" is enabled.", "manual_commands_exiftool_msg": "Message returned from EXIFtool commandline.", + "manual_commands_preview_cmd": "Command line which is executed to generate a live preview.", + "manual_commands_preview_killcmd": "Command line which is executed to kill the live preview.", "manual_commands_print_cmd": "Command line which is executed while pressing the \"Print\" button.", "manual_commands_print_msg": "Message returned from print command.", "manual_commands_take_picture_cmd": "Command line which is executed while pressing the \"Take Pic\" button. On Linux you can for example use gphoto2 to take pictures, on Windows you can use digiCamControl.", From ab69dd606d904764c524f07620b09029d56674ed Mon Sep 17 00:00:00 2001 From: Andreas Blaesius Date: Sun, 15 Nov 2020 12:11:40 +0100 Subject: [PATCH 5/9] gphoto preview: sleep 1 second after killing gphoto - a small delay is needed to use gphoto to take a picture Change-Id: I049e6cac42d4f30dcd9110828cce7af0bc74e7af --- lib/config.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/config.php b/lib/config.php index b4165166d..76d3711c0 100644 --- a/lib/config.php +++ b/lib/config.php @@ -39,7 +39,7 @@ ], 'preview' => [ 'cmd' => 'gphoto2 --stdout --capture-movie | ffmpeg -i - -vcodec rawvideo -pix_fmt yuv420p -threads 0 -f v4l2 /dev/video0 > /dev/null 2>&1 & echo $!', - 'killcmd' => 'killall gphoto2', + 'killcmd' => 'killall gphoto2 && sleep 1', ] ], ]; From a09f127e5ce8339214a51305156936b5cc399302 Mon Sep 17 00:00:00 2001 From: Andreas Blaesius Date: Sun, 15 Nov 2020 12:21:06 +0100 Subject: [PATCH 6/9] install-raspbian: add www-data user to video group by default - needed to use raspistill and also needed for gphoto live preview Change-Id: I13927db714833c90c2a26b1a3db0dc6f1a42baf3 --- install-raspbian.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/install-raspbian.sh b/install-raspbian.sh index 9925e76b4..cd2f06138 100755 --- a/install-raspbian.sh +++ b/install-raspbian.sh @@ -267,6 +267,7 @@ fi info "### Setting permissions." chown -R www-data:www-data $INSTALLFOLDERPATH gpasswd -a www-data plugdev +gpasswd -a www-data video if [ -f "/usr/lib/gvfs/gvfs-gphoto2-volume-monitor" ]; then info "### Disabling camera automount." From 2b9ff8e5caa57d3425fea6b695cb24bbf4bf00d7 Mon Sep 17 00:00:00 2001 From: Andreas Blaesius Date: Sun, 15 Nov 2020 14:05:21 +0100 Subject: [PATCH 7/9] gphoto preview: stop preview earlier to free gphoto Change-Id: Ifa23bc5eb80d47361a34e04b808a9e3a50807f99 --- src/js/core.js | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/js/core.js b/src/js/core.js index 162838d3d..d5df2bdf4 100644 --- a/src/js/core.js +++ b/src/js/core.js @@ -246,7 +246,7 @@ const photoBooth = (function () { } }; - api.stopVideoAndTakePic = function (data) { + api.stopPreviewVideo = function () { if (api.stream) { const dataVideo = { play: 'false', @@ -260,7 +260,6 @@ const photoBooth = (function () { const track = api.stream.getTracks()[0]; track.stop(); $('#video--view').hide(); - api.callTakePicApi(data); }) .fail(function (xhr, status, result) { console.log('Could not stop webcam', result); @@ -376,12 +375,7 @@ const photoBooth = (function () { loader.css('background', config.colors.panel); loader.css('background-color', config.colors.panel); - - if (config.preview_mode === 'gphoto' && api.stream) { - api.stopVideoAndTakePic(data); - } else { - api.callTakePicApi(data); - } + api.callTakePicApi(data); }; api.callTakePicApi = function (data) { @@ -672,6 +666,7 @@ const photoBooth = (function () { api.startCountdown = function (start, element, cb) { let count = 0; let current = start; + const stop = start > 2 ? start - 2 : start; function timerFunction() { element.text(current); @@ -686,6 +681,9 @@ const photoBooth = (function () { cb(); } count++; + if (config.preview_mode === 'gphoto' && count === stop) { + api.stopPreviewVideo(); + } } timerFunction(); }; From 820f408ebe7c6ca3239ba56ecfbf0a7c6532df56 Mon Sep 17 00:00:00 2001 From: Andreas Blaesius Date: Sun, 15 Nov 2020 15:23:43 +0100 Subject: [PATCH 8/9] feature (gphoto preview): allow to start gphoto2 preview in background Change-Id: I93b3d03f4203932aa98b0dae0037446dc26f6a17 --- config/config.inc.php | 1 + lib/configsetup.inc.php | 5 ++ resources/lang/en.json | 2 + src/js/core.js | 104 +++++++++++++++++++++++++++------------- 4 files changed, 79 insertions(+), 33 deletions(-) diff --git a/config/config.inc.php b/config/config.inc.php index 81dfb9a3f..eefc334ec 100644 --- a/config/config.inc.php +++ b/config/config.inc.php @@ -81,6 +81,7 @@ // Please read https://github.com/andi34/photobooth/wiki/FAQ#how-to-use-a-live-stream-as-background-at-countdown // possible preview_mode values: none, device_cam, url, gphoto $config['preview_mode'] = 'none'; +$config['preview_gphoto_bsm'] = true; $config['previewCamTakesPic'] = false; $config['previewCamFlipHorizontal'] = true; // possible ipCamPreviewRotation values: '0deg', '90deg', -90deg', '180deg', '45deg', '-45deg' diff --git a/lib/configsetup.inc.php b/lib/configsetup.inc.php index bb460ba46..cf658e843 100644 --- a/lib/configsetup.inc.php +++ b/lib/configsetup.inc.php @@ -372,6 +372,11 @@ ], 'value' => $config['preview_mode'] ], + 'preview_gphoto_bsm' => [ + 'type' => 'checkbox', + 'name' => 'preview_gphoto_bsm', + 'value' => $config['preview_gphoto_bsm'] + ], 'previewCamTakesPic' => [ 'type' => 'checkbox', 'name' => 'previewCamTakesPic', diff --git a/resources/lang/en.json b/resources/lang/en.json index 4a1169fd2..03e3d94de 100644 --- a/resources/lang/en.json +++ b/resources/lang/en.json @@ -204,6 +204,7 @@ "manual_previewCamFlipHorizontal": "If enabled, preview from device cam is flipped horizontal.", "manual_previewCamTakesPic": "If enabled, a picture is taken from device cam instead executing the \"Take picture command\". Please note that the resolution depends on the given hight and width because it's acts like taking a screenshot.", "manual_preview_camera_mode": "Choose between front- or back facing camera mode of your device cam.", + "manual_preview_gphoto_bsm": "If enabled, gphoto2 live preview is started once a photo get triggered. This results in a delay of ~3 seconds until the preview is visible at countdown. If disabled, a preview is generated in background which results in a high battery usage and also a general slowdown.", "manual_preview_ipCamPreviewRotation": "Choose to rotate the preview from URL.", "manual_preview_ipCamURL": "CSS style to use a stream from an URL for preview while countdown.

Example: url(../img/bg_bluegray.jpg)

", "manual_preview_mode": "Choose a live preview mode. By default live preview is disabled, you can choose between a preview at countdown by your device cam and a preview from a URL. Preview \"from device cam\" will always use the camera of the device where Photobooth get opened in a Browser (e.g. on a tablet it will always show the tablet camera while on a smartphone it will always show the smartphone camera instead)! A secure origin or exception is required! You can find out how to set an exception here.", @@ -293,6 +294,7 @@ "previewCamFlipHorizontal": "Flip image from device cam horizontally", "previewCamTakesPic": "Device cam takes picture", "preview_camera_mode": "Camera facing mode", + "preview_gphoto_bsm": "Battery saving mode on gphoto2 live preview", "preview_ipCamPreviewRotation": "Rotate preview from URL", "preview_ipCamURL": "Preview-URL", "preview_mode": "Preview mode", diff --git a/src/js/core.js b/src/js/core.js index d5df2bdf4..2bf47af64 100644 --- a/src/js/core.js +++ b/src/js/core.js @@ -99,7 +99,7 @@ const photoBooth = (function () { resultPage.hide(); startPage.addClass('open'); - if (config.previewCamBackground) { + if (config.previewCamBackground || (config.preview_mode == 'gphoto ' && !config.preview_gphoto_bsm)) { api.startVideo('preview'); } @@ -163,40 +163,78 @@ const photoBooth = (function () { } if (config.preview_mode === 'gphoto') { - jQuery - .post('api/takeVideo.php', dataVideo) - .done(function (result) { - console.log('Start webcam', result); - pid = result.pid; - const getMedia = - navigator.mediaDevices.getUserMedia || - navigator.mediaDevices.webkitGetUserMedia || - navigator.mediaDevices.mozGetUserMedia || - false; - - if (!getMedia) { - return; - } + if (!config.preview_gphoto_bsm && mode === 'preview') { + jQuery + .post('api/takeVideo.php', dataVideo) + .done(function (result) { + console.log('Start webcam', result); + pid = result.pid; + }) + .fail(function (xhr, status, result) { + console.log('Could not start webcam', result); + }); + } else if (!config.preview_gphoto_bsm && mode === 'view') { + const getMedia = + navigator.mediaDevices.getUserMedia || + navigator.mediaDevices.webkitGetUserMedia || + navigator.mediaDevices.mozGetUserMedia || + false; + + if (!getMedia) { + return; + } - if (config.previewCamFlipHorizontal) { - $('#video--view').addClass('flip-horizontal'); - $('#video--preview').addClass('flip-horizontal'); - } + if (config.previewCamFlipHorizontal) { + $('#video--view').addClass('flip-horizontal'); + $('#video--preview').addClass('flip-horizontal'); + } - getMedia - .call(navigator.mediaDevices, webcamConstraints) - .then(function (stream) { - $('#video--view').show(); - videoView.srcObject = stream; - api.stream = stream; - }) - .catch(function (error) { - console.log('Could not get user media: ', error); - }); - }) - .fail(function (xhr, status, result) { - console.log('Could not start webcam', result); - }); + getMedia + .call(navigator.mediaDevices, webcamConstraints) + .then(function (stream) { + $('#video--view').show(); + videoView.srcObject = stream; + api.stream = stream; + }) + .catch(function (error) { + console.log('Could not get user media: ', error); + }); + } else { + jQuery + .post('api/takeVideo.php', dataVideo) + .done(function (result) { + console.log('Start webcam', result); + pid = result.pid; + const getMedia = + navigator.mediaDevices.getUserMedia || + navigator.mediaDevices.webkitGetUserMedia || + navigator.mediaDevices.mozGetUserMedia || + false; + + if (!getMedia) { + return; + } + + if (config.previewCamFlipHorizontal) { + $('#video--view').addClass('flip-horizontal'); + $('#video--preview').addClass('flip-horizontal'); + } + + getMedia + .call(navigator.mediaDevices, webcamConstraints) + .then(function (stream) { + $('#video--view').show(); + videoView.srcObject = stream; + api.stream = stream; + }) + .catch(function (error) { + console.log('Could not get user media: ', error); + }); + }) + .fail(function (xhr, status, result) { + console.log('Could not start webcam', result); + }); + } } else { const getMedia = navigator.mediaDevices.getUserMedia || From d8bb286ee7aa8897d9aede6e4fd6cfd3d8fac446 Mon Sep 17 00:00:00 2001 From: Andreas Blaesius Date: Mon, 16 Nov 2020 19:50:59 +0100 Subject: [PATCH 9/9] faq: add initial gphoto2 preview instructions Change-Id: I6a81e6950faf2367c86af2c97204247470df4b8b --- faq/faq.md | 16 ++++++++++++++++ manual/faq.html | 17 +++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/faq/faq.md b/faq/faq.md index 378bbaab6..cfcf87e27 100644 --- a/faq/faq.md +++ b/faq/faq.md @@ -223,6 +223,22 @@ There's different ways depending on your needs and personal setup: - Capture pictures via `raspistill` won't work if motion is installed! - Requires Photobooth v2.2.1 or later! +3. A device independent preview can also be done using the video mode of your DSLR (Linux only): + - install all dependencies `sudo apt install ffmpeg v4l2loopback-dkms -y` + - create a virtual webcam `modprobe v4l2loopback exclusive_caps=1 card_label="GPhoto2 Webcam"` + - `/dev/video0` is used by default, you can use `v42l-ctl --list-devices` to check which `/dev/*` is the correct one: + If it doesn't match the default setup you need to adjust the `Command to generate a live preview` inside the admin panel! + - Give permissions to /dev/video* `sudo gpasswd -a www-data video` (this was done automatically if you used the installation script) and reboot once + - Admin panel config *"Preview mode"*: `from gphoto2` + + **Note** + - Requires Photobooth v2.11.0 or later! + - There's a delay of about 3 seconds until the preview starts, to avoid that disable the `Battery saving mode on gphoto2 live preview` option to generate a preview in background. **This results in a high battery usage and also a general slowdown.** + - Sometimes Chromium doesn't detect the V4l2 camera launch from php: you need to run `sudo gphoto2 --stdout --capture-movie | ffmpeg -i - -vcodec rawvideo -pix_fmt yuv420p -threads 0 -f v4l2 /dev/video0` from terminal first and load Chromium a first time with a webpage asking for the camera. + - Chromium sometimes has trouble, if there is another webcam like `bcm2835-isp`, it will take it by default instead. Disable other webcams, e.g. `rmmod bcm2835-isp`. + - Make sure the countdown is long enough to start the preview and free gphoto2 at the end of the countdown to be able to take a picture (2 seconds before the countdown ends). + - For best user experience the countdown should be set at least to 8 seconds. +
### Can I use a live stream as background? diff --git a/manual/faq.html b/manual/faq.html index 276b270ac..f93769f3d 100644 --- a/manual/faq.html +++ b/manual/faq.html @@ -268,6 +268,23 @@

How to use a live stream as background at countdown?

  • Do NOT enable "Device cam takes picture" in admin panel config!
  • Capture pictures via raspistill won't work if motion is installed!
  • Requires Photobooth v2.2.1 or later!
+
  • A device independent preview can also be done using the video mode of your DSLR (Linux only):

    + +
    • install all dependencies sudo apt install ffmpeg v4l2loopback-dkms -y
    • +
    • create a virtual webcam modprobe v4l2loopback exclusive_caps=1 card_label="GPhoto2 Webcam" +
      • /dev/video0 is used by default, you can use v42l-ctl --list-devices to check which /dev/* is the correct one:
        +If it doesn't match the default setup you need to adjust the Command to generate a live preview inside the admin panel!
    • +
    • Give permissions to /dev/video* sudo gpasswd -a www-data video (this was done automatically if you used the installation script) and reboot once
    • +
    • Admin panel config "Preview mode": from gphoto2
    + +

    Note

    + +
    • Requires Photobooth v2.11.0 or later!
    • +
    • There's a delay of about 3 seconds until the preview starts, to avoid that disable the Battery saving mode on gphoto2 live preview option to generate a preview in background. This results in a high battery usage and also a general slowdown.
    • +
    • Sometimes Chromium doesn't detect the V4l2 camera launch from php: you need to run sudo gphoto2 --stdout --capture-movie | ffmpeg -i - -vcodec rawvideo -pix_fmt yuv420p -threads 0 -f v4l2 /dev/video0 from terminal first and load Chromium a first time with a webpage asking for the camera.
    • +
    • Chromium sometimes has trouble, if there is another webcam like bcm2835-isp, it will take it by default instead. Disable other webcams, e.g. rmmod bcm2835-isp.
    • +
    • Make sure the countdown is long enough to start the preview and free gphoto2 at the end of the countdown to be able to take a picture (2 seconds before the countdown ends). +
      • For best user experience the countdown should be set at least to 8 seconds.