Add a Record button to SLP

S.L.P. image questions, stereoscopic video livestream and recording, stereoscopic photo capture etc.
Post Reply
User avatar
stereomii
Posts: 37
Joined: Mon May 13, 2019 3:11 pm
Location: Apeldoorn, The Netherlands
Contact:

Add a Record button to SLP

Post by stereomii »

Add a Record button to SLP

Recording a video is rather complicated in SLP 0.2.4, 06-12 correction:0.2.3, latest image.
Next steps must be performed to start/stop recording:
  • open settings menu
    (sometimes) scroll to "Recording" checkbox
    click checkbox
    scroll to "Save" button
    click button
    click screen to dismiss settings menu
And to check recorded video:
  • click "Video Records" button
    (sometimes) scroll to last recording
    click recorded file name
and to return:
  • click "back"
    click "back"
So I added a "Record" button showing and toggling recording state. Also added displaying a link the last recorded video in the same way as make photo does.

There are quite a numer of changes to make. Maybe there are better and more structured ways but this implementation works.

Basically the solution consists of replacing the stereopi logo with a new button, linked to a new javascript function "toggle_recording()" (copied for a great deal from "make_photo()". I removed the stereopi logo so it can not accidentally be hit if we toggle recording state.
toggle_recording calls /var/www/html/toggle_recording.php.
Added two images to /var/www/html/imgs: record0.png and record1.png as inactive/active state image.
Image and Image


To get consistent information aboute recording state after a refesh op the main web page a link to /run/record.png is used, loop-record.sh copies active or inactive button image here depending on recording state.

The solution presented here incorporates "Unreadeable recorded video in SLP" viewtopic.php?f=10&t=965

Step-by-step instruction (mount filesystems rw first):

step1: dowload record0.png and record1.png (from the links above), place them in /var/www/html/imgs
step2: copy record0.png to /run (via ssh in live SLP system or else you will not find /run)
step3: rename /run/record0.png to /run/record.png
step4: via ssh in live SLP cd to /var/www/html/imgs and create a symlink to record0.png: ln -s record.png /run/
step5: create new file /var/www/html/toggle_recording.php with following content:

Code: Select all

<?php
	$path = '/media/DCIM/';
	$filename = file('/run/RECFILE');


	/// Load config file
	$config_strings = file('/opt/StereoPi/config.conf');

	/// Parse config file
	$config = array();
	foreach ($config_strings as $k => $v) {
		$tmp = explode("=", trim($v));
		$config[$tmp[0]] = $tmp[1];
        	/// shell_exec("echo $tmp[0] $tmp[1] >> /media/message");
	}

	if ($config['record_enabled'] == "0") {
    		$config['record_enabled'] = "1";
		system("sudo cp imgs/record1.png imgs/record.png >> /dev/null 2>&1 &");
	} else {
		$config['record_enabled'] = "0";
		system("sudo cp imgs/record0.png imgs/record.png >> /dev/null 2>&1 &");
	}

	$config_string = "";
	foreach ($config as $k => $v ) {
		$config_string = $config_string . $k . "=" .  $v . "\n";
	}

        system("sudo killall -q sleep >> /dev/null 2>&1 &");
        system("sudo killall -q rtsp-server >> /dev/null 2>&1 &");
        system("sudo killall -q splitter >> /dev/null 2>&1 &");
        system("sudo killall -q raspivid >> /dev/null 2>&1 &");
        system("sudo killall -q gst-launch-1.0 >> /dev/null 2>&1 &");
        system("sudo killall -q nodejs index.js >> /dev/null 2>&1 &");

	$file = fopen('/opt/StereoPi/config.conf',"w");
	fwrite($file , $config_string);
	fclose($file);

	$res['status'] = $config['record_enabled'];
	///$res['filename'] = $filename;
	$res['filename'] = $filename;
	echo json_encode($res);
?>

step6: open /var/www/html/index.php
step7: add after following lines:

Code: Select all

	<body>

		<canvas id="video_canvas"></canvas>

(around line 58) the following:

Code: Select all

<!-- JV : add record button -->
                <img style="position:absolute;right:20px;top:20px;z-index:500;display:block;" id="record_icon" alt="" src="imgs/record.png" width="50" title="Toggle recording"
                    onclick="toggle_recording()" />
step8: comment-out logo_icon (around line 69)

Code: Select all

<!--		JV : remove logo icon, too much chanche to hit it accidentally if we want to toggle recording
		<div class="fw_hide" id="logo_icon"><a href="http://stereopi.com" target="_blank"><img src="imgs/stereopi_logo1.png" width="50" title="StereoPi site"></a></div>
		JV -->
step9: I added two addition fps rates in video_fps around line 213, included here to keep line numbers in this description consistent

Code: Select all

						<option>24</option>
						<option>25</option>
step10: after

Code: Select all

			$('#save_button').on('click', function() {
				.....
      			       var record_time = $("#record_time").val();
(around line 525) add:

Code: Select all

                       // 	JV : manage recording button state
                                ///window.alert(document.getElementById("record_icon").src);
                                if (record_enabled == "0") {
                                        document.getElementById("record_icon").src = "imgs/record0.png";
                                    } else {
                                        document.getElementById("record_icon").src = "imgs/record1.png";
                                }

step11: after function make_photo()

Code: Select all

			function make_photo() {
				show_status_message('making a photo...');
                            . . . . .
					} else {
						show_status_message('failed');
					}

				});
			}

(around line 607) add:

Code: Select all

                        // JV : toggle recording function, most stolen from make_photo;)
                        function toggle_recording() {
                                //window.alert(document.getElementById("record_icon").src.slice(-5));
                                //show_status_message('toggle recording...');
                                $.post("toggle_recording.php", {
                                } , function(data) {

                                        var json;

                                        try {
                                                json = JSON.parse(data);
                                        } catch (e) {
                                                show_status_message('failed');
                                                return;
                                        }

                                        ///page_reload();

                                        if (json.status == 0) {
                                                document.getElementById("record_icon").src = "imgs/record0.png"
                                                show_status_message('<a href="/records/' + json.filename + '" target="_blank">' + json.filename + '</a>');
                                        } else {
                                                document.getElementById("record_icon").src = "imgs/record1.png"
                                        }
                                    })
                        }
step12: save index.php
step13: open \opt\StereoPi\scripts\loop-record.sh in your favorite editor
step13: after

Code: Select all

mkdir -p $RECPATH
add (line 7)

Code: Select all

#JV create /run/record.png at startup
if [ -f ./config.conf ] ; then
    . ./config.conf
fi
#JV create /run/record.png at startup
if [ "$record_enabled" = "1" ] ; then
                cp /var/www/html/imgs/record1.png  /run/record.png
else
                cp /var/www/html/imgs/record0.png  /run/record.png
fi

after

Code: Select all

    if [ "$record_enabled" = "1" ] ; then
(line 27) add

Code: Select all

                #JV manage record button
                cp /var/www/html/imgs/record1.png  /run/record.png
add BEFORE!

Code: Select all

    if [ "$audio_enabled" = "1" ] ; then
(line 44) add BEFORE!

Code: Select all

 #JV do signal here
    killall -q -INT recorder
    sleep 2
 #JV save last vid id
    RECFILE="record-`date +%Y%m%d-%H%M%S`.mp4"
    echo -n $RECFILE > /run/RECFILE
    echo "RECFILE = " $RECPATH/`echo -n $RECFILE`
change filesink location in next block so it reads:

Code: Select all

    if [ "$audio_enabled" = "1" ] ; then
		echo "Recording with audio"
		amixer -D hw:1 set "Auto Gain Control" off
		amixer -D hw:1 set "Mic" 100
		#JV filesink location
		#./bin/recorder -e udpsrc port=3003 buffer-size=200000 ! h264parse ! queue ! mux.video_0 alsasrc device=plughw:1,0 ! "audio/x-raw,channels=1,depth=16,width=16,rate=44100" ! voaacenc bitrate=128000 ! aacparse ! queue ! mux.audio_0 qtmux name=mux ! filesink location="$RECPATH/record-`date +%Y%m%d-%H%M%S`.mp4" sync=true
		./bin/recorder -e udpsrc port=3003 buffer-size=200000 ! h264parse ! queue ! mux.video_0 alsasrc device=plughw:1,0 ! "audio/x-raw,channels=1,depth=16,width=16,rate=44100" ! voaacenc bitrate=128000 ! aacparse ! queue ! mux.audio_0 qtmux name=mux ! filesink location="$RECPATH/$RECFILE" sync=true
    else
		echo "Recording without audio"
		#JV filesink location
		#./bin/recorder -e udpsrc port=3003 buffer-size=200000 ! h264parse ! queue ! qtmux ! filesink location="$RECPATH/record-`date +%Y%m%d-%H%M%S`.mp4" sync=true
		./bin/recorder -e udpsrc port=3003 buffer-size=200000 ! h264parse ! queue ! qtmux ! filesink location="$RECPATH/$RECFILE" sync=true
    fi
Step 14: save loop_record.sh

Done! reboot your StereoPi and enjoy your record button.
[*]Allthough I double-checked the correct inclusion of all changed code I think you should test it out on a copy of your SD-card. At least until I get confirmation that this description indeed works and thus is complete ;)



From here I include all changed files, instead of copying you can also overwrite them if you trust me (or diff them with the originals) (:
/var/www/html/toggle_recording.php contents

Code: Select all

<?php
	$path = '/media/DCIM/';
	$filename = file('/run/RECFILE');


	/// Load config file
	$config_strings = file('/opt/StereoPi/config.conf');

	/// Parse config file
	$config = array();
	foreach ($config_strings as $k => $v) {
		$tmp = explode("=", trim($v));
		$config[$tmp[0]] = $tmp[1];
        	/// shell_exec("echo $tmp[0] $tmp[1] >> /media/message");
	}

	if ($config['record_enabled'] == "0") {
    		$config['record_enabled'] = "1";
		system("sudo cp imgs/record1.png imgs/record.png >> /dev/null 2>&1 &");
	} else {
		$config['record_enabled'] = "0";
		system("sudo cp imgs/record0.png imgs/record.png >> /dev/null 2>&1 &");
	}

	$config_string = "";
	foreach ($config as $k => $v ) {
		$config_string = $config_string . $k . "=" .  $v . "\n";
	}

        system("sudo killall -q sleep >> /dev/null 2>&1 &");
        system("sudo killall -q rtsp-server >> /dev/null 2>&1 &");
        system("sudo killall -q splitter >> /dev/null 2>&1 &");
        system("sudo killall -q raspivid >> /dev/null 2>&1 &");
        system("sudo killall -q gst-launch-1.0 >> /dev/null 2>&1 &");
        system("sudo killall -q nodejs index.js >> /dev/null 2>&1 &");

///	$file = fopen('/media/config.conf',"w");
	$file = fopen('/opt/StereoPi/config.conf',"w");
	fwrite($file , $config_string);
	fclose($file);

//JV
        //sleep (3);

        //system("sudo killall -q -INT recorder >> /dev/null 2>&1 &");


	$res['status'] = $config['record_enabled'];
	///$res['filename'] = $filename;
	$res['filename'] = $filename;
	echo json_encode($res);
?>
file /var/www/html/index.php

Code: Select all

<html>
	<head>
		<title>StereoPi : <?php echo $_SERVER['SERVER_ADDR'];  ?></title>

		<link rel="apple-touch-icon" sizes="57x57" href="/icons/apple-icon-57x57.png">
		<link rel="apple-touch-icon" sizes="60x60" href="/icons/apple-icon-60x60.png">
		<link rel="apple-touch-icon" sizes="72x72" href="/icons/apple-icon-72x72.png">
		<link rel="apple-touch-icon" sizes="76x76" href="/icons/apple-icon-76x76.png">
		<link rel="apple-touch-icon" sizes="114x114" href="/icons/apple-icon-114x114.png">
		<link rel="apple-touch-icon" sizes="120x120" href="/icons/apple-icon-120x120.png">
		<link rel="apple-touch-icon" sizes="144x144" href="/icons/apple-icon-144x144.png">
		<link rel="apple-touch-icon" sizes="152x152" href="/icons/apple-icon-152x152.png">
		<link rel="apple-touch-icon" sizes="180x180" href="/icons/apple-icon-180x180.png">
		<link rel="icon" type="image/png" sizes="192x192"  href="/icons/android-icon-192x192.png">
		<link rel="icon" type="image/png" sizes="32x32" href="/icons/favicon-32x32.png">
		<link rel="icon" type="image/png" sizes="96x96" href="/icons/favicon-96x96.png">
		<link rel="icon" type="image/png" sizes="16x16" href="/icons/favicon-16x16.png">
		<link rel="manifest" href="/icons/manifest.json">
		<meta name="msapplication-TileColor" content="#ffffff">
		<meta name="msapplication-TileImage" content="/icons/ms-icon-144x144.png">
		<meta name="theme-color" content="#ffffff">
	</head>

	<style>
		html,body {background-color:white; padding:0; margin:0; width:100%; height:100%; font-family:Arial; -webkit-user-select: none; -moz-user-select: -moz-none; -ms-user-select: none; user-select: none;}
		#version_block { position:absolute; bottom:10px; left:10px; font-color:black; font-family:Arial;}
		#video_canvas {width:100%; height:100%; background-image:url(imgs/stereopi_bg2.jpg); background-repeat:no-repeat; background-size:contain; background-position: 50% 50%;}
		#settings_window { position:absolute; left:0px; top:0px; bottom:0px; width:0px; background-color:black; display:block; overflow:hidden; color:white; z-index:510 }
		#toggle_settings { position:absolute;left:20px;top:20px;z-index:500;display:block; }
		#photo_icon { position:absolute;left:25px;top:100px;z-index:500;display:block; }
		#records_icon { position:absolute;left:25px;top:180px;z-index:500;display:block; }
		#filemanager_icon { position:absolute;left:25px;top:260px;z-index:500;display:block; }
		#console_icon { position:absolute;left:25px;top:340px;z-index:500;display:block; }
		#fwupdate_icon { position:absolute;left:25px;top:420px;z-index:500;display:block; }
		#logo_icon { position:absolute;right:20px;top:20px;z-index:500;display:block; }
		.input_box { padding:4px 10px 4px 4px;}
		input, select { padding:4px 10px 4px 4px; }
		#hellomessage { position:absolute; top:10%; left:30%; right:30%; width:auto; height:auto; margin:0; padding:10px; text-align:center; color:white; background-color:gray; font-size:1.4em; display:none; }
		#status_message { position:absolute; top:20px; left:220px; padding:5px; display:none; color:white; background-color:black; }
		#status_message a { color:white; }

		::-webkit-scrollbar {
	    	width: 0px;  /* remove scrollbar space */
		    background: transparent;  /* optional: just make scrollbar invisible */
		}
		/* optional: show position indicator in red */
		::-webkit-scrollbar-thumb {
		    background: #FF0000;
		}

	</style>

	<body>

		<canvas id="video_canvas"></canvas>

<!-- JV : add record button -->
                <img style="position:absolute;right:20px;top:20px;z-index:500;display:block;" id="record_icon" alt="" src="imgs/record.png" width="50" title="Toggle recording"
                    onclick="toggle_recording()" />

		<div class="fw_hide" id="version_block">
			<?php
				echo 'version ' . file_get_contents('/opt/StereoPi/version');
			?>
		</div>

<!--		JV : remove logo icon, too much chanche to hit it accidentally if we want to toggle recording
		<div class="fw_hide" id="logo_icon"><a href="http://stereopi.com" target="_blank"><img src="imgs/stereopi_logo1.png" width="50" title="StereoPi site"></a></div>
		JV -->
		<input class="fw_hide" id="toggle_settings" type="image" src="imgs/settings1.png" width="50" title="Settings"/>
		<div class="fw_hide" id="photo_icon"><a href="#" onclick="make_photo(); return false;"><img src="imgs/photo1.png" width="50" title="Make a photo"></a></div>
		<div class="fw_hide" id="records_icon"><a href="/records"><img src="imgs/files1.png" width="50" title="Video records"></a></div>
		<div class="fw_hide" id="filemanager_icon"><a href="/files"><img src="imgs/filemanager1.png" width="50" title="File manager"></a></div>
		<div class="fw_hide" id="console_icon"><a href="/console"><img src="imgs/console1.png" width="50" title="Console"></a></div>
		<div class="fw_hide" id="fwupdate_icon"><a href="/update.html"><img src="imgs/firmware_update1.png" width="50" title="Firmware update"></a></div>

		<div class="fw_hide" id="status_message"></div>

		<div id="settings_window">

			<div style="height:100%; padding:20px; overflow:auto; y-scroll:hidden;">

				<p>
					Image mode &nbsp;&nbsp;&nbsp;
					<select id="video_mode" style="width:100%;">
						<option>2D</option>
						<option>3D</option>
					</select>
				</p>

				<p>
					<input type="checkbox" id="updown_enabled"><label for="updown_enabled">Upside/down</label>
				</p>

				<p>
					<input type="checkbox" id="swapcams_enabled"><label for="swapcams_enabled">Swap cams</label>
				</p>
				
				<p>
					Photo resolution &nbsp;&nbsp;&nbsp;
					<select id="photo_resolution" style="width:100%;">
						<option>default</option>
						<option>V1-full-size</option>
						<option>V2-full-size</option>
					</select>
				</p>				

				<p>
					Video resolution &nbsp;&nbsp;&nbsp;
					<select id="video_resolution" style="width:100%;">
						<option>640x480</option>
						<option>1280x600</option>
						<option>1280x720</option>
						<option>1280x800</option>
						<option>1280x960</option>
						<option>1640x922</option>
						<option>1920x1080</option>
					</select>
				</p>

				<p>&nbsp;</p>

				<hr />

				<p style="color:yellow;">Rec settings</p>

				<p>
					<input type="checkbox" id="record_enabled"><label for="record_enabled">Recording</label>
				</p>

				<p>
					Max rec duration &nbsp;&nbsp;&nbsp;
					<select id="record_time" style="width:100%;">
						<option value="30">30 sec</option>
						<option value="60">1 min</option>
						<option value="300">5 min</option>
						<option value="600">10 min</option>
						<option value="1200">20 min</option>
						<option value="1800">30 min</option>
					</select>
				</p>

				<p>&nbsp;</p>

				<hr />

				<p style="color:yellow;">Stream settings</p>

				<p>
					<input type="checkbox" id="ws_enabled"><label for="ws_enabled">Browser stream</label>
				</p>

				<p>
					<input type="checkbox" id="udp_enabled"><label for="udp_enabled">Stream UDP</label>
				</p>

				<p>
					UDP clients &nbsp;&nbsp;&nbsp;
					<input type="text" id="udp_clients" class="input_box" style="width:100%;"/>
				</p>

				<p>
					<input type="checkbox" id="usb_enabled"><label for="usb_enabled">USB enabled</label>
				</p>

				<p>
					<input type="checkbox" id="rtmp_enabled"><label for="rtmp_enabled">RTMP enabled</label>
				</p>

				<p>
					<input type="checkbox" id="audio_switch"><label for="audio_switch">Audio enabled</label>
				</p>

				<p>
					RTMP URL &nbsp;&nbsp;&nbsp;
					<input type="text" id="rtmp_url" class="input_box" style="width:100%;"/>
				</p>


				<p>
					<input type="checkbox" id="mpegts_enabled"><label for="mpegts_enabled">MPEG-TS enabled</label>
				</p>

				<p>
					MPEG-TS clients &nbsp;&nbsp;&nbsp;
					<input type="text" id="mpegts_clients" class="input_box" style="width:100%;"/>
				</p>

				<p>
					<input type="checkbox" id="rtsp_enabled"><label for="rtsp_enabled">RTSP enabled</label> <br>
					<p style="color:gray;">All other streams disabled when RTSP enabled!</p>
					<p><a href="rtsp://<?php echo $_SERVER['SERVER_ADDR'];?>:554/h264" target="_blank">RTSP link</a></p>
				</p>

				<p>&nbsp;</p>

				<hr />

				<p style="color:yellow;">Video settings</p>

				<p>
					<input type="checkbox" id="dec_enabled"><label for="dec_enabled">Decimation</label>
				</p>


				<p>
					FPS &nbsp;&nbsp;&nbsp;
					<select id="video_fps" style="width:100%;">
						<option>10</option>
						<option>20</option>
						<option>24</option>
						<option>25</option>
						<option>30</option>
						<option>40</option>
						<option>42</option>
						<option>48</option>
						<option>60</option>
						<option>90</option>
					</select>
				</p>
				<p>
					Bitrate &nbsp;&nbsp;&nbsp;
					<select id="video_bitrate" style="width:100%;">
						<option>500000</option>
						<option>1000000</option>
						<option>2000000</option>
						<option>3000000</option>
						<option>4000000</option>
						<option>5000000</option>
						<option>6000000</option>
						<option>7000000</option>
						<option>8000000</option>
						<option>9000000</option>
						<option>10000000</option>
					</select>
				</p>

				<p>
					Profile &nbsp;&nbsp;&nbsp;
					<select id="video_profile" style="width:100%;">
						<option>baseline</option>
						<option>main</option>
						<option>high</option>
					</select>
				</p>

				<p>
					White balance &nbsp;&nbsp;&nbsp;
					<select id="video_wb" style="width:100%;">
						<option>off</option>
						<option>auto</option>
						<option>sun</option>
						<option>cloud</option>
						<option>shade</option>
						<option>tungsten</option>
						<option>fluorescent</option>
						<option>incandescent</option>
						<option>flash</option>
						<option>horizon</option>
					</select>
				</p>

				<p>
					Exposure &nbsp;&nbsp;&nbsp;
					<select id="exposure" style="width:100%;">
						<option>off</option>
						<option>auto</option>
						<option>night</option>
						<option>nightpreview</option>
						<option>backlight</option>
						<option>spotlight</option>
						<option>sports</option>
						<option>snow</option>
						<option>beach</option>
						<option>verylong</option>
						<option>fixedfps</option>
						<option>antishake</option>
						<option>fireworks</option>
					</select>
				</p>

				<p>
					Contrast &nbsp;&nbsp;&nbsp;
					<select id="contrast" style="width:100%;">
						<option>100</option>
						<option>90</option>
						<option>80</option>
						<option>70</option>
						<option>60</option>
						<option>50</option>
						<option>40</option>
						<option>30</option>
						<option>20</option>
						<option>15</option>
						<option>10</option>
						<option>5</option>
						<option>0</option>
						<option>-5</option>
						<option>-10</option>
						<option>-15</option>
						<option>-20</option>
						<option>-30</option>
						<option>-40</option>
						<option>-50</option>
						<option>-60</option>
						<option>-70</option>
						<option>-80</option>
						<option>-90</option>
						<option>-100</option>
					</select>
				</p>

				<p>
					Sharpness &nbsp;&nbsp;&nbsp;
					<select id="sharpness" style="width:100%;">
						<option>100</option>
						<option>90</option>
						<option>80</option>
						<option>70</option>
						<option>60</option>
						<option>50</option>
						<option>40</option>
						<option>30</option>
						<option>20</option>
						<option>15</option>
						<option>10</option>
						<option>5</option>
						<option>0</option>
						<option>-5</option>
						<option>-10</option>
						<option>-15</option>
						<option>-20</option>
						<option>-30</option>
						<option>-40</option>
						<option>-50</option>
						<option>-60</option>
						<option>-70</option>
						<option>-80</option>
						<option>-90</option>
						<option>-100</option>
					</select>
				</p>

				<p>
					Digital gain &nbsp;&nbsp;&nbsp;
					<select id="digitalgain" style="width:100%;">
						<option>10.0</option>
						<option>9.0</option>
						<option>8.0</option>
						<option>7.0</option>
						<option>6.0</option>
						<option>5.0</option>
						<option>4.0</option>
						<option>3.0</option>
						<option>2.0</option>
						<option>1.5</option>
						<option>1.0</option>
						<option>0.5</option>
						<option>0.0</option>
						<option>-0.5</option>
						<option>-1.0</option>
						<option>-1.5</option>
						<option>-2.0</option>
						<option>-3.0</option>
						<option>-4.0</option>
						<option>-5.0</option>
						<option>-6.0</option>
						<option>-7.0</option>
						<option>-8.0</option>
						<option>-9.0</option>
						<option>-10.0</option>
					</select>
				</p>

				<p>&nbsp;</p>

				<hr/>

				<p style="color:yellow;">Wi-Fi settings</p>

				<p>
					Wi-Fi interface &nbsp;&nbsp;&nbsp;
					<select id="wifi_iface" style="width:100%;">
						<option></option>
						<option>wifi0</option>
						<option>wlan0</option>
						<option>wlan1</option>
					</select>
				</p>

				<p>
					Wi-Fi SSID&nbsp;&nbsp;&nbsp;
					<input type="text" id="wifi_ssid" class="input_box" style="width:100%;"/>
				</p>

				<p>
					Wi-Fi password &nbsp;&nbsp;&nbsp;
					<input type="password" id="wifi_psk" class="input_box" style="width:100%;"/>
				</p>

				<p>&nbsp;</p>

				<hr />

				<p>
					<input type="button" id="save_button" value="Save" style="width:100%;background-color:lightgreen;">
				</p>

				<p>&nbsp;</p>
				<p>&nbsp;</p>

			</div>
			
		</div>

		<div id="hellomessage">Double tap for fullsreen toggle</div>

		<script type="text/javascript" src="js/jquery.min.js"></script>
		<script type="text/javascript" src="js/http-live-player.js">;</script>
		<script type="text/javascript" src="js/player.js">;</script>
		<script type="text/javascript" src="js/screen.js">;</script>


		<script type="text/javascript">


			$('#toggle_settings').on('click', function(){
				toggle_settings_window();
			});

			function is_settings_opened() {
				var state = $("#settings_window").css("width") == "0px" ? false : true;
				return state;
			}

			function toggle_settings_window() {

				if (!is_settings_opened()) {
					load_config();
					$('#toggle_settings').css("display","none");
					$("#settings_window").animate({width:"200px"}, 100);
				} else {
					$("#settings_window").animate({width:"0px"}, 100);
					$('#toggle_settings').css("display","block");
				}
			}

			function load_config() {
				$.post("getconfig.php", function( data ) {
					parse_config(data);
				});
			}

			function parse_config(data) {
				var json;
				try {
					json = JSON.parse(data);
				} catch (e) { return; }

				$("#photo_resolution").val(json.photo_resolution);
				$("#video_resolution").val(json.video_width + "x" + json.video_height);
				$("#video_mode").val(json.video_mode);
				$("#video_fps").val(json.video_fps);
				$("#video_bitrate").val(json.video_bitrate);
				$("#video_profile").val(json.video_profile);
				$("#rtmp_url").val(json.rtmp_url);
				$("#audio_switch").prop( "checked", json.audio_enabled == "1" ? true : false);
				$("#rtmp_enabled").prop( "checked", json.rtmp_enabled == "1" ? true : false);
				$("#mpegts_enabled").prop( "checked", json.mpegts_enabled == "1" ? true : false);
				$("#mpegts_clients").val(json.mpegts_clients);
				$("#rtsp_enabled").prop( "checked", json.rtsp_enabled == "1" ? true : false);
				$("#usb_enabled").prop( "checked", json.usb_enabled == "1" ? true : false);
				$("#video_wb").val(json.video_wb);
				$("#exposure").val(json.exposure);
				$("#sharpness").val(json.sharpness);
				$("#contrast").val(json.contrast);
				$("#digitalgain").val(json.digitalgain);
				$("#wifi_iface").val(json.wifi_iface);
				$("#wifi_ssid").val(json.wifi_ssid);
				$("#wifi_psk").val(json.wifi_psk);
				$("#record_enabled").prop( "checked", json.record_enabled == "1" ? true : false);
				$("#dec_enabled").prop( "checked", json.dec_enabled == "1" ? true : false);
				$("#updown_enabled").prop( "checked", json.up_down == "1" ? true : false);
				$("#swapcams_enabled").prop( "checked", json.swapcams == "1" ? true : false);
				$("#udp_enabled").prop( "checked", json.udp_enabled == "1" ? true : false);
				$("#ws_enabled").prop( "checked", json.ws_enabled == "1" ? true : false);
				$("#udp_clients").val(json.udp_clients);
				$("#record_time").val(json.record_time);				
			}

			$('#save_button').on('click', function() {
				var photo_resolution = $("#photo_resolution").val();
				var video_resolution = $("#video_resolution").val();
				var video_mode = $("#video_mode").val();
				var video_width = video_resolution.split('x')[0];
				var video_height = video_resolution.split('x')[1];
				var video_fps = $("#video_fps").val();
				var video_bitrate = $("#video_bitrate").val();
				var video_profile = $("#video_profile").val();
				var rtmp_url = $("#rtmp_url").val();
				var audio_enabled = $("#audio_switch").prop("checked") ? "1" : "0";
				var rtmp_enabled = $("#rtmp_enabled").prop("checked") ? "1" : "0";
				var mpegts_clients = $("#mpegts_clients").val();
				var mpegts_enabled = $("#mpegts_enabled").prop("checked") ? "1" : "0";
				var rtsp_enabled = $("#rtsp_enabled").prop("checked") ? "1" : "0";
				var usb_enabled = $("#usb_enabled").prop("checked") ? "1" : "0";
				var video_wb = $("#video_wb").val();
				var exposure = $("#exposure").val();
				var contrast = $("#contrast").val();
				var sharpness = $("#sharpness").val();
				var digitalgain = $("#digitalgain").val();
				var wifi_iface = $("#wifi_iface").val();
				var wifi_ssid = $("#wifi_ssid").val();
				var wifi_psk = $("#wifi_psk").val();
				var record_enabled = $("#record_enabled").prop("checked") ? "1" : "0";
				var dec_enabled = $("#dec_enabled").prop("checked") ? "1" : "0";
				var updown_enabled = $("#updown_enabled").prop("checked") ? "1" : "0";
				var swapcams_enabled = $("#swapcams_enabled").prop("checked") ? "1" : "0";
				var udp_enabled = $("#udp_enabled").prop("checked") ? "1" : "0";
				var ws_enabled = $("#ws_enabled").prop("checked") ? "1" : "0";
				var udp_clients = $("#udp_clients").val();
				var record_time = $("#record_time").val();

                       // 	JV : manage recording button state
                                ///window.alert(document.getElementById("record_icon").src);
                                if (record_enabled == "0") {
                                        document.getElementById("record_icon").src = "imgs/record0.png";
                                    } else {
                                        document.getElementById("record_icon").src = "imgs/record1.png";
                                }

				/// Only baseline profile available if WebSockets enabled
				if (ws_enabled == "1") {
					if (video_profile != "baseline") {
						alert('Only "baseline" profile allowed if "Browser stream" enabled');
						return;
					}
				}

				$.post("saveconfig.php", {
					photo_resolution:photo_resolution,
					video_width:video_width,
					video_mode:video_mode,
					video_height:video_height,
					video_fps:video_fps,
					video_bitrate:video_bitrate,
					video_profile:video_profile,
					rtmp_url:rtmp_url,
					rtmp_enabled:rtmp_enabled,
					mpegts_clients:mpegts_clients,
					mpegts_enabled:mpegts_enabled,
					rtsp_enabled:rtsp_enabled,
					usb_enabled:usb_enabled,
					audio_enabled:audio_enabled,
					video_wb:video_wb,
					exposure:exposure,
					contrast:contrast,
					sharpness:sharpness,
					digitalgain:digitalgain,
					wifi_iface:wifi_iface,
					wifi_ssid:wifi_ssid,
					wifi_psk:wifi_psk,
					record_enabled:record_enabled,
					record_time:record_time,
					dec_enabled:dec_enabled,
					up_down:updown_enabled,
					swapcams:swapcams_enabled,
					udp_clients:udp_clients,
					udp_enabled:udp_enabled,
					ws_enabled:ws_enabled
				} , function(data) {
					if (data != "") alert(data);
				});
			});

			function page_reload() {
				location.reload();
			}


			function make_photo() {
				show_status_message('making a photo...');
				$.post("make_photo.php", { 
				} , function(data) {

					var json;

					try {
						json = JSON.parse(data);
					} catch (e) {
						show_status_message('failed');
						return;
					}


					if (json.status == 0) {
						show_status_message('<a href="/records/' + json.filename + '" target="_blank">' + json.filename + '</a>');
					} else {
						show_status_message('failed');
					}

				});
			}

                        // JV : toggle recording function, most stolen from make_photo;)
                        function toggle_recording() {
                                //window.alert(document.getElementById("record_icon").src.slice(-5));
                                //show_status_message('toggle recording...');
                                $.post("toggle_recording.php", {
                                } , function(data) {

                                        var json;

                                        try {
                                                json = JSON.parse(data);
                                        } catch (e) {
                                                show_status_message('failed');
                                                return;
                                        }

                                        ///page_reload();

                                        if (json.status == 0) {
                                                document.getElementById("record_icon").src = "imgs/record0.png"
                                                show_status_message('<a href="/records/' + json.filename + '" target="_blank">' + json.filename + '</a>');
                                        } else {
                                                document.getElementById("record_icon").src = "imgs/record1.png"
                                        }
                                    })
                        }

			function show_status_message(message) {
				if (message != null) {
					$('#status_message').css('display', 'block');
					$('#status_message').html(message);
				} else {
					$('#status_message').css('display', 'none');
					$('#status_message').html('');
				}
			}

    	</script>



  </body>
</html>
\opt\StereoPi\scripts\loop-record.sh

Code: Select all

#!/bin/sh

RECPATH=/media/DCIM

mkdir -p $RECPATH

#JV create /run/record.png at startup
if [ -f ./config.conf ] ; then
    . ./config.conf

fi
if [ "$record_enabled" = "1" ] ; then
                cp /var/www/html/imgs/record1.png  /run/record.png
else
                cp /var/www/html/imgs/record0.png  /run/record.png
fi


while [ 1 ] ; do
    if [ -f ./config.conf ] ; then
	. ./config.conf
    else
		sleep 1
		continue
    fi

    if [ "$record_enabled" = "1" ] ; then
                #JV manage record button
                cp /var/www/html/imgs/record1.png  /run/record.png
		echo "Recording enabled"
	else
		sleep 1
		continue
    fi

 #JV do signal here
    killall -q -INT recorder
    sleep 2
 #JV save last vid id
    RECFILE="record-`date +%Y%m%d-%H%M%S`.mp4"
    echo -n $RECFILE > /run/RECFILE
    echo "RECFILE = " $RECPATH/`echo -n $RECFILE`

    if [ "$audio_enabled" = "1" ] ; then
		echo "Recording with audio"
		amixer -D hw:1 set "Auto Gain Control" off
		amixer -D hw:1 set "Mic" 100
		#JV filesink location
		#./bin/recorder -e udpsrc port=3003 buffer-size=200000 ! h264parse ! queue ! mux.video_0 alsasrc device=plughw:1,0 ! "audio/x-raw,channels=1,depth=16,width=16,rate=44100" ! voaacenc bitrate=128000 ! aacparse ! queue ! mux.audio_0 qtmux name=mux ! filesink location="$RECPATH/record-`date +%Y%m%d-%H%M%S`.mp4" sync=true
		./bin/recorder -e udpsrc port=3003 buffer-size=200000 ! h264parse ! queue ! mux.video_0 alsasrc device=plughw:1,0 ! "audio/x-raw,channels=1,depth=16,width=16,rate=44100" ! voaacenc bitrate=128000 ! aacparse ! queue ! mux.audio_0 qtmux name=mux ! filesink location="$RECPATH/$RECFILE" sync=true
    else
		echo "Recording without audio"
		#JV filesink location
		#./bin/recorder -e udpsrc port=3003 buffer-size=200000 ! h264parse ! queue ! qtmux ! filesink location="$RECPATH/record-`date +%Y%m%d-%H%M%S`.mp4" sync=true
		./bin/recorder -e udpsrc port=3003 buffer-size=200000 ! h264parse ! queue ! qtmux ! filesink location="$RECPATH/$RECFILE" sync=true
    fi

	echo "Recording stopped"

    sleep 1
done

Jan a.k.a. stereomii
StereoPi with Waveshare 160deg cams

User avatar
Realizator
Site Admin
Posts: 900
Joined: Tue Apr 16, 2019 9:23 am
Contact:

Re: Add a Record button to SLP

Post by Realizator »

Whoa, great tutorial, thank you!
We did not yet add a record button because of the very simple reason: with the current software configuration, we have no real control of a recording process. I.e. we can initiate a record, but if this subprocess is broken, the system does not know it, and still shows you "Recording is in a process". In the updated SLP we will control this at the low level. But, with your previously suggested improvement (to avoid broken video files), your current solution can be very stable!
Eugene a.k.a. Realizator

User avatar
stereomii
Posts: 37
Joined: Mon May 13, 2019 3:11 pm
Location: Apeldoorn, The Netherlands
Contact:

Re: Add a Record button to SLP

Post by stereomii »

Realizator wrote:
Wed Jun 10, 2020 9:29 pm
..., but if this subprocess is broken, the system does not know it, and still shows you "Recording is in a process". ...!
That is the reason why I added a link to the last recorded video after stopping recording.
At least I now have a quick way to check my recording :)
Jan a.k.a. stereomii
StereoPi with Waveshare 160deg cams

User avatar
stereomii
Posts: 37
Joined: Mon May 13, 2019 3:11 pm
Location: Apeldoorn, The Netherlands
Contact:

Re: Add a Record button to SLP

Post by stereomii »

There are still some minor flaws in this solution.

If StereoPi boots up with recording enabled sometimes loop_record does not read the correct date-time. Recording starts, recording status is correctly dispayed (red button) but the record-[date-time].mp4 has an old timestamp, making it difficult to find if you have a lot of recordings.

This wrong date-time could well be present in the original 0.2.3 version. I am not able to quickly check this at this moment.

Note: to change recording enabled in /boot/stereopi.conf you have to use [SAVE] in settings menu. The toggle button does not save state in /boot/stereopi.conf
Jan a.k.a. stereomii
StereoPi with Waveshare 160deg cams

User avatar
zoldaten
Posts: 48
Joined: Fri Apr 26, 2019 7:07 am

Re: Add a Record button to SLP

Post by zoldaten »

Why is so complicated solution ? It`s hard to follow.
Isn`t more easy to stop all raspivid as make_photo.php does and
then just start the same raspivid script with sintax something like this: > file

And where you add button ? To left-slide menu ?

User avatar
Realizator
Site Admin
Posts: 900
Joined: Tue Apr 16, 2019 9:23 am
Contact:

Re: Add a Record button to SLP

Post by Realizator »

Zoldaten, unfortunately Stereomii can't answer our questions anymore...
We already added video and photo recording options to the latest SLP 1 (published now), and will publish a new SLP2 soon (hope this week) for the mass-tests.
Eugene a.k.a. Realizator

Post Reply