Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
6147 | serge | 1 | /* |
2 | * Ogg muxer |
||
3 | * Copyright (c) 2007 Baptiste Coudurier |
||
4 | * |
||
5 | * This file is part of FFmpeg. |
||
6 | * |
||
7 | * FFmpeg is free software; you can redistribute it and/or |
||
8 | * modify it under the terms of the GNU Lesser General Public |
||
9 | * License as published by the Free Software Foundation; either |
||
10 | * version 2.1 of the License, or (at your option) any later version. |
||
11 | * |
||
12 | * FFmpeg is distributed in the hope that it will be useful, |
||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||
15 | * Lesser General Public License for more details. |
||
16 | * |
||
17 | * You should have received a copy of the GNU Lesser General Public |
||
18 | * License along with FFmpeg; if not, write to the Free Software |
||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||
20 | */ |
||
21 | |||
22 | #include |
||
23 | |||
24 | #include "libavutil/crc.h" |
||
25 | #include "libavutil/mathematics.h" |
||
26 | #include "libavutil/opt.h" |
||
27 | #include "libavutil/random_seed.h" |
||
28 | #include "libavcodec/xiph.h" |
||
29 | #include "libavcodec/bytestream.h" |
||
30 | #include "libavcodec/flac.h" |
||
31 | #include "avformat.h" |
||
32 | #include "avio_internal.h" |
||
33 | #include "internal.h" |
||
34 | #include "vorbiscomment.h" |
||
35 | |||
36 | #define MAX_PAGE_SIZE 65025 |
||
37 | |||
38 | typedef struct OGGPage { |
||
39 | int64_t start_granule; |
||
40 | int64_t granule; |
||
41 | int stream_index; |
||
42 | uint8_t flags; |
||
43 | uint8_t segments_count; |
||
44 | uint8_t segments[255]; |
||
45 | uint8_t data[MAX_PAGE_SIZE]; |
||
46 | uint16_t size; |
||
47 | } OGGPage; |
||
48 | |||
49 | typedef struct OGGStreamContext { |
||
50 | unsigned page_counter; |
||
51 | uint8_t *header[3]; |
||
52 | int header_len[3]; |
||
53 | /** for theora granule */ |
||
54 | int kfgshift; |
||
55 | int64_t last_kf_pts; |
||
56 | int vrev; |
||
57 | int eos; |
||
58 | unsigned page_count; ///< number of page buffered |
||
59 | OGGPage page; ///< current page |
||
60 | unsigned serial_num; ///< serial number |
||
61 | int64_t last_granule; ///< last packet granule |
||
62 | } OGGStreamContext; |
||
63 | |||
64 | typedef struct OGGPageList { |
||
65 | OGGPage page; |
||
66 | struct OGGPageList *next; |
||
67 | } OGGPageList; |
||
68 | |||
69 | typedef struct OGGContext { |
||
70 | const AVClass *class; |
||
71 | OGGPageList *page_list; |
||
72 | int pref_size; ///< preferred page size (0 => fill all segments) |
||
73 | int64_t pref_duration; ///< preferred page duration (0 => fill all segments) |
||
74 | int serial_offset; |
||
75 | } OGGContext; |
||
76 | |||
77 | #define OFFSET(x) offsetof(OGGContext, x) |
||
78 | #define PARAM AV_OPT_FLAG_ENCODING_PARAM |
||
79 | |||
80 | static const AVOption options[] = { |
||
81 | { "serial_offset", "serial number offset", |
||
82 | OFFSET(serial_offset), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, PARAM }, |
||
83 | { "oggpagesize", "Set preferred Ogg page size.", |
||
84 | OFFSET(pref_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, MAX_PAGE_SIZE, PARAM}, |
||
85 | { "pagesize", "preferred page size in bytes (deprecated)", |
||
86 | OFFSET(pref_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, MAX_PAGE_SIZE, PARAM }, |
||
87 | { "page_duration", "preferred page duration, in microseconds", |
||
88 | OFFSET(pref_duration), AV_OPT_TYPE_INT64, { .i64 = 1000000 }, 0, INT64_MAX, PARAM }, |
||
89 | { NULL }, |
||
90 | }; |
||
91 | |||
92 | #define OGG_CLASS(flavor, name)\ |
||
93 | static const AVClass flavor ## _muxer_class = {\ |
||
94 | .class_name = #name " muxer",\ |
||
95 | .item_name = av_default_item_name,\ |
||
96 | .option = options,\ |
||
97 | .version = LIBAVUTIL_VERSION_INT,\ |
||
98 | }; |
||
99 | |||
100 | static void ogg_update_checksum(AVFormatContext *s, AVIOContext *pb, int64_t crc_offset) |
||
101 | { |
||
102 | int64_t pos = avio_tell(pb); |
||
103 | uint32_t checksum = ffio_get_checksum(pb); |
||
104 | avio_seek(pb, crc_offset, SEEK_SET); |
||
105 | avio_wb32(pb, checksum); |
||
106 | avio_seek(pb, pos, SEEK_SET); |
||
107 | } |
||
108 | |||
109 | static int ogg_write_page(AVFormatContext *s, OGGPage *page, int extra_flags) |
||
110 | { |
||
111 | OGGStreamContext *oggstream = s->streams[page->stream_index]->priv_data; |
||
112 | AVIOContext *pb; |
||
113 | int64_t crc_offset; |
||
114 | int ret, size; |
||
115 | uint8_t *buf; |
||
116 | |||
117 | ret = avio_open_dyn_buf(&pb); |
||
118 | if (ret < 0) |
||
119 | return ret; |
||
120 | ffio_init_checksum(pb, ff_crc04C11DB7_update, 0); |
||
121 | ffio_wfourcc(pb, "OggS"); |
||
122 | avio_w8(pb, 0); |
||
123 | avio_w8(pb, page->flags | extra_flags); |
||
124 | avio_wl64(pb, page->granule); |
||
125 | avio_wl32(pb, oggstream->serial_num); |
||
126 | avio_wl32(pb, oggstream->page_counter++); |
||
127 | crc_offset = avio_tell(pb); |
||
128 | avio_wl32(pb, 0); // crc |
||
129 | avio_w8(pb, page->segments_count); |
||
130 | avio_write(pb, page->segments, page->segments_count); |
||
131 | avio_write(pb, page->data, page->size); |
||
132 | |||
133 | ogg_update_checksum(s, pb, crc_offset); |
||
134 | avio_flush(pb); |
||
135 | |||
136 | size = avio_close_dyn_buf(pb, &buf); |
||
137 | if (size < 0) |
||
138 | return size; |
||
139 | |||
140 | avio_write(s->pb, buf, size); |
||
141 | avio_flush(s->pb); |
||
142 | av_free(buf); |
||
143 | oggstream->page_count--; |
||
144 | return 0; |
||
145 | } |
||
146 | |||
147 | static int ogg_key_granule(OGGStreamContext *oggstream, int64_t granule) |
||
148 | { |
||
149 | return oggstream->kfgshift && !(granule & ((1< |
||
150 | } |
||
151 | |||
152 | static int64_t ogg_granule_to_timestamp(OGGStreamContext *oggstream, int64_t granule) |
||
153 | { |
||
154 | if (oggstream->kfgshift) |
||
155 | return (granule>>oggstream->kfgshift) + |
||
156 | (granule & ((1< |
||
157 | else |
||
158 | return granule; |
||
159 | } |
||
160 | |||
161 | static int ogg_compare_granule(AVFormatContext *s, OGGPage *next, OGGPage *page) |
||
162 | { |
||
163 | AVStream *st2 = s->streams[next->stream_index]; |
||
164 | AVStream *st = s->streams[page->stream_index]; |
||
165 | int64_t next_granule, cur_granule; |
||
166 | |||
167 | if (next->granule == -1 || page->granule == -1) |
||
168 | return 0; |
||
169 | |||
170 | next_granule = av_rescale_q(ogg_granule_to_timestamp(st2->priv_data, next->granule), |
||
171 | st2->time_base, AV_TIME_BASE_Q); |
||
172 | cur_granule = av_rescale_q(ogg_granule_to_timestamp(st->priv_data, page->granule), |
||
173 | st ->time_base, AV_TIME_BASE_Q); |
||
174 | return next_granule > cur_granule; |
||
175 | } |
||
176 | |||
177 | static int ogg_reset_cur_page(OGGStreamContext *oggstream) |
||
178 | { |
||
179 | oggstream->page.granule = -1; |
||
180 | oggstream->page.flags = 0; |
||
181 | oggstream->page.segments_count = 0; |
||
182 | oggstream->page.size = 0; |
||
183 | return 0; |
||
184 | } |
||
185 | |||
186 | static int ogg_buffer_page(AVFormatContext *s, OGGStreamContext *oggstream) |
||
187 | { |
||
188 | OGGContext *ogg = s->priv_data; |
||
189 | OGGPageList **p = &ogg->page_list; |
||
190 | OGGPageList *l = av_mallocz(sizeof(*l)); |
||
191 | |||
192 | if (!l) |
||
193 | return AVERROR(ENOMEM); |
||
194 | l->page = oggstream->page; |
||
195 | |||
196 | oggstream->page.start_granule = oggstream->page.granule; |
||
197 | oggstream->page_count++; |
||
198 | ogg_reset_cur_page(oggstream); |
||
199 | |||
200 | while (*p) { |
||
201 | if (ogg_compare_granule(s, &(*p)->page, &l->page)) |
||
202 | break; |
||
203 | p = &(*p)->next; |
||
204 | } |
||
205 | l->next = *p; |
||
206 | *p = l; |
||
207 | |||
208 | return 0; |
||
209 | } |
||
210 | |||
211 | static int ogg_buffer_data(AVFormatContext *s, AVStream *st, |
||
212 | uint8_t *data, unsigned size, int64_t granule, |
||
213 | int header) |
||
214 | { |
||
215 | OGGStreamContext *oggstream = st->priv_data; |
||
216 | OGGContext *ogg = s->priv_data; |
||
217 | int total_segments = size / 255 + 1; |
||
218 | uint8_t *p = data; |
||
219 | int i, segments, len, flush = 0; |
||
220 | |||
221 | // Handles VFR by flushing page because this frame needs to have a timestamp |
||
222 | // For theora, keyframes also need to have a timestamp to correctly mark |
||
223 | // them as such, otherwise seeking will not work correctly at the very |
||
224 | // least with old libogg versions. |
||
225 | // Do not try to flush header packets though, that will create broken files. |
||
226 | if (st->codec->codec_id == AV_CODEC_ID_THEORA && !header && |
||
227 | (ogg_granule_to_timestamp(oggstream, granule) > |
||
228 | ogg_granule_to_timestamp(oggstream, oggstream->last_granule) + 1 || |
||
229 | ogg_key_granule(oggstream, granule))) { |
||
230 | if (oggstream->page.granule != -1) |
||
231 | ogg_buffer_page(s, oggstream); |
||
232 | flush = 1; |
||
233 | } |
||
234 | |||
235 | // avoid a continued page |
||
236 | if (!header && oggstream->page.size > 0 && |
||
237 | MAX_PAGE_SIZE - oggstream->page.size < size) { |
||
238 | ogg_buffer_page(s, oggstream); |
||
239 | } |
||
240 | |||
241 | for (i = 0; i < total_segments; ) { |
||
242 | OGGPage *page = &oggstream->page; |
||
243 | |||
244 | segments = FFMIN(total_segments - i, 255 - page->segments_count); |
||
245 | |||
246 | if (i && !page->segments_count) |
||
247 | page->flags |= 1; // continued packet |
||
248 | |||
249 | memset(page->segments+page->segments_count, 255, segments - 1); |
||
250 | page->segments_count += segments - 1; |
||
251 | |||
252 | len = FFMIN(size, segments*255); |
||
253 | page->segments[page->segments_count++] = len - (segments-1)*255; |
||
254 | memcpy(page->data+page->size, p, len); |
||
255 | p += len; |
||
256 | size -= len; |
||
257 | i += segments; |
||
258 | page->size += len; |
||
259 | |||
260 | if (i == total_segments) |
||
261 | page->granule = granule; |
||
262 | |||
263 | { |
||
264 | AVStream *st = s->streams[page->stream_index]; |
||
265 | |||
266 | int64_t start = av_rescale_q(page->start_granule, st->time_base, |
||
267 | AV_TIME_BASE_Q); |
||
268 | int64_t next = av_rescale_q(page->granule, st->time_base, |
||
269 | AV_TIME_BASE_Q); |
||
270 | |||
271 | if (page->segments_count == 255) { |
||
272 | ogg_buffer_page(s, oggstream); |
||
273 | } else if (!header) { |
||
274 | if ((ogg->pref_size > 0 && page->size >= ogg->pref_size) || |
||
275 | (ogg->pref_duration > 0 && next - start >= ogg->pref_duration)) { |
||
276 | ogg_buffer_page(s, oggstream); |
||
277 | } |
||
278 | } |
||
279 | } |
||
280 | } |
||
281 | |||
282 | if (flush && oggstream->page.granule != -1) |
||
283 | ogg_buffer_page(s, oggstream); |
||
284 | |||
285 | return 0; |
||
286 | } |
||
287 | |||
288 | static uint8_t *ogg_write_vorbiscomment(int64_t offset, int bitexact, |
||
289 | int *header_len, AVDictionary **m, int framing_bit) |
||
290 | { |
||
291 | const char *vendor = bitexact ? "ffmpeg" : LIBAVFORMAT_IDENT; |
||
292 | int64_t size; |
||
293 | uint8_t *p, *p0; |
||
294 | |||
295 | ff_metadata_conv(m, ff_vorbiscomment_metadata_conv, NULL); |
||
296 | |||
297 | size = offset + ff_vorbiscomment_length(*m, vendor) + framing_bit; |
||
298 | if (size > INT_MAX) |
||
299 | return NULL; |
||
300 | p = av_mallocz(size); |
||
301 | if (!p) |
||
302 | return NULL; |
||
303 | p0 = p; |
||
304 | |||
305 | p += offset; |
||
306 | ff_vorbiscomment_write(&p, m, vendor); |
||
307 | if (framing_bit) |
||
308 | bytestream_put_byte(&p, 1); |
||
309 | |||
310 | *header_len = size; |
||
311 | return p0; |
||
312 | } |
||
313 | |||
314 | static int ogg_build_flac_headers(AVCodecContext *avctx, |
||
315 | OGGStreamContext *oggstream, int bitexact, |
||
316 | AVDictionary **m) |
||
317 | { |
||
318 | uint8_t *p; |
||
319 | |||
320 | if (avctx->extradata_size < FLAC_STREAMINFO_SIZE) |
||
321 | return AVERROR(EINVAL); |
||
322 | |||
323 | // first packet: STREAMINFO |
||
324 | oggstream->header_len[0] = 51; |
||
325 | oggstream->header[0] = av_mallocz(51); // per ogg flac specs |
||
326 | p = oggstream->header[0]; |
||
327 | if (!p) |
||
328 | return AVERROR(ENOMEM); |
||
329 | bytestream_put_byte(&p, 0x7F); |
||
330 | bytestream_put_buffer(&p, "FLAC", 4); |
||
331 | bytestream_put_byte(&p, 1); // major version |
||
332 | bytestream_put_byte(&p, 0); // minor version |
||
333 | bytestream_put_be16(&p, 1); // headers packets without this one |
||
334 | bytestream_put_buffer(&p, "fLaC", 4); |
||
335 | bytestream_put_byte(&p, 0x00); // streaminfo |
||
336 | bytestream_put_be24(&p, 34); |
||
337 | bytestream_put_buffer(&p, avctx->extradata, FLAC_STREAMINFO_SIZE); |
||
338 | |||
339 | // second packet: VorbisComment |
||
340 | p = ogg_write_vorbiscomment(4, bitexact, &oggstream->header_len[1], m, 0); |
||
341 | if (!p) |
||
342 | return AVERROR(ENOMEM); |
||
343 | oggstream->header[1] = p; |
||
344 | bytestream_put_byte(&p, 0x84); // last metadata block and vorbis comment |
||
345 | bytestream_put_be24(&p, oggstream->header_len[1] - 4); |
||
346 | |||
347 | return 0; |
||
348 | } |
||
349 | |||
350 | #define SPEEX_HEADER_SIZE 80 |
||
351 | |||
352 | static int ogg_build_speex_headers(AVCodecContext *avctx, |
||
353 | OGGStreamContext *oggstream, int bitexact, |
||
354 | AVDictionary **m) |
||
355 | { |
||
356 | uint8_t *p; |
||
357 | |||
358 | if (avctx->extradata_size < SPEEX_HEADER_SIZE) |
||
359 | return AVERROR_INVALIDDATA; |
||
360 | |||
361 | // first packet: Speex header |
||
362 | p = av_mallocz(SPEEX_HEADER_SIZE); |
||
363 | if (!p) |
||
364 | return AVERROR(ENOMEM); |
||
365 | oggstream->header[0] = p; |
||
366 | oggstream->header_len[0] = SPEEX_HEADER_SIZE; |
||
367 | bytestream_put_buffer(&p, avctx->extradata, SPEEX_HEADER_SIZE); |
||
368 | AV_WL32(&oggstream->header[0][68], 0); // set extra_headers to 0 |
||
369 | |||
370 | // second packet: VorbisComment |
||
371 | p = ogg_write_vorbiscomment(0, bitexact, &oggstream->header_len[1], m, 0); |
||
372 | if (!p) |
||
373 | return AVERROR(ENOMEM); |
||
374 | oggstream->header[1] = p; |
||
375 | |||
376 | return 0; |
||
377 | } |
||
378 | |||
379 | #define OPUS_HEADER_SIZE 19 |
||
380 | |||
381 | static int ogg_build_opus_headers(AVCodecContext *avctx, |
||
382 | OGGStreamContext *oggstream, int bitexact, |
||
383 | AVDictionary **m) |
||
384 | { |
||
385 | uint8_t *p; |
||
386 | |||
387 | if (avctx->extradata_size < OPUS_HEADER_SIZE) |
||
388 | return AVERROR_INVALIDDATA; |
||
389 | |||
390 | /* first packet: Opus header */ |
||
391 | p = av_mallocz(avctx->extradata_size); |
||
392 | if (!p) |
||
393 | return AVERROR(ENOMEM); |
||
394 | oggstream->header[0] = p; |
||
395 | oggstream->header_len[0] = avctx->extradata_size; |
||
396 | bytestream_put_buffer(&p, avctx->extradata, avctx->extradata_size); |
||
397 | |||
398 | /* second packet: VorbisComment */ |
||
399 | p = ogg_write_vorbiscomment(8, bitexact, &oggstream->header_len[1], m, 0); |
||
400 | if (!p) |
||
401 | return AVERROR(ENOMEM); |
||
402 | oggstream->header[1] = p; |
||
403 | bytestream_put_buffer(&p, "OpusTags", 8); |
||
404 | |||
405 | return 0; |
||
406 | } |
||
407 | |||
408 | static void ogg_write_pages(AVFormatContext *s, int flush) |
||
409 | { |
||
410 | OGGContext *ogg = s->priv_data; |
||
411 | OGGPageList *next, *p; |
||
412 | |||
413 | if (!ogg->page_list) |
||
414 | return; |
||
415 | |||
416 | for (p = ogg->page_list; p; ) { |
||
417 | OGGStreamContext *oggstream = |
||
418 | s->streams[p->page.stream_index]->priv_data; |
||
419 | if (oggstream->page_count < 2 && !flush) |
||
420 | break; |
||
421 | ogg_write_page(s, &p->page, |
||
422 | flush == 1 && oggstream->page_count == 1 ? 4 : 0); // eos |
||
423 | next = p->next; |
||
424 | av_freep(&p); |
||
425 | p = next; |
||
426 | } |
||
427 | ogg->page_list = p; |
||
428 | } |
||
429 | |||
430 | static int ogg_write_header(AVFormatContext *s) |
||
431 | { |
||
432 | OGGContext *ogg = s->priv_data; |
||
433 | OGGStreamContext *oggstream = NULL; |
||
434 | int i, j; |
||
435 | |||
436 | if (ogg->pref_size) |
||
437 | av_log(s, AV_LOG_WARNING, "The pagesize option is deprecated\n"); |
||
438 | |||
439 | for (i = 0; i < s->nb_streams; i++) { |
||
440 | AVStream *st = s->streams[i]; |
||
441 | unsigned serial_num = i + ogg->serial_offset; |
||
442 | |||
443 | if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { |
||
444 | if (st->codec->codec_id == AV_CODEC_ID_OPUS) |
||
445 | /* Opus requires a fixed 48kHz clock */ |
||
446 | avpriv_set_pts_info(st, 64, 1, 48000); |
||
447 | else |
||
448 | avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate); |
||
449 | } |
||
450 | |||
451 | if (st->codec->codec_id != AV_CODEC_ID_VORBIS && |
||
452 | st->codec->codec_id != AV_CODEC_ID_THEORA && |
||
453 | st->codec->codec_id != AV_CODEC_ID_SPEEX && |
||
454 | st->codec->codec_id != AV_CODEC_ID_FLAC && |
||
455 | st->codec->codec_id != AV_CODEC_ID_OPUS) { |
||
456 | av_log(s, AV_LOG_ERROR, "Unsupported codec id in stream %d\n", i); |
||
457 | return AVERROR(EINVAL); |
||
458 | } |
||
459 | |||
460 | if (!st->codec->extradata || !st->codec->extradata_size) { |
||
461 | av_log(s, AV_LOG_ERROR, "No extradata present\n"); |
||
462 | return AVERROR_INVALIDDATA; |
||
463 | } |
||
464 | oggstream = av_mallocz(sizeof(*oggstream)); |
||
465 | if (!oggstream) |
||
466 | return AVERROR(ENOMEM); |
||
467 | |||
468 | oggstream->page.stream_index = i; |
||
469 | |||
470 | if (!(s->flags & AVFMT_FLAG_BITEXACT)) |
||
471 | do { |
||
472 | serial_num = av_get_random_seed(); |
||
473 | for (j = 0; j < i; j++) { |
||
474 | OGGStreamContext *sc = s->streams[j]->priv_data; |
||
475 | if (serial_num == sc->serial_num) |
||
476 | break; |
||
477 | } |
||
478 | } while (j < i); |
||
479 | oggstream->serial_num = serial_num; |
||
480 | |||
481 | av_dict_copy(&st->metadata, s->metadata, AV_DICT_DONT_OVERWRITE); |
||
482 | |||
483 | st->priv_data = oggstream; |
||
484 | if (st->codec->codec_id == AV_CODEC_ID_FLAC) { |
||
485 | int err = ogg_build_flac_headers(st->codec, oggstream, |
||
486 | s->flags & AVFMT_FLAG_BITEXACT, |
||
487 | &st->metadata); |
||
488 | if (err) { |
||
489 | av_log(s, AV_LOG_ERROR, "Error writing FLAC headers\n"); |
||
490 | av_freep(&st->priv_data); |
||
491 | return err; |
||
492 | } |
||
493 | } else if (st->codec->codec_id == AV_CODEC_ID_SPEEX) { |
||
494 | int err = ogg_build_speex_headers(st->codec, oggstream, |
||
495 | s->flags & AVFMT_FLAG_BITEXACT, |
||
496 | &st->metadata); |
||
497 | if (err) { |
||
498 | av_log(s, AV_LOG_ERROR, "Error writing Speex headers\n"); |
||
499 | av_freep(&st->priv_data); |
||
500 | return err; |
||
501 | } |
||
502 | } else if (st->codec->codec_id == AV_CODEC_ID_OPUS) { |
||
503 | int err = ogg_build_opus_headers(st->codec, oggstream, |
||
504 | s->flags & AVFMT_FLAG_BITEXACT, |
||
505 | &st->metadata); |
||
506 | if (err) { |
||
507 | av_log(s, AV_LOG_ERROR, "Error writing Opus headers\n"); |
||
508 | av_freep(&st->priv_data); |
||
509 | return err; |
||
510 | } |
||
511 | } else { |
||
512 | uint8_t *p; |
||
513 | const char *cstr = st->codec->codec_id == AV_CODEC_ID_VORBIS ? "vorbis" : "theora"; |
||
514 | int header_type = st->codec->codec_id == AV_CODEC_ID_VORBIS ? 3 : 0x81; |
||
515 | int framing_bit = st->codec->codec_id == AV_CODEC_ID_VORBIS ? 1 : 0; |
||
516 | |||
517 | if (avpriv_split_xiph_headers(st->codec->extradata, st->codec->extradata_size, |
||
518 | st->codec->codec_id == AV_CODEC_ID_VORBIS ? 30 : 42, |
||
519 | (const uint8_t**)oggstream->header, oggstream->header_len) < 0) { |
||
520 | av_log(s, AV_LOG_ERROR, "Extradata corrupted\n"); |
||
521 | av_freep(&st->priv_data); |
||
522 | return AVERROR_INVALIDDATA; |
||
523 | } |
||
524 | |||
525 | p = ogg_write_vorbiscomment(7, s->flags & AVFMT_FLAG_BITEXACT, |
||
526 | &oggstream->header_len[1], &st->metadata, |
||
527 | framing_bit); |
||
528 | oggstream->header[1] = p; |
||
529 | if (!p) |
||
530 | return AVERROR(ENOMEM); |
||
531 | |||
532 | bytestream_put_byte(&p, header_type); |
||
533 | bytestream_put_buffer(&p, cstr, 6); |
||
534 | |||
535 | if (st->codec->codec_id == AV_CODEC_ID_THEORA) { |
||
536 | /** KFGSHIFT is the width of the less significant section of the granule position |
||
537 | The less significant section is the frame count since the last keyframe */ |
||
538 | oggstream->kfgshift = ((oggstream->header[0][40]&3)<<3)|(oggstream->header[0][41]>>5); |
||
539 | oggstream->vrev = oggstream->header[0][9]; |
||
540 | av_log(s, AV_LOG_DEBUG, "theora kfgshift %d, vrev %d\n", |
||
541 | oggstream->kfgshift, oggstream->vrev); |
||
542 | } |
||
543 | } |
||
544 | } |
||
545 | |||
546 | for (j = 0; j < s->nb_streams; j++) { |
||
547 | OGGStreamContext *oggstream = s->streams[j]->priv_data; |
||
548 | ogg_buffer_data(s, s->streams[j], oggstream->header[0], |
||
549 | oggstream->header_len[0], 0, 1); |
||
550 | oggstream->page.flags |= 2; // bos |
||
551 | ogg_buffer_page(s, oggstream); |
||
552 | } |
||
553 | for (j = 0; j < s->nb_streams; j++) { |
||
554 | AVStream *st = s->streams[j]; |
||
555 | OGGStreamContext *oggstream = st->priv_data; |
||
556 | for (i = 1; i < 3; i++) { |
||
557 | if (oggstream->header_len[i]) |
||
558 | ogg_buffer_data(s, st, oggstream->header[i], |
||
559 | oggstream->header_len[i], 0, 1); |
||
560 | } |
||
561 | ogg_buffer_page(s, oggstream); |
||
562 | } |
||
563 | |||
564 | oggstream->page.start_granule = AV_NOPTS_VALUE; |
||
565 | |||
566 | ogg_write_pages(s, 2); |
||
567 | |||
568 | return 0; |
||
569 | } |
||
570 | |||
571 | static int ogg_write_packet_internal(AVFormatContext *s, AVPacket *pkt) |
||
572 | { |
||
573 | AVStream *st = s->streams[pkt->stream_index]; |
||
574 | OGGStreamContext *oggstream = st->priv_data; |
||
575 | int ret; |
||
576 | int64_t granule; |
||
577 | |||
578 | if (st->codec->codec_id == AV_CODEC_ID_THEORA) { |
||
579 | int64_t pts = oggstream->vrev < 1 ? pkt->pts : pkt->pts + pkt->duration; |
||
580 | int pframe_count; |
||
581 | if (pkt->flags & AV_PKT_FLAG_KEY) |
||
582 | oggstream->last_kf_pts = pts; |
||
583 | pframe_count = pts - oggstream->last_kf_pts; |
||
584 | // prevent frame count from overflow if key frame flag is not set |
||
585 | if (pframe_count >= (1< |
||
586 | oggstream->last_kf_pts += pframe_count; |
||
587 | pframe_count = 0; |
||
588 | } |
||
589 | granule = (oggstream->last_kf_pts< |
||
590 | } else if (st->codec->codec_id == AV_CODEC_ID_OPUS) |
||
591 | granule = pkt->pts + pkt->duration + |
||
592 | av_rescale_q(st->codec->initial_padding, |
||
593 | (AVRational){ 1, st->codec->sample_rate }, |
||
594 | st->time_base); |
||
595 | else |
||
596 | granule = pkt->pts + pkt->duration; |
||
597 | |||
598 | if (oggstream->page.start_granule == AV_NOPTS_VALUE) |
||
599 | oggstream->page.start_granule = pkt->pts; |
||
600 | |||
601 | ret = ogg_buffer_data(s, st, pkt->data, pkt->size, granule, 0); |
||
602 | if (ret < 0) |
||
603 | return ret; |
||
604 | |||
605 | ogg_write_pages(s, 0); |
||
606 | |||
607 | oggstream->last_granule = granule; |
||
608 | |||
609 | return 0; |
||
610 | } |
||
611 | |||
612 | static int ogg_write_packet(AVFormatContext *s, AVPacket *pkt) |
||
613 | { |
||
614 | int i; |
||
615 | |||
616 | if (pkt) |
||
617 | return ogg_write_packet_internal(s, pkt); |
||
618 | |||
619 | for (i = 0; i < s->nb_streams; i++) { |
||
620 | OGGStreamContext *oggstream = s->streams[i]->priv_data; |
||
621 | if (oggstream->page.segments_count) |
||
622 | ogg_buffer_page(s, oggstream); |
||
623 | } |
||
624 | |||
625 | ogg_write_pages(s, 2); |
||
626 | return 1; |
||
627 | } |
||
628 | |||
629 | static int ogg_write_trailer(AVFormatContext *s) |
||
630 | { |
||
631 | int i; |
||
632 | |||
633 | /* flush current page if needed */ |
||
634 | for (i = 0; i < s->nb_streams; i++) { |
||
635 | OGGStreamContext *oggstream = s->streams[i]->priv_data; |
||
636 | |||
637 | if (oggstream->page.size > 0) |
||
638 | ogg_buffer_page(s, oggstream); |
||
639 | } |
||
640 | |||
641 | ogg_write_pages(s, 1); |
||
642 | |||
643 | for (i = 0; i < s->nb_streams; i++) { |
||
644 | AVStream *st = s->streams[i]; |
||
645 | OGGStreamContext *oggstream = st->priv_data; |
||
646 | if (st->codec->codec_id == AV_CODEC_ID_FLAC || |
||
647 | st->codec->codec_id == AV_CODEC_ID_SPEEX || |
||
648 | st->codec->codec_id == AV_CODEC_ID_OPUS) { |
||
649 | av_freep(&oggstream->header[0]); |
||
650 | } |
||
651 | av_freep(&oggstream->header[1]); |
||
652 | av_freep(&st->priv_data); |
||
653 | } |
||
654 | return 0; |
||
655 | } |
||
656 | |||
657 | #if CONFIG_OGG_MUXER |
||
658 | OGG_CLASS(ogg, Ogg) |
||
659 | AVOutputFormat ff_ogg_muxer = { |
||
660 | .name = "ogg", |
||
661 | .long_name = NULL_IF_CONFIG_SMALL("Ogg"), |
||
662 | .mime_type = "application/ogg", |
||
663 | .extensions = "ogg,ogv" |
||
664 | #if !CONFIG_SPX_MUXER |
||
665 | ",spx" |
||
666 | #endif |
||
667 | #if !CONFIG_OPUS_MUXER |
||
668 | ",opus" |
||
669 | #endif |
||
670 | , |
||
671 | .priv_data_size = sizeof(OGGContext), |
||
672 | .audio_codec = CONFIG_LIBVORBIS_ENCODER ? |
||
673 | AV_CODEC_ID_VORBIS : AV_CODEC_ID_FLAC, |
||
674 | .video_codec = AV_CODEC_ID_THEORA, |
||
675 | .write_header = ogg_write_header, |
||
676 | .write_packet = ogg_write_packet, |
||
677 | .write_trailer = ogg_write_trailer, |
||
678 | .flags = AVFMT_TS_NEGATIVE | AVFMT_ALLOW_FLUSH, |
||
679 | .priv_class = &ogg_muxer_class, |
||
680 | }; |
||
681 | #endif |
||
682 | |||
683 | #if CONFIG_OGA_MUXER |
||
684 | OGG_CLASS(oga, Ogg audio) |
||
685 | AVOutputFormat ff_oga_muxer = { |
||
686 | .name = "oga", |
||
687 | .long_name = NULL_IF_CONFIG_SMALL("Ogg Audio"), |
||
688 | .mime_type = "audio/ogg", |
||
689 | .extensions = "oga", |
||
690 | .priv_data_size = sizeof(OGGContext), |
||
691 | .audio_codec = CONFIG_LIBVORBIS_ENCODER ? |
||
692 | AV_CODEC_ID_VORBIS : AV_CODEC_ID_FLAC, |
||
693 | .write_header = ogg_write_header, |
||
694 | .write_packet = ogg_write_packet, |
||
695 | .write_trailer = ogg_write_trailer, |
||
696 | .flags = AVFMT_TS_NEGATIVE | AVFMT_ALLOW_FLUSH, |
||
697 | .priv_class = &oga_muxer_class, |
||
698 | }; |
||
699 | #endif |
||
700 | |||
701 | #if CONFIG_SPX_MUXER |
||
702 | OGG_CLASS(spx, Ogg Speex) |
||
703 | AVOutputFormat ff_spx_muxer = { |
||
704 | .name = "spx", |
||
705 | .long_name = NULL_IF_CONFIG_SMALL("Ogg Speex"), |
||
706 | .mime_type = "audio/ogg", |
||
707 | .extensions = "spx", |
||
708 | .priv_data_size = sizeof(OGGContext), |
||
709 | .audio_codec = AV_CODEC_ID_SPEEX, |
||
710 | .write_header = ogg_write_header, |
||
711 | .write_packet = ogg_write_packet, |
||
712 | .write_trailer = ogg_write_trailer, |
||
713 | .flags = AVFMT_TS_NEGATIVE | AVFMT_ALLOW_FLUSH, |
||
714 | .priv_class = &spx_muxer_class, |
||
715 | }; |
||
716 | #endif |
||
717 | |||
718 | #if CONFIG_OPUS_MUXER |
||
719 | OGG_CLASS(opus, Ogg Opus) |
||
720 | AVOutputFormat ff_opus_muxer = { |
||
721 | .name = "opus", |
||
722 | .long_name = NULL_IF_CONFIG_SMALL("Ogg Opus"), |
||
723 | .mime_type = "audio/ogg", |
||
724 | .extensions = "opus", |
||
725 | .priv_data_size = sizeof(OGGContext), |
||
726 | .audio_codec = AV_CODEC_ID_OPUS, |
||
727 | .write_header = ogg_write_header, |
||
728 | .write_packet = ogg_write_packet, |
||
729 | .write_trailer = ogg_write_trailer, |
||
730 | .flags = AVFMT_TS_NEGATIVE | AVFMT_ALLOW_FLUSH, |
||
731 | .priv_class = &opus_muxer_class, |
||
732 | }; |
||
733 | #endif>>>> |