oggparseogm.c 7.36 KB
Newer Older
Måns Rullgård's avatar
Måns Rullgård committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
/**
    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>
26

27
#include "libavutil/intreadwrite.h"
28

29
#include "libavcodec/bytestream.h"
30

Måns Rullgård's avatar
Måns Rullgård committed
31
#include "avformat.h"
32
#include "internal.h"
33
#include "oggdec.h"
34
#include "riff.h"
Måns Rullgård's avatar
Måns Rullgård committed
35 36 37 38

static int
ogm_header(AVFormatContext *s, int idx)
{
39 40
    struct ogg *ogg = s->priv_data;
    struct ogg_stream *os = ogg->streams + idx;
Måns Rullgård's avatar
Måns Rullgård committed
41
    AVStream *st = s->streams[idx];
42
    GetByteContext p;
Måns Rullgård's avatar
Måns Rullgård committed
43 44
    uint64_t time_unit;
    uint64_t spu;
45
    uint32_t size;
Måns Rullgård's avatar
Måns Rullgård committed
46

47 48
    bytestream2_init(&p, os->buf + os->pstart, os->psize);
    if (!(bytestream2_peek_byte(&p) & 1))
Måns Rullgård's avatar
Måns Rullgård committed
49 50
        return 0;

51 52
    if (bytestream2_peek_byte(&p) == 1) {
        bytestream2_skip(&p, 1);
Måns Rullgård's avatar
Måns Rullgård committed
53

54
        if (bytestream2_peek_byte(&p) == 'v'){
David Conrad's avatar
David Conrad committed
55
            int tag;
56
            st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
57 58
            bytestream2_skip(&p, 8);
            tag = bytestream2_get_le32(&p);
59 60
            st->codecpar->codec_id = ff_codec_get_id(ff_codec_bmp_tags, tag);
            st->codecpar->codec_tag = tag;
61
            if (st->codecpar->codec_id == AV_CODEC_ID_MPEG4)
62
                st->need_parsing = AVSTREAM_PARSE_HEADERS;
63
        } else if (bytestream2_peek_byte(&p) == 't') {
64 65
            st->codecpar->codec_type = AVMEDIA_TYPE_SUBTITLE;
            st->codecpar->codec_id = AV_CODEC_ID_TEXT;
66
            bytestream2_skip(&p, 12);
David Conrad's avatar
David Conrad committed
67
        } else {
68
            uint8_t acid[5] = { 0 };
David Conrad's avatar
David Conrad committed
69
            int cid;
70
            st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
71 72
            bytestream2_skip(&p, 8);
            bytestream2_get_buffer(&p, acid, 4);
David Conrad's avatar
David Conrad committed
73 74
            acid[4] = 0;
            cid = strtol(acid, NULL, 16);
75
            st->codecpar->codec_id = ff_codec_get_id(ff_codec_wav_tags, cid);
76
            // our parser completely breaks AAC in Ogg
77
            if (st->codecpar->codec_id != AV_CODEC_ID_AAC)
78
                st->need_parsing = AVSTREAM_PARSE_FULL;
David Conrad's avatar
David Conrad committed
79
        }
Måns Rullgård's avatar
Måns Rullgård committed
80

81
        size        = bytestream2_get_le32(&p);
82
        size        = FFMIN(size, os->psize);
83 84
        time_unit   = bytestream2_get_le64(&p);
        spu         = bytestream2_get_le64(&p);
85 86 87 88 89
        if (!time_unit || !spu) {
            av_log(s, AV_LOG_ERROR, "Invalid timing values.\n");
            return AVERROR_INVALIDDATA;
        }

90 91
        bytestream2_skip(&p, 4);    /* default_len */
        bytestream2_skip(&p, 8);    /* buffersize + bits_per_sample */
Måns Rullgård's avatar
Måns Rullgård committed
92

93 94 95
        if(st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO){
            st->codecpar->width = bytestream2_get_le32(&p);
            st->codecpar->height = bytestream2_get_le32(&p);
96
            avpriv_set_pts_info(st, 64, time_unit, spu * 10000000);
David Conrad's avatar
David Conrad committed
97
        } else {
98
            st->codecpar->channels = bytestream2_get_le16(&p);
99
            bytestream2_skip(&p, 2); /* block_align */
100 101 102
            st->codecpar->bit_rate = bytestream2_get_le32(&p) * 8;
            st->codecpar->sample_rate = spu * 10000000 / time_unit;
            avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate);
103
            if (size >= 56 && st->codecpar->codec_id == AV_CODEC_ID_AAC) {
104
                bytestream2_skip(&p, 4);
105 106 107 108
                size -= 4;
            }
            if (size > 52) {
                size -= 52;
109 110
                if (bytestream2_get_bytes_left(&p) < size)
                    return AVERROR_INVALIDDATA;
111
                av_freep(&st->codecpar->extradata);
112 113
                if (ff_alloc_extradata(st->codecpar, size) < 0)
                    return AVERROR(ENOMEM);
114
                bytestream2_get_buffer(&p, st->codecpar->extradata, st->codecpar->extradata_size);
115
            }
David Conrad's avatar
David Conrad committed
116
        }
117 118 119

        // Update internal avctx with changes to codecpar above.
        st->internal->need_context_update = 1;
120 121 122
    } else if (bytestream2_peek_byte(&p) == 3) {
        bytestream2_skip(&p, 7);
        if (bytestream2_get_bytes_left(&p) > 1)
123
            ff_vorbis_stream_comment(s, st, p.buffer, bytestream2_get_bytes_left(&p) - 1);
David Conrad's avatar
David Conrad committed
124
    }
Måns Rullgård's avatar
Måns Rullgård committed
125 126 127 128 129 130 131

    return 1;
}

static int
ogm_dshow_header(AVFormatContext *s, int idx)
{
132 133
    struct ogg *ogg = s->priv_data;
    struct ogg_stream *os = ogg->streams + idx;
Måns Rullgård's avatar
Måns Rullgård committed
134 135 136 137 138 139 140 141 142
    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;

143 144
    if (os->psize < 100)
        return AVERROR_INVALIDDATA;
145
    t = AV_RL32(p + 96);
Måns Rullgård's avatar
Måns Rullgård committed
146 147

    if(t == 0x05589f80){
148 149 150
        if (os->psize < 184)
            return AVERROR_INVALIDDATA;

151 152
        st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
        st->codecpar->codec_id = ff_codec_get_id(ff_codec_bmp_tags, AV_RL32(p + 68));
153
        avpriv_set_pts_info(st, 64, AV_RL64(p + 164), 10000000);
154 155
        st->codecpar->width = AV_RL32(p + 176);
        st->codecpar->height = AV_RL32(p + 180);
Måns Rullgård's avatar
Måns Rullgård committed
156
    } else if(t == 0x05589f81){
157 158 159
        if (os->psize < 136)
            return AVERROR_INVALIDDATA;

160 161 162 163 164
        st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
        st->codecpar->codec_id = ff_codec_get_id(ff_codec_wav_tags, AV_RL16(p + 124));
        st->codecpar->channels = AV_RL16(p + 126);
        st->codecpar->sample_rate = AV_RL32(p + 128);
        st->codecpar->bit_rate = AV_RL32(p + 132) * 8;
Måns Rullgård's avatar
Måns Rullgård committed
165 166 167 168 169 170 171 172
    }

    return 1;
}

static int
ogm_packet(AVFormatContext *s, int idx)
{
173 174
    struct ogg *ogg = s->priv_data;
    struct ogg_stream *os = ogg->streams + idx;
Måns Rullgård's avatar
Måns Rullgård committed
175 176 177
    uint8_t *p = os->buf + os->pstart;
    int lb;

178
    if(*p & 8)
179
        os->pflags |= AV_PKT_FLAG_KEY;
180

Måns Rullgård's avatar
Måns Rullgård committed
181
    lb = ((*p & 2) << 1) | ((*p >> 6) & 3);
182 183 184
    if (os->psize < lb + 1)
        return AVERROR_INVALIDDATA;

Måns Rullgård's avatar
Måns Rullgård committed
185 186 187
    os->pstart += lb + 1;
    os->psize -= lb + 1;

188
    while (lb--)
189
        os->pduration += (uint64_t)p[lb+1] << (lb*8);
190

Måns Rullgård's avatar
Måns Rullgård committed
191 192 193
    return 0;
}

194
const struct ogg_codec ff_ogm_video_codec = {
Måns Rullgård's avatar
Måns Rullgård committed
195 196 197
    .magic = "\001video",
    .magicsize = 6,
    .header = ogm_header,
David Conrad's avatar
David Conrad committed
198 199
    .packet = ogm_packet,
    .granule_is_start = 1,
200
    .nb_header = 2,
Måns Rullgård's avatar
Måns Rullgård committed
201 202
};

203
const struct ogg_codec ff_ogm_audio_codec = {
Måns Rullgård's avatar
Måns Rullgård committed
204 205 206
    .magic = "\001audio",
    .magicsize = 6,
    .header = ogm_header,
David Conrad's avatar
David Conrad committed
207 208
    .packet = ogm_packet,
    .granule_is_start = 1,
209
    .nb_header = 2,
Måns Rullgård's avatar
Måns Rullgård committed
210 211
};

212
const struct ogg_codec ff_ogm_text_codec = {
213 214 215
    .magic = "\001text",
    .magicsize = 5,
    .header = ogm_header,
David Conrad's avatar
David Conrad committed
216 217
    .packet = ogm_packet,
    .granule_is_start = 1,
218
    .nb_header = 2,
219 220
};

221
const struct ogg_codec ff_ogm_old_codec = {
Måns Rullgård's avatar
Måns Rullgård committed
222 223 224
    .magic = "\001Direct Show Samples embedded in Ogg",
    .magicsize = 35,
    .header = ogm_dshow_header,
David Conrad's avatar
David Conrad committed
225 226
    .packet = ogm_packet,
    .granule_is_start = 1,
227
    .nb_header = 1,
Måns Rullgård's avatar
Måns Rullgård committed
228
};