comparison mov.c @ 121:b9bd706c1ac3 libavformat

* simplified parameters for parse routines
author kabi
date Wed, 23 Apr 2003 08:58:42 +0000
parents 79d651162d35
children a1ad0f8b75bf
comparison
equal deleted inserted replaced
120:c720ddf380df 121:b9bd706c1ac3
77 (tag >> 24) & 0xff, 77 (tag >> 24) & 0xff,
78 (unsigned int)offset, 78 (unsigned int)offset,
79 (unsigned int)size); 79 (unsigned int)size);
80 assert((unsigned int)size < 0x7fffffff);// catching errors 80 assert((unsigned int)size < 0x7fffffff);// catching errors
81 } 81 }
82 #else
83 #define print_atom(a,b,c,d)
82 #endif 84 #endif
83 85
84 /* some streams in QT (and in MP4 mostly) aren't either video nor audio */ 86 /* some streams in QT (and in MP4 mostly) aren't either video nor audio */
85 /* so we first list them as this, then clean up the list of streams we give back, */ 87 /* so we first list them as this, then clean up the list of streams we give back, */
86 /* getting rid of these */ 88 /* getting rid of these */
87 #define CODEC_TYPE_MOV_OTHER 2 89 #define CODEC_TYPE_MOV_OTHER (enum CodecType) 2
88 90
89 static const CodecTag mov_video_tags[] = { 91 static const CodecTag mov_video_tags[] = {
90 /* { CODEC_ID_, MKTAG('c', 'v', 'i', 'd') }, *//* Cinepak */ 92 /* { CODEC_ID_, MKTAG('c', 'v', 'i', 'd') }, *//* Cinepak */
91 /* { CODEC_ID_H263, MKTAG('r', 'a', 'w', ' ') }, *//* Uncompressed RGB */ 93 /* { CODEC_ID_H263, MKTAG('r', 'a', 'w', ' ') }, *//* Uncompressed RGB */
92 /* { CODEC_ID_H263, MKTAG('Y', 'u', 'v', '2') }, *//* Uncompressed YUV422 */ 94 /* { CODEC_ID_H263, MKTAG('Y', 'u', 'v', '2') }, *//* Uncompressed YUV422 */
195 /* 0x06 SLConfigDescrTag */ 197 /* 0x06 SLConfigDescrTag */
196 uint8_t sl_config_len; 198 uint8_t sl_config_len;
197 uint8_t *sl_config; 199 uint8_t *sl_config;
198 } MOV_esds_t; 200 } MOV_esds_t;
199 201
202 struct MOVParseTableEntry;
203
200 typedef struct MOVStreamContext { 204 typedef struct MOVStreamContext {
201 int ffindex; /* the ffmpeg stream id */ 205 int ffindex; /* the ffmpeg stream id */
202 int is_ff_stream; /* Is this stream presented to ffmpeg ? i.e. is this an audio or video stream ? */ 206 int is_ff_stream; /* Is this stream presented to ffmpeg ? i.e. is this an audio or video stream ? */
203 long next_chunk; 207 long next_chunk;
204 long chunk_count; 208 long chunk_count;
233 */ 237 */
234 MOVStreamContext *streams[MAX_STREAMS]; 238 MOVStreamContext *streams[MAX_STREAMS];
235 239
236 int64_t next_chunk_offset; 240 int64_t next_chunk_offset;
237 MOVStreamContext *partial; /* != 0 : there is still to read in the current chunk */ 241 MOVStreamContext *partial; /* != 0 : there is still to read in the current chunk */
242 const struct MOVParseTableEntry *parse_table; /* could be eventually used to change the table */
243 /* NOTE: for recursion save to/ restore from local variable! */
238 } MOVContext; 244 } MOVContext;
239 245
240
241 struct MOVParseTableEntry;
242 246
243 /* XXX: it's the first time I make a recursive parser I think... sorry if it's ugly :P */ 247 /* XXX: it's the first time I make a recursive parser I think... sorry if it's ugly :P */
244 248
245 /* those functions parse an atom */ 249 /* those functions parse an atom */
246 /* return code: 250 /* return code:
247 1: found what I wanted, exit 251 1: found what I wanted, exit
248 0: continue to parse next atom 252 0: continue to parse next atom
249 -1: error occured, exit 253 -1: error occured, exit
250 */ 254 */
251 typedef int (*mov_parse_function)(const struct MOVParseTableEntry *parse_table, 255 typedef int (*mov_parse_function)(MOVContext *ctx,
252 ByteIOContext *pb, 256 ByteIOContext *pb,
253 uint32_t atom_type, 257 uint32_t atom_type,
254 int64_t atom_offset, /* after the size and type field (and eventually the extended size) */ 258 int64_t atom_offset, /* after the size and type field (and eventually the extended size) */
255 int64_t atom_size, /* total size (excluding the size and type fields) */ 259 int64_t atom_size); /* total size (excluding the size and type fields) */
256 void *param);
257 260
258 /* links atom IDs to parse functions */ 261 /* links atom IDs to parse functions */
259 typedef struct MOVParseTableEntry { 262 typedef struct MOVParseTableEntry {
260 uint32_t type; 263 uint32_t type;
261 mov_parse_function func; 264 mov_parse_function func;
262 } MOVParseTableEntry; 265 } MOVParseTableEntry;
263 static const MOVParseTableEntry mov_default_parse_table[]; 266
264 267 static int parse_leaf(MOVContext *c, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size)
265 static int parse_leaf(const MOVParseTableEntry *parse_table, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size, void *param) 268 {
266 {
267 #ifdef DEBUG
268 print_atom("leaf", atom_type, atom_offset, atom_size); 269 print_atom("leaf", atom_type, atom_offset, atom_size);
269 #endif 270
270 if(atom_size>1) 271 if(atom_size>1)
271 url_fskip(pb, atom_size); 272 url_fskip(pb, atom_size);
272 /* url_seek(pb, atom_offset+atom_size, SEEK_SET); */ 273 /* url_seek(pb, atom_offset+atom_size, SEEK_SET); */
273 return 0; 274 return 0;
274 } 275 }
275 276
276 277 static int parse_default(MOVContext *c, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size)
277 static int parse_default(const MOVParseTableEntry *parse_table, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size, void *param)
278 { 278 {
279 uint32_t type, foo=0; 279 uint32_t type, foo=0;
280 uint64_t offset, size; 280 uint64_t offset, size;
281 uint64_t total_size = 0; 281 int64_t total_size = 0;
282 int i; 282 int i;
283 int err = 0; 283 int err = 0;
284 foo=0; 284 foo=0;
285 #ifdef DEBUG 285 #ifdef DEBUG
286 print_atom("default", atom_type, atom_offset, atom_size); 286 print_atom("default", atom_type, atom_offset, atom_size);
309 if(size == 0) { 309 if(size == 0) {
310 size = atom_size - total_size; 310 size = atom_size - total_size;
311 if (size <= 8) 311 if (size <= 8)
312 break; 312 break;
313 } 313 }
314 for (i=0; parse_table[i].type != 0L && parse_table[i].type != type; i++) 314 for (i=0; c->parse_table[i].type != 0L && c->parse_table[i].type != type; i++)
315 /* empty */; 315 /* empty */;
316 316
317 size -= 8; 317 size -= 8;
318 // printf(" i=%ld\n", i); 318 // printf(" i=%ld\n", i);
319 if (parse_table[i].type == 0) { /* skip leaf atoms data */ 319 if (c->parse_table[i].type == 0) { /* skip leaf atoms data */
320 // url_seek(pb, atom_offset+atom_size, SEEK_SET); 320 // url_seek(pb, atom_offset+atom_size, SEEK_SET);
321 #ifdef DEBUG 321 #ifdef DEBUG
322 print_atom("unknown", type, offset, size); 322 print_atom("unknown", type, offset, size);
323 #endif 323 #endif
324 url_fskip(pb, size); 324 url_fskip(pb, size);
325 } else 325 } else {
326 err = (parse_table[i].func)(parse_table, pb, type, offset, size, param); 326 #ifdef DEBUG
327 //char b[5] = { type & 0xff, (type >> 8) & 0xff, (type >> 16) & 0xff, (type >> 24) & 0xff, 0 };
328 //print_atom(b, type, offset, size);
329 #endif
330 err = (c->parse_table[i].func)(c, pb, type, offset, size);
331 }
327 332
328 offset+=size; 333 offset+=size;
329 total_size+=size; 334 total_size+=size;
330 } 335 }
331 336
338 debug_indent--; 343 debug_indent--;
339 #endif 344 #endif
340 return err; 345 return err;
341 } 346 }
342 347
343 static int parse_ctab(const MOVParseTableEntry *parse_table, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size, void *param) 348 static int parse_ctab(MOVContext *c, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size)
344 { 349 {
345 url_fskip(pb, atom_size); // for now 350 url_fskip(pb, atom_size); // for now
346 return 0; 351 return 0;
347 } 352 }
348 353
349 static int parse_mvhd(const MOVParseTableEntry *parse_table, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size, void *param) 354 static int parse_mvhd(MOVContext *c, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size)
350 { 355 {
351 MOVContext *c;
352 #ifdef DEBUG
353 print_atom("mvhd", atom_type, atom_offset, atom_size); 356 print_atom("mvhd", atom_type, atom_offset, atom_size);
354 #endif
355 c = (MOVContext *)param;
356 357
357 get_byte(pb); /* version */ 358 get_byte(pb); /* version */
358 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ 359 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */
359 360
360 get_be32(pb); /* creation time */ 361 get_be32(pb); /* creation time */
382 383
383 return 0; 384 return 0;
384 } 385 }
385 386
386 /* this atom should contain all header atoms */ 387 /* this atom should contain all header atoms */
387 static int parse_moov(const MOVParseTableEntry *parse_table, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size, void *param) 388 static int parse_moov(MOVContext *c, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size)
388 { 389 {
389 int err; 390 int err;
390 MOVContext *c; 391
391 #ifdef DEBUG
392 print_atom("moov", atom_type, atom_offset, atom_size); 392 print_atom("moov", atom_type, atom_offset, atom_size);
393 #endif 393
394 c = (MOVContext *)param; 394 err = parse_default(c, pb, atom_type, atom_offset, atom_size);
395
396 err = parse_default(parse_table, pb, atom_type, atom_offset, atom_size, param);
397 /* we parsed the 'moov' atom, we can terminate the parsing as soon as we find the 'mdat' */ 395 /* we parsed the 'moov' atom, we can terminate the parsing as soon as we find the 'mdat' */
398 /* so we don't parse the whole file if over a network */ 396 /* so we don't parse the whole file if over a network */
399 c->found_moov=1; 397 c->found_moov=1;
400 if(c->found_mdat) 398 if(c->found_mdat)
401 return 1; /* found both, just go */ 399 return 1; /* found both, just go */
402 return 0; /* now go for mdat */ 400 return 0; /* now go for mdat */
403 } 401 }
404 402
405 /* this atom contains actual media data */ 403 /* this atom contains actual media data */
406 static int parse_mdat(const MOVParseTableEntry *parse_table, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size, void *param) 404 static int parse_mdat(MOVContext *c, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size)
407 { 405 {
408 MOVContext *c;
409 #ifdef DEBUG
410 print_atom("mdat", atom_type, atom_offset, atom_size); 406 print_atom("mdat", atom_type, atom_offset, atom_size);
411 #endif
412 c = (MOVContext *)param;
413 407
414 if(atom_size == 0) /* wrong one (MP4) */ 408 if(atom_size == 0) /* wrong one (MP4) */
415 return 0; 409 return 0;
416 c->found_mdat=1; 410 c->found_mdat=1;
417 c->mdat_offset = atom_offset; 411 c->mdat_offset = atom_offset;
423 } 417 }
424 418
425 /* this atom should be null (from specs), but some buggy files put the 'moov' atom inside it... */ 419 /* this atom should be null (from specs), but some buggy files put the 'moov' atom inside it... */
426 /* like the files created with Adobe Premiere 5.0, for samples see */ 420 /* like the files created with Adobe Premiere 5.0, for samples see */
427 /* http://graphics.tudelft.nl/~wouter/publications/soundtests/ */ 421 /* http://graphics.tudelft.nl/~wouter/publications/soundtests/ */
428 static int parse_wide(const MOVParseTableEntry *parse_table, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size, void *param) 422 static int parse_wide(MOVContext *c, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size)
429 { 423 {
430 int err; 424 int err;
431 uint32_t type; 425 uint32_t type;
426
432 #ifdef DEBUG 427 #ifdef DEBUG
433 print_atom("wide", atom_type, atom_offset, atom_size); 428 print_atom("wide", atom_type, atom_offset, atom_size);
434 debug_indent++; 429 debug_indent++;
435 #endif 430 #endif
436 if (atom_size < 8) 431 if (atom_size < 8)
442 type = get_le32(pb); 437 type = get_le32(pb);
443 if (type != MKTAG('m', 'd', 'a', 't')) { 438 if (type != MKTAG('m', 'd', 'a', 't')) {
444 url_fskip(pb, atom_size - 8); 439 url_fskip(pb, atom_size - 8);
445 return 0; 440 return 0;
446 } 441 }
447 err = parse_mdat(parse_table, pb, type, atom_offset + 8, atom_size - 8, param); 442 err = parse_mdat(c, pb, type, atom_offset + 8, atom_size - 8);
448 #ifdef DEBUG 443 #ifdef DEBUG
449 debug_indent--; 444 debug_indent--;
450 #endif 445 #endif
451 return err; 446 return err;
452 } 447 }
453 448
454 static int parse_trak(const MOVParseTableEntry *parse_table, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size, void *param) 449 static int parse_trak(MOVContext *c, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size)
455 { 450 {
456 MOVContext *c;
457 AVStream *st; 451 AVStream *st;
458 MOVStreamContext *sc; 452 MOVStreamContext *sc;
459 #ifdef DEBUG 453
460 print_atom("trak", atom_type, atom_offset, atom_size); 454 print_atom("trak", atom_type, atom_offset, atom_size);
461 #endif 455
462
463 c = (MOVContext *)param;
464 st = av_new_stream(c->fc, c->fc->nb_streams); 456 st = av_new_stream(c->fc, c->fc->nb_streams);
465 if (!st) return -2; 457 if (!st) return -2;
466 sc = av_malloc(sizeof(MOVStreamContext)); 458 sc = (MOVStreamContext*) av_mallocz(sizeof(MOVStreamContext));
467 memset(sc, 0, sizeof(MOVStreamContext)); 459 if (!sc) {
460 av_free(st);
461 return -1;
462 }
463
468 sc->sample_to_chunk_index = -1; 464 sc->sample_to_chunk_index = -1;
469 st->priv_data = sc; 465 st->priv_data = sc;
470 st->codec.codec_type = CODEC_TYPE_MOV_OTHER; 466 st->codec.codec_type = CODEC_TYPE_MOV_OTHER;
471 st->time_length = (c->duration * 1000) / c->time_scale; // time in miliseconds 467 st->time_length = (c->duration * 1000) / c->time_scale; // time in miliseconds
472 c->streams[c->fc->nb_streams-1] = sc; 468 c->streams[c->fc->nb_streams-1] = sc;
473 return parse_default(parse_table, pb, atom_type, atom_offset, atom_size, param); 469 return parse_default(c, pb, atom_type, atom_offset, atom_size);
474 } 470 }
475 471
476 static int parse_tkhd(const MOVParseTableEntry *parse_table, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size, void *param) 472 static int parse_tkhd(MOVContext *c, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size)
477 { 473 {
478 MOVContext *c;
479 AVStream *st; 474 AVStream *st;
480 #ifdef DEBUG 475
481 print_atom("tkhd", atom_type, atom_offset, atom_size); 476 print_atom("tkhd", atom_type, atom_offset, atom_size);
482 #endif 477
483
484 c = (MOVContext *)param;
485 st = c->fc->streams[c->fc->nb_streams-1]; 478 st = c->fc->streams[c->fc->nb_streams-1];
486 479
487 get_byte(pb); /* version */ 480 get_byte(pb); /* version */
488 481
489 get_byte(pb); get_byte(pb); 482 get_byte(pb); get_byte(pb);
515 st->codec.height = get_be32(pb) >> 16; /* track height */ 508 st->codec.height = get_be32(pb) >> 16; /* track height */
516 509
517 return 0; 510 return 0;
518 } 511 }
519 512
520 static int parse_mdhd(const MOVParseTableEntry *parse_table, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size, void *param) 513 static int parse_mdhd(MOVContext *c, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size)
521 { 514 {
522 MOVContext *c;
523 AVStream *st; 515 AVStream *st;
524 #ifdef DEBUG 516
525 print_atom("mdhd", atom_type, atom_offset, atom_size); 517 print_atom("mdhd", atom_type, atom_offset, atom_size);
526 #endif 518
527
528 c = (MOVContext *)param;
529 st = c->fc->streams[c->fc->nb_streams-1]; 519 st = c->fc->streams[c->fc->nb_streams-1];
530 520
531 get_byte(pb); /* version */ 521 get_byte(pb); /* version */
532 522
533 get_byte(pb); get_byte(pb); 523 get_byte(pb); get_byte(pb);
547 get_be16(pb); /* quality */ 537 get_be16(pb); /* quality */
548 538
549 return 0; 539 return 0;
550 } 540 }
551 541
552 static int parse_hdlr(const MOVParseTableEntry *parse_table, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size, void *param) 542 static int parse_hdlr(MOVContext *c, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size)
553 { 543 {
554 MOVContext *c;
555 int len = 0; 544 int len = 0;
556 char *buf; 545 uint8_t *buf;
557 uint32_t type; 546 uint32_t type;
558 AVStream *st; 547 AVStream *st;
559 uint32_t ctype; 548 uint32_t ctype;
560 #ifdef DEBUG 549
561 print_atom("hdlr", atom_type, atom_offset, atom_size); 550 print_atom("hdlr", atom_type, atom_offset, atom_size);
562 #endif 551
563 c = (MOVContext *)param;
564 st = c->fc->streams[c->fc->nb_streams-1]; 552 st = c->fc->streams[c->fc->nb_streams-1];
565 553
566 get_byte(pb); /* version */ 554 get_byte(pb); /* version */
567 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ 555 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */
568 556
621 /* .mp4: C string */ 609 /* .mp4: C string */
622 while(get_byte(pb) && (++len < (atom_size - 24))); 610 while(get_byte(pb) && (++len < (atom_size - 24)));
623 } else { 611 } else {
624 /* .mov: PASCAL string */ 612 /* .mov: PASCAL string */
625 len = get_byte(pb); 613 len = get_byte(pb);
626 buf = av_malloc(len+1); 614 buf = (uint8_t*) av_malloc(len+1);
627 get_buffer(pb, buf, len); 615 if (buf) {
628 buf[len] = '\0'; 616 get_buffer(pb, buf, len);
629 #ifdef DEBUG 617 #ifdef DEBUG
630 printf("**buf='%s'\n", buf); 618 buf[len] = '\0';
631 #endif 619 printf("**buf='%s'\n", buf);
632 av_free(buf); 620 #endif
621 av_free(buf);
622 } else
623 url_fskip(pb, len);
633 } 624 }
634 #if 0 625 #if 0
635 len = get_byte(pb); 626 len = get_byte(pb);
636 /* XXX: use a better heuristic */ 627 /* XXX: use a better heuristic */
637 if(len < 32) { 628 if(len < 32) {
638 /* assume that it is a Pascal like string */ 629 /* assume that it is a Pascal like string */
639 buf = av_malloc(len+1); 630 buf = av_malloc(len+1);
640 get_buffer(pb, buf, len); 631 if (buf) {
641 buf[len] = '\0'; 632 get_buffer(pb, buf, len);
642 #ifdef DEBUG 633 buf[len] = '\0';
643 printf("**buf='%s'\n", buf); 634 #ifdef DEBUG
644 #endif 635 printf("**buf='%s'\n", buf);
645 av_free(buf); 636 #endif
637 av_free(buf);
638 } else
639 url_fskip(pb, len)l
646 } else { 640 } else {
647 /* MP4 string */ 641 /* MP4 string */
648 for(;;) { 642 for(;;) {
649 if (len == 0) 643 if (len == 0)
650 break; 644 break;
689 val |= get_byte(s) << 8; 683 val |= get_byte(s) << 8;
690 val |= get_byte(s); 684 val |= get_byte(s);
691 return val; 685 return val;
692 } 686 }
693 687
694 static int parse_esds(const MOVParseTableEntry *parse_table, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size, void *param) 688 static int parse_esds(MOVContext *c, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size)
695 { 689 {
696 690
697 int64_t start_pos = url_ftell(pb); 691 int64_t start_pos = url_ftell(pb);
698 MOVContext *c = (MOVContext *)param;
699 AVStream *st = c->fc->streams[c->fc->nb_streams-1]; 692 AVStream *st = c->fc->streams[c->fc->nb_streams-1];
700 MOVStreamContext *sc = (MOVStreamContext *)st->priv_data; 693 MOVStreamContext *sc = (MOVStreamContext *)st->priv_data;
701 int tag, len; 694 int tag, len;
702 #ifdef DEBUG 695
703 print_atom("esds", atom_type, atom_offset, atom_size); 696 print_atom("esds", atom_type, atom_offset, atom_size);
704 #endif
705 697
706 /* Well, broken but suffisant for some MP4 streams */ 698 /* Well, broken but suffisant for some MP4 streams */
707 get_be32(pb); /* version + flags */ 699 get_be32(pb); /* version + flags */
708 len = mp4_read_descr(pb, &tag); 700 len = mp4_read_descr(pb, &tag);
709 if (tag == MP4ESDescrTag) { 701 if (tag == MP4ESDescrTag) {
723 printf("LEN %d TAG %d m:%d a:%d\n", len, tag, sc->esds.max_bitrate, sc->esds.avg_bitrate); 715 printf("LEN %d TAG %d m:%d a:%d\n", len, tag, sc->esds.max_bitrate, sc->esds.avg_bitrate);
724 if (tag == MP4DecSpecificDescrTag) { 716 if (tag == MP4DecSpecificDescrTag) {
725 #ifdef DEBUG 717 #ifdef DEBUG
726 printf("Specific MPEG4 header len=%d\n", len); 718 printf("Specific MPEG4 header len=%d\n", len);
727 #endif 719 #endif
728 sc->header_data = av_mallocz(len); 720 sc->header_data = (uint8_t*) av_mallocz(len);
729 if (sc->header_data) { 721 if (sc->header_data) {
730 get_buffer(pb, sc->header_data, len); 722 get_buffer(pb, sc->header_data, len);
731 sc->header_len = len; 723 sc->header_len = len;
732 } 724 }
733 } 725 }
735 /* in any case, skip garbage */ 727 /* in any case, skip garbage */
736 url_fskip(pb, (atom_size - 8) - ((url_ftell(pb) - start_pos))); 728 url_fskip(pb, (atom_size - 8) - ((url_ftell(pb) - start_pos)));
737 return 0; 729 return 0;
738 } 730 }
739 731
740 static int parse_stsd(const MOVParseTableEntry *parse_table, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size, void *param) 732 static int parse_stsd(MOVContext *c, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size)
741 { 733 {
742 MOVContext *c; 734 int entries, size, frames_per_sample;
743 int entries, size, frames_per_sample, id;
744 uint32_t format; 735 uint32_t format;
745 AVStream *st; 736 AVStream *st;
746 MOVStreamContext *sc; 737 MOVStreamContext *sc;
747 #ifdef DEBUG 738
748 print_atom("stsd", atom_type, atom_offset, atom_size); 739 print_atom("stsd", atom_type, atom_offset, atom_size);
749 #endif 740
750 c = (MOVContext *)param;
751 st = c->fc->streams[c->fc->nb_streams-1]; 741 st = c->fc->streams[c->fc->nb_streams-1];
752 sc = (MOVStreamContext *)st->priv_data; 742 sc = (MOVStreamContext *)st->priv_data;
753 743
754 get_byte(pb); /* version */ 744 get_byte(pb); /* version */
755 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ 745 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */
756 746
757 entries = get_be32(pb); 747 entries = get_be32(pb);
758 748
759 while(entries--) { 749 while(entries--) {
750 enum CodecID id;
760 size = get_be32(pb); /* size */ 751 size = get_be32(pb); /* size */
761 format = get_le32(pb); /* data format */ 752 format = get_le32(pb); /* data format */
762 753
763 get_be32(pb); /* reserved */ 754 get_be32(pb); /* reserved */
764 get_be16(pb); /* reserved */ 755 get_be16(pb); /* reserved */
766 757
767 /* for MPEG4: set codec type by looking for it */ 758 /* for MPEG4: set codec type by looking for it */
768 id = codec_get_id(mov_video_tags, format); 759 id = codec_get_id(mov_video_tags, format);
769 if (id >= 0) { 760 if (id >= 0) {
770 AVCodec *codec; 761 AVCodec *codec;
771 codec = avcodec_find_decoder(id); 762 codec = avcodec_find_decoder(id);
772 if (codec) 763 if (codec)
773 st->codec.codec_type = codec->type; 764 st->codec.codec_type = codec->type;
774 } 765 }
775 #ifdef DEBUG 766 #ifdef DEBUG
776 printf("size=%d 4CC= %c%c%c%c codec_type=%d\n", 767 printf("size=%d 4CC= %c%c%c%c codec_type=%d\n",
777 size, 768 size,
778 (format >> 0) & 0xff, 769 (format >> 0) & 0xff,
804 get_be32(pb); /* data size, always 0 */ 795 get_be32(pb); /* data size, always 0 */
805 frames_per_sample = get_be16(pb); /* frames per samples */ 796 frames_per_sample = get_be16(pb); /* frames per samples */
806 #ifdef DEBUG 797 #ifdef DEBUG
807 printf("frames/samples = %d\n", frames_per_sample); 798 printf("frames/samples = %d\n", frames_per_sample);
808 #endif 799 #endif
809 get_buffer(pb, st->codec.codec_name, 32); /* codec name */ 800 get_buffer(pb, (uint8_t *)st->codec.codec_name, 32); /* codec name */
810 801
811 st->codec.bits_per_sample = get_be16(pb); /* depth */ 802 st->codec.bits_per_sample = get_be16(pb); /* depth */
812 st->codec.color_table_id = get_be16(pb); /* colortable id */ 803 st->codec.color_table_id = get_be16(pb); /* colortable id */
813 804
814 st->codec.frame_rate = 25; 805 st->codec.frame_rate = 25;
884 if (size > 0) { 875 if (size > 0) {
885 /* unknown extension */ 876 /* unknown extension */
886 url_fskip(pb, size); 877 url_fskip(pb, size);
887 } 878 }
888 #else 879 #else
889 parse_default(mov_default_parse_table, pb, 0L, 0LL, size, param); 880 parse_default(c, pb, 0L, 0LL, size);
890 #endif 881 #endif
891 } else { 882 } else {
892 get_be16(pb); /* version */ 883 get_be16(pb); /* version */
893 get_be16(pb); /* revision level */ 884 get_be16(pb); /* revision level */
894 get_be32(pb); /* vendor */ 885 get_be32(pb); /* vendor */
900 /* handle specific s8 codec */ 891 /* handle specific s8 codec */
901 get_be16(pb); /* compression id = 0*/ 892 get_be16(pb); /* compression id = 0*/
902 get_be16(pb); /* packet size = 0 */ 893 get_be16(pb); /* packet size = 0 */
903 894
904 st->codec.sample_rate = ((get_be32(pb) >> 16)); 895 st->codec.sample_rate = ((get_be32(pb) >> 16));
905 896 printf("CODECID %d %d %.4s\n", st->codec.codec_id, CODEC_ID_PCM_S16BE, (char*)&format);
906 if (st->codec.codec_id == CODEC_ID_PCM_S16BE) { 897
898 switch (st->codec.codec_id) {
899 case CODEC_ID_PCM_S16BE:
907 if (st->codec.bits_per_sample == 8) 900 if (st->codec.bits_per_sample == 8)
908 st->codec.codec_id = CODEC_ID_PCM_S8; 901 st->codec.codec_id = CODEC_ID_PCM_S8;
909 st->codec.bit_rate = st->codec.sample_rate; 902 /* fall */
903 case CODEC_ID_PCM_U8:
904 st->codec.bit_rate = st->codec.sample_rate * 8;
905 break;
906 default:
907 ;
910 } 908 }
911 get_be32(pb); /* samples per packet */ 909 get_be32(pb); /* samples per packet */
912 get_be32(pb); /* bytes per packet */ 910 get_be32(pb); /* bytes per packet */
913 get_be32(pb); /* bytes per frame */ 911 get_be32(pb); /* bytes per frame */
914 get_be32(pb); /* bytes per sample */ 912 get_be32(pb); /* bytes per sample */
919 int fcc; 917 int fcc;
920 st->codec.extradata_size = get_be32(pb) - 8; 918 st->codec.extradata_size = get_be32(pb) - 8;
921 fcc = get_le32(pb); // evaw 919 fcc = get_le32(pb); // evaw
922 //printf("%x %.4s %d\n", fcc, (char*)&fcc, st->codec.extradata_size); 920 //printf("%x %.4s %d\n", fcc, (char*)&fcc, st->codec.extradata_size);
923 st->codec.extradata = av_mallocz(st->codec.extradata_size); 921 st->codec.extradata = av_mallocz(st->codec.extradata_size);
924 get_buffer(pb, st->codec.extradata, st->codec.extradata_size); 922 if (st->codec.extradata)
923 get_buffer(pb, st->codec.extradata, st->codec.extradata_size); // FIXME url_fskip
925 url_fskip(pb, size-(16 + 20 + 16 + 8 + st->codec.extradata_size)); 924 url_fskip(pb, size-(16 + 20 + 16 + 8 + st->codec.extradata_size));
926 } 925 }
927 else 926 else
928 url_fskip(pb, size-(16 + 20 + 16)); 927 url_fskip(pb, size-(16 + 20 + 16));
929 #else 928 #else
930 parse_default(mov_default_parse_table, pb, 0L, 0LL, size - (16 + 20 + 16 + 8), param); 929 parse_default(c, pb, 0L, 0LL, size - (16 + 20 + 16 + 8));
931 #endif 930 #endif
932 } 931 }
933 } 932 }
934 /* 933 /*
935 if(len) { 934 if(len) {
941 } 940 }
942 */ 941 */
943 return 0; 942 return 0;
944 } 943 }
945 944
946 static int parse_stco(const MOVParseTableEntry *parse_table, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size, void *param) 945 static int parse_stco(MOVContext *c, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size)
947 { 946 {
948 MOVContext *c;
949 int entries, i; 947 int entries, i;
950 AVStream *st; 948 AVStream *st;
951 MOVStreamContext *sc; 949 MOVStreamContext *sc;
952 #ifdef DEBUG 950
953 print_atom("stco", atom_type, atom_offset, atom_size); 951 print_atom("stco", atom_type, atom_offset, atom_size);
954 #endif 952
955 c = (MOVContext *)param;
956 st = c->fc->streams[c->fc->nb_streams-1]; 953 st = c->fc->streams[c->fc->nb_streams-1];
957 sc = (MOVStreamContext *)st->priv_data; 954 sc = (MOVStreamContext *)st->priv_data;
958 955
959 get_byte(pb); /* version */ 956 get_byte(pb); /* version */
960 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ 957 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */
961 958
962 entries = get_be32(pb); 959 entries = get_be32(pb);
963 sc->chunk_count = entries; 960 sc->chunk_count = entries;
964 sc->chunk_offsets = av_malloc(entries * sizeof(int64_t)); 961 sc->chunk_offsets = (int64_t*) av_malloc(entries * sizeof(int64_t));
962 if (!sc->chunk_offsets)
963 return -1;
965 if(atom_type == MKTAG('s', 't', 'c', 'o')) { 964 if(atom_type == MKTAG('s', 't', 'c', 'o')) {
966 for(i=0; i<entries; i++) { 965 for(i=0; i<entries; i++) {
967 sc->chunk_offsets[i] = get_be32(pb); 966 sc->chunk_offsets[i] = get_be32(pb);
968 } 967 }
969 } else if(atom_type == MKTAG('c', 'o', '6', '4')) { 968 } else if(atom_type == MKTAG('c', 'o', '6', '4')) {
980 */ 979 */
981 #endif 980 #endif
982 return 0; 981 return 0;
983 } 982 }
984 983
985 static int parse_stsc(const MOVParseTableEntry *parse_table, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size, void *param) 984 static int parse_stsc(MOVContext *c, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size)
986 { 985 {
987 MOVContext *c;
988 int entries, i; 986 int entries, i;
989 AVStream *st; 987 AVStream *st;
990 MOVStreamContext *sc; 988 MOVStreamContext *sc;
991 #ifdef DEBUG 989
992 print_atom("stsc", atom_type, atom_offset, atom_size); 990 print_atom("stsc", atom_type, atom_offset, atom_size);
993 #endif 991
994 c = (MOVContext *)param;
995 st = c->fc->streams[c->fc->nb_streams-1]; 992 st = c->fc->streams[c->fc->nb_streams-1];
996 sc = (MOVStreamContext *)st->priv_data; 993 sc = (MOVStreamContext *)st->priv_data;
997 994
998 get_byte(pb); /* version */ 995 get_byte(pb); /* version */
999 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ 996 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */
1001 entries = get_be32(pb); 998 entries = get_be32(pb);
1002 #ifdef DEBUG 999 #ifdef DEBUG
1003 printf("track[%i].stsc.entries = %i\n", c->fc->nb_streams-1, entries); 1000 printf("track[%i].stsc.entries = %i\n", c->fc->nb_streams-1, entries);
1004 #endif 1001 #endif
1005 sc->sample_to_chunk_sz = entries; 1002 sc->sample_to_chunk_sz = entries;
1006 sc->sample_to_chunk = av_malloc(entries * sizeof(MOV_sample_to_chunk_tbl)); 1003 sc->sample_to_chunk = (MOV_sample_to_chunk_tbl*) av_malloc(entries * sizeof(MOV_sample_to_chunk_tbl));
1004 if (!sc->sample_to_chunk)
1005 return -1;
1007 for(i=0; i<entries; i++) { 1006 for(i=0; i<entries; i++) {
1008 sc->sample_to_chunk[i].first = get_be32(pb); 1007 sc->sample_to_chunk[i].first = get_be32(pb);
1009 sc->sample_to_chunk[i].count = get_be32(pb); 1008 sc->sample_to_chunk[i].count = get_be32(pb);
1010 sc->sample_to_chunk[i].id = get_be32(pb); 1009 sc->sample_to_chunk[i].id = get_be32(pb);
1011 #ifdef DEBUG 1010 #ifdef DEBUG
1013 #endif 1012 #endif
1014 } 1013 }
1015 return 0; 1014 return 0;
1016 } 1015 }
1017 1016
1018 static int parse_stsz(const MOVParseTableEntry *parse_table, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size, void *param) 1017 static int parse_stsz(MOVContext *c, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size)
1019 { 1018 {
1020 MOVContext *c;
1021 int entries, i; 1019 int entries, i;
1022 AVStream *st; 1020 AVStream *st;
1023 MOVStreamContext *sc; 1021 MOVStreamContext *sc;
1024 #ifdef DEBUG 1022
1025 print_atom("stsz", atom_type, atom_offset, atom_size); 1023 print_atom("stsz", atom_type, atom_offset, atom_size);
1026 #endif 1024
1027 c = (MOVContext *)param;
1028 st = c->fc->streams[c->fc->nb_streams-1]; 1025 st = c->fc->streams[c->fc->nb_streams-1];
1029 sc = (MOVStreamContext *)st->priv_data; 1026 sc = (MOVStreamContext *)st->priv_data;
1030 1027
1031 get_byte(pb); /* version */ 1028 get_byte(pb); /* version */
1032 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ 1029 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */
1037 #ifdef DEBUG 1034 #ifdef DEBUG
1038 printf("sample_size = %ld sample_count = %ld\n", sc->sample_size, sc->sample_count); 1035 printf("sample_size = %ld sample_count = %ld\n", sc->sample_size, sc->sample_count);
1039 #endif 1036 #endif
1040 if(sc->sample_size) 1037 if(sc->sample_size)
1041 return 0; /* there isn't any table following */ 1038 return 0; /* there isn't any table following */
1042 sc->sample_sizes = av_malloc(entries * sizeof(long)); 1039 sc->sample_sizes = (long*) av_malloc(entries * sizeof(long));
1040 if (!sc->sample_sizes)
1041 return -1;
1043 for(i=0; i<entries; i++) { 1042 for(i=0; i<entries; i++) {
1044 sc->sample_sizes[i] = get_be32(pb); 1043 sc->sample_sizes[i] = get_be32(pb);
1045 #ifdef DEBUG 1044 #ifdef DEBUG
1046 /* printf("sample_sizes[]=%ld\n", sc->sample_sizes[i]); */ 1045 /* printf("sample_sizes[]=%ld\n", sc->sample_sizes[i]); */
1047 #endif 1046 #endif
1048 } 1047 }
1049 return 0; 1048 return 0;
1050 } 1049 }
1051 1050
1052 static int parse_stts(const MOVParseTableEntry *parse_table, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size, void *param) 1051 static int parse_stts(MOVContext *c, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size)
1053 { 1052 {
1054 MOVContext *c;
1055 int entries, i; 1053 int entries, i;
1056 AVStream *st; 1054 AVStream *st;
1057 MOVStreamContext *sc; 1055 MOVStreamContext *sc;
1058 #ifdef DEBUG 1056
1059 print_atom("stts", atom_type, atom_offset, atom_size); 1057 print_atom("stts", atom_type, atom_offset, atom_size);
1060 #endif 1058
1061 c = (MOVContext *)param;
1062 st = c->fc->streams[c->fc->nb_streams-1]; 1059 st = c->fc->streams[c->fc->nb_streams-1];
1063 sc = (MOVStreamContext *)st->priv_data; 1060 sc = (MOVStreamContext *)st->priv_data;
1064 1061
1065 get_byte(pb); /* version */ 1062 get_byte(pb); /* version */
1066 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ 1063 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */
1089 static int null_read_packet(void *opaque, uint8_t *buf, int buf_size) 1086 static int null_read_packet(void *opaque, uint8_t *buf, int buf_size)
1090 { 1087 {
1091 return -1; 1088 return -1;
1092 } 1089 }
1093 1090
1094 static int parse_cmov(const MOVParseTableEntry *parse_table, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size, void *param) 1091 static int parse_cmov(MOVContext *c, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size)
1095 { 1092 {
1096 MOVContext *c;
1097 ByteIOContext ctx; 1093 ByteIOContext ctx;
1098 char *cmov_data; 1094 uint8_t *cmov_data;
1099 unsigned char *moov_data; /* uncompressed data */ 1095 uint8_t *moov_data; /* uncompressed data */
1100 long cmov_len, moov_len; 1096 long cmov_len, moov_len;
1101 int ret; 1097 int ret;
1102 #ifdef DEBUG 1098
1103 print_atom("cmov", atom_type, atom_offset, atom_size); 1099 print_atom("cmov", atom_type, atom_offset, atom_size);
1104 #endif
1105 c = (MOVContext *)param;
1106 1100
1107 get_be32(pb); /* dcom atom */ 1101 get_be32(pb); /* dcom atom */
1108 if (get_le32(pb) != MKTAG( 'd', 'c', 'o', 'm' )) 1102 if (get_le32(pb) != MKTAG( 'd', 'c', 'o', 'm' ))
1109 return -1; 1103 return -1;
1110 if (get_le32(pb) != MKTAG( 'z', 'l', 'i', 'b' )) { 1104 if (get_le32(pb) != MKTAG( 'z', 'l', 'i', 'b' )) {
1115 if (get_le32(pb) != MKTAG( 'c', 'm', 'v', 'd' )) 1109 if (get_le32(pb) != MKTAG( 'c', 'm', 'v', 'd' ))
1116 return -1; 1110 return -1;
1117 moov_len = get_be32(pb); /* uncompressed size */ 1111 moov_len = get_be32(pb); /* uncompressed size */
1118 cmov_len = atom_size - 6 * 4; 1112 cmov_len = atom_size - 6 * 4;
1119 1113
1120 cmov_data = av_malloc(cmov_len); 1114 cmov_data = (uint8_t *) av_malloc(cmov_len);
1121 if (!cmov_data) 1115 if (!cmov_data)
1122 return -1; 1116 return -1;
1123 moov_data = av_malloc(moov_len); 1117 moov_data = (uint8_t *) av_malloc(moov_len);
1124 if (!moov_data) { 1118 if (!moov_data) {
1125 av_free(cmov_data); 1119 av_free(cmov_data);
1126 return -1; 1120 return -1;
1127 } 1121 }
1128 get_buffer(pb, cmov_data, cmov_len); 1122 get_buffer(pb, cmov_data, cmov_len);
1129 if(uncompress (moov_data, &moov_len, (const Bytef *)cmov_data, cmov_len) != Z_OK) 1123 if(uncompress (moov_data, (uLongf *) &moov_len, (const Bytef *)cmov_data, cmov_len) != Z_OK)
1130 return -1; 1124 return -1;
1131 if(init_put_byte(&ctx, moov_data, moov_len, 0, NULL, null_read_packet, NULL, NULL) != 0) 1125 if(init_put_byte(&ctx, moov_data, moov_len, 0, NULL, null_read_packet, NULL, NULL) != 0)
1132 return -1; 1126 return -1;
1133 ctx.buf_end = ctx.buffer + moov_len; 1127 ctx.buf_end = ctx.buffer + moov_len;
1134 ret = parse_default(parse_table, &ctx, MKTAG( 'm', 'o', 'o', 'v' ), 0, moov_len, param); 1128 ret = parse_default(c, &ctx, MKTAG( 'm', 'o', 'o', 'v' ), 0, moov_len);
1135 av_free(moov_data); 1129 av_free(moov_data);
1136 av_free(cmov_data); 1130 av_free(cmov_data);
1137 return ret; 1131 return ret;
1138 } 1132 }
1139 #endif 1133 #endif
1233 static inline uint32_t to_be32(uint8_t *buf) 1227 static inline uint32_t to_be32(uint8_t *buf)
1234 { 1228 {
1235 return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; 1229 return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
1236 } 1230 }
1237 1231
1238 /* XXX: is it suffisant ? */ 1232 /* XXX: is it sufficient ? */
1239 static int mov_probe(AVProbeData *p) 1233 static int mov_probe(AVProbeData *p)
1240 { 1234 {
1241 unsigned int offset; 1235 unsigned int offset;
1242 uint32_t tag; 1236 uint32_t tag;
1243 1237
1269 return 0; 1263 return 0;
1270 } 1264 }
1271 1265
1272 static int mov_read_header(AVFormatContext *s, AVFormatParameters *ap) 1266 static int mov_read_header(AVFormatContext *s, AVFormatParameters *ap)
1273 { 1267 {
1274 MOVContext *mov = s->priv_data; 1268 MOVContext *mov = (MOVContext *) s->priv_data;
1275 ByteIOContext *pb = &s->pb; 1269 ByteIOContext *pb = &s->pb;
1276 int i, j, nb, err; 1270 int i, j, nb, err;
1277 int64_t size; 1271 int64_t size;
1278 1272
1279 mov->fc = s; 1273 mov->fc = s;
1274 mov->parse_table = mov_default_parse_table;
1280 #if 0 1275 #if 0
1281 /* XXX: I think we should auto detect */ 1276 /* XXX: I think we should auto detect */
1282 if(s->iformat->name[1] == 'p') 1277 if(s->iformat->name[1] == 'p')
1283 mov->mp4 = 1; 1278 mov->mp4 = 1;
1284 #endif 1279 #endif
1290 #ifdef DEBUG 1285 #ifdef DEBUG
1291 printf("filesz=%Ld\n", size); 1286 printf("filesz=%Ld\n", size);
1292 #endif 1287 #endif
1293 1288
1294 /* check MOV header */ 1289 /* check MOV header */
1295 err = parse_default(mov_default_parse_table, pb, 0L, 0LL, size, mov); 1290 err = parse_default(mov, pb, 0L, 0LL, size);
1296 if(err<0 || (!mov->found_moov || !mov->found_mdat)) { 1291 if(err<0 || (!mov->found_moov || !mov->found_mdat)) {
1297 puts("header not found !!!"); 1292 puts("header not found !!!");
1298 exit(1); 1293 exit(1);
1299 } 1294 }
1300 #ifdef DEBUG 1295 #ifdef DEBUG
1340 1335
1341 /* Yes, this is ugly... I didn't write the specs of QT :p */ 1336 /* Yes, this is ugly... I didn't write the specs of QT :p */
1342 /* XXX:remove useless commented code sometime */ 1337 /* XXX:remove useless commented code sometime */
1343 static int mov_read_packet(AVFormatContext *s, AVPacket *pkt) 1338 static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
1344 { 1339 {
1345 MOVContext *mov = s->priv_data; 1340 MOVContext *mov = (MOVContext *) s->priv_data;
1346 MOVStreamContext *sc; 1341 MOVStreamContext *sc;
1347 int64_t offset = 0x0FFFFFFFFFFFFFFF; 1342 int64_t offset = 0x0FFFFFFFFFFFFFFF;
1348 int i; 1343 int i;
1349 int size; 1344 int size;
1350 size = 0x0FFFFFFF; 1345 size = 0x0FFFFFFF;
1470 } 1465 }
1471 1466
1472 static int mov_read_close(AVFormatContext *s) 1467 static int mov_read_close(AVFormatContext *s)
1473 { 1468 {
1474 int i; 1469 int i;
1475 MOVContext *mov = s->priv_data; 1470 MOVContext *mov = (MOVContext *) s->priv_data;
1476 for(i=0; i<mov->total_streams; i++) 1471 for(i=0; i<mov->total_streams; i++)
1477 mov_free_stream_context(mov->streams[i]); 1472 mov_free_stream_context(mov->streams[i]);
1478 for(i=0; i<s->nb_streams; i++) 1473 for(i=0; i<s->nb_streams; i++)
1479 av_freep(&s->streams[i]); 1474 av_freep(&s->streams[i]);
1480 return 0; 1475 return 0;