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