yading@11: /** yading@11: Copyright (C) 2005 Michael Ahlberg, Måns Rullgård yading@11: yading@11: Permission is hereby granted, free of charge, to any person yading@11: obtaining a copy of this software and associated documentation yading@11: files (the "Software"), to deal in the Software without yading@11: restriction, including without limitation the rights to use, copy, yading@11: modify, merge, publish, distribute, sublicense, and/or sell copies yading@11: of the Software, and to permit persons to whom the Software is yading@11: furnished to do so, subject to the following conditions: yading@11: yading@11: The above copyright notice and this permission notice shall be yading@11: included in all copies or substantial portions of the Software. yading@11: yading@11: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, yading@11: EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF yading@11: MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND yading@11: NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT yading@11: HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, yading@11: WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, yading@11: OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER yading@11: DEALINGS IN THE SOFTWARE. yading@11: **/ yading@11: yading@11: #include yading@11: #include "libavutil/avassert.h" yading@11: #include "libavutil/intreadwrite.h" yading@11: #include "libavcodec/get_bits.h" yading@11: #include "libavcodec/bytestream.h" yading@11: #include "avformat.h" yading@11: #include "internal.h" yading@11: #include "oggdec.h" yading@11: #include "riff.h" yading@11: yading@11: static int yading@11: ogm_header(AVFormatContext *s, int idx) yading@11: { yading@11: struct ogg *ogg = s->priv_data; yading@11: struct ogg_stream *os = ogg->streams + idx; yading@11: AVStream *st = s->streams[idx]; yading@11: const uint8_t *p = os->buf + os->pstart; yading@11: uint64_t time_unit; yading@11: uint64_t spu; yading@11: uint32_t size; yading@11: yading@11: if(!(*p & 1)) yading@11: return 0; yading@11: yading@11: if(*p == 1) { yading@11: p++; yading@11: yading@11: if(*p == 'v'){ yading@11: int tag; yading@11: st->codec->codec_type = AVMEDIA_TYPE_VIDEO; yading@11: p += 8; yading@11: tag = bytestream_get_le32(&p); yading@11: st->codec->codec_id = ff_codec_get_id(ff_codec_bmp_tags, tag); yading@11: st->codec->codec_tag = tag; yading@11: } else if (*p == 't') { yading@11: st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE; yading@11: st->codec->codec_id = AV_CODEC_ID_TEXT; yading@11: p += 12; yading@11: } else { yading@11: uint8_t acid[5]; yading@11: int cid; yading@11: st->codec->codec_type = AVMEDIA_TYPE_AUDIO; yading@11: p += 8; yading@11: bytestream_get_buffer(&p, acid, 4); yading@11: acid[4] = 0; yading@11: cid = strtol(acid, NULL, 16); yading@11: st->codec->codec_id = ff_codec_get_id(ff_codec_wav_tags, cid); yading@11: // our parser completely breaks AAC in Ogg yading@11: if (st->codec->codec_id != AV_CODEC_ID_AAC) yading@11: st->need_parsing = AVSTREAM_PARSE_FULL; yading@11: } yading@11: yading@11: size = bytestream_get_le32(&p); yading@11: size = FFMIN(size, os->psize); yading@11: time_unit = bytestream_get_le64(&p); yading@11: spu = bytestream_get_le64(&p); yading@11: p += 4; /* default_len */ yading@11: p += 8; /* buffersize + bits_per_sample */ yading@11: yading@11: if(st->codec->codec_type == AVMEDIA_TYPE_VIDEO){ yading@11: st->codec->width = bytestream_get_le32(&p); yading@11: st->codec->height = bytestream_get_le32(&p); yading@11: avpriv_set_pts_info(st, 64, time_unit, spu * 10000000); yading@11: } else { yading@11: st->codec->channels = bytestream_get_le16(&p); yading@11: p += 2; /* block_align */ yading@11: st->codec->bit_rate = bytestream_get_le32(&p) * 8; yading@11: st->codec->sample_rate = time_unit ? spu * 10000000 / time_unit : 0; yading@11: avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate); yading@11: if (size >= 56 && st->codec->codec_id == AV_CODEC_ID_AAC) { yading@11: p += 4; yading@11: size -= 4; yading@11: } yading@11: if (size > 52) { yading@11: av_assert0(FF_INPUT_BUFFER_PADDING_SIZE <= 52); yading@11: size -= 52; yading@11: st->codec->extradata_size = size; yading@11: st->codec->extradata = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE); yading@11: bytestream_get_buffer(&p, st->codec->extradata, size); yading@11: } yading@11: } yading@11: } else if (*p == 3) { yading@11: if (os->psize > 8) yading@11: ff_vorbis_comment(s, &st->metadata, p+7, os->psize-8); yading@11: } yading@11: yading@11: return 1; yading@11: } yading@11: yading@11: static int yading@11: ogm_dshow_header(AVFormatContext *s, int idx) yading@11: { yading@11: struct ogg *ogg = s->priv_data; yading@11: struct ogg_stream *os = ogg->streams + idx; yading@11: AVStream *st = s->streams[idx]; yading@11: uint8_t *p = os->buf + os->pstart; yading@11: uint32_t t; yading@11: yading@11: if(!(*p & 1)) yading@11: return 0; yading@11: if(*p != 1) yading@11: return 1; yading@11: yading@11: t = AV_RL32(p + 96); yading@11: yading@11: if(t == 0x05589f80){ yading@11: st->codec->codec_type = AVMEDIA_TYPE_VIDEO; yading@11: st->codec->codec_id = ff_codec_get_id(ff_codec_bmp_tags, AV_RL32(p + 68)); yading@11: avpriv_set_pts_info(st, 64, AV_RL64(p + 164), 10000000); yading@11: st->codec->width = AV_RL32(p + 176); yading@11: st->codec->height = AV_RL32(p + 180); yading@11: } else if(t == 0x05589f81){ yading@11: st->codec->codec_type = AVMEDIA_TYPE_AUDIO; yading@11: st->codec->codec_id = ff_codec_get_id(ff_codec_wav_tags, AV_RL16(p + 124)); yading@11: st->codec->channels = AV_RL16(p + 126); yading@11: st->codec->sample_rate = AV_RL32(p + 128); yading@11: st->codec->bit_rate = AV_RL32(p + 132) * 8; yading@11: } yading@11: yading@11: return 1; yading@11: } yading@11: yading@11: static int yading@11: ogm_packet(AVFormatContext *s, int idx) yading@11: { yading@11: struct ogg *ogg = s->priv_data; yading@11: struct ogg_stream *os = ogg->streams + idx; yading@11: uint8_t *p = os->buf + os->pstart; yading@11: int lb; yading@11: yading@11: if(*p & 8) yading@11: os->pflags |= AV_PKT_FLAG_KEY; yading@11: yading@11: lb = ((*p & 2) << 1) | ((*p >> 6) & 3); yading@11: os->pstart += lb + 1; yading@11: os->psize -= lb + 1; yading@11: yading@11: while (lb--) yading@11: os->pduration += p[lb+1] << (lb*8); yading@11: yading@11: return 0; yading@11: } yading@11: yading@11: const struct ogg_codec ff_ogm_video_codec = { yading@11: .magic = "\001video", yading@11: .magicsize = 6, yading@11: .header = ogm_header, yading@11: .packet = ogm_packet, yading@11: .granule_is_start = 1, yading@11: .nb_header = 2, yading@11: }; yading@11: yading@11: const struct ogg_codec ff_ogm_audio_codec = { yading@11: .magic = "\001audio", yading@11: .magicsize = 6, yading@11: .header = ogm_header, yading@11: .packet = ogm_packet, yading@11: .granule_is_start = 1, yading@11: .nb_header = 2, yading@11: }; yading@11: yading@11: const struct ogg_codec ff_ogm_text_codec = { yading@11: .magic = "\001text", yading@11: .magicsize = 5, yading@11: .header = ogm_header, yading@11: .packet = ogm_packet, yading@11: .granule_is_start = 1, yading@11: .nb_header = 2, yading@11: }; yading@11: yading@11: const struct ogg_codec ff_ogm_old_codec = { yading@11: .magic = "\001Direct Show Samples embedded in Ogg", yading@11: .magicsize = 35, yading@11: .header = ogm_dshow_header, yading@11: .packet = ogm_packet, yading@11: .granule_is_start = 1, yading@11: .nb_header = 1, yading@11: };