3 * Copyright (c) 2007 Baptiste Coudurier <baptiste dot coudurier at free dot fr>
5 * This file is part of FFmpeg.
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.
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.
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
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"
32 #include "avio_internal.h"
34 #include "vorbiscomment.h"
36 #define MAX_PAGE_SIZE 65025
39 int64_t start_granule
;
43 uint8_t segments_count
;
44 uint8_t segments
[255];
45 uint8_t data
[MAX_PAGE_SIZE
];
50 unsigned page_counter
;
53 /** for theora granule */
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
64 typedef struct OGGPageList
{
66 struct OGGPageList
*next
;
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)
76 #define OFFSET(x) offsetof(OGGContext, x)
77 #define PARAM AV_OPT_FLAG_ENCODING_PARAM
79 static const AVOption options
[] = {
80 { "oggpagesize", "Set preferred Ogg page size.",
81 offsetof(OGGContext
, pref_size
), AV_OPT_TYPE_INT
, {.i64
= 0}, 0, MAX_PAGE_SIZE
, AV_OPT_FLAG_ENCODING_PARAM
},
82 { "pagesize", "preferred page size in bytes (deprecated)",
83 OFFSET(pref_size
), AV_OPT_TYPE_INT
, { .i64
= 0 }, 0, MAX_PAGE_SIZE
, PARAM
},
84 { "page_duration", "preferred page duration, in microseconds",
85 OFFSET(pref_duration
), AV_OPT_TYPE_INT64
, { .i64
= 1000000 }, 0, INT64_MAX
, PARAM
},
89 #define OGG_CLASS(flavor, name)\
90 static const AVClass flavor ## _muxer_class = {\
91 .class_name = #name " muxer",\
92 .item_name = av_default_item_name,\
94 .version = LIBAVUTIL_VERSION_INT,\
97 static void ogg_update_checksum(AVFormatContext
*s
, AVIOContext
*pb
, int64_t crc_offset
)
99 int64_t pos
= avio_tell(pb
);
100 uint32_t checksum
= ffio_get_checksum(pb
);
101 avio_seek(pb
, crc_offset
, SEEK_SET
);
102 avio_wb32(pb
, checksum
);
103 avio_seek(pb
, pos
, SEEK_SET
);
106 static int ogg_write_page(AVFormatContext
*s
, OGGPage
*page
, int extra_flags
)
108 OGGStreamContext
*oggstream
= s
->streams
[page
->stream_index
]->priv_data
;
114 ret
= avio_open_dyn_buf(&pb
);
117 ffio_init_checksum(pb
, ff_crc04C11DB7_update
, 0);
118 ffio_wfourcc(pb
, "OggS");
120 avio_w8(pb
, page
->flags
| extra_flags
);
121 avio_wl64(pb
, page
->granule
);
122 avio_wl32(pb
, oggstream
->serial_num
);
123 avio_wl32(pb
, oggstream
->page_counter
++);
124 crc_offset
= avio_tell(pb
);
125 avio_wl32(pb
, 0); // crc
126 avio_w8(pb
, page
->segments_count
);
127 avio_write(pb
, page
->segments
, page
->segments_count
);
128 avio_write(pb
, page
->data
, page
->size
);
130 ogg_update_checksum(s
, pb
, crc_offset
);
133 size
= avio_close_dyn_buf(pb
, &buf
);
137 avio_write(s
->pb
, buf
, size
);
140 oggstream
->page_count
--;
144 static int ogg_key_granule(OGGStreamContext
*oggstream
, int64_t granule
)
146 return oggstream
->kfgshift
&& !(granule
& ((1<<oggstream
->kfgshift
)-1));
149 static int64_t ogg_granule_to_timestamp(OGGStreamContext
*oggstream
, int64_t granule
)
151 if (oggstream
->kfgshift
)
152 return (granule
>>oggstream
->kfgshift
) +
153 (granule
& ((1<<oggstream
->kfgshift
)-1));
158 static int ogg_compare_granule(AVFormatContext
*s
, OGGPage
*next
, OGGPage
*page
)
160 AVStream
*st2
= s
->streams
[next
->stream_index
];
161 AVStream
*st
= s
->streams
[page
->stream_index
];
162 int64_t next_granule
, cur_granule
;
164 if (next
->granule
== -1 || page
->granule
== -1)
167 next_granule
= av_rescale_q(ogg_granule_to_timestamp(st2
->priv_data
, next
->granule
),
168 st2
->time_base
, AV_TIME_BASE_Q
);
169 cur_granule
= av_rescale_q(ogg_granule_to_timestamp(st
->priv_data
, page
->granule
),
170 st
->time_base
, AV_TIME_BASE_Q
);
171 return next_granule
> cur_granule
;
174 static int ogg_reset_cur_page(OGGStreamContext
*oggstream
)
176 oggstream
->page
.granule
= -1;
177 oggstream
->page
.flags
= 0;
178 oggstream
->page
.segments_count
= 0;
179 oggstream
->page
.size
= 0;
183 static int ogg_buffer_page(AVFormatContext
*s
, OGGStreamContext
*oggstream
)
185 OGGContext
*ogg
= s
->priv_data
;
186 OGGPageList
**p
= &ogg
->page_list
;
187 OGGPageList
*l
= av_mallocz(sizeof(*l
));
190 return AVERROR(ENOMEM
);
191 l
->page
= oggstream
->page
;
193 oggstream
->page
.start_granule
= oggstream
->page
.granule
;
194 oggstream
->page_count
++;
195 ogg_reset_cur_page(oggstream
);
198 if (ogg_compare_granule(s
, &(*p
)->page
, &l
->page
))
208 static int ogg_buffer_data(AVFormatContext
*s
, AVStream
*st
,
209 uint8_t *data
, unsigned size
, int64_t granule
,
212 OGGStreamContext
*oggstream
= st
->priv_data
;
213 OGGContext
*ogg
= s
->priv_data
;
214 int total_segments
= size
/ 255 + 1;
216 int i
, segments
, len
, flush
= 0;
218 // Handles VFR by flushing page because this frame needs to have a timestamp
219 // For theora, keyframes also need to have a timestamp to correctly mark
220 // them as such, otherwise seeking will not work correctly at the very
221 // least with old libogg versions.
222 // Do not try to flush header packets though, that will create broken files.
223 if (st
->codec
->codec_id
== AV_CODEC_ID_THEORA
&& !header
&&
224 (ogg_granule_to_timestamp(oggstream
, granule
) >
225 ogg_granule_to_timestamp(oggstream
, oggstream
->last_granule
) + 1 ||
226 ogg_key_granule(oggstream
, granule
))) {
227 if (oggstream
->page
.granule
!= -1)
228 ogg_buffer_page(s
, oggstream
);
232 // avoid a continued page
233 if (!header
&& oggstream
->page
.size
> 0 &&
234 MAX_PAGE_SIZE
- oggstream
->page
.size
< size
) {
235 ogg_buffer_page(s
, oggstream
);
238 for (i
= 0; i
< total_segments
; ) {
239 OGGPage
*page
= &oggstream
->page
;
241 segments
= FFMIN(total_segments
- i
, 255 - page
->segments_count
);
243 if (i
&& !page
->segments_count
)
244 page
->flags
|= 1; // continued packet
246 memset(page
->segments
+page
->segments_count
, 255, segments
- 1);
247 page
->segments_count
+= segments
- 1;
249 len
= FFMIN(size
, segments
*255);
250 page
->segments
[page
->segments_count
++] = len
- (segments
-1)*255;
251 memcpy(page
->data
+page
->size
, p
, len
);
257 if (i
== total_segments
)
258 page
->granule
= granule
;
261 AVStream
*st
= s
->streams
[page
->stream_index
];
263 int64_t start
= av_rescale_q(page
->start_granule
, st
->time_base
,
265 int64_t next
= av_rescale_q(page
->granule
, st
->time_base
,
268 if (page
->segments_count
== 255 ||
269 (ogg
->pref_size
> 0 && page
->size
>= ogg
->pref_size
) ||
270 (ogg
->pref_duration
> 0 && next
- start
>= ogg
->pref_duration
)) {
271 ogg_buffer_page(s
, oggstream
);
276 if (flush
&& oggstream
->page
.granule
!= -1)
277 ogg_buffer_page(s
, oggstream
);
282 static uint8_t *ogg_write_vorbiscomment(int offset
, int bitexact
,
283 int *header_len
, AVDictionary
**m
, int framing_bit
)
285 const char *vendor
= bitexact
? "ffmpeg" : LIBAVFORMAT_IDENT
;
289 ff_metadata_conv(m
, ff_vorbiscomment_metadata_conv
, NULL
);
291 size
= offset
+ ff_vorbiscomment_length(*m
, vendor
) + framing_bit
;
292 p
= av_mallocz(size
);
298 ff_vorbiscomment_write(&p
, m
, vendor
);
300 bytestream_put_byte(&p
, 1);
306 static int ogg_build_flac_headers(AVCodecContext
*avctx
,
307 OGGStreamContext
*oggstream
, int bitexact
,
312 if (avctx
->extradata_size
< FLAC_STREAMINFO_SIZE
)
313 return AVERROR(EINVAL
);
315 // first packet: STREAMINFO
316 oggstream
->header_len
[0] = 51;
317 oggstream
->header
[0] = av_mallocz(51); // per ogg flac specs
318 p
= oggstream
->header
[0];
320 return AVERROR(ENOMEM
);
321 bytestream_put_byte(&p
, 0x7F);
322 bytestream_put_buffer(&p
, "FLAC", 4);
323 bytestream_put_byte(&p
, 1); // major version
324 bytestream_put_byte(&p
, 0); // minor version
325 bytestream_put_be16(&p
, 1); // headers packets without this one
326 bytestream_put_buffer(&p
, "fLaC", 4);
327 bytestream_put_byte(&p
, 0x00); // streaminfo
328 bytestream_put_be24(&p
, 34);
329 bytestream_put_buffer(&p
, avctx
->extradata
, FLAC_STREAMINFO_SIZE
);
331 // second packet: VorbisComment
332 p
= ogg_write_vorbiscomment(4, bitexact
, &oggstream
->header_len
[1], m
, 0);
334 return AVERROR(ENOMEM
);
335 oggstream
->header
[1] = p
;
336 bytestream_put_byte(&p
, 0x84); // last metadata block and vorbis comment
337 bytestream_put_be24(&p
, oggstream
->header_len
[1] - 4);
342 #define SPEEX_HEADER_SIZE 80
344 static int ogg_build_speex_headers(AVCodecContext
*avctx
,
345 OGGStreamContext
*oggstream
, int bitexact
,
350 if (avctx
->extradata_size
< SPEEX_HEADER_SIZE
)
351 return AVERROR_INVALIDDATA
;
353 // first packet: Speex header
354 p
= av_mallocz(SPEEX_HEADER_SIZE
);
356 return AVERROR(ENOMEM
);
357 oggstream
->header
[0] = p
;
358 oggstream
->header_len
[0] = SPEEX_HEADER_SIZE
;
359 bytestream_put_buffer(&p
, avctx
->extradata
, SPEEX_HEADER_SIZE
);
360 AV_WL32(&oggstream
->header
[0][68], 0); // set extra_headers to 0
362 // second packet: VorbisComment
363 p
= ogg_write_vorbiscomment(0, bitexact
, &oggstream
->header_len
[1], m
, 0);
365 return AVERROR(ENOMEM
);
366 oggstream
->header
[1] = p
;
371 #define OPUS_HEADER_SIZE 19
373 static int ogg_build_opus_headers(AVCodecContext
*avctx
,
374 OGGStreamContext
*oggstream
, int bitexact
,
379 if (avctx
->extradata_size
< OPUS_HEADER_SIZE
)
380 return AVERROR_INVALIDDATA
;
382 /* first packet: Opus header */
383 p
= av_mallocz(avctx
->extradata_size
);
385 return AVERROR(ENOMEM
);
386 oggstream
->header
[0] = p
;
387 oggstream
->header_len
[0] = avctx
->extradata_size
;
388 bytestream_put_buffer(&p
, avctx
->extradata
, avctx
->extradata_size
);
390 /* second packet: VorbisComment */
391 p
= ogg_write_vorbiscomment(8, bitexact
, &oggstream
->header_len
[1], m
, 0);
393 return AVERROR(ENOMEM
);
394 oggstream
->header
[1] = p
;
395 bytestream_put_buffer(&p
, "OpusTags", 8);
400 static void ogg_write_pages(AVFormatContext
*s
, int flush
)
402 OGGContext
*ogg
= s
->priv_data
;
403 OGGPageList
*next
, *p
;
408 for (p
= ogg
->page_list
; p
; ) {
409 OGGStreamContext
*oggstream
=
410 s
->streams
[p
->page
.stream_index
]->priv_data
;
411 if (oggstream
->page_count
< 2 && !flush
)
413 ogg_write_page(s
, &p
->page
,
414 flush
== 1 && oggstream
->page_count
== 1 ? 4 : 0); // eos
422 static int ogg_write_header(AVFormatContext
*s
)
424 OGGContext
*ogg
= s
->priv_data
;
425 OGGStreamContext
*oggstream
= NULL
;
429 av_log(s
, AV_LOG_WARNING
, "The pagesize option is deprecated\n");
431 for (i
= 0; i
< s
->nb_streams
; i
++) {
432 AVStream
*st
= s
->streams
[i
];
433 unsigned serial_num
= i
;
435 if (st
->codec
->codec_type
== AVMEDIA_TYPE_AUDIO
) {
436 if (st
->codec
->codec_id
== AV_CODEC_ID_OPUS
)
437 /* Opus requires a fixed 48kHz clock */
438 avpriv_set_pts_info(st
, 64, 1, 48000);
440 avpriv_set_pts_info(st
, 64, 1, st
->codec
->sample_rate
);
443 if (st
->codec
->codec_id
!= AV_CODEC_ID_VORBIS
&&
444 st
->codec
->codec_id
!= AV_CODEC_ID_THEORA
&&
445 st
->codec
->codec_id
!= AV_CODEC_ID_SPEEX
&&
446 st
->codec
->codec_id
!= AV_CODEC_ID_FLAC
&&
447 st
->codec
->codec_id
!= AV_CODEC_ID_OPUS
) {
448 av_log(s
, AV_LOG_ERROR
, "Unsupported codec id in stream %d\n", i
);
449 return AVERROR(EINVAL
);
452 if (!st
->codec
->extradata
|| !st
->codec
->extradata_size
) {
453 av_log(s
, AV_LOG_ERROR
, "No extradata present\n");
454 return AVERROR_INVALIDDATA
;
456 oggstream
= av_mallocz(sizeof(*oggstream
));
458 return AVERROR(ENOMEM
);
460 oggstream
->page
.stream_index
= i
;
462 if (!(s
->flags
& AVFMT_FLAG_BITEXACT
))
464 serial_num
= av_get_random_seed();
465 for (j
= 0; j
< i
; j
++) {
466 OGGStreamContext
*sc
= s
->streams
[j
]->priv_data
;
467 if (serial_num
== sc
->serial_num
)
471 oggstream
->serial_num
= serial_num
;
473 av_dict_copy(&st
->metadata
, s
->metadata
, AV_DICT_DONT_OVERWRITE
);
475 st
->priv_data
= oggstream
;
476 if (st
->codec
->codec_id
== AV_CODEC_ID_FLAC
) {
477 int err
= ogg_build_flac_headers(st
->codec
, oggstream
,
478 s
->flags
& AVFMT_FLAG_BITEXACT
,
481 av_log(s
, AV_LOG_ERROR
, "Error writing FLAC headers\n");
482 av_freep(&st
->priv_data
);
485 } else if (st
->codec
->codec_id
== AV_CODEC_ID_SPEEX
) {
486 int err
= ogg_build_speex_headers(st
->codec
, oggstream
,
487 s
->flags
& AVFMT_FLAG_BITEXACT
,
490 av_log(s
, AV_LOG_ERROR
, "Error writing Speex headers\n");
491 av_freep(&st
->priv_data
);
494 } else if (st
->codec
->codec_id
== AV_CODEC_ID_OPUS
) {
495 int err
= ogg_build_opus_headers(st
->codec
, oggstream
,
496 s
->flags
& AVFMT_FLAG_BITEXACT
,
499 av_log(s
, AV_LOG_ERROR
, "Error writing Opus headers\n");
500 av_freep(&st
->priv_data
);
505 const char *cstr
= st
->codec
->codec_id
== AV_CODEC_ID_VORBIS
? "vorbis" : "theora";
506 int header_type
= st
->codec
->codec_id
== AV_CODEC_ID_VORBIS
? 3 : 0x81;
507 int framing_bit
= st
->codec
->codec_id
== AV_CODEC_ID_VORBIS
? 1 : 0;
509 if (avpriv_split_xiph_headers(st
->codec
->extradata
, st
->codec
->extradata_size
,
510 st
->codec
->codec_id
== AV_CODEC_ID_VORBIS
? 30 : 42,
511 oggstream
->header
, oggstream
->header_len
) < 0) {
512 av_log(s
, AV_LOG_ERROR
, "Extradata corrupted\n");
513 av_freep(&st
->priv_data
);
514 return AVERROR_INVALIDDATA
;
517 p
= ogg_write_vorbiscomment(7, s
->flags
& AVFMT_FLAG_BITEXACT
,
518 &oggstream
->header_len
[1], &st
->metadata
,
520 oggstream
->header
[1] = p
;
522 return AVERROR(ENOMEM
);
524 bytestream_put_byte(&p
, header_type
);
525 bytestream_put_buffer(&p
, cstr
, 6);
527 if (st
->codec
->codec_id
== AV_CODEC_ID_THEORA
) {
528 /** KFGSHIFT is the width of the less significant section of the granule position
529 The less significant section is the frame count since the last keyframe */
530 oggstream
->kfgshift
= ((oggstream
->header
[0][40]&3)<<3)|(oggstream
->header
[0][41]>>5);
531 oggstream
->vrev
= oggstream
->header
[0][9];
532 av_log(s
, AV_LOG_DEBUG
, "theora kfgshift %d, vrev %d\n",
533 oggstream
->kfgshift
, oggstream
->vrev
);
538 for (j
= 0; j
< s
->nb_streams
; j
++) {
539 OGGStreamContext
*oggstream
= s
->streams
[j
]->priv_data
;
540 ogg_buffer_data(s
, s
->streams
[j
], oggstream
->header
[0],
541 oggstream
->header_len
[0], 0, 1);
542 oggstream
->page
.flags
|= 2; // bos
543 ogg_buffer_page(s
, oggstream
);
545 for (j
= 0; j
< s
->nb_streams
; j
++) {
546 AVStream
*st
= s
->streams
[j
];
547 OGGStreamContext
*oggstream
= st
->priv_data
;
548 for (i
= 1; i
< 3; i
++) {
549 if (oggstream
->header_len
[i
])
550 ogg_buffer_data(s
, st
, oggstream
->header
[i
],
551 oggstream
->header_len
[i
], 0, 1);
553 ogg_buffer_page(s
, oggstream
);
556 oggstream
->page
.start_granule
= AV_NOPTS_VALUE
;
558 ogg_write_pages(s
, 2);
563 static int ogg_write_packet_internal(AVFormatContext
*s
, AVPacket
*pkt
)
565 AVStream
*st
= s
->streams
[pkt
->stream_index
];
566 OGGStreamContext
*oggstream
= st
->priv_data
;
570 if (st
->codec
->codec_id
== AV_CODEC_ID_THEORA
) {
571 int64_t pts
= oggstream
->vrev
< 1 ? pkt
->pts
: pkt
->pts
+ pkt
->duration
;
573 if (pkt
->flags
& AV_PKT_FLAG_KEY
)
574 oggstream
->last_kf_pts
= pts
;
575 pframe_count
= pts
- oggstream
->last_kf_pts
;
576 // prevent frame count from overflow if key frame flag is not set
577 if (pframe_count
>= (1<<oggstream
->kfgshift
)) {
578 oggstream
->last_kf_pts
+= pframe_count
;
581 granule
= (oggstream
->last_kf_pts
<<oggstream
->kfgshift
) | pframe_count
;
582 } else if (st
->codec
->codec_id
== AV_CODEC_ID_OPUS
)
583 granule
= pkt
->pts
+ pkt
->duration
+
584 av_rescale_q(st
->codec
->initial_padding
,
585 (AVRational
){ 1, st
->codec
->sample_rate
},
588 granule
= pkt
->pts
+ pkt
->duration
;
590 if (oggstream
->page
.start_granule
== AV_NOPTS_VALUE
)
591 oggstream
->page
.start_granule
= pkt
->pts
;
593 ret
= ogg_buffer_data(s
, st
, pkt
->data
, pkt
->size
, granule
, 0);
597 ogg_write_pages(s
, 0);
599 oggstream
->last_granule
= granule
;
604 static int ogg_write_packet(AVFormatContext
*s
, AVPacket
*pkt
)
609 return ogg_write_packet_internal(s
, pkt
);
611 for (i
= 0; i
< s
->nb_streams
; i
++) {
612 OGGStreamContext
*oggstream
= s
->streams
[i
]->priv_data
;
613 if (oggstream
->page
.segments_count
)
614 ogg_buffer_page(s
, oggstream
);
617 ogg_write_pages(s
, 2);
621 static int ogg_write_trailer(AVFormatContext
*s
)
625 /* flush current page if needed */
626 for (i
= 0; i
< s
->nb_streams
; i
++) {
627 OGGStreamContext
*oggstream
= s
->streams
[i
]->priv_data
;
629 if (oggstream
->page
.size
> 0)
630 ogg_buffer_page(s
, oggstream
);
633 ogg_write_pages(s
, 1);
635 for (i
= 0; i
< s
->nb_streams
; i
++) {
636 AVStream
*st
= s
->streams
[i
];
637 OGGStreamContext
*oggstream
= st
->priv_data
;
638 if (st
->codec
->codec_id
== AV_CODEC_ID_FLAC
||
639 st
->codec
->codec_id
== AV_CODEC_ID_SPEEX
||
640 st
->codec
->codec_id
== AV_CODEC_ID_OPUS
) {
641 av_freep(&oggstream
->header
[0]);
643 av_freep(&oggstream
->header
[1]);
644 av_freep(&st
->priv_data
);
651 AVOutputFormat ff_ogg_muxer
= {
653 .long_name
= NULL_IF_CONFIG_SMALL("Ogg"),
654 .mime_type
= "application/ogg",
655 .extensions
= "ogg,ogv"
656 #if !CONFIG_SPX_MUXER
659 #if !CONFIG_OPUS_MUXER
663 .priv_data_size
= sizeof(OGGContext
),
664 .audio_codec
= CONFIG_LIBVORBIS_ENCODER
?
665 AV_CODEC_ID_VORBIS
: AV_CODEC_ID_FLAC
,
666 .video_codec
= AV_CODEC_ID_THEORA
,
667 .write_header
= ogg_write_header
,
668 .write_packet
= ogg_write_packet
,
669 .write_trailer
= ogg_write_trailer
,
670 .flags
= AVFMT_TS_NEGATIVE
| AVFMT_ALLOW_FLUSH
,
671 .priv_class
= &ogg_muxer_class
,
676 OGG_CLASS(oga
, Ogg audio
)
677 AVOutputFormat ff_oga_muxer
= {
679 .long_name
= NULL_IF_CONFIG_SMALL("Ogg Audio"),
680 .mime_type
= "audio/ogg",
682 .priv_data_size
= sizeof(OGGContext
),
683 .audio_codec
= CONFIG_LIBVORBIS_ENCODER
?
684 AV_CODEC_ID_VORBIS
: AV_CODEC_ID_FLAC
,
685 .write_header
= ogg_write_header
,
686 .write_packet
= ogg_write_packet
,
687 .write_trailer
= ogg_write_trailer
,
688 .flags
= AVFMT_TS_NEGATIVE
| AVFMT_ALLOW_FLUSH
,
689 .priv_class
= &oga_muxer_class
,
694 OGG_CLASS(spx
, Ogg Speex
)
695 AVOutputFormat ff_spx_muxer
= {
697 .long_name
= NULL_IF_CONFIG_SMALL("Ogg Speex"),
698 .mime_type
= "audio/ogg",
700 .priv_data_size
= sizeof(OGGContext
),
701 .audio_codec
= AV_CODEC_ID_SPEEX
,
702 .write_header
= ogg_write_header
,
703 .write_packet
= ogg_write_packet
,
704 .write_trailer
= ogg_write_trailer
,
705 .flags
= AVFMT_TS_NEGATIVE
| AVFMT_ALLOW_FLUSH
,
706 .priv_class
= &spx_muxer_class
,
710 #if CONFIG_OPUS_MUXER
711 OGG_CLASS(opus
, Ogg Opus
)
712 AVOutputFormat ff_opus_muxer
= {
714 .long_name
= NULL_IF_CONFIG_SMALL("Ogg Opus"),
715 .mime_type
= "audio/ogg",
716 .extensions
= "opus",
717 .priv_data_size
= sizeof(OGGContext
),
718 .audio_codec
= AV_CODEC_ID_OPUS
,
719 .write_header
= ogg_write_header
,
720 .write_packet
= ogg_write_packet
,
721 .write_trailer
= ogg_write_trailer
,
722 .flags
= AVFMT_TS_NEGATIVE
| AVFMT_ALLOW_FLUSH
,
723 .priv_class
= &opus_muxer_class
,