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