apps/camogm/camogm.c

Go to the documentation of this file.
00001  
00002 /*!***************************************************************************
00003 *! FILE NAME  : camogm.c
00004 *! DESCRIPTION: Program to write captured video (and audio) to camera file system
00005 *! using Ogg container.
00006 *! Original implementation will copy package data to a buffer to use library calls?
00007 *! Copyright (C) 2007 Elphel, Inc.
00008 *! -----------------------------------------------------------------------------**
00009 *!  This program is free software: you can redistribute it and/or modify
00010 *!  it under the terms of the GNU General Public License as published by
00011 *!  the Free Software Foundation, either version 3 of the License, or
00012 *!  (at your option) any later version.
00013 *!
00014 *!  This program is distributed in the hope that it will be useful,
00015 *!  but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 *!  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017 *!  GNU General Public License for more details.
00018 *!
00019 *!  You should have received a copy of the GNU General Public License
00020 *!  along with this program.  If not, see <http://www.gnu.org/licenses/>.
00021 *! -----------------------------------------------------------------------------**
00022 *!
00023 *!  $Log: camogm.c,v $
00024 *!  Revision 1.1.1.1  2008/11/27 20:04:01  elphel
00025 *!
00026 *!
00027 *!  Revision 1.6  2008/11/21 01:52:53  elphel
00028 *!  updated for 8.0
00029 *!
00030 *!  Revision 1.5  2008/11/20 23:21:32  elphel
00031 *!  Put FIXME notes and removed parameters that are not used anymore
00032 *!
00033 *!  Revision 1.4  2008/10/29 04:18:28  elphel
00034 *!  v.8.0.alpha10 made a separate structure for global parameters (not related to particular frames in a frame queue)
00035 *!
00036 *!  Revision 1.3  2008/10/13 16:55:53  elphel
00037 *!  removed (some) obsolete P_* parameters, renamed CIRCLSEEK to LSEEK_CIRC constants (same as other similar)
00038 *!
00039 *!  Revision 1.2  2008/09/07 19:48:08  elphel
00040 *!  snapshot
00041 *!
00042 *!  Revision 1.9  2008/04/13 21:05:19  elphel
00043 *!  Fixing KML generation
00044 *!
00045 *!  Revision 1.8  2008/04/11 23:09:33  elphel
00046 *!  modified to handle kml generation
00047 *!
00048 *!  Revision 1.7  2008/04/07 09:13:34  elphel
00049 *!  Changes related to new Exif generation/processing
00050 *!
00051 *!  Revision 1.6  2008/01/14 22:59:00  elphel
00052 *!  7.1.7.4 - added timelapse mode to camogm
00053 *!
00054 *!  Revision 1.5  2007/12/03 08:28:45  elphel
00055 *!  Multiple changes, mostly cleanup
00056 *!
00057 *!  Revision 1.4  2007/11/29 00:38:57  elphel
00058 *!  fixed timescale bug
00059 *!
00060 *!  Revision 1.3  2007/11/19 05:07:19  elphel
00061 *!  fixed 2 typos
00062 *!
00063 *!  Revision 1.2  2007/11/19 03:23:21  elphel
00064 *!  7.1.5.5 Added support for *.mov files in camogm.
00065 *!
00066 *!  Revision 1.1  2007/11/16 08:49:56  elphel
00067 *!  Initial release of camogm - program to record video/image to the camera hard drive (or other storage)
00068 *!
00069 */ 
00070 #include <unistd.h>
00071 #include <stdio.h>
00072 #include <stdlib.h>
00073 #include <signal.h>
00074 #include <fcntl.h>
00075 #include <sys/uio.h>
00076 #include <errno.h>
00077 #include <sys/types.h>
00078 #include <sys/socket.h>
00079 #include <sys/stat.h>
00080 //#include <ctype.h>
00081 //#include <getopt.h>
00082 #include <time.h>
00083 #include <string.h>
00084 
00085 #include <netinet/in.h> /*little <-> big endian ?*/
00086 #include <sys/mman.h>           /* mmap */
00087 #include <sys/ioctl.h>
00088 
00089 #include <asm/elphel/c313a.h>
00090 //#include <asm/elphel/exifa.h>
00091 #include <asm/elphel/ext353.h>
00092 #include <asm/byteorder.h>
00093 
00094 
00095 #include <ogg/ogg.h> // has to be before ogmstreams.h
00096 #include "ogmstreams.h" // move it to <>?
00097 
00098 //#include "camogm_exif.h"
00099 #include "camogm_ogm.h"
00100 #include "camogm_jpeg.h"
00101 #include "camogm_mov.h"
00102 #include "camogm_kml.h"
00103 #include "camogm.h"
00104 
00105 #define TRAILER_SIZE   0x02
00106 #define MAP_OPTIONS MAP_FILE|MAP_PRIVATE
00107 
00108 char trailer[TRAILER_SIZE] = {0xff,0xd9};
00109 
00110 const char ExifFileName[]="/dev/exif_exif";
00111 
00112 const char HeadFileName[]="/dev/jpeghead";
00113 const char ctlFileName[]="/dev/frameparsall";
00114 unsigned long * ccam_dma_buf;           /* mmapped array */
00115 
00116 int lastDaemonBit= DAEMON_BIT_CAMOGM;
00117 struct framepars_all_t   *frameParsAll;
00118 struct framepars_t       *framePars;
00119 unsigned long            *globalPars; 
00120 
00121 
00122 int buff_size;
00123 
00124 #define DEFAULT_DURATION 60 
00125 #define DEFAULT_LENGTH 100000000 
00126 
00127 #define DEFAULT_FRAMES           16384 /* Maximal number of frames in file segment (each need 4* (1 + 1/frames_per_chunk) bytes for the frame index */
00128 #define DEFAULT_FRAMES_PER_CHUNK    10 /*second sparse index - for Quicktime fast forward */
00129 
00130 #define DEFAULT_LENGTH 100000000 
00131 #define DEFAULT_EXIF 1 /* use Exif */
00132 
00133 static char cmdbuf[1024];
00134 static int  cmdbufp=0; // current input pointer in the command buffer (read from pipe)
00135 static int  cmdstrt=0; // start of the next partial command
00136 
00137 camogm_state sstate;
00138 camogm_state * state;
00139 
00140 int   debug_level;
00141 FILE* debug_file;
00142 
00143 
00144 int camogm_init(void);
00145 int camogm_start(void);
00146 
00147 
00148 
00149 
00150 
00151 
00152 int camogm_stop(void);
00153 int camogm_reset(void); 
00154 int camogm_debug(const char * fname);
00155 int camogm_debug_level(int d);
00156 void  camogm_set_segment_duration(int sd);
00157 void  camogm_set_segment_length(int sl);
00158 void  camogm_set_save_gp(int d);
00159 void  camogm_set_prefix (const char * p);
00160 void  camogm_set_exif(int d);
00161 void  camogm_set_timescale(double d); 
00162 void  camogm_set_frames_skip(int d); 
00163 void  camogm_set_format(int d);
00164 
00165 void  camogm_kml_set_enable(int d);
00166 void  camogm_kml_set_horHalfFov (double dd);
00167 void  camogm_kml_set_vertHalfFov(double dd);
00168 void  camogm_kml_set_height_mode(int d);
00169 void  camogm_kml_set_height(double dd);
00170 void  camogm_kml_set_period(int d);
00171 void  camogm_kml_set_near(double dd); // distance to PhotoOverlay
00172 
00173 
00174 int   parse_cmd(FILE* npipe);
00175 char * getLineFromPipe(FILE* npipe);
00176 
00177 int  sendImageFrame (void);
00178 
00179 void  camogm_set_max_frames(int d);
00180 void  camogm_set_frames_per_chunk(int d);
00181 
00182 
00184 void put_uint16(void *buf, u_int16_t val)
00185 {
00186         unsigned char  *tmp;
00187 
00188         tmp = (unsigned char *) buf;
00189 
00190         tmp[0] = val & 0xff;
00191         tmp[1] = (val >>= 8) & 0xff;
00192 }
00193 
00194 void put_uint32(void *buf, u_int32_t val)
00195 {
00196         unsigned char  *tmp;
00197 
00198         tmp = (unsigned char *) buf;
00199 
00200         tmp[0] = val & 0xff;
00201         tmp[1] = (val >>= 8) & 0xff;
00202         tmp[2] = (val >>= 8) & 0xff;
00203         tmp[3] = (val >>= 8) & 0xff;
00204 }
00205 
00206 void put_uint64(void *buf, u_int64_t val)
00207 {
00208         unsigned char  *tmp;
00209 
00210         tmp = (unsigned char *) buf;
00211 
00212         tmp[0] = val & 0xff;
00213         tmp[1] = (val >>= 8) & 0xff;
00214         tmp[2] = (val >>= 8) & 0xff;
00215         tmp[3] = (val >>= 8) & 0xff;
00216         tmp[4] = (val >>= 8) & 0xff;
00217         tmp[5] = (val >>= 8) & 0xff;
00218         tmp[6] = (val >>= 8) & 0xff;
00219         tmp[7] = (val >>= 8) & 0xff;
00220 }
00221 
00222 int camogm_init(void) {
00223    const char sserial[]="elp0";
00224    int * ipser= (int*) sserial;
00225    state->running=0; // mo
00226    state->starting=0; // mo
00227    state->vf=NULL;
00228    camogm_set_segment_duration(DEFAULT_DURATION);
00229    camogm_set_segment_length(DEFAULT_LENGTH);
00230    camogm_set_max_frames(DEFAULT_FRAMES);
00231    camogm_set_frames_per_chunk(DEFAULT_FRAMES_PER_CHUNK);
00232    camogm_set_prefix ("\0");
00233    camogm_set_save_gp(0);
00234    camogm_reset(); 
00235    state->serialno= ipser[0];
00236    state->last= 0;
00237    debug_file= stderr;
00238    camogm_debug_level(1);
00239    strcpy(state->debug_name,"stderr");
00240    camogm_set_timescale(1.0);
00241    camogm_set_frames_skip(0); 
00242    camogm_set_format(CAMOGM_FORMAT_OGM);
00243    state->exifSize=0;
00244    state->exif= DEFAULT_EXIF;
00245    state->frame_lengths=NULL;
00246    state->frameno=0;
00247    state->formats=0;
00248 
00250    camogm_kml_set_enable(0);
00251    state->kml_file=NULL;
00252    camogm_kml_set_horHalfFov (20.0);
00253    camogm_kml_set_vertHalfFov(15.0);
00254    camogm_kml_set_height_mode(0);
00255    camogm_kml_set_height(10.0);
00256    camogm_kml_set_period(2); // 2 sec
00257    camogm_kml_set_near(40.0); // 40 m (distance to PhotoOverlay)
00258    state->kml_path[0]='\0';
00259 
00260 
00261 /*
00262 void  camogm_kml_set_enable(int d);
00263 void  camogm_kml_set_horHalfFov (double dd);
00264 void  camogm_kml_set_vertHalfFov(double dd);
00265 void  camogm_kml_set_height_mode(int d);
00266 void  camogm_kml_set_height(double dd);
00267 void  camogm_kml_set_decimate(int d);
00268 
00269   int                   kml_enable;       //! enable KML file generation
00270   FILE*                 kml_file;         //! stream to write kml file
00271   double                kml_horHalfFov;   //! half horizontal Fov (degrees)
00272   double                kml_vertHalfFov;  //! half vertical Fov (degrees)
00273   int                   kml_height_mode;  //! 1 - actual, 0 - ground
00274   double                kml_height;       //! extra height to add
00275   int                   kml_decimate;     //! generate PhotoOverlay for each kml_decimate frame;
00276   int                   kml_decimate_counter; //! counter to skip kml frames
00277   double                kml_near;         //! Use in KML "near" parameter (<=0 - don't use it)
00278 
00279 */
00280 
00281 
00282 
00283    return 0;
00284 }
00285 
00286 
00287 int camogm_debug(const char * fname) {
00288   int none=1;
00289   if (fname && strlen(fname) && strcmp(fname, "none") && strcmp(fname, "null")  && strcmp(fname, "/dev/null")) none=0;
00290   if (debug_file){
00291     if (strcmp(state->debug_name, "stdout") && strcmp(state->debug_name, "stderr")) fclose (debug_file);
00292     debug_file=NULL;
00293     state->debug_name[0]='\0';
00294   }
00295   if (!none) {
00296     if      (strcmp(fname, "stdout") ==0) debug_file=stdout;
00297     else if (strcmp(fname, "stderr") ==0) debug_file=stderr;
00298     else                                  debug_file=fopen(fname,"w+");
00299   }
00300   if (debug_file) {
00301       strncpy(state->debug_name,fname,sizeof(state->debug_name)-1);
00302       state->debug_name[sizeof(state->debug_name)-1]='\0';
00303   }
00304   return 0;
00305 }
00306 
00307 int camogm_debug_level(int d) {
00308   debug_level=d;
00309   return 0;
00310 }
00311 
00312 
00313 
00314 
00315 int camogm_start(void) {
00316   int timestamp_start;
00317   int rslt;
00318   int next_metadata_start, next_jpeg_len, fp;
00319   D1(fprintf (debug_file,"Starting recording\n"));
00320   state->frameno=0;
00321   state->timescale=        state->set_timescale;
00322 
00323   int * ifp =      (int *) &(state->frame_params) ;
00324   int * ifp_this = (int *) &(state->this_frame_params) ;
00325   if (state->kml_enable) camogm_init_kml() ; // do nothing
00326 
00327   if (state->format != state->set_format) {
00328      state->format=  state->set_format;
00329      switch (state->format) {
00330       case CAMOGM_FORMAT_NONE: rslt= 0; break;
00331       case CAMOGM_FORMAT_OGM:  rslt= camogm_init_ogm(); break;
00332       case CAMOGM_FORMAT_JPEG: rslt= camogm_init_jpeg();break;
00333       case CAMOGM_FORMAT_MOV:  rslt= camogm_init_mov(); break;
00334      }
00335      state->formats |= 1 << (state->format);
00337   }
00338   state->max_frames=       state->set_max_frames;
00339   state->frames_per_chunk= state->frames_per_chunk;
00340   state->starting=1; 
00341 
00342 D3(fprintf (debug_file,"1: state->cirbuf_rp=0x%x\n",state->cirbuf_rp));
00343   if ((state->cirbuf_rp <0) || (lseek(state->fd_circ,state->cirbuf_rp,SEEK_SET) < 0) || (lseek(state->fd_circ,LSEEK_CIRC_VALID,SEEK_END) < 0 )) {
00344 D3(fprintf (debug_file,"2: state->cirbuf_rp=0x%x\n",state->cirbuf_rp));
00345     state->cirbuf_rp=lseek(state->fd_circ,LSEEK_CIRC_LAST,SEEK_END);
00346     if (((fp=lseek(state->fd_circ,LSEEK_CIRC_PREV,SEEK_END)))>=0) state->cirbuf_rp=fp; 
00347     state->buf_overruns++;
00349 //    state->buf_min=lseek(state->fd_circ,LSEEK_CIRC_FREE,SEEK_END);
00350 //    lseek(state->fd_circ,state->cirbuf_rp,SEEK_SET); //! restore after moving (side effect)
00351     state->buf_min=getGPValue(G_FREECIRCBUF);
00352 
00353   } else {
00354 //      b_free=lseek(state->fd_circ,LSEEK_CIRC_FREE,SEEK_END);
00355 //      lseek(state->fd_circ,state->cirbuf_rp,SEEK_SET); //! restore after moving (side effect)
00356        if (state->buf_min > getGPValue(G_FREECIRCBUF)) state->buf_min=getGPValue(G_FREECIRCBUF);
00357 
00358   }
00359 D3(fprintf (debug_file,"3: state->cirbuf_rp=0x%x\n",state->cirbuf_rp));
00360 D3(fprintf (debug_file,"4:lseek(state->fd_circ,LSEEK_CIRC_READY,SEEK_END)=%d\n",(int) lseek(state->fd_circ,LSEEK_CIRC_READY,SEEK_END)));
00361 
00363   if (lseek(state->fd_circ,LSEEK_CIRC_READY,SEEK_END) <0) return -CAMOGM_FRAME_NOT_READY; 
00364 D3(fprintf (debug_file,"5: state->cirbuf_rp=0x%x\n",state->cirbuf_rp));
00365   state->metadata_start=(state->cirbuf_rp)-32;
00366   if (state->metadata_start<0) state->metadata_start+=state->circ_buff_size;
00367 
00369 
00370   memcpy (&(state->frame_params), (unsigned long * ) &ccam_dma_buf[state->metadata_start>>2],32);
00371   state->jpeg_len=state->frame_params.frame_length; 
00372 
00373 
00374   if (state->frame_params.signffff !=0xffff) {
00375     D0(fprintf(debug_file, "%s:%d: wrong signature - %d\r\n",__FILE__,__LINE__,(int) state->frame_params.signffff));
00376      state->cirbuf_rp=-1;
00377      D1(fprintf(debug_file, "state->cirbuf_rp=0x%x\r\n",(int) state->cirbuf_rp));
00378      D1(fprintf(debug_file, "%08x %08x %08x %08x %08x %08x %08x %08x\r\n",ifp[0],ifp[1],ifp[2],ifp[3],ifp[4],ifp[5],ifp[6],ifp[7]));
00379      return -CAMOGM_FRAME_BROKEN;
00380   }
00383   timestamp_start=(state->cirbuf_rp)+((state->jpeg_len+CCAM_MMAP_META+3) & (~0x1f)) + 32 - CCAM_MMAP_META_SEC; 
00384   if (timestamp_start >= state->circ_buff_size) timestamp_start-=state->circ_buff_size;
00385   memcpy (&(state->frame_params.timestamp_sec), (unsigned long * ) &ccam_dma_buf[timestamp_start>>2],8);
00386 
00388   if ((lseek(state->fd_circ,LSEEK_CIRC_NEXT,SEEK_END) < 0 ) ||
00390       (((fp=lseek(state->fd_circ,LSEEK_CIRC_READY,SEEK_END))) < 0)) {
00391         lseek(state->fd_circ,state->cirbuf_rp,SEEK_SET); 
00392         return -CAMOGM_FRAME_NOT_READY; 
00393   }
00394   next_metadata_start=fp-32;
00395   if (next_metadata_start<0) next_metadata_start+= state->circ_buff_size;
00396   memcpy (&(state->this_frame_params), (unsigned long * ) &ccam_dma_buf[next_metadata_start>>2],32);
00397   next_jpeg_len=state->this_frame_params.frame_length; 
00398   if (state->this_frame_params.signffff !=0xffff) { 
00399      D0(fprintf(debug_file, "%s:%d: wrong signature - %d\r\n",__FILE__,__LINE__,(int) state->this_frame_params.signffff));
00400      D1(fprintf(debug_file, "fp=0x%x\r\n",(int) fp));
00401      D1(fprintf(debug_file, "%08x %08x %08x %08x %08x %08x %08x %08x\r\n",ifp_this[0],ifp_this[1],ifp_this[2],ifp_this[3],ifp_this[4],ifp_this[5],ifp_this[6],ifp_this[7]));
00402 //  int * ifp =      (int *) &(state->this_frame_params) ;
00403 //  int * ifp_this = (int *) &(state->this_frame_params) ;
00404 
00405      state->cirbuf_rp=-1;
00406      return -CAMOGM_FRAME_BROKEN;
00407   }
00409   timestamp_start=fp+((next_jpeg_len+CCAM_MMAP_META+3) & (~0x1f)) + 32 - CCAM_MMAP_META_SEC; 
00410   if (timestamp_start >= state->circ_buff_size) timestamp_start-=state->circ_buff_size;
00411   memcpy (&(state->this_frame_params.timestamp_sec), (unsigned long * ) &ccam_dma_buf[timestamp_start>>2],8);
00413   if ((state->frame_params.width  != state->this_frame_params.width) ||
00414       (state->frame_params.height != state->this_frame_params.height)) {
00416      state->cirbuf_rp=fp;
00417      return -CAMOGM_FRAME_CHANGED; // no yet checking for the FPS
00418   }
00420    state->frame_period=(state->this_frame_params.timestamp_usec - state->frame_params.timestamp_usec)+
00421                1000000*(state->this_frame_params.timestamp_sec  - state->frame_params.timestamp_sec);
00422 
00424   state->frames_skip=      state->set_frames_skip;
00425   if (state->frames_skip > 0) {
00426     state->frames_skip_left=0;
00427     state->frame_period *= (state->frames_skip+1);
00428 //    state->frames_skip_left= state->set_frames_skip;
00429   } else if (state->frames_skip < 0) {
00430     state->frame_period=-(state->frames_skip) ; 
00431     state->frames_skip_left=state->frame_params.timestamp_sec;
00432   }
00433    state->time_unit= (ogg_int64_t) (((double) state-> frame_period) * ((double) 10) / ((double) state-> timescale));
00434    state->width=state->frame_params.width;
00435    state->height=state->frame_params.height;
00436 
00439    lseek(state->fd_head,state->cirbuf_rp+1,SEEK_END); 
00440    state->head_size=lseek(state->fd_head,0,SEEK_END); 
00441    if (state->head_size>JPEG_HEADER_MAXSIZE) {
00442      D0(fprintf (debug_file,"%s:%d: Too big JPEG header (%d > %d)",__FILE__,__LINE__,state->head_size, JPEG_HEADER_MAXSIZE ));
00443      return -2;
00444    }
00446    lseek(state->fd_head,0,0);
00447    read (state->fd_head,state->jpegHeader,state->head_size);
00449    lseek(state->fd_circ,state->cirbuf_rp,SEEK_SET);
00450 
00452    switch (state->format) {
00453     case CAMOGM_FORMAT_NONE: rslt= 0;  break;
00454     case CAMOGM_FORMAT_OGM:  rslt= camogm_start_ogm();  break;
00455     case CAMOGM_FORMAT_JPEG: rslt= camogm_start_jpeg(); break;
00456     case CAMOGM_FORMAT_MOV:  rslt= camogm_start_mov();  break;
00457     default: rslt=0; // do nothing
00458    }
00459    if (rslt) return rslt;
00460    if (state->kml_enable) rslt=camogm_start_kml() ; // will turn on state->kml_used if it can
00461    if (rslt) return rslt;
00462    state->running=1;
00463    state->starting=0;
00464    D1(fprintf (debug_file,"Started OK\n"));
00465    return 0;
00466 }
00467 
00468 
00469 int  sendImageFrame (void) {
00470    int rslt;
00471 //   struct interframe_params_t this_frame_params;
00472 //   elph_packet_chunk packetchunks[7];
00473    unsigned char frame_packet_type = PACKET_IS_SYNCPOINT;
00474 //   int chunk_index=0;
00475 //   int i;
00476 //   unsigned long * tts= (unsigned long *) &(state->granulepos); //to word-swap timestamt to granule
00477    int timestamp_start;
00479 //   int * ifp =      (int *) &(state->frame_params) ;
00480    int * ifp_this = (int *) &(state->this_frame_params) ;
00481 
00483    if (state->frameno >= (state->max_frames)) return -CAMOGM_FRAME_CHANGED;
00485 //   D3(fprintf (debug_file,"sendImageFrame: format=%d, set_format=%d\n", state->format, state->set_format));
00486 
00487    if (state->format != state->set_format) return -CAMOGM_FRAME_CHANGED;
00489    if ((state->vf) && (state->segment_length >=0) && (ftell(state->vf) > state->segment_length)) return -CAMOGM_FRAME_CHANGED;
00491    if (((state->ivf)>=0) && (state->segment_length >=0) && (lseek(state->ivf, 0, SEEK_CUR) > state->segment_length)) return -CAMOGM_FRAME_CHANGED;
00493    if (lseek(state->fd_circ,state->cirbuf_rp,SEEK_SET) <0) return -CAMOGM_FRAME_INVALID; 
00494 
00495    if (lseek(state->fd_circ,LSEEK_CIRC_READY,SEEK_END) <0) return -CAMOGM_FRAME_NOT_READY; 
00496 /*
00498   state->frames_skip=      state->set_frames_skip;
00499   if (state->frames_skip > 0) {
00500     state->frames_skip_left=0;
00501     state->frame_period *= (state->frames_skip+1);
00502 //    state->frames_skip_left= state->set_frames_skip;
00503   } else if (state->frames_skip < 0) {
00504     state->frame_period=-(state->frames_skip) ; //! actual frame period will fluctuate to the nearest frame acquired (free running)
00505     state->frames_skip_left=state->frame_params.timestamp_sec;
00506   }
00507 */
00508 
00510    if ( (state->frames_skip > 0) && (state->frames_skip_left > 0 )) { 
00511      state->cirbuf_rp=lseek(state->fd_circ,LSEEK_CIRC_NEXT,SEEK_END);
00513      if (state->save_gp) lseek(state->fd_circ,LSEEK_CIRC_SETP,SEEK_END);
00514      state->frames_skip_left--;
00515      return -CAMOGM_FRAME_NOT_READY; 
00516    }
00517 
00519 //D3(fprintf (debug_file,"_1_"));
00520    state->metadata_start=state->cirbuf_rp-32;
00521    if (state->metadata_start<0) state->metadata_start+=state->circ_buff_size;
00522    memcpy (&(state->this_frame_params), (unsigned long * ) &ccam_dma_buf[state->metadata_start>>2],32);
00523    state->jpeg_len=state->this_frame_params.frame_length; 
00524    if (state->this_frame_params.signffff !=0xffff) {
00525      D0(fprintf(debug_file, "%s:%d: wrong signature - %d\r\n",__FILE__,__LINE__,(int) state->this_frame_params.signffff));
00526      D1(fprintf(debug_file, "state->cirbuf_rp=0x%x\r\n",(int) state->cirbuf_rp));
00527      D1(fprintf(debug_file, "%08x %08x %08x %08x %08x %08x %08x %08x\r\n",ifp_this[0],ifp_this[1],ifp_this[2],ifp_this[3],ifp_this[4],ifp_this[5],ifp_this[6],ifp_this[7]));
00528 
00529 
00530      return -CAMOGM_FRAME_BROKEN;
00531    }
00532 //D3(fprintf (debug_file,"_2_"));
00534    timestamp_start=state->cirbuf_rp+((state->jpeg_len+CCAM_MMAP_META+3) & (~0x1f)) + 32 - CCAM_MMAP_META_SEC; 
00535    if (timestamp_start >= state->circ_buff_size) timestamp_start-=state->circ_buff_size;
00536 //D3(fprintf (debug_file,"_3_"));
00537    memcpy (&(state->this_frame_params.timestamp_sec), (unsigned long * ) &ccam_dma_buf[timestamp_start>>2],8);
00539    if ((state->frame_params.width  != state->this_frame_params.width) ||
00540        (state->frame_params.height != state->this_frame_params.height)) return -CAMOGM_FRAME_CHANGED; 
00541 
00542    if ((state->segment_duration > 0) && 
00543        ((state->this_frame_params.timestamp_sec-state->frame_params.timestamp_sec) > state->segment_duration))
00544            return -CAMOGM_FRAME_CHANGED;
00545 
00547    if ((state->frames_skip < 0) && (state->frames_skip_left > state->this_frame_params.timestamp_sec) ) {
00548      state->cirbuf_rp=lseek(state->fd_circ,LSEEK_CIRC_NEXT,SEEK_END);
00550      if (state->save_gp) lseek(state->fd_circ,LSEEK_CIRC_SETP,SEEK_END);
00551      return -CAMOGM_FRAME_NOT_READY; 
00552    }
00553 
00554 
00555 //D3(fprintf (debug_file,"_4_"));
00556    if (state->exif) {
00557 D3(fprintf (debug_file,"_5_"));
00559 //     updateExif(ep, state->ed, &(state->frame_params));
00560      state->exifSize=lseek(state->fd_exif,1,SEEK_END); // at the beginning of page 1 - position == page length
00561 //     if (state->exifSize < 0) state->exifSize=0; // error from lseek;
00562      if (state->exifSize > 0) {
00563 //state->this_frame_params.meta_index
00564        lseek(state->fd_exif,state->this_frame_params.meta_index,SEEK_END); 
00565        rslt=read (state->fd_exif, state->ed, state->exifSize);
00566        if (rslt<0) rslt=0;
00567        state->exifSize=rslt;
00568      } else state->exifSize=0;
00569    } else state->exifSize=0;
00570 
00571 //D3(fprintf (debug_file,"_6_"));
00572 
00574    state->chunk_index=0;
00575    state->packetchunks[state->chunk_index  ].bytes=1;
00576    state->packetchunks[state->chunk_index++].chunk=&frame_packet_type;
00577    if (state->exif>0) {
00578 //D3(fprintf (debug_file,"_7_"));
00579      state->packetchunks[state->chunk_index  ].bytes=2;
00580      state->packetchunks[state->chunk_index++].chunk=state->jpegHeader;
00581      state->packetchunks[state->chunk_index  ].bytes=state->exifSize;
00582      state->packetchunks[state->chunk_index++].chunk= state->ed;
00583      state->packetchunks[state->chunk_index  ].bytes=state->head_size-2;
00584      state->packetchunks[state->chunk_index++].chunk= &(state->jpegHeader[2]);
00585    } else {
00586 //D3(fprintf (debug_file,"_8_"));
00587      state->packetchunks[state->chunk_index  ].bytes=state->head_size;
00588      state->packetchunks[state->chunk_index++].chunk= state->jpegHeader;
00589    }
00590 //D3(fprintf (debug_file,"_9_"));
00591 
00593 //     if ((jpeg_start+jpeg_len) > state->circ_buff_size) { // two segments
00594    if ((state->cirbuf_rp + state->jpeg_len) > state->circ_buff_size) { 
00595 
00596 //D3(fprintf (debug_file,"_10_"));
00597 
00598 //        sendBuffer((void *) &ccam_dma_buf[jpeg_start>>2], state->circ_buff_size-state->cirbuf_rp);
00599      state->packetchunks[state->chunk_index  ].bytes=state->circ_buff_size-state->cirbuf_rp;
00600      state->packetchunks[state->chunk_index++].chunk= (unsigned char*) &ccam_dma_buf[state->cirbuf_rp>>2];
00602 //        sendBuffer((void *) &ccam_dma_buf[0], jpeg_len-(state->circ_buff_size-state->cirbuf_rp));
00603      state->packetchunks[state->chunk_index  ].bytes=state->jpeg_len - (state->circ_buff_size-state->cirbuf_rp);
00604      state->packetchunks[state->chunk_index++].chunk= (unsigned char*) &ccam_dma_buf[0];
00605    } else { // single segment
00606 //D3(fprintf (debug_file,"_11_"));
00607 
00609 //        sendBuffer((void *) &ccam_dma_buf[state->cirbuf_rp>>2], state->jpeg_len);
00610      state->packetchunks[state->chunk_index  ].bytes=state->jpeg_len;
00611      state->packetchunks[state->chunk_index++].chunk= (unsigned char*)  &ccam_dma_buf[state->cirbuf_rp>>2];
00612    }
00613 //D3(fprintf (debug_file,"_12_"));
00614    state->packetchunks[state->chunk_index  ].bytes=2;
00615    state->packetchunks[state->chunk_index++].chunk= (unsigned char*) trailer;
00616 
00617    switch (state->format) {
00618     case CAMOGM_FORMAT_NONE: rslt=0; break;
00619     case CAMOGM_FORMAT_OGM:  rslt=camogm_frame_ogm(); break;
00620     case CAMOGM_FORMAT_JPEG: rslt=camogm_frame_jpeg(); break;
00621     case CAMOGM_FORMAT_MOV:  rslt=camogm_frame_mov(); break;
00622     default: rslt=0; // do nothing
00623    }
00624    if (rslt) return rslt;
00625    if (state->kml_used) rslt=camogm_frame_kml() ; // will turn on state->kml_used if it can
00626    if (rslt) return rslt;
00627 
00628 //D3(fprintf (debug_file,"_14_"));
00630    state->frameno++;
00631    state->cirbuf_rp=lseek(state->fd_circ,LSEEK_CIRC_NEXT,SEEK_END);
00633    if (state->save_gp) lseek(state->fd_circ,LSEEK_CIRC_SETP,SEEK_END);
00634 //D3(fprintf (debug_file,"_15_\n"));
00635 //D3(fprintf (debug_file,"state->cirbuf_rp=0x%08x granulepos=0x%x 0x%x (%d.%06d)\n", state->cirbuf_rp, (int) ((state->granulepos)>>32), (int) (state->granulepos),
00636 //                                                                (int) state->this_frame_params.timestamp_sec, (int)state->this_frame_params.timestamp_usec));
00637   if (state->frames_skip > 0) {
00638      state->frames_skip_left= state->frames_skip;
00639   } else if (state->frames_skip < 0) {
00640      state->frames_skip_left+= -(state->frames_skip);
00641   }
00642    return 0;
00643 }
00644 
00645 
00646 
00647 int camogm_stop(void) {
00648   int rslt=0;
00649   if (!state->running) {
00650     if (!state->starting) {
00651       D2(fprintf (debug_file,"Recording was not running, nothing to stop\n"));
00652     } else {
00653       state->starting=0;
00654       D1(fprintf (debug_file,"Dropping attempt to start\n"));
00655     }
00656     return 0;
00657   }
00658   D1(fprintf (debug_file,"Ending recording\n"));
00659    if (state->kml_used) camogm_end_kml() ;
00660    switch (state->format) {
00661     case CAMOGM_FORMAT_NONE: rslt= 0; break;
00662     case CAMOGM_FORMAT_OGM:  rslt= camogm_end_ogm(); break;
00663     case CAMOGM_FORMAT_JPEG: rslt= camogm_end_jpeg();break;
00664     case CAMOGM_FORMAT_MOV:  rslt= camogm_end_mov(); break;
00666    }
00668   if (state->vf) fclose (state->vf);
00669   state->vf=NULL;
00670   if (rslt) return rslt;
00671   state->last=1;
00673   state->running=0;
00674   state->starting=0;
00675   return 0;
00676 }
00677 
00678 void camogm_free() {
00679    int f;
00681 //add kml when needed
00682    for (f=0;f<31;f++) {
00683      if (state->formats & ( 1 << (state->format))) {
00684        switch (f) {
00685         case CAMOGM_FORMAT_NONE: break;
00686         case CAMOGM_FORMAT_OGM:  camogm_free_ogm(); break;
00687         case CAMOGM_FORMAT_JPEG: camogm_free_jpeg();break;
00688         case CAMOGM_FORMAT_MOV:  camogm_free_mov(); break;
00689        }
00690      }
00691    }
00692    state->formats=0;
00693 }
00694 
00695 int camogm_reset(void) { 
00696    state->cirbuf_rp=-1;
00697    state->buf_overruns=-1; 
00698    return 0;
00699 }
00700 
00702 void  camogm_kml_set_enable(int d) {
00703    state->kml_enable=d;
00704 }
00705 void  camogm_kml_set_horHalfFov (double dd) {
00706    state->kml_horHalfFov=dd;
00707 }
00708 void  camogm_kml_set_vertHalfFov(double dd) {
00709    state->kml_vertHalfFov=dd;
00710 }
00711 void  camogm_kml_set_height_mode(int d) {
00712    state->kml_height_mode=d;
00713 }
00714 void  camogm_kml_set_height(double dd) {
00715    state->kml_height=dd;
00716 }
00717 void  camogm_kml_set_period(int d) {
00718    state->kml_period=d;
00719    state->kml_last_ts=0;
00720    state->kml_last_uts=0;
00721 }
00722 void  camogm_kml_set_near(double dd) { // distance to PhotoOverlay
00723    state->kml_near=dd;
00724 }
00725 
00726 
00727 void  camogm_set_segment_duration(int sd) {
00728    state->segment_duration=sd;
00729 }
00730 void  camogm_set_segment_length(int sl) {
00731    state->segment_length=   sl;
00732 }
00733 void  camogm_set_save_gp(int d) {
00734    state->save_gp=   d;
00735 }
00736 void  camogm_set_exif(int d) {
00737    state->exif=   d;
00738 }
00739 
00740 void  camogm_set_prefix (const char * p) {
00741   strncpy(state->path_prefix, p, sizeof(state->path_prefix)-1);
00742   state->path_prefix[sizeof(state->path_prefix)-1]='\0';
00743 }
00744 
00745 void  camogm_set_timescale(double d) { 
00746    state->set_timescale=  d;
00747    if ((state->running==0) && (state->starting==0)) {
00748      state->timescale=state->set_timescale;
00749    }
00750 }
00751 
00752 void  camogm_set_frames_skip(int d) { 
00753    state->set_frames_skip=  d;
00754    if ((state->running==0) && (state->starting==0)) {
00755      state->frames_skip=      state->set_frames_skip;
00756 //     state->frames_skip_left= state->set_frames_skip;
00757      state->frames_skip_left= 0;
00758    }
00759 }
00760 
00761 
00762 void  camogm_set_format(int d) {
00763    int rslt=0;
00764    state->set_format=  d;
00765    if ((state->running==0) && (state->starting==0)) {
00766      state->format=  state->set_format;
00767      switch (state->format) {
00768       case CAMOGM_FORMAT_NONE: rslt= 0; break;
00769       case CAMOGM_FORMAT_OGM:  rslt= camogm_init_ogm(); break;
00770       case CAMOGM_FORMAT_JPEG: rslt= camogm_init_jpeg();break;
00771       case CAMOGM_FORMAT_MOV:  rslt= camogm_init_mov(); break;
00772      }
00773      if (rslt) {
00774        D0(fprintf (debug_file,"%s:%d: Error setting format to=%d\n",__FILE__,__LINE__, state->format));
00775      }
00776      state->formats |= 1 << (state->format);
00777    }
00778 }
00780 void  camogm_set_max_frames(int d) {
00781    state->set_max_frames=  d;
00782    if ((state->running==0) && (state->starting==0)) state->max_frames=  d;
00783 }
00784 void  camogm_set_frames_per_chunk(int d) {
00785    state->set_frames_per_chunk=  d;
00786    if ((state->running==0) && (state->starting==0)) state->frames_per_chunk=  d;
00787 }
00788 void  camogm_status(char * fn, int xml) {
00789   int _len=0;
00790   int _dur,_udur;
00791 //TODO:make it XML file
00792   FILE* f;
00793   char *_state, *_output_format, *_using_exif, *_using_global_pointer, *_compressor_state;
00794   int _b_free, _b_used; // , save_p;
00795   int _frames_remain=0;
00796   int _sec_remain=0;
00797   int _frames_skip=0;
00798   int _sec_skip=0;
00799   char *_kml_enable, *_kml_used, *_kml_height_mode;
00800 
00801   _kml_enable=      state->kml_enable?"yes":"no";
00802   _kml_used=        state->kml_used?"yes":"no";
00803   _kml_height_mode= state->kml_height_mode?"GPS altitude":"map ground level";  
00804 
00805 
00806   _b_free=getGPValue(G_FREECIRCBUF);
00807   _b_used=getGPValue(G_CIRCBUFSIZE)-getGPValue(G_FREECIRCBUF);
00808 
00809   if (!fn) f=stdout;
00810   else if (strcmp(fn, "stdout")==0) f=stdout;
00811   else if (strcmp(fn, "stderr")==0) f=stderr;
00812   else {
00813     if (!((f=fopen (fn,"w")))) {
00814        D0(fprintf (debug_file,"Error opening %s\n", fn));
00815       return;
00816     }
00817   }
00818   if      (state->vf)       _len=ftell(state->vf); 
00819   else if ((state->ivf)>=0) _len=lseek(state->ivf, 0, SEEK_CUR); 
00820   _dur= state->this_frame_params.timestamp_sec-state->frame_params.timestamp_sec;
00821   _udur=state->this_frame_params.timestamp_usec-state->frame_params.timestamp_usec;
00822   if (_udur<0) {
00823     _dur-=1;
00824     _udur+=1000000;
00825   } else if (_udur>=1000000) {
00826     _dur+=1;
00827     _udur-=1000000;
00828   }
00829   _state=         state->running? "running":(state->starting?"starting":"stopped");
00830   _output_format= state->format?((state->format==CAMOGM_FORMAT_OGM)?"ogm":
00831                                              ((state->format==CAMOGM_FORMAT_JPEG)?"jpeg":
00832                                              ((state->format==CAMOGM_FORMAT_MOV)?"mov":
00833                                               "other"))):"none";
00834   _using_exif=    state->exif?"yes":"no";
00835   _using_global_pointer=state->save_gp?"yes":"no";
00836   _compressor_state=(getGPValue(P_COMPRESSOR_RUN)==2)?"running":"stoppped";
00837     if ( state->frames_skip >0 ) {
00838       _frames_remain= state->frames_skip_left;
00839       _frames_skip=state->frames_skip;
00840     } else if ( state->frames_skip <0 ) {
00841       _sec_remain= (state->frames_skip_left - state->this_frame_params.timestamp_sec);
00842       _sec_skip=-(state->frames_skip);
00843     }
00844 
00845 
00846   if (xml) {
00847     fprintf (f,"<?xml version=\"1.0\"?>\n" \
00848              "<camogm_state>\n" \
00849              "  <state>\"%s\"</state>\n" \
00850              "  <compressor_state>\"%s\"</compressor_state>\n" \
00851              "  <file_name>\"%s\"</file_name>\n" \
00852              "  <frame_number>%d</frame_number>\n" \
00853              "  <file_duration>%d.%06d</file_duration>\n" \
00854              "  <file_length>%d</file_length>\n" \
00855              "  <frame_period>%d</frame_period>\n" \
00856              "  <frames_skip>%d</frames_skip>\n" \
00857              "  <seconds_skip>%d</seconds_skip>\n" \
00858              "  <frames_skip_left>%d</frames_skip_left>\n" \
00859              "  <seconds_skip_left>%d</seconds_skip_left>\n" \
00860              "  <frame_width>%d</frame_width>\n" \
00861              "  <frame_height>%d</frame_height>\n" \
00862              "  <format>\"%s\"</format>\n" \
00863              "  <exif>\"%s\"</exif>\n" \
00864              "  <prefix>\"%s\"</prefix>\n" \
00865              "  <max_duration>%d</max_duration>\n" \
00866              "  <max_length>%d</max_length>\n" \
00867              "  <max_frames>%d</max_frames>\n" \
00868              "  <timescale>%f</timescale>\n" \
00869              "  <frames_per_chunk>%d</frames_per_chunk>\n" \
00870              "  <buffer_overruns>%d</buffer_overruns>\n" \
00871              "  <buffer_minimal>%d</buffer_minimal>\n" \
00872              "  <buffer_free>%d</buffer_free>\n" \
00873              "  <buffer_used>%d</buffer_used>\n" \
00874              "  <circbuf_rp>%d</circbuf_rp>\n" \
00875              "  <debug_output>\"%s\"</debug_output>\n" \
00876              "  <debug_level>%d</debug_level>\n" \
00877              "  <use_global_rp>\"%s\"</use_global_rp>\n" \
00878              "  <kml_enable>\"%s\"</kml_enable>\n" \
00879              "  <kml_used>\"%s\"</kml_used>\n" \
00880              "  <kml_path>\"%s\"</kml_path>\n" \
00881              "  <kml_horHalfFov>\"%f\"</kml_horHalfFov>\n" \
00882              "  <kml_vertHalfFov>\"%f\"</kml_vertHalfFov>\n" \
00883              "  <kml_near>\"%f\"</kml_near>\n" \
00884              "  <kml_height_mode>\"%s\"</kml_height_mode>\n" \
00885              "  <kml_height>\"%f\"</kml_height>\n" \
00886              "  <kml_period>%d</kml_period>\n" \
00887              "  <kml_last_ts>%d.%06d</kml_last_ts>\n" \
00888              "</camogm_state>\n",
00889              _state,_compressor_state,state->path,state->frameno,_dur,_udur,_len,state->frame_period, \
00890              _frames_skip,_sec_skip,_frames_remain, _sec_remain, \
00891              state->width,state->height,_output_format,_using_exif, \
00892              state->path_prefix, state->segment_duration, state->segment_length, state->max_frames, state->timescale, \
00893              state->frames_per_chunk, state->buf_overruns, state->buf_min, _b_free, _b_used, state->cirbuf_rp, \
00894              state->debug_name, debug_level, _using_global_pointer, \
00895              _kml_enable,_kml_used,state->kml_path,state->kml_horHalfFov,state->kml_vertHalfFov,state->kml_near,\
00896              _kml_height_mode,state->kml_height,state->kml_period,state->kml_last_ts,state->kml_last_uts);
00897   } else {
00898     fprintf (f,"state              %s\n",        _state);
00899     fprintf (f,"compressor state   %s\n",        _compressor_state);
00900     fprintf (f,"file               %s\n",        state->path);
00901     fprintf (f,"frame              %d\n",        state->frameno);
00902     fprintf (f,"file duration      %d.%06d sec\n",_dur,_udur);
00903     fprintf (f,"file length        %d B\n",      _len);
00904     fprintf (f,"frame period       %d (0x%x)\n", state->frame_period,state->frame_period);
00905     if ( _frames_skip >0 ) fprintf (f,"frames to skip   %d (left %d)\n",_frames_skip, _frames_remain);
00906     if ( _sec_skip    <0 ) fprintf (f,"timelapse period  %d sec (remaining %d sec)\n", _sec_skip, _sec_remain);
00907     fprintf (f,"width              %d (0x%x)\n", state->width,state->width);
00908     fprintf (f,"height             %d (0x%x)\n", state->height,state->height);
00909     fprintf (f,"\n");
00910     fprintf (f,"output format      %s\n",        _output_format);
00911     fprintf (f,"using exif         %s\n",        _using_exif);
00912     fprintf (f,"path prefix:       %s\n",        state->path_prefix);
00913     fprintf (f,"max file duration: %d sec\n",    state->segment_duration);
00914     fprintf (f,"max file length:   %d B\n",      state->segment_length);
00915     fprintf (f,"max frames         %d\n",        state->max_frames);
00916     fprintf (f,"timescale          %f\n",        state->timescale);
00917     fprintf (f,"frames per chunk   %d\n",        state->frames_per_chunk);
00918     fprintf (f,"\n");
00919     fprintf (f,"buffer overruns    %d\n",        state->buf_overruns);
00920     fprintf (f,"buffer minimal     %d\n",        state->buf_min);
00921     fprintf (f,"buffer free        %d\n",        _b_free);
00922     fprintf (f,"buffer used        %d\n",        _b_used);
00923     fprintf (f,"circbuf_rp         %d (0x%x)\n", state->cirbuf_rp,state->cirbuf_rp);
00924     fprintf (f,"\n");
00925     fprintf (f,"debug output to    %s\n",        state->debug_name);
00926     fprintf (f,"debug level        %d\n",        debug_level);
00927     fprintf (f,"use global pointer %s\n",        _using_global_pointer);
00928     fprintf (f,"\n\n");
00929     fprintf (f,"kml_enable         %s\n",        _kml_enable);
00930     fprintf (f,"kml_used           %s\n",        _kml_used);
00931     fprintf (f,"kml_path           %s\n",        state->kml_path);
00932     fprintf (f,"kml_horHalfFov     %f degrees\n",state->kml_horHalfFov);
00933     fprintf (f,"kml_vertHalfFov    %f degrees\n",state->kml_vertHalfFov);
00934     fprintf (f,"kml_near           %f m\n",      state->kml_near);
00935     fprintf (f,"kml height mode    %s\n",        _kml_height_mode);
00936     fprintf (f,"kml_height (extra) %f m\n",      state->kml_height);
00937     fprintf (f,"kml_period         %d\n",        state->kml_period);
00938     fprintf (f,"kml_last_ts        %d.%06d\n",   state->kml_last_ts,state->kml_last_uts);
00939     fprintf (f,"\n\n");
00940 
00941   }
00942   if ((f!=stdout) && (f!=stderr)) fclose (f);
00943   if (state->buf_overruns>=0) state->buf_overruns=0; 
00944   state->buf_min=_b_free;
00945 }
00946 
00948 char * getLineFromPipe(FILE* npipe) {
00949       int fl;
00950       char * nlp;
00952       if (cmdstrt > 0) {
00954         memmove(cmdbuf, &cmdbuf[cmdstrt], sizeof(cmdbuf)- cmdstrt);
00955         cmdbufp-=cmdstrt;
00956         cmdstrt=0;
00957       }
00959       if (!cmdbufp) cmdbuf[cmdbufp]=0; 
00960 //      nlp= strchr(cmdbuf,'\n');
00961       nlp= strpbrk(cmdbuf,";\n");
00962       if (!nlp) { 
00963         fl=fread(&cmdbuf[cmdbufp], 1,sizeof(cmdbuf)-cmdbufp-1,npipe);
00964         cmdbuf[cmdbufp+fl]=0;
00966 //        nlp= strchr(&cmdbuf[cmdbufp],'\n'); //! there were no new lines before cmdbufp
00967         nlp= strpbrk(&cmdbuf[cmdbufp],";\n"); 
00968         cmdbufp+=fl; 
00969       }
00970       if (nlp) {
00971 //printf ("++nlp=%d\n", (int) (nlp-cmdbuf));
00972         nlp[0]=0;
00973         cmdstrt=nlp-cmdbuf+1;
00974 //printf ("++cmdstrt=%d\n", cmdstrt);
00975 //printf ("cmdbuf[0]=%d, cmdbuf[1]=%d, cmdbuf[2]=%d, cmdbuf[3]=%d, \n",cmdbuf[0],cmdbuf[1],cmdbuf[2],cmdbuf[3]);
00976         for (fl=0; cmdbuf[fl] && strchr(" \t",cmdbuf[fl]); fl++);
00977 //printf ("++fl=%d\n", fl);
00978         return &cmdbuf[fl];
00979       } else {
00980 //printf ("notready: cmdbufp=%d, cmdstrt=%d\n",cmdbufp, cmdstrt);
00981           return NULL;
00982       }
00983 }
00984 // command[= \t]*args[ \t]*
00985 int parse_cmd(FILE* npipe) {
00986   char * cmd;
00987   char * args;
00988   char * argse;
00989   int d;
00990   double dd;
00991 //  if (!((cmd=getLineFromPipe(npipe)))) return 0; //! nothing in the pipe
00993   while(((cmd=getLineFromPipe(npipe))) && !cmd[0]) ;
00994   if (!cmd) return 0; 
00995 //  printf ("cmd[0]=%d:%s\n",(int) cmd[0],cmd);
00996   args=strpbrk(cmd,"= \t");
00998   if (args) {
00999     args[0]=0;
01000     args++;
01001     while (strchr("= \t",args[0])) args++;
01002     if (args[0]) {
01004       for (argse=strchr(args,'\0')-1; strchr("= \t",argse[0]);argse--) argse[0]='\0';
01005     }
01006     if (!args[0]) args=NULL;
01007   }
01009   if      (strcmp(cmd, "start")==0) {
01010      camogm_start();
01011      return 1;
01012   } else if (strcmp(cmd, "reset")==0) { 
01013      camogm_reset();
01014      return 2;
01015   } else if (strcmp(cmd, "stop")==0) {
01016      camogm_stop();
01017      return 3;
01018   } else if (strcmp(cmd, "exit")==0) { 
01019      camogm_stop();
01020      camogm_free();
01021      exit (0);
01022   } else if (strcmp(cmd, "duration")==0) {
01023      if (!(args) || (((d= strtol(args, NULL, 10)))<=0)) d=DEFAULT_DURATION;
01024      camogm_set_segment_duration(d);
01025      return 4;
01026   } else if (strcmp(cmd, "length")==0) {
01027      if (!(args) || (((d= strtol(args, NULL, 10)))<=0)) d=DEFAULT_LENGTH;
01028      camogm_set_segment_length(d);
01029      return 5;
01030   } else if (strcmp(cmd, "prefix")==0) {
01031      if (args) camogm_set_prefix (args);
01032      return 6;
01033   } else if (strcmp(cmd, "status")==0) { 
01034      camogm_status(args, 0);
01035      return 7;
01036   } else if (strcmp(cmd, "xstatus")==0) { 
01037      camogm_status(args, 1);
01038      return 7;
01039   } else if (strcmp(cmd, "save_gp")==0) {
01040      if ((args) && (((d= strtol(args, NULL, 10)))>=0)) camogm_set_save_gp(d);
01041      return 8;
01042   } else if (strcmp(cmd, "exif")==0) {
01043      if ((args) && (((d= strtol(args, NULL, 10)))>=0)) camogm_set_exif(d);
01044      return 8;
01045   } else if (strcmp(cmd, "debug")==0) {
01046      camogm_debug(args);
01047      return 9;
01048   } else if (strcmp(cmd, "timescale")==0) {
01049      dd= strtod(args,NULL);
01050      camogm_set_timescale(dd?dd:1.0);
01051      return 10;
01054 
01055 
01056   } else if (strcmp(cmd, "frameskip")==0) {
01057      d= strtol(args, NULL, 10);
01058      camogm_set_frames_skip(d);
01059      return 11;
01060   } else if (strcmp(cmd, "timelapse")==0) { 
01061      d= strtol(args, NULL, 10);
01062      camogm_set_frames_skip(-d);
01063      return 11;
01064   } else if (strcmp(cmd, "format")==0) {
01065      if (args) {
01066       if      (strcmp(args,  "none")==0) camogm_set_format(0);
01067       else if ((strcmp(args, "ogm" )==0) || (strcmp(args, "ogg")==0)) camogm_set_format(CAMOGM_FORMAT_OGM);
01068       else if ((strcmp(args, "jpeg")==0) || (strcmp(args, "jpg")==0)) camogm_set_format(CAMOGM_FORMAT_JPEG);
01069       else if (strcmp(args,  "mov" )==0)                              camogm_set_format(CAMOGM_FORMAT_MOV);
01070      }
01071      return 12;
01072   } else if (strcmp(cmd, "debuglev")==0) {
01073      d= strtol(args, NULL, 10);
01074      camogm_debug_level(d?d:0);
01075      return 13;
01076   } else if (strcmp(cmd, "kml")==0) {
01077      if ((args) && (((d= strtol(args, NULL, 10)))>=0)) camogm_kml_set_enable(d);
01078      return 14;
01079   } else if (strcmp(cmd, "kml_hhf")==0) {
01080      dd= strtod(args,NULL);
01081      camogm_kml_set_horHalfFov(dd);
01082      return 15;
01083   } else if (strcmp(cmd, "kml_vhf")==0) {
01084      dd= strtod(args,NULL);
01085      camogm_kml_set_vertHalfFov(dd);
01086      return 16;
01087   } else if (strcmp(cmd, "kml_near")==0) {
01088      dd= strtod(args,NULL);
01089      camogm_kml_set_near(dd);
01090      return 17;
01091   } else if (strcmp(cmd, "kml_alt")==0) {
01092      if (args) {
01093       if      (strcmp(args, "gps"   )==0) camogm_kml_set_height_mode(1);
01094       else if (strcmp(args, "ground")==0) camogm_kml_set_height_mode(0);
01095      }
01096      return 18;
01097   } else if (strcmp(cmd, "kml_height")==0) {
01098      dd= strtod(args,NULL);
01099      camogm_kml_set_height(dd);
01100      return 19;
01101   } else if (strcmp(cmd, "kml_period")==0) {
01102      d= strtol(args, NULL, 10);
01103      camogm_kml_set_period(d?d:1);
01104      return 20;
01105   }
01106 
01107   return -1;
01108 }
01109 
01110 int main(int argc, char *argv[])
01111 {
01112    const char circbufFileName[]="/dev/circbuf";
01113 //     int fd_circ;
01114    FILE * cmd_file;
01115    const char usage[]=   "This program allows recording of the video/images acquired by Elphel camera to the storage media.\n" \
01116                          "It is designed to run in the background and accept commands through a named pipe.\n\n" \
01117                          "Usage:\n\n" \
01118                          "%s <named_pipe_name>\n\n" \
01119                          "i.e.:\n\n" \
01120                          "%s /var/state/camogm_cmd\n\n" \
01121                          "When the program is runninig you may send commands by writing strings to the command file\n" \
01122                          "(/var/state/camogm_cmd in the example above). The complete list of available commands is available\n" \
01123                          "on Elphel Wiki (http://wiki.elphel.com/index.php?title=Camogm), here is the example of usage\n" \
01124                          "from the shell prompt in the camera:\n\n" \
01125                          "echo \"status; exif=1; format=jpeg;status=/var/tmp/camogm.status\" > /var/state/camogm_cmd\n\n" \
01126                          "That will print status information on the standard output (may not be visible if the program was not\n" \
01127                          "started from the same session), set exif mode on (each frame will have the full Exif header including\n" \
01128                          "a precise time stamp), set output format to a series of individual JPEG files, and then send status\n" \
01129                          "information to a file /var/tmp/camogm.status in the camera file system.\n\n" \
01130                          "This program does not control the process of acquisition of the video/images to the camera internal\n" \
01131                          "buffer, it only retrieves that data from the buffer (waiting when needed), packages it to selected\n" \
01132                          "format and stores the result files.\n\n";
01133    int go=1;
01134    int cmd;
01135    int i,rslt;
01136    state= &sstate; //extern
01138    if ((argc < 2) || (argv[1][1]=='-'))  { 
01139      printf (usage,argv[0],argv[0]);
01140      return 0;
01141    }
01142    camogm_init();
01143 
01145    state->fd_exif = open(ExifFileName, O_RDONLY);
01146    if (state->fd_exif<0) { // check control OK
01147      D0(fprintf (debug_file,"Error opening %s\n", ExifFileName));
01148      return -1;
01149    }
01150 
01152    state->fd_head = open(HeadFileName, O_RDWR);
01153    if (state->fd_head<0) { // check control OK
01154      D0(fprintf (debug_file,"Error opening %s\n", HeadFileName));
01155      return -1;
01156    }
01157    state->head_size=lseek(state->fd_head,0,SEEK_END);
01158    if (state->head_size>JPEG_HEADER_MAXSIZE) {
01159      D0(fprintf (debug_file,"%s:%d: Too big JPEG header (%d > %d)",__FILE__,__LINE__,state->head_size, JPEG_HEADER_MAXSIZE ));
01160      return -2;
01161    }
01162 
01164    state->fd_circ = open(circbufFileName, O_RDWR);
01165    if (state->fd_circ<0) { // check control OK
01166       D0(fprintf (debug_file,"Error opening %s\n", circbufFileName));
01167       return -2;
01168    }
01170    state->circ_buff_size=lseek(state->fd_circ,0,SEEK_END);
01171    ccam_dma_buf = (unsigned long *) mmap(0, state->circ_buff_size, PROT_READ, MAP_SHARED, state->fd_circ, 0);
01172    if((int)ccam_dma_buf == -1) {
01173      D0(fprintf (debug_file,"Error in mmap of %s\n",circbufFileName));
01174 //     close (fd_head);
01175      close(state->fd_circ);
01176      return -3;
01177    }
01178 
01180 
01182     state->fd_fparmsall = open(ctlFileName, O_RDWR);
01183     if (state->fd_fparmsall<0) { // check control OK
01184        D0(fprintf (debug_file,"%s:%d:%s: Error opening %s\n",__FILE__,__LINE__,__FUNCTION__, ctlFileName));
01185        return -2;
01186     }
01187 
01189     frameParsAll = (struct framepars_all_t *) mmap(0, sizeof (struct framepars_all_t) , PROT_READ, MAP_SHARED, state->fd_fparmsall, 0);
01190     if((int)frameParsAll == -1) {
01191       D0(fprintf(debug_file,"%s:%d:%s: Error in mmap in %s\n",__FILE__,__LINE__,__FUNCTION__,ctlFileName));
01192       close(state->fd_fparmsall);
01193       close(state->fd_circ);
01194       return -3;
01195     }
01196     framePars=frameParsAll->framePars;
01197     globalPars=frameParsAll->globalPars;
01198 
01201    i=unlink (argv[1]);
01202    if (i) {
01203        D1(fprintf (debug_file,"Unlink %s returned %d, errno=%d \n", argv[1], i, errno));
01204    }
01205    i=mkfifo(argv[1], 0777); //EEXIST
01207    if (i) {
01208     if (errno==EEXIST) {
01209        D1(fprintf (debug_file,"Named pipe %s already exists, will use it.\n", argv[1]));
01210     } else {
01211        D0(fprintf (debug_file,"Can not create a named pipe %s, errno=%d \n", argv[1], errno));
01212        return -4;
01213     }
01214    }
01215 
01218    if (!((cmd_file=fopen(argv[1],"r")))) {
01219      D0(fprintf (debug_file,"Can not open command file %s\n",argv[1]));
01220      return -5;
01221    }
01222    D1(fprintf (debug_file,"Pipe %s open for reading\n",argv[1]));
01223 
01225 #define COMMAND_LOOP_DELAY 500000 //0.5sec
01226  
01227    while (go) {
01228 //   D3(fprintf (debug_file,"%s:%d: format=%d, set_format=%d\n",__FILE__,__LINE__, state->format, state->set_format));
01229 
01231      cmd=parse_cmd(cmd_file);
01232      if (cmd) {
01233        if (cmd<0) D0(fprintf (debug_file,"Unrecognized command\n"));
01234      } else if (state->running) { 
01235 //   D3(fprintf (debug_file,"%s:%d: format=%d, set_format=%d\n",__FILE__,__LINE__, state->format, state->set_format));
01236 
01237        switch ((rslt=-sendImageFrame ())) {
01238          case 0:
01239 /*
01240           D3(fprintf (debug_file,"%s:line %d - sendImageFrame() returned %d\n" \
01241                                   "state->cirbuf_rp= 0x%x\n",__FILE__,__LINE__,rslt,state->cirbuf_rp));
01242 */
01243                             break; 
01244          case CAMOGM_FRAME_NOT_READY:        
01245 
01246 
01247 //     D3(fprintf (debug_file,"%s:line %d - sendImageFrame() returned -%d\n",__FILE__,__LINE__,rslt));
01248 /*
01249      D3(fprintf (debug_file,"%s:line %d - sendImageFrame() returned -%d\n" \
01250                                   "state->cirbuf_rp= 0x%x\n",__FILE__,__LINE__,rslt,state->cirbuf_rp));
01251 */
01252 
01253                 lseek(state->fd_circ,LSEEK_CIRC_WAIT,SEEK_END);
01254                 break;
01255          case  CAMOGM_FRAME_CHANGED:   
01256          case  CAMOGM_FRAME_NEXTFILE:  
01257          case  CAMOGM_FRAME_INVALID:   
01258          case  CAMOGM_FRAME_BROKEN:    
01259 
01260 //     D3(fprintf (debug_file,"%s:line %d - sendImageFrame() returned -%d\n",__FILE__,__LINE__,rslt));
01261                 camogm_stop();
01262                 camogm_start();
01263                 break;
01264          case  CAMOGM_FRAME_FILE_ERR:  
01265          case  CAMOGM_FRAME_OTHER:     
01266                 D0(fprintf (debug_file,"%s:line %d - error=%d\n",__FILE__,__LINE__,rslt));
01267                 break;
01268          default:
01269           D0(fprintf (debug_file,"%s:line %d - should not get here (rslt=%d)\n",__FILE__,__LINE__,rslt));
01270           exit (-1);
01271        } //switch
01272      } else if (state->starting) { 
01273 //   D3(fprintf (debug_file,"%s:%d: format=%d, set_format=%d\n",__FILE__,__LINE__, state->format, state->set_format));
01274 
01276        switch ((rslt=-camogm_start())) {
01277          case 0:                       break; 
01278          case CAMOGM_FRAME_NOT_READY:        
01279 
01280 
01281 //                lseek(state->fd_circ,LSEEK_CIRC_WAIT,SEEK_END);
01282          case  CAMOGM_FRAME_CHANGED:   
01283          case  CAMOGM_FRAME_NEXTFILE:
01284          case  CAMOGM_FRAME_INVALID:   
01285          case  CAMOGM_FRAME_BROKEN:    
01286 //     D3(fprintf (debug_file,"%s:line %d - camogm_start() returned -%d,  state->cirbuf_rp= 0x%x\n", __FILE__,__LINE__,rslt,state->cirbuf_rp));
01287                 usleep( COMMAND_LOOP_DELAY) ; 
01288                 break;
01289          case  CAMOGM_FRAME_FILE_ERR:  
01290          case  CAMOGM_FRAME_OTHER:     
01291                 D0(fprintf (debug_file,"%s:line %d - error=%d\n",__FILE__,__LINE__,rslt));
01292                 break;
01293          default:
01294           D0(fprintf (debug_file,"%s:line %d - should not get here (rslt=%d)\n",__FILE__,__LINE__,rslt));
01295           exit (-1);
01296        } //switch
01297      } else { 
01298        usleep( COMMAND_LOOP_DELAY) ; 
01299      }
01300    } 
01301    return 0;
01302 }
01309 unsigned long getGPValue(unsigned long GPNumber) {
01310    return (GPNumber>=FRAMEPAR_GLOBALS)?
01311               GLOBALPARS(GPNumber):
01312               framePars[GLOBALPARS(G_THIS_FRAME) & PARS_FRAMES_MASK].pars[GPNumber];
01313 }
01314 
01320 void setGValue(unsigned long  GNumber,   unsigned long value) {
01321     GLOBALPARS(GNumber)=value;
01322 }
01323 
01330 int  waitDaemonEnabled(int daemonBit) { // <0 - use default
01331    if ((daemonBit>=0) && (daemonBit<32)) lastDaemonBit=daemonBit;
01332    unsigned long this_frame=this_frame=GLOBALPARS(G_THIS_FRAME);
01335    lseek(state->fd_circ, LSEEK_DAEMON_CIRCBUF+lastDaemonBit, SEEK_END); 
01336    if (this_frame==GLOBALPARS(G_THIS_FRAME)) return 1;
01337    return 0;
01338 }
01339 
01345 int  isDaemonEnabled(int daemonBit) { // <0 - use default
01346    if ((daemonBit>=0) && (daemonBit<32)) lastDaemonBit=daemonBit;
01347    return ((framePars[GLOBALPARS(G_THIS_FRAME) & PARS_FRAMES_MASK].pars[P_DAEMON_EN] & (1 <<lastDaemonBit))!=0);
01348 }

Generated on Fri Nov 28 00:06:21 2008 for elphel by  doxygen 1.5.1