Mercurial > libavformat.hg
comparison mov.c @ 491:4cf46e9a1bb8 libavformat
Seeking in .mov/.mp4 files
printf->av_log
patch by (Gael Chardon <gael.ffmpeg at 4now dot net>)
author | michael |
---|---|
date | Tue, 06 Jul 2004 02:35:39 +0000 |
parents | aeb69a5f3756 |
children | 0ed5d359f63a |
comparison
equal
deleted
inserted
replaced
490:c0849ef998e7 | 491:4cf46e9a1bb8 |
---|---|
26 #include <zlib.h> | 26 #include <zlib.h> |
27 #endif | 27 #endif |
28 | 28 |
29 /* | 29 /* |
30 * First version by Francois Revol revol@free.fr | 30 * First version by Francois Revol revol@free.fr |
31 * Seek function by Gael Chardon gael.dev@4now.net | |
31 * | 32 * |
32 * Features and limitations: | 33 * Features and limitations: |
33 * - reads most of the QT files I have (at least the structure), | 34 * - reads most of the QT files I have (at least the structure), |
34 * the exceptions are .mov with zlib compressed headers ('cmov' section). It shouldn't be hard to implement. | 35 * the exceptions are .mov with zlib compressed headers ('cmov' section). It shouldn't be hard to implement. |
35 * FIXED, Francois Revol, 07/17/2002 | 36 * FIXED, Francois Revol, 07/17/2002 |
38 * Sample QuickTime files with mp3 audio can be found at: http://www.3ivx.com/showcase.html | 39 * Sample QuickTime files with mp3 audio can be found at: http://www.3ivx.com/showcase.html |
39 * - .mp4 parsing is still hazardous, although the format really is QuickTime with some minor changes | 40 * - .mp4 parsing is still hazardous, although the format really is QuickTime with some minor changes |
40 * (to make .mov parser crash maybe ?), despite what they say in the MPEG FAQ at | 41 * (to make .mov parser crash maybe ?), despite what they say in the MPEG FAQ at |
41 * http://mpeg.telecomitalialab.com/faq.htm | 42 * http://mpeg.telecomitalialab.com/faq.htm |
42 * - the code is quite ugly... maybe I won't do it recursive next time :-) | 43 * - the code is quite ugly... maybe I won't do it recursive next time :-) |
44 * - seek is not supported with files that contain edit list | |
43 * | 45 * |
44 * Funny I didn't know about http://sourceforge.net/projects/qt-ffmpeg/ | 46 * Funny I didn't know about http://sourceforge.net/projects/qt-ffmpeg/ |
45 * when coding this :) (it's a writer anyway) | 47 * when coding this :) (it's a writer anyway) |
46 * | 48 * |
47 * Reference documents: | 49 * Reference documents: |
48 * http://www.geocities.com/xhelmboyx/quicktime/formats/qtm-layout.txt | 50 * http://www.geocities.com/xhelmboyx/quicktime/formats/qtm-layout.txt |
49 * Apple: | 51 * Apple: |
50 * http://developer.apple.com/techpubs/quicktime/qtdevdocs/QTFF/qtff.html | 52 * http://developer.apple.com/documentation/QuickTime/QTFF/ |
51 * http://developer.apple.com/techpubs/quicktime/qtdevdocs/PDF/QTFileFormat.pdf | 53 * http://developer.apple.com/documentation/QuickTime/PDF/QTFileFormat.pdf |
52 * QuickTime is a trademark of Apple (AFAIK :)) | 54 * QuickTime is a trademark of Apple (AFAIK :)) |
53 */ | 55 */ |
54 | 56 |
55 //#define DEBUG | 57 //#define DEBUG |
56 #ifdef DEBUG | 58 #ifdef DEBUG |
57 #include <stdio.h> | 59 #include <stdio.h> |
58 #include <fcntl.h> | 60 #include <fcntl.h> |
59 #endif | 61 #endif |
60 | 62 |
61 #include "qtpalette.h" | 63 #include "qtpalette.h" |
64 | |
65 | |
66 /* Allows seeking (MOV_SPLIT_CHUNKS should also be defined) */ | |
67 #define MOV_SEEK | |
62 | 68 |
63 /* allows chunk splitting - should work now... */ | 69 /* allows chunk splitting - should work now... */ |
64 /* in case you can't read a file, try commenting */ | 70 /* in case you can't read a file, try commenting */ |
65 #define MOV_SPLIT_CHUNKS | 71 #define MOV_SPLIT_CHUNKS |
66 | 72 |
215 int ffindex; /* the ffmpeg stream id */ | 221 int ffindex; /* the ffmpeg stream id */ |
216 int is_ff_stream; /* Is this stream presented to ffmpeg ? i.e. is this an audio or video stream ? */ | 222 int is_ff_stream; /* Is this stream presented to ffmpeg ? i.e. is this an audio or video stream ? */ |
217 long next_chunk; | 223 long next_chunk; |
218 long chunk_count; | 224 long chunk_count; |
219 int64_t *chunk_offsets; | 225 int64_t *chunk_offsets; |
226 int32_t stts_count; | |
227 uint64_t *stts_data; /* concatenated data from the time-to-sample atom (count|duration) */ | |
228 int32_t edit_count; /* number of 'edit' (elst atom) */ | |
220 long sample_to_chunk_sz; | 229 long sample_to_chunk_sz; |
221 MOV_sample_to_chunk_tbl *sample_to_chunk; | 230 MOV_sample_to_chunk_tbl *sample_to_chunk; |
222 long sample_to_chunk_index; | 231 long sample_to_chunk_index; |
223 long sample_size; | 232 long sample_size; |
224 long sample_count; | 233 long sample_count; |
287 unsigned int tag, i; | 296 unsigned int tag, i; |
288 tag = (unsigned int) atom.type; | 297 tag = (unsigned int) atom.type; |
289 i=debug_indent; | 298 i=debug_indent; |
290 if(tag == 0) tag = MKTAG('N', 'U', 'L', 'L'); | 299 if(tag == 0) tag = MKTAG('N', 'U', 'L', 'L'); |
291 while(i--) | 300 while(i--) |
292 printf("|"); | 301 av_log(NULL, AV_LOG_DEBUG, "|"); |
293 printf("parse:"); | 302 av_log(NULL, AV_LOG_DEBUG, "parse:"); |
294 printf(" %s: tag=%c%c%c%c offset=0x%x size=0x%x\n", | 303 av_log(NULL, AV_LOG_DEBUG, " %s: tag=%c%c%c%c offset=0x%x size=0x%x\n", |
295 str, tag & 0xff, | 304 str, tag & 0xff, |
296 (tag >> 8) & 0xff, | 305 (tag >> 8) & 0xff, |
297 (tag >> 16) & 0xff, | 306 (tag >> 16) & 0xff, |
298 (tag >> 24) & 0xff, | 307 (tag >> 24) & 0xff, |
299 (unsigned int)atom.offset, | 308 (unsigned int)atom.offset, |
338 a.size = get_be32(pb); | 347 a.size = get_be32(pb); |
339 a.type = get_le32(pb); | 348 a.type = get_le32(pb); |
340 } | 349 } |
341 total_size += 8; | 350 total_size += 8; |
342 a.offset += 8; | 351 a.offset += 8; |
343 //printf("type: %08x %.4s sz: %Lx %Lx %Lx\n", type, (char*)&type, size, atom.size, total_size); | 352 //av_log(NULL, AV_LOG_DEBUG, "type: %08x %.4s sz: %Lx %Lx %Lx\n", type, (char*)&type, size, atom.size, total_size); |
344 if (a.size == 1) { /* 64 bit extended size */ | 353 if (a.size == 1) { /* 64 bit extended size */ |
345 a.size = get_be64(pb) - 8; | 354 a.size = get_be64(pb) - 8; |
346 a.offset += 8; | 355 a.offset += 8; |
347 total_size += 8; | 356 total_size += 8; |
348 } | 357 } |
354 for (i = 0; c->parse_table[i].type != 0L | 363 for (i = 0; c->parse_table[i].type != 0L |
355 && c->parse_table[i].type != a.type; i++) | 364 && c->parse_table[i].type != a.type; i++) |
356 /* empty */; | 365 /* empty */; |
357 | 366 |
358 a.size -= 8; | 367 a.size -= 8; |
359 // printf(" i=%ld\n", i); | 368 // av_log(NULL, AV_LOG_DEBUG, " i=%ld\n", i); |
360 if (c->parse_table[i].type == 0) { /* skip leaf atoms data */ | 369 if (c->parse_table[i].type == 0) { /* skip leaf atoms data */ |
361 // url_seek(pb, atom.offset+atom.size, SEEK_SET); | 370 // url_seek(pb, atom.offset+atom.size, SEEK_SET); |
362 #ifdef DEBUG | 371 #ifdef DEBUG |
363 print_atom("unknown", a); | 372 print_atom("unknown", a); |
364 #endif | 373 #endif |
374 a.offset += a.size; | 383 a.offset += a.size; |
375 total_size += a.size; | 384 total_size += a.size; |
376 } | 385 } |
377 | 386 |
378 if (!err && total_size < atom.size && atom.size < 0x7ffff) { | 387 if (!err && total_size < atom.size && atom.size < 0x7ffff) { |
379 //printf("RESET %Ld %Ld err:%d\n", atom.size, total_size, err); | 388 //av_log(NULL, AV_LOG_DEBUG, "RESET %Ld %Ld err:%d\n", atom.size, total_size, err); |
380 url_fskip(pb, atom.size - total_size); | 389 url_fskip(pb, atom.size - total_size); |
381 } | 390 } |
382 | 391 |
383 #ifdef DEBUG | 392 #ifdef DEBUG |
384 debug_indent--; | 393 debug_indent--; |
421 /* component type */ | 430 /* component type */ |
422 ctype = get_le32(pb); | 431 ctype = get_le32(pb); |
423 type = get_le32(pb); /* component subtype */ | 432 type = get_le32(pb); /* component subtype */ |
424 | 433 |
425 #ifdef DEBUG | 434 #ifdef DEBUG |
426 printf("ctype= %c%c%c%c (0x%08lx)\n", *((char *)&ctype), ((char *)&ctype)[1], ((char *)&ctype)[2], ((char *)&ctype)[3], (long) ctype); | 435 av_log(NULL, AV_LOG_DEBUG, "ctype= %c%c%c%c (0x%08lx)\n", *((char *)&ctype), ((char *)&ctype)[1], ((char *)&ctype)[2], ((char *)&ctype)[3], (long) ctype); |
427 printf("stype= %c%c%c%c\n", *((char *)&type), ((char *)&type)[1], ((char *)&type)[2], ((char *)&type)[3]); | 436 av_log(NULL, AV_LOG_DEBUG, "stype= %c%c%c%c\n", *((char *)&type), ((char *)&type)[1], ((char *)&type)[2], ((char *)&type)[3]); |
428 #endif | 437 #endif |
429 #ifdef DEBUG | 438 #ifdef DEBUG |
430 /* XXX: yeah this is ugly... */ | 439 /* XXX: yeah this is ugly... */ |
431 if(ctype == MKTAG('m', 'h', 'l', 'r')) { /* MOV */ | 440 if(ctype == MKTAG('m', 'h', 'l', 'r')) { /* MOV */ |
432 if(type == MKTAG('v', 'i', 'd', 'e')) | 441 if(type == MKTAG('v', 'i', 'd', 'e')) |
481 #ifdef DEBUG | 490 #ifdef DEBUG |
482 buf = (uint8_t*) av_malloc(len+1); | 491 buf = (uint8_t*) av_malloc(len+1); |
483 if (buf) { | 492 if (buf) { |
484 get_buffer(pb, buf, len); | 493 get_buffer(pb, buf, len); |
485 buf[len] = '\0'; | 494 buf[len] = '\0'; |
486 printf("**buf='%s'\n", buf); | 495 av_log(NULL, AV_LOG_DEBUG, "**buf='%s'\n", buf); |
487 av_free(buf); | 496 av_free(buf); |
488 } else | 497 } else |
489 #endif | 498 #endif |
490 url_fskip(pb, len); | 499 url_fskip(pb, len); |
491 } | 500 } |
511 { | 520 { |
512 int len; | 521 int len; |
513 *tag = get_byte(pb); | 522 *tag = get_byte(pb); |
514 len = mov_mp4_read_descr_len(pb); | 523 len = mov_mp4_read_descr_len(pb); |
515 #ifdef DEBUG | 524 #ifdef DEBUG |
516 printf("MPEG4 description: tag=0x%02x len=%d\n", *tag, len); | 525 av_log(NULL, AV_LOG_DEBUG, "MPEG4 description: tag=0x%02x len=%d\n", *tag, len); |
517 #endif | 526 #endif |
518 return len; | 527 return len; |
519 } | 528 } |
520 | 529 |
521 static inline unsigned int get_be24(ByteIOContext *s) | 530 static inline unsigned int get_be24(ByteIOContext *s) |
552 sc->esds.buffer_size_db = get_be24(pb); | 561 sc->esds.buffer_size_db = get_be24(pb); |
553 sc->esds.max_bitrate = get_be32(pb); | 562 sc->esds.max_bitrate = get_be32(pb); |
554 sc->esds.avg_bitrate = get_be32(pb); | 563 sc->esds.avg_bitrate = get_be32(pb); |
555 | 564 |
556 len = mov_mp4_read_descr(pb, &tag); | 565 len = mov_mp4_read_descr(pb, &tag); |
557 //printf("LEN %d TAG %d m:%d a:%d\n", len, tag, sc->esds.max_bitrate, sc->esds.avg_bitrate); | 566 //av_log(NULL, AV_LOG_DEBUG, "LEN %d TAG %d m:%d a:%d\n", len, tag, sc->esds.max_bitrate, sc->esds.avg_bitrate); |
558 if (tag == MP4DecSpecificDescrTag) { | 567 if (tag == MP4DecSpecificDescrTag) { |
559 #ifdef DEBUG | 568 #ifdef DEBUG |
560 printf("Specific MPEG4 header len=%d\n", len); | 569 av_log(NULL, AV_LOG_DEBUG, "Specific MPEG4 header len=%d\n", len); |
561 #endif | 570 #endif |
562 st->codec.extradata = (uint8_t*) av_mallocz(len); | 571 st->codec.extradata = (uint8_t*) av_mallocz(len); |
563 if (st->codec.extradata) { | 572 if (st->codec.extradata) { |
564 get_buffer(pb, st->codec.extradata, len); | 573 get_buffer(pb, st->codec.extradata, len); |
565 st->codec.extradata_size = len; | 574 st->codec.extradata_size = len; |
614 get_byte(pb); /* flags */ | 623 get_byte(pb); /* flags */ |
615 | 624 |
616 get_be32(pb); /* creation time */ | 625 get_be32(pb); /* creation time */ |
617 get_be32(pb); /* modification time */ | 626 get_be32(pb); /* modification time */ |
618 | 627 |
619 c->streams[c->total_streams]->time_scale = get_be32(pb); | 628 c->streams[c->fc->nb_streams-1]->time_scale = get_be32(pb); |
620 | 629 |
621 #ifdef DEBUG | 630 #ifdef DEBUG |
622 printf("track[%i].time_scale = %i\n", c->fc->nb_streams-1, c->streams[c->total_streams]->time_scale); /* time scale */ | 631 av_log(NULL, AV_LOG_DEBUG, "track[%i].time_scale = %i\n", c->fc->nb_streams-1, c->streams[c->fc->nb_streams-1]->time_scale); /* time scale */ |
623 #endif | 632 #endif |
624 get_be32(pb); /* duration */ | 633 get_be32(pb); /* duration */ |
625 | 634 |
626 get_be16(pb); /* language */ | 635 get_be16(pb); /* language */ |
627 get_be16(pb); /* quality */ | 636 get_be16(pb); /* quality */ |
638 | 647 |
639 get_be32(pb); /* creation time */ | 648 get_be32(pb); /* creation time */ |
640 get_be32(pb); /* modification time */ | 649 get_be32(pb); /* modification time */ |
641 c->time_scale = get_be32(pb); /* time scale */ | 650 c->time_scale = get_be32(pb); /* time scale */ |
642 #ifdef DEBUG | 651 #ifdef DEBUG |
643 printf("time scale = %i\n", c->time_scale); | 652 av_log(NULL, AV_LOG_DEBUG, "time scale = %i\n", c->time_scale); |
644 #endif | 653 #endif |
645 c->duration = get_be32(pb); /* duration */ | 654 c->duration = get_be32(pb); /* duration */ |
646 get_be32(pb); /* preferred scale */ | 655 get_be32(pb); /* preferred scale */ |
647 | 656 |
648 get_be16(pb); /* preferred volume */ | 657 get_be16(pb); /* preferred volume */ |
673 st->codec.extradata = (uint8_t*) av_mallocz(st->codec.extradata_size); | 682 st->codec.extradata = (uint8_t*) av_mallocz(st->codec.extradata_size); |
674 | 683 |
675 if (st->codec.extradata) { | 684 if (st->codec.extradata) { |
676 strcpy(st->codec.extradata, "SVQ3"); // fake | 685 strcpy(st->codec.extradata, "SVQ3"); // fake |
677 get_buffer(pb, st->codec.extradata + 0x5a, atom.size); | 686 get_buffer(pb, st->codec.extradata + 0x5a, atom.size); |
678 //printf("Reading SMI %Ld %s\n", atom.size, (char*)st->codec.extradata + 0x5a); | 687 //av_log(NULL, AV_LOG_DEBUG, "Reading SMI %Ld %s\n", atom.size, (char*)st->codec.extradata + 0x5a); |
679 } else | 688 } else |
680 url_fskip(pb, atom.size); | 689 url_fskip(pb, atom.size); |
681 | 690 |
682 return 0; | 691 return 0; |
683 } | 692 } |
709 } else | 718 } else |
710 return -1; | 719 return -1; |
711 #ifdef DEBUG | 720 #ifdef DEBUG |
712 /* | 721 /* |
713 for(i=0; i<entries; i++) { | 722 for(i=0; i<entries; i++) { |
714 printf("chunk offset=0x%Lx\n", sc->chunk_offsets[i]); | 723 av_log(NULL, AV_LOG_DEBUG, "chunk offset=0x%Lx\n", sc->chunk_offsets[i]); |
715 } | 724 } |
716 */ | 725 */ |
717 #endif | 726 #endif |
718 return 0; | 727 return 0; |
719 } | 728 } |
760 codec = avcodec_find_decoder(id); | 769 codec = avcodec_find_decoder(id); |
761 if (codec) | 770 if (codec) |
762 st->codec.codec_type = codec->type; | 771 st->codec.codec_type = codec->type; |
763 } | 772 } |
764 #ifdef DEBUG | 773 #ifdef DEBUG |
765 printf("size=%d 4CC= %c%c%c%c codec_type=%d\n", | 774 av_log(NULL, AV_LOG_DEBUG, "size=%d 4CC= %c%c%c%c codec_type=%d\n", |
766 size, | 775 size, |
767 (format >> 0) & 0xff, | 776 (format >> 0) & 0xff, |
768 (format >> 8) & 0xff, | 777 (format >> 8) & 0xff, |
769 (format >> 16) & 0xff, | 778 (format >> 16) & 0xff, |
770 (format >> 24) & 0xff, | 779 (format >> 24) & 0xff, |
792 get_be32(pb); /* horiz resolution */ | 801 get_be32(pb); /* horiz resolution */ |
793 get_be32(pb); /* vert resolution */ | 802 get_be32(pb); /* vert resolution */ |
794 get_be32(pb); /* data size, always 0 */ | 803 get_be32(pb); /* data size, always 0 */ |
795 frames_per_sample = get_be16(pb); /* frames per samples */ | 804 frames_per_sample = get_be16(pb); /* frames per samples */ |
796 #ifdef DEBUG | 805 #ifdef DEBUG |
797 printf("frames/samples = %d\n", frames_per_sample); | 806 av_log(NULL, AV_LOG_DEBUG, "frames/samples = %d\n", frames_per_sample); |
798 #endif | 807 #endif |
799 get_buffer(pb, (uint8_t *)st->codec.codec_name, 32); /* codec name */ | 808 get_buffer(pb, (uint8_t *)st->codec.codec_name, 32); /* codec name */ |
800 | 809 |
801 st->codec.bits_per_sample = get_be16(pb); /* depth */ | 810 st->codec.bits_per_sample = get_be16(pb); /* depth */ |
802 st->codec.color_table_id = get_be16(pb); /* colortable id */ | 811 st->codec.color_table_id = get_be16(pb); /* colortable id */ |
813 | 822 |
814 a.size = get_be32(pb); | 823 a.size = get_be32(pb); |
815 a.type = get_le32(pb); | 824 a.type = get_le32(pb); |
816 size -= 8; | 825 size -= 8; |
817 #ifdef DEBUG | 826 #ifdef DEBUG |
818 printf("VIDEO: atom_type=%c%c%c%c atom.size=%Ld size_left=%d\n", | 827 av_log(NULL, AV_LOG_DEBUG, "VIDEO: atom_type=%c%c%c%c atom.size=%Ld size_left=%d\n", |
819 (a.type >> 0) & 0xff, | 828 (a.type >> 0) & 0xff, |
820 (a.type >> 8) & 0xff, | 829 (a.type >> 8) & 0xff, |
821 (a.type >> 16) & 0xff, | 830 (a.type >> 16) & 0xff, |
822 (a.type >> 24) & 0xff, | 831 (a.type >> 24) & 0xff, |
823 a.size, size); | 832 a.size, size); |
846 len = mov_mp4_read_descr(pb, &tag); | 855 len = mov_mp4_read_descr(pb, &tag); |
847 if (tag != 0x05) | 856 if (tag != 0x05) |
848 goto fail; | 857 goto fail; |
849 /* MP4DecSpecificDescrTag */ | 858 /* MP4DecSpecificDescrTag */ |
850 #ifdef DEBUG | 859 #ifdef DEBUG |
851 printf("Specific MPEG4 header len=%d\n", len); | 860 av_log(NULL, AV_LOG_DEBUG, "Specific MPEG4 header len=%d\n", len); |
852 #endif | 861 #endif |
853 sc->header_data = av_mallocz(len); | 862 sc->header_data = av_mallocz(len); |
854 if (sc->header_data) { | 863 if (sc->header_data) { |
855 get_buffer(pb, sc->header_data, len); | 864 get_buffer(pb, sc->header_data, len); |
856 sc->header_len = len; | 865 sc->header_len = len; |
861 break; | 870 break; |
862 default: | 871 default: |
863 break; | 872 break; |
864 } | 873 } |
865 fail: | 874 fail: |
866 printf("ATOMENEWSIZE %Ld %d\n", atom.size, url_ftell(pb) - start_pos); | 875 av_log(NULL, AV_LOG_DEBUG, "ATOMENEWSIZE %Ld %d\n", atom.size, url_ftell(pb) - start_pos); |
867 if (atom.size > 8) { | 876 if (atom.size > 8) { |
868 url_fskip(pb, (atom.size - 8) - | 877 url_fskip(pb, (atom.size - 8) - |
869 ((url_ftell(pb) - start_pos))); | 878 ((url_ftell(pb) - start_pos))); |
870 size -= atom.size - 8; | 879 size -= atom.size - 8; |
871 } | 880 } |
952 } else { | 961 } else { |
953 st->codec.codec_id = codec_get_id(mov_audio_tags, format); | 962 st->codec.codec_id = codec_get_id(mov_audio_tags, format); |
954 if(st->codec.codec_id==CODEC_ID_AMR_NB || st->codec.codec_id==CODEC_ID_AMR_WB) //from TS26.244 | 963 if(st->codec.codec_id==CODEC_ID_AMR_NB || st->codec.codec_id==CODEC_ID_AMR_WB) //from TS26.244 |
955 { | 964 { |
956 #ifdef DEBUG | 965 #ifdef DEBUG |
957 printf("AMR-NB or AMR-WB audio identified!!\n"); | 966 av_log(NULL, AV_LOG_DEBUG, "AMR-NB or AMR-WB audio identified!!\n"); |
958 #endif | 967 #endif |
959 get_be32(pb);get_be32(pb); //Reserved_8 | 968 get_be32(pb);get_be32(pb); //Reserved_8 |
960 get_be16(pb);//Reserved_2 | 969 get_be16(pb);//Reserved_2 |
961 get_be16(pb);//Reserved_2 | 970 get_be16(pb);//Reserved_2 |
962 get_be32(pb);//Reserved_4 | 971 get_be32(pb);//Reserved_4 |
1025 } | 1034 } |
1026 } | 1035 } |
1027 else if(size>=(16+20)) | 1036 else if(size>=(16+20)) |
1028 {//16 bytes read, reading atleast 20 more | 1037 {//16 bytes read, reading atleast 20 more |
1029 #ifdef DEBUG | 1038 #ifdef DEBUG |
1030 printf("audio size=0x%X\n",size); | 1039 av_log(NULL, AV_LOG_DEBUG, "audio size=0x%X\n",size); |
1031 #endif | 1040 #endif |
1032 uint16_t version = get_be16(pb); /* version */ | 1041 uint16_t version = get_be16(pb); /* version */ |
1033 get_be16(pb); /* revision level */ | 1042 get_be16(pb); /* revision level */ |
1034 get_be32(pb); /* vendor */ | 1043 get_be32(pb); /* vendor */ |
1035 | 1044 |
1039 /* handle specific s8 codec */ | 1048 /* handle specific s8 codec */ |
1040 get_be16(pb); /* compression id = 0*/ | 1049 get_be16(pb); /* compression id = 0*/ |
1041 get_be16(pb); /* packet size = 0 */ | 1050 get_be16(pb); /* packet size = 0 */ |
1042 | 1051 |
1043 st->codec.sample_rate = ((get_be32(pb) >> 16)); | 1052 st->codec.sample_rate = ((get_be32(pb) >> 16)); |
1044 //printf("CODECID %d %d %.4s\n", st->codec.codec_id, CODEC_ID_PCM_S16BE, (char*)&format); | 1053 //av_log(NULL, AV_LOG_DEBUG, "CODECID %d %d %.4s\n", st->codec.codec_id, CODEC_ID_PCM_S16BE, (char*)&format); |
1045 | 1054 |
1046 switch (st->codec.codec_id) { | 1055 switch (st->codec.codec_id) { |
1047 case CODEC_ID_PCM_S16BE: | 1056 case CODEC_ID_PCM_S16BE: |
1048 if (st->codec.bits_per_sample == 8) | 1057 if (st->codec.bits_per_sample == 8) |
1049 st->codec.codec_id = CODEC_ID_PCM_S8; | 1058 st->codec.codec_id = CODEC_ID_PCM_S8; |
1055 ; | 1064 ; |
1056 } | 1065 } |
1057 | 1066 |
1058 //Read QT version 1 fields. In version 0 theese dont exist | 1067 //Read QT version 1 fields. In version 0 theese dont exist |
1059 #ifdef DEBUG | 1068 #ifdef DEBUG |
1060 printf("version =%d mp4=%d\n",version,c->mp4); | 1069 av_log(NULL, AV_LOG_DEBUG, "version =%d mp4=%d\n",version,c->mp4); |
1061 printf("size-(16+20+16)=%d\n",size-(16+20+16)); | 1070 av_log(NULL, AV_LOG_DEBUG, "size-(16+20+16)=%d\n",size-(16+20+16)); |
1062 #endif | 1071 #endif |
1063 if((version==1) && size>=(16+20+16)) | 1072 if((version==1) && size>=(16+20+16)) |
1064 { | 1073 { |
1065 get_be32(pb); /* samples per packet */ | 1074 get_be32(pb); /* samples per packet */ |
1066 get_be32(pb); /* bytes per packet */ | 1075 get_be32(pb); /* bytes per packet */ |
1068 get_be32(pb); /* bytes per sample */ | 1077 get_be32(pb); /* bytes per sample */ |
1069 if(size>(16+20+16)) | 1078 if(size>(16+20+16)) |
1070 { | 1079 { |
1071 //Optional, additional atom-based fields | 1080 //Optional, additional atom-based fields |
1072 #ifdef DEBUG | 1081 #ifdef DEBUG |
1073 printf("offest=0x%X, sizeleft=%d=0x%x,format=%c%c%c%c\n",(int)url_ftell(pb),size - (16 + 20 + 16 ),size - (16 + 20 + 16 ), | 1082 av_log(NULL, AV_LOG_DEBUG, "offest=0x%X, sizeleft=%d=0x%x,format=%c%c%c%c\n",(int)url_ftell(pb),size - (16 + 20 + 16 ),size - (16 + 20 + 16 ), |
1074 (format >> 0) & 0xff, | 1083 (format >> 0) & 0xff, |
1075 (format >> 8) & 0xff, | 1084 (format >> 8) & 0xff, |
1076 (format >> 16) & 0xff, | 1085 (format >> 16) & 0xff, |
1077 (format >> 24) & 0xff); | 1086 (format >> 24) & 0xff); |
1078 #endif | 1087 #endif |
1084 { | 1093 { |
1085 //We should be down to 0 bytes here, but lets make sure. | 1094 //We should be down to 0 bytes here, but lets make sure. |
1086 size-=(16+20); | 1095 size-=(16+20); |
1087 #ifdef DEBUG | 1096 #ifdef DEBUG |
1088 if(size>0) | 1097 if(size>0) |
1089 printf("skipping 0x%X bytes\n",size-(16+20)); | 1098 av_log(NULL, AV_LOG_DEBUG, "skipping 0x%X bytes\n",size-(16+20)); |
1090 #endif | 1099 #endif |
1091 url_fskip(pb, size); | 1100 url_fskip(pb, size); |
1092 } | 1101 } |
1093 } | 1102 } |
1094 else | 1103 else |
1095 { | 1104 { |
1096 size-=16; | 1105 size-=16; |
1097 //Unknown size, but lets do our best and skip the rest. | 1106 //Unknown size, but lets do our best and skip the rest. |
1098 #ifdef DEBUG | 1107 #ifdef DEBUG |
1099 printf("Strange size, skipping 0x%X bytes\n",size); | 1108 av_log(NULL, AV_LOG_DEBUG, "Strange size, skipping 0x%X bytes\n",size); |
1100 #endif | 1109 #endif |
1101 url_fskip(pb, size); | 1110 url_fskip(pb, size); |
1102 } | 1111 } |
1103 } | 1112 } |
1104 } | 1113 } |
1117 get_byte(pb); /* version */ | 1126 get_byte(pb); /* version */ |
1118 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ | 1127 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ |
1119 | 1128 |
1120 entries = get_be32(pb); | 1129 entries = get_be32(pb); |
1121 #ifdef DEBUG | 1130 #ifdef DEBUG |
1122 printf("track[%i].stsc.entries = %i\n", c->fc->nb_streams-1, entries); | 1131 av_log(NULL, AV_LOG_DEBUG, "track[%i].stsc.entries = %i\n", c->fc->nb_streams-1, entries); |
1123 #endif | 1132 #endif |
1124 sc->sample_to_chunk_sz = entries; | 1133 sc->sample_to_chunk_sz = entries; |
1125 sc->sample_to_chunk = (MOV_sample_to_chunk_tbl*) av_malloc(entries * sizeof(MOV_sample_to_chunk_tbl)); | 1134 sc->sample_to_chunk = (MOV_sample_to_chunk_tbl*) av_malloc(entries * sizeof(MOV_sample_to_chunk_tbl)); |
1126 if (!sc->sample_to_chunk) | 1135 if (!sc->sample_to_chunk) |
1127 return -1; | 1136 return -1; |
1128 for(i=0; i<entries; i++) { | 1137 for(i=0; i<entries; i++) { |
1129 sc->sample_to_chunk[i].first = get_be32(pb); | 1138 sc->sample_to_chunk[i].first = get_be32(pb); |
1130 sc->sample_to_chunk[i].count = get_be32(pb); | 1139 sc->sample_to_chunk[i].count = get_be32(pb); |
1131 sc->sample_to_chunk[i].id = get_be32(pb); | 1140 sc->sample_to_chunk[i].id = get_be32(pb); |
1132 #ifdef DEBUG | 1141 #ifdef DEBUG |
1133 /* printf("sample_to_chunk first=%ld count=%ld, id=%ld\n", sc->sample_to_chunk[i].first, sc->sample_to_chunk[i].count, sc->sample_to_chunk[i].id); */ | 1142 /* av_log(NULL, AV_LOG_DEBUG, "sample_to_chunk first=%ld count=%ld, id=%ld\n", sc->sample_to_chunk[i].first, sc->sample_to_chunk[i].count, sc->sample_to_chunk[i].id); */ |
1134 #endif | 1143 #endif |
1135 } | 1144 } |
1136 return 0; | 1145 return 0; |
1137 } | 1146 } |
1138 | 1147 |
1177 | 1186 |
1178 sc->sample_size = get_be32(pb); | 1187 sc->sample_size = get_be32(pb); |
1179 entries = get_be32(pb); | 1188 entries = get_be32(pb); |
1180 sc->sample_count = entries; | 1189 sc->sample_count = entries; |
1181 #ifdef DEBUG | 1190 #ifdef DEBUG |
1182 printf("sample_size = %ld sample_count = %ld\n", sc->sample_size, sc->sample_count); | 1191 av_log(NULL, AV_LOG_DEBUG, "sample_size = %ld sample_count = %ld\n", sc->sample_size, sc->sample_count); |
1183 #endif | 1192 #endif |
1184 if(sc->sample_size) | 1193 if(sc->sample_size) |
1185 return 0; /* there isn't any table following */ | 1194 return 0; /* there isn't any table following */ |
1186 sc->sample_sizes = (long*) av_malloc(entries * sizeof(long)); | 1195 sc->sample_sizes = (long*) av_malloc(entries * sizeof(long)); |
1187 if (!sc->sample_sizes) | 1196 if (!sc->sample_sizes) |
1188 return -1; | 1197 return -1; |
1189 for(i=0; i<entries; i++) { | 1198 for(i=0; i<entries; i++) { |
1190 sc->sample_sizes[i] = get_be32(pb); | 1199 sc->sample_sizes[i] = get_be32(pb); |
1191 #ifdef DEBUG | 1200 #ifdef DEBUG |
1192 /* printf("sample_sizes[]=%ld\n", sc->sample_sizes[i]); */ | 1201 /* av_log(NULL, AV_LOG_DEBUG, "sample_sizes[]=%ld\n", sc->sample_sizes[i]); */ |
1193 #endif | 1202 #endif |
1194 } | 1203 } |
1195 return 0; | 1204 return 0; |
1196 } | 1205 } |
1197 | 1206 |
1207 | 1216 |
1208 get_byte(pb); /* version */ | 1217 get_byte(pb); /* version */ |
1209 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ | 1218 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ |
1210 entries = get_be32(pb); | 1219 entries = get_be32(pb); |
1211 | 1220 |
1212 | 1221 c->streams[c->fc->nb_streams-1]->stts_count = entries; |
1213 #ifdef DEBUG | 1222 c->streams[c->fc->nb_streams-1]->stts_data = (uint64_t*) av_malloc(entries * sizeof(uint64_t)); |
1214 printf("track[%i].stts.entries = %i\n", c->fc->nb_streams-1, entries); | 1223 |
1224 #ifdef DEBUG | |
1225 av_log(NULL, AV_LOG_DEBUG, "track[%i].stts.entries = %i\n", c->fc->nb_streams-1, entries); | |
1215 #endif | 1226 #endif |
1216 for(i=0; i<entries; i++) { | 1227 for(i=0; i<entries; i++) { |
1217 int sample_duration; | 1228 int32_t sample_duration; |
1218 int sample_count; | 1229 int32_t sample_count; |
1219 | 1230 |
1220 sample_count=get_be32(pb); | 1231 sample_count=get_be32(pb); |
1221 sample_duration = get_be32(pb); | 1232 sample_duration = get_be32(pb); |
1222 #ifdef DEBUG | 1233 c->streams[c->fc->nb_streams - 1]->stts_data[i] = (uint64_t)sample_count<<32 | (uint64_t)sample_duration; |
1223 printf("sample_count=%d, sample_duration=%d\n",sample_count,sample_duration); | 1234 #ifdef DEBUG |
1235 av_log(NULL, AV_LOG_DEBUG, "sample_count=%d, sample_duration=%d\n",sample_count,sample_duration); | |
1224 #endif | 1236 #endif |
1225 duration+=sample_duration*sample_count; | 1237 duration+=sample_duration*sample_count; |
1226 total_sample_count+=sample_count; | 1238 total_sample_count+=sample_count; |
1227 | 1239 |
1228 #if 0 //We calculate an average instead, needed by .mp4-files created with nec e606 3g phone | 1240 #if 0 //We calculate an average instead, needed by .mp4-files created with nec e606 3g phone |
1229 | 1241 |
1230 if (!i && st->codec.codec_type==CODEC_TYPE_VIDEO) { | 1242 if (!i && st->codec.codec_type==CODEC_TYPE_VIDEO) { |
1231 st->codec.frame_rate_base = sample_duration ? sample_duration : 1; | 1243 st->codec.frame_rate_base = sample_duration ? sample_duration : 1; |
1232 st->codec.frame_rate = c->streams[c->total_streams]->time_scale; | 1244 st->codec.frame_rate = c->streams[c->fc->nb_streams-1]->time_scale; |
1233 #ifdef DEBUG | 1245 #ifdef DEBUG |
1234 printf("VIDEO FRAME RATE= %i (sd= %i)\n", st->codec.frame_rate, sample_duration); | 1246 av_log(NULL, AV_LOG_DEBUG, "VIDEO FRAME RATE= %i (sd= %i)\n", st->codec.frame_rate, sample_duration); |
1235 #endif | 1247 #endif |
1236 } | 1248 } |
1237 #endif | 1249 #endif |
1238 } | 1250 } |
1239 | 1251 |
1241 if(duration>0) | 1253 if(duration>0) |
1242 { | 1254 { |
1243 av_reduce( | 1255 av_reduce( |
1244 &st->codec.frame_rate, | 1256 &st->codec.frame_rate, |
1245 &st->codec.frame_rate_base, | 1257 &st->codec.frame_rate_base, |
1246 c->streams[c->total_streams]->time_scale * total_sample_count, | 1258 c->streams[c->fc->nb_streams-1]->time_scale * total_sample_count, |
1247 duration, | 1259 duration, |
1248 INT_MAX | 1260 INT_MAX |
1249 ); | 1261 ); |
1250 | 1262 |
1251 #ifdef DEBUG | 1263 #ifdef DEBUG |
1252 printf("FRAME RATE average (video or audio)= %f (tot sample count= %i ,tot dur= %i timescale=%d)\n", (float)st->codec.frame_rate/st->codec.frame_rate_base,total_sample_count,duration,c->streams[c->total_streams]->time_scale); | 1264 av_log(NULL, AV_LOG_DEBUG, "FRAME RATE average (video or audio)= %f (tot sample count= %i ,tot dur= %i timescale=%d)\n", (float)st->codec.frame_rate/st->codec.frame_rate_base,total_sample_count,duration,c->streams[c->fc->nb_streams-1]->time_scale); |
1253 #endif | 1265 #endif |
1254 } | 1266 } |
1255 else | 1267 else |
1256 { | 1268 { |
1257 st->codec.frame_rate_base = 1; | 1269 st->codec.frame_rate_base = 1; |
1258 st->codec.frame_rate = c->streams[c->total_streams]->time_scale; | 1270 st->codec.frame_rate = c->streams[c->fc->nb_streams-1]->time_scale; |
1259 } | 1271 } |
1260 return 0; | 1272 return 0; |
1261 } | 1273 } |
1262 | 1274 |
1263 static int mov_read_trak(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) | 1275 static int mov_read_trak(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) |
1377 | 1389 |
1378 get_be32(pb); /* dcom atom */ | 1390 get_be32(pb); /* dcom atom */ |
1379 if (get_le32(pb) != MKTAG( 'd', 'c', 'o', 'm' )) | 1391 if (get_le32(pb) != MKTAG( 'd', 'c', 'o', 'm' )) |
1380 return -1; | 1392 return -1; |
1381 if (get_le32(pb) != MKTAG( 'z', 'l', 'i', 'b' )) { | 1393 if (get_le32(pb) != MKTAG( 'z', 'l', 'i', 'b' )) { |
1382 dprintf("unknown compression for cmov atom !"); | 1394 av_log(NULL, AV_LOG_DEBUG, "unknown compression for cmov atom !"); |
1383 return -1; | 1395 return -1; |
1384 } | 1396 } |
1385 get_be32(pb); /* cmvd atom */ | 1397 get_be32(pb); /* cmvd atom */ |
1386 if (get_le32(pb) != MKTAG( 'c', 'm', 'v', 'd' )) | 1398 if (get_le32(pb) != MKTAG( 'c', 'm', 'v', 'd' )) |
1387 return -1; | 1399 return -1; |
1413 av_free(cmov_data); | 1425 av_free(cmov_data); |
1414 | 1426 |
1415 return ret; | 1427 return ret; |
1416 } | 1428 } |
1417 #endif | 1429 #endif |
1430 | |
1431 /* edit list atom */ | |
1432 static int mov_read_elst(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) | |
1433 { | |
1434 print_atom("elst", atom); | |
1435 | |
1436 get_byte(pb); /* version */ | |
1437 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ | |
1438 c->streams[c->fc->nb_streams-1]->edit_count = get_be32(pb); /* entries */ | |
1439 #ifdef DEBUG | |
1440 av_log(NULL, AV_LOG_DEBUG, "track[%i].edit_count = %i\n", c->fc->nb_streams-1, c->streams[c->fc->nb_streams-1]->edit_count); | |
1441 #endif | |
1442 return 0; | |
1443 } | |
1418 | 1444 |
1419 static const MOVParseTableEntry mov_default_parse_table[] = { | 1445 static const MOVParseTableEntry mov_default_parse_table[] = { |
1420 /* mp4 atoms */ | 1446 /* mp4 atoms */ |
1421 { MKTAG( 'c', 'o', '6', '4' ), mov_read_stco }, | 1447 { MKTAG( 'c', 'o', '6', '4' ), mov_read_stco }, |
1422 { MKTAG( 'c', 'p', 'r', 't' ), mov_read_default }, | 1448 { MKTAG( 'c', 'p', 'r', 't' ), mov_read_default }, |
1424 { MKTAG( 'c', 't', 't', 's' ), mov_read_leaf }, /* composition time to sample */ | 1450 { MKTAG( 'c', 't', 't', 's' ), mov_read_leaf }, /* composition time to sample */ |
1425 { MKTAG( 'd', 'i', 'n', 'f' ), mov_read_default }, /* data information */ | 1451 { MKTAG( 'd', 'i', 'n', 'f' ), mov_read_default }, /* data information */ |
1426 { MKTAG( 'd', 'p', 'n', 'd' ), mov_read_leaf }, | 1452 { MKTAG( 'd', 'p', 'n', 'd' ), mov_read_leaf }, |
1427 { MKTAG( 'd', 'r', 'e', 'f' ), mov_read_leaf }, | 1453 { MKTAG( 'd', 'r', 'e', 'f' ), mov_read_leaf }, |
1428 { MKTAG( 'e', 'd', 't', 's' ), mov_read_default }, | 1454 { MKTAG( 'e', 'd', 't', 's' ), mov_read_default }, |
1429 { MKTAG( 'e', 'l', 's', 't' ), mov_read_leaf }, | 1455 { MKTAG( 'e', 'l', 's', 't' ), mov_read_elst }, |
1430 { MKTAG( 'f', 'r', 'e', 'e' ), mov_read_leaf }, | 1456 { MKTAG( 'f', 'r', 'e', 'e' ), mov_read_leaf }, |
1431 { MKTAG( 'h', 'd', 'l', 'r' ), mov_read_hdlr }, | 1457 { MKTAG( 'h', 'd', 'l', 'r' ), mov_read_hdlr }, |
1432 { MKTAG( 'h', 'i', 'n', 't' ), mov_read_leaf }, | 1458 { MKTAG( 'h', 'i', 'n', 't' ), mov_read_leaf }, |
1433 { MKTAG( 'h', 'm', 'h', 'd' ), mov_read_leaf }, | 1459 { MKTAG( 'h', 'm', 'h', 'd' ), mov_read_leaf }, |
1434 { MKTAG( 'i', 'o', 'd', 's' ), mov_read_leaf }, | 1460 { MKTAG( 'i', 'o', 'd', 's' ), mov_read_leaf }, |
1500 av_free(sc->chunk_offsets); | 1526 av_free(sc->chunk_offsets); |
1501 av_free(sc->sample_to_chunk); | 1527 av_free(sc->sample_to_chunk); |
1502 av_free(sc->sample_sizes); | 1528 av_free(sc->sample_sizes); |
1503 av_free(sc->keyframes); | 1529 av_free(sc->keyframes); |
1504 av_free(sc->header_data); | 1530 av_free(sc->header_data); |
1531 av_free(sc->stts_data); | |
1505 av_free(sc); | 1532 av_free(sc); |
1506 } | 1533 } |
1507 } | 1534 } |
1508 | 1535 |
1509 static inline uint32_t mov_to_tag(uint8_t *buf) | 1536 static inline uint32_t mov_to_tag(uint8_t *buf) |
1569 atom.size = url_filesize(url_fileno(pb)); | 1596 atom.size = url_filesize(url_fileno(pb)); |
1570 else | 1597 else |
1571 atom.size = 0x7FFFFFFFFFFFFFFFLL; | 1598 atom.size = 0x7FFFFFFFFFFFFFFFLL; |
1572 | 1599 |
1573 #ifdef DEBUG | 1600 #ifdef DEBUG |
1574 printf("filesz=%Ld\n", atom.size); | 1601 av_log(NULL, AV_LOG_DEBUG, "filesz=%Ld\n", atom.size); |
1575 #endif | 1602 #endif |
1576 | 1603 |
1577 /* check MOV header */ | 1604 /* check MOV header */ |
1578 err = mov_read_default(mov, pb, atom); | 1605 err = mov_read_default(mov, pb, atom); |
1579 if (err<0 || (!mov->found_moov && !mov->found_mdat)) { | 1606 if (err<0 || (!mov->found_moov && !mov->found_mdat)) { |
1580 av_log(s, AV_LOG_ERROR, "mov: header not found !!! (err:%d, moov:%d, mdat:%d) pos:%lld\n", | 1607 av_log(s, AV_LOG_ERROR, "mov: header not found !!! (err:%d, moov:%d, mdat:%d) pos:%lld\n", |
1581 err, mov->found_moov, mov->found_mdat, url_ftell(pb)); | 1608 err, mov->found_moov, mov->found_mdat, url_ftell(pb)); |
1582 return -1; | 1609 return -1; |
1583 } | 1610 } |
1584 #ifdef DEBUG | 1611 #ifdef DEBUG |
1585 printf("on_parse_exit_offset=%d\n", (int) url_ftell(pb)); | 1612 av_log(NULL, AV_LOG_DEBUG, "on_parse_exit_offset=%d\n", (int) url_ftell(pb)); |
1586 #endif | 1613 #endif |
1587 /* some cleanup : make sure we are on the mdat atom */ | 1614 /* some cleanup : make sure we are on the mdat atom */ |
1588 if(!url_is_streamed(pb) && (url_ftell(pb) != mov->mdat_offset)) | 1615 if(!url_is_streamed(pb) && (url_ftell(pb) != mov->mdat_offset)) |
1589 url_fseek(pb, mov->mdat_offset, SEEK_SET); | 1616 url_fseek(pb, mov->mdat_offset, SEEK_SET); |
1590 | 1617 |
1591 mov->next_chunk_offset = mov->mdat_offset; /* initialise reading */ | 1618 mov->next_chunk_offset = mov->mdat_offset; /* initialise reading */ |
1592 | 1619 |
1593 #ifdef DEBUG | 1620 #ifdef DEBUG |
1594 printf("mdat_reset_offset=%d\n", (int) url_ftell(pb)); | 1621 av_log(NULL, AV_LOG_DEBUG, "mdat_reset_offset=%d\n", (int) url_ftell(pb)); |
1595 #endif | 1622 #endif |
1596 | 1623 |
1597 #ifdef DEBUG | 1624 #ifdef DEBUG |
1598 printf("streams= %d\n", s->nb_streams); | 1625 av_log(NULL, AV_LOG_DEBUG, "streams= %d\n", s->nb_streams); |
1599 #endif | 1626 #endif |
1600 mov->total_streams = nb = s->nb_streams; | 1627 mov->total_streams = nb = s->nb_streams; |
1601 | 1628 |
1602 #if 1 | 1629 #if 1 |
1603 for(i=0; i<s->nb_streams;) { | 1630 for(i=0; i<s->nb_streams;) { |
1615 sc->ffindex = i; | 1642 sc->ffindex = i; |
1616 sc->is_ff_stream = 1; | 1643 sc->is_ff_stream = 1; |
1617 } | 1644 } |
1618 #endif | 1645 #endif |
1619 #ifdef DEBUG | 1646 #ifdef DEBUG |
1620 printf("real streams= %d\n", s->nb_streams); | 1647 av_log(NULL, AV_LOG_DEBUG, "real streams= %d\n", s->nb_streams); |
1621 #endif | 1648 #endif |
1622 return 0; | 1649 return 0; |
1623 } | 1650 } |
1624 | 1651 |
1625 /* Yes, this is ugly... I didn't write the specs of QT :p */ | 1652 /* Yes, this is ugly... I didn't write the specs of QT :p */ |
1658 | 1685 |
1659 again: | 1686 again: |
1660 sc = 0; | 1687 sc = 0; |
1661 for(i=0; i<mov->total_streams; i++) { | 1688 for(i=0; i<mov->total_streams; i++) { |
1662 MOVStreamContext *msc = mov->streams[i]; | 1689 MOVStreamContext *msc = mov->streams[i]; |
1663 //printf("MOCHUNK %ld %d %p pos:%Ld\n", mov->streams[i]->next_chunk, mov->total_streams, mov->streams[i], url_ftell(&s->pb)); | 1690 //av_log(NULL, AV_LOG_DEBUG, "MOCHUNK %ld %d %p pos:%Ld\n", mov->streams[i]->next_chunk, mov->total_streams, mov->streams[i], url_ftell(&s->pb)); |
1664 if ((msc->next_chunk < msc->chunk_count) && msc->next_chunk >= 0 | 1691 if ((msc->next_chunk < msc->chunk_count) && msc->next_chunk >= 0 |
1665 && (msc->chunk_offsets[msc->next_chunk] < offset)) { | 1692 && (msc->chunk_offsets[msc->next_chunk] < offset)) { |
1666 sc = msc; | 1693 sc = msc; |
1667 offset = msc->chunk_offsets[msc->next_chunk]; | 1694 offset = msc->chunk_offsets[msc->next_chunk]; |
1668 //printf("SELETED %Ld i:%d\n", offset, i); | 1695 //av_log(NULL, AV_LOG_DEBUG, "SELETED %Ld i:%d\n", offset, i); |
1669 } | 1696 } |
1670 } | 1697 } |
1671 if (!sc || offset==0x0FFFFFFFFFFFFFFFLL) | 1698 if (!sc || offset==0x0FFFFFFFFFFFFFFFLL) |
1672 return -1; | 1699 return -1; |
1673 | 1700 |
1676 if(mov->next_chunk_offset < offset) { /* some meta data */ | 1703 if(mov->next_chunk_offset < offset) { /* some meta data */ |
1677 url_fskip(&s->pb, (offset - mov->next_chunk_offset)); | 1704 url_fskip(&s->pb, (offset - mov->next_chunk_offset)); |
1678 mov->next_chunk_offset = offset; | 1705 mov->next_chunk_offset = offset; |
1679 } | 1706 } |
1680 | 1707 |
1681 //printf("chunk: [%i] %lli -> %lli\n", st_id, mov->next_chunk_offset, offset); | 1708 //av_log(NULL, AV_LOG_DEBUG, "chunk: [%i] %lli -> %lli\n", st_id, mov->next_chunk_offset, offset); |
1682 if(!sc->is_ff_stream) { | 1709 if(!sc->is_ff_stream) { |
1683 url_fskip(&s->pb, (offset - mov->next_chunk_offset)); | 1710 url_fskip(&s->pb, (offset - mov->next_chunk_offset)); |
1684 mov->next_chunk_offset = offset; | 1711 mov->next_chunk_offset = offset; |
1685 offset = 0x0FFFFFFFFFFFFFFFLL; | 1712 offset = 0x0FFFFFFFFFFFFFFFLL; |
1686 goto again; | 1713 goto again; |
1712 foundsize=(sc->sample_to_chunk[i].count*cod->channels*cod->bits_per_sample)/8; | 1739 foundsize=(sc->sample_to_chunk[i].count*cod->channels*cod->bits_per_sample)/8; |
1713 else | 1740 else |
1714 foundsize=sc->sample_to_chunk[i].count*sc->sample_size; | 1741 foundsize=sc->sample_to_chunk[i].count*sc->sample_size; |
1715 } | 1742 } |
1716 #ifdef DEBUG | 1743 #ifdef DEBUG |
1717 /*printf("sample_to_chunk first=%ld count=%ld, id=%ld\n", sc->sample_to_chunk[i].first, sc->sample_to_chunk[i].count, sc->sample_to_chunk[i].id);*/ | 1744 /*av_log(NULL, AV_LOG_DEBUG, "sample_to_chunk first=%ld count=%ld, id=%ld\n", sc->sample_to_chunk[i].first, sc->sample_to_chunk[i].count, sc->sample_to_chunk[i].id);*/ |
1718 #endif | 1745 #endif |
1719 } | 1746 } |
1720 if( (foundsize>0) && (foundsize<size) ) | 1747 if( (foundsize>0) && (foundsize<size) ) |
1721 { | 1748 { |
1722 #ifdef DEBUG | 1749 #ifdef DEBUG |
1723 /*printf("this size should actually be %d\n",foundsize);*/ | 1750 /*av_log(NULL, AV_LOG_DEBUG, "this size should actually be %d\n",foundsize);*/ |
1724 #endif | 1751 #endif |
1725 size=foundsize; | 1752 size=foundsize; |
1726 } | 1753 } |
1727 } | 1754 } |
1728 #endif //MOV_MINOLTA_FIX | 1755 #endif //MOV_MINOLTA_FIX |
1745 sc->current_sample++; | 1772 sc->current_sample++; |
1746 } | 1773 } |
1747 #endif | 1774 #endif |
1748 | 1775 |
1749 readchunk: | 1776 readchunk: |
1750 //printf("chunk: [%i] %lli -> %lli (%i)\n", st_id, offset, offset + size, size); | 1777 //av_log(NULL, AV_LOG_DEBUG, "chunk: [%i] %lli -> %lli (%i)\n", st_id, offset, offset + size, size); |
1751 if(size == 0x0FFFFFFF) | 1778 if(size == 0x0FFFFFFF) |
1752 size = mov->mdat_size + mov->mdat_offset - offset; | 1779 size = mov->mdat_size + mov->mdat_offset - offset; |
1753 if(size < 0) | 1780 if(size < 0) |
1754 return -1; | 1781 return -1; |
1755 if(size == 0) | 1782 if(size == 0) |
1756 return -1; | 1783 return -1; |
1757 url_fseek(&s->pb, offset, SEEK_SET); | 1784 url_fseek(&s->pb, offset, SEEK_SET); |
1758 | 1785 |
1759 //printf("READCHUNK hlen: %d %d off: %Ld pos:%Ld\n", size, sc->header_len, offset, url_ftell(&s->pb)); | 1786 //av_log(NULL, AV_LOG_DEBUG, "READCHUNK hlen: %d %d off: %Ld pos:%Ld\n", size, sc->header_len, offset, url_ftell(&s->pb)); |
1760 if (sc->header_len > 0) { | 1787 if (sc->header_len > 0) { |
1761 av_new_packet(pkt, size + sc->header_len); | 1788 av_new_packet(pkt, size + sc->header_len); |
1762 memcpy(pkt->data, sc->header_data, sc->header_len); | 1789 memcpy(pkt->data, sc->header_data, sc->header_len); |
1763 get_buffer(&s->pb, pkt->data + sc->header_len, size); | 1790 get_buffer(&s->pb, pkt->data + sc->header_len, size); |
1764 /* free header */ | 1791 /* free header */ |
1791 else | 1818 else |
1792 pkt->flags |= PKT_FLAG_KEY; | 1819 pkt->flags |= PKT_FLAG_KEY; |
1793 | 1820 |
1794 #ifdef DEBUG | 1821 #ifdef DEBUG |
1795 /* | 1822 /* |
1796 printf("Packet (%d, %d, %ld) ", pkt->stream_index, st_id, pkt->size); | 1823 av_log(NULL, AV_LOG_DEBUG, "Packet (%d, %d, %ld) ", pkt->stream_index, st_id, pkt->size); |
1797 for(i=0; i<8; i++) | 1824 for(i=0; i<8; i++) |
1798 printf("%02x ", pkt->data[i]); | 1825 av_log(NULL, AV_LOG_DEBUG, "%02x ", pkt->data[i]); |
1799 for(i=0; i<8; i++) | 1826 for(i=0; i<8; i++) |
1800 printf("%c ", (pkt->data[i]) & 0x7F); | 1827 av_log(NULL, AV_LOG_DEBUG, "%c ", (pkt->data[i]) & 0x7F); |
1801 puts(""); | 1828 puts(""); |
1802 */ | 1829 */ |
1803 #endif | 1830 #endif |
1804 | 1831 |
1805 mov->next_chunk_offset = offset + size; | 1832 mov->next_chunk_offset = offset + size; |
1806 | 1833 |
1807 return 0; | 1834 return 0; |
1808 } | 1835 } |
1836 | |
1837 #if defined(MOV_SPLIT_CHUNKS) && defined(MOV_SEEK) | |
1838 /** | |
1839 * Seek method based on the one described in the Appendix C of QTFileFormat.pdf | |
1840 */ | |
1841 static int mov_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp) | |
1842 { | |
1843 MOVContext* mov = (MOVContext *) s->priv_data; | |
1844 MOVStreamContext* sc; | |
1845 int32_t i, a, b, m; | |
1846 int64_t sample_time; | |
1847 int64_t start_time; | |
1848 int32_t seek_sample, sample; | |
1849 int32_t duration; | |
1850 int32_t count; | |
1851 int32_t chunk; | |
1852 int32_t left_in_chunk; | |
1853 int64_t chunk_file_offset; | |
1854 int64_t sample_file_offset; | |
1855 int32_t first_chunk_sample; | |
1856 int32_t sample_to_chunk_idx; | |
1857 int mov_idx; | |
1858 | |
1859 // Find the corresponding mov stream | |
1860 for (mov_idx = 0; mov_idx < mov->total_streams; mov_idx++) | |
1861 if (mov->streams[mov_idx]->ffindex == stream_index) | |
1862 break; | |
1863 if (mov_idx == mov->total_streams) { | |
1864 av_log(s, AV_LOG_ERROR, "mov: requested stream was not found in mov streams (idx=%i)\n", stream_index); | |
1865 return -1; | |
1866 } | |
1867 sc = mov->streams[mov_idx]; | |
1868 | |
1869 // Step 1. Find the edit that contains the requested time (elst) | |
1870 if (sc->edit_count) { | |
1871 // FIXME should handle edit list | |
1872 av_log(s, AV_LOG_ERROR, "mov: does not handle seeking in files that contain edit list (c:%d)\n", sc->edit_count); | |
1873 return -1; | |
1874 } | |
1875 | |
1876 // Step 2. Find the corresponding sample using the Time-to-sample atom (stts) */ | |
1877 #ifdef DEBUG | |
1878 av_log(s, AV_LOG_DEBUG, "Searching for time %li in stream #%i (time_scale=%i)\n", (long)timestamp, mov_idx, sc->time_scale); | |
1879 #endif | |
1880 // convert timestamp from time_base unit to timescale unit | |
1881 sample_time = av_rescale( timestamp, | |
1882 (int64_t)sc->time_scale * s->streams[stream_index]->time_base.num, | |
1883 (int64_t)s->streams[stream_index]->time_base.den); | |
1884 start_time = 0; // FIXME use elst atom | |
1885 sample = 1; // sample are 0 based in table | |
1886 #ifdef DEBUG | |
1887 av_log(s, AV_LOG_DEBUG, "Searching for sample_time %li \n", (long)sample_time); | |
1888 #endif | |
1889 for (i = 0; i < sc->stts_count; i++) { | |
1890 count = (uint32_t)(sc->stts_data[i]>>32); | |
1891 duration = (uint32_t)(sc->stts_data[i]&0xffff); | |
1892 //av_log(s, AV_LOG_DEBUG, "> sample_time %lli \n", (long)sample_time); | |
1893 //av_log(s, AV_LOG_DEBUG, "> count=%i duration=%i\n", count, duration); | |
1894 if ((start_time + count*duration) > sample_time) { | |
1895 sample += (sample_time - start_time) / duration; | |
1896 break; | |
1897 } | |
1898 sample += count; | |
1899 start_time += count * duration; | |
1900 } | |
1901 /* NOTE: despite what qt doc say, the dt value (Display Time in qt vocabulary) computed with the stts atom | |
1902 is a decoding time stamp (dts) not a presentation time stamp. And as usual dts != pts for stream with b frames */ | |
1903 | |
1904 #ifdef DEBUG | |
1905 av_log(s, AV_LOG_DEBUG, "Found time %li at sample #%u\n", (long)sample_time, sample); | |
1906 #endif | |
1907 if (sample > sc->sample_count) { | |
1908 av_log(s, AV_LOG_ERROR, "mov: sample pos is too high, unable to seek (req. sample=%i, sample count=%ld)\n", sample, sc->sample_count); | |
1909 return -1; | |
1910 } | |
1911 | |
1912 // Step 3. Find the prior sync. sample using the Sync sample atom (stss) | |
1913 if (sc->keyframes) { | |
1914 a = 0; | |
1915 b = sc->keyframe_count - 1; | |
1916 while (a < b) { | |
1917 m = (a + b + 1) >> 1; | |
1918 if (sc->keyframes[m] > sample) { | |
1919 b = m - 1; | |
1920 } else { | |
1921 a = m; | |
1922 } | |
1923 #ifdef DEBUG | |
1924 // av_log(s, AV_LOG_DEBUG, "a=%i (%i) b=%i (%i) m=%i (%i) stream #%i\n", a, sc->keyframes[a], b, sc->keyframes[b], m, sc->keyframes[m], mov_idx); | |
1925 #endif | |
1926 } | |
1927 seek_sample = sc->keyframes[a]; | |
1928 } | |
1929 else | |
1930 seek_sample = sample; // else all samples are key frames | |
1931 #ifdef DEBUG | |
1932 av_log(s, AV_LOG_DEBUG, "Found nearest keyframe at sample #%i \n", seek_sample); | |
1933 #endif | |
1934 | |
1935 // Step 4. Find the chunk of the sample using the Sample-to-chunk-atom (stsc) | |
1936 for (first_chunk_sample = 1, i = 0; i < (sc->sample_to_chunk_sz - 1); i++) { | |
1937 b = (sc->sample_to_chunk[i + 1].first - sc->sample_to_chunk[i].first) * sc->sample_to_chunk[i].count; | |
1938 if (seek_sample >= first_chunk_sample && seek_sample < (first_chunk_sample + b)) | |
1939 break; | |
1940 first_chunk_sample += b; | |
1941 } | |
1942 chunk = sc->sample_to_chunk[i].first + (seek_sample - first_chunk_sample) / sc->sample_to_chunk[i].count; | |
1943 left_in_chunk = sc->sample_to_chunk[i].count - (seek_sample - first_chunk_sample) % sc->sample_to_chunk[i].count; | |
1944 first_chunk_sample += ((seek_sample - first_chunk_sample) / sc->sample_to_chunk[i].count) * sc->sample_to_chunk[i].count; | |
1945 sample_to_chunk_idx = i; | |
1946 #ifdef DEBUG | |
1947 av_log(s, AV_LOG_DEBUG, "Sample was found in chunk #%i at sample offset %i (idx %i)\n", chunk, seek_sample - first_chunk_sample, sample_to_chunk_idx); | |
1948 #endif | |
1949 | |
1950 // Step 5. Find the offset of the chunk using the chunk offset atom | |
1951 if (!sc->chunk_offsets) { | |
1952 av_log(s, AV_LOG_ERROR, "mov: no chunk offset atom, unable to seek\n"); | |
1953 return -1; | |
1954 } | |
1955 if (chunk > sc->chunk_count) { | |
1956 av_log(s, AV_LOG_ERROR, "mov: chunk offset atom too short, unable to seek (req. chunk=%i, chunk count=%li)\n", chunk, sc->chunk_count); | |
1957 return -1; | |
1958 } | |
1959 chunk_file_offset = sc->chunk_offsets[chunk - 1]; | |
1960 #ifdef DEBUG | |
1961 av_log(s, AV_LOG_DEBUG, "Chunk file offset is #%llu \n", chunk_file_offset); | |
1962 #endif | |
1963 | |
1964 // Step 6. Find the byte offset within the chunk using the sample size atom | |
1965 sample_file_offset = chunk_file_offset; | |
1966 if (sc->sample_size) | |
1967 sample_file_offset += (seek_sample - first_chunk_sample) * sc->sample_size; | |
1968 else { | |
1969 for (i = 0; i < (seek_sample - first_chunk_sample); i++) { | |
1970 sample_file_offset += sc->sample_sizes[first_chunk_sample + i - 1]; | |
1971 } | |
1972 } | |
1973 #ifdef DEBUG | |
1974 av_log(s, AV_LOG_DEBUG, "Sample file offset is #%llu \n", sample_file_offset); | |
1975 #endif | |
1976 | |
1977 // Step 6. Update the parser | |
1978 mov->partial = sc; | |
1979 mov->next_chunk_offset = sample_file_offset; | |
1980 // Update current stream state | |
1981 sc->current_sample = seek_sample - 1; // zero based | |
1982 sc->left_in_chunk = left_in_chunk; | |
1983 sc->next_chunk = chunk; // +1 -1 (zero based) | |
1984 sc->sample_to_chunk_index = sample_to_chunk_idx; | |
1985 | |
1986 // Update other streams | |
1987 for (i = 0; i<mov->total_streams; i++) { | |
1988 if (i == mov_idx) continue; | |
1989 // Find the nearest 'next' chunk | |
1990 MOVStreamContext *msc = mov->streams[i]; | |
1991 a = 0; | |
1992 b = msc->chunk_count - 1; | |
1993 while (a < b) { | |
1994 m = (a + b + 1) >> 1; | |
1995 if (msc->chunk_offsets[m] > chunk_file_offset) { | |
1996 b = m - 1; | |
1997 } else { | |
1998 a = m; | |
1999 } | |
2000 #ifdef DEBUG | |
2001 /* av_log(s, AV_LOG_DEBUG, "a=%i (%li) b=%i (%li) m=%i (%li) stream #%i\n" | |
2002 , a, (long)msc->chunk_offsets[a], b, (long)msc->chunk_offsets[b], m, (long)msc->chunk_offsets[m], i); */ | |
2003 #endif | |
2004 } | |
2005 msc->next_chunk = a; | |
2006 if (msc->chunk_offsets[a] < chunk_file_offset && a < (msc->chunk_count-1)) | |
2007 msc->next_chunk ++; | |
2008 #ifdef DEBUG | |
2009 av_log(s, AV_LOG_DEBUG, "Nearest next chunk for stream #%i is #%i @%lli\n", i, msc->next_chunk+1, msc->chunk_offsets[msc->next_chunk]); | |
2010 #endif | |
2011 // Compute sample count and index in the sample_to_chunk table (what a pity) | |
2012 msc->sample_to_chunk_index = 0; | |
2013 msc->current_sample = 0; | |
2014 for(; msc->sample_to_chunk_index < (msc->sample_to_chunk_sz - 1) | |
2015 && msc->sample_to_chunk[msc->sample_to_chunk_index + 1].first <= (1 + msc->next_chunk); msc->sample_to_chunk_index++) { | |
2016 msc->current_sample += (msc->sample_to_chunk[msc->sample_to_chunk_index + 1].first - msc->sample_to_chunk[msc->sample_to_chunk_index].first) \ | |
2017 * msc->sample_to_chunk[msc->sample_to_chunk_index].count; | |
2018 } | |
2019 msc->current_sample += (msc->next_chunk - (msc->sample_to_chunk[msc->sample_to_chunk_index].first - 1)) * sc->sample_to_chunk[msc->sample_to_chunk_index].count; | |
2020 msc->left_in_chunk = msc->sample_to_chunk[msc->sample_to_chunk_index].count - 1; | |
2021 #ifdef DEBUG | |
2022 av_log(s, AV_LOG_DEBUG, "Next Sample for stream #%i is #%i @%i\n", i, msc->current_sample + 1, msc->sample_to_chunk_index + 1); | |
2023 #endif | |
2024 } | |
2025 return 0; | |
2026 } | |
2027 #endif | |
1809 | 2028 |
1810 static int mov_read_close(AVFormatContext *s) | 2029 static int mov_read_close(AVFormatContext *s) |
1811 { | 2030 { |
1812 int i; | 2031 int i; |
1813 MOVContext *mov = (MOVContext *) s->priv_data; | 2032 MOVContext *mov = (MOVContext *) s->priv_data; |
1826 sizeof(MOVContext), | 2045 sizeof(MOVContext), |
1827 mov_probe, | 2046 mov_probe, |
1828 mov_read_header, | 2047 mov_read_header, |
1829 mov_read_packet, | 2048 mov_read_packet, |
1830 mov_read_close, | 2049 mov_read_close, |
2050 #if defined(MOV_SPLIT_CHUNKS) && defined(MOV_SEEK) | |
2051 mov_read_seek, | |
2052 #endif | |
1831 }; | 2053 }; |
1832 | 2054 |
1833 int mov_init(void) | 2055 int mov_init(void) |
1834 { | 2056 { |
1835 av_register_input_format(&mov_iformat); | 2057 av_register_input_format(&mov_iformat); |