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