1cabdff1aSopenharmony_ci/**
2cabdff1aSopenharmony_ci    Copyright (C) 2005  Michael Ahlberg, Måns Rullgård
3cabdff1aSopenharmony_ci
4cabdff1aSopenharmony_ci    Permission is hereby granted, free of charge, to any person
5cabdff1aSopenharmony_ci    obtaining a copy of this software and associated documentation
6cabdff1aSopenharmony_ci    files (the "Software"), to deal in the Software without
7cabdff1aSopenharmony_ci    restriction, including without limitation the rights to use, copy,
8cabdff1aSopenharmony_ci    modify, merge, publish, distribute, sublicense, and/or sell copies
9cabdff1aSopenharmony_ci    of the Software, and to permit persons to whom the Software is
10cabdff1aSopenharmony_ci    furnished to do so, subject to the following conditions:
11cabdff1aSopenharmony_ci
12cabdff1aSopenharmony_ci    The above copyright notice and this permission notice shall be
13cabdff1aSopenharmony_ci    included in all copies or substantial portions of the Software.
14cabdff1aSopenharmony_ci
15cabdff1aSopenharmony_ci    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16cabdff1aSopenharmony_ci    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17cabdff1aSopenharmony_ci    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18cabdff1aSopenharmony_ci    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19cabdff1aSopenharmony_ci    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20cabdff1aSopenharmony_ci    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21cabdff1aSopenharmony_ci    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22cabdff1aSopenharmony_ci    DEALINGS IN THE SOFTWARE.
23cabdff1aSopenharmony_ci**/
24cabdff1aSopenharmony_ci
25cabdff1aSopenharmony_ci#include <stdlib.h>
26cabdff1aSopenharmony_ci
27cabdff1aSopenharmony_ci#include "libavutil/intreadwrite.h"
28cabdff1aSopenharmony_ci
29cabdff1aSopenharmony_ci#include "libavcodec/bytestream.h"
30cabdff1aSopenharmony_ci
31cabdff1aSopenharmony_ci#include "avformat.h"
32cabdff1aSopenharmony_ci#include "internal.h"
33cabdff1aSopenharmony_ci#include "oggdec.h"
34cabdff1aSopenharmony_ci#include "riff.h"
35cabdff1aSopenharmony_ci
36cabdff1aSopenharmony_cistatic int
37cabdff1aSopenharmony_ciogm_header(AVFormatContext *s, int idx)
38cabdff1aSopenharmony_ci{
39cabdff1aSopenharmony_ci    struct ogg *ogg = s->priv_data;
40cabdff1aSopenharmony_ci    struct ogg_stream *os = ogg->streams + idx;
41cabdff1aSopenharmony_ci    AVStream *st = s->streams[idx];
42cabdff1aSopenharmony_ci    FFStream *const sti = ffstream(st);
43cabdff1aSopenharmony_ci    GetByteContext p;
44cabdff1aSopenharmony_ci    uint64_t time_unit;
45cabdff1aSopenharmony_ci    uint64_t spu;
46cabdff1aSopenharmony_ci    uint32_t size;
47cabdff1aSopenharmony_ci    int ret;
48cabdff1aSopenharmony_ci
49cabdff1aSopenharmony_ci    bytestream2_init(&p, os->buf + os->pstart, os->psize);
50cabdff1aSopenharmony_ci    if (!(bytestream2_peek_byte(&p) & 1))
51cabdff1aSopenharmony_ci        return 0;
52cabdff1aSopenharmony_ci
53cabdff1aSopenharmony_ci    if (bytestream2_peek_byte(&p) == 1) {
54cabdff1aSopenharmony_ci        bytestream2_skip(&p, 1);
55cabdff1aSopenharmony_ci
56cabdff1aSopenharmony_ci        if (bytestream2_peek_byte(&p) == 'v'){
57cabdff1aSopenharmony_ci            int tag;
58cabdff1aSopenharmony_ci            st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
59cabdff1aSopenharmony_ci            bytestream2_skip(&p, 8);
60cabdff1aSopenharmony_ci            tag = bytestream2_get_le32(&p);
61cabdff1aSopenharmony_ci            st->codecpar->codec_id = ff_codec_get_id(ff_codec_bmp_tags, tag);
62cabdff1aSopenharmony_ci            st->codecpar->codec_tag = tag;
63cabdff1aSopenharmony_ci            if (st->codecpar->codec_id == AV_CODEC_ID_MPEG4)
64cabdff1aSopenharmony_ci                sti->need_parsing = AVSTREAM_PARSE_HEADERS;
65cabdff1aSopenharmony_ci        } else if (bytestream2_peek_byte(&p) == 't') {
66cabdff1aSopenharmony_ci            st->codecpar->codec_type = AVMEDIA_TYPE_SUBTITLE;
67cabdff1aSopenharmony_ci            st->codecpar->codec_id = AV_CODEC_ID_TEXT;
68cabdff1aSopenharmony_ci            bytestream2_skip(&p, 12);
69cabdff1aSopenharmony_ci        } else {
70cabdff1aSopenharmony_ci            uint8_t acid[5] = { 0 };
71cabdff1aSopenharmony_ci            int cid;
72cabdff1aSopenharmony_ci            st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
73cabdff1aSopenharmony_ci            bytestream2_skip(&p, 8);
74cabdff1aSopenharmony_ci            bytestream2_get_buffer(&p, acid, 4);
75cabdff1aSopenharmony_ci            acid[4] = 0;
76cabdff1aSopenharmony_ci            cid = strtol(acid, NULL, 16);
77cabdff1aSopenharmony_ci            st->codecpar->codec_id = ff_codec_get_id(ff_codec_wav_tags, cid);
78cabdff1aSopenharmony_ci            // our parser completely breaks AAC in Ogg
79cabdff1aSopenharmony_ci            if (st->codecpar->codec_id != AV_CODEC_ID_AAC)
80cabdff1aSopenharmony_ci                sti->need_parsing = AVSTREAM_PARSE_FULL;
81cabdff1aSopenharmony_ci        }
82cabdff1aSopenharmony_ci
83cabdff1aSopenharmony_ci        size        = bytestream2_get_le32(&p);
84cabdff1aSopenharmony_ci        size        = FFMIN(size, os->psize);
85cabdff1aSopenharmony_ci        time_unit   = bytestream2_get_le64(&p);
86cabdff1aSopenharmony_ci        spu         = bytestream2_get_le64(&p);
87cabdff1aSopenharmony_ci        if (!time_unit || !spu) {
88cabdff1aSopenharmony_ci            av_log(s, AV_LOG_ERROR, "Invalid timing values.\n");
89cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
90cabdff1aSopenharmony_ci        }
91cabdff1aSopenharmony_ci
92cabdff1aSopenharmony_ci        bytestream2_skip(&p, 4);    /* default_len */
93cabdff1aSopenharmony_ci        bytestream2_skip(&p, 8);    /* buffersize + bits_per_sample */
94cabdff1aSopenharmony_ci
95cabdff1aSopenharmony_ci        if(st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO){
96cabdff1aSopenharmony_ci            st->codecpar->width = bytestream2_get_le32(&p);
97cabdff1aSopenharmony_ci            st->codecpar->height = bytestream2_get_le32(&p);
98cabdff1aSopenharmony_ci            avpriv_set_pts_info(st, 64, time_unit, spu * 10000000);
99cabdff1aSopenharmony_ci        } else {
100cabdff1aSopenharmony_ci            st->codecpar->ch_layout.nb_channels = bytestream2_get_le16(&p);
101cabdff1aSopenharmony_ci            bytestream2_skip(&p, 2); /* block_align */
102cabdff1aSopenharmony_ci            st->codecpar->bit_rate = bytestream2_get_le32(&p) * 8;
103cabdff1aSopenharmony_ci            st->codecpar->sample_rate = spu * 10000000 / time_unit;
104cabdff1aSopenharmony_ci            avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate);
105cabdff1aSopenharmony_ci            if (size >= 56 && st->codecpar->codec_id == AV_CODEC_ID_AAC) {
106cabdff1aSopenharmony_ci                bytestream2_skip(&p, 4);
107cabdff1aSopenharmony_ci                size -= 4;
108cabdff1aSopenharmony_ci            }
109cabdff1aSopenharmony_ci            if (size > 52) {
110cabdff1aSopenharmony_ci                size -= 52;
111cabdff1aSopenharmony_ci                if (bytestream2_get_bytes_left(&p) < size)
112cabdff1aSopenharmony_ci                    return AVERROR_INVALIDDATA;
113cabdff1aSopenharmony_ci                if ((ret = ff_alloc_extradata(st->codecpar, size)) < 0)
114cabdff1aSopenharmony_ci                    return ret;
115cabdff1aSopenharmony_ci                bytestream2_get_buffer(&p, st->codecpar->extradata, st->codecpar->extradata_size);
116cabdff1aSopenharmony_ci            }
117cabdff1aSopenharmony_ci        }
118cabdff1aSopenharmony_ci
119cabdff1aSopenharmony_ci        // Update internal avctx with changes to codecpar above.
120cabdff1aSopenharmony_ci        sti->need_context_update = 1;
121cabdff1aSopenharmony_ci    } else if (bytestream2_peek_byte(&p) == 3) {
122cabdff1aSopenharmony_ci        bytestream2_skip(&p, 7);
123cabdff1aSopenharmony_ci        if (bytestream2_get_bytes_left(&p) > 1)
124cabdff1aSopenharmony_ci            ff_vorbis_stream_comment(s, st, p.buffer, bytestream2_get_bytes_left(&p) - 1);
125cabdff1aSopenharmony_ci    }
126cabdff1aSopenharmony_ci
127cabdff1aSopenharmony_ci    return 1;
128cabdff1aSopenharmony_ci}
129cabdff1aSopenharmony_ci
130cabdff1aSopenharmony_cistatic int
131cabdff1aSopenharmony_ciogm_dshow_header(AVFormatContext *s, int idx)
132cabdff1aSopenharmony_ci{
133cabdff1aSopenharmony_ci    struct ogg *ogg = s->priv_data;
134cabdff1aSopenharmony_ci    struct ogg_stream *os = ogg->streams + idx;
135cabdff1aSopenharmony_ci    AVStream *st = s->streams[idx];
136cabdff1aSopenharmony_ci    uint8_t *p = os->buf + os->pstart;
137cabdff1aSopenharmony_ci    uint32_t t;
138cabdff1aSopenharmony_ci
139cabdff1aSopenharmony_ci    if(!(*p & 1))
140cabdff1aSopenharmony_ci        return 0;
141cabdff1aSopenharmony_ci    if(*p != 1)
142cabdff1aSopenharmony_ci        return 1;
143cabdff1aSopenharmony_ci
144cabdff1aSopenharmony_ci    if (os->psize < 100)
145cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
146cabdff1aSopenharmony_ci    t = AV_RL32(p + 96);
147cabdff1aSopenharmony_ci
148cabdff1aSopenharmony_ci    if(t == 0x05589f80){
149cabdff1aSopenharmony_ci        if (os->psize < 184)
150cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
151cabdff1aSopenharmony_ci
152cabdff1aSopenharmony_ci        st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
153cabdff1aSopenharmony_ci        st->codecpar->codec_id = ff_codec_get_id(ff_codec_bmp_tags, AV_RL32(p + 68));
154cabdff1aSopenharmony_ci        avpriv_set_pts_info(st, 64, AV_RL64(p + 164), 10000000);
155cabdff1aSopenharmony_ci        st->codecpar->width = AV_RL32(p + 176);
156cabdff1aSopenharmony_ci        st->codecpar->height = AV_RL32(p + 180);
157cabdff1aSopenharmony_ci    } else if(t == 0x05589f81){
158cabdff1aSopenharmony_ci        if (os->psize < 136)
159cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
160cabdff1aSopenharmony_ci
161cabdff1aSopenharmony_ci        st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
162cabdff1aSopenharmony_ci        st->codecpar->codec_id = ff_codec_get_id(ff_codec_wav_tags, AV_RL16(p + 124));
163cabdff1aSopenharmony_ci        st->codecpar->ch_layout.nb_channels = AV_RL16(p + 126);
164cabdff1aSopenharmony_ci        st->codecpar->sample_rate = AV_RL32(p + 128);
165cabdff1aSopenharmony_ci        st->codecpar->bit_rate = AV_RL32(p + 132) * 8;
166cabdff1aSopenharmony_ci    }
167cabdff1aSopenharmony_ci
168cabdff1aSopenharmony_ci    return 1;
169cabdff1aSopenharmony_ci}
170cabdff1aSopenharmony_ci
171cabdff1aSopenharmony_cistatic int
172cabdff1aSopenharmony_ciogm_packet(AVFormatContext *s, int idx)
173cabdff1aSopenharmony_ci{
174cabdff1aSopenharmony_ci    struct ogg *ogg = s->priv_data;
175cabdff1aSopenharmony_ci    struct ogg_stream *os = ogg->streams + idx;
176cabdff1aSopenharmony_ci    uint8_t *p = os->buf + os->pstart;
177cabdff1aSopenharmony_ci    int lb;
178cabdff1aSopenharmony_ci
179cabdff1aSopenharmony_ci    if(*p & 8)
180cabdff1aSopenharmony_ci        os->pflags |= AV_PKT_FLAG_KEY;
181cabdff1aSopenharmony_ci
182cabdff1aSopenharmony_ci    lb = ((*p & 2) << 1) | ((*p >> 6) & 3);
183cabdff1aSopenharmony_ci    if (os->psize < lb + 1)
184cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
185cabdff1aSopenharmony_ci
186cabdff1aSopenharmony_ci    os->pstart += lb + 1;
187cabdff1aSopenharmony_ci    os->psize -= lb + 1;
188cabdff1aSopenharmony_ci
189cabdff1aSopenharmony_ci    while (lb--)
190cabdff1aSopenharmony_ci        os->pduration += (uint64_t)p[lb+1] << (lb*8);
191cabdff1aSopenharmony_ci
192cabdff1aSopenharmony_ci    return 0;
193cabdff1aSopenharmony_ci}
194cabdff1aSopenharmony_ci
195cabdff1aSopenharmony_ciconst struct ogg_codec ff_ogm_video_codec = {
196cabdff1aSopenharmony_ci    .magic = "\001video",
197cabdff1aSopenharmony_ci    .magicsize = 6,
198cabdff1aSopenharmony_ci    .header = ogm_header,
199cabdff1aSopenharmony_ci    .packet = ogm_packet,
200cabdff1aSopenharmony_ci    .granule_is_start = 1,
201cabdff1aSopenharmony_ci    .nb_header = 2,
202cabdff1aSopenharmony_ci};
203cabdff1aSopenharmony_ci
204cabdff1aSopenharmony_ciconst struct ogg_codec ff_ogm_audio_codec = {
205cabdff1aSopenharmony_ci    .magic = "\001audio",
206cabdff1aSopenharmony_ci    .magicsize = 6,
207cabdff1aSopenharmony_ci    .header = ogm_header,
208cabdff1aSopenharmony_ci    .packet = ogm_packet,
209cabdff1aSopenharmony_ci    .granule_is_start = 1,
210cabdff1aSopenharmony_ci    .nb_header = 2,
211cabdff1aSopenharmony_ci};
212cabdff1aSopenharmony_ci
213cabdff1aSopenharmony_ciconst struct ogg_codec ff_ogm_text_codec = {
214cabdff1aSopenharmony_ci    .magic = "\001text",
215cabdff1aSopenharmony_ci    .magicsize = 5,
216cabdff1aSopenharmony_ci    .header = ogm_header,
217cabdff1aSopenharmony_ci    .packet = ogm_packet,
218cabdff1aSopenharmony_ci    .granule_is_start = 1,
219cabdff1aSopenharmony_ci    .nb_header = 2,
220cabdff1aSopenharmony_ci};
221cabdff1aSopenharmony_ci
222cabdff1aSopenharmony_ciconst struct ogg_codec ff_ogm_old_codec = {
223cabdff1aSopenharmony_ci    .magic = "\001Direct Show Samples embedded in Ogg",
224cabdff1aSopenharmony_ci    .magicsize = 35,
225cabdff1aSopenharmony_ci    .header = ogm_dshow_header,
226cabdff1aSopenharmony_ci    .packet = ogm_packet,
227cabdff1aSopenharmony_ci    .granule_is_start = 1,
228cabdff1aSopenharmony_ci    .nb_header = 1,
229cabdff1aSopenharmony_ci};
230