Page 1 of 1

Add a Record button to SLP

Posted: Wed Jun 10, 2020 8:09 pm
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


Re: Add a Record button to SLP

Posted: Wed Jun 10, 2020 9:29 pm
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!

Re: Add a Record button to SLP

Posted: Wed Jun 10, 2020 9:56 pm
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 :)

Re: Add a Record button to SLP

Posted: Fri Jun 12, 2020 4:13 pm
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