From de23f234dfb79fdc2281a765430aef89e6974d4f Mon Sep 17 00:00:00 2001 From: Baptiste Coudurier Date: Sun, 19 Feb 2006 20:00:00 +0000 Subject: Cleans reading stsd audio, and makes it more generic patch by (Baptiste COUDURIER ) Originally committed as revision 5038 to svn://svn.ffmpeg.org/ffmpeg/trunk --- libavformat/mov.c | 279 ++++++++++++++++++++---------------------------------- 1 file changed, 101 insertions(+), 178 deletions(-) (limited to 'libavformat/mov.c') diff --git a/libavformat/mov.c b/libavformat/mov.c index 36084e53c6..94ee0d9b57 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -744,8 +744,49 @@ static int mov_read_smi(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) return 0; } +static int mov_read_enda(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) +{ + AVStream *st = c->fc->streams[c->fc->nb_streams-1]; + int little_endian = get_be16(pb); + + if (little_endian) { + switch (st->codec->codec_id) { + case CODEC_ID_PCM_S24BE: + st->codec->codec_id = CODEC_ID_PCM_S24LE; + break; + case CODEC_ID_PCM_S32BE: + st->codec->codec_id = CODEC_ID_PCM_S32LE; + break; + default: + break; + } + } + return 0; +} + +static int mov_read_alac(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) +{ + AVStream *st = c->fc->streams[c->fc->nb_streams-1]; + + // currently ALAC decoder expect full atom header - so let's fake it + // this should be fixed and just ALAC header should be passed + + av_free(st->codec->extradata); + st->codec->extradata_size = 36; + st->codec->extradata = (uint8_t*) av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); + + if (st->codec->extradata) { + strcpy(st->codec->extradata + 4, "alac"); // fake + get_buffer(pb, st->codec->extradata + 8, 36 - 8); + dprintf("Reading alac %Ld %s\n", st->codec->extradata_size, (char*)st->codec->extradata); + } else + url_fskip(pb, atom.size); + return 0; +} + static int mov_read_wave(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) { + offset_t start_pos = url_ftell(pb); AVStream *st = c->fc->streams[c->fc->nb_streams-1]; if((uint64_t)atom.size > (1<<30)) @@ -765,6 +806,8 @@ static int mov_read_wave(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) mov_read_default(c, pb, atom); } else if (atom.size > 0) url_fskip(pb, atom.size); + /* in any case, skip garbage */ + url_fskip(pb, atom.size - ((url_ftell(pb) - start_pos))); return 0; } @@ -856,6 +899,7 @@ static int mov_read_stsd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) while(entries--) { //Parsing Sample description table enum CodecID id; + MOV_atom_t a = { 0, 0, 0 }; offset_t start_pos = url_ftell(pb); int size = get_be32(pb); /* size */ format = get_le32(pb); /* data format */ @@ -864,23 +908,17 @@ static int mov_read_stsd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) get_be16(pb); /* reserved */ get_be16(pb); /* index */ - /* for MPEG4: set codec type by looking for it */ - id = codec_get_id(mov_video_tags, format); - if(id <= 0) - id = codec_get_id(codec_bmp_tags, format); - if (id >= 0) { - AVCodec *codec; - codec = avcodec_find_decoder(id); - if (codec) - st->codec->codec_type = codec->type; - } dprintf("size=%d 4CC= %c%c%c%c codec_type=%d\n", size, (format >> 0) & 0xff, (format >> 8) & 0xff, (format >> 16) & 0xff, (format >> 24) & 0xff, st->codec->codec_type); st->codec->codec_tag = format; + /* codec_type is set earlier by read_hdlr */ if(st->codec->codec_type==CODEC_TYPE_VIDEO) { - MOV_atom_t a = { 0, 0, 0 }; + /* for MPEG4: set codec type by looking for it */ + id = codec_get_id(mov_video_tags, format); + if(id <= 0) + id = codec_get_id(codec_bmp_tags, format); st->codec->codec_id = id; get_be16(pb); /* version */ get_be16(pb); /* revision level */ @@ -984,180 +1022,63 @@ static int mov_read_stsd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) st->codec->palctrl->palette_changed = 1; } else st->codec->palctrl = NULL; + } else if(st->codec->codec_type==CODEC_TYPE_AUDIO) { + uint16_t version = get_be16(pb); - a.size = size - (url_ftell(pb) - start_pos); - if (a.size > 8) - mov_read_default(c, pb, a); - else if (a.size > 0) - url_fskip(pb, a.size); - } else { st->codec->codec_id = codec_get_id(mov_audio_tags, format); - if(st->codec->codec_id==CODEC_ID_AMR_NB || st->codec->codec_id==CODEC_ID_AMR_WB) //from TS26.244 - { - dprintf("AMR audio identified %d!!\n", st->codec->codec_id); - get_be32(pb);get_be32(pb); //Reserved_8 - get_be16(pb);//Reserved_2 - get_be16(pb);//Reserved_2 - get_be32(pb);//Reserved_4 - get_be16(pb);//TimeScale - get_be16(pb);//Reserved_2 - - //AMRSpecificBox.(10 bytes) - - get_be32(pb); //size - get_be32(pb); //type=='damr' - get_be32(pb); //vendor - get_byte(pb); //decoder version - get_be16(pb); //mode_set - get_byte(pb); //mode_change_period - get_byte(pb); //frames_per_sample - - st->duration = AV_NOPTS_VALUE;//Not possible to get from this info, must count number of AMR frames - if(st->codec->codec_id==CODEC_ID_AMR_NB) - { - st->codec->sample_rate=8000; - st->codec->channels=1; - } - else //AMR-WB - { - st->codec->sample_rate=16000; - st->codec->channels=1; - } - st->codec->bits_per_sample=16; - 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 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( st->codec->codec_tag == MKTAG( 'm', 'p', '4', 'a' )) - { - MOV_atom_t a; - int mp4_version; - - /* Handle mp4 audio tag */ - mp4_version=get_be16(pb);/*version*/ - get_be16(pb); /*revesion*/ - get_be32(pb); - st->codec->channels = get_be16(pb); /* channels */ - st->codec->bits_per_sample = get_be16(pb); /* bits per sample */ - get_be32(pb); - st->codec->sample_rate = get_be16(pb); /* sample rate, not always correct */ - if(st->codec->sample_rate == 1) //nonsese rate? -> ignore - st->codec->sample_rate= 0; - - get_be16(pb); - c->mp4=1; - - if(mp4_version==1) - { - url_fskip(pb,16); - a.size=size-(16+20+16); - } - else - a.size=size-(16+20); - - a.offset=url_ftell(pb); - - mov_read_default(c, pb, a); - - /* Get correct sample rate from extradata */ - if(st->codec->extradata_size) { - const int samplerate_table[] = { - 96000, 88200, 64000, 48000, 44100, 32000, - 24000, 22050, 16000, 12000, 11025, 8000, - 7350, 0, 0, 0 - }; - unsigned char *px = st->codec->extradata; - // 5 bits objectTypeIndex, 4 bits sampleRateIndex, 4 bits channels - int samplerate_index = ((px[0] & 7) << 1) + ((px[1] >> 7) & 1); - st->codec->sample_rate = samplerate_table[samplerate_index]; - st->codec->channels = (px[1] >> 3) & 15; - } - } - else if( st->codec->codec_tag == MKTAG( 'a', 'l', 'a', 'c' )) - { - /* Handle alac audio tag + special extradata */ - get_be32(pb); /* version */ - get_be32(pb); - st->codec->channels = get_be16(pb); /* channels */ - st->codec->bits_per_sample = get_be16(pb); /* bits per sample */ - get_be32(pb); - st->codec->sample_rate = get_be16(pb); - get_be16(pb); + get_be16(pb); /* revision level */ + get_be32(pb); /* vendor */ - /* fetch the 36-byte extradata needed for alac decoding */ - st->codec->extradata_size = 36; - st->codec->extradata = (uint8_t*) - av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); - get_buffer(pb, st->codec->extradata, st->codec->extradata_size); + st->codec->channels = get_be16(pb); /* channel count */ + st->codec->bits_per_sample = get_be16(pb); /* sample size */ + /* do we need to force to 16 for AMR ? */ + + /* handle specific s8 codec */ + get_be16(pb); /* compression id = 0*/ + get_be16(pb); /* packet size = 0 */ + + st->codec->sample_rate = ((get_be32(pb) >> 16)); + + switch (st->codec->codec_id) { + case CODEC_ID_PCM_S16BE: + if (st->codec->bits_per_sample == 8) + st->codec->codec_id = CODEC_ID_PCM_S8; + /* fall */ + case CODEC_ID_PCM_U8: + if (st->codec->bits_per_sample == 16) + st->codec->codec_id = CODEC_ID_PCM_S16BE; + st->codec->bit_rate = st->codec->sample_rate * 8; + break; + case CODEC_ID_AMR_WB: + st->codec->sample_rate = 16000; /* should really we ? */ + st->codec->channels=1; /* really needed */ + break; + case CODEC_ID_AMR_NB: + st->codec->sample_rate = 8000; /* should really we ? */ + st->codec->channels=1; /* really needed */ + break; + default: + break; } - else if(size>=(16+20)) - {//16 bytes read, reading atleast 20 more - uint16_t version; - version = get_be16(pb); /* version */ - get_be16(pb); /* revision level */ - get_be32(pb); /* vendor */ - - st->codec->channels = get_be16(pb); /* channel count */ - st->codec->bits_per_sample = get_be16(pb); /* sample size */ - - /* handle specific s8 codec */ - get_be16(pb); /* compression id = 0*/ - get_be16(pb); /* packet size = 0 */ - - st->codec->sample_rate = ((get_be32(pb) >> 16)); - - switch (st->codec->codec_id) { - case CODEC_ID_PCM_S16BE: - if (st->codec->bits_per_sample == 8) - st->codec->codec_id = CODEC_ID_PCM_S8; - /* fall */ - case CODEC_ID_PCM_U8: - st->codec->bit_rate = st->codec->sample_rate * 8; - break; - default: - ; - } - //Read QT version 1 fields. In version 0 theese dont exist - dprintf("version =%d mp4=%d\n",version,c->mp4); - 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 - 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); - if(size>0) { - dprintf("skipping 0x%X bytes\n",size-(16+20)); - url_fskip(pb, size); - } - } - } - else - { - size-=16; - //Unknown size, but lets do our best and skip the rest. - dprintf("Strange size, skipping 0x%X bytes\n",size); - url_fskip(pb, size); + //Read QT version 1 fields. In version 0 theese dont exist + dprintf("version =%d mp4=%d\n",version,c->mp4); + if(version==1) { + get_be32(pb); /* samples per packet */ + get_be32(pb); /* bytes per packet */ + get_be32(pb); /* bytes per frame */ + get_be32(pb); /* bytes per sample */ } + } else { + /* other codec type, just skip (rtp, mp4s, tmcd ...) */ + url_fskip(pb, size - (url_ftell(pb) - start_pos)); } + /* this will read extra atoms at the end (wave, alac, damr, avcC, SMI ...) */ + a.size = size - (url_ftell(pb) - start_pos); + if (a.size > 8) + mov_read_default(c, pb, a); + else if (a.size > 0) + url_fskip(pb, a.size); } if(st->codec->codec_type==CODEC_TYPE_AUDIO && st->codec->sample_rate==0 && sc->time_scale>1) { @@ -1497,6 +1418,7 @@ static const MOVParseTableEntry mov_default_parse_table[] = { { MKTAG( 'd', 'r', 'e', 'f' ), mov_read_leaf }, { MKTAG( 'e', 'd', 't', 's' ), mov_read_default }, { MKTAG( 'e', 'l', 's', 't' ), mov_read_elst }, +{ MKTAG( 'e', 'n', 'd', 'a' ), mov_read_enda }, { MKTAG( 'f', 'r', 'e', 'e' ), mov_read_leaf }, { MKTAG( 'f', 't', 'y', 'p' ), mov_read_ftyp }, { MKTAG( 'h', 'd', 'l', 'r' ), mov_read_hdlr }, @@ -1519,6 +1441,7 @@ static const MOVParseTableEntry mov_default_parse_table[] = { { MKTAG( 's', 'k', 'i', 'p' ), mov_read_leaf }, { MKTAG( 's', 'm', 'h', 'd' ), mov_read_leaf }, /* sound media info header */ { MKTAG( 'S', 'M', 'I', ' ' ), mov_read_smi }, /* Sorenson extension ??? */ +{ MKTAG( 'a', 'l', 'a', 'c' ), mov_read_alac }, /* alac specific atom */ { MKTAG( 'a', 'v', 'c', 'C' ), mov_read_avcC }, { MKTAG( 's', 't', 'b', 'l' ), mov_read_default }, { MKTAG( 's', 't', 'c', 'o' ), mov_read_stco }, -- cgit v1.2.3