]> rtime.felk.cvut.cz Git - frescor/ffmpeg.git/blob - libavformat/oggparsevorbis.c
check values more thoroughly in vorbis_header()
[frescor/ffmpeg.git] / libavformat / oggparsevorbis.c
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 "avformat.h"
27 #include "bitstream.h"
28 #include "bytestream.h"
29 #include "bswap.h"
30 #include "ogg2.h"
31 #include "avstring.h"
32
33 extern int
34 vorbis_comment(AVFormatContext * as, uint8_t *buf, int size)
35 {
36     uint8_t *p = buf;
37     unsigned s, n, j;
38
39     if (size < 8) /* must have vendor_length and user_comment_list_length */
40         return -1;
41
42     s = AV_RL32(p);
43     p += 4;
44     size -= 4;
45
46     if (size - 4 < s)
47         return -1;
48
49     p += s;
50     size -= s;
51
52     n = AV_RL32(p);
53     p += 4;
54     size -= 4;
55
56     while (size >= 4) {
57         char *t, *v;
58         int tl, vl;
59
60         s = AV_RL32(p);
61         p += 4;
62         size -= 4;
63
64         if (size < s)
65             break;
66
67         t = p;
68         p += s;
69         size -= s;
70         n--;
71
72         v = memchr(t, '=', s);
73         if (!v)
74             continue;
75
76         tl = v - t;
77         vl = s - tl - 1;
78         v++;
79
80         if (tl && vl) {
81             char tt[tl + 1];
82             char ct[vl + 1];
83
84             for (j = 0; j < tl; j++)
85                 tt[j] = toupper(t[j]);
86             tt[tl] = 0;
87
88             memcpy(ct, v, vl);
89             ct[vl] = 0;
90
91             // took from Vorbis_I_spec
92             if (!strcmp(tt, "AUTHOR") || !strcmp(tt, "ARTIST"))
93                 av_strlcpy(as->author, ct, sizeof(as->author));
94             else if (!strcmp(tt, "TITLE"))
95                 av_strlcpy(as->title, ct, sizeof(as->title));
96             else if (!strcmp(tt, "COPYRIGHT"))
97                 av_strlcpy(as->copyright, ct, sizeof(as->copyright));
98             else if (!strcmp(tt, "DESCRIPTION"))
99                 av_strlcpy(as->comment, ct, sizeof(as->comment));
100             else if (!strcmp(tt, "GENRE"))
101                 av_strlcpy(as->genre, ct, sizeof(as->genre));
102             else if (!strcmp(tt, "TRACKNUMBER"))
103                 as->track = atoi(ct);
104             else if (!strcmp(tt, "ALBUM"))
105                 av_strlcpy(as->album, ct, sizeof(as->album));
106         }
107     }
108
109     if (size > 0)
110         av_log(as, AV_LOG_INFO, "%i bytes of comment header remain\n", size);
111     if (n > 0)
112         av_log(as, AV_LOG_INFO,
113                "truncated comment header, %i comments not found\n", n);
114
115     return 0;
116 }
117
118
119 /** Parse the vorbis header
120  * Vorbis Identification header from Vorbis_I_spec.html#vorbis-spec-codec
121  * [vorbis_version] = read 32 bits as unsigned integer | Not used
122  * [audio_channels] = read 8 bit integer as unsigned | Used
123  * [audio_sample_rate] = read 32 bits as unsigned integer | Used
124  * [bitrate_maximum] = read 32 bits as signed integer | Not used yet
125  * [bitrate_nominal] = read 32 bits as signed integer | Not used yet
126  * [bitrate_minimum] = read 32 bits as signed integer | Used as bitrate
127  * [blocksize_0] = read 4 bits as unsigned integer | Not Used
128  * [blocksize_1] = read 4 bits as unsigned integer | Not Used
129  * [framing_flag] = read one bit | Not Used
130  *    */
131
132 typedef struct {
133     unsigned int len[3];
134     unsigned char *packet[3];
135 } oggvorbis_private_t;
136
137
138 static unsigned int
139 fixup_vorbis_headers(AVFormatContext * as, oggvorbis_private_t *priv,
140                      uint8_t **buf)
141 {
142     int i,offset, len;
143     unsigned char *ptr;
144
145     len = priv->len[0] + priv->len[1] + priv->len[2];
146     ptr = *buf = av_mallocz(len + len/255 + 64);
147
148     ptr[0] = 2;
149     offset = 1;
150     offset += av_xiphlacing(&ptr[offset], priv->len[0]);
151     offset += av_xiphlacing(&ptr[offset], priv->len[1]);
152     for (i = 0; i < 3; i++) {
153         memcpy(&ptr[offset], priv->packet[i], priv->len[i]);
154         offset += priv->len[i];
155     }
156     *buf = av_realloc(*buf, offset);
157     return offset;
158 }
159
160
161 static int
162 vorbis_header (AVFormatContext * s, int idx)
163 {
164     ogg_t *ogg = s->priv_data;
165     ogg_stream_t *os = ogg->streams + idx;
166     AVStream *st = s->streams[idx];
167     oggvorbis_private_t *priv;
168
169     if (os->seq > 2)
170         return 0;
171
172     if (os->seq == 0) {
173         os->private = av_mallocz(sizeof(oggvorbis_private_t));
174         if (!os->private)
175             return 0;
176     }
177
178     if (os->psize < 1)
179         return -1;
180
181     priv = os->private;
182     priv->len[os->seq] = os->psize;
183     priv->packet[os->seq] = av_mallocz(os->psize);
184     memcpy(priv->packet[os->seq], os->buf + os->pstart, os->psize);
185     if (os->buf[os->pstart] == 1) {
186         uint8_t *p = os->buf + os->pstart + 7; /* skip "\001vorbis" tag */
187         unsigned blocksize, bs0, bs1;
188
189         if (os->psize != 30)
190             return -1;
191
192         if (bytestream_get_le32(&p) != 0) /* vorbis_version */
193             return -1;
194
195         st->codec->channels = bytestream_get_byte(&p);
196         st->codec->sample_rate = bytestream_get_le32(&p);
197         p += 4; // skip maximum bitrate
198         st->codec->bit_rate = bytestream_get_le32(&p); // nominal bitrate
199         p += 4; // skip minimum bitrate
200
201         blocksize = bytestream_get_byte(&p);
202         bs0 = blocksize & 15;
203         bs1 = blocksize >> 4;
204
205         if (bs0 > bs1)
206             return -1;
207         if (bs0 < 6 || bs1 > 13)
208             return -1;
209
210         if (bytestream_get_byte(&p) != 1) /* framing_flag */
211             return -1;
212
213         st->codec->codec_type = CODEC_TYPE_AUDIO;
214         st->codec->codec_id = CODEC_ID_VORBIS;
215
216         st->time_base.num = 1;
217         st->time_base.den = st->codec->sample_rate;
218     } else if (os->buf[os->pstart] == 3) {
219         if (os->psize > 8)
220             vorbis_comment (s, os->buf + os->pstart + 7, os->psize - 8);
221     } else {
222         st->codec->extradata_size =
223             fixup_vorbis_headers(s, priv, &st->codec->extradata);
224     }
225
226     return os->seq < 3;
227 }
228
229 ogg_codec_t vorbis_codec = {
230     .magic = "\001vorbis",
231     .magicsize = 7,
232     .header = vorbis_header
233 };