1/**
2      Copyright (C) 2005  Michael Ahlberg, M��ns Rullg��rd
3
4      Permission is hereby granted, free of charge, to any person
5      obtaining a copy of this software and associated documentation
6      files (the "Software"), to deal in the Software without
7      restriction, including without limitation the rights to use, copy,
8      modify, merge, publish, distribute, sublicense, and/or sell copies
9      of the Software, and to permit persons to whom the Software is
10      furnished to do so, subject to the following conditions:
11
12      The above copyright notice and this permission notice shall be
13      included in all copies or substantial portions of the Software.
14
15      THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16      EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17      MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18      NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19      HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20      WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21      OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22      DEALINGS IN THE SOFTWARE.
23**/
24
25#include <stdlib.h>
26#include "libavutil/avstring.h"
27#include "libavutil/bswap.h"
28#include "libavcodec/bitstream.h"
29#include "libavcodec/bytestream.h"
30#include "avformat.h"
31#include "oggdec.h"
32
33int
34vorbis_comment(AVFormatContext * as, uint8_t *buf, int size)
35{
36    const uint8_t *p = buf;
37    const uint8_t *end = buf + size;
38    unsigned n, j;
39    int s;
40
41    if (size < 8) /* must have vendor_length and user_comment_list_length */
42        return -1;
43
44    s = bytestream_get_le32(&p);
45
46    if (end - p - 4 < s || s < 0)
47        return -1;
48
49    p += s;
50
51    n = bytestream_get_le32(&p);
52
53    while (end - p >= 4 && n > 0) {
54        const char *t, *v;
55        int tl, vl;
56
57        s = bytestream_get_le32(&p);
58
59        if (end - p < s || s < 0)
60            break;
61
62        t = p;
63        p += s;
64        n--;
65
66        v = memchr(t, '=', s);
67        if (!v)
68            continue;
69
70        tl = v - t;
71        vl = s - tl - 1;
72        v++;
73
74        if (tl && vl) {
75            char *tt, *ct;
76
77            tt = av_malloc(tl + 1);
78            ct = av_malloc(vl + 1);
79            if (!tt || !ct) {
80                av_freep(&tt);
81                av_freep(&ct);
82                av_log(as, AV_LOG_WARNING, "out-of-memory error. skipping VorbisComment tag.\n");
83                continue;
84            }
85
86            for (j = 0; j < tl; j++)
87                tt[j] = toupper(t[j]);
88            tt[tl] = 0;
89
90            memcpy(ct, v, vl);
91            ct[vl] = 0;
92
93            av_metadata_set(&as->metadata, tt, ct);
94
95            av_freep(&tt);
96            av_freep(&ct);
97        }
98    }
99
100    if (p != end)
101        av_log(as, AV_LOG_INFO, "%ti bytes of comment header remain\n", p-end);
102    if (n > 0)
103        av_log(as, AV_LOG_INFO,
104               "truncated comment header, %i comments not found\n", n);
105
106    return 0;
107}
108
109
110/** Parse the vorbis header
111 * Vorbis Identification header from Vorbis_I_spec.html#vorbis-spec-codec
112 * [vorbis_version] = read 32 bits as unsigned integer | Not used
113 * [audio_channels] = read 8 bit integer as unsigned | Used
114 * [audio_sample_rate] = read 32 bits as unsigned integer | Used
115 * [bitrate_maximum] = read 32 bits as signed integer | Not used yet
116 * [bitrate_nominal] = read 32 bits as signed integer | Not used yet
117 * [bitrate_minimum] = read 32 bits as signed integer | Used as bitrate
118 * [blocksize_0] = read 4 bits as unsigned integer | Not Used
119 * [blocksize_1] = read 4 bits as unsigned integer | Not Used
120 * [framing_flag] = read one bit | Not Used
121 *    */
122
123struct oggvorbis_private {
124    unsigned int len[3];
125    unsigned char *packet[3];
126};
127
128
129static unsigned int
130fixup_vorbis_headers(AVFormatContext * as, struct oggvorbis_private *priv,
131                     uint8_t **buf)
132{
133    int i,offset, len;
134    unsigned char *ptr;
135
136    len = priv->len[0] + priv->len[1] + priv->len[2];
137    ptr = *buf = av_mallocz(len + len/255 + 64);
138
139    ptr[0] = 2;
140    offset = 1;
141    offset += av_xiphlacing(&ptr[offset], priv->len[0]);
142    offset += av_xiphlacing(&ptr[offset], priv->len[1]);
143    for (i = 0; i < 3; i++) {
144        memcpy(&ptr[offset], priv->packet[i], priv->len[i]);
145        offset += priv->len[i];
146    }
147    *buf = av_realloc(*buf, offset + FF_INPUT_BUFFER_PADDING_SIZE);
148    return offset;
149}
150
151
152static int
153vorbis_header (AVFormatContext * s, int idx)
154{
155    struct ogg *ogg = s->priv_data;
156    struct ogg_stream *os = ogg->streams + idx;
157    AVStream *st = s->streams[idx];
158    struct oggvorbis_private *priv;
159
160    if (os->seq > 2)
161        return 0;
162
163    if (os->seq == 0) {
164        os->private = av_mallocz(sizeof(struct oggvorbis_private));
165        if (!os->private)
166            return 0;
167    }
168
169    if (os->psize < 1)
170        return -1;
171
172    priv = os->private;
173    priv->len[os->seq] = os->psize;
174    priv->packet[os->seq] = av_mallocz(os->psize);
175    memcpy(priv->packet[os->seq], os->buf + os->pstart, os->psize);
176    if (os->buf[os->pstart] == 1) {
177        const uint8_t *p = os->buf + os->pstart + 7; /* skip "\001vorbis" tag */
178        unsigned blocksize, bs0, bs1;
179
180        if (os->psize != 30)
181            return -1;
182
183        if (bytestream_get_le32(&p) != 0) /* vorbis_version */
184            return -1;
185
186        st->codec->channels = bytestream_get_byte(&p);
187        st->codec->sample_rate = bytestream_get_le32(&p);
188        p += 4; // skip maximum bitrate
189        st->codec->bit_rate = bytestream_get_le32(&p); // nominal bitrate
190        p += 4; // skip minimum bitrate
191
192        blocksize = bytestream_get_byte(&p);
193        bs0 = blocksize & 15;
194        bs1 = blocksize >> 4;
195
196        if (bs0 > bs1)
197            return -1;
198        if (bs0 < 6 || bs1 > 13)
199            return -1;
200
201        if (bytestream_get_byte(&p) != 1) /* framing_flag */
202            return -1;
203
204        st->codec->codec_type = CODEC_TYPE_AUDIO;
205        st->codec->codec_id = CODEC_ID_VORBIS;
206
207        st->time_base.num = 1;
208        st->time_base.den = st->codec->sample_rate;
209    } else if (os->buf[os->pstart] == 3) {
210        if (os->psize > 8)
211            vorbis_comment (s, os->buf + os->pstart + 7, os->psize - 8);
212    } else {
213        st->codec->extradata_size =
214            fixup_vorbis_headers(s, priv, &st->codec->extradata);
215    }
216
217    return os->seq < 3;
218}
219
220const struct ogg_codec ff_vorbis_codec = {
221    .magic = "\001vorbis",
222    .magicsize = 7,
223    .header = vorbis_header
224};
225