diff --git a/libavformat/mov.c b/libavformat/mov.c index f24a22b052..72f03d4fd4 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -59,6 +59,10 @@ /* in case you can't read a file, try commenting */ #define MOV_SPLIT_CHUNKS +/* Special handling for movies created with Minolta Dimaxe Xi*/ +/* this fix should not interfere with other .mov files, but just in case*/ +#define MOV_MINOLTA_FIX + /* some streams in QT (and in MP4 mostly) aren't either video nor audio */ /* so we first list them as this, then clean up the list of streams we give back, */ /* getting rid of these */ @@ -768,9 +772,10 @@ static int mov_read_stsd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) st->codec.bits_per_sample = get_be16(pb); /* depth */ st->codec.color_table_id = get_be16(pb); /* colortable id */ +/* These are set in mov_read_stts and might already be set! st->codec.frame_rate = 25; st->codec.frame_rate_base = 1; - +*/ size -= (16+8*4+2+32+2*2); #if 0 while (size >= 8) { @@ -878,7 +883,7 @@ static int mov_read_stsd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) get_byte(pb); //frames_per_sample #ifdef DEBUG - printf("Audio: damr_type=%c%c%c%c damr_size=%Ld damr_vendor=%c%c%c%c\n", + printf("Audio: damr_type=%c%c%c%c damr_size=%d damr_vendor=%c%c%c%c\n", (damr_type >> 24) & 0xff, (damr_type >> 16) & 0xff, (damr_type >> 8) & 0xff, @@ -890,7 +895,7 @@ static int mov_read_stsd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) (damr_vendor >> 0) & 0xff ); #endif - + st->time_length=0;//Not possible to get from this info, must count number of AMR frames st->codec.sample_rate=8000; st->codec.channels=1; @@ -898,9 +903,20 @@ static int mov_read_stsd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) st->codec.bit_rate=0; /*It is not possible to tell this before we have an audio frame and even then every frame can be different*/ } - else - { - get_be16(pb); /* version */ + else if( st->codec.codec_tag == MKTAG( 'm', 'p', '4', 's' )) + { + //This is some stuff for the hint track, lets ignore it! + //Do some mp4 auto detect. + c->mp4=1; + size-=(16); + url_fskip(pb, size); /* The mp4s atom also contians a esds atom that we can skip*/ + } + else if(size>=(16+20)) + {//16 bytes read, reading atleast 20 more +#ifdef DEBUG + printf("audio size=0x%X\n",size); +#endif + uint16_t version = get_be16(pb); /* version */ get_be16(pb); /* revision level */ get_be32(pb); /* vendor */ @@ -925,14 +941,51 @@ static int mov_read_stsd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) default: ; } - get_be32(pb); /* samples per packet */ - get_be32(pb); /* bytes per packet */ - get_be32(pb); /* bytes per frame */ - get_be32(pb); /* bytes per sample */ - { - MOV_atom_t a = { format, url_ftell(pb), size - (16 + 20 + 16 + 8) }; - mov_read_default(c, pb, a); - } + + //Read QT version 1 fields. In version 0 theese dont exist +#ifdef DEBUG + printf("version =%d mp4=%d\n",version,c->mp4); + printf("size-(16+20+16)=%d\n",size-(16+20+16)); +#endif + if((version==1) && size>=(16+20+16)) + { + get_be32(pb); /* samples per packet */ + get_be32(pb); /* bytes per packet */ + get_be32(pb); /* bytes per frame */ + get_be32(pb); /* bytes per sample */ + if(size>(16+20+16)) + { + //Optional, additional atom-based fields +#ifdef DEBUG + 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 ), + (format >> 0) & 0xff, + (format >> 8) & 0xff, + (format >> 16) & 0xff, + (format >> 24) & 0xff); +#endif + MOV_atom_t a = { format, url_ftell(pb), size - (16 + 20 + 16 + 8) }; + mov_read_default(c, pb, a); + } + } + else + { + //We should be down to 0 bytes here, but lets make sure. + size-=(16+20); +#ifdef DEBUG + if(size>0) + printf("skipping 0x%X bytes\n",size-(16+20)); +#endif + url_fskip(pb, size); + } + } + else + { + size-=16; + //Unknown size, but lets do our best and skip the rest. +#ifdef DEBUG + printf("Strange size, skipping 0x%X bytes\n",size); +#endif + url_fskip(pb, size); } } } @@ -1043,16 +1096,43 @@ printf("track[%i].stts.entries = %i\n", c->fc->nb_streams-1, entries); #endif } - if(st->codec.codec_type==CODEC_TYPE_VIDEO) +#define MAX(a,b) a>b?a:b +#define MIN(a,b) a>b?b:a + /*The stsd atom which contain codec type sometimes comes after the stts so we cannot check for codec_type*/ + if(duration>0) { + //Find greatest common divisor to avoid overflow using the Euclidean Algorithm... + uint32_t max=MAX(duration,total_sample_count); + uint32_t min=MIN(duration,total_sample_count); + uint32_t spare=max%min; + + while(spare!=0) + { + max=min; + min=spare; + spare=max%min; + } + + duration/=min; + total_sample_count/=min; + //Only support constant frame rate. But lets calculate the average. Needed by .mp4-files created with nec e606 3g phone. - //Hmm, lets set base to 1 - st->codec.frame_rate_base=1; - st->codec.frame_rate = st->codec.frame_rate_base * c->streams[c->total_streams]->time_scale * total_sample_count / duration; + //To get better precision, we use the duration as frame_rate_base + + st->codec.frame_rate_base=duration; + st->codec.frame_rate = c->streams[c->total_streams]->time_scale * total_sample_count; + #ifdef DEBUG - printf("VIDEO FRAME RATE average= %i (tot sample count= %i ,tot dur= %i)\n", st->codec.frame_rate,total_sample_count,duration); + 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); #endif } + else + { + st->codec.frame_rate_base = 1; + st->codec.frame_rate = c->streams[c->total_streams]->time_scale; + } +#undef MAX +#undef MIN return 0; } @@ -1334,7 +1414,7 @@ static int mov_probe(AVProbeData *p) return AVPROBE_SCORE_MAX; case MKTAG( 'f', 't', 'y', 'p' ): case MKTAG( 's', 'k', 'i', 'p' ): - offset = to_be32(p->buf) + offset; + offset = to_be32(p->buf+offset) + offset; break; default: /* unrecognized tag */