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