/** @file camogm.h
* @brief Program to write captured video (and audio) to camera file system
* using Ogg container.
* @copyright Copyright (C) 2016 Elphel, Inc.
*
* @par License
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifndef _CAMOGM_H
#define _CAMOGM_H
#include
#include
#include
#include
#include
#include "ogmstreams.h"
#define CAMOGM_FRAME_NOT_READY 1 ///< frame pointer valid, but not yet acquired
#define CAMOGM_FRAME_INVALID 2 ///< invalid frame pointer
#define CAMOGM_FRAME_CHANGED 3 ///< frame parameters have changed
#define CAMOGM_FRAME_NEXTFILE 4 ///< need to switch to a new file segment
#define CAMOGM_FRAME_BROKEN 5 ///< frame broken (buffer overrun)
#define CAMOGM_FRAME_FILE_ERR 6 ///< error with file I/O
#define CAMOGM_FRAME_MALLOC 7 ///< can not allocate memory
#define CAMOGM_TOO_EARLY 8 ///< too early to start, waiting for particular timestamp
#define CAMOGM_FRAME_OTHER 9 ///< other errors
#define CAMOGM_NO_SPACE 10 ///< no free space left on current file system
#define CAMOGM_FORMAT_NONE 0 ///< no video output
#define CAMOGM_FORMAT_OGM 1 ///< output as Ogg Media file
#define CAMOGM_FORMAT_JPEG 2 ///< output as individual JPEG files
#define CAMOGM_FORMAT_MOV 3 ///< output as Apple Quicktime
#define D(x) { if (debug_file && debug_level) { x; fflush(debug_file); } }
#define D0(x) { if (debug_file) { pthread_mutex_lock(&print_mutex); x; fflush(debug_file); pthread_mutex_unlock(&print_mutex); } }
#define D1(x) { if (debug_file && (debug_level > 0)) { pthread_mutex_lock(&print_mutex); x; fflush(debug_file); pthread_mutex_unlock(&print_mutex); } }
#define D2(x) { if (debug_file && (debug_level > 1)) { pthread_mutex_lock(&print_mutex); x; fflush(debug_file); pthread_mutex_unlock(&print_mutex); } }
#define D3(x) { if (debug_file && (debug_level > 2)) { pthread_mutex_lock(&print_mutex); x; fflush(debug_file); pthread_mutex_unlock(&print_mutex); } }
#define D4(x) { if (debug_file && (debug_level > 3)) { pthread_mutex_lock(&print_mutex); x; fflush(debug_file); pthread_mutex_unlock(&print_mutex); } }
#define D5(x) { if (debug_file && (debug_level > 4)) { pthread_mutex_lock(&print_mutex); x; fflush(debug_file); pthread_mutex_unlock(&print_mutex); } }
#define D6(x) { if (debug_file && (debug_level > 5)) { pthread_mutex_lock(&print_mutex); x; fflush(debug_file); pthread_mutex_unlock(&print_mutex); } }
//#define DD(x)
#define DD(x) { if (debug_file) { fprintf(debug_file, "%s:%d:", __FILE__, __LINE__); x; fflush(debug_file); } }
/** @brief HEADER_SIZE is defined to be larger than actual header (with EXIF) to use compile-time buffer */
#define JPEG_HEADER_MAXSIZE 0x300
/** @brief Offset from the beginning of raw device buffer. Must be aligned to physical sector size */
#define RAWDEV_START_OFFSET 1024
/** @brief Maximum length of file or raw device path */
#define ELPHEL_PATH_MAX 300
#define MMAP_CHUNK_SIZE 10485760
/**
* @enum state_flags
* @brief Program state flags
*/
enum state_flags {
STATE_STOPPED,
STATE_STARTING,
STATE_RUNNING,
STATE_READING,
STATE_CANCEL
};
/**
* @struct rawdev_buffer
* @brief Holds pointers related to raw device buffer operation
* @var rawdev_buffer::rawdev_fd
* File descriptor of open raw device
* @var rawdev_buffer::rawdev_path
* A string containing full path to raw device
* @var rawdev_buffer::overrun
* The number of times the buffer has overrun during current work session
* @var rawdev_buffer::start_pos
* The start position of raw device buffer
* @var rawdev_buffer::end_pos
* The end position of raw device buffer
* @var rawdev_buffer::curr_pos
* Current read position in raw device buffer
* @var rawdev_buffer::file_start
* Pointer to the beginning of current file. This pointer is set during raw device reading and
* updated every time new file is found.
*/
typedef struct {
int rawdev_fd;
char rawdev_path[ELPHEL_PATH_MAX];
uint32_t overrun;
uint64_t start_pos;
uint64_t end_pos;
uint64_t curr_pos_w;
unsigned char *disk_mmap;
uint64_t mmap_default_size;
uint64_t mmap_current_size;
uint64_t mmap_offset;
volatile uint64_t curr_pos_r;
uint64_t file_start;
pthread_t tid;
int thread_state;
volatile bool thread_finished;
} rawdev_buffer;
/**
* @struct camogm_state
* @brief Holds current state of the running program
*/
typedef struct {
int segment_duration;
int segment_length;
int greedy;
int ignore_fps;
int save_gp; ///< if non zero, current circbuf pointer will be saved to global pointer, so imgsrv can report /pointers
char path_prefix[256]; ///< file name prefix
char path[ELPHEL_PATH_MAX]; ///< full file name
int cirbuf_rp[SENSOR_PORTS]; ///< -1 means the pointer is invalid
int fd_circ[SENSOR_PORTS]; ///< file descriptor for circbuf
int fd_head[SENSOR_PORTS]; ///< file descriptor for JPEG header
int fd_fparmsall[SENSOR_PORTS]; ///< file descriptor for sensor/compressor parameters
int fd_exif[SENSOR_PORTS]; ///< file descriptor for Exif data
int head_size[SENSOR_PORTS]; ///< JPEG header size
unsigned char jpegHeader[SENSOR_PORTS][JPEG_HEADER_MAXSIZE];
int metadata_start;
struct interframe_params_t frame_params[SENSOR_PORTS];
struct interframe_params_t this_frame_params[SENSOR_PORTS];
int jpeg_len;
int frame_period[SENSOR_PORTS]; ///< in microseconds (1/10 of what is needed for the Ogm header)
int width; ///< image width
int height; ///< image height
int prog_state; ///< program state flag, can be one of #state_flags
int last_error_code;
ogg_stream_state os;
ogg_page og;
ogg_packet op;
elph_ogg_packet eop;
int serialno;
ogg_int64_t packetno;
ogg_int64_t granulepos;
FILE* vf; ///< video file (ogm, fopen)
int ivf; ///< video file (jpeg, mov - open)
int last; ///< last packet in a file
int exif; ///< flag indicating that Exif headers should be calculated and included in each frame
int exifSize[SENSOR_PORTS]; ///< signed
unsigned char ed[SENSOR_PORTS][MAX_EXIF_SIZE];
int circ_buff_size[SENSOR_PORTS];
char debug_name[256];
double timescale; ///< current timescale, default 1.0
double set_timescale;
double start_after_timestamp; ///< delay recording start to after frame timestamp
int max_frames;
int set_max_frames;
int frames_per_chunk;
int set_frames_per_chunk; ///< quicktime - index for fast forward?
int frameno;
int *frame_lengths;
off_t frame_data_start; ///< Quicktime (and else?) - frame data start (0xff 0xd8...)
ogg_int64_t time_unit;
int formats; ///< bitmask of used (initialized) formats
int format; ///< output file format
int set_format; ///< output format to set (will be updated after stop)
elph_packet_chunk packetchunks[7];
int chunk_index;
int buf_overruns[SENSOR_PORTS];
int buf_min[SENSOR_PORTS];
int set_frames_skip; ///< will be copied to frames_skip if stopped or at start
int frames_skip; ///< number of frames to skip after the one recorded (for time lapse)
///< if negative - -(interval between frames in seconds)
int frames_skip_left[SENSOR_PORTS]; ///< number of frames left to skip before the next one to be processed
///< if (frames_skip <0) - next timestamp to save an image
// kml stuff
int kml_enable; ///< enable KML file generation
int kml_used; ///< KML file generation used (change only when stopped)
char kml_path[300]; ///< full path for KML file (if any)
FILE* kml_file; ///< stream to write kml file
double kml_horHalfFov; ///< half horizontal Fov (degrees)
double kml_vertHalfFov; ///< half vertical Fov (degrees)
double kml_near; ///< Use in KML "near" parameter (<=0 - don't use it)
int kml_height_mode; ///< 1 - actual, 0 - ground
double kml_height; ///< extra height to add
int kml_period; ///< generate PhotoOverlay for each kml_period seconds;
int kml_last_ts; ///< last generated kml file timestamp
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 we are currently working with
char *pipe_name; ///< command pipe name
int rawdev_op; ///< flag indicating writing to raw device
rawdev_buffer rawdev; ///< contains pointers to raw device buffer
unsigned int active_chn; ///< bitmask of active sensor ports
} camogm_state;
extern int debug_level;
extern FILE* debug_file;
extern pthread_mutex_t print_mutex;
void put_uint16(void *buf, u_int16_t val);
void put_uint32(void *buf, u_int32_t val);
void put_uint64(void *buf, u_int64_t val);
unsigned long getGPValue(unsigned int port, unsigned long GPNumber);
void setGValue(unsigned int port, unsigned long GNumber, unsigned long value);
int waitDaemonEnabled(unsigned int port, int daemonBit);
int isDaemonEnabled(unsigned int port, int daemonBit);
#endif /* _CAMOGM_H */