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