Commit 89d1c8fe authored by Andrey Filippov's avatar Andrey Filippov

Merge branch 'master' of github.com:Elphel/elphel-apps-camogm

parents 8177e5eb 8431e010
......@@ -212,6 +212,21 @@ void put_uint64(void *buf, u_int64_t val)
tmp[7] = (val >>= 8) & 0xff;
}
/**
* @brief Detect running compressors and update active channels mask. This function should be
* called right after all driver files are opened.
* @param state pointer to #camogm_state structure containing program state
* @return none
*/
void check_compressors(camogm_state *state)
{
for (int i = 0; i < SENSOR_PORTS; i++) {
if (getGPValue(i, P_COMPRESSOR_RUN) != COMPRESSOR_RUN_STOP) {
state->active_chn |= 1 << i;
}
}
}
/**
* @brief Initialize the state of the program
* @param[in] state pointer to #camogm_state structure containing program state
......@@ -259,7 +274,7 @@ void camogm_init(camogm_state *state, char *pipe_name, uint16_t port_num)
state->rawdev.end_pos = state->rawdev.start_pos;
state->rawdev.curr_pos_w = state->rawdev.start_pos;
state->rawdev.curr_pos_r = state->rawdev.start_pos;
state->active_chn = ALL_CHN_ACTIVE;
state->active_chn = ALL_CHN_INACTIVE;
state->rawdev.mmap_default_size = MMAP_CHUNK_SIZE;
state->sock_port = port_num;
}
......@@ -378,7 +393,6 @@ int camogm_start(camogm_state *state)
memcpy(&(state->frame_params[chn]), (unsigned long* )&ccam_dma_buf[chn][state->metadata_start >> 2], 32);
state->jpeg_len = state->frame_params[chn].frame_length; // frame_params.frame_length are now the length of bitstream
if (state->frame_params[chn].signffff != 0xffff) {
D0(fprintf(debug_file, "%s:%d: wrong signature - %d\r\n", __FILE__, __LINE__, (int)state->frame_params[chn].signffff));
state->cirbuf_rp[chn] = -1;
......@@ -928,7 +942,7 @@ void camogm_set_start_after_timestamp(camogm_state *state, double d)
*/
void camogm_status(camogm_state *state, char * fn, int xml)
{
int _len = 0;
int64_t _len = 0;
int _dur = 0, _udur = 0, _dur_raw, _udur_raw;
FILE* f;
char *_state, *_output_format, *_using_exif, *_using_global_pointer, *_compressor_state[SENSOR_PORTS];
......@@ -985,8 +999,10 @@ void camogm_status(camogm_state *state, char * fn, int xml)
return;
}
}
if (state->vf) _len = ftell(state->vf); // for ogm
else if ((state->ivf) >= 0) _len = lseek(state->ivf, 0, SEEK_CUR); //for mov
if (state->rawdev_op)
_len = state->rawdev.total_rec_len;
else if (state->vf) _len = (int64_t)ftell(state->vf); // for ogm
else if ((state->ivf) >= 0) _len = (int64_t)lseek(state->ivf, 0, SEEK_CUR); //for mov
switch (state->prog_state) {
case STATE_STOPPED:
_state = "stopped";
......@@ -1022,7 +1038,7 @@ void camogm_status(camogm_state *state, char * fn, int xml)
" <frame_number>%d</frame_number>\n" \
" <start_after_timestamp>%f</start_after_timestamp>\n" \
" <file_duration>%d.%06d</file_duration>\n" \
" <file_length>%d</file_length>\n" \
" <file_length>%" PRId64 "</file_length>\n" \
" <frames_skip_left>%d</frames_skip_left>\n" \
" <seconds_skip_left>%d</seconds_skip_left>\n" \
" <frame_width>%d</frame_width>\n" \
......@@ -1104,7 +1120,7 @@ void camogm_status(camogm_state *state, char * fn, int xml)
fprintf(f, "frame \t%d\n", state->frameno);
fprintf(f, "start_after_timestamp \t%f\n", state->start_after_timestamp);
fprintf(f, "file duration \t%d.%06d sec\n", _dur, _udur);
fprintf(f, "file length \t%d B\n", _len);
fprintf(f, "file length \t%" PRId64 " B\n", _len);
fprintf(f, "width \t%d (0x%x)\n", state->width, state->width);
fprintf(f, "height \t%d (0x%x)\n", state->height, state->height);
fprintf(f, "\n");
......@@ -1902,6 +1918,7 @@ int main(int argc, char *argv[])
ret = open_files(&sstate);
if (ret < 0)
return ret;
check_compressors(&sstate);
if (pthread_create(&sstate.rawdev.tid, NULL, reader, &sstate) != 0 ||
pthread_detach(sstate.rawdev.tid) != 0) {
D0(fprintf(debug_file, "%s:line %d: Can not start reading thread in detached state\n", __FILE__, __LINE__));
......@@ -1955,7 +1972,7 @@ int waitDaemonEnabled(unsigned int port, int daemonBit) // <0 - use default
unsigned long this_frame = GLOBALPARS(port, G_THIS_FRAME);
// No semaphors, so it is possible to miss event and wait until the streamer will be re-enabled before sending message,
// but it seems not so terrible
lseek(state->fd_circ[state->port_num], LSEEK_DAEMON_CIRCBUF + lastDaemonBit[port], SEEK_END);
lseek(state->fd_circ[port], LSEEK_DAEMON_CIRCBUF + lastDaemonBit[port], SEEK_END);
if (this_frame == GLOBALPARS(port, G_THIS_FRAME)) return 1;
return 0;
}
......
......@@ -123,6 +123,7 @@ typedef struct {
uint64_t mmap_current_size;
uint64_t mmap_offset;
uint64_t file_start;
int64_t total_rec_len;
pthread_t tid;
volatile int thread_state;
unsigned char *disk_mmap;
......
......@@ -41,6 +41,18 @@ void camogm_free_jpeg(void)
{
}
/** Calculate the total length of current frame */
int64_t camogm_get_jpeg_size(camogm_state *state)
{
int64_t len = 0;
for (int i = 0; i < state->chunk_index - 1; i++) {
len += state->packetchunks[i + 1].bytes;
}
return len;
}
/**
* @brief Called every time the JPEG files recording is started.
*
......@@ -135,6 +147,8 @@ int camogm_frame_jpeg(camogm_state *state)
D0(fprintf(debug_file, "Can not pass IO vector to driver: %s\n", strerror(errno)));
return -CAMOGM_FRAME_FILE_ERR;
}
// update statistics
state->rawdev.total_rec_len += camogm_get_jpeg_size(state);
}
return 0;
......
......@@ -349,6 +349,8 @@ else
case "listdevices":
exec ("cat /proc/partitions", $arr1);
exec ("cat /proc/mounts", $arr2);
$ret = get_mnt_dev();
$mnt_dev = $ret["devices"];
$j = 0;
// first two lines are header and empty line separator, skip them
$i = 2;
......@@ -372,35 +374,50 @@ else
}
$j = 0;
foreach ($partitions as $partition) {
echo "<item>";
echo "<partition>/dev/".$partition."</partition>";
echo "<size>".round($size[$j]/1024/1024, 2) ." GB</size>";
$j++;
$i = 0;
while($i < count($arr2)) {
if(strpos($arr2[$i], $partition))
{
$parts = explode(" ", $arr2[$i]);
$mountpoint = $parts[1];
$filesystem = $parts[2];
}
$i++;
}
if ($mountpoint != "") {
echo "<mountpoint>".$mountpoint."</mountpoint>";
$mountpoint = "";
} else {
echo "<mountpoint>none</mountpoint>";
$include = false;
foreach ($mnt_dev as $dev) {
if (strpos($dev, $partition))
$include = true;
}
if ($filesystem != "") {
echo "<filesystem>".$filesystem."</filesystem>";
$filesystem = "";
} else {
echo "<filesystem>none</filesystem>";
if ($include) {
echo "<item>";
echo "<partition>/dev/".$partition."</partition>";
echo "<size>".round($size[$j]/1024/1024, 2) ." GB</size>";
$j++;
$i = 0;
while($i < count($arr2)) {
if(strpos($arr2[$i], $partition))
{
$parts = explode(" ", $arr2[$i]);
$mountpoint = $parts[1];
$filesystem = $parts[2];
}
$i++;
}
if ($mountpoint != "") {
echo "<mountpoint>".$mountpoint."</mountpoint>";
$mountpoint = "";
} else {
echo "<mountpoint>none</mountpoint>";
}
if ($filesystem != "") {
echo "<filesystem>".$filesystem."</filesystem>";
$filesystem = "";
} else {
echo "<filesystem>none</filesystem>";
}
echo "</item>";
}
}
break;
case "list_raw_devices":
$devices = get_raw_dev();
foreach ($devices as $device => $size) {
echo "<item>";
echo "<raw_device>" . $device . "</raw_device>";
echo "<size>" . round($size / 1048576, 2) . "</size>";
echo "</item>";
}
break;
case "mkdir":
$dir_name = $_GET['name'];
......@@ -601,6 +618,63 @@ function xml_footer() {
echo "</camogm_interface>\n";
}
/** Get a list of disk devices which have file system and can be mounted. This function
* uses 'blkid' command from busybox.
*/
function get_mnt_dev()
{
exec("blkid", $ids);
$i = 0;
foreach ($ids as $id) {
$devices[$i] = preg_replace('/: +.*/', "", $id);
if (preg_match('/(?<=TYPE=")[a-z0-9]+(?=")/', $id, $fs) == 1)
$fs_types[$i] = $fs[0];
else
$fs_types[$i] = "none";
$i++;
}
return array("devices" => $devices, "types" => $fs_types);
}
/** Get a list of devices whithout file system which can be used for raw disk storage from camogm. */
function get_raw_dev()
{
$j = 0;
$regexp = '/([0-9]+) +(sd[a-z0-9]+$)/';
$names = array();
$ret = get_mnt_dev();
$devices = $ret["devices"];
$types = $ret["types"];
exec("cat /proc/partitions", $partitions);
// get a list of all suitable partitions
// the first two elements of an array are table header and empty line delimiter, skip them
for ($i = 2; $i < count($partitions); $i++) {
// select SATA devices only
if (preg_match($regexp, $partitions[$i], $name) == 1) {
$names[$name[2]] = $name[1];
$j++;
}
}
// filter out partitions with file system
$i = 0;
$raw_devices = array();
foreach ($names as $name => $size) {
$found = false;
foreach ($devices as $device) {
if (strpos($device, $name) !== false)
$found = true;
}
if ($found === false) {
// current partition is not found in the blkid list, add it to raw devices
$raw_devices["/dev/" . $name] = $size;
$i++;
}
}
return $raw_devices;
}
?>
......@@ -256,4 +256,8 @@ table.state_table td {
#live_image_auto_update {
margin: 0px;
padding: 0px;
}
.radio_class {
margin-top: 1px;
}
\ No newline at end of file
// store path to partition that camogm is currently using
var rawdev_path = "";
// shows if partition selection should be updated
var update_dev_radio = false;
function timer_functions(){
list_files(getCookie("current_dir"));
update_state();
......@@ -17,13 +22,17 @@ function init() {
//setTimeout('update_audio_form(document.getElementById("audioform"))', 1500);
//setTimeout('calc_split_size()', 2300);
//setTimeout('scan_devices()', 3000);
update_name_scheme();
check_audio_hardware();
update_audio_form(document.getElementById("audioform"));
calc_split_size();
//calling "is_mounted" at response
scan_devices("is_mounted(selected_device)");
//global_timer = setInterval(timer_functions,2000);
update_name_scheme();
check_audio_hardware();
update_audio_form(document.getElementById("audioform"));
calc_split_size();
//calling "is_mounted" at response
//global_timer = setInterval(timer_functions,2000);
if (document.getElementById('fast_rec').checked) {
makeRequest('camogm_interface.php', '?cmd=list_raw_devices');
} else {
scan_devices("is_mounted(selected_device)");
}
}
function reload() {
makeRequest('camogm_interface.php', '?cmd=run_camogm');
......@@ -104,7 +113,9 @@ function process_is_hdd_mounted(xmldoc) {
//scan_devices() - fills the device list.
function scan_devices(callback) {
makeRequest('camogm_interface.php','?cmd=listdevices',callback);
if (document.getElementById('fast_rec').checked == false) {
makeRequest('camogm_interface.php','?cmd=listdevices',callback);
}
}
var devices = Array();
......@@ -384,6 +395,8 @@ function process_request(xmldoc) {
case "listdevices":
process_scan_devices(xmldoc);
break;
case "list_raw_devices":
process_raw_dev_list(xmldoc);
default:
break;
}
......@@ -423,6 +436,18 @@ function process_recording(xmldoc) {
if (xmldoc.getElementsByTagName('buffer_overruns')[0].firstChild.data > 0)
alert ("Buffer overrun! current datarate exceeds max. write rate")
// update partition selection
if (update_dev_radio) {
var radios = document.getElementsByName('rawdev_path');
rawdev_path = xmldoc.getElementsByTagName('raw_device_path')[0].firstChild.data;
for (var i = 0; i < radios.length; i++) {
if (rawdev_path == '"' + radios[i].value + '"') {
radios[i].checked = true;
}
}
update_dev_radio = false;
}
}
recording = false;
function update_state() {
......@@ -535,7 +560,9 @@ function help(caller) {
case 'debug':
alert("The higher the debug-level the more information is written to the debug file (it may slow down camogm and cause it to drop frames even if it could handle it with no/lower debug-level output).")
break;
case 'fast_rec':
alert("Enable or disable fast recoding feature. The disk drive should have at least one partition without file system or" +
"any data on it to enable this feature.");
}
}
function format_changed(parent) {
......@@ -747,13 +774,73 @@ function toggle_buffer() {
}
}
// enable fast recording through disk driver
function fast_rec_changed(parent)
/** Enable or disable page controls in accordance to new state which cat be one of 'fast_rec' or 'standart_rec' */
function set_controls_state(new_state)
{
if (parent.checked) {
var radios = document.getElementsByName('container');
if (new_state == 'fast_rec') {
radios_disable = true;
document.getElementById('radioJpg').checked = true;
document.getElementById('directory').disabled = true;
} else {
radios_disable = false;
document.getElementById('directory').disabled = false;
if (document.getElementById('submit_button').disabled == true)
document.getElementById('submit_button').disabled = false;
}
for (var i = 0; i < radios.length; i++) {
radios[i].disabled = radios_disable;
}
}
/** Enable fast recording through disk driver */
function fast_rec_changed(parent)
{
if (parent.checked) {
makeRequest('camogm_interface.php', '?cmd=list_raw_devices');
} else {
scan_devices("is_mounted(selected_device)");
set_controls_state('standart_rec');
}
}
/** Show raw devices table and change the state of controls */
function process_raw_dev_list(xmldoc)
{
var content = "";
var items = xmldoc.getElementsByTagName('item');
content += "";
if (items.length > 0) {
set_controls_state('fast_rec');
content += "<table cellpadding='5' cellspacing='0' cellmargin='0'>";
content += "<tr><td></td><td><b>Partition</b></td><td><b></b></td><td><b>Size</b></td><td><b></b></td><td></td></tr>";
for (var i = 0; i < items.length; i++) {
var partition = items[i].childNodes[0];
var size = items[i].childNodes[1];
content += "<tr><td><input type=\"radio\" id=\"radio_dev_" + i + "\" class=\"radio_class\" name=\"rawdev_path\" value=\"" +
partition.firstChild.nodeValue + "\" ";
if (i == 0) {
content += "checked ";
}
content += "/></td>" +
"<td>" + partition.firstChild.nodeValue + "</td>" +
"<td></td><td>" + size.firstChild.nodeValue + " GB" + "</td>" +
"<td></td><td></td></tr>";
}
content += "</table>";
} else {
content += "<p class=\"alert\">Device partitions without file system are not found. Fast recording can not be started. " +
"Create a partition without file system on it and try again.</p>";
document.getElementById('submit_button').disabled = true;
}
document.getElementById('ajax_devices').innerHTML = content;
// get current partition if we have more than one available and update selection
if (items.length > 1) {
update_dev_radio = true;
makeRequest('camogm_interface.php', '?cmd=status');
}
}
......@@ -117,28 +117,38 @@
// format tab submit
if (isset($_POST['settings_format'])){
switch($_POST['container']){
case'ogm':
$container = $_POST['container'];
break;
case'jpg':
$container = $_POST['container'];
break;
case'mov':
$container = $_POST['container'];
break;
default:
$container = "mov";
break;
if (!isset($_POST['fastrec_checkbox'])) {
switch($_POST['container']){
case'ogm':
$container = $_POST['container'];
break;
case'jpg':
$container = $_POST['container'];
break;
case'mov':
$container = $_POST['container'];
break;
default:
$container = "mov";
break;
}
$rawdev_path = "";
$prefix = $_POST['prefix'];
} else {
// fast recording supports jpeg format only
$container = "jpeg";
$rawdev_path = $_POST['rawdev_path'];
$prefix = "";
}
if ($camogm_running) {
// set format
fprintf($fcmd, "format=%s;\n", $container);
// set record directory
$prefix = $_POST['prefix'];
fprintf($fcmd, "prefix=%s;\n", $prefix);
setcookie("directory", $prefix); // save as cookie so we can get prefered record directory even after camera reboot
if ($prefix != "") {
fprintf($fcmd, "prefix=%s;\n", $prefix);
setcookie("directory", $prefix); // save as cookie so we can get prefered record directory even after camera reboot
}
//set debug file
$debug = $_POST['debug'];
......@@ -150,6 +160,11 @@
}
else
fprintf($fcmd, "debug;\ndebuglev=1;\n");
if ($rawdev_path != "")
fprintf($fcmd, "rawdev_path=%s;\n", $rawdev_path);
else
fprintf($fcmd, "rawdev_path;\n");
}
}
......@@ -573,7 +588,7 @@
else
echo "<input type=\"radio\" id=\"radioJpg\" style=\"top:3px; position:relative;\" name=\"container\" value=\"jpg\" onChange=\"format_changed(this);\"> JPEG Sequence<br />";
?>
<input id="fast_rec" type="checkbox" style="left:1px; top:3px; position:relative;" name="" value="" onChange="fast_rec_changed(this)"> Use fast recording
<input id="fast_rec" type="checkbox" style="left:1px; top:3px; position:relative;" name="fastrec_checkbox" value="checked" onChange="fast_rec_changed(this)" checked="checked"> Use fast recording
<a href="#" onClick="help('fast_rec');"><img src="images/help.png"></a><br />
<br />
......@@ -594,7 +609,7 @@
</select>
<a href="#" onClick="help('debug');"><img src="images/help.png"></a><br />
<br />
<input name="settings_format" type="submit" value="OK">
<input id="submit_button" name="settings_format" type="submit" value="OK">
</form>
</div>
<div class="TabbedPanelsContent">
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment