Commit 13e75796 authored by Mikhail Karpenko's avatar Mikhail Karpenko

Write markers in the start and end of each file

parent 173e7331
...@@ -113,6 +113,7 @@ ...@@ -113,6 +113,7 @@
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <linux/limits.h> #include <linux/limits.h>
#include <linux/fs.h>
//#include <ctype.h> //#include <ctype.h>
//#include <getopt.h> //#include <getopt.h>
#include <time.h> #include <time.h>
...@@ -230,6 +231,7 @@ void camogm_set_start_after_timestamp(camogm_state *state, double d); ...@@ -230,6 +231,7 @@ void camogm_set_start_after_timestamp(camogm_state *state, double d);
void camogm_set_max_frames(camogm_state *state, int d); void camogm_set_max_frames(camogm_state *state, int d);
void camogm_set_frames_per_chunk(camogm_state *state, int d); void camogm_set_frames_per_chunk(camogm_state *state, int d);
uint64_t get_disk_size(const char *name);
//!====================================================================================================== //!======================================================================================================
void put_uint16(void *buf, u_int16_t val) void put_uint16(void *buf, u_int16_t val)
...@@ -323,6 +325,11 @@ void camogm_init(camogm_state *state, unsigned int port, char *pipe_name) ...@@ -323,6 +325,11 @@ void camogm_init(camogm_state *state, unsigned int port, char *pipe_name)
state->port_num = port; state->port_num = port;
state->pipe_name = pipe_name; state->pipe_name = pipe_name;
state->rawdev.start_pos = RAWDEV_START_OFFSET;
state->rawdev.end_pos = state->rawdev.start_pos;
state->rawdev.curr_pos = state->rawdev.start_pos;
state->rawdev.overrun = 0;
state->rawdev_op = 0;
} }
...@@ -732,7 +739,7 @@ int camogm_stop(camogm_state *state) ...@@ -732,7 +739,7 @@ int camogm_stop(camogm_state *state)
switch (state->format) { switch (state->format) {
case CAMOGM_FORMAT_NONE: rslt = 0; break; case CAMOGM_FORMAT_NONE: rslt = 0; break;
case CAMOGM_FORMAT_OGM: rslt = camogm_end_ogm(state); break; case CAMOGM_FORMAT_OGM: rslt = camogm_end_ogm(state); break;
case CAMOGM_FORMAT_JPEG: rslt = camogm_end_jpeg(); break; case CAMOGM_FORMAT_JPEG: rslt = camogm_end_jpeg(state); break;
case CAMOGM_FORMAT_MOV: rslt = camogm_end_mov(state); break; case CAMOGM_FORMAT_MOV: rslt = camogm_end_mov(state); break;
/// default: return 0; // do nothing /// default: return 0; // do nothing
} }
...@@ -838,6 +845,23 @@ void camogm_set_prefix(camogm_state *state, const char * p) ...@@ -838,6 +845,23 @@ void camogm_set_prefix(camogm_state *state, const char * p)
{ {
strncpy(state->path_prefix, p, sizeof(state->path_prefix) - 1); strncpy(state->path_prefix, p, sizeof(state->path_prefix) - 1);
state->path_prefix[sizeof(state->path_prefix) - 1] = '\0'; state->path_prefix[sizeof(state->path_prefix) - 1] = '\0';
// check if we are going to write to raw device
if (strncmp("/dev/", state->path_prefix, 5) == 0) {
state->rawdev.end_pos = get_disk_size(state->path_prefix);
if (state->rawdev.end_pos == 0) {
state->rawdev_op = 0;
state->rawdev.end_pos = state->rawdev.start_pos;
state->path_prefix[0] = '\0';
printf("ERROR: unable to initiate raw device operation\n");
} else {
printf("WARNING: raw device write initiated\n");
state->rawdev_op = 1;
/* debug code follows */
state->rawdev.end_pos = state->rawdev.start_pos + 10485760; // 10Mib size
}
} else {
state->rawdev_op = 0;
}
} }
void camogm_set_timescale(camogm_state *state, double d) //! set timescale, default=1,000,000 void camogm_set_timescale(camogm_state *state, double d) //! set timescale, default=1,000,000
...@@ -1511,6 +1535,31 @@ int listener_loop(camogm_state *state) ...@@ -1511,6 +1535,31 @@ int listener_loop(camogm_state *state)
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
/**
* @brief Return disk size in bytes
*
* This function reads disk size using ioctl call.
* @param name pointer to disk name string
* @return disk size in bytes if it was read correctly and 0 otherwise
*/
uint64_t get_disk_size(const char *name)
{
int fd;
uint64_t dev_sz;
if ((fd = open(name, O_RDONLY)) < 0) {
perror(__func__);
return 0;
}
if (ioctl(fd, BLKGETSIZE64, &dev_sz) < 0) {
perror(__func__);
return 0;
}
close(fd);
return dev_sz;
}
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
const char usage[] = "This program allows recording of the video/images acquired by Elphel camera to the storage media.\n" \ const char usage[] = "This program allows recording of the video/images acquired by Elphel camera to the storage media.\n" \
......
...@@ -72,6 +72,18 @@ ...@@ -72,6 +72,18 @@
#define Exif_GPSInfo_CompassRoll_Index 0x10 #define Exif_GPSInfo_CompassRoll_Index 0x10
#define ExifKmlNumber 0x11 #define ExifKmlNumber 0x11
*/ */
/** @brief Offset from the beginning of raw device buffer. Must be aligned to physical sector size */
#define RAWDEV_START_OFFSET 1024
typedef struct {
int rawdev_fd;
uint64_t start_pos;
uint64_t end_pos;
uint64_t curr_pos;
uint32_t overrun;
} rawdev_buffer;
typedef struct { typedef struct {
int segment_duration; int segment_duration;
int segment_length; int segment_length;
...@@ -158,8 +170,10 @@ typedef struct { ...@@ -158,8 +170,10 @@ typedef struct {
int kml_last_uts; //! last generated kml file timestamp, microseconds int kml_last_uts; //! last generated kml file timestamp, microseconds
struct exif_dir_table_t kml_exif[ExifKmlNumber]; //! store locations of the fields needed for KML generations in the Exif block struct exif_dir_table_t kml_exif[ExifKmlNumber]; //! store locations of the fields needed for KML generations in the Exif block
unsigned int port_num; // sensor port this state assigned to unsigned int port_num; // sensor port this state is assigned to
char *pipe_name; // command pipe name for this sensor port char *pipe_name; // command pipe name for this sensor port
int rawdev_op; // flag indicating writing to raw device
rawdev_buffer rawdev; // contains pointers to raw device buffer
} camogm_state; } camogm_state;
extern int debug_level; extern int debug_level;
......
...@@ -34,35 +34,54 @@ ...@@ -34,35 +34,54 @@
*! Initial release of camogm - program to record video/image to the camera hard drive (or other storage) *! Initial release of camogm - program to record video/image to the camera hard drive (or other storage)
*! *!
*/ */
#define LARGEFILES64_SOURCE
//!Not all are needed, just copied from the camogm.c //!Not all are needed, just copied from the camogm.c
#include <unistd.h> #include <unistd.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <signal.h> //#include <signal.h>
#include <fcntl.h> #include <fcntl.h>
#include <sys/uio.h> #include <sys/uio.h>
#include <errno.h> #include <errno.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/socket.h> //#include <sys/socket.h>
#include <sys/stat.h> //#include <sys/stat.h>
//#include <ctype.h> //#include <ctype.h>
//#include <getopt.h> //#include <getopt.h>
#include <time.h> //#include <time.h>
#include <string.h> #include <string.h>
#include <netinet/in.h> /*little <-> big endian ?*/ #include <netinet/in.h> /*little <-> big endian ?*/
#include <sys/mman.h> /* mmap */ //#include <sys/mman.h> /* mmap */
#include <sys/ioctl.h> //#include <sys/ioctl.h>
#include <c313a.h> #include <c313a.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
#include <assert.h>
#include <ogg/ogg.h> // has to be before ogmstreams.h #include <ogg/ogg.h> // has to be before ogmstreams.h
#include "ogmstreams.h" // move it to <>? #include "ogmstreams.h" // move it to <>?
#include "camogm_jpeg.h" #include "camogm_jpeg.h"
/** @brief Size of iovec structures holding data to be written */
#define IOVEC_SIZE 10
/** @brief Start of file marker, contains "elphelst" string in ASCII symbols */
const unsigned char elphelst[] = {0x65, 0x6c, 0x70, 0x68, 0x65, 0x6c, 0x73, 0x74};
/** @brief End of file marker, contains "elphelen" string in ASCII symbols */
const unsigned char elphelen[] = {0x65, 0x6c, 0x70, 0x68, 0x65, 0x6c, 0x65, 0x6e};
static struct iovec start_marker = {
.iov_base = elphelst,
.iov_len = sizeof(elphelst)
};
static struct iovec end_marker = {
.iov_base = elphelen,
.iov_len = sizeof(elphelen)
};
//! may add something - called first time format is changed to this one (only once) recording is stopped //! may add something - called first time format is changed to this one (only once) recording is stopped
int camogm_init_jpeg(void) int camogm_init_jpeg(void)
{ {
...@@ -78,58 +97,133 @@ int camogm_start_jpeg(camogm_state *state) ...@@ -78,58 +97,133 @@ int camogm_start_jpeg(camogm_state *state)
char * slash; char * slash;
int rslt; int rslt;
strcpy(state->path, state->path_prefix); //!make state->path a directory name (will be replaced when the frames will be written) if (!state->rawdev_op) {
slash = strrchr(state->path, '/'); strcpy(state->path, state->path_prefix); //!make state->path a directory name (will be replaced when the frames will be written)
D2(fprintf(debug_file, "camogm_start_jpeg\n")); slash = strrchr(state->path, '/');
if (slash) { D2(fprintf(debug_file, "camogm_start_jpeg\n"));
D3(fprintf(debug_file, "Full path %s\n", state->path)); if (slash) {
slash[0] = '\0'; //! truncate path to the directory name D3(fprintf(debug_file, "Full path %s\n", state->path));
D3(fprintf(debug_file, "directory path %s\n", state->path)); slash[0] = '\0'; //! truncate path to the directory name
rslt = mkdir(state->path, 0777); D3(fprintf(debug_file, "directory path %s\n", state->path));
D3(fprintf(debug_file, "mkdir (%s, 0777) returned %d, errno=%d\n", state->path, rslt, errno)); rslt = mkdir(state->path, 0777);
if ((rslt < 0) && (errno != EEXIST)) { // already exists is OK D3(fprintf(debug_file, "mkdir (%s, 0777) returned %d, errno=%d\n", state->path, rslt, errno));
D0(fprintf(debug_file, "Error creating directory %s, errno=%d\n", state->path, errno)); if ((rslt < 0) && (errno != EEXIST)) { // already exists is OK
D0(fprintf(debug_file, "Error creating directory %s, errno=%d\n", state->path, errno));
return -CAMOGM_FRAME_FILE_ERR;
}
}
} else {
state->ivf = open(state->path_prefix, O_RDWR);
if (state->ivf < 0) {
D0(perror(__func__));
D0(fprintf(debug_file, "Error opening raw device %s\n", state->path));
return -CAMOGM_FRAME_FILE_ERR; return -CAMOGM_FRAME_FILE_ERR;
} }
D0(fprintf(debug_file, "Open raw device %s; start_pos = %llu, end_pos = %llu, curr_pos = %llu\n", state->path,
state->rawdev.start_pos, state->rawdev.end_pos, state->rawdev.curr_pos));
lseek64(state->ivf, state->rawdev.curr_pos, SEEK_SET);
} }
return 0; return 0;
} }
int camogm_frame_jpeg(camogm_state *state) int camogm_frame_jpeg(camogm_state *state)
{ {
int i, j; int i, j, split_index;
// int fd; int chunks_used = state->chunk_index - 1;
ssize_t iovlen, l; ssize_t iovlen, l;
struct iovec chunks_iovec[7]; struct iovec chunks_iovec[8];
unsigned char *split_ptr = NULL;
long split_cntr;
long total_len;
const uint64_t storage_sz = state->rawdev.end_pos - state->rawdev.start_pos;
l = 0; if (!state->rawdev_op) {
for (i = 0; i < (state->chunk_index) - 1; i++) { l = 0;
chunks_iovec[i].iov_base = state->packetchunks[i + 1].chunk; for (i = 0; i < (state->chunk_index) - 1; i++) {
chunks_iovec[i].iov_len = state->packetchunks[i + 1].bytes; chunks_iovec[i].iov_base = state->packetchunks[i + 1].chunk;
l += chunks_iovec[i].iov_len; chunks_iovec[i].iov_len = state->packetchunks[i + 1].bytes;
} l += chunks_iovec[i].iov_len;
}
sprintf(state->path, "%s%010ld_%06ld.jpeg", state->path_prefix, state->this_frame_params.timestamp_sec, state->this_frame_params.timestamp_usec);
if (((state->ivf = open(state->path, O_RDWR | O_CREAT, 0777))) < 0) {
D0(fprintf(debug_file, "Error opening %s for writing, returned %d, errno=%d\n", state->path, state->ivf, errno));
return -CAMOGM_FRAME_FILE_ERR;
}
iovlen = writev(state->ivf, chunks_iovec, (state->chunk_index) - 1);
if (iovlen < l) {
j = errno;
D0(fprintf(debug_file, "writev error %d (returned %d, expected %d)\n", j, iovlen, l));
close(state->ivf);
return -CAMOGM_FRAME_FILE_ERR;
}
close(state->ivf);
} else {
D0(fprintf(debug_file, "\n%s: current pointers start_pos = %llu, end_pos = %llu, curr_pos = %llu, data in buffer %d\n", __func__,
state->rawdev.start_pos, state->rawdev.end_pos, state->rawdev.curr_pos, l));
l = 0;
split_index = -1;
for (int i = 0, total_len = 0; i < state->chunk_index - 1; i++) {
total_len += state->packetchunks[i + 1].bytes;
if (total_len + state->rawdev.curr_pos > state->rawdev.end_pos) {
split_index = i;
chunks_used++;
D0(fprintf(debug_file, "\n>>> raw storage roll over detected\n"));
break;
}
}
chunks_iovec[0] = start_marker;
for (int i = 1; i < chunks_used; i++) {
if (i == split_index) {
// one of the chunks rolls over the end of the raw storage, split it into two segments and
// use additional chunk in chunks_iovec for this additional segment
split_cntr = state->rawdev.end_pos - (l + state->rawdev.curr_pos);
split_ptr = state->packetchunks[i].chunk + split_cntr;
sprintf(state->path, "%s%010ld_%06ld.jpeg", state->path_prefix, state->this_frame_params.timestamp_sec, state->this_frame_params.timestamp_usec); // be careful with indexes here
// if ((devfd = open("/dev/fpgaio", O_RDWR))<0) {printf("error opening /dev/fpgaio\r\n"); return -1;} chunks_iovec[i].iov_base = state->packetchunks[i].chunk;
//_1__12_Error opening /tmp/z/video1195147018_273452.jpeg for writing chunks_iovec[i].iov_len = split_cntr;
l += chunks_iovec[i].iov_len;
chunks_iovec[++i].iov_base = split_ptr + 1;
chunks_iovec[i].iov_len = state->packetchunks[i].bytes - split_cntr;
l += chunks_iovec[i].iov_len;
} else {
chunks_iovec[i].iov_base = state->packetchunks[i].chunk;
chunks_iovec[i].iov_len = state->packetchunks[i].bytes;
l += chunks_iovec[i].iov_len;
}
}
assert(chunks_used < IOVEC_SIZE);
// consider start_marker here and increment chunks_used
chunks_iovec[chunks_used++] = end_marker;
if (((state->ivf = open(state->path, O_RDWR | O_CREAT, 0777))) < 0) { /* debug code follows */
D0(fprintf(debug_file, "Error opening %s for writing, returned %d, errno=%d\n", state->path, state->ivf, errno)); fprintf(debug_file, "\n=== raw device write, iovec dump ===\n");
return -CAMOGM_FRAME_FILE_ERR; fprintf(debug_file, "split_cntr = %ld; split_ptr = %p; split_index = %d\n", split_cntr, split_ptr, split_index);
} for (int i = 0; i < chunks_used; i++) {
fprintf(debug_file, "i = %d; iov_base = %p; iov_len = %u\n", i, chunks_iovec[i].iov_base, chunks_iovec[i].iov_len);
}
fprintf(debug_file, "total len = %d\n======\n", l);
/* end of debug code */
iovlen = writev(state->ivf, chunks_iovec, (state->chunk_index) - 1); iovlen = writev(state->ivf, chunks_iovec, chunks_used);
if (iovlen < l) { if (iovlen < l) {
j = errno; j = errno;
D0(fprintf(debug_file, "writev error %d (returned %d, expected %d)\n", j, iovlen, l)); D0(fprintf(debug_file, "writev error %d (returned %d, expected %d)\n", j, iovlen, l));
close(state->ivf); return -CAMOGM_FRAME_FILE_ERR;
return -CAMOGM_FRAME_FILE_ERR; }
state->rawdev.curr_pos += l;
if (state->rawdev.curr_pos > state->rawdev.end_pos)
state->rawdev.curr_pos = state->rawdev.curr_pos - state->rawdev.end_pos + state->rawdev.start_pos;
D0(fprintf(debug_file, "%d bytes written, curr_pos = %llu\n", l, state->rawdev.curr_pos));
} }
close(state->ivf);
return 0; return 0;
} }
int camogm_end_jpeg(void) int camogm_end_jpeg(camogm_state *state)
{ {
close(state->ivf);
D0(fprintf(debug_file, "Closing raw device %s\n", state->path_prefix));
return 0; return 0;
} }
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
int camogm_init_jpeg(void); int camogm_init_jpeg(void);
int camogm_start_jpeg(camogm_state *state); int camogm_start_jpeg(camogm_state *state);
int camogm_frame_jpeg(camogm_state *state); int camogm_frame_jpeg(camogm_state *state);
int camogm_end_jpeg(void); int camogm_end_jpeg(camogm_state *state);
void camogm_free_jpeg(void); void camogm_free_jpeg(void);
#endif /* _CAMOGM_JPEG_H */ #endif /* _CAMOGM_JPEG_H */
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