00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 
00036 
00037 
00039 #include <unistd.h>
00040 #include <stdio.h>
00041 #include <stdlib.h>
00042 #include <signal.h>
00043 #include <fcntl.h>
00044 #include <sys/uio.h>
00045 #include <errno.h>
00046 #include <sys/types.h>
00047 #include <sys/socket.h>
00048 #include <sys/stat.h>
00049 
00050 
00051 #include <time.h>
00052 #include <string.h>
00053 
00054 #include <netinet/in.h> 
00055 #include <sys/mman.h>           
00056 #include <sys/ioctl.h>
00057 
00058 #include <asm/elphel/c313a.h>
00059 #include <asm/elphel/ext353.h>
00060 #include <asm/byteorder.h>
00061 
00062 
00063 #include <ogg/ogg.h> 
00064 #include "ogmstreams.h" 
00065 
00066 #include "camogm_mov.h"
00067 #include "camogm.h"
00068 
00069 #define QUICKTIME_MIN_HEADER 0x300 // Quicktime header length (w/o index tables) enough to accomodate 
00070                                    
00071 
00072 
00074 const char hexStr[]="0123456789abcdef";
00075 const char qtSourceFileName[]= "/etc/qt_source";
00076 char comStr[1024];
00077 int     width=1280;
00078 int height=1024;
00079 int nframes=100;
00080 int sample_dur=80;
00081 int samplesPerChunk=10;
00082 int     framesize=80000;
00083 int     timescale=600;
00084 int * sizes;    
00085 int iPos; 
00086 
00087 int ofd; 
00088 int iFileLen;
00089 char * q_template=NULL;
00090 long headerSize=0;
00091 const char *iFile=NULL;
00092 
00093 
00094 int quicktime_template_parser (const char * i_iFile, 
00095            int i_ofd,   
00096            int i_width, 
00097            int i_height,
00098            int i_nframes,
00099            int i_sample_dur,
00100            int i_samplesPerChunk,
00101            int i_framesize,
00102            int i_timescale,
00103            int * i_sizes,
00104            int   data_start 
00105          );
00106 void putBigEndian(unsigned long d, int l);
00107 int parse_special(void);
00108 int parse (int top);
00111 int camogm_init_mov(void) {
00112   FILE* qt_header;
00113   int size;
00114   if ((qt_header= fopen (qtSourceFileName,"r"))==NULL) {
00115     D0(fprintf (debug_file,"Error opening Quicktime header template %s for reading\n", qtSourceFileName));
00116     return -CAMOGM_FRAME_FILE_ERR;
00117   }
00118   fseek(qt_header, 0, SEEK_END);
00119   size=ftell(qt_header);
00120   
00121   if (!((q_template=malloc(size+1)))) {
00122      D0(fprintf (debug_file,"Could not allocate %d bytes of memory for Quicktime header template\n", (size+1)));
00123      fclose(qt_header);
00124      return -CAMOGM_FRAME_MALLOC ;
00125   }
00126   fseek(qt_header, 0, SEEK_SET); 
00127   if (fread (q_template,size,1,qt_header)<1) {
00128     D0(fprintf (debug_file,"Could not read %d bytes of Quicktime header template from %s\n", (size+1),qtSourceFileName));
00129     free(q_template);
00130     q_template=NULL;
00131     fclose(qt_header);
00132     return -CAMOGM_FRAME_FILE_ERR;
00133   }
00134   q_template[size]=0;
00135   return 0;
00136 }
00137 
00138 void camogm_free_mov(void) {
00139   if (q_template) {
00140     free (q_template);
00141     q_template=NULL;
00142   }
00143 }
00144 
00145 int camogm_start_mov(void) {
00146 
00148   if (!((state->frame_lengths=malloc(4*state->max_frames)))) return -CAMOGM_FRAME_MALLOC ;
00150    sprintf(state->path,"%s%010ld_%06ld.mov",state->path_prefix,state->frame_params.timestamp_sec,state->frame_params.timestamp_usec);
00151    if (((state->ivf=open(state->path,O_RDWR | O_CREAT, 0777)))<0){
00152      D0(fprintf (debug_file, "Error opening %s for writing, returned %d, errno=%d\n", state->path,state->ivf,errno));
00153      return -CAMOGM_FRAME_FILE_ERR;
00154    }
00157   state->frame_data_start=QUICKTIME_MIN_HEADER+16+ 4*(state->max_frames)+ ( 4*(state->max_frames))/(state->frames_per_chunk); 
00158    lseek(state->ivf, state->frame_data_start, SEEK_SET);
00159   return 0;
00160 }
00161 
00162 int camogm_frame_mov(void){
00163    int i,j;
00164    ssize_t iovlen,l;
00165    struct iovec chunks_iovec[7];
00166    l=0;
00167    for (i=0; i< (state->chunk_index)-1; i++) {
00168       chunks_iovec[i].iov_base=state->packetchunks[i+1].chunk;
00169       chunks_iovec[i].iov_len= state->packetchunks[i+1].bytes;
00170       l+=chunks_iovec[i].iov_len;
00171    }
00172    iovlen=writev(state->ivf,chunks_iovec, (state->chunk_index)-1);
00173    if (iovlen < l) {
00174           j=errno;
00175           D0(fprintf(debug_file,"writev error %d (returned %d, expected %d)\n",j,iovlen,l));
00176           close (state->ivf);
00177           state->ivf=-1;
00178           return -CAMOGM_FRAME_FILE_ERR;
00179    }
00180    state->frame_lengths[state->frameno]=l;
00181    return 0;
00182 }
00184 int camogm_end_mov(void){
00185    off_t l
00186 
00187 ;
00188    timescale=10000; 
00189 
00190    l=lseek(state->ivf, 0, SEEK_CUR) - (state->frame_data_start)+8; 
00191 
00192 
00193    lseek(state->ivf, 0, SEEK_SET);
00194    quicktime_template_parser (q_template, 
00195            state->ivf,   
00196            state->width, 
00197            state->height,
00198            state->frameno,
00199            state->frame_period/ (1000000/timescale),
00200            state->frames_per_chunk,
00201            0, 
00202            (int) ((float)timescale/(state->timescale)),
00203            state->frame_lengths, 
00204            state->frame_data_start
00205          );
00206 #if 0
00209    he=lseek(state->ivf, 0, SEEK_CUR);// just after the original header end
00210    l=state->frame_data_start-he; 
00211    D4(fprintf (debug_file,"Remaining gap between Quicktime header and the data is %d (it should be>=8) \n", (int) l));  
00212    lseek(state->ivf, he-8, SEEK_SET);
00213    read (state->ivf, mdat_tag,8);    
00214    lseek(state->ivf, state->frame_data_start-8, SEEK_SET);
00215    write(state->ivf, mdat_tag,8);
00216    skip_tag[0]=(l >> 24) & 0xff;
00217    skip_tag[1]=(l >> 16) & 0xff;
00218    skip_tag[2]=(l >>  8) & 0xff;
00219    skip_tag[3]=(l      ) & 0xff;
00220    lseek(state->ivf, he-8, SEEK_SET);
00221    write(state->ivf, skip_tag,8);
00222 #endif
00223    close (state->ivf);
00224    state->ivf=-1;
00226   if (state->frame_lengths) {
00227      free(state->frame_lengths);
00228      state->frame_lengths=NULL;
00229   }
00230   return 0;
00231 }
00232 
00233 
00234 
00235 
00236 
00237 
00238 
00239 
00240 void putBigEndian(unsigned long d, int l) {
00241 unsigned char od[4];
00242    od[3]=d;
00243    od[2]=d >> 8;
00244    od[1]=d >> 16;
00245    od[0]=d >> 24;
00246    if (l) write (ofd, &od[4-l], l);
00247 
00248 }
00250 char * sfgets(char * str, int size, const char * stream, int * pos) {
00251      int l;
00252      const char * eol=strchr(&stream[*pos],'\n');
00253      if (!eol) eol=stream+(strlen(stream)-1); 
00254      l=(eol-stream)-(*pos);
00255 
00256      if (l >= size) l=size-1;
00257      memcpy(str, &stream[*pos],l);
00258      str[l]='\0';
00259      *pos+=l;
00260     return str;
00261 }
00262 
00263 int parse_special(void) {
00264         
00265    time_t ltime;
00266          int n,j,l;
00267         char str[256];
00268         char c;
00269         int i=0;
00270    int gap;
00271 
00272         while (((c=iFile[iPos++])!=0x20) && (c!=0x09) && (c!=0x0a) && (c!=0x0d) && (c!=0x0) && (i<255) && ( iPos<iFileLen )) str[i++]=c;
00273         str[i]=0;
00274 
00275   D4(fprintf (debug_file, "parse_special, str=!%s\n",str));
00276 
00277         if (strcmp(str,"mdata")==0)  {putBigEndian(headerSize, 4);return 0;} 
00278         if (strcmp(str,"height")==0) {putBigEndian(height,2);return 0;}
00279         if (strcmp(str,"width")==0)  {putBigEndian(width,2);return 0;}
00280         if (strcmp(str,"width")==0)  {putBigEndian(width,2);return 0;}
00281         if (strcmp(str,"nframes")==0)  {putBigEndian(nframes,4);return 0;}
00282         if (strcmp(str,"timescale")==0)  {putBigEndian(timescale,4);return 0;}
00283         if (strcmp(str,"duration")==0)  {putBigEndian(nframes*sample_dur,4);return 0;}
00284         if (strcmp(str,"frame_duration")==0)  {putBigEndian(sample_dur,4);return 0;}
00285         if (strcmp(str,"samples_chunk")==0)  {putBigEndian(samplesPerChunk, 4);return 0;} 
00286         if (strcmp(str,"sample_sizes")==0)  {
00287        if (sizes!=NULL) for (i=0;i<nframes;i++) putBigEndian(sizes[i],4);
00288        else             for (i=0;i<nframes;i++) putBigEndian(framesize,4);
00289            return 0;
00290         }
00291         if (strcmp(str,"chunk_offsets")==0)  {
00292        n= (nframes-1)/samplesPerChunk +1;
00293        putBigEndian(n,4);
00294        if (sizes!=NULL) {
00295          l=0;j=0;
00296          for (i=0; i<nframes;i++) {
00297            if (j==0) putBigEndian(headerSize+l,4);
00298            j++; if (j>=samplesPerChunk) j=0;
00299            l+=sizes[i];
00300          }
00301 
00302        } else for (i=0;i<n;i++) putBigEndian(headerSize+framesize*samplesPerChunk*i,4);
00303            return 0;
00304         }
00306         if (strcmp(str,"data_size")==0)  {
00307        gap=headerSize-lseek(ofd,0,SEEK_CUR)-8;
00308        if (gap>0) { 
00309   D4(fprintf (debug_file, "Inserting a skip tag to compensate for a gap (%d bytes) between the header and the frame data\n",gap));
00310           if (gap<8) {
00311   D0(fprintf (debug_file, "not enough room to insret 'skip' tag - %d (need 8)\n",gap));
00312              return -1; 
00313           }
00314   D4(fprintf (debug_file, "writing hex %x, %x bytes\n",gap,4));
00315           putBigEndian(gap, 4);
00316   D4(fprintf (debug_file, "writing string <%s>\n","skip"));
00317           write (ofd, "skip", 4);
00318           lseek(ofd,gap-8,SEEK_CUR); 
00319        }
00320        if (sizes!=NULL) {
00321          l=0;
00322          for (i=0; i<nframes;i++) l+=sizes[i];
00323   D4(fprintf (debug_file, "writing hex %x, %x bytes\n",l,4));
00324          putBigEndian(l,4);
00325        } else putBigEndian(nframes * framesize,4);
00326            return 0;
00327         }
00328         if (strcmp(str,"time")==0)  {
00329                 time (<ime);
00330                 ltime+=2082801600;      
00331                 putBigEndian(ltime,4);return 0;
00332    }
00333         return -1;
00334 }
00335 
00336 
00337 
00338 int parse (int top) {   
00339         long out_start, out_end;
00340         char c;
00341         unsigned long d,l;
00342         char * cp;
00343   D4(fprintf (debug_file,"parse(%x)\n",top));
00344 
00345    c=iFile[iPos++];
00346   D5(fprintf (debug_file,"%c",c));
00347 
00348 
00349 
00350    out_start=lseek(ofd,0,SEEK_CUR);
00351 
00352         if (!top)  putBigEndian(0, 4);
00353 
00354    while (( iPos<iFileLen ) && (c!='}')) {
00355 
00356                 if ((c!=' ') && (c!=0x9) && (c!=0xa) && (c!=0xd)) {
00357                   if (c=='!') {
00358                      if (parse_special()<0) return -1;
00359                   }
00360 
00361                   else if (c=='{') {
00362                     if (parse(0)<0) return -1;
00363 
00364 
00365                   } else if (c=='#') sfgets( comStr, sizeof(comStr), iFile, &iPos);
00366                   else if (c=='\'') {
00367 
00368                    sfgets( comStr, sizeof(comStr), iFile, &iPos);
00369                         if ((cp=strchr(comStr,0x0a))!=NULL) cp[0]=0;
00370                         if ((cp=strchr(comStr,0x0d))!=NULL) cp[0]=0;
00371                         if ((cp=strchr(comStr,'#'))!=NULL) cp[0]=0;
00372                         cp=comStr+strlen(comStr)-1;
00373                         while ((cp>comStr) && ((cp[0]==0x20) || (cp[0]==0x09))) cp--;
00374                         cp[1]=0;
00375 
00376 
00377                         write (ofd, comStr, strlen(comStr));
00378   D4(fprintf (debug_file, "writing string <%s>\n",comStr));
00379                   } else if (strchr(hexStr,c)) {
00380                         d=0;
00381                         l=1;
00382                         do {
00383                                 d=(d<<4)+(strchr(hexStr,c)-hexStr);
00384                                 l++;
00385                         } while (( iPos<iFileLen ) && (l<=8) && (strchr(hexStr,(c=iFile[iPos++]))) );
00386                         l=(l)>>1;
00387                 putBigEndian(d, l);
00388 
00389   D4(fprintf (debug_file, "writing hex %lx, %lx bytes\n",d,l));
00390 
00391 
00392                   } else if ((c=='}')){
00393              break;
00394 
00395                   } else {
00396                     return -1;
00397                   }
00398 
00399         }
00400 
00401        c=iFile[iPos++];
00402 
00403         }       
00404 
00405         
00406         if (!top) {
00407 
00408 
00409      out_end=lseek(ofd,0,SEEK_CUR);
00410 
00411 
00412      lseek (ofd,out_start,SEEK_SET);
00413           putBigEndian((out_end-out_start), 4);
00414 
00415 
00416      lseek (state->ivf,out_end,SEEK_SET);
00417     }
00418         return 0;
00419 }
00420 
00421 
00422 int quicktime_template_parser (const char * i_iFile, 
00423            int i_ofd,   
00424            int i_width, 
00425            int i_height,
00426            int i_nframes,
00427            int i_sample_dur,
00428            int i_samplesPerChunk,
00429            int i_framesize,
00430            int i_timescale,
00431            int * i_sizes,
00432            int   data_start 
00433          ) {
00434         iFile=           i_iFile;
00435         width=           i_width;
00436         height=          i_height;
00437         nframes=         i_nframes;
00438         sample_dur=      i_sample_dur;
00439         samplesPerChunk= i_samplesPerChunk;
00440         framesize=       i_framesize;
00441         timescale=       i_timescale;
00442         sizes=           i_sizes;
00443         iPos=0; 
00444         ofd=             i_ofd;
00445         iFileLen=        strlen(iFile);
00446         lseek (ofd,0,SEEK_SET);
00447         if (data_start) headerSize=data_start;
00448 
00449   D3(fprintf (debug_file, "PASS I\n"));
00450 
00451 
00452    while ( iPos < iFileLen )   parse(1); 
00453 
00454 
00455 
00456 
00457           if (!headerSize) headerSize=lseek(ofd,0,SEEK_CUR);
00458           iPos=0;
00459 
00460           lseek (ofd,0,SEEK_SET);
00461 
00462   D3(fprintf (debug_file, "PASS II\n"));
00463 
00464    while ( iPos < iFileLen )   parse(1); 
00465 
00466 
00467 
00468 
00469         return 0;
00470 }