libavformat/oggparseogm.c
e1203ac0
 /**
     Copyright (C) 2005  Michael Ahlberg, Måns Rullgård
 
     Permission is hereby granted, free of charge, to any person
     obtaining a copy of this software and associated documentation
     files (the "Software"), to deal in the Software without
     restriction, including without limitation the rights to use, copy,
     modify, merge, publish, distribute, sublicense, and/or sell copies
     of the Software, and to permit persons to whom the Software is
     furnished to do so, subject to the following conditions:
 
     The above copyright notice and this permission notice shall be
     included in all copies or substantial portions of the Software.
 
     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     DEALINGS IN THE SOFTWARE.
 **/
 
 #include <stdlib.h>
7c8d4772
 #include "libavutil/avassert.h"
245976da
 #include "libavutil/intreadwrite.h"
9106a698
 #include "libavcodec/get_bits.h"
245976da
 #include "libavcodec/bytestream.h"
e1203ac0
 #include "avformat.h"
c3f9ebf7
 #include "internal.h"
a0ddef24
 #include "oggdec.h"
9d9f4119
 #include "riff.h"
e1203ac0
 
 static int
 ogm_header(AVFormatContext *s, int idx)
 {
77be08ee
     struct ogg *ogg = s->priv_data;
     struct ogg_stream *os = ogg->streams + idx;
e1203ac0
     AVStream *st = s->streams[idx];
19b9659f
     GetByteContext p;
e1203ac0
     uint64_t time_unit;
     uint64_t spu;
7c8d4772
     uint32_t size;
e1203ac0
 
19b9659f
     bytestream2_init(&p, os->buf + os->pstart, os->psize);
     if (!(bytestream2_peek_byte(&p) & 1))
e1203ac0
         return 0;
 
19b9659f
     if (bytestream2_peek_byte(&p) == 1) {
         bytestream2_skip(&p, 1);
e1203ac0
 
19b9659f
         if (bytestream2_peek_byte(&p) == 'v'){
2e508585
             int tag;
72415b2a
             st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
19b9659f
             bytestream2_skip(&p, 8);
             tag = bytestream2_get_le32(&p);
2e508585
             st->codec->codec_id = ff_codec_get_id(ff_codec_bmp_tags, tag);
             st->codec->codec_tag = tag;
19b9659f
         } else if (bytestream2_peek_byte(&p) == 't') {
72415b2a
             st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
36ef5369
             st->codec->codec_id = AV_CODEC_ID_TEXT;
19b9659f
             bytestream2_skip(&p, 12);
2e508585
         } else {
19b9659f
             uint8_t acid[5] = { 0 };
2e508585
             int cid;
72415b2a
             st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
19b9659f
             bytestream2_skip(&p, 8);
             bytestream2_get_buffer(&p, acid, 4);
2e508585
             acid[4] = 0;
             cid = strtol(acid, NULL, 16);
             st->codec->codec_id = ff_codec_get_id(ff_codec_wav_tags, cid);
7c8d4772
             // our parser completely breaks AAC in Ogg
7a72695c
             if (st->codec->codec_id != AV_CODEC_ID_AAC)
7c8d4772
                 st->need_parsing = AVSTREAM_PARSE_FULL;
2e508585
         }
e1203ac0
 
a1fb3e51
         size        = bytestream2_get_le32(&p);
7c8d4772
         size        = FFMIN(size, os->psize);
19b9659f
         time_unit   = bytestream2_get_le64(&p);
         spu         = bytestream2_get_le64(&p);
75647dea
         if (!time_unit || !spu) {
             av_log(s, AV_LOG_ERROR, "Invalid timing values.\n");
             return AVERROR_INVALIDDATA;
         }
 
19b9659f
         bytestream2_skip(&p, 4);    /* default_len */
         bytestream2_skip(&p, 8);    /* buffersize + bits_per_sample */
e1203ac0
 
72415b2a
         if(st->codec->codec_type == AVMEDIA_TYPE_VIDEO){
19b9659f
             st->codec->width = bytestream2_get_le32(&p);
             st->codec->height = bytestream2_get_le32(&p);
12c65efb
             avpriv_set_pts_info(st, 64, time_unit, spu * 10000000);
2e508585
         } else {
19b9659f
             st->codec->channels = bytestream2_get_le16(&p);
             bytestream2_skip(&p, 2); /* block_align */
             st->codec->bit_rate = bytestream2_get_le32(&p) * 8;
2e508585
             st->codec->sample_rate = spu * 10000000 / time_unit;
c3f9ebf7
             avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
7a72695c
             if (size >= 56 && st->codec->codec_id == AV_CODEC_ID_AAC) {
a1fb3e51
                 bytestream2_skip(&p, 4);
7c8d4772
                 size -= 4;
             }
             if (size > 52) {
29d147c9
                 av_assert0(AV_INPUT_BUFFER_PADDING_SIZE <= 52);
7c8d4772
                 size -= 52;
a807c682
                 ff_alloc_extradata(st->codec, size);
                 bytestream2_get_buffer(&p, st->codec->extradata, st->codec->extradata_size);
7c8d4772
             }
2e508585
         }
19b9659f
     } else if (bytestream2_peek_byte(&p) == 3) {
         bytestream2_skip(&p, 7);
         if (bytestream2_get_bytes_left(&p) > 1)
db68ef89
             ff_vorbis_stream_comment(s, st, p.buffer, bytestream2_get_bytes_left(&p) - 1);
d8ba7483
     }
e1203ac0
 
     return 1;
 }
 
 static int
 ogm_dshow_header(AVFormatContext *s, int idx)
 {
77be08ee
     struct ogg *ogg = s->priv_data;
     struct ogg_stream *os = ogg->streams + idx;
e1203ac0
     AVStream *st = s->streams[idx];
     uint8_t *p = os->buf + os->pstart;
     uint32_t t;
 
     if(!(*p & 1))
         return 0;
     if(*p != 1)
         return 1;
 
0875a9e4
     if (os->psize < 100)
         return AVERROR_INVALIDDATA;
78c3c188
     t = AV_RL32(p + 96);
e1203ac0
 
     if(t == 0x05589f80){
63598728
         if (os->psize < 184)
             return AVERROR_INVALIDDATA;
 
72415b2a
         st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
1a40491e
         st->codec->codec_id = ff_codec_get_id(ff_codec_bmp_tags, AV_RL32(p + 68));
1bb3990b
         avpriv_set_pts_info(st, 64, AV_RL64(p + 164), 10000000);
78c3c188
         st->codec->width = AV_RL32(p + 176);
         st->codec->height = AV_RL32(p + 180);
e1203ac0
     } else if(t == 0x05589f81){
63598728
         if (os->psize < 136)
             return AVERROR_INVALIDDATA;
 
72415b2a
         st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
1a40491e
         st->codec->codec_id = ff_codec_get_id(ff_codec_wav_tags, AV_RL16(p + 124));
78c3c188
         st->codec->channels = AV_RL16(p + 126);
         st->codec->sample_rate = AV_RL32(p + 128);
         st->codec->bit_rate = AV_RL32(p + 132) * 8;
e1203ac0
     }
 
     return 1;
 }
 
 static int
 ogm_packet(AVFormatContext *s, int idx)
 {
77be08ee
     struct ogg *ogg = s->priv_data;
     struct ogg_stream *os = ogg->streams + idx;
e1203ac0
     uint8_t *p = os->buf + os->pstart;
     int lb;
 
e1a794b2
     if(*p & 8)
cc947f04
         os->pflags |= AV_PKT_FLAG_KEY;
e1a794b2
 
e1203ac0
     lb = ((*p & 2) << 1) | ((*p >> 6) & 3);
     os->pstart += lb + 1;
     os->psize -= lb + 1;
 
3477897e
     while (lb--)
         os->pduration += p[lb+1] << (lb*8);
 
e1203ac0
     return 0;
 }
 
77be08ee
 const struct ogg_codec ff_ogm_video_codec = {
e1203ac0
     .magic = "\001video",
     .magicsize = 6,
     .header = ogm_header,
5e15c7d9
     .packet = ogm_packet,
     .granule_is_start = 1,
7751e469
     .nb_header = 2,
e1203ac0
 };
 
77be08ee
 const struct ogg_codec ff_ogm_audio_codec = {
e1203ac0
     .magic = "\001audio",
     .magicsize = 6,
     .header = ogm_header,
5e15c7d9
     .packet = ogm_packet,
     .granule_is_start = 1,
7751e469
     .nb_header = 2,
e1203ac0
 };
 
77be08ee
 const struct ogg_codec ff_ogm_text_codec = {
2331e31c
     .magic = "\001text",
     .magicsize = 5,
     .header = ogm_header,
5e15c7d9
     .packet = ogm_packet,
     .granule_is_start = 1,
7751e469
     .nb_header = 2,
2331e31c
 };
 
77be08ee
 const struct ogg_codec ff_ogm_old_codec = {
e1203ac0
     .magic = "\001Direct Show Samples embedded in Ogg",
     .magicsize = 35,
     .header = ogm_dshow_header,
5e15c7d9
     .packet = ogm_packet,
     .granule_is_start = 1,
7751e469
     .nb_header = 1,
e1203ac0
 };