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/get_bits.h"
29#include "libavcodec/bytestream.h"
30#include "avformat.h"
31#include "oggdec.h"
32
33static int ogm_chapter(AVFormatContext *as, uint8_t *key, uint8_t *val)
34{
35    int i, cnum, h, m, s, ms, keylen = strlen(key);
36    AVChapter *chapter = NULL;
37
38    if (keylen < 9 || sscanf(key, "CHAPTER%02d", &cnum) != 1)
39        return 0;
40
41    if (keylen == 9) {
42        if (sscanf(val, "%02d:%02d:%02d.%03d", &h, &m, &s, &ms) < 4)
43            return 0;
44
45        ff_new_chapter(as, cnum, (AVRational){1,1000},
46                       ms + 1000*(s + 60*(m + 60*h)),
47                       AV_NOPTS_VALUE, NULL);
48        av_free(val);
49    } else if (!strcmp(key+9, "NAME")) {
50        for(i = 0; i < as->nb_chapters; i++)
51            if (as->chapters[i]->id == cnum) {
52                chapter = as->chapters[i];
53                break;
54            }
55        if (!chapter)
56            return 0;
57
58        av_metadata_set2(&chapter->metadata, "title", val,
59                         AV_METADATA_DONT_STRDUP_VAL);
60    } else
61        return 0;
62
63    av_free(key);
64    return 1;
65}
66
67int
68ff_vorbis_comment(AVFormatContext * as, AVMetadata **m, const uint8_t *buf, int size)
69{
70    const uint8_t *p = buf;
71    const uint8_t *end = buf + size;
72    unsigned n, j;
73    int s;
74
75    if (size < 8) /* must have vendor_length and user_comment_list_length */
76        return -1;
77
78    s = bytestream_get_le32(&p);
79
80    if (end - p - 4 < s || s < 0)
81        return -1;
82
83    p += s;
84
85    n = bytestream_get_le32(&p);
86
87    while (end - p >= 4 && n > 0) {
88        const char *t, *v;
89        int tl, vl;
90
91        s = bytestream_get_le32(&p);
92
93        if (end - p < s || s < 0)
94            break;
95
96        t = p;
97        p += s;
98        n--;
99
100        v = memchr(t, '=', s);
101        if (!v)
102            continue;
103
104        tl = v - t;
105        vl = s - tl - 1;
106        v++;
107
108        if (tl && vl) {
109            char *tt, *ct;
110
111            tt = av_malloc(tl + 1);
112            ct = av_malloc(vl + 1);
113            if (!tt || !ct) {
114                av_freep(&tt);
115                av_freep(&ct);
116                av_log(as, AV_LOG_WARNING, "out-of-memory error. skipping VorbisComment tag.\n");
117                continue;
118            }
119
120            for (j = 0; j < tl; j++)
121                tt[j] = toupper(t[j]);
122            tt[tl] = 0;
123
124            memcpy(ct, v, vl);
125            ct[vl] = 0;
126
127            if (!ogm_chapter(as, tt, ct))
128                av_metadata_set2(m, tt, ct,
129                                   AV_METADATA_DONT_STRDUP_KEY |
130                                   AV_METADATA_DONT_STRDUP_VAL);
131        }
132    }
133
134    if (p != end)
135        av_log(as, AV_LOG_INFO, "%ti bytes of comment header remain\n", end-p);
136    if (n > 0)
137        av_log(as, AV_LOG_INFO,
138               "truncated comment header, %i comments not found\n", n);
139
140    return 0;
141}
142
143
144/** Parse the vorbis header
145 * Vorbis Identification header from Vorbis_I_spec.html#vorbis-spec-codec
146 * [vorbis_version] = read 32 bits as unsigned integer | Not used
147 * [audio_channels] = read 8 bit integer as unsigned | Used
148 * [audio_sample_rate] = read 32 bits as unsigned integer | Used
149 * [bitrate_maximum] = read 32 bits as signed integer | Not used yet
150 * [bitrate_nominal] = read 32 bits as signed integer | Not used yet
151 * [bitrate_minimum] = read 32 bits as signed integer | Used as bitrate
152 * [blocksize_0] = read 4 bits as unsigned integer | Not Used
153 * [blocksize_1] = read 4 bits as unsigned integer | Not Used
154 * [framing_flag] = read one bit | Not Used
155 *    */
156
157struct oggvorbis_private {
158    unsigned int len[3];
159    unsigned char *packet[3];
160};
161
162
163static unsigned int
164fixup_vorbis_headers(AVFormatContext * as, struct oggvorbis_private *priv,
165                     uint8_t **buf)
166{
167    int i,offset, len;
168    unsigned char *ptr;
169
170    len = priv->len[0] + priv->len[1] + priv->len[2];
171    ptr = *buf = av_mallocz(len + len/255 + 64);
172
173    ptr[0] = 2;
174    offset = 1;
175    offset += av_xiphlacing(&ptr[offset], priv->len[0]);
176    offset += av_xiphlacing(&ptr[offset], priv->len[1]);
177    for (i = 0; i < 3; i++) {
178        memcpy(&ptr[offset], priv->packet[i], priv->len[i]);
179        offset += priv->len[i];
180        av_freep(&priv->packet[i]);
181    }
182    *buf = av_realloc(*buf, offset + FF_INPUT_BUFFER_PADDING_SIZE);
183    return offset;
184}
185
186
187static int
188vorbis_header (AVFormatContext * s, int idx)
189{
190    struct ogg *ogg = s->priv_data;
191    struct ogg_stream *os = ogg->streams + idx;
192    AVStream *st = s->streams[idx];
193    struct oggvorbis_private *priv;
194    int pkt_type = os->buf[os->pstart];
195
196    if (!(pkt_type & 1))
197        return 0;
198
199    if (!os->private) {
200        os->private = av_mallocz(sizeof(struct oggvorbis_private));
201        if (!os->private)
202            return 0;
203    }
204
205    if (os->psize < 1 || pkt_type > 5)
206        return -1;
207
208    priv = os->private;
209    priv->len[pkt_type >> 1] = os->psize;
210    priv->packet[pkt_type >> 1] = av_mallocz(os->psize);
211    memcpy(priv->packet[pkt_type >> 1], os->buf + os->pstart, os->psize);
212    if (os->buf[os->pstart] == 1) {
213        const uint8_t *p = os->buf + os->pstart + 7; /* skip "\001vorbis" tag */
214        unsigned blocksize, bs0, bs1;
215
216        if (os->psize != 30)
217            return -1;
218
219        if (bytestream_get_le32(&p) != 0) /* vorbis_version */
220            return -1;
221
222        st->codec->channels = bytestream_get_byte(&p);
223        st->codec->sample_rate = bytestream_get_le32(&p);
224        p += 4; // skip maximum bitrate
225        st->codec->bit_rate = bytestream_get_le32(&p); // nominal bitrate
226        p += 4; // skip minimum bitrate
227
228        blocksize = bytestream_get_byte(&p);
229        bs0 = blocksize & 15;
230        bs1 = blocksize >> 4;
231
232        if (bs0 > bs1)
233            return -1;
234        if (bs0 < 6 || bs1 > 13)
235            return -1;
236
237        if (bytestream_get_byte(&p) != 1) /* framing_flag */
238            return -1;
239
240        st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
241        st->codec->codec_id = CODEC_ID_VORBIS;
242
243        st->time_base.num = 1;
244        st->time_base.den = st->codec->sample_rate;
245    } else if (os->buf[os->pstart] == 3) {
246        if (os->psize > 8)
247            ff_vorbis_comment (s, &st->metadata, os->buf + os->pstart + 7, os->psize - 8);
248    } else {
249        st->codec->extradata_size =
250            fixup_vorbis_headers(s, priv, &st->codec->extradata);
251    }
252
253    return 1;
254}
255
256const struct ogg_codec ff_vorbis_codec = {
257    .magic = "\001vorbis",
258    .magicsize = 7,
259    .header = vorbis_header
260};
261