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 }