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