1 /*
2 * avilib.c
3 *
4 * Copyright (C) Thomas �streich - June 2001
5 * multiple audio track support Copyright (C) 2002 Thomas �streich
6 *
7 * Original code:
8 * Copyright (C) 1999 Rainer Johanni <Rainer@Johanni.de>
9 *
10 * This file is part of transcode, a linux video stream processing tool
11 *
12 * transcode is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2, or (at your option)
15 * any later version.
16 *
17 * transcode is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with GNU Make; see the file COPYING. If not, write to
24 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
25 *
26 */
27
28 #include <unistd.h>
29
30 #include "avilib.h"
31
32 #include "xio.h"
33
34 #define INFO_LIST
35
36 // add a new riff chunk after XX MB
37 //#define NEW_RIFF_THRES (1900*1024*1024)
38 #define NEW_RIFF_THRES (1900*1024*1024)
39 //#define NEW_RIFF_THRES (10*1024*1024)
40
41 // Maximum number of indices per stream
42 #define NR_IXNN_CHUNKS 32
43
44
45 #define DEBUG_ODML
46 #undef DEBUG_ODML
47
48 /* The following variable indicates the kind of error */
49
50 long AVI_errno = 0;
51
52 #define MAX_INFO_STRLEN 64
53 static char id_str[MAX_INFO_STRLEN];
54
55 #define FRAME_RATE_SCALE 1000000
56
57 /*******************************************************************
58 * *
59 * Utilities for writing an AVI File *
60 * *
61 *******************************************************************/
62
avi_read(int fd,char * buf,size_t len)63 static ssize_t avi_read(int fd, char *buf, size_t len)
64 {
65 ssize_t n = 0;
66 ssize_t r = 0;
67
68 while (r < len) {
69 n = xio_read (fd, buf + r, len - r);
70 if (n == 0)
71 break;
72 if (n < 0) {
73 if (errno == EINTR)
74 continue;
75 else
76 break;
77 }
78
79 r += n;
80 }
81
82 return r;
83 }
84
avi_write(int fd,char * buf,size_t len)85 static ssize_t avi_write (int fd, char *buf, size_t len)
86 {
87 ssize_t n = 0;
88 ssize_t r = 0;
89
90 while (r < len) {
91 n = xio_write (fd, buf + r, len - r);
92 if (n < 0)
93 return n;
94
95 r += n;
96 }
97 return r;
98 }
99
100 /* HEADERBYTES: The number of bytes to reserve for the header */
101
102 #define HEADERBYTES 2048
103
104 /* AVI_MAX_LEN: The maximum length of an AVI file, we stay a bit below
105 the 2GB limit (Remember: 2*10^9 is smaller than 2 GB) */
106
107 #define AVI_MAX_LEN (UINT_MAX-(1<<20)*16-HEADERBYTES)
108
109 #define PAD_EVEN(x) ( ((x)+1) & ~1 )
110
111
112 /* Copy n into dst as a 4 or 2 byte, little endian number.
113 Should also work on big endian machines */
114
long2str(unsigned char * dst,int32_t n)115 static void long2str(unsigned char *dst, int32_t n)
116 {
117 dst[0] = (n )&0xff;
118 dst[1] = (n>> 8)&0xff;
119 dst[2] = (n>>16)&0xff;
120 dst[3] = (n>>24)&0xff;
121 }
122
123 #ifdef WORDS_BIGENDIAN
short2str(unsigned char * dst,int32_t n)124 static void short2str(unsigned char *dst, int32_t n)
125 {
126 dst[0] = (n )&0xff;
127 dst[1] = (n>> 8)&0xff;
128 }
129 #endif
130
131 /* Convert a string of 4 or 2 bytes to a number,
132 also working on big endian machines */
133
str2ullong(unsigned char * str)134 static uint64_t str2ullong(unsigned char *str)
135 {
136 uint64_t r = (str[0] | (str[1]<<8) | (str[2]<<16) | (str[3]<<24));
137 uint64_t s = (str[4] | (str[5]<<8) | (str[6]<<16) | (str[7]<<24));
138 return ((s<<32)&0xffffffff00000000ULL)|(r&0xffffffffULL);
139 }
140
str2ulong(unsigned char * str)141 static uint32_t str2ulong(unsigned char *str)
142 {
143 return ( str[0] | (str[1]<<8) | (str[2]<<16) | (str[3]<<24) );
144 }
str2ushort(unsigned char * str)145 static uint32_t str2ushort(unsigned char *str)
146 {
147 return ( str[0] | (str[1]<<8) );
148 }
149
150 // bit 31 denotes a keyframe
str2ulong_len(unsigned char * str)151 static uint32_t str2ulong_len (unsigned char *str)
152 {
153 return str2ulong(str) & 0x7fffffff;
154 }
155
156
157 // if bit 31 is 0, its a keyframe
str2ulong_key(unsigned char * str)158 static uint32_t str2ulong_key (unsigned char *str)
159 {
160 uint32_t c = str2ulong(str);
161 c &= 0x80000000;
162 if (c == 0) return 0x10;
163 else return 0;
164 }
165
166 /* Calculate audio sample size from number of bits and number of channels.
167 This may have to be adjusted for eg. 12 bits and stereo */
168
avi_sampsize(avi_t * AVI,int j)169 static int avi_sampsize(avi_t *AVI, int j)
170 {
171 int s;
172 s = ((AVI->track[j].a_bits+7)/8)*AVI->track[j].a_chans;
173 // if(s==0) s=1; /* avoid possible zero divisions */
174 if(s<4) s=4; /* avoid possible zero divisions */
175 return s;
176 }
177
178 /* Add a chunk (=tag and data) to the AVI file,
179 returns -1 on write error, 0 on success */
180
avi_add_chunk(avi_t * AVI,unsigned char * tag,unsigned char * data,int length)181 static int avi_add_chunk(avi_t *AVI, unsigned char *tag, unsigned char *data, int length)
182 {
183 unsigned char c[8];
184 char p=0;
185
186 /* Copy tag and length int c, so that we need only 1 write system call
187 for these two values */
188
189 memcpy(c,tag,4);
190 long2str(c+4,length);
191
192 /* Output tag, length and data, restore previous position
193 if the write fails */
194
195 if( avi_write(AVI->fdes,(char *)c,8) != 8 ||
196 avi_write(AVI->fdes,(char *)data,length) != length ||
197 avi_write(AVI->fdes,&p,length&1) != (length&1)) // if len is uneven, write a pad byte
198 {
199 xio_lseek(AVI->fdes,AVI->pos,SEEK_SET);
200 AVI_errno = AVI_ERR_WRITE;
201 return -1;
202 }
203
204 /* Update file position */
205
206 AVI->pos += 8 + PAD_EVEN(length);
207
208 //fprintf(stderr, "pos=%lu %s\n", AVI->pos, tag);
209
210 return 0;
211 }
212
213 #define OUTD(n) long2str(ix00+bl,n); bl+=4
214 #define OUTW(n) ix00[bl] = (n)&0xff; ix00[bl+1] = (n>>8)&0xff; bl+=2
215 #define OUTC(n) ix00[bl] = (n)&0xff; bl+=1
216 #define OUTS(s) memcpy(ix00+bl,s,4); bl+=4
217
218 // this does the physical writeout of the ix## structure
avi_ixnn_entry(avi_t * AVI,avistdindex_chunk * ch,avisuperindex_entry * en)219 static int avi_ixnn_entry(avi_t *AVI, avistdindex_chunk *ch, avisuperindex_entry *en)
220 {
221 int bl, k;
222 unsigned int max = ch->nEntriesInUse * sizeof (uint32_t) * ch->wLongsPerEntry + 24; // header
223 char *ix00 = malloc (max);
224 char dfcc[5];
225 memcpy (dfcc, ch->fcc, 4);
226 dfcc[4] = 0;
227
228 bl = 0;
229
230 if (en) {
231 en->qwOffset = AVI->pos;
232 en->dwSize = max;
233 //en->dwDuration = ch->nEntriesInUse -1; // NUMBER OF stream ticks == frames for video/samples for audio
234 }
235
236 #ifdef DEBUG_ODML
237 //printf ("ODML Write %s: Entries %ld size %d \n", dfcc, ch->nEntriesInUse, max);
238 #endif
239
240 //OUTS(ch->fcc);
241 //OUTD(max);
242 OUTW(ch->wLongsPerEntry);
243 OUTC(ch->bIndexSubType);
244 OUTC(ch->bIndexType);
245 OUTD(ch->nEntriesInUse);
246 OUTS(ch->dwChunkId);
247 OUTD(ch->qwBaseOffset&0xffffffff);
248 OUTD((ch->qwBaseOffset>>32)&0xffffffff);
249 OUTD(ch->dwReserved3);
250
251 for (k = 0; k < ch->nEntriesInUse; k++) {
252 OUTD(ch->aIndex[k].dwOffset);
253 OUTD(ch->aIndex[k].dwSize);
254
255 }
256 avi_add_chunk (AVI, ch->fcc, ix00, max);
257
258 free(ix00);
259
260 return 0;
261 }
262 #undef OUTS
263 #undef OUTW
264 #undef OUTD
265 #undef OUTC
266
267 // inits a super index structure including its enclosed stdindex
avi_init_super_index(avi_t * AVI,unsigned char * idxtag,avisuperindex_chunk ** si)268 static int avi_init_super_index(avi_t *AVI, unsigned char *idxtag, avisuperindex_chunk **si)
269 {
270 int k;
271
272 avisuperindex_chunk *sil = NULL;
273
274 if ((sil = (avisuperindex_chunk *) malloc (sizeof (avisuperindex_chunk))) == NULL) {
275 AVI_errno = AVI_ERR_NO_MEM;
276 return -1;
277 }
278 memcpy (sil->fcc, "indx", 4);
279 sil->dwSize = 0; // size of this chunk
280 sil->wLongsPerEntry = 4;
281 sil->bIndexSubType = 0;
282 sil->bIndexType = AVI_INDEX_OF_INDEXES;
283 sil->nEntriesInUse = 0; // none are in use
284 memcpy (sil->dwChunkId, idxtag, 4);
285 memset (sil->dwReserved, 0, sizeof (sil->dwReserved));
286
287 // NR_IXNN_CHUNKS == allow 32 indices which means 32 GB files -- arbitrary
288 sil->aIndex = malloc (sil->wLongsPerEntry * NR_IXNN_CHUNKS * sizeof (uint32_t));
289 if (!sil->aIndex) {
290 AVI_errno = AVI_ERR_NO_MEM;
291 return -1;
292 }
293 memset (sil->aIndex, 0, sil->wLongsPerEntry * NR_IXNN_CHUNKS * sizeof (uint32_t));
294
295 sil->stdindex = malloc (NR_IXNN_CHUNKS * sizeof (avistdindex_chunk *));
296 if (!sil->stdindex) {
297 AVI_errno = AVI_ERR_NO_MEM;
298 return -1;
299 }
300 for (k = 0; k < NR_IXNN_CHUNKS; k++) {
301 sil->stdindex[k] = malloc (sizeof (avistdindex_chunk));
302 // gets rewritten later
303 sil->stdindex[k]->qwBaseOffset = (uint64_t)k * NEW_RIFF_THRES;
304 }
305
306 *si = sil;
307
308 return 0;
309 }
310
311 // fills an alloc'ed stdindex structure and mallocs some entries for the actual chunks
avi_add_std_index(avi_t * AVI,unsigned char * idxtag,unsigned char * strtag,avistdindex_chunk * stdil)312 static int avi_add_std_index(avi_t *AVI, unsigned char *idxtag, unsigned char *strtag,
313 avistdindex_chunk *stdil)
314 {
315
316 memcpy (stdil->fcc, idxtag, 4);
317 stdil->dwSize = 4096;
318 stdil->wLongsPerEntry = 2; //sizeof(avistdindex_entry)/sizeof(uint32_t);
319 stdil->bIndexSubType = 0;
320 stdil->bIndexType = AVI_INDEX_OF_CHUNKS;
321 stdil->nEntriesInUse = 0;
322
323 // cp 00db ChunkId
324 memcpy(stdil->dwChunkId, strtag, 4);
325
326 //stdil->qwBaseOffset = AVI->video_superindex->aIndex[ cur_std_idx ]->qwOffset;
327
328 stdil->aIndex = malloc(stdil->dwSize * sizeof (uint32_t) * stdil->wLongsPerEntry);
329
330 if (!stdil->aIndex) {
331 AVI_errno = AVI_ERR_NO_MEM;
332 return -1;
333 }
334
335
336 return 0;
337 }
338
avi_add_odml_index_entry_core(avi_t * AVI,long flags,int64_t pos,unsigned long len,avistdindex_chunk * si)339 static int avi_add_odml_index_entry_core(avi_t *AVI, long flags, int64_t pos, unsigned long len, avistdindex_chunk *si)
340 {
341 int cur_chunk_idx;
342 // put new chunk into index
343 si->nEntriesInUse++;
344 cur_chunk_idx = si->nEntriesInUse-1;
345
346 // need to fetch more memory
347 if (cur_chunk_idx >= si->dwSize) {
348 si->dwSize += 4096;
349 si->aIndex = realloc ( si->aIndex, si->dwSize * sizeof (uint32_t) * si->wLongsPerEntry);
350 }
351
352 if(len>AVI->max_len) AVI->max_len=len;
353
354 // if bit 31 is set, it is NOT a keyframe
355 if (flags != 0x10) {
356 len |= 0x80000000;
357 }
358
359 si->aIndex [ cur_chunk_idx ].dwSize = len;
360 si->aIndex [ cur_chunk_idx ].dwOffset =
361 pos - si->qwBaseOffset + 8;
362
363 //printf("ODML: POS: 0x%lX\n", si->aIndex [ cur_chunk_idx ].dwOffset);
364
365 return 0;
366 }
367
avi_add_odml_index_entry(avi_t * AVI,unsigned char * tag,long flags,int64_t pos,unsigned long len)368 static int avi_add_odml_index_entry(avi_t *AVI, unsigned char *tag, long flags, int64_t pos, unsigned long len)
369 {
370 char fcc[5];
371
372 int audio = (strchr (tag, 'w')?1:0);
373 int video = !audio;
374
375 unsigned int cur_std_idx;
376 int audtr;
377 int64_t towrite = 0LL;
378
379 if (video) {
380
381 if (!AVI->video_superindex) {
382 if (avi_init_super_index(AVI, "ix00", &AVI->video_superindex) < 0) return -1;
383 AVI->video_superindex->nEntriesInUse++;
384 cur_std_idx = AVI->video_superindex->nEntriesInUse-1;
385
386 if (avi_add_std_index (AVI, "ix00", "00db", AVI->video_superindex->stdindex[ cur_std_idx ]) < 0)
387 return -1;
388 } // init
389
390 } // video
391
392 if (audio) {
393
394 fcc[0] = 'i'; fcc[1] = 'x'; fcc[2] = tag[0]; fcc[3] = tag[1]; fcc[4] = '\0';
395 if (!AVI->track[AVI->aptr].audio_superindex) {
396
397 #ifdef DEBUG_ODML
398 printf("ODML: fcc = %s\n", fcc);
399 #endif
400 if (avi_init_super_index(AVI, fcc, &AVI->track[AVI->aptr].audio_superindex) < 0) return -1;
401
402
403 AVI->track[AVI->aptr].audio_superindex->nEntriesInUse++;
404
405 sprintf(fcc, "ix%02d", AVI->aptr+1);
406 if (avi_add_std_index (AVI, fcc, tag, AVI->track[AVI->aptr].audio_superindex->stdindex[
407 AVI->track[AVI->aptr].audio_superindex->nEntriesInUse - 1 ]) < 0
408 ) return -1;
409 } // init
410
411 }
412
413 towrite = 0;
414 if (AVI->video_superindex) {
415
416 cur_std_idx = AVI->video_superindex->nEntriesInUse-1;
417 towrite += AVI->video_superindex->stdindex[cur_std_idx]->nEntriesInUse*8
418 + 4+4+2+1+1+4+4+8+4;
419 if (cur_std_idx == 0) {
420 towrite += AVI->n_idx*16 + 8;
421 towrite += HEADERBYTES;
422 }
423 }
424
425 for (audtr=0; audtr<AVI->anum; audtr++) {
426 if (AVI->track[audtr].audio_superindex) {
427 cur_std_idx = AVI->track[audtr].audio_superindex->nEntriesInUse-1;
428 towrite += AVI->track[audtr].audio_superindex->stdindex[cur_std_idx]->nEntriesInUse*8
429 + 4+4+2+1+1+4+4+8+4;
430 }
431 }
432 towrite += len + (len&1) + 8;
433
434 //printf("ODML: towrite = 0x%llX = %lld\n", towrite, towrite);
435
436 if (AVI->video_superindex &&
437 (int64_t)(AVI->pos+towrite) > (int64_t)((int64_t)NEW_RIFF_THRES*AVI->video_superindex->nEntriesInUse)) {
438
439 fprintf(stderr, "Adding a new RIFF chunk: %d\n", AVI->video_superindex->nEntriesInUse);
440
441 // rotate ALL indices
442 AVI->video_superindex->nEntriesInUse++;
443 cur_std_idx = AVI->video_superindex->nEntriesInUse-1;
444
445 if (AVI->video_superindex->nEntriesInUse > NR_IXNN_CHUNKS) {
446 fprintf (stderr, "Internal error in avilib - redefine NR_IXNN_CHUNKS\n");
447 fprintf (stderr, "[avilib dump] cur_std_idx=%d NR_IXNN_CHUNKS=%d"
448 "POS=%lld towrite=%lld\n",
449 cur_std_idx,NR_IXNN_CHUNKS, AVI->pos, towrite);
450 return -1;
451 }
452
453 if (avi_add_std_index (AVI, "ix00", "00db", AVI->video_superindex->stdindex[ cur_std_idx ]) < 0)
454 return -1;
455
456 for (audtr = 0; audtr < AVI->anum; audtr++) {
457 char aud[5];
458 if (!AVI->track[audtr].audio_superindex) {
459 // not initialized -> no index
460 continue;
461 }
462 AVI->track[audtr].audio_superindex->nEntriesInUse++;
463
464 sprintf(fcc, "ix%02d", audtr+1);
465 sprintf(aud, "0%01dwb", audtr+1);
466 if (avi_add_std_index (AVI, fcc, aud, AVI->track[audtr].audio_superindex->stdindex[
467 AVI->track[audtr].audio_superindex->nEntriesInUse - 1 ]) < 0
468 ) return -1;
469 }
470
471 // write the new riff;
472 if (cur_std_idx > 0) {
473
474 // dump the _previous_ == already finished index
475 avi_ixnn_entry (AVI, AVI->video_superindex->stdindex[cur_std_idx - 1],
476 &AVI->video_superindex->aIndex[cur_std_idx - 1]);
477 AVI->video_superindex->aIndex[cur_std_idx - 1].dwDuration =
478 AVI->video_superindex->stdindex[cur_std_idx - 1]->nEntriesInUse - 1;
479
480 for (audtr = 0; audtr < AVI->anum; audtr++) {
481
482 if (!AVI->track[audtr].audio_superindex) {
483 // not initialized -> no index
484 continue;
485 }
486 avi_ixnn_entry (AVI, AVI->track[audtr].audio_superindex->stdindex[cur_std_idx - 1],
487 &AVI->track[audtr].audio_superindex->aIndex[cur_std_idx - 1]);
488
489 AVI->track[audtr].audio_superindex->aIndex[cur_std_idx - 1].dwDuration =
490 AVI->track[audtr].audio_superindex->stdindex[cur_std_idx - 1]->nEntriesInUse - 1;
491 if (AVI->track[audtr].a_fmt == 0x1) {
492 AVI->track[audtr].audio_superindex->aIndex[cur_std_idx - 1].dwDuration *=
493 AVI->track[audtr].a_bits*AVI->track[audtr].a_rate*AVI->track[audtr].a_chans/800;
494 }
495 }
496
497 // XXX: dump idx1 structure
498 if (cur_std_idx == 1) {
499 avi_add_chunk(AVI, (unsigned char *)"idx1", (unsigned char *)AVI->idx, AVI->n_idx*16);
500 // qwBaseOffset will contain the start of the second riff chunk
501 }
502 // Fix the Offsets later at closing time
503 avi_add_chunk(AVI, (unsigned char *)"RIFF", "AVIXLIST\0\0\0\0movi", 16);
504
505 AVI->video_superindex->stdindex[ cur_std_idx ]->qwBaseOffset = AVI->pos -16 -8;
506 #ifdef DEBUG_ODML
507 printf("ODML: RIFF No.%02d at Offset 0x%llX\n", cur_std_idx, AVI->pos -16 -8);
508 #endif
509
510 for (audtr = 0; audtr < AVI->anum; audtr++) {
511 if (AVI->track[audtr].audio_superindex)
512 AVI->track[audtr].audio_superindex->stdindex[ cur_std_idx ]->qwBaseOffset =
513 AVI->pos -16 -8;
514
515 }
516
517 // now we can be sure
518 AVI->is_opendml++;
519 }
520
521 }
522
523
524 if (video) {
525 avi_add_odml_index_entry_core(AVI, flags, AVI->pos, len,
526 AVI->video_superindex->stdindex[ AVI->video_superindex->nEntriesInUse-1 ]);
527
528 AVI->total_frames++;
529 } // video
530
531 if (audio) {
532 avi_add_odml_index_entry_core(AVI, flags, AVI->pos, len,
533 AVI->track[AVI->aptr].audio_superindex->stdindex[
534 AVI->track[AVI->aptr].audio_superindex->nEntriesInUse-1 ]);
535 }
536
537
538 return 0;
539 }
540
541 // #undef NR_IXNN_CHUNKS
542
avi_add_index_entry(avi_t * AVI,unsigned char * tag,long flags,unsigned long pos,unsigned long len)543 static int avi_add_index_entry(avi_t *AVI, unsigned char *tag, long flags, unsigned long pos, unsigned long len)
544 {
545 void *ptr;
546
547 if(AVI->n_idx>=AVI->max_idx) {
548 ptr = realloc((void *)AVI->idx,(AVI->max_idx+4096)*16);
549
550 if(ptr == 0) {
551 AVI_errno = AVI_ERR_NO_MEM;
552 return -1;
553 }
554 AVI->max_idx += 4096;
555 AVI->idx = (unsigned char((*)[16]) ) ptr;
556 }
557
558 /* Add index entry */
559
560 // fprintf(stderr, "INDEX %s %ld %lu %lu\n", tag, flags, pos, len);
561
562 memcpy(AVI->idx[AVI->n_idx],tag,4);
563 long2str(AVI->idx[AVI->n_idx]+ 4,flags);
564 long2str(AVI->idx[AVI->n_idx]+ 8, pos);
565 long2str(AVI->idx[AVI->n_idx]+12, len);
566
567 /* Update counter */
568
569 AVI->n_idx++;
570
571 if(len>AVI->max_len) AVI->max_len=len;
572
573 return 0;
574 }
575
576 /* Returns 1 if more audio is in that video junk */
AVI_can_read_audio(avi_t * AVI)577 int AVI_can_read_audio(avi_t *AVI)
578 {
579 if(AVI->mode==AVI_MODE_WRITE) { return -1; }
580 if(!AVI->video_index) { return -1; }
581 if(!AVI->track[AVI->aptr].audio_index) { return -1; }
582
583 // is it -1? the last ones got left out --tibit
584 //if (AVI->track[AVI->aptr].audio_posc>=AVI->track[AVI->aptr].audio_chunks-1) {
585 if (AVI->track[AVI->aptr].audio_posc>=AVI->track[AVI->aptr].audio_chunks) {
586 return 0;
587 }
588
589 if (AVI->video_pos >= AVI->video_frames) return 1;
590
591 if (AVI->track[AVI->aptr].audio_index[AVI->track[AVI->aptr].audio_posc].pos < AVI->video_index[AVI->video_pos].pos) return 1;
592 else return 0;
593 }
594 /*
595 AVI_open_output_file: Open an AVI File and write a bunch
596 of zero bytes as space for the header.
597
598 returns a pointer to avi_t on success, a zero pointer on error
599 */
600
AVI_open_output_file(char * filename)601 avi_t* AVI_open_output_file(char * filename)
602 {
603 avi_t *AVI;
604 int i;
605
606 unsigned char AVI_header[HEADERBYTES];
607
608 /* Allocate the avi_t struct and zero it */
609
610 AVI = (avi_t *) malloc(sizeof(avi_t));
611 if(AVI==0)
612 {
613 AVI_errno = AVI_ERR_NO_MEM;
614 return 0;
615 }
616 memset((void *)AVI,0,sizeof(avi_t));
617
618 /* Since Linux needs a long time when deleting big files,
619 we do not truncate the file when we open it.
620 Instead it is truncated when the AVI file is closed */
621
622 #if defined(SYS_UNIX) || defined(SYS_APPLE)
623 AVI->fdes = xio_open(filename, O_RDWR|O_CREAT,
624 S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
625 #elif defined(COMP_MINGW) || defined(COMP_CYGWIN)
626 AVI->fdes = xio_open(filename, O_RDWR|O_CREAT|O_BINARY, S_IRUSR | S_IWUSR);
627 #else
628 AVI->fdes = xio_open(filename, O_RDWR|O_CREAT|O_BINARY,
629 S_IRUSR | S_IWUSR | S_IGRP | S_IROTH);
630 #endif
631
632 if (AVI->fdes < 0)
633 {
634 AVI_errno = AVI_ERR_OPEN;
635 free(AVI);
636 return 0;
637 }
638
639 /* Write out HEADERBYTES bytes, the header will go here
640 when we are finished with writing */
641
642 for (i=0;i<HEADERBYTES;i++) AVI_header[i] = 0;
643 i = avi_write(AVI->fdes,(char *)AVI_header,HEADERBYTES);
644 if (i != HEADERBYTES)
645 {
646 xio_close(AVI->fdes);
647 AVI_errno = AVI_ERR_WRITE;
648 free(AVI);
649 return 0;
650 }
651
652 AVI->pos = HEADERBYTES;
653 AVI->mode = AVI_MODE_WRITE; /* open for writing */
654
655 //init
656 AVI->anum = 0;
657 AVI->aptr = 0;
658
659 return AVI;
660 }
661
AVI_set_video(avi_t * AVI,int width,int height,double fps,char * compressor)662 void AVI_set_video(avi_t *AVI, int width, int height, double fps, char *compressor)
663 {
664 /* may only be called if file is open for writing */
665
666 if(AVI->mode==AVI_MODE_READ) return;
667
668 AVI->width = width;
669 AVI->height = height;
670 AVI->fps = fps;
671
672 if(strncmp(compressor, "RGB", 3)==0) {
673 memset(AVI->compressor, 0, 4);
674 } else {
675 memcpy(AVI->compressor,compressor,4);
676 }
677
678 AVI->compressor[4] = 0;
679
680 avi_update_header(AVI);
681 }
682
AVI_set_audio(avi_t * AVI,int channels,long rate,int bits,int format,long mp3rate)683 void AVI_set_audio(avi_t *AVI, int channels, long rate, int bits, int format, long mp3rate)
684 {
685 /* may only be called if file is open for writing */
686
687 if(AVI->mode==AVI_MODE_READ) return;
688
689 //inc audio tracks
690 AVI->aptr=AVI->anum;
691 ++AVI->anum;
692
693 if(AVI->anum > AVI_MAX_TRACKS) {
694 fprintf(stderr, "error - only %d audio tracks supported\n", AVI_MAX_TRACKS);
695 exit(1);
696 }
697
698 AVI->track[AVI->aptr].a_chans = channels;
699 AVI->track[AVI->aptr].a_rate = rate;
700 AVI->track[AVI->aptr].a_bits = bits;
701 AVI->track[AVI->aptr].a_fmt = format;
702 AVI->track[AVI->aptr].mp3rate = mp3rate;
703
704 avi_update_header(AVI);
705 }
706
707 #define OUT4CC(s) \
708 if(nhb<=HEADERBYTES-4) memcpy(AVI_header+nhb,s,4); nhb += 4
709
710 #define OUTLONG(n) \
711 if(nhb<=HEADERBYTES-4) long2str(AVI_header+nhb,n); nhb += 4
712
713 #define OUTSHRT(n) \
714 if(nhb<=HEADERBYTES-2) { \
715 AVI_header[nhb ] = (n )&0xff; \
716 AVI_header[nhb+1] = (n>>8)&0xff; \
717 } \
718 nhb += 2
719
720 #define OUTCHR(n) \
721 if(nhb<=HEADERBYTES-1) { \
722 AVI_header[nhb ] = (n )&0xff; \
723 } \
724 nhb += 1
725
726 #define OUTMEM(d, s) \
727 { \
728 unsigned int s_ = (s); \
729 if(nhb <= HEADERBYTES-s_) \
730 memcpy(AVI_header+nhb, (d), s_); \
731 nhb += s_; \
732 }
733
734
735 //ThOe write preliminary AVI file header: 0 frames, max vid/aud size
avi_update_header(avi_t * AVI)736 int avi_update_header(avi_t *AVI)
737 {
738 int njunk, sampsize, hasIndex, ms_per_frame, frate, flag;
739 int movi_len, hdrl_start, strl_start, j;
740 unsigned char AVI_header[HEADERBYTES];
741 long nhb;
742 unsigned long xd_size, xd_size_align2;
743
744 //assume max size
745 movi_len = AVI_MAX_LEN - HEADERBYTES + 4;
746
747 //assume index will be written
748 hasIndex=1;
749
750 if(AVI->fps < 0.001) {
751 frate=0;
752 ms_per_frame=0;
753 } else {
754 frate = (int) (FRAME_RATE_SCALE*AVI->fps + 0.5);
755 ms_per_frame=(int) (1000000/AVI->fps + 0.5);
756 }
757
758 /* Prepare the file header */
759
760 nhb = 0;
761
762 /* The RIFF header */
763
764 OUT4CC ("RIFF");
765 OUTLONG(movi_len); // assume max size
766 OUT4CC ("AVI ");
767
768 /* Start the header list */
769
770 OUT4CC ("LIST");
771 OUTLONG(0); /* Length of list in bytes, don't know yet */
772 hdrl_start = nhb; /* Store start position */
773 OUT4CC ("hdrl");
774
775 /* The main AVI header */
776
777 /* The Flags in AVI File header */
778
779 #define AVIF_HASINDEX 0x00000010 /* Index at end of file */
780 #define AVIF_MUSTUSEINDEX 0x00000020
781 #define AVIF_ISINTERLEAVED 0x00000100
782 #define AVIF_TRUSTCKTYPE 0x00000800 /* Use CKType to find key frames */
783 #define AVIF_WASCAPTUREFILE 0x00010000
784 #define AVIF_COPYRIGHTED 0x00020000
785
786 OUT4CC ("avih");
787 OUTLONG(56); /* # of bytes to follow */
788 OUTLONG(ms_per_frame); /* Microseconds per frame */
789 //ThOe ->0
790 // OUTLONG(10000000); /* MaxBytesPerSec, I hope this will never be used */
791 OUTLONG(0);
792 OUTLONG(0); /* PaddingGranularity (whatever that might be) */
793 /* Other sources call it 'reserved' */
794 flag = AVIF_ISINTERLEAVED;
795 if(hasIndex) flag |= AVIF_HASINDEX;
796 if(hasIndex && AVI->must_use_index) flag |= AVIF_MUSTUSEINDEX;
797 OUTLONG(flag); /* Flags */
798 OUTLONG(0); // no frames yet
799 OUTLONG(0); /* InitialFrames */
800
801 OUTLONG(AVI->anum+1);
802
803 OUTLONG(0); /* SuggestedBufferSize */
804 OUTLONG(AVI->width); /* Width */
805 OUTLONG(AVI->height); /* Height */
806 /* MS calls the following 'reserved': */
807 OUTLONG(0); /* TimeScale: Unit used to measure time */
808 OUTLONG(0); /* DataRate: Data rate of playback */
809 OUTLONG(0); /* StartTime: Starting time of AVI data */
810 OUTLONG(0); /* DataLength: Size of AVI data chunk */
811
812
813 /* Start the video stream list ---------------------------------- */
814
815 OUT4CC ("LIST");
816 OUTLONG(0); /* Length of list in bytes, don't know yet */
817 strl_start = nhb; /* Store start position */
818 OUT4CC ("strl");
819
820 /* The video stream header */
821
822 OUT4CC ("strh");
823 OUTLONG(56); /* # of bytes to follow */
824 OUT4CC ("vids"); /* Type */
825 OUT4CC (AVI->compressor); /* Handler */
826 OUTLONG(0); /* Flags */
827 OUTLONG(0); /* Reserved, MS says: wPriority, wLanguage */
828 OUTLONG(0); /* InitialFrames */
829 OUTLONG(FRAME_RATE_SCALE); /* Scale */
830 OUTLONG(frate); /* Rate: Rate/Scale == samples/second */
831 OUTLONG(0); /* Start */
832 OUTLONG(0); // no frames yet
833 OUTLONG(0); /* SuggestedBufferSize */
834 OUTLONG(-1); /* Quality */
835 OUTLONG(0); /* SampleSize */
836 OUTLONG(0); /* Frame */
837 OUTLONG(0); /* Frame */
838 // OUTLONG(0); /* Frame */
839 //OUTLONG(0); /* Frame */
840
841 /* The video stream format */
842
843 xd_size = AVI->extradata_size;
844 xd_size_align2 = (AVI->extradata_size+1) & ~1;
845
846 OUT4CC ("strf");
847 OUTLONG(40 + xd_size_align2);/* # of bytes to follow */
848 OUTLONG(40 + xd_size); /* Size */
849 OUTLONG(AVI->width); /* Width */
850 OUTLONG(AVI->height); /* Height */
851 OUTSHRT(1); OUTSHRT(24); /* Planes, Count */
852 OUT4CC (AVI->compressor); /* Compression */
853 // ThOe (*3)
854 OUTLONG(AVI->width*AVI->height*3); /* SizeImage (in bytes?) */
855 OUTLONG(0); /* XPelsPerMeter */
856 OUTLONG(0); /* YPelsPerMeter */
857 OUTLONG(0); /* ClrUsed: Number of colors used */
858 OUTLONG(0); /* ClrImportant: Number of colors important */
859
860 // write extradata
861 if (xd_size > 0 && AVI->extradata) {
862 OUTMEM(AVI->extradata, xd_size);
863 if (xd_size != xd_size_align2) {
864 OUTCHR(0);
865 }
866 }
867
868 /* Finish stream list, i.e. put number of bytes in the list to proper pos */
869
870 long2str(AVI_header+strl_start-4,nhb-strl_start);
871
872
873 /* Start the audio stream list ---------------------------------- */
874
875 for(j=0; j<AVI->anum; ++j) {
876
877 sampsize = avi_sampsize(AVI, j);
878
879 OUT4CC ("LIST");
880 OUTLONG(0); /* Length of list in bytes, don't know yet */
881 strl_start = nhb; /* Store start position */
882 OUT4CC ("strl");
883
884 /* The audio stream header */
885
886 OUT4CC ("strh");
887 OUTLONG(56); /* # of bytes to follow */
888 OUT4CC ("auds");
889
890 // -----------
891 // ThOe
892 OUTLONG(0); /* Format (Optionally) */
893 // -----------
894
895 OUTLONG(0); /* Flags */
896 OUTLONG(0); /* Reserved, MS says: wPriority, wLanguage */
897 OUTLONG(0); /* InitialFrames */
898
899 // ThOe /4
900 OUTLONG(sampsize/4); /* Scale */
901 OUTLONG(1000*AVI->track[j].mp3rate/8);
902 OUTLONG(0); /* Start */
903 OUTLONG(4*AVI->track[j].audio_bytes/sampsize); /* Length */
904 OUTLONG(0); /* SuggestedBufferSize */
905 OUTLONG(-1); /* Quality */
906
907 // ThOe /4
908 OUTLONG(sampsize/4); /* SampleSize */
909
910 OUTLONG(0); /* Frame */
911 OUTLONG(0); /* Frame */
912 // OUTLONG(0); /* Frame */
913 //OUTLONG(0); /* Frame */
914
915 /* The audio stream format */
916
917 OUT4CC ("strf");
918 OUTLONG(16); /* # of bytes to follow */
919 OUTSHRT(AVI->track[j].a_fmt); /* Format */
920 OUTSHRT(AVI->track[j].a_chans); /* Number of channels */
921 OUTLONG(AVI->track[j].a_rate); /* SamplesPerSec */
922 // ThOe
923 OUTLONG(1000*AVI->track[j].mp3rate/8);
924 //ThOe (/4)
925
926 OUTSHRT(sampsize/4); /* BlockAlign */
927
928
929 OUTSHRT(AVI->track[j].a_bits); /* BitsPerSample */
930
931 /* Finish stream list, i.e. put number of bytes in the list to proper pos */
932
933 long2str(AVI_header+strl_start-4,nhb-strl_start);
934 }
935
936 /* Finish header list */
937
938 long2str(AVI_header+hdrl_start-4,nhb-hdrl_start);
939
940
941 /* Calculate the needed amount of junk bytes, output junk */
942
943 njunk = HEADERBYTES - nhb - 8 - 12;
944
945 /* Safety first: if njunk <= 0, somebody has played with
946 HEADERBYTES without knowing what (s)he did.
947 This is a fatal error */
948
949 if(njunk<=0)
950 {
951 fprintf(stderr,"AVI_close_output_file: # of header bytes too small\n");
952 exit(1);
953 }
954
955 OUT4CC ("JUNK");
956 OUTLONG(njunk);
957 memset(AVI_header+nhb,0,njunk);
958
959 nhb += njunk;
960
961 /* Start the movi list */
962
963 OUT4CC ("LIST");
964 OUTLONG(movi_len); /* Length of list in bytes */
965 OUT4CC ("movi");
966
967 /* Output the header, truncate the file to the number of bytes
968 actually written, report an error if someting goes wrong */
969
970 if ( xio_lseek(AVI->fdes,0,SEEK_SET)<0 ||
971 avi_write(AVI->fdes,(char *)AVI_header,HEADERBYTES)!=HEADERBYTES ||
972 xio_lseek(AVI->fdes,AVI->pos,SEEK_SET)<0)
973 {
974 AVI_errno = AVI_ERR_CLOSE;
975 return -1;
976 }
977
978 return 0;
979 }
980
valid_info_tag(char * c)981 static int valid_info_tag(char *c)
982 {
983 if (!strncmp(c, "IARL", 4)) return 1;
984 else if (!strncmp(c, "IART", 4)) return 1;
985 else if (!strncmp(c, "ICMS", 4)) return 1;
986 else if (!strncmp(c, "ICMT", 4)) return 1;
987 else if (!strncmp(c, "ICOP", 4)) return 1;
988 else if (!strncmp(c, "ICRD", 4)) return 1;
989 else if (!strncmp(c, "ICRP", 4)) return 1;
990 else if (!strncmp(c, "IDIM", 4)) return 1;
991 else if (!strncmp(c, "IDPI", 4)) return 1;
992 else if (!strncmp(c, "IENG", 4)) return 1;
993 else if (!strncmp(c, "IGNR", 4)) return 1;
994 else if (!strncmp(c, "IKEY", 4)) return 1;
995 else if (!strncmp(c, "ILGT", 4)) return 1;
996 else if (!strncmp(c, "IMED", 4)) return 1;
997 else if (!strncmp(c, "INAM", 4)) return 1;
998 else if (!strncmp(c, "IPLT", 4)) return 1;
999 else if (!strncmp(c, "IPRD", 4)) return 1;
1000 else if (!strncmp(c, "ISBJ", 4)) return 1;
1001 else if (!strncmp(c, "ISHP", 4)) return 1;
1002 else if (!strncmp(c, "ISRC", 4)) return 1;
1003 else if (!strncmp(c, "ISRF", 4)) return 1;
1004 else if (!strncmp(c, "ITCH", 4)) return 1;
1005 else return 0;
1006
1007 return 0;
1008 }
1009 // see ../docs/avi_comments.txt
1010 // returns the length of written stream (-1 on error)
avi_parse_comments(int fd,char * buf,int space_left)1011 static int avi_parse_comments (int fd, char *buf, int space_left)
1012 {
1013 int len=0, readlen=0, k;
1014 char *data, *c, *d;
1015 struct stat st;
1016
1017 // safety checks
1018 if (fd<=0 || !buf || space_left<=0)
1019 return -1;
1020
1021 memset (buf, 0, space_left);
1022 if (fstat (fd, &st) == -1) {
1023 perror ("stat");
1024 return -1;
1025 }
1026
1027 if ( !(data = malloc(st.st_size*sizeof(char)+1)) ) {
1028 fprintf(stderr, "malloc failed\n");
1029 return -1;
1030 }
1031
1032 readlen = avi_read ( fd, data, st.st_size);
1033
1034 //printf("Read %d bytes from %d\n", readlen, fd);
1035
1036 c = data;
1037 space_left--;
1038
1039 while (len < space_left) {
1040 if ( !c || *c == '\0')
1041 break; // eof;
1042 else if (*c == '#') { // comment, ignore
1043 c = strchr(c, '\n')+1;
1044 }
1045 else if (*c == '\n') { // empty, ignore
1046 c++;
1047 }
1048 else if (*c == 'I') {
1049
1050 // do not write ISFT -- this is written by transcode
1051 // and important for debugging.
1052 if (!valid_info_tag(c)) {
1053 // skip this line
1054 while (c && *c && *c != '\n' ) {
1055 c++;
1056 }
1057 continue;
1058 }
1059
1060 // set d after TAG
1061 d = c+4;
1062
1063 // find first non-blank (!space or !TAB)
1064 while ( d && *d && (*d == ' ' || *d == ' ')) ++d;
1065 if (!d) break;
1066
1067 // TAG without argument is fine but ignored
1068 if (*d == '\n' || *d == '\r') {
1069 c = d+1;
1070 if (*c == '\n') ++c;
1071 continue;
1072 }
1073
1074 k = 0;
1075 while (d[k] != '\r' && d[k] != '\n' && d[k] != '\0') ++k;
1076 if (k>=space_left) return len;
1077
1078 // write TAG
1079 memcpy(buf+len,c,4);
1080 len += 4;
1081
1082 // write length + '\0'
1083 long2str(buf+len, k+1); len += 4;
1084
1085 // write comment string
1086 memcpy (buf+len, d, k);
1087 // must be null terminated
1088 *(buf+len+k+1) = '\0';
1089
1090 // PAD
1091 if ((k+1)&1) {
1092 k++;
1093 *(buf+len+k+1) = '\0';
1094 }
1095 len += k+1;
1096
1097 // advance c
1098 while (*c != '\n' && *c != '\0') ++c;
1099 if (*c != '\0') ++c;
1100 else break;
1101
1102 } else {
1103
1104 // ignore junk lines
1105 while (c && *c && *c != '\n' ) {
1106 if (*c == ' ' || *c == ' ') { c++; break; }
1107 c++;
1108 }
1109 if (!c) break;
1110 }
1111
1112 }
1113 free(data);
1114
1115 return len;
1116 }
1117
1118 //SLM
1119 #ifndef S_IRUSR
1120 #define S_IRWXU 00700 /* read, write, execute: owner */
1121 #define S_IRUSR 00400 /* read permission: owner */
1122 #define S_IWUSR 00200 /* write permission: owner */
1123 #define S_IXUSR 00100 /* execute permission: owner */
1124 #define S_IRWXG 00070 /* read, write, execute: group */
1125 #define S_IRGRP 00040 /* read permission: group */
1126 #define S_IWGRP 00020 /* write permission: group */
1127 #define S_IXGRP 00010 /* execute permission: group */
1128 #define S_IRWXO 00007 /* read, write, execute: other */
1129 #define S_IROTH 00004 /* read permission: other */
1130 #define S_IWOTH 00002 /* write permission: other */
1131 #define S_IXOTH 00001 /* execute permission: other */
1132 #endif
1133
1134 /*
1135 Write the header of an AVI file and close it.
1136 returns 0 on success, -1 on write error.
1137 */
1138
avi_close_output_file(avi_t * AVI)1139 static int avi_close_output_file(avi_t *AVI)
1140 {
1141
1142 int ret, njunk, sampsize, hasIndex, ms_per_frame, frate, idxerror, flag;
1143 unsigned long movi_len;
1144 int hdrl_start, strl_start, j;
1145 unsigned char AVI_header[HEADERBYTES];
1146 long nhb;
1147 unsigned long xd_size, xd_size_align2;
1148
1149 #ifdef INFO_LIST
1150 long info_len;
1151 long id_len, real_id_len;
1152 long info_start_pos;
1153 // time_t calptr;
1154 #endif
1155
1156 /* Calculate length of movi list */
1157
1158 // dump the rest of the index
1159 if (AVI->is_opendml) {
1160 int cur_std_idx = AVI->video_superindex->nEntriesInUse-1;
1161 int audtr;
1162
1163 #ifdef DEBUG_ODML
1164 printf("ODML dump the rest indices\n");
1165 #endif
1166 avi_ixnn_entry (AVI, AVI->video_superindex->stdindex[cur_std_idx],
1167 &AVI->video_superindex->aIndex[cur_std_idx]);
1168
1169 AVI->video_superindex->aIndex[cur_std_idx].dwDuration =
1170 AVI->video_superindex->stdindex[cur_std_idx]->nEntriesInUse - 1;
1171
1172 for (audtr = 0; audtr < AVI->anum; audtr++) {
1173 if (!AVI->track[audtr].audio_superindex) {
1174 // not initialized -> no index
1175 continue;
1176 }
1177 avi_ixnn_entry (AVI, AVI->track[audtr].audio_superindex->stdindex[cur_std_idx],
1178 &AVI->track[audtr].audio_superindex->aIndex[cur_std_idx]);
1179 AVI->track[audtr].audio_superindex->aIndex[cur_std_idx].dwDuration =
1180 AVI->track[audtr].audio_superindex->stdindex[cur_std_idx]->nEntriesInUse - 1;
1181 if (AVI->track[audtr].a_fmt == 0x1) {
1182 AVI->track[audtr].audio_superindex->aIndex[cur_std_idx].dwDuration *=
1183 AVI->track[audtr].a_bits*AVI->track[audtr].a_rate*AVI->track[audtr].a_chans/800;
1184 }
1185 }
1186 // The AVI->video_superindex->nEntriesInUse contains the offset
1187 AVI->video_superindex->stdindex[ cur_std_idx+1 ]->qwBaseOffset = AVI->pos;
1188 }
1189
1190 if (AVI->is_opendml) {
1191 // Correct!
1192 movi_len = AVI->video_superindex->stdindex[ 1 ]->qwBaseOffset - HEADERBYTES+4 - AVI->n_idx*16 - 8;
1193 } else {
1194 movi_len = AVI->pos - HEADERBYTES + 4;
1195 }
1196
1197
1198 /* Try to ouput the index entries. This may fail e.g. if no space
1199 is left on device. We will report this as an error, but we still
1200 try to write the header correctly (so that the file still may be
1201 readable in the most cases */
1202
1203 idxerror = 0;
1204 hasIndex = 1;
1205 if (!AVI->is_opendml) {
1206 // fprintf(stderr, "pos=%lu, index_len=%ld \n", AVI->pos, AVI->n_idx*16);
1207 ret = avi_add_chunk(AVI, (unsigned char *)"idx1", (unsigned char *)AVI->idx, AVI->n_idx*16);
1208 hasIndex = (ret==0);
1209 //fprintf(stderr, "pos=%lu, index_len=%d\n", AVI->pos, hasIndex);
1210
1211 if(ret) {
1212 idxerror = 1;
1213 AVI_errno = AVI_ERR_WRITE_INDEX;
1214 }
1215 }
1216
1217 /* Calculate Microseconds per frame */
1218
1219 if(AVI->fps < 0.001) {
1220 frate=0;
1221 ms_per_frame=0;
1222 } else {
1223 frate = (int) (FRAME_RATE_SCALE*AVI->fps + 0.5);
1224 ms_per_frame=(int) (1000000/AVI->fps + 0.5);
1225 }
1226
1227 /* Prepare the file header */
1228
1229 nhb = 0;
1230
1231 /* The RIFF header */
1232
1233 OUT4CC ("RIFF");
1234 if (AVI->is_opendml) {
1235 OUTLONG(AVI->video_superindex->stdindex[ 1 ]->qwBaseOffset - 8); /* # of bytes to follow */
1236 } else {
1237 OUTLONG(AVI->pos - 8); /* # of bytes to follow */
1238 }
1239
1240 OUT4CC ("AVI ");
1241
1242 /* Start the header list */
1243
1244 OUT4CC ("LIST");
1245 OUTLONG(0); /* Length of list in bytes, don't know yet */
1246 hdrl_start = nhb; /* Store start position */
1247 OUT4CC ("hdrl");
1248
1249 /* The main AVI header */
1250
1251 /* The Flags in AVI File header */
1252
1253 #define AVIF_HASINDEX 0x00000010 /* Index at end of file */
1254 #define AVIF_MUSTUSEINDEX 0x00000020
1255 #define AVIF_ISINTERLEAVED 0x00000100
1256 #define AVIF_TRUSTCKTYPE 0x00000800 /* Use CKType to find key frames */
1257 #define AVIF_WASCAPTUREFILE 0x00010000
1258 #define AVIF_COPYRIGHTED 0x00020000
1259
1260 OUT4CC ("avih");
1261 OUTLONG(56); /* # of bytes to follow */
1262 OUTLONG(ms_per_frame); /* Microseconds per frame */
1263 //ThOe ->0
1264 // OUTLONG(10000000); /* MaxBytesPerSec, I hope this will never be used */
1265 OUTLONG(0);
1266 OUTLONG(0); /* PaddingGranularity (whatever that might be) */
1267 /* Other sources call it 'reserved' */
1268 flag = AVIF_ISINTERLEAVED;
1269 if(hasIndex) flag |= AVIF_HASINDEX;
1270 if(hasIndex && AVI->must_use_index) flag |= AVIF_MUSTUSEINDEX;
1271 OUTLONG(flag); /* Flags */
1272 OUTLONG(AVI->video_frames); /* TotalFrames */
1273 OUTLONG(0); /* InitialFrames */
1274
1275 OUTLONG(AVI->anum+1);
1276 // if (AVI->track[0].audio_bytes)
1277 // { OUTLONG(2); } /* Streams */
1278 // else
1279 // { OUTLONG(1); } /* Streams */
1280
1281 OUTLONG(0); /* SuggestedBufferSize */
1282 OUTLONG(AVI->width); /* Width */
1283 OUTLONG(AVI->height); /* Height */
1284 /* MS calls the following 'reserved': */
1285 OUTLONG(0); /* TimeScale: Unit used to measure time */
1286 OUTLONG(0); /* DataRate: Data rate of playback */
1287 OUTLONG(0); /* StartTime: Starting time of AVI data */
1288 OUTLONG(0); /* DataLength: Size of AVI data chunk */
1289
1290
1291 /* Start the video stream list ---------------------------------- */
1292
1293 OUT4CC ("LIST");
1294 OUTLONG(0); /* Length of list in bytes, don't know yet */
1295 strl_start = nhb; /* Store start position */
1296 OUT4CC ("strl");
1297
1298 /* The video stream header */
1299
1300 OUT4CC ("strh");
1301 OUTLONG(56); /* # of bytes to follow */
1302 OUT4CC ("vids"); /* Type */
1303 OUT4CC (AVI->compressor); /* Handler */
1304 OUTLONG(0); /* Flags */
1305 OUTLONG(0); /* Reserved, MS says: wPriority, wLanguage */
1306 OUTLONG(0); /* InitialFrames */
1307 OUTLONG(FRAME_RATE_SCALE); /* Scale */
1308 OUTLONG(frate); /* Rate: Rate/Scale == samples/second */
1309 OUTLONG(0); /* Start */
1310 OUTLONG(AVI->video_frames); /* Length */
1311 OUTLONG(AVI->max_len); /* SuggestedBufferSize */
1312 OUTLONG(0); /* Quality */
1313 OUTLONG(0); /* SampleSize */
1314 OUTLONG(0); /* Frame */
1315 OUTLONG(0); /* Frame */
1316 //OUTLONG(0); /* Frame */
1317 //OUTLONG(0); /* Frame */
1318
1319 /* The video stream format */
1320
1321 xd_size = AVI->extradata_size;
1322 xd_size_align2 = (AVI->extradata_size+1) & ~1;
1323
1324 OUT4CC ("strf");
1325 OUTLONG(40 + xd_size_align2);/* # of bytes to follow */
1326 OUTLONG(40 + xd_size); /* Size */
1327 OUTLONG(AVI->width); /* Width */
1328 OUTLONG(AVI->height); /* Height */
1329 OUTSHRT(1); OUTSHRT(24); /* Planes, Count */
1330 OUT4CC (AVI->compressor); /* Compression */
1331 // ThOe (*3)
1332 OUTLONG(AVI->width*AVI->height*3); /* SizeImage (in bytes?) */
1333 OUTLONG(0); /* XPelsPerMeter */
1334 OUTLONG(0); /* YPelsPerMeter */
1335 OUTLONG(0); /* ClrUsed: Number of colors used */
1336 OUTLONG(0); /* ClrImportant: Number of colors important */
1337
1338 // write extradata if present
1339 if (xd_size > 0 && AVI->extradata) {
1340 OUTMEM(AVI->extradata, xd_size);
1341 if (xd_size != xd_size_align2) {
1342 OUTCHR(0);
1343 }
1344 }
1345
1346 // dump index of indices for audio
1347 if (AVI->is_opendml) {
1348
1349 int k;
1350
1351 OUT4CC(AVI->video_superindex->fcc);
1352 OUTLONG(2+1+1+4+4+3*4 + AVI->video_superindex->nEntriesInUse * (8+4+4));
1353 OUTSHRT(AVI->video_superindex->wLongsPerEntry);
1354 OUTCHR(AVI->video_superindex->bIndexSubType);
1355 OUTCHR(AVI->video_superindex->bIndexType);
1356 OUTLONG(AVI->video_superindex->nEntriesInUse);
1357 OUT4CC(AVI->video_superindex->dwChunkId);
1358 OUTLONG(0);
1359 OUTLONG(0);
1360 OUTLONG(0);
1361
1362
1363 for (k = 0; k < AVI->video_superindex->nEntriesInUse; k++) {
1364 uint32_t r = (AVI->video_superindex->aIndex[k].qwOffset >> 32) & 0xffffffff;
1365 uint32_t s = (AVI->video_superindex->aIndex[k].qwOffset) & 0xffffffff;
1366
1367 printf("VID NrEntries %d/%ld (%c%c%c%c) |0x%llX|%ld|%ld|\n", k,
1368 (unsigned long)AVI->video_superindex->nEntriesInUse,
1369 AVI->video_superindex->dwChunkId[0],
1370 AVI->video_superindex->dwChunkId[1],
1371 AVI->video_superindex->dwChunkId[2],
1372 AVI->video_superindex->dwChunkId[3],
1373 (unsigned long long)AVI->video_superindex->aIndex[k].qwOffset,
1374 (unsigned long)AVI->video_superindex->aIndex[k].dwSize,
1375 (unsigned long)AVI->video_superindex->aIndex[k].dwDuration
1376 );
1377 /*
1378 */
1379
1380 OUTLONG(s);
1381 OUTLONG(r);
1382 OUTLONG(AVI->video_superindex->aIndex[k].dwSize);
1383 OUTLONG(AVI->video_superindex->aIndex[k].dwDuration);
1384 }
1385
1386 }
1387
1388 /* Finish stream list, i.e. put number of bytes in the list to proper pos */
1389
1390 long2str(AVI_header+strl_start-4,nhb-strl_start);
1391
1392 /* Start the audio stream list ---------------------------------- */
1393
1394 for(j=0; j<AVI->anum; ++j) {
1395
1396 //if (AVI->track[j].a_chans && AVI->track[j].audio_bytes)
1397 {
1398 unsigned long nBlockAlign = 0;
1399 unsigned long avgbsec = 0;
1400 unsigned long scalerate = 0;
1401
1402 sampsize = avi_sampsize(AVI, j);
1403 sampsize = AVI->track[j].a_fmt==0x1?sampsize*4:sampsize;
1404
1405 nBlockAlign = (AVI->track[j].a_rate<32000)?576:1152;
1406 /*
1407 printf("XXX sampsize (%d) block (%ld) rate (%ld) audio_bytes (%ld) mp3rate(%ld,%ld)\n",
1408 sampsize, nBlockAlign, AVI->track[j].a_rate,
1409 (long int)AVI->track[j].audio_bytes,
1410 1000*AVI->track[j].mp3rate/8, AVI->track[j].mp3rate);
1411 */
1412
1413 if (AVI->track[j].a_fmt==0x1) {
1414 sampsize = (AVI->track[j].a_chans<2)?sampsize/2:sampsize;
1415 avgbsec = AVI->track[j].a_rate*sampsize/4;
1416 scalerate = AVI->track[j].a_rate*sampsize/4;
1417 } else {
1418 avgbsec = 1000*AVI->track[j].mp3rate/8;
1419 scalerate = 1000*AVI->track[j].mp3rate/8;
1420 }
1421
1422 OUT4CC ("LIST");
1423 OUTLONG(0); /* Length of list in bytes, don't know yet */
1424 strl_start = nhb; /* Store start position */
1425 OUT4CC ("strl");
1426
1427 /* The audio stream header */
1428
1429 OUT4CC ("strh");
1430 OUTLONG(56); /* # of bytes to follow */
1431 OUT4CC ("auds");
1432
1433 // -----------
1434 // ThOe
1435 OUTLONG(0); /* Format (Optionally) */
1436 // -----------
1437
1438 OUTLONG(0); /* Flags */
1439 OUTLONG(0); /* Reserved, MS says: wPriority, wLanguage */
1440 OUTLONG(0); /* InitialFrames */
1441
1442 // VBR
1443 if (AVI->track[j].a_fmt == 0x55 && AVI->track[j].a_vbr) {
1444 OUTLONG(nBlockAlign); /* Scale */
1445 OUTLONG(AVI->track[j].a_rate); /* Rate */
1446 OUTLONG(0); /* Start */
1447 OUTLONG(AVI->track[j].audio_chunks); /* Length */
1448 OUTLONG(0); /* SuggestedBufferSize */
1449 OUTLONG(0); /* Quality */
1450 OUTLONG(0); /* SampleSize */
1451 OUTLONG(0); /* Frame */
1452 OUTLONG(0); /* Frame */
1453 } else {
1454 OUTLONG(sampsize/4); /* Scale */
1455 OUTLONG(scalerate); /* Rate */
1456 OUTLONG(0); /* Start */
1457 OUTLONG(4*AVI->track[j].audio_bytes/sampsize); /* Length */
1458 OUTLONG(0); /* SuggestedBufferSize */
1459 OUTLONG(0xffffffff); /* Quality */
1460 OUTLONG(sampsize/4); /* SampleSize */
1461 OUTLONG(0); /* Frame */
1462 OUTLONG(0); /* Frame */
1463 }
1464
1465 /* The audio stream format */
1466
1467 OUT4CC ("strf");
1468
1469 if (AVI->track[j].a_fmt == 0x55 && AVI->track[j].a_vbr) {
1470
1471 OUTLONG(30); /* # of bytes to follow */ // mplayer writes 28
1472 OUTSHRT(AVI->track[j].a_fmt); /* Format */ // 2
1473 OUTSHRT(AVI->track[j].a_chans); /* Number of channels */ // 2
1474 OUTLONG(AVI->track[j].a_rate); /* SamplesPerSec */ // 4
1475 //ThOe/tibit
1476 OUTLONG(1000*AVI->track[j].mp3rate/8); /* maybe we should write an avg. */ // 4
1477 OUTSHRT(nBlockAlign); /* BlockAlign */ // 2
1478 OUTSHRT(AVI->track[j].a_bits); /* BitsPerSample */ // 2
1479
1480 OUTSHRT(12); /* cbSize */ // 2
1481 OUTSHRT(1); /* wID */ // 2
1482 OUTLONG(2); /* fdwFlags */ // 4
1483 OUTSHRT(nBlockAlign); /* nBlockSize */ // 2
1484 OUTSHRT(1); /* nFramesPerBlock */ // 2
1485 OUTSHRT(0); /* nCodecDelay */ // 2
1486
1487 } else if (AVI->track[j].a_fmt == 0x55 && !AVI->track[j].a_vbr) {
1488
1489 OUTLONG(30); /* # of bytes to follow */
1490 OUTSHRT(AVI->track[j].a_fmt); /* Format */
1491 OUTSHRT(AVI->track[j].a_chans); /* Number of channels */
1492 OUTLONG(AVI->track[j].a_rate); /* SamplesPerSec */
1493 //ThOe/tibit
1494 OUTLONG(1000*AVI->track[j].mp3rate/8);
1495 OUTSHRT(sampsize/4); /* BlockAlign */
1496 OUTSHRT(AVI->track[j].a_bits); /* BitsPerSample */
1497
1498 OUTSHRT(12); /* cbSize */
1499 OUTSHRT(1); /* wID */
1500 OUTLONG(2); /* fdwFlags */
1501 OUTSHRT(nBlockAlign); /* nBlockSize */
1502 OUTSHRT(1); /* nFramesPerBlock */
1503 OUTSHRT(0); /* nCodecDelay */
1504
1505 } else {
1506
1507 OUTLONG(18); /* # of bytes to follow */
1508 OUTSHRT(AVI->track[j].a_fmt); /* Format */
1509 OUTSHRT(AVI->track[j].a_chans); /* Number of channels */
1510 OUTLONG(AVI->track[j].a_rate); /* SamplesPerSec */
1511 //ThOe/tibit
1512 OUTLONG(avgbsec); /* Avg bytes/sec */
1513 OUTSHRT(sampsize/4); /* BlockAlign */
1514 OUTSHRT(AVI->track[j].a_bits); /* BitsPerSample */
1515 OUTSHRT(0); /* cbSize */
1516
1517 }
1518 }
1519 if (AVI->is_opendml) {
1520
1521 int k ;
1522
1523 if (!AVI->track[j].audio_superindex) {
1524 // not initialized -> no index
1525 continue;
1526 }
1527
1528 OUT4CC(AVI->track[j].audio_superindex->fcc); /* "indx" */
1529 OUTLONG(2+1+1+4+4+3*4 + AVI->track[j].audio_superindex->nEntriesInUse * (8+4+4));
1530 OUTSHRT(AVI->track[j].audio_superindex->wLongsPerEntry);
1531 OUTCHR(AVI->track[j].audio_superindex->bIndexSubType);
1532 OUTCHR(AVI->track[j].audio_superindex->bIndexType);
1533 OUTLONG(AVI->track[j].audio_superindex->nEntriesInUse);
1534 OUT4CC(AVI->track[j].audio_superindex->dwChunkId);
1535 OUTLONG(0); OUTLONG(0); OUTLONG(0);
1536
1537 for (k = 0; k < AVI->track[j].audio_superindex->nEntriesInUse; k++) {
1538 uint32_t r = (AVI->track[j].audio_superindex->aIndex[k].qwOffset >> 32) & 0xffffffff;
1539 uint32_t s = (AVI->track[j].audio_superindex->aIndex[k].qwOffset) & 0xffffffff;
1540
1541 /*
1542 printf("AUD[%d] NrEntries %d/%ld (%c%c%c%c) |0x%llX|%ld|%ld| \n", j, k,
1543 AVI->track[j].audio_superindex->nEntriesInUse,
1544 AVI->track[j].audio_superindex->dwChunkId[0], AVI->track[j].audio_superindex->dwChunkId[1],
1545 AVI->track[j].audio_superindex->dwChunkId[2], AVI->track[j].audio_superindex->dwChunkId[3],
1546 AVI->track[j].audio_superindex->aIndex[k].qwOffset,
1547 AVI->track[j].audio_superindex->aIndex[k].dwSize,
1548 AVI->track[j].audio_superindex->aIndex[k].dwDuration
1549 );
1550 */
1551
1552 OUTLONG(s);
1553 OUTLONG(r);
1554 OUTLONG(AVI->track[j].audio_superindex->aIndex[k].dwSize);
1555 OUTLONG(AVI->track[j].audio_superindex->aIndex[k].dwDuration);
1556 }
1557 }
1558 /* Finish stream list, i.e. put number of bytes in the list to proper pos */
1559 long2str(AVI_header+strl_start-4,nhb-strl_start);
1560 }
1561
1562 if (AVI->is_opendml) {
1563 OUT4CC("LIST");
1564 OUTLONG(16);
1565 OUT4CC("odml");
1566 OUT4CC("dmlh");
1567 OUTLONG(4);
1568 OUTLONG(AVI->total_frames);
1569 }
1570
1571 /* Finish header list */
1572
1573 long2str(AVI_header+hdrl_start-4,nhb-hdrl_start);
1574
1575
1576 // add INFO list --- (0.6.0pre4)
1577
1578 #ifdef INFO_LIST
1579 OUT4CC ("LIST");
1580
1581 info_start_pos = nhb;
1582 info_len = MAX_INFO_STRLEN + 12;
1583 OUTLONG(info_len); // rewritten later
1584 OUT4CC ("INFO");
1585
1586 OUT4CC ("ISFT");
1587 //OUTLONG(MAX_INFO_STRLEN);
1588 memset(id_str, 0, MAX_INFO_STRLEN);
1589
1590 sprintf(id_str, "%s-%s", PACKAGE, VERSION);
1591 real_id_len = id_len = strlen(id_str)+1;
1592 if (id_len&1) id_len++;
1593
1594 OUTLONG(real_id_len);
1595
1596 memset(AVI_header+nhb, 0, id_len);
1597 memcpy(AVI_header+nhb, id_str, id_len);
1598 nhb += id_len;
1599
1600 info_len = avi_parse_comments (AVI->comment_fd, AVI_header+nhb, HEADERBYTES - nhb - 8 - 12);
1601 if (info_len <= 0) info_len=0;
1602
1603 // write correct len
1604 long2str(AVI_header+info_start_pos, info_len + id_len + 4+4+4);
1605
1606 nhb += info_len;
1607
1608 // OUT4CC ("ICMT");
1609 // OUTLONG(MAX_INFO_STRLEN);
1610
1611 // calptr=time(NULL);
1612 // sprintf(id_str, "\t%s %s", ctime(&calptr), "");
1613 // memset(AVI_header+nhb, 0, MAX_INFO_STRLEN);
1614 // memcpy(AVI_header+nhb, id_str, 25);
1615 // nhb += MAX_INFO_STRLEN;
1616 #endif
1617
1618 // ----------------------------
1619
1620 /* Calculate the needed amount of junk bytes, output junk */
1621
1622 njunk = HEADERBYTES - nhb - 8 - 12;
1623
1624 /* Safety first: if njunk <= 0, somebody has played with
1625 HEADERBYTES without knowing what (s)he did.
1626 This is a fatal error */
1627
1628 if(njunk<=0)
1629 {
1630 fprintf(stderr,"AVI_close_output_file: # of header bytes too small\n");
1631 exit(1);
1632 }
1633
1634 OUT4CC ("JUNK");
1635 OUTLONG(njunk);
1636 memset(AVI_header+nhb,0,njunk);
1637
1638 nhb += njunk;
1639
1640 /* Start the movi list */
1641
1642 OUT4CC ("LIST");
1643 OUTLONG(movi_len); /* Length of list in bytes */
1644 OUT4CC ("movi");
1645
1646 /* Output the header, truncate the file to the number of bytes
1647 actually written, report an error if someting goes wrong */
1648
1649 if ( xio_lseek(AVI->fdes,0,SEEK_SET)<0 ||
1650 avi_write(AVI->fdes,(char *)AVI_header,HEADERBYTES)!=HEADERBYTES ||
1651 xio_ftruncate(AVI->fdes,AVI->pos)<0 )
1652 {
1653 AVI_errno = AVI_ERR_CLOSE;
1654 return -1;
1655 }
1656
1657
1658 // Fix up the empty additional RIFF and LIST chunks
1659 if (AVI->is_opendml) {
1660 int k = 0;
1661 char f[4];
1662 unsigned int len;
1663
1664 for (k=1; k<AVI->video_superindex->nEntriesInUse; k++) {
1665 // the len of the RIFF Chunk
1666 xio_lseek(AVI->fdes, AVI->video_superindex->stdindex[k]->qwBaseOffset+4, SEEK_SET);
1667 len = AVI->video_superindex->stdindex[k+1]->qwBaseOffset -
1668 AVI->video_superindex->stdindex[k]->qwBaseOffset - 8;
1669 long2str(f, len);
1670 avi_write(AVI->fdes, f, 4);
1671
1672 // len of the LIST/movi chunk
1673 xio_lseek(AVI->fdes, 8, SEEK_CUR);
1674 len -= 12;
1675 long2str(f, len);
1676 avi_write(AVI->fdes, f, 4);
1677 }
1678 }
1679
1680
1681 if(idxerror) return -1;
1682
1683 return 0;
1684 }
1685
1686 /*
1687 AVI_write_data:
1688 Add video or audio data to the file;
1689
1690 Return values:
1691 0 No error;
1692 -1 Error, AVI_errno is set appropriatly;
1693
1694 */
1695
avi_write_data(avi_t * AVI,char * data,unsigned long length,int audio,int keyframe)1696 static int avi_write_data(avi_t *AVI, char *data, unsigned long length, int audio, int keyframe)
1697 {
1698 int n = 0;
1699
1700 unsigned char astr[5];
1701
1702 // transcode core itself checks for the size -- unneeded and
1703 // does harm to xvid 2pass encodes where the first pass can get
1704 // _very_ large -- tibit.
1705
1706 #if 0
1707 /* Check for maximum file length */
1708
1709 if ( (AVI->pos + 8 + length + 8 + (AVI->n_idx+1)*16) > AVI_MAX_LEN ) {
1710 AVI_errno = AVI_ERR_SIZELIM;
1711 return -1;
1712 }
1713 #endif
1714
1715 /* Add index entry */
1716
1717 //set tag for current audio track
1718 sprintf((char *)astr, "0%1dwb", (int)(AVI->aptr+1));
1719
1720 if(audio) {
1721 if (!AVI->is_opendml) n = avi_add_index_entry(AVI,astr,0x10,AVI->pos,length);
1722 n += avi_add_odml_index_entry(AVI,astr,0x10,AVI->pos,length);
1723 } else {
1724 if (!AVI->is_opendml) n = avi_add_index_entry(AVI,(unsigned char *)"00db",((keyframe)?0x10:0x0),AVI->pos,length);
1725 n += avi_add_odml_index_entry(AVI,(unsigned char *)"00db",((keyframe)?0x10:0x0),AVI->pos,length);
1726 }
1727
1728 if(n) return -1;
1729
1730 /* Output tag and data */
1731
1732 if(audio)
1733 n = avi_add_chunk(AVI,(unsigned char *)astr,data,length);
1734 else
1735 n = avi_add_chunk(AVI,(unsigned char *)"00db",data,length);
1736
1737 if (n) return -1;
1738
1739 return 0;
1740 }
1741
AVI_write_frame(avi_t * AVI,char * data,long bytes,int keyframe)1742 int AVI_write_frame(avi_t *AVI, char *data, long bytes, int keyframe)
1743 {
1744 int64_t pos;
1745
1746 if(AVI->mode==AVI_MODE_READ) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
1747
1748 pos = AVI->pos;
1749
1750 if(avi_write_data(AVI,data,bytes,0,keyframe)) return -1;
1751
1752 AVI->last_pos = pos;
1753 AVI->last_len = bytes;
1754 AVI->video_frames++;
1755 return 0;
1756 }
1757
AVI_dup_frame(avi_t * AVI)1758 int AVI_dup_frame(avi_t *AVI)
1759 {
1760 if(AVI->mode==AVI_MODE_READ) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
1761
1762 if(AVI->last_pos==0) return 0; /* No previous real frame */
1763 if(avi_add_index_entry(AVI,(unsigned char *)"00db",0x10,AVI->last_pos,AVI->last_len)) return -1;
1764 AVI->video_frames++;
1765 AVI->must_use_index = 1;
1766 return 0;
1767 }
1768
AVI_write_audio(avi_t * AVI,char * data,long bytes)1769 int AVI_write_audio(avi_t *AVI, char *data, long bytes)
1770 {
1771 if(AVI->mode==AVI_MODE_READ) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
1772
1773 if( avi_write_data(AVI,data,bytes,1,0) ) return -1;
1774 AVI->track[AVI->aptr].audio_bytes += bytes;
1775 AVI->track[AVI->aptr].audio_chunks++;
1776 return 0;
1777 }
1778
1779
AVI_append_audio(avi_t * AVI,char * data,long bytes)1780 int AVI_append_audio(avi_t *AVI, char *data, long bytes)
1781 {
1782
1783 // won't work for >2gb
1784 long i, length, pos;
1785 unsigned char c[4];
1786
1787 if(AVI->mode==AVI_MODE_READ) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
1788
1789 // update last index entry:
1790
1791 --AVI->n_idx;
1792 length = str2ulong(AVI->idx[AVI->n_idx]+12);
1793 pos = str2ulong(AVI->idx[AVI->n_idx]+8);
1794
1795 //update;
1796 long2str(AVI->idx[AVI->n_idx]+12,length+bytes);
1797
1798 ++AVI->n_idx;
1799
1800 AVI->track[AVI->aptr].audio_bytes += bytes;
1801
1802 //update chunk header
1803 xio_lseek(AVI->fdes, pos+4, SEEK_SET);
1804 long2str(c, length+bytes);
1805 avi_write(AVI->fdes, (char *)c, 4);
1806
1807 xio_lseek(AVI->fdes, pos+8+length, SEEK_SET);
1808
1809 i=PAD_EVEN(length + bytes);
1810
1811 bytes = i - length;
1812 avi_write(AVI->fdes, data, bytes);
1813 AVI->pos = pos + 8 + i;
1814
1815 return 0;
1816 }
1817
1818
AVI_bytes_remain(avi_t * AVI)1819 long AVI_bytes_remain(avi_t *AVI)
1820 {
1821 if(AVI->mode==AVI_MODE_READ) return 0;
1822
1823 return ( AVI_MAX_LEN - (AVI->pos + 8 + 16*AVI->n_idx));
1824 }
1825
AVI_bytes_written(avi_t * AVI)1826 long AVI_bytes_written(avi_t *AVI)
1827 {
1828 if(AVI->mode==AVI_MODE_READ) return 0;
1829
1830 return (AVI->pos + 8 + 16*AVI->n_idx);
1831 }
1832
AVI_set_audio_track(avi_t * AVI,int track)1833 int AVI_set_audio_track(avi_t *AVI, int track)
1834 {
1835
1836 if(track < 0 || track + 1 > AVI->anum) return(-1);
1837
1838 //this info is not written to file anyway
1839 AVI->aptr=track;
1840 return 0;
1841 }
1842
AVI_get_audio_track(avi_t * AVI)1843 int AVI_get_audio_track(avi_t *AVI)
1844 {
1845 return(AVI->aptr);
1846 }
1847
AVI_set_audio_vbr(avi_t * AVI,long is_vbr)1848 void AVI_set_audio_vbr(avi_t *AVI, long is_vbr)
1849 {
1850 AVI->track[AVI->aptr].a_vbr = is_vbr;
1851 }
1852
AVI_get_audio_vbr(avi_t * AVI)1853 long AVI_get_audio_vbr(avi_t *AVI)
1854 {
1855 return(AVI->track[AVI->aptr].a_vbr);
1856 }
1857
AVI_set_comment_fd(avi_t * AVI,int fd)1858 void AVI_set_comment_fd(avi_t *AVI, int fd)
1859 {
1860 AVI->comment_fd = fd;
1861 }
AVI_get_comment_fd(avi_t * AVI)1862 int AVI_get_comment_fd(avi_t *AVI)
1863 {
1864 return AVI->comment_fd;
1865 }
1866
1867
1868 /*******************************************************************
1869 * *
1870 * Utilities for reading video and audio from an AVI File *
1871 * *
1872 *******************************************************************/
1873
AVI_close(avi_t * AVI)1874 int AVI_close(avi_t *AVI)
1875 {
1876 int ret;
1877 int j;
1878
1879 /* If the file was open for writing, the header and index still have
1880 to be written */
1881
1882 if(AVI->mode == AVI_MODE_WRITE)
1883 ret = avi_close_output_file(AVI);
1884 else
1885 ret = 0;
1886
1887 /* Even if there happened an error, we first clean up */
1888
1889 if (AVI->comment_fd>0)
1890 xio_close(AVI->comment_fd);
1891 AVI->comment_fd = -1;
1892 xio_close(AVI->fdes);
1893 if(AVI->idx) free(AVI->idx);
1894 if(AVI->video_index) free(AVI->video_index);
1895 if(AVI->video_superindex) {
1896 if(AVI->video_superindex->aIndex) free(AVI->video_superindex->aIndex);
1897 free(AVI->video_superindex);
1898 }
1899
1900 for (j=0; j<AVI->anum; j++)
1901 {
1902 if(AVI->track[j].audio_index) free(AVI->track[j].audio_index);
1903 if(AVI->track[j].audio_superindex) {
1904 if(AVI->track[j].audio_superindex->aIndex) free(AVI->track[j].audio_superindex->aIndex);
1905 free(AVI->track[j].audio_superindex);
1906 }
1907 }
1908
1909 if (AVI->bitmap_info_header)
1910 free(AVI->bitmap_info_header);
1911 for (j = 0; j < AVI->anum; j++)
1912 if (AVI->wave_format_ex[j])
1913 free(AVI->wave_format_ex[j]);
1914
1915 free(AVI);
1916 AVI=NULL;
1917
1918 return ret;
1919 }
1920
1921
1922 #define ERR_EXIT(x) \
1923 { \
1924 AVI_close(AVI); \
1925 AVI_errno = x; \
1926 return 0; \
1927 }
1928
AVI_open_input_indexfile(char * filename,int getIndex,char * indexfile)1929 avi_t *AVI_open_input_indexfile(char *filename, int getIndex, char *indexfile)
1930 {
1931 avi_t *AVI=NULL;
1932
1933 /* Create avi_t structure */
1934
1935 AVI = (avi_t *) malloc(sizeof(avi_t));
1936 if(AVI==NULL)
1937 {
1938 AVI_errno = AVI_ERR_NO_MEM;
1939 return 0;
1940 }
1941 memset((void *)AVI,0,sizeof(avi_t));
1942
1943 AVI->mode = AVI_MODE_READ; /* open for reading */
1944
1945 /* Open the file */
1946
1947 #if defined(SYS_WINDOWS)
1948 AVI->fdes = open(filename,O_RDONLY|O_BINARY);
1949 #else
1950 AVI->fdes = xio_open(filename,O_RDONLY);
1951 #endif
1952 if(AVI->fdes < 0)
1953 {
1954 AVI_errno = AVI_ERR_OPEN;
1955 free(AVI);
1956 return 0;
1957 }
1958
1959 AVI->index_file=strdup(indexfile);
1960 AVI_errno = 0;
1961 avi_parse_input_file(AVI, getIndex);
1962
1963 if (AVI != NULL && !AVI_errno) {
1964 AVI->aptr=0; //reset
1965 }
1966
1967 if (AVI_errno)
1968 return AVI=NULL;
1969 else
1970 return AVI;
1971 }
1972
AVI_open_indexfd(int fd,int getIndex,char * indexfile)1973 avi_t *AVI_open_indexfd(int fd, int getIndex, char *indexfile)
1974 {
1975 avi_t *AVI=NULL;
1976
1977 /* Create avi_t structure */
1978
1979 AVI = (avi_t *) malloc(sizeof(avi_t));
1980 if(AVI==NULL)
1981 {
1982 AVI_errno = AVI_ERR_NO_MEM;
1983 return 0;
1984 }
1985 memset((void *)AVI,0,sizeof(avi_t));
1986
1987 AVI->mode = AVI_MODE_READ; /* open for reading */
1988
1989 // file alread open
1990 AVI->fdes = fd;
1991
1992 AVI->index_file=strdup(indexfile);
1993 AVI_errno = 0;
1994 avi_parse_input_file(AVI, getIndex);
1995
1996 if (AVI != NULL && !AVI_errno) {
1997 AVI->aptr=0; //reset
1998 }
1999
2000 if (AVI_errno)
2001 return AVI=NULL;
2002 else
2003 return AVI;
2004 }
2005
2006
AVI_open_input_file(char * filename,int getIndex)2007 avi_t *AVI_open_input_file(char *filename, int getIndex)
2008 {
2009 avi_t *AVI=NULL;
2010
2011 /* Create avi_t structure */
2012
2013 AVI = (avi_t *) malloc(sizeof(avi_t));
2014 if(AVI==NULL)
2015 {
2016 AVI_errno = AVI_ERR_NO_MEM;
2017 return 0;
2018 }
2019 memset((void *)AVI,0,sizeof(avi_t));
2020
2021 AVI->mode = AVI_MODE_READ; /* open for reading */
2022
2023 /* Open the file */
2024
2025 AVI->fdes = xio_open(filename,O_RDONLY);
2026 if(AVI->fdes < 0)
2027 {
2028 AVI_errno = AVI_ERR_OPEN;
2029 free(AVI);
2030 return 0;
2031 }
2032
2033 AVI_errno = 0;
2034 avi_parse_input_file(AVI, getIndex);
2035
2036 if (AVI != NULL && !AVI_errno) {
2037 AVI->aptr=0; //reset
2038 }
2039
2040 if (AVI_errno)
2041 return AVI=NULL;
2042 else
2043 return AVI;
2044 }
2045
AVI_open_fd(int fd,int getIndex)2046 avi_t *AVI_open_fd(int fd, int getIndex)
2047 {
2048 avi_t *AVI=NULL;
2049
2050 /* Create avi_t structure */
2051
2052 AVI = (avi_t *) malloc(sizeof(avi_t));
2053 if(AVI==NULL)
2054 {
2055 AVI_errno = AVI_ERR_NO_MEM;
2056 return 0;
2057 }
2058 memset((void *)AVI,0,sizeof(avi_t));
2059
2060 AVI->mode = AVI_MODE_READ; /* open for reading */
2061
2062 // file alread open
2063 AVI->fdes = fd;
2064
2065 AVI_errno = 0;
2066 avi_parse_input_file(AVI, getIndex);
2067
2068 if (AVI != NULL && !AVI_errno) {
2069 AVI->aptr=0; //reset
2070 }
2071
2072 if (AVI_errno)
2073 return AVI=NULL;
2074 else
2075 return AVI;
2076 }
2077
2078 // transcode-0.6.8
2079 // reads a file generated by aviindex and builds the index out of it.
2080
avi_parse_index_from_file(avi_t * AVI,char * filename)2081 int avi_parse_index_from_file(avi_t *AVI, char *filename)
2082 {
2083 char data[100]; // line buffer
2084 FILE *fd = NULL; // read from
2085 int64_t pos, len, f_pos, tot_chunks[AVI_MAX_TRACKS];
2086 int key=0, type;
2087 int vid_chunks=0, aud_chunks[AVI_MAX_TRACKS];
2088 long line_count=0;
2089 char *c, d;
2090 int i,j;
2091
2092 for (i=0; i<AVI_MAX_TRACKS; i++) aud_chunks[i] = 0;
2093 i=0;
2094
2095 // already have an index -- may be incomplete
2096 if (AVI->video_index) {
2097 free(AVI->video_index);
2098 AVI->video_index = NULL;
2099 }
2100
2101 for(j=0; j<AVI->anum; ++j) {
2102 if(AVI->track[j].audio_index) {
2103 free(AVI->track[j].audio_index);
2104 }
2105 AVI->track[j].audio_index = NULL;
2106 AVI->track[j].audio_chunks = 0;
2107 }
2108
2109 if (!(fd = fopen(filename, "r"))) { perror ("avi_parse_index_from_file: fopen"); return -1; }
2110
2111 // read header
2112 fgets(data, 100, fd);
2113
2114 if ( strncasecmp(data, "AVIIDX1", 7) != 0) {
2115 fprintf(stderr, "%s: Not an AVI index file\n", filename);
2116 return -1;
2117 }
2118
2119 // read comment
2120 fgets(data, 100, fd);
2121 f_pos = ftell(fd);
2122 while (fgets(data, 100, fd)) {
2123 d = data[5] - '1';
2124 if (d == 0) {
2125 vid_chunks++;
2126 } else if (d == 1 || d == 2 || d == 3 || d == 4 ||
2127 d == 5 || d == 6 || d == 7 || d == 8 ) {
2128 aud_chunks[d-1]++;
2129 } else
2130 continue;
2131
2132 line_count++;
2133 }
2134
2135 AVI->video_frames = vid_chunks;
2136 for(j=0; j<AVI->anum; ++j) AVI->track[j].audio_chunks = aud_chunks[j];
2137
2138 if(AVI->video_frames==0) ERR_EXIT(AVI_ERR_NO_VIDS);
2139 AVI->video_index = (video_index_entry *) malloc(vid_chunks*sizeof(video_index_entry));
2140 if(AVI->video_index==0) ERR_EXIT(AVI_ERR_NO_MEM);
2141
2142 for(j=0; j<AVI->anum; ++j) {
2143 if(AVI->track[j].audio_chunks) {
2144 AVI->track[j].audio_index = (audio_index_entry *) malloc(aud_chunks[j]*sizeof(audio_index_entry));
2145 if(AVI->track[j].audio_index==0) ERR_EXIT(AVI_ERR_NO_MEM);
2146 }
2147 }
2148
2149 // reset after header
2150 fseek(fd, f_pos, SEEK_SET);
2151
2152 vid_chunks = 0;
2153 for(j=0; j<AVI->anum; ++j) aud_chunks[j] = tot_chunks[j] = 0;
2154
2155 while (fgets(data, 100, fd)) {
2156 // this is very slow
2157 // sscanf(data, "%*s %d %*d %*d %lld %lld %d %*f", &type, &pos, &len, &key);
2158 c = strchr (data, ' ');
2159 type = strtol(c+1, &c, 10);
2160 //ch = strtol(c+1, &c, 10);
2161 c = strchr(c+1, ' ');
2162 //chtype= strtol(c+1, &c, 10);
2163 c = strchr(c+1, ' ');
2164 pos = strtoll(c+1, &c, 10);
2165 len = strtol(c+1, &c, 10);
2166 key = strtol(c+1, &c, 10);
2167 //ms = strtod(c+1, NULL);
2168 i = type-1;
2169
2170 switch (i) {
2171 case 0: // video
2172 AVI->video_index[vid_chunks].key = (int64_t)(key?0x10:0);
2173 AVI->video_index[vid_chunks].pos = pos+8;
2174 AVI->video_index[vid_chunks].len = len;
2175 vid_chunks++;
2176 break;
2177 case 1: case 2: case 3: case 4:
2178 case 5: case 6: case 7: case 8:
2179 j=i-1;
2180 AVI->track[j].audio_index[aud_chunks[j]].pos = pos+8;
2181 AVI->track[j].audio_index[aud_chunks[j]].len = len;
2182 AVI->track[j].audio_index[aud_chunks[j]].tot = tot_chunks[j];
2183 tot_chunks[j] += AVI->track[j].audio_index[aud_chunks[j]].len;
2184 aud_chunks[j]++;
2185 break;
2186 default:
2187 continue;
2188 }
2189
2190 }
2191 for(j=0; j<AVI->anum; ++j) AVI->track[j].audio_bytes = tot_chunks[j];
2192
2193 fclose (fd);
2194
2195 return 0;
2196 }
2197
avi_parse_input_file(avi_t * AVI,int getIndex)2198 int avi_parse_input_file(avi_t *AVI, int getIndex)
2199 {
2200 long i, rate, scale, idx_type;
2201 int64_t n;
2202 unsigned char *hdrl_data;
2203 long header_offset=0, hdrl_len=0;
2204 long nvi, nai[AVI_MAX_TRACKS], ioff;
2205 long tot[AVI_MAX_TRACKS];
2206 int j;
2207 int lasttag = 0;
2208 int vids_strh_seen = 0;
2209 int vids_strf_seen = 0;
2210 int auds_strh_seen = 0;
2211 // int auds_strf_seen = 0;
2212 int num_stream = 0;
2213 char data[256];
2214 int64_t oldpos=-1, newpos=-1;
2215
2216 /* Read first 12 bytes and check that this is an AVI file */
2217
2218 if( avi_read(AVI->fdes,data,12) != 12 ) ERR_EXIT(AVI_ERR_READ)
2219
2220 if( strncasecmp(data ,"RIFF",4) !=0 ||
2221 strncasecmp(data+8,"AVI ",4) !=0 ) ERR_EXIT(AVI_ERR_NO_AVI)
2222
2223 /* Go through the AVI file and extract the header list,
2224 the start position of the 'movi' list and an optionally
2225 present idx1 tag */
2226
2227 hdrl_data = 0;
2228
2229
2230 while(1)
2231 {
2232 if( avi_read(AVI->fdes,data,8) != 8 ) break; /* We assume it's EOF */
2233 newpos=xio_lseek(AVI->fdes,0,SEEK_CUR);
2234 if(oldpos==newpos) {
2235 /* This is a broken AVI stream... */
2236 return -1;
2237 }
2238 oldpos=newpos;
2239
2240 n = str2ulong((unsigned char *)data+4);
2241 n = PAD_EVEN(n);
2242
2243 if(strncasecmp(data,"LIST",4) == 0)
2244 {
2245 if( avi_read(AVI->fdes,data,4) != 4 ) ERR_EXIT(AVI_ERR_READ)
2246 n -= 4;
2247 if(strncasecmp(data,"hdrl",4) == 0)
2248 {
2249 hdrl_len = n;
2250 hdrl_data = (unsigned char *) malloc(n);
2251 if(hdrl_data==0) ERR_EXIT(AVI_ERR_NO_MEM);
2252
2253 // offset of header
2254
2255 header_offset = xio_lseek(AVI->fdes,0,SEEK_CUR);
2256
2257 if( avi_read(AVI->fdes,(char *)hdrl_data,n) != n ) ERR_EXIT(AVI_ERR_READ)
2258 }
2259 else if(strncasecmp(data,"movi",4) == 0)
2260 {
2261 AVI->movi_start = xio_lseek(AVI->fdes,0,SEEK_CUR);
2262 if (xio_lseek(AVI->fdes,n,SEEK_CUR)==(int64_t)-1) break;
2263 }
2264 else
2265 if (xio_lseek(AVI->fdes,n,SEEK_CUR)==(int64_t)-1) break;
2266 }
2267 else if(strncasecmp(data,"idx1",4) == 0)
2268 {
2269 /* n must be a multiple of 16, but the reading does not
2270 break if this is not the case */
2271
2272 AVI->n_idx = AVI->max_idx = n/16;
2273 AVI->idx = (unsigned char((*)[16]) ) malloc(n);
2274 if(AVI->idx==0) ERR_EXIT(AVI_ERR_NO_MEM)
2275 if(avi_read(AVI->fdes, (char *) AVI->idx, n) != n ) {
2276 free ( AVI->idx); AVI->idx=NULL;
2277 AVI->n_idx = 0;
2278 }
2279 }
2280 else
2281 xio_lseek(AVI->fdes,n,SEEK_CUR);
2282 }
2283
2284 if(!hdrl_data ) ERR_EXIT(AVI_ERR_NO_HDRL)
2285 if(!AVI->movi_start) ERR_EXIT(AVI_ERR_NO_MOVI)
2286
2287 /* Interpret the header list */
2288
2289 for(i=0;i<hdrl_len;)
2290 {
2291 /* List tags are completly ignored */
2292
2293 #ifdef DEBUG_ODML
2294 printf("TAG %c%c%c%c\n", (hdrl_data+i)[0], (hdrl_data+i)[1], (hdrl_data+i)[2], (hdrl_data+i)[3]);
2295 #endif
2296
2297 if(strncasecmp((char *)hdrl_data+i,"LIST",4)==0) { i+= 12; continue; }
2298
2299 n = str2ulong(hdrl_data+i+4);
2300 n = PAD_EVEN(n);
2301
2302
2303 /* Interpret the tag and its args */
2304
2305 if(strncasecmp((char *)hdrl_data+i,"strh",4)==0)
2306 {
2307 i += 8;
2308 #ifdef DEBUG_ODML
2309 printf("TAG %c%c%c%c\n", (hdrl_data+i)[0], (hdrl_data+i)[1], (hdrl_data+i)[2], (hdrl_data+i)[3]);
2310 #endif
2311 if(strncasecmp((char *)hdrl_data+i,"vids",4) == 0 && !vids_strh_seen)
2312 {
2313 memcpy(AVI->compressor,hdrl_data+i+4,4);
2314 AVI->compressor[4] = 0;
2315
2316 // ThOe
2317 AVI->v_codech_off = header_offset + i+4;
2318
2319 scale = str2ulong(hdrl_data+i+20);
2320 rate = str2ulong(hdrl_data+i+24);
2321 if(scale!=0) AVI->fps = (double)rate/(double)scale;
2322 AVI->video_frames = str2ulong(hdrl_data+i+32);
2323 AVI->video_strn = num_stream;
2324 AVI->max_len = 0;
2325 vids_strh_seen = 1;
2326 lasttag = 1; /* vids */
2327 memcpy(&AVI->video_stream_header, hdrl_data + i,
2328 sizeof(alAVISTREAMHEADER));
2329 }
2330 else if (strncasecmp ((char *)hdrl_data+i,"auds",4) ==0 && ! auds_strh_seen)
2331 {
2332
2333 //inc audio tracks
2334 AVI->aptr=AVI->anum;
2335 ++AVI->anum;
2336
2337 if(AVI->anum > AVI_MAX_TRACKS) {
2338 fprintf(stderr, "error - only %d audio tracks supported\n", AVI_MAX_TRACKS);
2339 return(-1);
2340 }
2341
2342 AVI->track[AVI->aptr].audio_bytes = str2ulong(hdrl_data+i+32)*avi_sampsize(AVI, 0);
2343 AVI->track[AVI->aptr].audio_strn = num_stream;
2344
2345 // if samplesize==0 -> vbr
2346 AVI->track[AVI->aptr].a_vbr = !str2ulong(hdrl_data+i+44);
2347
2348 AVI->track[AVI->aptr].padrate = str2ulong(hdrl_data+i+24);
2349 memcpy(&AVI->stream_headers[AVI->aptr], hdrl_data + i,
2350 sizeof(alAVISTREAMHEADER));
2351
2352 // auds_strh_seen = 1;
2353 lasttag = 2; /* auds */
2354
2355 // ThOe
2356 AVI->track[AVI->aptr].a_codech_off = header_offset + i;
2357
2358 }
2359 else if (strncasecmp (hdrl_data+i,"iavs",4) ==0 && ! auds_strh_seen) {
2360 fprintf(stderr, "AVILIB: error - DV AVI Type 1 no supported\n");
2361 return (-1);
2362 }
2363 else
2364 lasttag = 0;
2365 num_stream++;
2366 }
2367 else if(strncasecmp(hdrl_data+i,"dmlh",4) == 0) {
2368 AVI->total_frames = str2ulong(hdrl_data+i+8);
2369 #ifdef DEBUG_ODML
2370 fprintf(stderr, "real number of frames %d\n", AVI->total_frames);
2371 #endif
2372 i += 8;
2373 }
2374 else if(strncasecmp((char *)hdrl_data+i,"strf",4)==0)
2375 {
2376 i += 8;
2377 if(lasttag == 1)
2378 {
2379 alBITMAPINFOHEADER bih;
2380
2381 memcpy(&bih, hdrl_data + i, sizeof(alBITMAPINFOHEADER));
2382 AVI->bitmap_info_header = (alBITMAPINFOHEADER *)
2383 malloc(str2ulong((unsigned char *)&bih.bi_size));
2384 if (AVI->bitmap_info_header != NULL)
2385 memcpy(AVI->bitmap_info_header, hdrl_data + i,
2386 str2ulong((unsigned char *)&bih.bi_size));
2387
2388 AVI->width = str2ulong(hdrl_data+i+4);
2389 AVI->height = str2ulong(hdrl_data+i+8);
2390 vids_strf_seen = 1;
2391 //ThOe
2392 AVI->v_codecf_off = header_offset + i+16;
2393
2394 memcpy(AVI->compressor2, hdrl_data+i+16, 4);
2395 AVI->compressor2[4] = 0;
2396
2397 }
2398 else if(lasttag == 2)
2399 {
2400 alWAVEFORMATEX *wfe;
2401 char *nwfe;
2402 int wfes;
2403
2404 if ((hdrl_len - i) < sizeof(alWAVEFORMATEX))
2405 wfes = hdrl_len - i;
2406 else
2407 wfes = sizeof(alWAVEFORMATEX);
2408 wfe = (alWAVEFORMATEX *)malloc(sizeof(alWAVEFORMATEX));
2409 if (wfe != NULL) {
2410 memset(wfe, 0, sizeof(alWAVEFORMATEX));
2411 memcpy(wfe, hdrl_data + i, wfes);
2412 if (str2ushort((unsigned char *)&wfe->cb_size) != 0) {
2413 nwfe = (char *)
2414 realloc(wfe, sizeof(alWAVEFORMATEX) +
2415 str2ushort((unsigned char *)&wfe->cb_size));
2416 if (nwfe != 0) {
2417 int64_t lpos = xio_lseek(AVI->fdes, 0, SEEK_CUR);
2418 xio_lseek(AVI->fdes, header_offset + i + sizeof(alWAVEFORMATEX),
2419 SEEK_SET);
2420 wfe = (alWAVEFORMATEX *)nwfe;
2421 nwfe = &nwfe[sizeof(alWAVEFORMATEX)];
2422 avi_read(AVI->fdes, nwfe,
2423 str2ushort((unsigned char *)&wfe->cb_size));
2424 xio_lseek(AVI->fdes, lpos, SEEK_SET);
2425 }
2426 }
2427 AVI->wave_format_ex[AVI->aptr] = wfe;
2428 }
2429
2430 AVI->track[AVI->aptr].a_fmt = str2ushort(hdrl_data+i );
2431
2432 //ThOe
2433 AVI->track[AVI->aptr].a_codecf_off = header_offset + i;
2434
2435 AVI->track[AVI->aptr].a_chans = str2ushort(hdrl_data+i+2);
2436 AVI->track[AVI->aptr].a_rate = str2ulong (hdrl_data+i+4);
2437 //ThOe: read mp3bitrate
2438 AVI->track[AVI->aptr].mp3rate = 8*str2ulong(hdrl_data+i+8)/1000;
2439 //:ThOe
2440 AVI->track[AVI->aptr].a_bits = str2ushort(hdrl_data+i+14);
2441 // auds_strf_seen = 1;
2442 }
2443 }
2444 else if(strncasecmp(hdrl_data+i,"indx",4) == 0) {
2445 char *a;
2446 int j;
2447
2448 if(lasttag == 1) // V I D E O
2449 {
2450
2451 a = hdrl_data+i;
2452
2453 AVI->video_superindex = (avisuperindex_chunk *) malloc (sizeof (avisuperindex_chunk));
2454 memcpy (AVI->video_superindex->fcc, a, 4); a += 4;
2455 AVI->video_superindex->dwSize = str2ulong(a); a += 4;
2456 AVI->video_superindex->wLongsPerEntry = str2ushort(a); a += 2;
2457 AVI->video_superindex->bIndexSubType = *a; a += 1;
2458 AVI->video_superindex->bIndexType = *a; a += 1;
2459 AVI->video_superindex->nEntriesInUse = str2ulong(a); a += 4;
2460 memcpy (AVI->video_superindex->dwChunkId, a, 4); a += 4;
2461
2462 // 3 * reserved
2463 a += 4; a += 4; a += 4;
2464
2465 if (AVI->video_superindex->bIndexSubType != 0) {fprintf(stderr, "Invalid Header, bIndexSubType != 0\n"); }
2466
2467 AVI->video_superindex->aIndex =
2468 malloc (AVI->video_superindex->wLongsPerEntry * AVI->video_superindex->nEntriesInUse * sizeof (uint32_t));
2469
2470 // position of ix## chunks
2471 for (j=0; j<AVI->video_superindex->nEntriesInUse; ++j) {
2472 AVI->video_superindex->aIndex[j].qwOffset = str2ullong (a); a += 8;
2473 AVI->video_superindex->aIndex[j].dwSize = str2ulong (a); a += 4;
2474 AVI->video_superindex->aIndex[j].dwDuration = str2ulong (a); a += 4;
2475
2476 #ifdef DEBUG_ODML
2477 printf("[%d] 0x%llx 0x%lx %lu\n", j,
2478 (unsigned long long)AVI->video_superindex->aIndex[j].qwOffset,
2479 (unsigned long)AVI->video_superindex->aIndex[j].dwSize,
2480 (unsigned long)AVI->video_superindex->aIndex[j].dwDuration);
2481 #endif
2482 }
2483
2484
2485 #ifdef DEBUG_ODML
2486 printf("FOURCC \"%c%c%c%c\"\n", AVI->video_superindex->fcc[0], AVI->video_superindex->fcc[1],
2487 AVI->video_superindex->fcc[2], AVI->video_superindex->fcc[3]);
2488 printf("LEN \"%ld\"\n", (long)AVI->video_superindex->dwSize);
2489 printf("wLongsPerEntry \"%d\"\n", AVI->video_superindex->wLongsPerEntry);
2490 printf("bIndexSubType \"%d\"\n", AVI->video_superindex->bIndexSubType);
2491 printf("bIndexType \"%d\"\n", AVI->video_superindex->bIndexType);
2492 printf("nEntriesInUse \"%ld\"\n", (long)AVI->video_superindex->nEntriesInUse);
2493 printf("dwChunkId \"%c%c%c%c\"\n", AVI->video_superindex->dwChunkId[0], AVI->video_superindex->dwChunkId[1],
2494 AVI->video_superindex->dwChunkId[2], AVI->video_superindex->dwChunkId[3]);
2495 printf("--\n");
2496 #endif
2497
2498 AVI->is_opendml = 1;
2499
2500 }
2501 else if(lasttag == 2) // A U D I O
2502 {
2503
2504 a = hdrl_data+i;
2505
2506 AVI->track[AVI->aptr].audio_superindex = (avisuperindex_chunk *) malloc (sizeof (avisuperindex_chunk));
2507 memcpy (AVI->track[AVI->aptr].audio_superindex->fcc, a, 4); a += 4;
2508 AVI->track[AVI->aptr].audio_superindex->dwSize = str2ulong(a); a += 4;
2509 AVI->track[AVI->aptr].audio_superindex->wLongsPerEntry = str2ushort(a); a += 2;
2510 AVI->track[AVI->aptr].audio_superindex->bIndexSubType = *a; a += 1;
2511 AVI->track[AVI->aptr].audio_superindex->bIndexType = *a; a += 1;
2512 AVI->track[AVI->aptr].audio_superindex->nEntriesInUse = str2ulong(a); a += 4;
2513 memcpy (AVI->track[AVI->aptr].audio_superindex->dwChunkId, a, 4); a += 4;
2514
2515 // 3 * reserved
2516 a += 4; a += 4; a += 4;
2517
2518 if (AVI->track[AVI->aptr].audio_superindex->bIndexSubType != 0) {fprintf(stderr, "Invalid Header, bIndexSubType != 0\n"); }
2519
2520 AVI->track[AVI->aptr].audio_superindex->aIndex =
2521 malloc (AVI->track[AVI->aptr].audio_superindex->wLongsPerEntry *
2522 AVI->track[AVI->aptr].audio_superindex->nEntriesInUse * sizeof (uint32_t));
2523
2524 // position of ix## chunks
2525 for (j=0; j<AVI->track[AVI->aptr].audio_superindex->nEntriesInUse; ++j) {
2526 AVI->track[AVI->aptr].audio_superindex->aIndex[j].qwOffset = str2ullong (a); a += 8;
2527 AVI->track[AVI->aptr].audio_superindex->aIndex[j].dwSize = str2ulong (a); a += 4;
2528 AVI->track[AVI->aptr].audio_superindex->aIndex[j].dwDuration = str2ulong (a); a += 4;
2529
2530 #ifdef DEBUG_ODML
2531 printf("[%d] 0x%llx 0x%lx %lu\n", j,
2532 (unsigned long long)AVI->track[AVI->aptr].audio_superindex->aIndex[j].qwOffset,
2533 (unsigned long)AVI->track[AVI->aptr].audio_superindex->aIndex[j].dwSize,
2534 (unsigned long)AVI->track[AVI->aptr].audio_superindex->aIndex[j].dwDuration);
2535 #endif
2536 }
2537
2538 #ifdef DEBUG_ODML
2539 printf("FOURCC \"%.4s\"\n", AVI->track[AVI->aptr].audio_superindex->fcc);
2540 printf("LEN \"%ld\"\n", (long)AVI->track[AVI->aptr].audio_superindex->dwSize);
2541 printf("wLongsPerEntry \"%d\"\n", AVI->track[AVI->aptr].audio_superindex->wLongsPerEntry);
2542 printf("bIndexSubType \"%d\"\n", AVI->track[AVI->aptr].audio_superindex->bIndexSubType);
2543 printf("bIndexType \"%d\"\n", AVI->track[AVI->aptr].audio_superindex->bIndexType);
2544 printf("nEntriesInUse \"%ld\"\n", (long)AVI->track[AVI->aptr].audio_superindex->nEntriesInUse);
2545 printf("dwChunkId \"%.4s\"\n", AVI->track[AVI->aptr].audio_superindex->dwChunkId[0]);
2546 printf("--\n");
2547 #endif
2548
2549 }
2550 i += 8;
2551 }
2552 else if((strncasecmp(hdrl_data+i,"JUNK",4) == 0) ||
2553 (strncasecmp(hdrl_data+i,"strn",4) == 0) ||
2554 (strncasecmp(hdrl_data+i,"vprp",4) == 0)){
2555 i += 8;
2556 // do not reset lasttag
2557 } else
2558 {
2559 i += 8;
2560 lasttag = 0;
2561 }
2562 //printf("adding %ld bytes\n", (long int)n);
2563
2564 i += n;
2565 }
2566
2567 free(hdrl_data);
2568
2569 if(!vids_strh_seen || !vids_strf_seen) ERR_EXIT(AVI_ERR_NO_VIDS)
2570
2571 AVI->video_tag[0] = AVI->video_strn/10 + '0';
2572 AVI->video_tag[1] = AVI->video_strn%10 + '0';
2573 AVI->video_tag[2] = 'd';
2574 AVI->video_tag[3] = 'b';
2575
2576 /* Audio tag is set to "99wb" if no audio present */
2577 if(!AVI->track[0].a_chans) AVI->track[0].audio_strn = 99;
2578
2579 {
2580 int i=0;
2581 for(j=0; j<AVI->anum+1; ++j) {
2582 if (j == AVI->video_strn) continue;
2583 AVI->track[i].audio_tag[0] = j/10 + '0';
2584 AVI->track[i].audio_tag[1] = j%10 + '0';
2585 AVI->track[i].audio_tag[2] = 'w';
2586 AVI->track[i].audio_tag[3] = 'b';
2587 ++i;
2588 }
2589 }
2590
2591 xio_lseek(AVI->fdes,AVI->movi_start,SEEK_SET);
2592
2593 /* get index if wanted */
2594
2595 if(AVI->index_file && !getIndex) {
2596 int ret;
2597
2598 ret = avi_parse_index_from_file(AVI, AVI->index_file);
2599
2600 /* Reposition the file */
2601
2602 xio_lseek(AVI->fdes,AVI->movi_start,SEEK_SET);
2603 AVI->video_pos = 0;
2604 return (ret);
2605
2606 }
2607 if(!getIndex) return(0);
2608
2609 /* if the file has an idx1, check if this is relative
2610 to the start of the file or to the start of the movi list */
2611
2612 idx_type = 0;
2613
2614 if(AVI->idx)
2615 {
2616 int64_t pos, len;
2617
2618 /* Search the first videoframe in the idx1 and look where
2619 it is in the file */
2620
2621 for(i=0;i<AVI->n_idx;i++)
2622 if( strncasecmp((char *)AVI->idx[i],(char *)AVI->video_tag,3)==0 ) break;
2623 if(i>=AVI->n_idx) ERR_EXIT(AVI_ERR_NO_VIDS)
2624
2625 pos = str2ulong(AVI->idx[i]+ 8);
2626 len = str2ulong(AVI->idx[i]+12);
2627
2628 xio_lseek(AVI->fdes,pos,SEEK_SET);
2629 if(avi_read(AVI->fdes,data,8)!=8) ERR_EXIT(AVI_ERR_READ)
2630 if( strncasecmp(data,(char *)AVI->idx[i],4)==0 && str2ulong((unsigned char *)data+4)==len )
2631 {
2632 idx_type = 1; /* Index from start of file */
2633 }
2634 else
2635 {
2636 xio_lseek(AVI->fdes,pos+AVI->movi_start-4,SEEK_SET);
2637 if(avi_read(AVI->fdes,data,8)!=8) ERR_EXIT(AVI_ERR_READ)
2638 if( strncasecmp(data,(char *)AVI->idx[i],4)==0 && str2ulong((unsigned char *)data+4)==len )
2639 {
2640 idx_type = 2; /* Index from start of movi list */
2641 }
2642 }
2643 /* idx_type remains 0 if neither of the two tests above succeeds */
2644 }
2645
2646
2647 if(idx_type == 0 && !AVI->is_opendml && !AVI->total_frames)
2648 {
2649 /* we must search through the file to get the index */
2650
2651 xio_lseek(AVI->fdes, AVI->movi_start, SEEK_SET);
2652
2653 AVI->n_idx = 0;
2654
2655 while(1)
2656 {
2657 if( avi_read(AVI->fdes,data,8) != 8 ) break;
2658 n = str2ulong((unsigned char *)data+4);
2659
2660 /* The movi list may contain sub-lists, ignore them */
2661
2662 if(strncasecmp(data,"LIST",4)==0)
2663 {
2664 xio_lseek(AVI->fdes,4,SEEK_CUR);
2665 continue;
2666 }
2667
2668 /* Check if we got a tag ##db, ##dc or ##wb */
2669
2670 if( ( (data[2]=='d' || data[2]=='D') &&
2671 (data[3]=='b' || data[3]=='B' || data[3]=='c' || data[3]=='C') )
2672 || ( (data[2]=='w' || data[2]=='W') &&
2673 (data[3]=='b' || data[3]=='B') ) )
2674 {
2675 avi_add_index_entry(AVI,(unsigned char *)data,0,xio_lseek(AVI->fdes,0,SEEK_CUR)-8,n);
2676 }
2677
2678 xio_lseek(AVI->fdes,PAD_EVEN(n),SEEK_CUR);
2679 }
2680 idx_type = 1;
2681 }
2682
2683 // ************************
2684 // OPENDML
2685 // ************************
2686
2687 // read extended index chunks
2688 if (AVI->is_opendml) {
2689 uint64_t offset = 0;
2690 int hdrl_len = 4+4+2+1+1+4+4+8+4;
2691 char *en, *chunk_start;
2692 int k = 0, audtr = 0;
2693 uint32_t nrEntries = 0;
2694
2695 AVI->video_index = NULL;
2696
2697 nvi = 0;
2698 for(audtr=0; audtr<AVI->anum; ++audtr) nai[audtr] = tot[audtr] = 0;
2699
2700 // ************************
2701 // VIDEO
2702 // ************************
2703
2704 for (j=0; j<AVI->video_superindex->nEntriesInUse; j++) {
2705
2706 // read from file
2707 chunk_start = en = malloc (AVI->video_superindex->aIndex[j].dwSize+hdrl_len);
2708
2709 if (xio_lseek(AVI->fdes, AVI->video_superindex->aIndex[j].qwOffset, SEEK_SET) == (int64_t)-1) {
2710 fprintf(stderr, "(%s) cannot seek to 0x%llx\n", __FILE__,
2711 (unsigned long long)AVI->video_superindex->aIndex[j].qwOffset);
2712 free(chunk_start);
2713 continue;
2714 }
2715
2716 if (avi_read(AVI->fdes, en, AVI->video_superindex->aIndex[j].dwSize+hdrl_len) <= 0) {
2717 fprintf(stderr, "(%s) cannot read from offset 0x%llx %ld bytes; broken (incomplete) file?\n",
2718 __FILE__, (unsigned long long)AVI->video_superindex->aIndex[j].qwOffset,
2719 (unsigned long)AVI->video_superindex->aIndex[j].dwSize+hdrl_len);
2720 free(chunk_start);
2721 continue;
2722 }
2723
2724 nrEntries = str2ulong(en + 12);
2725 #ifdef DEBUG_ODML
2726 //printf("[%d:0] Video nrEntries %ld\n", j, nrEntries);
2727 #endif
2728 offset = str2ullong(en + 20);
2729
2730 // skip header
2731 en += hdrl_len;
2732 nvi += nrEntries;
2733 AVI->video_index = (video_index_entry *) realloc (AVI->video_index, nvi * sizeof (video_index_entry));
2734 if (!AVI->video_index) {
2735 fprintf(stderr, "AVILIB: out of mem (size = %ld)\n", nvi * sizeof (video_index_entry));
2736 exit(1);
2737 }
2738
2739 while (k < nvi) {
2740
2741 AVI->video_index[k].pos = offset + str2ulong(en); en += 4;
2742 AVI->video_index[k].len = str2ulong_len(en);
2743 AVI->video_index[k].key = str2ulong_key(en); en += 4;
2744
2745 // completely empty chunk
2746 if (AVI->video_index[k].pos-offset == 0 && AVI->video_index[k].len == 0) {
2747 k--;
2748 nvi--;
2749 }
2750
2751 #ifdef DEBUG_ODML
2752 /*
2753 printf("[%d] POS 0x%llX len=%d key=%s offset (%llx) (%ld)\n", k,
2754 AVI->video_index[k].pos,
2755 (int)AVI->video_index[k].len,
2756 AVI->video_index[k].key?"yes":"no ", offset,
2757 AVI->video_superindex->aIndex[j].dwSize);
2758 */
2759 #endif
2760
2761 k++;
2762 }
2763
2764 free(chunk_start);
2765 }
2766
2767 AVI->video_frames = nvi;
2768 // this should deal with broken 'rec ' odml files.
2769 if (AVI->video_frames == 0) {
2770 AVI->is_opendml=0;
2771 goto multiple_riff;
2772 }
2773
2774 // ************************
2775 // AUDIO
2776 // ************************
2777
2778 for(audtr=0; audtr<AVI->anum; ++audtr) {
2779
2780 k = 0;
2781 if (!AVI->track[audtr].audio_superindex) {
2782 fprintf(stderr, "(%s) cannot read audio index for track %d\n", __FILE__, audtr);
2783 continue;
2784 }
2785 for (j=0; j<AVI->track[audtr].audio_superindex->nEntriesInUse; j++) {
2786
2787 // read from file
2788 chunk_start = en = malloc (AVI->track[audtr].audio_superindex->aIndex[j].dwSize+hdrl_len);
2789
2790 if (xio_lseek(AVI->fdes, AVI->track[audtr].audio_superindex->aIndex[j].qwOffset, SEEK_SET) == (int64_t)-1) {
2791 fprintf(stderr, "(%s) cannot seek to 0x%llx\n", __FILE__, (unsigned long long)AVI->track[audtr].audio_superindex->aIndex[j].qwOffset);
2792 free(chunk_start);
2793 continue;
2794 }
2795
2796 if (avi_read(AVI->fdes, en, AVI->track[audtr].audio_superindex->aIndex[j].dwSize+hdrl_len) <= 0) {
2797 fprintf(stderr, "(%s) cannot read from offset 0x%llx; broken (incomplete) file?\n",
2798 __FILE__,(unsigned long long) AVI->track[audtr].audio_superindex->aIndex[j].qwOffset);
2799 free(chunk_start);
2800 continue;
2801 }
2802
2803 nrEntries = str2ulong(en + 12);
2804 //if (nrEntries > 50) nrEntries = 2; // XXX
2805 #ifdef DEBUG_ODML
2806 //printf("[%d:%d] Audio nrEntries %ld\n", j, audtr, nrEntries);
2807 #endif
2808 offset = str2ullong(en + 20);
2809
2810 // skip header
2811 en += hdrl_len;
2812 nai[audtr] += nrEntries;
2813 AVI->track[audtr].audio_index = (audio_index_entry *) realloc (AVI->track[audtr].audio_index, nai[audtr] * sizeof (audio_index_entry));
2814
2815 while (k < nai[audtr]) {
2816
2817 AVI->track[audtr].audio_index[k].pos = offset + str2ulong(en); en += 4;
2818 AVI->track[audtr].audio_index[k].len = str2ulong_len(en); en += 4;
2819 AVI->track[audtr].audio_index[k].tot = tot[audtr];
2820 tot[audtr] += AVI->track[audtr].audio_index[k].len;
2821
2822 #ifdef DEBUG_ODML
2823 /*
2824 printf("[%d:%d] POS 0x%llX len=%d offset (%llx) (%ld)\n", k, audtr,
2825 AVI->track[audtr].audio_index[k].pos,
2826 (int)AVI->track[audtr].audio_index[k].len,
2827 offset, AVI->track[audtr].audio_superindex->aIndex[j].dwSize);
2828 */
2829 #endif
2830
2831 ++k;
2832 }
2833
2834 free(chunk_start);
2835 }
2836
2837 AVI->track[audtr].audio_chunks = nai[audtr];
2838 AVI->track[audtr].audio_bytes = tot[audtr];
2839 }
2840 } // is opendml
2841
2842 else if (AVI->total_frames && !AVI->is_opendml && idx_type==0) {
2843
2844 // *********************
2845 // MULTIPLE RIFF CHUNKS (and no index)
2846 // *********************
2847
2848 long aud_chunks = 0;
2849 multiple_riff:
2850
2851 xio_lseek(AVI->fdes, AVI->movi_start, SEEK_SET);
2852
2853 AVI->n_idx = 0;
2854
2855 fprintf(stderr, "[avilib] Reconstructing index...");
2856
2857 // Number of frames; only one audio track supported
2858 nvi = AVI->video_frames = AVI->total_frames;
2859 nai[0] = AVI->track[0].audio_chunks = AVI->total_frames;
2860 for(j=1; j<AVI->anum; ++j) AVI->track[j].audio_chunks = 0;
2861
2862 AVI->video_index = (video_index_entry *) malloc(nvi*sizeof(video_index_entry));
2863
2864 if(AVI->video_index==0) ERR_EXIT(AVI_ERR_NO_MEM);
2865
2866 for(j=0; j<AVI->anum; ++j) {
2867 if(AVI->track[j].audio_chunks) {
2868 AVI->track[j].audio_index = (audio_index_entry *) malloc((nai[j]+1)*sizeof(audio_index_entry));
2869 memset(AVI->track[j].audio_index, 0, (nai[j]+1)*(sizeof(audio_index_entry)));
2870 if(AVI->track[j].audio_index==0) ERR_EXIT(AVI_ERR_NO_MEM);
2871 }
2872 }
2873
2874 nvi = 0;
2875 for(j=0; j<AVI->anum; ++j) nai[j] = tot[j] = 0;
2876
2877 aud_chunks = AVI->total_frames;
2878
2879 while(1)
2880 {
2881 if (nvi >= AVI->total_frames) break;
2882
2883 if( avi_read(AVI->fdes,data,8) != 8 ) break;
2884 n = str2ulong((unsigned char *)data+4);
2885
2886
2887 j=0;
2888
2889 if (aud_chunks - nai[j] -1 <= 0) {
2890 aud_chunks += AVI->total_frames;
2891 AVI->track[j].audio_index = (audio_index_entry *)
2892 realloc( AVI->track[j].audio_index, (aud_chunks+1)*sizeof(audio_index_entry));
2893 if (!AVI->track[j].audio_index) {
2894 fprintf(stderr, "Internal error in avilib -- no mem\n");
2895 AVI_errno = AVI_ERR_NO_MEM;
2896 return -1;
2897 }
2898 }
2899
2900 /* Check if we got a tag ##db, ##dc or ##wb */
2901
2902 // VIDEO
2903 if(
2904 (data[0]=='0' || data[1]=='0') &&
2905 (data[2]=='d' || data[2]=='D') &&
2906 (data[3]=='b' || data[3]=='B' || data[3]=='c' || data[3]=='C') ) {
2907
2908 AVI->video_index[nvi].key = 0x0;
2909 AVI->video_index[nvi].pos = xio_lseek(AVI->fdes,0,SEEK_CUR);
2910 AVI->video_index[nvi].len = n;
2911
2912 /*
2913 fprintf(stderr, "Frame %ld pos %lld len %lld key %ld\n",
2914 nvi, AVI->video_index[nvi].pos, AVI->video_index[nvi].len, (long)AVI->video_index[nvi].key);
2915 */
2916 nvi++;
2917 xio_lseek(AVI->fdes,PAD_EVEN(n),SEEK_CUR);
2918 }
2919
2920 //AUDIO
2921 else if(
2922 (data[0]=='0' || data[1]=='1') &&
2923 (data[2]=='w' || data[2]=='W') &&
2924 (data[3]=='b' || data[3]=='B') ) {
2925
2926
2927 AVI->track[j].audio_index[nai[j]].pos = xio_lseek(AVI->fdes,0,SEEK_CUR);
2928 AVI->track[j].audio_index[nai[j]].len = n;
2929 AVI->track[j].audio_index[nai[j]].tot = tot[j];
2930 tot[j] += AVI->track[j].audio_index[nai[j]].len;
2931 nai[j]++;
2932
2933 xio_lseek(AVI->fdes,PAD_EVEN(n),SEEK_CUR);
2934 }
2935 else {
2936 xio_lseek(AVI->fdes,-4,SEEK_CUR);
2937 }
2938
2939 }
2940 if (nvi < AVI->total_frames) {
2941 fprintf(stderr, "\n[avilib] Uh? Some frames seems missing (%ld/%d)\n",
2942 nvi, AVI->total_frames);
2943 }
2944
2945
2946 AVI->video_frames = nvi;
2947 AVI->track[0].audio_chunks = nai[0];
2948
2949 for(j=0; j<AVI->anum; ++j) AVI->track[j].audio_bytes = tot[j];
2950 idx_type = 1;
2951 fprintf(stderr, "done. nvi=%ld nai=%ld tot=%ld\n", nvi, nai[0], tot[0]);
2952
2953 } // total_frames but no indx chunk (xawtv does this)
2954
2955 else
2956
2957 {
2958 // ******************
2959 // NO OPENDML
2960 // ******************
2961
2962 /* Now generate the video index and audio index arrays */
2963
2964 nvi = 0;
2965 for(j=0; j<AVI->anum; ++j) nai[j] = 0;
2966
2967 for(i=0;i<AVI->n_idx;i++) {
2968
2969 if(strncasecmp((char *)AVI->idx[i],AVI->video_tag,3) == 0) nvi++;
2970
2971 for(j=0; j<AVI->anum; ++j) if(strncasecmp((char *)AVI->idx[i], AVI->track[j].audio_tag,4) == 0) nai[j]++;
2972 }
2973
2974 AVI->video_frames = nvi;
2975 for(j=0; j<AVI->anum; ++j) AVI->track[j].audio_chunks = nai[j];
2976
2977
2978 if(AVI->video_frames==0) ERR_EXIT(AVI_ERR_NO_VIDS);
2979 AVI->video_index = (video_index_entry *) malloc(nvi*sizeof(video_index_entry));
2980 if(AVI->video_index==0) ERR_EXIT(AVI_ERR_NO_MEM);
2981
2982 for(j=0; j<AVI->anum; ++j) {
2983 if(AVI->track[j].audio_chunks) {
2984 AVI->track[j].audio_index = (audio_index_entry *) malloc((nai[j]+1)*sizeof(audio_index_entry));
2985 memset(AVI->track[j].audio_index, 0, (nai[j]+1)*(sizeof(audio_index_entry)));
2986 if(AVI->track[j].audio_index==0) ERR_EXIT(AVI_ERR_NO_MEM);
2987 }
2988 }
2989
2990 nvi = 0;
2991 for(j=0; j<AVI->anum; ++j) nai[j] = tot[j] = 0;
2992
2993 ioff = idx_type == 1 ? 8 : AVI->movi_start+4;
2994
2995 for(i=0;i<AVI->n_idx;i++) {
2996
2997 //video
2998 if(strncasecmp((char *)AVI->idx[i],AVI->video_tag,3) == 0) {
2999 AVI->video_index[nvi].key = str2ulong(AVI->idx[i]+ 4);
3000 AVI->video_index[nvi].pos = str2ulong(AVI->idx[i]+ 8)+ioff;
3001 AVI->video_index[nvi].len = str2ulong(AVI->idx[i]+12);
3002 nvi++;
3003 }
3004
3005 //audio
3006 for(j=0; j<AVI->anum; ++j) {
3007
3008 if(strncasecmp((char *)AVI->idx[i],AVI->track[j].audio_tag,4) == 0) {
3009 AVI->track[j].audio_index[nai[j]].pos = str2ulong(AVI->idx[i]+ 8)+ioff;
3010 AVI->track[j].audio_index[nai[j]].len = str2ulong(AVI->idx[i]+12);
3011 AVI->track[j].audio_index[nai[j]].tot = tot[j];
3012 tot[j] += AVI->track[j].audio_index[nai[j]].len;
3013 nai[j]++;
3014 }
3015 }
3016 }
3017
3018
3019 for(j=0; j<AVI->anum; ++j) AVI->track[j].audio_bytes = tot[j];
3020
3021 } // is no opendml
3022
3023 /* Reposition the file */
3024
3025 xio_lseek(AVI->fdes,AVI->movi_start,SEEK_SET);
3026 AVI->video_pos = 0;
3027
3028 return(0);
3029 }
3030
AVI_video_frames(avi_t * AVI)3031 long AVI_video_frames(avi_t *AVI)
3032 {
3033 return AVI->video_frames;
3034 }
AVI_video_width(avi_t * AVI)3035 int AVI_video_width(avi_t *AVI)
3036 {
3037 return AVI->width;
3038 }
AVI_video_height(avi_t * AVI)3039 int AVI_video_height(avi_t *AVI)
3040 {
3041 return AVI->height;
3042 }
AVI_frame_rate(avi_t * AVI)3043 double AVI_frame_rate(avi_t *AVI)
3044 {
3045 return AVI->fps;
3046 }
AVI_video_compressor(avi_t * AVI)3047 char* AVI_video_compressor(avi_t *AVI)
3048 {
3049 return AVI->compressor2;
3050 }
3051
AVI_max_video_chunk(avi_t * AVI)3052 long AVI_max_video_chunk(avi_t *AVI)
3053 {
3054 return AVI->max_len;
3055 }
3056
AVI_audio_tracks(avi_t * AVI)3057 int AVI_audio_tracks(avi_t *AVI)
3058 {
3059 return(AVI->anum);
3060 }
3061
AVI_audio_channels(avi_t * AVI)3062 int AVI_audio_channels(avi_t *AVI)
3063 {
3064 return AVI->track[AVI->aptr].a_chans;
3065 }
3066
AVI_audio_mp3rate(avi_t * AVI)3067 long AVI_audio_mp3rate(avi_t *AVI)
3068 {
3069 return AVI->track[AVI->aptr].mp3rate;
3070 }
3071
AVI_audio_padrate(avi_t * AVI)3072 long AVI_audio_padrate(avi_t *AVI)
3073 {
3074 return AVI->track[AVI->aptr].padrate;
3075 }
3076
AVI_audio_bits(avi_t * AVI)3077 int AVI_audio_bits(avi_t *AVI)
3078 {
3079 return AVI->track[AVI->aptr].a_bits;
3080 }
3081
AVI_audio_format(avi_t * AVI)3082 int AVI_audio_format(avi_t *AVI)
3083 {
3084 return AVI->track[AVI->aptr].a_fmt;
3085 }
3086
AVI_audio_rate(avi_t * AVI)3087 long AVI_audio_rate(avi_t *AVI)
3088 {
3089 return AVI->track[AVI->aptr].a_rate;
3090 }
3091
AVI_audio_bytes(avi_t * AVI)3092 long AVI_audio_bytes(avi_t *AVI)
3093 {
3094 return AVI->track[AVI->aptr].audio_bytes;
3095 }
3096
AVI_audio_chunks(avi_t * AVI)3097 long AVI_audio_chunks(avi_t *AVI)
3098 {
3099 return AVI->track[AVI->aptr].audio_chunks;
3100 }
3101
AVI_audio_codech_offset(avi_t * AVI)3102 long AVI_audio_codech_offset(avi_t *AVI)
3103 {
3104 return AVI->track[AVI->aptr].a_codech_off;
3105 }
3106
AVI_audio_codecf_offset(avi_t * AVI)3107 long AVI_audio_codecf_offset(avi_t *AVI)
3108 {
3109 return AVI->track[AVI->aptr].a_codecf_off;
3110 }
3111
AVI_video_codech_offset(avi_t * AVI)3112 long AVI_video_codech_offset(avi_t *AVI)
3113 {
3114 return AVI->v_codech_off;
3115 }
3116
AVI_video_codecf_offset(avi_t * AVI)3117 long AVI_video_codecf_offset(avi_t *AVI)
3118 {
3119 return AVI->v_codecf_off;
3120 }
3121
AVI_frame_size(avi_t * AVI,long frame)3122 long AVI_frame_size(avi_t *AVI, long frame)
3123 {
3124 if(AVI->mode==AVI_MODE_WRITE) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
3125 if(!AVI->video_index) { AVI_errno = AVI_ERR_NO_IDX; return -1; }
3126
3127 if(frame < 0 || frame >= AVI->video_frames) return 0;
3128 return(AVI->video_index[frame].len);
3129 }
3130
AVI_audio_size(avi_t * AVI,long frame)3131 long AVI_audio_size(avi_t *AVI, long frame)
3132 {
3133 if(AVI->mode==AVI_MODE_WRITE) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
3134 if(!AVI->track[AVI->aptr].audio_index) { AVI_errno = AVI_ERR_NO_IDX; return -1; }
3135
3136 if(frame < 0 || frame >= AVI->track[AVI->aptr].audio_chunks) return -1;
3137 return(AVI->track[AVI->aptr].audio_index[frame].len);
3138 }
3139
AVI_get_video_position(avi_t * AVI,long frame)3140 long AVI_get_video_position(avi_t *AVI, long frame)
3141 {
3142 if(AVI->mode==AVI_MODE_WRITE) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
3143 if(!AVI->video_index) { AVI_errno = AVI_ERR_NO_IDX; return -1; }
3144
3145 if(frame < 0 || frame >= AVI->video_frames) return 0;
3146 return(AVI->video_index[frame].pos);
3147 }
3148
3149
AVI_seek_start(avi_t * AVI)3150 int AVI_seek_start(avi_t *AVI)
3151 {
3152 if(AVI->mode==AVI_MODE_WRITE) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
3153
3154 xio_lseek(AVI->fdes,AVI->movi_start,SEEK_SET);
3155 AVI->video_pos = 0;
3156 return 0;
3157 }
3158
AVI_set_video_position(avi_t * AVI,long frame)3159 int AVI_set_video_position(avi_t *AVI, long frame)
3160 {
3161 if(AVI->mode==AVI_MODE_WRITE) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
3162 if(!AVI->video_index) { AVI_errno = AVI_ERR_NO_IDX; return -1; }
3163
3164 if (frame < 0 ) frame = 0;
3165 AVI->video_pos = frame;
3166 return 0;
3167 }
3168
AVI_set_audio_bitrate(avi_t * AVI,long bitrate)3169 int AVI_set_audio_bitrate(avi_t *AVI, long bitrate)
3170 {
3171 if(AVI->mode==AVI_MODE_READ) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
3172
3173 AVI->track[AVI->aptr].mp3rate = bitrate;
3174 return 0;
3175 }
3176
3177
AVI_read_frame(avi_t * AVI,char * vidbuf,int * keyframe)3178 long AVI_read_frame(avi_t *AVI, char *vidbuf, int *keyframe)
3179 {
3180 long n;
3181
3182 if(AVI->mode==AVI_MODE_WRITE) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
3183 if(!AVI->video_index) { AVI_errno = AVI_ERR_NO_IDX; return -1; }
3184
3185 if(AVI->video_pos < 0 || AVI->video_pos >= AVI->video_frames) return -1;
3186 n = AVI->video_index[AVI->video_pos].len;
3187
3188 *keyframe = (AVI->video_index[AVI->video_pos].key==0x10) ? 1:0;
3189
3190 if (vidbuf == NULL) {
3191 AVI->video_pos++;
3192 return n;
3193 }
3194
3195 xio_lseek(AVI->fdes, AVI->video_index[AVI->video_pos].pos, SEEK_SET);
3196
3197 if (avi_read(AVI->fdes,vidbuf,n) != n)
3198 {
3199 AVI_errno = AVI_ERR_READ;
3200 return -1;
3201 }
3202
3203 AVI->video_pos++;
3204
3205 return n;
3206 }
3207
AVI_get_audio_position_index(avi_t * AVI)3208 long AVI_get_audio_position_index(avi_t *AVI)
3209 {
3210 if(AVI->mode==AVI_MODE_WRITE) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
3211 if(!AVI->track[AVI->aptr].audio_index) { AVI_errno = AVI_ERR_NO_IDX; return -1; }
3212
3213 return (AVI->track[AVI->aptr].audio_posc);
3214 }
3215
AVI_set_audio_position_index(avi_t * AVI,long indexpos)3216 int AVI_set_audio_position_index(avi_t *AVI, long indexpos)
3217 {
3218 if(AVI->mode==AVI_MODE_WRITE) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
3219 if(!AVI->track[AVI->aptr].audio_index) { AVI_errno = AVI_ERR_NO_IDX; return -1; }
3220 if(indexpos > AVI->track[AVI->aptr].audio_chunks) { AVI_errno = AVI_ERR_NO_IDX; return -1; }
3221
3222 AVI->track[AVI->aptr].audio_posc = indexpos;
3223 AVI->track[AVI->aptr].audio_posb = 0;
3224
3225 return 0;
3226 }
3227
3228
AVI_set_audio_position(avi_t * AVI,long byte)3229 int AVI_set_audio_position(avi_t *AVI, long byte)
3230 {
3231 long n0, n1, n;
3232
3233 if(AVI->mode==AVI_MODE_WRITE) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
3234 if(!AVI->track[AVI->aptr].audio_index) { AVI_errno = AVI_ERR_NO_IDX; return -1; }
3235
3236 if(byte < 0) byte = 0;
3237
3238 /* Binary search in the audio chunks */
3239
3240 n0 = 0;
3241 n1 = AVI->track[AVI->aptr].audio_chunks;
3242
3243 while(n0<n1-1)
3244 {
3245 n = (n0+n1)/2;
3246 if(AVI->track[AVI->aptr].audio_index[n].tot>byte)
3247 n1 = n;
3248 else
3249 n0 = n;
3250 }
3251
3252 AVI->track[AVI->aptr].audio_posc = n0;
3253 AVI->track[AVI->aptr].audio_posb = byte - AVI->track[AVI->aptr].audio_index[n0].tot;
3254
3255 return 0;
3256 }
3257
AVI_read_audio(avi_t * AVI,char * audbuf,long bytes)3258 long AVI_read_audio(avi_t *AVI, char *audbuf, long bytes)
3259 {
3260 long nr, left, todo;
3261 int64_t pos;
3262
3263 if(AVI->mode==AVI_MODE_WRITE) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
3264 if(!AVI->track[AVI->aptr].audio_index) { AVI_errno = AVI_ERR_NO_IDX; return -1; }
3265
3266 nr = 0; /* total number of bytes read */
3267
3268 if (bytes==0) {
3269 AVI->track[AVI->aptr].audio_posc++;
3270 AVI->track[AVI->aptr].audio_posb = 0;
3271 xio_lseek(AVI->fdes, 0LL, SEEK_CUR);
3272 }
3273 while(bytes>0)
3274 {
3275 int64_t ret;
3276 left = AVI->track[AVI->aptr].audio_index[AVI->track[AVI->aptr].audio_posc].len - AVI->track[AVI->aptr].audio_posb;
3277 if(left==0)
3278 {
3279 if(AVI->track[AVI->aptr].audio_posc>=AVI->track[AVI->aptr].audio_chunks-1) return nr;
3280 AVI->track[AVI->aptr].audio_posc++;
3281 AVI->track[AVI->aptr].audio_posb = 0;
3282 continue;
3283 }
3284 if(bytes<left)
3285 todo = bytes;
3286 else
3287 todo = left;
3288 pos = AVI->track[AVI->aptr].audio_index[AVI->track[AVI->aptr].audio_posc].pos + AVI->track[AVI->aptr].audio_posb;
3289 xio_lseek(AVI->fdes, pos, SEEK_SET);
3290 if ( (ret = avi_read(AVI->fdes,audbuf+nr,todo)) != todo)
3291 {
3292 fprintf(stderr, "XXX pos = %lld, ret = %lld, todo = %ld\n", pos, ret, todo);
3293 AVI_errno = AVI_ERR_READ;
3294 return -1;
3295 }
3296 bytes -= todo;
3297 nr += todo;
3298 AVI->track[AVI->aptr].audio_posb += todo;
3299 }
3300
3301 return nr;
3302 }
3303
AVI_read_audio_chunk(avi_t * AVI,char * audbuf)3304 long AVI_read_audio_chunk(avi_t *AVI, char *audbuf)
3305 {
3306 int64_t pos, left;
3307
3308 if(AVI->mode==AVI_MODE_WRITE) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
3309 if(!AVI->track[AVI->aptr].audio_index) { AVI_errno = AVI_ERR_NO_IDX; return -1; }
3310
3311 if (AVI->track[AVI->aptr].audio_posc+1>AVI->track[AVI->aptr].audio_chunks) return -1;
3312
3313 left = AVI->track[AVI->aptr].audio_index[AVI->track[AVI->aptr].audio_posc].len - AVI->track[AVI->aptr].audio_posb;
3314
3315 if (audbuf == NULL) return left;
3316
3317 if(left==0) {
3318 AVI->track[AVI->aptr].audio_posc++;
3319 AVI->track[AVI->aptr].audio_posb = 0;
3320 return 0;
3321 }
3322
3323 pos = AVI->track[AVI->aptr].audio_index[AVI->track[AVI->aptr].audio_posc].pos + AVI->track[AVI->aptr].audio_posb;
3324 xio_lseek(AVI->fdes, pos, SEEK_SET);
3325 if (avi_read(AVI->fdes,audbuf,left) != left)
3326 {
3327 AVI_errno = AVI_ERR_READ;
3328 return -1;
3329 }
3330 AVI->track[AVI->aptr].audio_posc++;
3331 AVI->track[AVI->aptr].audio_posb = 0;
3332
3333 return left;
3334 }
3335
3336 /* AVI_read_data: Special routine for reading the next audio or video chunk
3337 without having an index of the file. */
3338
AVI_read_data(avi_t * AVI,char * vidbuf,long max_vidbuf,char * audbuf,long max_audbuf,long * len)3339 int AVI_read_data(avi_t *AVI, char *vidbuf, long max_vidbuf,
3340 char *audbuf, long max_audbuf,
3341 long *len)
3342 {
3343
3344 /*
3345 * Return codes:
3346 *
3347 * 1 = video data read
3348 * 2 = audio data read
3349 * 0 = reached EOF
3350 * -1 = video buffer too small
3351 * -2 = audio buffer too small
3352 */
3353
3354 int64_t n;
3355 char data[8];
3356
3357 if(AVI->mode==AVI_MODE_WRITE) return 0;
3358
3359 while(1)
3360 {
3361 /* Read tag and length */
3362
3363 if( avi_read(AVI->fdes,data,8) != 8 ) return 0;
3364
3365 /* if we got a list tag, ignore it */
3366
3367 if(strncasecmp(data,"LIST",4) == 0)
3368 {
3369 xio_lseek(AVI->fdes,4,SEEK_CUR);
3370 continue;
3371 }
3372
3373 n = PAD_EVEN(str2ulong((unsigned char *)data+4));
3374
3375 if(strncasecmp(data,AVI->video_tag,3) == 0)
3376 {
3377 *len = n;
3378 AVI->video_pos++;
3379 if(n>max_vidbuf)
3380 {
3381 xio_lseek(AVI->fdes,n,SEEK_CUR);
3382 return -1;
3383 }
3384 if(avi_read(AVI->fdes,vidbuf,n) != n ) return 0;
3385 return 1;
3386 }
3387 else if(strncasecmp(data,AVI->track[AVI->aptr].audio_tag,4) == 0)
3388 {
3389 *len = n;
3390 if(n>max_audbuf)
3391 {
3392 xio_lseek(AVI->fdes,n,SEEK_CUR);
3393 return -2;
3394 }
3395 if(avi_read(AVI->fdes,audbuf,n) != n ) return 0;
3396 return 2;
3397 break;
3398 }
3399 else
3400 if(xio_lseek(AVI->fdes,n,SEEK_CUR)<0) return 0;
3401 }
3402 }
3403
3404 /* AVI_print_error: Print most recent error (similar to perror) */
3405
3406 char *(avi_errors[]) =
3407 {
3408 /* 0 */ "avilib - No Error",
3409 /* 1 */ "avilib - AVI file size limit reached",
3410 /* 2 */ "avilib - Error opening AVI file",
3411 /* 3 */ "avilib - Error reading from AVI file",
3412 /* 4 */ "avilib - Error writing to AVI file",
3413 /* 5 */ "avilib - Error writing index (file may still be useable)",
3414 /* 6 */ "avilib - Error closing AVI file",
3415 /* 7 */ "avilib - Operation (read/write) not permitted",
3416 /* 8 */ "avilib - Out of memory (malloc failed)",
3417 /* 9 */ "avilib - Not an AVI file",
3418 /* 10 */ "avilib - AVI file has no header list (corrupted?)",
3419 /* 11 */ "avilib - AVI file has no MOVI list (corrupted?)",
3420 /* 12 */ "avilib - AVI file has no video data",
3421 /* 13 */ "avilib - operation needs an index",
3422 /* 14 */ "avilib - Unkown Error"
3423 };
3424 static int num_avi_errors = sizeof(avi_errors)/sizeof(char*);
3425
3426 static char error_string[4096];
3427
AVI_print_error(char * str)3428 void AVI_print_error(char *str)
3429 {
3430 int aerrno;
3431
3432 aerrno = (AVI_errno>=0 && AVI_errno<num_avi_errors) ? AVI_errno : num_avi_errors-1;
3433
3434 if (aerrno != 0)
3435 fprintf(stderr,"%s: %s\n",str,avi_errors[aerrno]);
3436
3437 /* for the following errors, perror should report a more detailed reason: */
3438
3439 if(AVI_errno == AVI_ERR_OPEN ||
3440 AVI_errno == AVI_ERR_READ ||
3441 AVI_errno == AVI_ERR_WRITE ||
3442 AVI_errno == AVI_ERR_WRITE_INDEX ||
3443 AVI_errno == AVI_ERR_CLOSE )
3444 {
3445 perror("REASON");
3446 }
3447 }
3448
AVI_strerror(void)3449 char *AVI_strerror(void)
3450 {
3451 int aerrno;
3452
3453 aerrno = (AVI_errno>=0 && AVI_errno<num_avi_errors) ? AVI_errno : num_avi_errors-1;
3454
3455 if(AVI_errno == AVI_ERR_OPEN ||
3456 AVI_errno == AVI_ERR_READ ||
3457 AVI_errno == AVI_ERR_WRITE ||
3458 AVI_errno == AVI_ERR_WRITE_INDEX ||
3459 AVI_errno == AVI_ERR_CLOSE )
3460 {
3461 sprintf(error_string,"%s - %s",avi_errors[aerrno],strerror(errno));
3462 return error_string;
3463 }
3464 else
3465 {
3466 return avi_errors[aerrno];
3467 }
3468 }
3469
AVI_max_size(void)3470 uint64_t AVI_max_size(void)
3471 {
3472 return((uint64_t) AVI_MAX_LEN);
3473 }
3474
3475 #if 0
3476
3477 // This expression is a compile-time constraint. It will force a
3478 // compiler error, if the condition (the correct size of the struct
3479 // wave_header) is not met. The reason that this may fail is
3480 // structure padding. If it happens, the code should be changed to
3481 // use a byte array for the raw data, instead of doing the fixup
3482 // in-place.
3483 typedef char struct_packing_constraint [
3484 44 == sizeof(struct wave_header) ? 1 : -1];
3485 #endif
3486
AVI_read_wave_header(int fd,struct wave_header * wave)3487 int AVI_read_wave_header( int fd, struct wave_header * wave )
3488 {
3489 char buf[44];
3490 // read raw data
3491 if( avi_read (fd, buf, 44) != 44)
3492 {
3493 AVI_errno = AVI_ERR_READ;
3494 return -1;
3495 }
3496
3497 memcpy(&wave->riff.id ,buf+0, 4);
3498 memcpy(&wave->riff.len ,buf+4, 4);
3499 memcpy(&wave->riff.wave_id ,buf+8, 4);
3500
3501 memcpy(&wave->format.id ,buf+12, 4);
3502 memcpy(&wave->format.len ,buf+16, 4);
3503
3504 memcpy(&wave->common.wFormatTag ,buf+20, 2);
3505 memcpy(&wave->common.wChannels ,buf+22, 2);
3506 memcpy(&wave->common.dwSamplesPerSec ,buf+24, 4);
3507 memcpy(&wave->common.dwAvgBytesPerSec ,buf+28, 4);
3508 memcpy(&wave->common.wBlockAlign ,buf+32, 2);
3509 memcpy(&wave->common.wBitsPerSample ,buf+34, 2);
3510
3511 memcpy(&wave->data.id ,buf+36, 4);
3512 memcpy(&wave->data.len ,buf+40, 4);
3513
3514
3515 /*
3516 fprintf(stderr, "RIFF: %c%c%c%c| (%d) (%d)\n",
3517 wave->riff.id[0], wave->riff.id[1], wave->riff.id[2], wave->riff.id[3],
3518 sizeof (*wave), sizeof (struct wave_header));
3519 fprintf(stderr, "WAVE: %c%c%c%c|\n",
3520 wave->riff.wave_id[0], wave->riff.wave_id[1], wave->riff.wave_id[2], wave->riff.wave_id[3]);
3521 fprintf(stderr, "fmt : %c%c%c%c|\n",
3522 wave->format.id[0], wave->format.id[1], wave->format.id[2], wave->format.id[3]);
3523 fprintf(stderr, "data: %c%c%c%c|\n",
3524 wave->data.id[0], wave->data.id[1], wave->data.id[2], wave->data.id[3]);
3525 */
3526
3527 if( strncasecmp(wave->riff.id , "RIFF",4) != 0 ||
3528 strncasecmp(wave->riff.wave_id, "WAVE",4) != 0 ||
3529 strncasecmp(wave->format.id , "fmt ",4) != 0 )
3530 {
3531 AVI_errno = AVI_ERR_NO_AVI;
3532 return -1;
3533 }
3534
3535 #ifdef WORDS_BIGENDIAN
3536 #define x_FIXUP(field) \
3537 ((field) = (sizeof(field) == 4 ? str2ulong((unsigned char*)&(field)) \
3538 : str2ushort((unsigned char*)&(field))))
3539
3540 x_FIXUP(wave->riff.len);
3541 x_FIXUP(wave->format.len);
3542 x_FIXUP(wave->common.wFormatTag);
3543 x_FIXUP(wave->common.wChannels);
3544 x_FIXUP(wave->common.dwSamplesPerSec);
3545 x_FIXUP(wave->common.dwAvgBytesPerSec);
3546 x_FIXUP(wave->common.wBlockAlign);
3547 x_FIXUP(wave->common.wBitsPerSample);
3548 x_FIXUP(wave->data.len);
3549
3550 #undef x_FIXUP
3551 #endif
3552
3553 return 0;
3554 }
3555
AVI_write_wave_header(int fd,const struct wave_header * wave)3556 int AVI_write_wave_header( int fd, const struct wave_header * wave )
3557 {
3558 char buf[44];
3559 struct wave_header buffer = *wave;
3560
3561
3562
3563 #ifdef WORDS_BIGENDIAN
3564 #define x_FIXUP(field) \
3565 ((sizeof(field) == 4 ? long2str((unsigned char*)&(field),(field)) \
3566 : short2str((unsigned char*)&(field),(field))))
3567
3568 x_FIXUP(buffer.riff.len);
3569 x_FIXUP(buffer.format.len);
3570 x_FIXUP(buffer.common.wFormatTag);
3571 x_FIXUP(buffer.common.wChannels);
3572 x_FIXUP(buffer.common.dwSamplesPerSec);
3573 x_FIXUP(buffer.common.dwAvgBytesPerSec);
3574 x_FIXUP(buffer.common.wBlockAlign);
3575 x_FIXUP(buffer.common.wBitsPerSample);
3576 x_FIXUP(buffer.data.len);
3577
3578 #undef x_FIXUP
3579 #endif
3580
3581 memcpy(buf+ 0, &buffer.riff.id, 4);
3582 memcpy(buf+ 4, &buffer.riff.len, 4);
3583 memcpy(buf+ 8, &buffer.riff.wave_id, 4);
3584
3585 memcpy(buf+12, &buffer.format.id, 4);
3586 memcpy(buf+16, &buffer.format.len, 4);
3587
3588 memcpy(buf+20, &buffer.common.wFormatTag, 2);
3589 memcpy(buf+22, &buffer.common.wChannels, 2);
3590 memcpy(buf+24, &buffer.common.dwSamplesPerSec, 4);
3591 memcpy(buf+28, &buffer.common.dwAvgBytesPerSec, 4);
3592 memcpy(buf+32, &buffer.common.wBlockAlign, 2);
3593 memcpy(buf+34, &buffer.common.wBitsPerSample, 2);
3594
3595 memcpy(buf+36, &buffer.data.id, 4);
3596 memcpy(buf+40, &buffer.data.len, 4);
3597
3598
3599 // write raw data
3600 if( avi_write (fd, buf, sizeof(buf)) != sizeof(buf) )
3601 {
3602 AVI_errno = AVI_ERR_WRITE;
3603 return -1;
3604 }
3605
3606 return 0;
3607 }
3608
AVI_read_wave_pcm_data(int fd,void * buffer,size_t buflen)3609 size_t AVI_read_wave_pcm_data( int fd, void * buffer, size_t buflen )
3610 {
3611 int doneread = avi_read(fd, buffer, buflen);
3612
3613 #ifdef WORDS_BIGENDIAN
3614 {
3615 char * bufptr = buffer;
3616 size_t i;
3617 char tmp;
3618
3619 for( i=0; i<doneread; i+=2 )
3620 {
3621 tmp = bufptr[i];
3622 bufptr[i] = bufptr[i+1];
3623 bufptr[i+1] = tmp;
3624 }
3625 }
3626 #endif
3627
3628 return doneread;
3629 }
3630
AVI_write_wave_pcm_data(int fd,const void * data,size_t datalen)3631 size_t AVI_write_wave_pcm_data( int fd, const void * data, size_t datalen )
3632 {
3633 size_t totalwritten = 0;
3634
3635 #ifdef WORDS_BIGENDIAN
3636 const char * inptr = data;
3637 char buffer[2048];
3638 size_t i, buflen, donewritten;
3639
3640 while( datalen>0 )
3641 {
3642 buflen = datalen;
3643 if( buflen > sizeof(buffer) )
3644 {
3645 buflen = sizeof(buffer);
3646 }
3647
3648 for( i=0; i<buflen; i+=2 )
3649 {
3650 buffer[i] = inptr[i+1];
3651 buffer[i+1] = inptr[i];
3652 }
3653
3654 donewritten = avi_write(fd, buffer, buflen);
3655 totalwritten += donewritten;
3656 if( buflen != donewritten )
3657 {
3658 AVI_errno = AVI_ERR_WRITE;
3659 return totalwritten;
3660 }
3661
3662 datalen -= buflen;
3663 inptr += buflen;
3664 }
3665 #else
3666 totalwritten = avi_write(fd, (char *)data, datalen);
3667 if( datalen != totalwritten )
3668 {
3669 AVI_errno = AVI_ERR_WRITE;
3670 }
3671 #endif
3672
3673 return totalwritten;
3674 }
3675