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

Write markers in the start and end of each file

parent 173e7331
Loading
Loading
Loading
Loading
+50 −1
Original line number Diff line number Diff line
@@ -113,6 +113,7 @@
#include <sys/socket.h>
#include <sys/stat.h>
#include <linux/limits.h>
#include <linux/fs.h>
//#include <ctype.h>
//#include <getopt.h>
#include <time.h>
@@ -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_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)
@@ -323,6 +325,11 @@ void camogm_init(camogm_state *state, unsigned int port, char *pipe_name)

	state->port_num = port;
	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)
	switch (state->format) {
	case CAMOGM_FORMAT_NONE: rslt = 0; 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;
///    default: return 0; // do nothing
	}
@@ -838,6 +845,23 @@ void camogm_set_prefix(camogm_state *state, const char * p)
{
	strncpy(state->path_prefix, p, sizeof(state->path_prefix) - 1);
	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
@@ -1511,6 +1535,31 @@ int listener_loop(camogm_state *state)
	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[])
{
	const char usage[] =   "This program allows recording of the video/images acquired by Elphel camera to the storage media.\n" \
+15 −1
Original line number Diff line number Diff line
@@ -72,6 +72,18 @@
   #define  Exif_GPSInfo_CompassRoll_Index         0x10
   #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 {
	int segment_duration;
	int segment_length;
@@ -158,8 +170,10 @@ typedef struct {
	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

	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
	int rawdev_op;                                          // flag indicating writing to raw device
	rawdev_buffer rawdev;                            // contains pointers to raw device buffer
} camogm_state;

extern int debug_level;
+136 −42
Original line number Diff line number Diff line
@@ -34,35 +34,54 @@
   *!  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
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
//#include <signal.h>
#include <fcntl.h>
#include <sys/uio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
//#include <sys/socket.h>
//#include <sys/stat.h>
//#include <ctype.h>
//#include <getopt.h>
#include <time.h>
//#include <time.h>
#include <string.h>

#include <netinet/in.h> /*little <-> big endian ?*/
#include <sys/mman.h>   /* mmap */
#include <sys/ioctl.h>
//#include <sys/mman.h>   /* mmap */
//#include <sys/ioctl.h>

#include <c313a.h>
#include <asm/byteorder.h>

#include <assert.h>

#include <ogg/ogg.h>    // has to be before ogmstreams.h
#include "ogmstreams.h" // move it to <>?

#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
int camogm_init_jpeg(void)
{
@@ -78,6 +97,7 @@ int camogm_start_jpeg(camogm_state *state)
	char * slash;
	int rslt;

	if (!state->rawdev_op) {
		strcpy(state->path, state->path_prefix); //!make state->path a directory name (will be replaced when the frames will be written)
		slash = strrchr(state->path, '/');
		D2(fprintf(debug_file, "camogm_start_jpeg\n"));
@@ -92,16 +112,32 @@ int camogm_start_jpeg(camogm_state *state)
				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;
		}
		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;
}

int camogm_frame_jpeg(camogm_state *state)
{
	int i, j;
//   int fd;
	int i, j, split_index;
	int chunks_used = state->chunk_index - 1;
	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;

	if (!state->rawdev_op) {
		l = 0;
		for (i = 0; i < (state->chunk_index) - 1; i++) {
			chunks_iovec[i].iov_base = state->packetchunks[i + 1].chunk;
@@ -110,14 +146,10 @@ int camogm_frame_jpeg(camogm_state *state)
		}

		sprintf(state->path, "%s%010ld_%06ld.jpeg", state->path_prefix, state->this_frame_params.timestamp_sec, state->this_frame_params.timestamp_usec);
// if ((devfd = open("/dev/fpgaio", O_RDWR))<0)  {printf("error opening /dev/fpgaio\r\n"); return -1;}
//_1__12_Error opening /tmp/z/video1195147018_273452.jpeg for writing

		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;
@@ -126,10 +158,72 @@ int camogm_frame_jpeg(camogm_state *state)
			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;

				// be careful with indexes here
				chunks_iovec[i].iov_base = state->packetchunks[i].chunk;
				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;

		/* debug code follows */
		fprintf(debug_file, "\n=== raw device write, iovec dump ===\n");
		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, chunks_used);
		if (iovlen < l) {
			j = errno;
			D0(fprintf(debug_file, "writev error %d (returned %d, expected %d)\n", j, iovlen, l));
			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));
	}

	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;
}
+1 −1
Original line number Diff line number Diff line
@@ -6,7 +6,7 @@
int camogm_init_jpeg(void);
int camogm_start_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);

#endif /* _CAMOGM_JPEG_H */