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