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