apps/camogm2/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.8  2008/06/06 10:53:32  spectr_rain
00025 *!  clean
00026 *!
00027 *!  Revision 1.7  2008/06/02 19:49:41  spectr_rain
00028 *!  fixed QuickTime compatibility - need to cleanup
00029 *!
00030 *!  Revision 1.4  2008/05/23 15:54:45  spectr_rain
00031 *!  *** empty log message ***
00032 *!
00033 *!  Revision 1.3  2008/05/23 15:42:10  spectr_rain
00034 *!  *** empty log message ***
00035 *!
00036 *!  Revision 1.2  2008/05/23 13:09:49  spectr_rain
00037 *!  QuickTime support
00038 *!
00039 *!  Revision 1.1  2008/05/02 12:45:57  spectr_rain
00040 *!  initial revision with the sound support
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 #include <sched.h>
00085 
00086 #include <netinet/in.h> /*little <-> big endian ?*/
00087 #include <sys/mman.h>           /* mmap */
00088 #include <sys/ioctl.h>
00089 
00090 #include <asm/elphel/c313a.h>
00091 //#include <asm/elphel/exifa.h>
00092 #include <asm/elphel/ext353.h>
00093 #include <asm/byteorder.h>
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 #include "camogm_wav.h"
00105 
00106 //#include <alsa/asoundlib.h>
00107 
00108 #define TRAILER_SIZE   0x02
00109 #define MAP_OPTIONS MAP_FILE|MAP_PRIVATE
00110 
00111 char trailer[TRAILER_SIZE] = {0xff,0xd9};
00112 
00113 const char ExifFileName[]="/dev/exif_exif";
00114 
00115 const char HeadFileName[]="/dev/jpeghead";
00116 const char SensParsFileName[]="/dev/sensorpars";
00117 unsigned long * ccam_dma_buf;           /* mmapped array */
00118 unsigned long * imageParamsR;
00119 int buff_size;
00120 
00121 #define DEFAULT_DURATION 600 
00122 //#define DEFAULT_DURATION 60 
00123 //#define DEFAULT_DURATION 10 
00124 //#define DEFAULT_LENGTH 100000000 
00125 #define DEFAULT_LENGTH (700 * 1024 * 1024) 
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 #define DEFAULT_FRAMES_PER_CHUNK    1 /*second sparse index - for Quicktime fast forward */
00130 
00131 //#define DEFAULT_LENGTH 100000000 /*!default segment length (B) */
00132 #define DEFAULT_EXIF 1 /* use Exif */
00133 
00134 #define DEFAULT_AUDIO_RATE      44100
00135 #define DEFAULT_AUDIO_CHANNELS  2
00136 
00137 #define AUDIO_RATE_MAX  44100
00138 #define AUDIO_RATE_MIN  11025
00139 #define AUDIO_CHANNELS_MAX      2
00140 #define AUDIO_CHANNELS_MIN      1
00141 
00142 static char cmdbuf[1024];
00143 static int  cmdbufp=0; // current input pointer in the command buffer (read from pipe)
00144 static int  cmdstrt=0; // start of the next partial command
00145 
00146 camogm_state sstate;
00147 camogm_state * state;
00148 
00149 int   debug_level;
00150 FILE* debug_file;
00151 
00152 
00153 int camogm_init(void);
00154 
00155 int camogm_start(int by_command);
00156 int camogm_stop(int by_command);
00157 
00158 int camogm_reset(void); 
00159 int camogm_debug(const char * fname);
00160 int camogm_debug_level(int d);
00161 void  camogm_set_segment_duration(int sd);
00162 void  camogm_set_segment_length(int sl);
00163 void  camogm_set_save_gp(int d);
00164 void  camogm_set_prefix (const char * p);
00165 void  camogm_set_exif(int d);
00166 void  camogm_set_timescale(double d); 
00167 void  camogm_set_frames_skip(int d); 
00168 void  camogm_set_format(int d);
00169 
00170 void  camogm_kml_set_enable(int d);
00171 void  camogm_kml_set_horHalfFov (double dd);
00172 void  camogm_kml_set_vertHalfFov(double dd);
00173 void  camogm_kml_set_height_mode(int d);
00174 void  camogm_kml_set_height(double dd);
00175 void  camogm_kml_set_period(int d);
00176 void  camogm_kml_set_near(double dd); // distance to PhotoOverlay
00177 
00178 
00179 int   parse_cmd(FILE* npipe);
00180 char * getLineFromPipe(FILE* npipe);
00181 
00182 int  sendImageFrame (void);
00183 
00184 void  camogm_set_max_frames(int d);
00185 void  camogm_set_frames_per_chunk(int d);
00186 
00187 
00188 void camogm_set_audio_state(char *args);
00189 void camogm_set_audio_format(char *args);
00190 void camogm_set_sync_state(char *args);
00191 void audio_process(void);
00192 void audio_init(int by_command);
00193 void audio_start(int by_command);
00194 void audio_end(int by_command);
00195 void audio_free(void);
00196 void camogm_audio_initialize(void);
00198 
00199 int time_comp(struct timeval *t1, struct timeval *t2) {
00200         if(t1->tv_sec > t2->tv_sec)
00201                 return 1;
00202         if(t1->tv_sec == t2->tv_sec) {
00203                 if(t1->tv_usec > t2->tv_usec)
00204                         return 1;
00205                 if(t1->tv_usec == t2->tv_usec)
00206                         return 0;
00207         }
00208         return -1;
00209 }
00210 
00211 void time_normalize(struct timeval *tv) {
00212         while(tv->tv_usec >= 1000000) {
00213                 tv->tv_usec -= 1000000;
00214                 tv->tv_sec += 1;
00215         }
00216 }
00217 
00218 struct timeval time_delta(struct timeval *t1, struct timeval *t2) {
00219         struct timeval tv;
00220         tv.tv_sec = t1->tv_sec - t2->tv_sec;
00221         if(t1->tv_usec >= t2->tv_usec) {
00222                 tv.tv_usec = t1->tv_usec - t2->tv_usec;
00223         } else {
00224                 tv.tv_usec = 1000000 + t1->tv_usec - t2->tv_usec;
00225                 tv.tv_sec -= 1;
00226         }
00227         return tv;
00228 }
00229 
00230 void put_uint16(void *buf, u_int16_t val)
00231 {
00232         unsigned char  *tmp;
00233 
00234         tmp = (unsigned char *) buf;
00235 
00236         tmp[0] = val & 0xff;
00237         tmp[1] = (val >>= 8) & 0xff;
00238 }
00239 
00240 void put_uint32(void *buf, u_int32_t val)
00241 {
00242         unsigned char  *tmp;
00243 
00244         tmp = (unsigned char *) buf;
00245 
00246         tmp[0] = val & 0xff;
00247         tmp[1] = (val >>= 8) & 0xff;
00248         tmp[2] = (val >>= 8) & 0xff;
00249         tmp[3] = (val >>= 8) & 0xff;
00250 }
00251 
00252 void put_uint64(void *buf, u_int64_t val)
00253 {
00254         unsigned char  *tmp;
00255 
00256         tmp = (unsigned char *) buf;
00257 
00258         tmp[0] = val & 0xff;
00259         tmp[1] = (val >>= 8) & 0xff;
00260         tmp[2] = (val >>= 8) & 0xff;
00261         tmp[3] = (val >>= 8) & 0xff;
00262         tmp[4] = (val >>= 8) & 0xff;
00263         tmp[5] = (val >>= 8) & 0xff;
00264         tmp[6] = (val >>= 8) & 0xff;
00265         tmp[7] = (val >>= 8) & 0xff;
00266 }
00267 
00268 int camogm_init(void) {
00269    const char sserial[]="elp0";
00270    int * ipser= (int*) sserial;
00271    state->running=0; // mo
00272    state->starting=0; // mo
00273 //   state->vf=NULL;
00274    state->vf = 0;
00275    camogm_set_segment_duration(DEFAULT_DURATION);
00276    camogm_set_segment_length(DEFAULT_LENGTH);
00277    camogm_set_max_frames(DEFAULT_FRAMES);
00278    camogm_set_frames_per_chunk(DEFAULT_FRAMES_PER_CHUNK);
00279    camogm_set_prefix ("\0");
00280 //   camogm_set_prefix ("/tmp/video/c");
00281    camogm_set_save_gp(0);
00282    camogm_reset(); 
00283    state->serialno= ipser[0];
00284    state->last= 0;
00285    debug_file= stderr;
00286    camogm_debug_level(1);
00287    strcpy(state->debug_name,"stderr");
00288    camogm_set_timescale(1.0);
00289    camogm_set_frames_skip(0); 
00290    camogm_set_format(CAMOGM_FORMAT_OGM);
00291 //   camogm_set_format(CAMOGM_FORMAT_MOV);
00292    camogm_set_audio_state("on");
00293    camogm_set_audio_format("44100/2");
00294    camogm_set_audio_state("off");
00295 //   camogm_set_sync_state("on");
00296    camogm_set_sync_state("off");
00297    state->exifSize=0;
00298    state->exif= DEFAULT_EXIF;
00299 //   state->frame_lengths=NULL;
00300    state->frameno=0;
00301    state->formats=0;
00302 
00303         camogm_audio_initialize();
00304 
00306    camogm_kml_set_enable(0);
00307    state->kml_file=NULL;
00308    camogm_kml_set_horHalfFov (20.0);
00309    camogm_kml_set_vertHalfFov(15.0);
00310    camogm_kml_set_height_mode(0);
00311    camogm_kml_set_height(10.0);
00312    camogm_kml_set_period(2); // 2 sec
00313    camogm_kml_set_near(40.0); // 40 m (distance to PhotoOverlay)
00314    state->kml_path[0]='\0';
00315 
00316 
00317 /*
00318 void  camogm_kml_set_enable(int d);
00319 void  camogm_kml_set_horHalfFov (double dd);
00320 void  camogm_kml_set_vertHalfFov(double dd);
00321 void  camogm_kml_set_height_mode(int d);
00322 void  camogm_kml_set_height(double dd);
00323 void  camogm_kml_set_decimate(int d);
00324 
00325   int                   kml_enable;       //! enable KML file generation
00326   FILE*                 kml_file;         //! stream to write kml file
00327   double                kml_horHalfFov;   //! half horizontal Fov (degrees)
00328   double                kml_vertHalfFov;  //! half vertical Fov (degrees)
00329   int                   kml_height_mode;  //! 1 - actual, 0 - ground
00330   double                kml_height;       //! extra height to add
00331   int                   kml_decimate;     //! generate PhotoOverlay for each kml_decimate frame;
00332   int                   kml_decimate_counter; //! counter to skip kml frames
00333   double                kml_near;         //! Use in KML "near" parameter (<=0 - don't use it)
00334 
00335 */
00336 
00337 
00338 
00339    return 0;
00340 }
00341 
00342 
00343 int camogm_debug(const char * fname) {
00344   int none=1;
00345   if (fname && strlen(fname) && strcmp(fname, "none") && strcmp(fname, "null")  && strcmp(fname, "/dev/null")) none=0;
00346   if (debug_file){
00347     if (strcmp(state->debug_name, "stdout") && strcmp(state->debug_name, "stderr")) fclose (debug_file);
00348     debug_file=NULL;
00349     state->debug_name[0]='\0';
00350   }
00351   if (!none) {
00352     if      (strcmp(fname, "stdout") ==0) debug_file=stdout;
00353     else if (strcmp(fname, "stderr") ==0) debug_file=stderr;
00354     else                                  debug_file=fopen(fname,"w+");
00355   }
00356   if (debug_file) {
00357       strncpy(state->debug_name,fname,sizeof(state->debug_name)-1);
00358       state->debug_name[sizeof(state->debug_name)-1]='\0';
00359   }
00360   return 0;
00361 }
00362 
00363 int camogm_debug_level(int d) {
00364   debug_level=d;
00365   return 0;
00366 }
00367 
00368 
00369 
00370 
00371 int camogm_start(int by_command) {
00372   int timestamp_start;
00373   int rslt;
00374   int next_metadata_start, next_jpeg_len, fp;
00375   D1(fprintf (debug_file,"Starting recording\n"));
00376   state->frameno=0;
00377   state->timescale=        state->set_timescale;
00378 
00379   int * ifp =      (int *) &(state->frame_params) ;
00380   int * ifp_this = (int *) &(state->this_frame_params) ;
00381   if (state->kml_enable) camogm_init_kml() ; // do nothing
00382 
00383         audio_init(by_command);
00384   if (state->format != state->set_format) {
00385      state->format=  state->set_format;
00386      switch (state->format) {
00387       case CAMOGM_FORMAT_NONE: rslt= 0; break;
00388       case CAMOGM_FORMAT_OGM:  rslt= camogm_init_ogm(); break;
00389       case CAMOGM_FORMAT_JPEG: rslt= camogm_init_jpeg();break;
00390       case CAMOGM_FORMAT_MOV:  rslt= camogm_init_mov(); break;
00391      }
00392      state->formats |= 1 << (state->format);
00394   }
00395   state->max_frames=       state->set_max_frames;
00396   state->frames_per_chunk= state->frames_per_chunk;
00397   state->starting=1; 
00398 
00399 D3(fprintf (debug_file,"1: state->cirbuf_rp=0x%x\n",state->cirbuf_rp));
00400   if ((state->cirbuf_rp <0) || (lseek(state->fd_circ,state->cirbuf_rp,SEEK_SET) < 0) || (lseek(state->fd_circ,CIRCLSEEK_VALID,SEEK_END) < 0 )) {
00401 D3(fprintf (debug_file,"2: state->cirbuf_rp=0x%x\n",state->cirbuf_rp));
00402     state->cirbuf_rp=lseek(state->fd_circ,CIRCLSEEK_LAST,SEEK_END);
00403     if (((fp=lseek(state->fd_circ,CIRCLSEEK_PREV,SEEK_END)))>=0) state->cirbuf_rp=fp; 
00404     state->buf_overruns++;
00406 //    state->buf_min=lseek(state->fd_circ,CIRCLSEEK_FREE,SEEK_END);
00407 //    lseek(state->fd_circ,state->cirbuf_rp,SEEK_SET); //! restore after moving (side effect)
00408     state->buf_min=imageParamsR[P_FREECIRCBUF];
00409 
00410   } else {
00411 //      b_free=lseek(state->fd_circ,CIRCLSEEK_FREE,SEEK_END);
00412 //      lseek(state->fd_circ,state->cirbuf_rp,SEEK_SET); //! restore after moving (side effect)
00413 //      if (state->buf_min > b_free) state->buf_min=b_free;
00414       if (state->buf_min > imageParamsR[P_FREECIRCBUF]) state->buf_min=imageParamsR[P_FREECIRCBUF];
00415 
00416   }
00417 D3(fprintf (debug_file,"3: state->cirbuf_rp=0x%x\n",state->cirbuf_rp));
00418 D3(fprintf (debug_file,"4:lseek(state->fd_circ,CIRCLSEEK_READY,SEEK_END)=%d\n",(int) lseek(state->fd_circ,CIRCLSEEK_READY,SEEK_END)));
00419 
00421   if (lseek(state->fd_circ,CIRCLSEEK_READY,SEEK_END) <0) return -CAMOGM_FRAME_NOT_READY; 
00422 D3(fprintf (debug_file,"5: state->cirbuf_rp=0x%x\n",state->cirbuf_rp));
00423   state->metadata_start=(state->cirbuf_rp)-32;
00424   if (state->metadata_start<0) state->metadata_start+=state->circ_buff_size;
00425 
00427 
00428   memcpy (&(state->frame_params), (unsigned long * ) &ccam_dma_buf[state->metadata_start>>2],32);
00429   state->jpeg_len=state->frame_params.frame_length; 
00430 
00431 
00432   if (state->frame_params.signffff !=0xffff) {
00433     D0(fprintf(debug_file, "%s:%d: wrong signature - %d\r\n",__FILE__,__LINE__,(int) state->frame_params.signffff));
00434      state->cirbuf_rp=-1;
00435      D1(fprintf(debug_file, "state->cirbuf_rp=0x%x\r\n",(int) state->cirbuf_rp));
00436      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]));
00437      return -CAMOGM_FRAME_BROKEN;
00438   }
00441   timestamp_start=(state->cirbuf_rp)+((state->jpeg_len+CCAM_MMAP_META+3) & (~0x1f)) + 32 - CCAM_MMAP_META_SEC; 
00442   if (timestamp_start >= state->circ_buff_size) timestamp_start-=state->circ_buff_size;
00443   memcpy (&(state->frame_params.timestamp_sec), (unsigned long * ) &ccam_dma_buf[timestamp_start>>2],8);
00444 
00446   if ((lseek(state->fd_circ,CIRCLSEEK_NEXT,SEEK_END) < 0 ) ||
00448       (((fp=lseek(state->fd_circ,CIRCLSEEK_READY,SEEK_END))) < 0)) {
00449         lseek(state->fd_circ,state->cirbuf_rp,SEEK_SET); 
00450         return -CAMOGM_FRAME_NOT_READY; 
00451   }
00452   next_metadata_start=fp-32;
00453   if (next_metadata_start<0) next_metadata_start+= state->circ_buff_size;
00454   memcpy (&(state->this_frame_params), (unsigned long * ) &ccam_dma_buf[next_metadata_start>>2],32);
00455   next_jpeg_len=state->this_frame_params.frame_length; 
00456   if (state->this_frame_params.signffff !=0xffff) { 
00457      D0(fprintf(debug_file, "%s:%d: wrong signature - %d\r\n",__FILE__,__LINE__,(int) state->this_frame_params.signffff));
00458      D1(fprintf(debug_file, "fp=0x%x\r\n",(int) fp));
00459      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]));
00460 //  int * ifp =      (int *) &(state->this_frame_params) ;
00461 //  int * ifp_this = (int *) &(state->this_frame_params) ;
00462 
00463      state->cirbuf_rp=-1;
00464      return -CAMOGM_FRAME_BROKEN;
00465   }
00467   timestamp_start=fp+((next_jpeg_len+CCAM_MMAP_META+3) & (~0x1f)) + 32 - CCAM_MMAP_META_SEC; 
00468   if (timestamp_start >= state->circ_buff_size) timestamp_start-=state->circ_buff_size;
00469   memcpy (&(state->this_frame_params.timestamp_sec), (unsigned long * ) &ccam_dma_buf[timestamp_start>>2],8);
00471   if ((state->frame_params.width  != state->this_frame_params.width) ||
00472       (state->frame_params.height != state->this_frame_params.height)) {
00474      state->cirbuf_rp=fp;
00475      return -CAMOGM_FRAME_CHANGED; // no yet checking for the FPS
00476   }
00478    state->frame_period=(state->this_frame_params.timestamp_usec - state->frame_params.timestamp_usec)+
00479                1000000*(state->this_frame_params.timestamp_sec  - state->frame_params.timestamp_sec);
00480 
00482   state->frames_skip=      state->set_frames_skip;
00483   if (state->frames_skip > 0) {
00484     state->frames_skip_left=0;
00485     state->frame_period *= (state->frames_skip+1);
00486 //    state->frames_skip_left= state->set_frames_skip;
00487   } else if (state->frames_skip < 0) {
00488     state->frame_period=-(state->frames_skip) ; 
00489     state->frames_skip_left=state->frame_params.timestamp_sec;
00490   }
00491    state->time_unit= (ogg_int64_t) (((double) state-> frame_period) * ((double) 10) / ((double) state-> timescale));
00492    state->width=state->frame_params.width;
00493    state->height=state->frame_params.height;
00494 
00497    lseek(state->fd_head,state->cirbuf_rp+1,SEEK_END); 
00498 
00499    lseek(state->fd_head,0,0);
00500    read (state->fd_head,state->jpegHeader,state->head_size);
00502    lseek(state->fd_circ,state->cirbuf_rp,SEEK_SET);
00504         audio_start(by_command);
00505    switch (state->format) {
00506     case CAMOGM_FORMAT_NONE: rslt= 0;  break;
00507     case CAMOGM_FORMAT_OGM:  rslt= camogm_start_ogm();  break;
00508     case CAMOGM_FORMAT_JPEG: rslt= camogm_start_jpeg(); break;
00509     case CAMOGM_FORMAT_MOV:  rslt= camogm_start_mov();  break;
00510     default: rslt=0; // do nothing
00511    }
00512    if (rslt) return rslt;
00513    if (state->kml_enable) rslt=camogm_start_kml() ; // will turn on state->kml_used if it can
00514    if (rslt) return rslt;
00515    state->running=1;
00516    state->starting=0;
00517    D1(fprintf (debug_file,"Started OK\n"));
00518    return 0;
00519 }
00520 
00521 struct timeval v_ts;
00522 
00523 int sendImageFrame(void) {
00524         int rslt;
00525 //      struct frame_params_t this_frame_params;
00526 //      elph_packet_chunk packetchunks[7];
00527         unsigned char frame_packet_type = PACKET_IS_SYNCPOINT;
00528 //      int chunk_index=0;
00529 //      int i;
00530 //      unsigned long * tts= (unsigned long *) &(state->granulepos); //to word-swap timestamt to granule
00531         int timestamp_start;
00532 // debugging:
00533 //      int * ifp =      (int *) &(state->frame_params) ;
00534         int * ifp_this = (int *) &(state->this_frame_params) ;
00535 
00536         struct timeval ts;
00537 
00538         // This is probably needed only for Quicktime (not to exceed already allocated frame index)
00539         if(state->frameno >= (state->max_frames)) {
00540 fprintf(stderr, "--------------------> there is not enough frames...");
00541                 return -CAMOGM_FRAME_CHANGED;
00542         }
00543         // Format changed?
00544 //      D3(fprintf (debug_file,"sendImageFrame: format=%d, set_format=%d\n", state->format, state->set_format));
00545 
00546         if(state->format != state->set_format)
00547                 return -CAMOGM_FRAME_CHANGED;
00548         // check if file size is exceeded (assuming fopen),-CAMOGM_FRAME_CHANGED will trigger a new segment
00549 //      if((state->vf) && (state->segment_length >= 0) && (ftell(state->vf) > state->segment_length))
00550         if((state->vf) && (state->segment_length >= 0) && (lseek(state->vf, 0, SEEK_CUR) > state->segment_length))
00551                 return -CAMOGM_FRAME_CHANGED;
00552         // same for open
00553         if(((state->ivf) >= 0) && (state->segment_length >= 0) && (lseek(state->ivf, 0, SEEK_CUR) > state->segment_length))
00554                 return -CAMOGM_FRAME_CHANGED;
00555         // check the frame pointer is valid
00556         if(lseek(state->fd_circ, state->cirbuf_rp, SEEK_SET) < 0)
00557                 return -CAMOGM_FRAME_INVALID; 
00558         // is the frame ready?
00559         if(lseek(state->fd_circ, CIRCLSEEK_READY, SEEK_END) < 0)
00560                 return -CAMOGM_FRAME_NOT_READY; 
00561 
00562         // process skipping frames. TODO: add - skipping time between frames (or better -  actual time period - use the nearest frame) instead of the frame number
00563         if((state->frames_skip > 0) && (state->frames_skip_left > 0)) { 
00564                 state->cirbuf_rp = lseek(state->fd_circ, CIRCLSEEK_NEXT, SEEK_END);
00565                 // optionally save it to global read pointer (i.e. for debugging with imgsrv "/pointers")
00566                 if(state->save_gp)
00567                         lseek(state->fd_circ, CIRCLSEEK_SETP, SEEK_END);
00568                 state->frames_skip_left--;
00569                 return -CAMOGM_FRAME_NOT_READY; 
00570         }
00571 
00572         // Get metadata
00573 //      D3(fprintf (debug_file,"_1_"));
00574         state->metadata_start = state->cirbuf_rp - 32;
00575         if(state->metadata_start < 0)
00576                 state->metadata_start += state->circ_buff_size;
00577         memcpy(&(state->this_frame_params), (unsigned long *)&ccam_dma_buf[state->metadata_start >> 2], 32);
00578         state->jpeg_len = state->this_frame_params.frame_length; 
00579         if(state->this_frame_params.signffff != 0xffff) {
00580                 D0(fprintf(debug_file, "%s:%d: wrong signature - %d\r\n",__FILE__,__LINE__,(int) state->this_frame_params.signffff));
00581                 D1(fprintf(debug_file, "state->cirbuf_rp=0x%x\r\n",(int) state->cirbuf_rp));
00582                 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]));
00583                 return -CAMOGM_FRAME_BROKEN;
00584         }
00585 //      D3(fprintf (debug_file,"_2_"));
00586         // find location of the timestamp and copy it to the frame_params structure
00587         timestamp_start = state->cirbuf_rp + ((state->jpeg_len + CCAM_MMAP_META + 3) & (~0x1f)) + 32 - CCAM_MMAP_META_SEC; 
00588         if(timestamp_start >= state->circ_buff_size)
00589                 timestamp_start -= state->circ_buff_size;
00590 //      D3(fprintf (debug_file,"_3_"));
00591         memcpy(&(state->this_frame_params.timestamp_sec), (unsigned long *)&ccam_dma_buf[timestamp_start >> 2], 8);
00592 
00593         ts.tv_sec = state->this_frame_params.timestamp_sec;
00594         ts.tv_usec = state->this_frame_params.timestamp_usec;
00595 
00596         // verify that the essential current frame params did not change, if they did - return an error (need new file header) 
00597         if((state->frame_params.width != state->this_frame_params.width) || (state->frame_params.height != state->this_frame_params.height))
00598                 return -CAMOGM_FRAME_CHANGED; 
00599         // check if file duration (in seconds) exceeded ,-CAMOGM_FRAME_CHANGED will trigger a new segment
00600         if((state->segment_duration > 0) && ((state->this_frame_params.timestamp_sec - state->frame_params.timestamp_sec) > state->segment_duration)) {
00601 fprintf(stderr, "!!! close file !!! \n");
00602                 return -CAMOGM_FRAME_CHANGED;
00603         }
00604         // check if (in timelapse mode)  it is too early for the frame to be stored
00605         if((state->frames_skip < 0) && (state->frames_skip_left > state->this_frame_params.timestamp_sec)) {
00606                 state->cirbuf_rp = lseek(state->fd_circ, CIRCLSEEK_NEXT, SEEK_END);
00607                 // optionally save it to global read pointer (i.e. for debugging with imgsrv "/pointers")
00608                 if(state->save_gp)
00609                         lseek(state->fd_circ, CIRCLSEEK_SETP, SEEK_END);
00610                 return -CAMOGM_FRAME_NOT_READY; 
00611         }
00612 
00613 
00614 //      D3(fprintf (debug_file,"_4_"));
00615         if(state->exif) {
00616                 D3(fprintf(debug_file,"_5_"));
00617                 // update the Exif header with the current frame metadata
00618 //              updateExif(ep, state->ed, &(state->frame_params));
00619                 state->exifSize = lseek(state->fd_exif, 1, SEEK_END); // at the beginning of page 1 - position == page length
00620 //              if(state->exifSize < 0) state->exifSize = 0; // error from lseek;
00621                 if(state->exifSize > 0) {
00622 //                      state->this_frame_params.meta_index
00623                         lseek(state->fd_exif, state->this_frame_params.meta_index, SEEK_END); 
00624                         rslt = read(state->fd_exif, state->ed, state->exifSize);
00625                         if(rslt < 0)
00626                                 rslt = 0;
00627                         state->exifSize = rslt;
00628                 } else {
00629                         state->exifSize = 0;
00630                 }
00631         } else {
00632                 state->exifSize = 0;
00633         }
00634 
00635 //      D3(fprintf (debug_file,"_6_"));
00636 
00637         // prepare a packet to be sent (a lst of memory chunks)
00638         state->chunk_index=0;
00639         state->packetchunks[state->chunk_index  ].bytes=1;
00640         state->packetchunks[state->chunk_index++].chunk=&frame_packet_type;
00641         if(state->exif > 0) {
00642 //              D3(fprintf (debug_file,"_7_"));
00643                 state->packetchunks[state->chunk_index  ].bytes = 2;
00644                 state->packetchunks[state->chunk_index++].chunk = state->jpegHeader;
00645                 state->packetchunks[state->chunk_index  ].bytes = state->exifSize;
00646                 state->packetchunks[state->chunk_index++].chunk = state->ed;
00647                 state->packetchunks[state->chunk_index  ].bytes = state->head_size - 2;
00648                 state->packetchunks[state->chunk_index++].chunk = &(state->jpegHeader[2]);
00649         } else {
00650 //              D3(fprintf (debug_file,"_8_"));
00651                 state->packetchunks[state->chunk_index  ].bytes = state->head_size;
00652                 state->packetchunks[state->chunk_index++].chunk = state->jpegHeader;
00653         }
00654 //      D3(fprintf (debug_file,"_9_"));
00655 
00656         // JPEG image data may be split in two segments (rolled over buffer end) - process both variants
00657 //      if((jpeg_start + jpeg_len) > state->circ_buff_size) { // two segments
00658         if((state->cirbuf_rp + state->jpeg_len) > state->circ_buff_size) { 
00659                 // copy from the beginning of the frame to the end of the buffer
00660 //              D3(fprintf (debug_file,"_10_"));
00661 //              sendBuffer((void *) &ccam_dma_buf[jpeg_start>>2], state->circ_buff_size-state->cirbuf_rp);
00662                 state->packetchunks[state->chunk_index  ].bytes = state->circ_buff_size-state->cirbuf_rp;
00663                 state->packetchunks[state->chunk_index++].chunk = (unsigned char*) &ccam_dma_buf[state->cirbuf_rp >> 2];
00664                 // copy from the beginning of the buffer to the end of the frame
00665 //              sendBuffer((void *) &ccam_dma_buf[0], jpeg_len-(state->circ_buff_size-state->cirbuf_rp));
00666                 state->packetchunks[state->chunk_index  ].bytes = state->jpeg_len - (state->circ_buff_size - state->cirbuf_rp);
00667                 state->packetchunks[state->chunk_index++].chunk = (unsigned char*) &ccam_dma_buf[0];
00668         } else { // single segment
00669 //              D3(fprintf (debug_file,"_11_"));
00670                 // copy from the beginning of the frame to the end of the frame (no buffer rollovers)
00671 //              sendBuffer((void *) &ccam_dma_buf[state->cirbuf_rp>>2], state->jpeg_len);
00672                 state->packetchunks[state->chunk_index  ].bytes = state->jpeg_len;
00673                 state->packetchunks[state->chunk_index++].chunk = (unsigned char*)  &ccam_dma_buf[state->cirbuf_rp >> 2];
00674         }
00675 //      D3(fprintf (debug_file,"_12_"));
00676         state->packetchunks[state->chunk_index  ].bytes = 2;
00677         state->packetchunks[state->chunk_index++].chunk = (unsigned char*) trailer;
00678 
00679         // synchronize audio and video here - skip video if needed...
00680         // analyze frame timestamp...
00681         long delta = ts.tv_sec - v_ts.tv_sec;
00682         delta *= 1000000;
00683         delta += ts.tv_usec;
00684         delta -= v_ts.tv_usec;
00685 //      fprintf(stderr, "timestamp: %d:%06d; delta == %06d\n", ts.tv_sec, ts.tv_usec, delta);
00686         v_ts = ts;
00687         state->ts_video = ts;
00688 
00689         int flag = 1;
00690         if(ctx_a.begin_of_stream_with_audio) {
00691                 if(ctx_a.begin_of_stream_with_audio_trigger) {
00692                         state->ts_video_start = state->ts_audio;
00693                         state->ts_video_start.tv_usec += state->frame_period / 2;
00694                         time_normalize(&state->ts_video_start);
00695                         ctx_a.begin_of_stream_with_audio_trigger = 0;
00696                         // compute how many audio samples we need to skip here
00697                         long audio_to_skip = 0;
00698                         struct timeval tv = state->ts_video;
00699                         while(time_comp(&tv, &state->ts_video_start) < 0) {
00700                                 tv.tv_usec += state->frame_period;
00701                                 time_normalize(&tv);
00702                         }
00703                         tv.tv_sec -= 1;
00704                         tv.tv_usec += 1000000;
00705                         tv.tv_usec -= state->frame_period / 2;
00706                         time_normalize(&tv);
00707                         if(tv.tv_sec != state->ts_audio.tv_sec) {
00708                                 audio_to_skip = tv.tv_sec - state->ts_audio.tv_sec;
00709                                 audio_to_skip *= 1000000;
00710                         }
00711                         audio_to_skip += tv.tv_usec;
00712                         audio_to_skip -= state->ts_audio.tv_usec;
00713                         double s = state->audio_rate;
00714                         s /= 1000.0;
00715                         s *= audio_to_skip;
00716                         s /= 1000.0;
00717                         ctx_a.audio_skip_samples = (long)s;
00718                         ctx_a.movie_start = tv;
00719 DA(                     fprintf(stderr, "____ AUDIO started from: %d:%06d; we need to record it from: %d:%06d; audio_to_skip_us == %d; audio samples to skip == %d\n", state->ts_audio.tv_sec, state->ts_audio.tv_usec, tv.tv_sec, tv.tv_usec, audio_to_skip, ctx_a.audio_skip_samples););
00720                 }
00721 DA(             fprintf(stderr, "AUDIO (start): %d:%06d; VIDEO (current): %d:%06d; frame period is: %d\n", state->ts_audio.tv_sec, state->ts_audio.tv_usec, state->ts_video.tv_sec, state->ts_video.tv_usec, state->frame_period););
00722                 if(time_comp(&state->ts_video_start, &state->ts_video) > 0) {
00723 DA(                     fprintf(stderr, "skip the video frame\n"););
00724                         flag = 0;
00725                 } else {
00726 DA(                     fprintf(stderr, "save the VIDEO frame with time: %d:%06d\n", state->ts_video.tv_sec, state->ts_video.tv_usec););
00727                         ctx_a.begin_of_stream_with_audio = 0;
00728                 }
00729         }
00730         if(flag) {
00731                 switch (state->format) {
00732                         case CAMOGM_FORMAT_NONE: rslt=0; break;
00733                         case CAMOGM_FORMAT_OGM:  rslt = camogm_frame_ogm(); break;
00734                         case CAMOGM_FORMAT_JPEG: rslt = camogm_frame_jpeg(); break;
00735                         case CAMOGM_FORMAT_MOV:  rslt = camogm_frame_mov(); break;
00736                         default: rslt = 0; // do nothing
00737                 }
00738         } else {
00739                 rslt = 0;
00740         }
00741 
00742         if(rslt)
00743                 return rslt;
00744         if(state->kml_used)
00745                 rslt = camogm_frame_kml() ; // will turn on state->kml_used if it can
00746         if(rslt)
00747                 return rslt;
00748 
00749 //      D3(fprintf (debug_file,"_14_"));
00750         // advance frame pointer
00751         if(flag)
00752                 state->frameno++;
00753         state->cirbuf_rp = lseek(state->fd_circ, CIRCLSEEK_NEXT, SEEK_END);
00754         // optionally save it to global read pointer (i.e. for debugging with imgsrv "/pointers")
00755         if(state->save_gp)
00756                 lseek(state->fd_circ, CIRCLSEEK_SETP, SEEK_END);
00757 //      D3(fprintf (debug_file,"_15_\n"));
00758 //      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),
00759 //                                                                (int) state->this_frame_params.timestamp_sec, (int)state->this_frame_params.timestamp_usec));
00760         if(state->frames_skip > 0) {
00761                 state->frames_skip_left = state->frames_skip;
00762         } else {
00763                 if(state->frames_skip < 0) {
00764                         state->frames_skip_left += -(state->frames_skip);
00765                 }
00766         }
00767         return 0;
00768 }
00769 
00770 void audio_finish(int by_command) {
00771         // finalize audio stream to file here
00772         // TODO - check the time correctly.
00773 DA(     fprintf(stderr, "here must be last push of the audio to the file\n"););
00774         struct timeval m_end;
00775 DA(     fprintf(stderr, "  movie start at: %d:%06d\n", ctx_a.movie_start.tv_sec, ctx_a.movie_start.tv_usec););
00776         m_end = state->ts_video;
00777         m_end.tv_usec += state->frame_period / 2;
00778         time_normalize(&m_end);
00779 DA(     fprintf(stderr, "    movie end at: %d:%06d\n", m_end.tv_sec, m_end.tv_usec););
00780 
00781         struct timeval m_len;
00782         if(m_len.tv_sec != ctx_a.movie_start.tv_sec) {
00783                 m_len.tv_sec = m_end.tv_sec - 1;
00784                 m_len.tv_usec = m_end.tv_usec + 1000000;
00785         }
00786         m_len.tv_sec -= ctx_a.movie_start.tv_sec;
00787         m_len.tv_usec -= ctx_a.movie_start.tv_usec;
00788         time_normalize(&m_len);
00789 DA(     fprintf(stderr, "    movie length: %d:%06d\n", m_len.tv_sec, m_len.tv_usec););
00790         ctx_a.movie_start = m_end;
00791         // calculate how many samples we need to save now for the end
00792         int fd_stream = open("/dev/ext353", O_RDWR);
00793         unsigned long rtc[4];
00794         ioctl(fd_stream, EXT_GET_TIME_SYNC, (void *)&rtc[0]);
00795         close(fd_stream);
00796 DA(     fprintf(stderr, "_________________ END ____________________\n"););
00797 DA(     fprintf(stderr, "       sys time == %d:%06d\n", rtc[0], rtc[1]););
00798 DA(     fprintf(stderr, "      FPGA time == %d:%06d\n", rtc[2], rtc[3]););
00799 DA(     fprintf(stderr, "AUDIO  sys time == %d:%06d\n", ctx_a.time_last.tv_sec, ctx_a.time_last.tv_usec););
00800         int flag = 0;
00801         struct timeval audio_last;
00802         audio_last = ctx_a.time_last;
00803         if(m_len.tv_sec > audio_last.tv_sec) {
00804                 m_len.tv_sec--;
00805                 m_len.tv_usec += 1000000;
00806         }
00807         m_len.tv_sec -= audio_last.tv_sec;
00808         m_len.tv_usec -= audio_last.tv_usec;
00809         time_normalize(&m_len);
00810         long to_finish_us = m_len.tv_usec + 1000000 * m_len.tv_sec;
00811 DA(     fprintf(stderr, "... and now we need to save audio for this time: %d:%06d - i.e. %06d usecs\n", m_len.tv_sec, m_len.tv_usec, to_finish_us););
00812         double s = state->audio_rate;
00813         s /= 1000.0;
00814         s *= to_finish_us;
00815         s /= 1000.0;
00816         ctx_a.to_finish_samples = (long)s;
00817         // from the state->tv_video_start to ctx_a.time_last (with FPGA time recalculation)
00818         do {
00819                 audio_process();
00820                 if(ctx_a.to_finish_samples > 0)
00821                         sched_yield();
00822         } while(ctx_a.to_finish_samples > 0);
00823         audio_end(by_command);
00824 }
00825 
00826 int camogm_stop(int by_command) {
00827         int rslt = 0;
00828         if(!state->running) {
00829                 if(!state->starting) {
00830                         D2(fprintf (debug_file,"Recording was not running, nothing to stop\n"));
00831                 } else {
00832                         state->starting = 0;
00833                         D1(fprintf (debug_file,"Dropping attempt to start\n"));
00834                 }
00835                 return 0;
00836         }
00837         D1(fprintf (debug_file,"Ending recording\n"));
00838         if(state->kml_used)
00839                 camogm_end_kml() ;
00840 
00841         if(ctx_a.audio_present)
00842                 audio_finish(by_command);
00843 
00844         switch(state->format) {
00845         case CAMOGM_FORMAT_NONE: rslt = 0; break;
00846         case CAMOGM_FORMAT_OGM:  rslt = camogm_end_ogm(); break;
00847         case CAMOGM_FORMAT_JPEG: rslt = camogm_end_jpeg();break;
00848         case CAMOGM_FORMAT_MOV:  rslt = camogm_end_mov(); break;
00849 //      default: return 0; // do nothing
00850         }
00851         // now close video file (if it is open)
00852         if(state->vf)
00853                 close(state->vf);
00854         state->vf = 0;
00855         if(rslt)
00856                 return rslt;
00857         state->last = 1;
00858         // state->running=0 should be output after file is finished and closed
00859         state->running = 0;
00860         state->starting = 0;
00861         return 0;
00862 }
00863 
00864 void camogm_free() {
00865         int f;
00866         // free all file format handlers that were used
00867         // add kml when needed
00868         for(f = 0; f < 31; f++) {
00869                 if(state->formats & ( 1 << (state->format))) {
00870                         switch(f) {
00871                         case CAMOGM_FORMAT_NONE: break;
00872                         case CAMOGM_FORMAT_OGM:  camogm_free_ogm(); break;
00873                         case CAMOGM_FORMAT_JPEG: camogm_free_jpeg();break;
00874                         case CAMOGM_FORMAT_MOV:  camogm_free_mov(); break;
00875                         }
00876                 }
00877         }
00878         state->formats = 0;
00879 }
00880 
00881 int camogm_reset(void) { 
00882    state->cirbuf_rp=-1;
00883    state->buf_overruns=-1; 
00884    return 0;
00885 }
00886 
00888 void  camogm_kml_set_enable(int d) {
00889    state->kml_enable=d;
00890 }
00891 void  camogm_kml_set_horHalfFov (double dd) {
00892    state->kml_horHalfFov=dd;
00893 }
00894 void  camogm_kml_set_vertHalfFov(double dd) {
00895    state->kml_vertHalfFov=dd;
00896 }
00897 void  camogm_kml_set_height_mode(int d) {
00898    state->kml_height_mode=d;
00899 }
00900 void  camogm_kml_set_height(double dd) {
00901    state->kml_height=dd;
00902 }
00903 void  camogm_kml_set_period(int d) {
00904    state->kml_period=d;
00905    state->kml_last_ts=0;
00906    state->kml_last_uts=0;
00907 }
00908 void  camogm_kml_set_near(double dd) { // distance to PhotoOverlay
00909    state->kml_near=dd;
00910 }
00911 
00912 
00913 void  camogm_set_segment_duration(int sd) {
00914    state->segment_duration=sd;
00915 }
00916 void  camogm_set_segment_length(int sl) {
00917    state->segment_length=   sl;
00918 }
00919 void  camogm_set_save_gp(int d) {
00920    state->save_gp=   d;
00921 }
00922 void  camogm_set_exif(int d) {
00923    state->exif=   d;
00924 }
00925 
00926 void  camogm_set_prefix (const char * p) {
00927   strncpy(state->path_prefix, p, sizeof(state->path_prefix)-1);
00928   state->path_prefix[sizeof(state->path_prefix)-1]='\0';
00929 }
00930 
00931 void  camogm_set_timescale(double d) { 
00932    state->set_timescale=  d;
00933    if ((state->running==0) && (state->starting==0)) {
00934      state->timescale=state->set_timescale;
00935    }
00936 }
00937 
00938 void  camogm_set_frames_skip(int d) { 
00939    state->set_frames_skip=  d;
00940    if ((state->running==0) && (state->starting==0)) {
00941      state->frames_skip=      state->set_frames_skip;
00942 //     state->frames_skip_left= state->set_frames_skip;
00943      state->frames_skip_left= 0;
00944    }
00945 }
00946 
00947 void  camogm_set_format(int d) {
00948    int rslt=0;
00949    state->set_format = d;
00950 /* set format with the "start" command
00951    if ((state->running==0) && (state->starting==0)) {
00952      state->format=  state->set_format;
00953      switch (state->format) {
00954       case CAMOGM_FORMAT_NONE: rslt= 0; break;
00955       case CAMOGM_FORMAT_OGM:  rslt= camogm_init_ogm(); break;
00956       case CAMOGM_FORMAT_JPEG: rslt= camogm_init_jpeg();break;
00957       case CAMOGM_FORMAT_MOV:  rslt= camogm_init_mov(); break;
00958      }
00959      if (rslt) {
00960        D0(fprintf (debug_file,"%s:%d: Error setting format to=%d\n",__FILE__,__LINE__, state->format));
00961      }
00962      state->formats |= 1 << (state->format);
00963    }
00964 */
00965 }
00966 
00968 void  camogm_set_max_frames(int d) {
00969    state->set_max_frames=  d;
00970    if ((state->running==0) && (state->starting==0)) state->max_frames=  d;
00971 }
00972 
00973 void  camogm_set_frames_per_chunk(int d) {
00974    state->set_frames_per_chunk=  d;
00975    if ((state->running==0) && (state->starting==0)) state->frames_per_chunk=  d;
00976 }
00977 
00978 void  camogm_status(char * fn, int xml) {
00979   int _len=0;
00980   int _dur,_udur;
00981 //TODO:make it XML file
00982   FILE* f;
00983   char *_state, *_output_format, *_using_exif, *_using_global_pointer, *_compressor_state;
00984   int _b_free, _b_used; // , save_p;
00985   int _frames_remain=0;
00986   int _sec_remain=0;
00987   int _frames_skip=0;
00988   int _sec_skip=0;
00989   char *_kml_enable, *_kml_used, *_kml_height_mode;
00990 
00991   _kml_enable=      state->kml_enable?"yes":"no";
00992   _kml_used=        state->kml_used?"yes":"no";
00993   _kml_height_mode= state->kml_height_mode?"GPS altitude":"map ground level";  
00994   char *_audio_enable, *_allow_sync;
00995   _audio_enable=      state->set_audio_enable?"yes":"no";
00996   _allow_sync=      state->set_allow_sync?"yes":"no";
00997 
00998 
00999   _b_free=imageParamsR[P_FREECIRCBUF];
01000   _b_used=imageParamsR[P_CIRCBUFSIZE]-imageParamsR[P_FREECIRCBUF];
01001 
01002   if (!fn) f=stdout;
01003   else if (strcmp(fn, "stdout")==0) f=stdout;
01004   else if (strcmp(fn, "stderr")==0) f=stderr;
01005   else {
01006     if (!((f=fopen (fn,"w")))) {
01007        D0(fprintf (debug_file,"Error opening %s\n", fn));
01008       return;
01009     }
01010   }
01011 //  if      (state->vf)       _len=ftell(state->vf); //! for ogm
01012   if      (state->vf)       _len=lseek(state->vf, 0, SEEK_CUR); 
01013   else if ((state->ivf)>=0) _len=lseek(state->ivf, 0, SEEK_CUR); 
01014   _dur= state->this_frame_params.timestamp_sec-state->frame_params.timestamp_sec;
01015   _udur=state->this_frame_params.timestamp_usec-state->frame_params.timestamp_usec;
01016   if (_udur<0) {
01017     _dur-=1;
01018     _udur+=1000000;
01019   } else if (_udur>=1000000) {
01020     _dur+=1;
01021     _udur-=1000000;
01022   }
01023   _state=         state->running? "running":(state->starting?"starting":"stopped");
01024   _output_format= state->format?((state->format==CAMOGM_FORMAT_OGM)?"ogm":
01025                                              ((state->format==CAMOGM_FORMAT_JPEG)?"jpeg":
01026                                              ((state->format==CAMOGM_FORMAT_MOV)?"mov":
01027                                               "other"))):"none";
01028   _using_exif=    state->exif?"yes":"no";
01029   _using_global_pointer=state->save_gp?"yes":"no";
01030   _compressor_state=(imageParamsR[P_CAMSEQSTATE]==CAMSEQ_RUN)?"running":
01031                      ((imageParamsR[P_CAMSEQSTATE]==CAMSEQ_SINGLE)?"acquiring":
01032                       ((imageParamsR[P_CAMSEQSTATE]==CAMSEQ_STOP)?"stoppping":
01033                        ((imageParamsR[P_CAMSEQSTATE]==CAMSEQ_JPEG)?"stopped":
01034                         ((imageParamsR[P_CAMSEQSTATE]==CAMSEQ_OFF)?"reset":"other"))));
01035     if ( state->frames_skip >0 ) {
01036       _frames_remain= state->frames_skip_left;
01037       _frames_skip=state->frames_skip;
01038     } else if ( state->frames_skip <0 ) {
01039       _sec_remain= (state->frames_skip_left - state->this_frame_params.timestamp_sec);
01040       _sec_skip=-(state->frames_skip);
01041     }
01042 
01043 
01044   if (xml) {
01045     fprintf (f,"<?xml version=\"1.0\"?>\n" \
01046              "<camogm_state>\n" \
01047              "  <state>\"%s\"</state>\n" \
01048              "  <compressor_state>\"%s\"</compressor_state>\n" \
01049              "  <file_name>\"%s\"</file_name>\n" \
01050              "  <frame_number>%d</frame_number>\n" \
01051              "  <file_duration>%d.%06d</file_duration>\n" \
01052              "  <file_length>%d</file_length>\n" \
01053              "  <frame_period>%d</frame_period>\n" \
01054              "  <frames_skip>%d</frames_skip>\n" \
01055              "  <seconds_skip>%d</seconds_skip>\n" \
01056              "  <frames_skip_left>%d</frames_skip_left>\n" \
01057              "  <seconds_skip_left>%d</seconds_skip_left>\n" \
01058              "  <frame_width>%d</frame_width>\n" \
01059              "  <frame_height>%d</frame_height>\n" \
01060              "  <format>\"%s\"</format>\n" \
01061              "  <exif>\"%s\"</exif>\n" \
01062              "  <prefix>\"%s\"</prefix>\n" \
01063              "  <max_duration>%d</max_duration>\n" \
01064              "  <max_length>%d</max_length>\n" \
01065              "  <max_frames>%d</max_frames>\n" \
01066              "  <timescale>%f</timescale>\n" \
01067              "  <frames_per_chunk>%d</frames_per_chunk>\n" \
01068              "  <buffer_overruns>%d</buffer_overruns>\n" \
01069              "  <buffer_minimal>%d</buffer_minimal>\n" \
01070              "  <buffer_free>%d</buffer_free>\n" \
01071              "  <buffer_used>%d</buffer_used>\n" \
01072              "  <circbuf_rp>%d</circbuf_rp>\n" \
01073              "  <debug_output>\"%s\"</debug_output>\n" \
01074              "  <debug_level>%d</debug_level>\n" \
01075              "  <use_global_rp>\"%s\"</use_global_rp>\n" \
01076              "  <kml_enable>\"%s\"</kml_enable>\n" \
01077              "  <kml_used>\"%s\"</kml_used>\n" \
01078              "  <kml_path>\"%s\"</kml_path>\n" \
01079              "  <kml_horHalfFov>\"%f\"</kml_horHalfFov>\n" \
01080              "  <kml_vertHalfFov>\"%f\"</kml_vertHalfFov>\n" \
01081              "  <kml_near>\"%f\"</kml_near>\n" \
01082              "  <kml_height_mode>\"%s\"</kml_height_mode>\n" \
01083              "  <kml_height>\"%f\"</kml_height>\n" \
01084              "  <kml_period>%d</kml_period>\n" \
01085              "  <kml_last_ts>%d.%06d</kml_last_ts>\n" \
01086              "  <audio_enable>\"%s\"</audio_enable>\n" \
01087              "  <audio_channels>\"%d\"</audio_channels>\n" \
01088              "  <audio_rate>\"%d\"</audio_rate>\n" \
01089              "  <allow_sync>\"%s\"</allow_sync>\n" \
01090              "</camogm_state>\n",
01091              _state,_compressor_state,state->path,state->frameno,_dur,_udur,_len,state->frame_period, \
01092              _frames_skip,_sec_skip,_frames_remain, _sec_remain, \
01093              state->width,state->height,_output_format,_using_exif, \
01094              state->path_prefix, state->segment_duration, state->segment_length, state->max_frames, state->timescale, \
01095              state->frames_per_chunk, state->buf_overruns, state->buf_min, _b_free, _b_used, state->cirbuf_rp, \
01096              state->debug_name, debug_level, _using_global_pointer, \
01097              _kml_enable,_kml_used,state->kml_path,state->kml_horHalfFov,state->kml_vertHalfFov,state->kml_near,\
01098              _kml_height_mode,state->kml_height,state->kml_period,state->kml_last_ts,state->kml_last_uts,\
01099                          _audio_enable,state->set_audio_channels,state->set_audio_rate,_allow_sync);
01100   } else {
01101     fprintf (f,"state              %s\n",        _state);
01102     fprintf (f,"compressor state   %s\n",        _compressor_state);
01103     fprintf (f,"file               %s\n",        state->path);
01104     fprintf (f,"frame              %d\n",        state->frameno);
01105     fprintf (f,"file duration      %d.%06d sec\n",_dur,_udur);
01106     fprintf (f,"file length        %d B\n",      _len);
01107     fprintf (f,"frame period       %d (0x%x)\n", state->frame_period,state->frame_period);
01108     if ( _frames_skip >0 ) fprintf (f,"frames to skip   %d (left %d)\n",_frames_skip, _frames_remain);
01109     if ( _sec_skip    <0 ) fprintf (f,"timelapse period  %d sec (remaining %d sec)\n", _sec_skip, _sec_remain);
01110     fprintf (f,"width              %d (0x%x)\n", state->width,state->width);
01111     fprintf (f,"height             %d (0x%x)\n", state->height,state->height);
01112     fprintf (f,"\n");
01113     fprintf (f,"output format      %s\n",        _output_format);
01114     fprintf (f,"using exif         %s\n",        _using_exif);
01115     fprintf (f,"path prefix:       %s\n",        state->path_prefix);
01116     fprintf (f,"max file duration: %d sec\n",    state->segment_duration);
01117     fprintf (f,"max file length:   %d B\n",      state->segment_length);
01118     fprintf (f,"max frames         %d\n",        state->max_frames);
01119     fprintf (f,"timescale          %f\n",        state->timescale);
01120     fprintf (f,"frames per chunk   %d\n",        state->frames_per_chunk);
01121     fprintf (f,"\n");
01122     fprintf (f,"buffer overruns    %d\n",        state->buf_overruns);
01123     fprintf (f,"buffer minimal     %d\n",        state->buf_min);
01124     fprintf (f,"buffer free        %d\n",        _b_free);
01125     fprintf (f,"buffer used        %d\n",        _b_used);
01126     fprintf (f,"circbuf_rp         %d (0x%x)\n", state->cirbuf_rp,state->cirbuf_rp);
01127     fprintf (f,"\n");
01128     fprintf (f,"debug output to    %s\n",        state->debug_name);
01129     fprintf (f,"debug level        %d\n",        debug_level);
01130     fprintf (f,"use global pointer %s\n",        _using_global_pointer);
01131     fprintf (f,"\n\n");
01132     fprintf (f,"kml_enable         %s\n",        _kml_enable);
01133     fprintf (f,"kml_used           %s\n",        _kml_used);
01134     fprintf (f,"kml_path           %s\n",        state->kml_path);
01135     fprintf (f,"kml_horHalfFov     %f degrees\n",state->kml_horHalfFov);
01136     fprintf (f,"kml_vertHalfFov    %f degrees\n",state->kml_vertHalfFov);
01137     fprintf (f,"kml_near           %f m\n",      state->kml_near);
01138     fprintf (f,"kml height mode    %s\n",        _kml_height_mode);
01139     fprintf (f,"kml_height (extra) %f m\n",      state->kml_height);
01140     fprintf (f,"kml_period         %d\n",        state->kml_period);
01141     fprintf (f,"kml_last_ts        %d.%06d\n",   state->kml_last_ts,state->kml_last_uts);
01142     fprintf (f,"audio_enable       %s\n",        _audio_enable);
01143     fprintf (f,"audio_channels     %d\n",        state->set_audio_channels);
01144     fprintf (f,"audio_rate         %d\n",        state->set_audio_rate);
01145     fprintf (f,"allow_sync         %s\n",        _allow_sync);
01146     fprintf (f,"\n\n");
01147 
01148   }
01149   if ((f!=stdout) && (f!=stderr)) fclose (f);
01150   if (state->buf_overruns>=0) state->buf_overruns=0; 
01151   state->buf_min=_b_free;
01152 }
01153 
01155 char * getLineFromPipe(FILE* npipe) {
01156       int fl;
01157       char * nlp;
01159       if (cmdstrt > 0) {
01161         memmove(cmdbuf, &cmdbuf[cmdstrt], sizeof(cmdbuf)- cmdstrt);
01162         cmdbufp-=cmdstrt;
01163         cmdstrt=0;
01164       }
01166       if (!cmdbufp) cmdbuf[cmdbufp]=0; 
01167 //      nlp= strchr(cmdbuf,'\n');
01168       nlp= strpbrk(cmdbuf,";\n");
01169       if (!nlp) { 
01170         fl=fread(&cmdbuf[cmdbufp], 1,sizeof(cmdbuf)-cmdbufp-1,npipe);
01171         cmdbuf[cmdbufp+fl]=0;
01173 //        nlp= strchr(&cmdbuf[cmdbufp],'\n'); //! there were no new lines before cmdbufp
01174         nlp= strpbrk(&cmdbuf[cmdbufp],";\n"); 
01175         cmdbufp+=fl; 
01176       }
01177       if (nlp) {
01178 //printf ("++nlp=%d\n", (int) (nlp-cmdbuf));
01179         nlp[0]=0;
01180         cmdstrt=nlp-cmdbuf+1;
01181 //printf ("++cmdstrt=%d\n", cmdstrt);
01182 //printf ("cmdbuf[0]=%d, cmdbuf[1]=%d, cmdbuf[2]=%d, cmdbuf[3]=%d, \n",cmdbuf[0],cmdbuf[1],cmdbuf[2],cmdbuf[3]);
01183         for (fl=0; cmdbuf[fl] && strchr(" \t",cmdbuf[fl]); fl++);
01184 //printf ("++fl=%d\n", fl);
01185         return &cmdbuf[fl];
01186       } else {
01187 //printf ("notready: cmdbufp=%d, cmdstrt=%d\n",cmdbufp, cmdstrt);
01188           return NULL;
01189       }
01190 }
01191 // command[= \t]*args[ \t]*
01192 int parse_cmd(FILE* npipe) {
01193   char * cmd;
01194   char * args;
01195   char * argse;
01196   int d;
01197   double dd;
01198 //  if (!((cmd=getLineFromPipe(npipe)))) return 0; //! nothing in the pipe
01200   while(((cmd=getLineFromPipe(npipe))) && !cmd[0]) ;
01201   if (!cmd) return 0; 
01202 //  printf ("cmd[0]=%d:%s\n",(int) cmd[0],cmd);
01203   args=strpbrk(cmd,"= \t");
01205   if (args) {
01206     args[0]=0;
01207     args++;
01208     while (strchr("= \t",args[0])) args++;
01209     if (args[0]) {
01211       for (argse=strchr(args,'\0')-1; strchr("= \t",argse[0]);argse--) argse[0]='\0';
01212     }
01213     if (!args[0]) args=NULL;
01214   }
01216   if      (strcmp(cmd, "start")==0) {
01217      camogm_start(1);
01218      return 1;
01219   } else if (strcmp(cmd, "reset")==0) { 
01220      camogm_reset();
01221      return 2;
01222   } else if (strcmp(cmd, "stop")==0) {
01223      camogm_stop(1);
01224      return 3;
01225   } else if (strcmp(cmd, "exit")==0) { 
01226      camogm_stop(1);
01227      camogm_free();
01228      exit (0);
01229   } else if (strcmp(cmd, "duration")==0) {
01230      if (!(args) || (((d= strtol(args, NULL, 10)))<=0)) d=DEFAULT_DURATION;
01231      camogm_set_segment_duration(d);
01232      return 4;
01233   } else if (strcmp(cmd, "length")==0) {
01234      if (!(args) || (((d= strtol(args, NULL, 10)))<=0)) d=DEFAULT_LENGTH;
01235      camogm_set_segment_length(d);
01236      return 5;
01237   } else if (strcmp(cmd, "prefix")==0) {
01238      if (args) camogm_set_prefix (args);
01239      return 6;
01240   } else if (strcmp(cmd, "status")==0) { 
01241      camogm_status(args, 0);
01242      return 7;
01243   } else if (strcmp(cmd, "xstatus")==0) { 
01244      camogm_status(args, 1);
01245      return 7;
01246   } else if (strcmp(cmd, "save_gp")==0) {
01247      if ((args) && (((d= strtol(args, NULL, 10)))>=0)) camogm_set_save_gp(d);
01248      return 8;
01249   } else if (strcmp(cmd, "exif")==0) {
01250      if ((args) && (((d= strtol(args, NULL, 10)))>=0)) camogm_set_exif(d);
01251      return 8;
01252   } else if (strcmp(cmd, "debug")==0) {
01253      camogm_debug(args);
01254      return 9;
01255   } else if (strcmp(cmd, "timescale")==0) {
01256      dd= strtod(args,NULL);
01257      camogm_set_timescale(dd?dd:1.0);
01258      return 10;
01261 
01262 
01263   } else if (strcmp(cmd, "frameskip")==0) {
01264      d= strtol(args, NULL, 10);
01265      camogm_set_frames_skip(d);
01266      return 11;
01267   } else if (strcmp(cmd, "timelapse")==0) { 
01268      d= strtol(args, NULL, 10);
01269      camogm_set_frames_skip(-d);
01270      return 11;
01271   } else if (strcmp(cmd, "format")==0) {
01272      if (args) {
01273       if      (strcmp(args,  "none")==0) camogm_set_format(0);
01274       else if ((strcmp(args, "ogm" )==0) || (strcmp(args, "ogg")==0)) camogm_set_format(CAMOGM_FORMAT_OGM);
01275       else if ((strcmp(args, "jpeg")==0) || (strcmp(args, "jpg")==0)) camogm_set_format(CAMOGM_FORMAT_JPEG);
01276       else if (strcmp(args,  "mov" )==0)                              camogm_set_format(CAMOGM_FORMAT_MOV);
01277      }
01278      return 12;
01279   } else if (strcmp(cmd, "debuglev")==0) {
01280      d= strtol(args, NULL, 10);
01281      camogm_debug_level(d?d:0);
01282      return 13;
01283   } else if (strcmp(cmd, "kml")==0) {
01284      if ((args) && (((d= strtol(args, NULL, 10)))>=0)) camogm_kml_set_enable(d);
01285      return 14;
01286   } else if (strcmp(cmd, "kml_hhf")==0) {
01287      dd= strtod(args,NULL);
01288      camogm_kml_set_horHalfFov(dd);
01289      return 15;
01290   } else if (strcmp(cmd, "kml_vhf")==0) {
01291      dd= strtod(args,NULL);
01292      camogm_kml_set_vertHalfFov(dd);
01293      return 16;
01294   } else if (strcmp(cmd, "kml_near")==0) {
01295      dd= strtod(args,NULL);
01296      camogm_kml_set_near(dd);
01297      return 17;
01298   } else if (strcmp(cmd, "kml_alt")==0) {
01299      if (args) {
01300       if      (strcmp(args, "gps"   )==0) camogm_kml_set_height_mode(1);
01301       else if (strcmp(args, "ground")==0) camogm_kml_set_height_mode(0);
01302      }
01303      return 18;
01304   } else if (strcmp(cmd, "kml_height")==0) {
01305      dd= strtod(args,NULL);
01306      camogm_kml_set_height(dd);
01307      return 19;
01308   } else if (strcmp(cmd, "kml_period")==0) {
01309      d= strtol(args, NULL, 10);
01310      camogm_kml_set_period(d?d:1);
01311      return 20;
01312   } else if (strcmp(cmd, "audio")==0) {
01313      if (args) {
01314                 camogm_set_audio_state(args);
01315      }
01316      return 21;
01317   } else if (strcmp(cmd, "audio_format")==0) {
01318      if (args) {
01319                 camogm_set_audio_format(args);
01320      }
01321      return 22;
01322   } else if (strcmp(cmd, "allow_sync")==0) {
01323      if (args) {
01324                 camogm_set_sync_state(args);
01325      }
01326      return 23;
01327   }
01328 
01329   return -1;
01330 }
01331 
01332 int main(int argc, char *argv[])
01333 {
01334    const char circbufFileName[]="/dev/circbuf";
01335 //     int fd_circ;
01336    FILE * cmd_file;
01337 debug_file = stderr;
01338    const char usage[]=   "This program allows recording of the video/images acquired by Elphel camera to the storage media.\n" \
01339                          "It is designed to run in the background and accept commands through a named pipe.\n\n" \
01340                          "Usage:\n\n" \
01341                          "%s <named_pipe_name>\n\n" \
01342                          "i.e.:\n\n" \
01343                          "%s /var/state/camogm_cmd\n\n" \
01344                          "When the program is runninig you may send commands by writing strings to the command file\n" \
01345                          "(/var/state/camogm_cmd in the example above). The complete list of available commands is available\n" \
01346                          "on Elphel Wiki (http://wiki.elphel.com/index.php?title=Camogm), here is the example of usage\n" \
01347                          "from the shell prompt in the camera:\n\n" \
01348                          "echo \"status; exif=1; format=jpeg;status=/var/tmp/camogm.status\" > /var/state/camogm_cmd\n\n" \
01349                          "That will print status information on the standard output (may not be visible if the program was not\n" \
01350                          "started from the same session), set exif mode on (each frame will have the full Exif header including\n" \
01351                          "a precise time stamp), set output format to a series of individual JPEG files, and then send status\n" \
01352                          "information to a file /var/tmp/camogm.status in the camera file system.\n\n" \
01353                          "This program does not control the process of acquisition of the video/images to the camera internal\n" \
01354                          "buffer, it only retrieves that data from the buffer (waiting when needed), packages it to selected\n" \
01355                          "format and stores the result files.\n\n";
01356    int go=1;
01357    int cmd;
01358    int i,rslt;
01359    state= &sstate; //extern
01361    if ((argc < 2) || (argv[1][1]=='-'))  { 
01362      printf (usage,argv[0],argv[0]);
01363      return 0;
01364    }
01365    camogm_init();
01366 
01368    state->fd_exif = open(ExifFileName, O_RDONLY);
01369    if (state->fd_exif<0) { // check control OK
01370      D0(fprintf (debug_file,"Error opening %s\n", ExifFileName));
01371      return -1;
01372    }
01373 
01375    state->fd_head = open(HeadFileName, O_RDWR);
01376    if (state->fd_head<0) { // check control OK
01377      D0(fprintf (debug_file,"Error opening %s\n", HeadFileName));
01378      return -1;
01379    }
01380    state->head_size=lseek(state->fd_head,0,SEEK_END);
01381    if (state->head_size>JPEG_HEADER_SIZE) {
01382      D0(fprintf (debug_file,"%s:%d: Too big JPEG header (%d > %d)",__FILE__,__LINE__,state->head_size, JPEG_HEADER_SIZE ));
01383      return -2;
01384    }
01385 
01387    state->fd_circ = open(circbufFileName, O_RDWR);
01388    if (state->fd_circ<0) { // check control OK
01389       D0(fprintf (debug_file,"Error opening %s\n", circbufFileName));
01390       return -2;
01391    }
01393    state->circ_buff_size=lseek(state->fd_circ,0,SEEK_END);
01394    ccam_dma_buf = (unsigned long *) mmap(0, state->circ_buff_size, PROT_READ, MAP_SHARED, state->fd_circ, 0);
01395    if((int)ccam_dma_buf == -1) {
01396      D0(fprintf (debug_file,"Error in mmap of %s\n",circbufFileName));
01397 //     close (fd_head);
01398      close(state->fd_circ);
01399      return -3;
01400    }
01401 
01403 
01405    state->fd_sens = open(SensParsFileName, O_RDWR);
01406    if (state->fd_sens<0) { // check control OK
01407       D0(fprintf (debug_file,"Error opening %s\n", SensParsFileName));
01408       return -2;
01409    }
01411    state->senspars_size=lseek(state->fd_sens,0,SEEK_END);
01412    imageParamsR = (unsigned long *) mmap(0, state->senspars_size, PROT_READ, MAP_SHARED, state->fd_sens, 0);
01413    if((int)imageParamsR == -1) {
01414      D0(fprintf (debug_file,"Error in mmap of %s\n",SensParsFileName));
01415      close(state->fd_sens);
01416      close(state->fd_circ);
01417      return -3;
01418    }
01419 
01420 
01421 
01424    i=unlink (argv[1]);
01425    if (i) {
01426        D1(fprintf (debug_file,"Unlink %s returned %d, errno=%d \n", argv[1], i, errno));
01427    }
01428    i=mkfifo(argv[1], 0777); //EEXIST
01430    if (i) {
01431     if (errno==EEXIST) {
01432        D1(fprintf (debug_file,"Named pipe %s already exists, will use it.\n", argv[1]));
01433     } else {
01434        D0(fprintf (debug_file,"Can not create a named pipe %s, errno=%d \n", argv[1], errno));
01435        return -4;
01436     }
01437    }
01438 
01441    if (!((cmd_file=fopen(argv[1],"r")))) {
01442      D0(fprintf (debug_file,"Can not open command file %s\n",argv[1]));
01443      return -5;
01444    }
01445    D1(fprintf (debug_file,"Pipe %s open for reading\n",argv[1]));
01446 
01448 #define COMMAND_LOOP_DELAY 500000 //0.5sec
01449  
01450         while(go) {
01451 //              D3(fprintf (debug_file,"%s:%d: format=%d, set_format=%d\n",__FILE__,__LINE__, state->format, state->set_format));
01453                 cmd = parse_cmd(cmd_file);
01454                 if(cmd) {
01455                         if(cmd < 0)
01456                                 D0(fprintf(debug_file,"Unrecognized command\n"));
01457                 } else {
01458                         if(state->running) {
01459                                 // process audio, if needed (really, check presence at this function)
01460 //                              audio_process();
01461 
01462                                 // no commands in queue, started 
01463 //                              D3(fprintf (debug_file,"%s:%d: format=%d, set_format=%d\n",__FILE__,__LINE__, state->format, state->set_format));
01464                                 switch((rslt = -sendImageFrame())) {
01465                                 case 0:
01466                                         audio_process();
01467 /*
01468                                         D3(fprintf (debug_file,"%s:line %d - sendImageFrame() returned %d\n" \
01469                                                 "state->cirbuf_rp= 0x%x\n",__FILE__,__LINE__,rslt,state->cirbuf_rp));
01470 */
01471                                         break; 
01472                                 case CAMOGM_FRAME_NOT_READY:        
01473 //                                      audio_process();
01476 //     D3(fprintf (debug_file,"%s:line %d - sendImageFrame() returned -%d\n",__FILE__,__LINE__,rslt));
01477 /*
01478      D3(fprintf (debug_file,"%s:line %d - sendImageFrame() returned -%d\n" \
01479                                   "state->cirbuf_rp= 0x%x\n",__FILE__,__LINE__,rslt,state->cirbuf_rp));
01480 */
01481                                         lseek(state->fd_circ,CIRCLSEEK_WAIT,SEEK_END);
01482                                         break;
01483                                 case CAMOGM_FRAME_CHANGED:   
01484                                 case CAMOGM_FRAME_NEXTFILE:  
01485                                 case CAMOGM_FRAME_INVALID:   
01486                                 case CAMOGM_FRAME_BROKEN:    
01487 
01488 //     D3(fprintf (debug_file,"%s:line %d - sendImageFrame() returned -%d\n",__FILE__,__LINE__,rslt));
01489 fprintf(stderr, "broken frame - restart of sequence...\n");
01490                                         camogm_stop(0);
01491                                         camogm_start(0);
01492                                         break;
01493                                 case CAMOGM_FRAME_FILE_ERR:  
01494                                 case CAMOGM_FRAME_OTHER:     
01495                                         D0(fprintf (debug_file,"%s:line %d - error=%d\n",__FILE__,__LINE__,rslt));
01496                                         break;
01497                                 default:
01498                                         D0(fprintf (debug_file,"%s:line %d - should not get here (rslt=%d)\n",__FILE__,__LINE__,rslt));
01499                                         exit (-1);
01500                                 } //switch
01501 if(rslt != 0 && rslt != CAMOGM_FRAME_NOT_READY) {
01502 fprintf(stderr, "loosed frame...\n");
01503 }
01504                         } else {
01505                                 if(state->starting) { 
01506 //   D3(fprintf (debug_file,"%s:%d: format=%d, set_format=%d\n",__FILE__,__LINE__, state->format, state->set_format));
01507 
01509                                         switch ((rslt = -camogm_start(1))) {
01510                                         case 0:
01511                                                 break; 
01512                                         case CAMOGM_FRAME_NOT_READY:        
01513 
01514 
01515 //                lseek(state->fd_circ,CIRCLSEEK_WAIT,SEEK_END);
01516                                         case CAMOGM_FRAME_CHANGED:   
01517                                         case CAMOGM_FRAME_NEXTFILE:
01518                                         case CAMOGM_FRAME_INVALID:   
01519                                         case CAMOGM_FRAME_BROKEN:    
01520 //     D3(fprintf (debug_file,"%s:line %d - camogm_start() returned -%d,  state->cirbuf_rp= 0x%x\n", __FILE__,__LINE__,rslt,state->cirbuf_rp));
01521                                                 usleep( COMMAND_LOOP_DELAY) ; 
01522                                                 break;
01523                                         case CAMOGM_FRAME_FILE_ERR:  
01524                                         case CAMOGM_FRAME_OTHER:     
01525                                                 D0(fprintf (debug_file,"%s:line %d - error=%d\n",__FILE__,__LINE__,rslt));
01526                                                 break;
01527                                         default:
01528                                                 D0(fprintf (debug_file,"%s:line %d - should not get here (rslt=%d)\n",__FILE__,__LINE__,rslt));
01529                                                 exit (-1);
01530                                         } //switch
01531                                 } else { 
01532                                         usleep( COMMAND_LOOP_DELAY) ; 
01533                                 }
01534                         }
01535                 }
01536         }
01537         return 0;
01538 }
01539 
01540 /*******************************************************************************
01541  *
01542  * audio
01543  *
01544  */
01545 
01546 void camogm_set_audio_state(char *args) {
01547         if(strcmp(args, "on") == 0 || strcmp(args, "enable") == 0) {
01548                 state->set_audio_enable = 1;
01549         }
01550         if(strcmp(args, "off") == 0 || strcmp(args, "disable") == 0) {
01551                 state->set_audio_enable = 0;
01552         }
01553 DA(     fprintf(stderr, "request for audio state: %s\n", args););
01554 }
01555 
01556 void camogm_set_sync_state(char *args) {
01557         if(strcmp(args, "on") == 0 || strcmp(args, "enable") == 0) {
01558                 state->set_allow_sync = 1;
01559         }
01560         if(strcmp(args, "off") == 0 || strcmp(args, "disable") == 0) {
01561                 state->set_allow_sync = 0;
01562         }
01563 }
01564 
01565 void camogm_set_audio_format(char *args) {
01566         char buf[8];
01567         int i;
01568         int channels = -1;
01569         int rate = -1;
01570         char *right = strstr(args, "/");
01571         if(right != NULL) {
01572                 channels = atol(&right[1]);
01573                 if(channels < AUDIO_CHANNELS_MIN)
01574                         channels = AUDIO_CHANNELS_MIN;
01575                 if(channels > AUDIO_CHANNELS_MAX)
01576                         channels = AUDIO_CHANNELS_MAX;
01577                 state->set_audio_channels = channels;
01578         }
01579         for(i = 0; i < 7; i++) {
01580                 if(args[i] != '\0' && args[i] != '/')
01581                         buf[i] = args[i];
01582                 else
01583                         break;
01584         }
01585         buf[i] = '\0';
01586         if(buf[0] != '\0') {
01587                 rate = atol(buf);
01588                 if(rate < AUDIO_RATE_MIN)
01589                         rate = AUDIO_RATE_MIN;
01590                 if(rate > AUDIO_RATE_MAX)
01591                         rate = AUDIO_RATE_MAX;
01592                 state->set_audio_rate = rate;
01593         }
01594 
01595 DA(     fprintf(stderr, "request for audio format: %s; after apply: rate == %d; channels == %d\n", args, state->set_audio_rate, state->set_audio_channels););
01596 }
01597 
01598 void camogm_audio_initialize(void) {
01599         ctx_a.audio_present = 0;
01600         ctx_a.audio_set = 0;
01601         ctx_a.capture_handle = NULL;
01602         ctx_a.sbuffer = NULL;
01603         ctx_a.sample_time = 200; // ms
01604 }
01605 
01606 void audio_process(void) {
01607         if(ctx_a.audio_present == 0)
01608                 return;
01609         if(state->format == CAMOGM_FORMAT_JPEG)
01610                 return;
01611 /*
01612         if(state->format == CAMOGM_FORMAT_JPEG) {
01613                 int slen;
01614                 int _len = 0;
01615                 while((slen = snd_pcm_readi(ctx_a.capture_handle, ctx_a.sbuffer, ctx_a.sbuffer_len)) > 0) {
01616                         wave_push((void *)ctx_a.sbuffer, slen * 2 * state->audio_channels);
01617                         _len += slen;
01618                 }
01619                 fprintf(stderr, "process == %d bytes, request == %d bytes\n", _len, ctx_a.sbuffer_len);
01620         }
01621 */
01622 
01623 // !!! TODO: check here how many seconds (samples) we can send w/o desynchronization with the video stream TODO !!!
01624 
01625 int counter = 0;
01626         void *_buf;
01627         int _buf_len;
01628         struct timeval tv_sys;
01629         if(state->format == CAMOGM_FORMAT_OGM || state->format == CAMOGM_FORMAT_MOV) {
01630                 int slen;
01631                 int _len = 0;
01632                 snd_pcm_status_t *status;
01633                 snd_pcm_status_alloca(&status);
01634                 snd_timestamp_t ts;
01635                 for(;;) {
01636                         counter++;
01637                         long avail = 0;
01638                         avail = snd_pcm_avail_update(ctx_a.capture_handle);
01639                         gettimeofday(&tv_sys);
01640                         tv_sys.tv_usec += ctx_a.sample_time;
01641                         time_normalize(&tv_sys);
01642                         snd_pcm_status(ctx_a.capture_handle, status);
01643                         snd_pcm_status_get_tstamp(status, &ts);
01644 //                      avail = snd_pcm_status_get_avail_max(status);
01645 //                      int av = snd_pcm_status_get_avail(status);
01646                         int to_push_flag = 0;
01647                         int to_read = ctx_a.sbuffer_len; // length in the samples...
01648                         if(ctx_a.to_finish_samples < 0)
01649                                 ctx_a.to_finish_samples = 0;
01650                         if(avail >= ctx_a.sbuffer_len && ctx_a.to_finish_samples == 0)
01651                                 to_push_flag = 1;
01652                         if(ctx_a.to_finish_samples > 0) {
01653                                 if(ctx_a.to_finish_samples > ctx_a.sbuffer_len) {
01654                                         if(avail >= ctx_a.sbuffer_len) {
01655                                                 to_read = ctx_a.sbuffer_len;
01656                                                 ctx_a.to_finish_samples -= ctx_a.sbuffer_len;
01657                                                 to_push_flag = 2;
01658                                         }
01659                                 } else {
01660                                         if(avail >= ctx_a.to_finish_samples) {
01661                                                 to_read = ctx_a.to_finish_samples;
01662                                                 ctx_a.to_finish_samples = 0;
01663                                                 to_push_flag = 2;
01664                                         }
01665                                 }
01666                         }
01667                         if(to_push_flag) {
01668                                 slen = snd_pcm_mmap_readi(ctx_a.capture_handle, (void *)(ctx_a.sbuffer + AUDIO_SBUFFER_PREFIX), to_read);
01669 //                              snd_pcm_status(ctx_a.capture_handle, status);
01670 //                              snd_pcm_status_get_tstamp(status, &ts);
01671                                 if(slen > 0) {
01672                                         int flag = 1;
01673                                         long offset = 0;
01674                                         // check the length of the movie and sound track
01675                                         if(to_push_flag == 1) {
01676                                                 struct timeval sl = ctx_a.time_last;
01677                                                 sl.tv_usec += ctx_a.sample_time;
01678                                                 time_normalize(&sl);
01679                                                 struct timeval m_end;
01680                                                 m_end = state->ts_video;
01681                                                 m_end.tv_usec += state->frame_period / 2;
01682                                                 time_normalize(&m_end);
01683                                                 struct timeval m_len;
01684                                                 if(m_len.tv_sec != ctx_a.movie_start.tv_sec) {
01685                                                         m_len.tv_sec = m_end.tv_sec - 1;
01686                                                         m_len.tv_usec = m_end.tv_usec + 1000000;
01687                                                 }
01688                                                 m_len.tv_sec -= ctx_a.movie_start.tv_sec;
01689                                                 m_len.tv_usec -= ctx_a.movie_start.tv_usec;
01690                                                 time_normalize(&m_len);
01691                                                 if(time_comp(&sl, &m_len) > 0) {
01692                                                         // sound too early - skip this sequence
01693                                                         break;
01694                                                 }
01695                                         }
01696                                         // we need to skip some samples in a new session
01697                                         // but if we just will switch the frames - we need to split new samples in the buffer for two parts - for the previous file,
01698                                         // and the next one...
01699                                         // so we can just save in the first file new data, and for the next - use "skip_samples" field
01700                                         if(ctx_a.audio_skip_samples != 0) {
01701 DA(fprintf(stderr, "skip_samples == %d\n", ctx_a.audio_skip_samples, slen););
01702                                                 if(ctx_a.audio_skip_samples >= slen) {
01703                                                         ctx_a.audio_skip_samples -= slen;
01704                                                         flag = 0;
01705                                                 } else {
01706                                                         offset = ctx_a.audio_skip_samples;
01707                                                         ctx_a.audio_skip_samples = 0;
01708                                                 }
01709                                         } 
01710                                         if(flag) {
01711                                                 long samples = slen - offset;
01712                                                 ctx_a.audio_count += samples;
01713                                                 _buf = (void *)(ctx_a.sbuffer + AUDIO_SBUFFER_PREFIX);
01714                                                 _buf = (void *)((char *)_buf + offset * 2 * state->audio_channels);
01715                                                 _buf_len = samples * 2 * state->audio_channels;
01716                                                 if(state->format == CAMOGM_FORMAT_OGM)
01717                                                         camogm_audio_ogm_push(_buf, _buf_len, samples, AUDIO_SBUFFER_PREFIX);
01718                                                 if(state->format == CAMOGM_FORMAT_MOV)
01719                                                         camogm_audio_mov(_buf, _buf_len, samples);
01720                                                 float tr = 1.0 / state->audio_rate;
01721                                                 float l = tr * ctx_a.audio_count;
01722                                                 unsigned long s = (unsigned long)l;
01723                                                 l -= s;
01724                                                 l *= 1000000;
01725                                                 unsigned long us = (unsigned long)l;
01726                                                 ctx_a.time_last.tv_sec = s;
01727                                                 ctx_a.time_last.tv_usec = us;
01728 DA(                                             fprintf(stderr, "%d: sound time %d:%06d, at %d:%06d; and the sound time is: %d:%06d, samples: %d\n", counter, s, us, tv_sys.tv_sec, tv_sys.tv_usec, ctx_a.time_last.tv_sec, ctx_a.time_last.tv_usec, samples););
01729                                         }
01730                                 }
01731                         } else {
01732                                 break;
01733                         }
01734                 }
01735         }
01736 }
01737 
01738 void audio_init(by_command) {
01739         // apply settings - i.e. just copy to current
01740         state->audio_enable = state->set_audio_enable;
01741         state->audio_rate = state->set_audio_rate;
01742         state->audio_channels = state->set_audio_channels;
01743         state->allow_sync = state->set_allow_sync;
01744 
01745 //      ctx_a.audio_count = 0;
01746 //      ctx_a.audio_skip_samples = 0;
01747 
01748         int slen;
01749         snd_timestamp_t audio_ts;
01750         if(state->audio_enable == 0) {
01751                 return;
01752         }
01753         if(state->format == CAMOGM_FORMAT_JPEG)
01754                 return;
01755         // set up audio device
01756         if(by_command && !ctx_a.audio_set) {
01757                 snd_pcm_hw_params_t *hw_params;
01758                 ctx_a.audio_set = 1;
01759 //              sbuffer_len = state->audio_rate * 2 * state->audio_channels * sample_time;
01760 //              ctx_a.sbuffer_len = state->audio_rate * state->audio_channels * ctx_a.sample_time;
01761                 ctx_a.sbuffer_len = state->audio_rate * ctx_a.sample_time;
01762                 ctx_a.sbuffer_len /= 1000;
01763                 ctx_a.sbuffer_len -= ctx_a.sbuffer_len % 2;
01764 
01765 DA(             fprintf(stderr, "sbuffer_len == %d\n", ctx_a.sbuffer_len););
01766 
01767 //              state->audio_format = SND_PCM_FORMAT_S16_LE;
01768                 int audio_format = SND_PCM_FORMAT_S16_LE;
01769 
01770                 int err;
01771                 ctx_a.sbuffer = (void *)malloc(ctx_a.sbuffer_len * 8 + AUDIO_SBUFFER_PREFIX);
01772                 if((err = snd_pcm_open(&ctx_a.capture_handle, "default", SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)) < 0)
01773                         return;
01774                 if((err = snd_pcm_hw_params_malloc(&hw_params)) < 0)
01775                         return;
01776                 if((err = snd_pcm_hw_params_any(ctx_a.capture_handle, hw_params)) < 0)
01777                         return;
01778                 snd_pcm_access_mask_t *mask = alloca(snd_pcm_access_mask_sizeof());
01779                 snd_pcm_access_mask_none(mask);
01780                 snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
01781                 if((err = snd_pcm_hw_params_set_access_mask(ctx_a.capture_handle, hw_params, mask)) < 0)
01782                         return;
01783 //              if((err = snd_pcm_hw_params_set_format(ctx_a.capture_handle, hw_params, state->audio_format)) < 0)
01784                 if((err = snd_pcm_hw_params_set_format(ctx_a.capture_handle, hw_params, audio_format)) < 0)
01785                         return;
01786                 unsigned int t = state->audio_rate;
01787                 if((err = snd_pcm_hw_params_set_rate_near(ctx_a.capture_handle, hw_params, &t, 0)) < 0)
01788                         return;
01789                 state->audio_rate = t;
01790                 if((err = snd_pcm_hw_params_set_channels(ctx_a.capture_handle, hw_params, state->audio_channels)) < 0)
01791                         return;
01792                 if((err = snd_pcm_hw_params(ctx_a.capture_handle, hw_params)) < 0)
01793                         return;
01794                 snd_pcm_uframes_t buffer_time = 2000000;
01795                 if((err = snd_pcm_hw_params_set_buffer_time_near(ctx_a.capture_handle, hw_params, &buffer_time, 0)) < 0)
01796                         return;
01797 //              fprintf(stderr, "buffer_time is == %d\n", buffer_time);
01798 
01799                 snd_pcm_sw_params_t *sw_params;
01800                 snd_pcm_sw_params_malloc(&sw_params);
01801                 err = snd_pcm_sw_params_current(ctx_a.capture_handle, sw_params);
01802                 if(err < 0)     return;
01803                 err = snd_pcm_sw_params_set_tstamp_mode(ctx_a.capture_handle, sw_params, SND_PCM_TSTAMP_MMAP);
01804                 if(err < 0)     return;
01805                 err = snd_pcm_sw_params(ctx_a.capture_handle, sw_params);
01806                 if(err < 0)     return;
01807                 snd_pcm_sw_params_free(sw_params);
01808                 
01809                 snd_pcm_hw_params_free(hw_params);
01810                 if((err = snd_pcm_prepare(ctx_a.capture_handle)) < 0)
01811                         return;
01812 
01813                 ctx_a.audio_present = 1;
01814                 ctx_a.begin_of_stream_with_audio = 1;
01815                 ctx_a.begin_of_stream_with_audio_trigger = 1;
01816 
01817                 ctx_a.audio_count = 0;
01818                 ctx_a.audio_skip_samples = 0;
01819 
01820                 int fd_stream = open("/dev/ext353", O_RDWR);
01821                 unsigned long rtc[4];
01822                 ioctl(fd_stream, EXT_GET_TIME_SYNC, (void *)&rtc[0]);
01823                 close(fd_stream);
01824 DA(             fprintf(stderr, "SYNC; sys time == %d:%06d; ", rtc[0], rtc[1]););
01825 DA(             fprintf(stderr, "FPGA time == %d:%06d\n", rtc[2], rtc[3]););
01826 
01827                 fprintf(stderr, "audio_init(%d)... OK\n", by_command);
01828                 snd_pcm_status_t *status;
01829                 snd_pcm_status_alloca(&status);
01830                 while((slen = snd_pcm_mmap_readi(ctx_a.capture_handle, (void *)(ctx_a.sbuffer), 2)) < 0)
01831                         snd_pcm_prepare(ctx_a.capture_handle);
01832                 snd_pcm_status(ctx_a.capture_handle, status);
01833                 snd_pcm_status_get_tstamp(status, &audio_ts);
01834 DA(             fprintf(stderr, "audio: device is open...   !!!!!!!!!!!!!!!!!!!; slen == %d\n", slen););
01835 
01836                 struct timeval d; // SYS time - FPGA time;
01837                 d.tv_sec = rtc[0] - 1;
01838                 d.tv_usec = rtc[1] + 1000000;
01839                 d.tv_sec -= rtc[2];
01840                 d.tv_usec -= rtc[3];
01841                 time_normalize(&d);
01842                 struct timeval tv;
01843                 tv = audio_ts;
01844                 tv.tv_sec -= 1;
01845                 tv.tv_usec += 1000000;
01846                 tv.tv_sec -= d.tv_sec;
01847                 tv.tv_usec -= d.tv_usec;
01848                 time_normalize(&tv);
01849                 state->ts_audio = tv;
01850 
01851                 gettimeofday(&tv, NULL);
01852 DA(             fprintf(stderr, "audio_init(%d) - at %d:%06d", by_command, tv.tv_sec, (unsigned)tv.tv_usec););
01853 DA(             fprintf(stderr, "status at %d:%06d\n", audio_ts.tv_sec, audio_ts.tv_usec););
01854         }
01855 }
01856 
01857 void audio_start(int by_command) {
01858         state->audio_frameno = 0;
01859         state->audio_samples = 0;
01860         ctx_a.to_finish_samples = 0;
01861         ctx_a.time_last.tv_sec = 0;
01862         ctx_a.time_last.tv_usec = 0;
01863         ctx_a.audio_count = 0;
01864         if(state->format == CAMOGM_FORMAT_JPEG)
01865                 return;
01866 /*
01867         if(state->format == CAMOGM_FORMAT_JPEG) {
01868                 if(ctx_a.audio_present) {
01869                         char fname[256];
01870                         sprintf(fname, "%s_01.wav", state->path_prefix);
01871                         // open WAV file...
01872                         fprintf(stderr, "open WAV file, name == \"%s\"\n", fname);
01873                         wave_begin(fname);
01874                 }
01875         }
01876 */
01877         struct timeval tv;
01878         gettimeofday(&tv, NULL);
01879 DA(     fprintf(stderr, "audio_start(%d) - at %d:%06d\n", by_command, tv.tv_sec, (unsigned)tv.tv_usec););
01880 }
01881 
01882 void audio_end(int by_command) {
01883         if(ctx_a.audio_present) {
01884                 if(state->format == CAMOGM_FORMAT_JPEG)
01885                         return;
01886 /*
01887                 if(state->format == CAMOGM_FORMAT_JPEG) {
01888                         // close WAV file...
01889                         fprintf(stderr, "close WAV file\n");
01890                         wave_end();
01891                 }
01892 */
01893         }
01894         // set down audio device
01895         if(by_command && ctx_a.audio_set) {
01896                 ctx_a.audio_present = 0;
01897                 ctx_a.audio_set = 0;
01898                 snd_pcm_close(ctx_a.capture_handle);
01899 DA(             fprintf(stderr, "audio: device is closed... !!!!!!!!!!!!!!!!!!!\n"););
01900                 free((void *)ctx_a.sbuffer);
01901                 ctx_a.sbuffer = NULL;
01902         }
01903 //      fprintf(stderr, "audio_end(%d)\n", by_command);
01904         struct timeval tv;
01905         gettimeofday(&tv, NULL);
01906 DA(     fprintf(stderr, "audio_end(%d) - at %d:%06d\n", by_command, tv.tv_sec, (unsigned)tv.tv_usec););
01907 }
01908 
01909 void audio_free(void) {
01910 //      fprintf(stderr, "audio_free()\n");
01911 }

Generated on Thu Aug 7 16:18:58 2008 for elphel by  doxygen 1.5.1