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