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
,
310 enum FLACExtradataFormat format
;
314 if (!avpriv_flac_is_extradata_valid(avctx
, &format
, &streaminfo
))
317 // first packet: STREAMINFO
318 oggstream
->header_len
[0] = 51;
319 oggstream
->header
[0] = av_mallocz(51); // per ogg flac specs
320 p
= oggstream
->header
[0];
322 return AVERROR(ENOMEM
);
323 bytestream_put_byte(&p
, 0x7F);
324 bytestream_put_buffer(&p
, "FLAC", 4);
325 bytestream_put_byte(&p
, 1); // major version
326 bytestream_put_byte(&p
, 0); // minor version
327 bytestream_put_be16(&p
, 1); // headers packets without this one
328 bytestream_put_buffer(&p
, "fLaC", 4);
329 bytestream_put_byte(&p
, 0x00); // streaminfo
330 bytestream_put_be24(&p
, 34);
331 bytestream_put_buffer(&p
, streaminfo
, FLAC_STREAMINFO_SIZE
);
333 // second packet: VorbisComment
334 p
= ogg_write_vorbiscomment(4, bitexact
, &oggstream
->header_len
[1], m
, 0);
336 return AVERROR(ENOMEM
);
337 oggstream
->header
[1] = p
;
338 bytestream_put_byte(&p
, 0x84); // last metadata block and vorbis comment
339 bytestream_put_be24(&p
, oggstream
->header_len
[1] - 4);
344 #define SPEEX_HEADER_SIZE 80
346 static int ogg_build_speex_headers(AVCodecContext
*avctx
,
347 OGGStreamContext
*oggstream
, int bitexact
,
352 if (avctx
->extradata_size
< SPEEX_HEADER_SIZE
)
355 // first packet: Speex header
356 p
= av_mallocz(SPEEX_HEADER_SIZE
);
358 return AVERROR(ENOMEM
);
359 oggstream
->header
[0] = p
;
360 oggstream
->header_len
[0] = SPEEX_HEADER_SIZE
;
361 bytestream_put_buffer(&p
, avctx
->extradata
, SPEEX_HEADER_SIZE
);
362 AV_WL32(&oggstream
->header
[0][68], 0); // set extra_headers to 0
364 // second packet: VorbisComment
365 p
= ogg_write_vorbiscomment(0, bitexact
, &oggstream
->header_len
[1], m
, 0);
367 return AVERROR(ENOMEM
);
368 oggstream
->header
[1] = p
;
373 #define OPUS_HEADER_SIZE 19
375 static int ogg_build_opus_headers(AVCodecContext
*avctx
,
376 OGGStreamContext
*oggstream
, int bitexact
,
381 if (avctx
->extradata_size
< OPUS_HEADER_SIZE
)
384 /* first packet: Opus header */
385 p
= av_mallocz(avctx
->extradata_size
);
387 return AVERROR(ENOMEM
);
388 oggstream
->header
[0] = p
;
389 oggstream
->header_len
[0] = avctx
->extradata_size
;
390 bytestream_put_buffer(&p
, avctx
->extradata
, avctx
->extradata_size
);
392 /* second packet: VorbisComment */
393 p
= ogg_write_vorbiscomment(8, bitexact
, &oggstream
->header_len
[1], m
, 0);
395 return AVERROR(ENOMEM
);
396 oggstream
->header
[1] = p
;
397 bytestream_put_buffer(&p
, "OpusTags", 8);
402 static void ogg_write_pages(AVFormatContext
*s
, int flush
)
404 OGGContext
*ogg
= s
->priv_data
;
405 OGGPageList
*next
, *p
;
410 for (p
= ogg
->page_list
; p
; ) {
411 OGGStreamContext
*oggstream
=
412 s
->streams
[p
->page
.stream_index
]->priv_data
;
413 if (oggstream
->page_count
< 2 && !flush
)
415 ogg_write_page(s
, &p
->page
,
416 flush
== 1 && oggstream
->page_count
== 1 ? 4 : 0); // eos
424 static int ogg_write_header(AVFormatContext
*s
)
426 OGGContext
*ogg
= s
->priv_data
;
427 OGGStreamContext
*oggstream
= NULL
;
431 av_log(s
, AV_LOG_WARNING
, "The pagesize option is deprecated\n");
433 for (i
= 0; i
< s
->nb_streams
; i
++) {
434 AVStream
*st
= s
->streams
[i
];
435 unsigned serial_num
= i
;
437 if (st
->codec
->codec_type
== AVMEDIA_TYPE_AUDIO
) {
438 if (st
->codec
->codec_id
== AV_CODEC_ID_OPUS
)
439 /* Opus requires a fixed 48kHz clock */
440 avpriv_set_pts_info(st
, 64, 1, 48000);
442 avpriv_set_pts_info(st
, 64, 1, st
->codec
->sample_rate
);
445 if (st
->codec
->codec_id
!= AV_CODEC_ID_VORBIS
&&
446 st
->codec
->codec_id
!= AV_CODEC_ID_THEORA
&&
447 st
->codec
->codec_id
!= AV_CODEC_ID_SPEEX
&&
448 st
->codec
->codec_id
!= AV_CODEC_ID_FLAC
&&
449 st
->codec
->codec_id
!= AV_CODEC_ID_OPUS
) {
450 av_log(s
, AV_LOG_ERROR
, "Unsupported codec id in stream %d\n", i
);
454 if (!st
->codec
->extradata
|| !st
->codec
->extradata_size
) {
455 av_log(s
, AV_LOG_ERROR
, "No extradata present\n");
458 oggstream
= av_mallocz(sizeof(*oggstream
));
460 return AVERROR(ENOMEM
);
462 oggstream
->page
.stream_index
= i
;
464 if (!(s
->flags
& AVFMT_FLAG_BITEXACT
))
466 serial_num
= av_get_random_seed();
467 for (j
= 0; j
< i
; j
++) {
468 OGGStreamContext
*sc
= s
->streams
[j
]->priv_data
;
469 if (serial_num
== sc
->serial_num
)
473 oggstream
->serial_num
= serial_num
;
475 av_dict_copy(&st
->metadata
, s
->metadata
, AV_DICT_DONT_OVERWRITE
);
477 st
->priv_data
= oggstream
;
478 if (st
->codec
->codec_id
== AV_CODEC_ID_FLAC
) {
479 int err
= ogg_build_flac_headers(st
->codec
, oggstream
,
480 s
->flags
& AVFMT_FLAG_BITEXACT
,
483 av_log(s
, AV_LOG_ERROR
, "Error writing FLAC headers\n");
484 av_freep(&st
->priv_data
);
487 } else if (st
->codec
->codec_id
== AV_CODEC_ID_SPEEX
) {
488 int err
= ogg_build_speex_headers(st
->codec
, oggstream
,
489 s
->flags
& AVFMT_FLAG_BITEXACT
,
492 av_log(s
, AV_LOG_ERROR
, "Error writing Speex headers\n");
493 av_freep(&st
->priv_data
);
496 } else if (st
->codec
->codec_id
== AV_CODEC_ID_OPUS
) {
497 int err
= ogg_build_opus_headers(st
->codec
, oggstream
,
498 s
->flags
& AVFMT_FLAG_BITEXACT
,
501 av_log(s
, AV_LOG_ERROR
, "Error writing Opus headers\n");
502 av_freep(&st
->priv_data
);
507 const char *cstr
= st
->codec
->codec_id
== AV_CODEC_ID_VORBIS
? "vorbis" : "theora";
508 int header_type
= st
->codec
->codec_id
== AV_CODEC_ID_VORBIS
? 3 : 0x81;
509 int framing_bit
= st
->codec
->codec_id
== AV_CODEC_ID_VORBIS
? 1 : 0;
511 if (avpriv_split_xiph_headers(st
->codec
->extradata
, st
->codec
->extradata_size
,
512 st
->codec
->codec_id
== AV_CODEC_ID_VORBIS
? 30 : 42,
513 oggstream
->header
, oggstream
->header_len
) < 0) {
514 av_log(s
, AV_LOG_ERROR
, "Extradata corrupted\n");
515 av_freep(&st
->priv_data
);
519 p
= ogg_write_vorbiscomment(7, s
->flags
& AVFMT_FLAG_BITEXACT
,
520 &oggstream
->header_len
[1], &st
->metadata
,
522 oggstream
->header
[1] = p
;
524 return AVERROR(ENOMEM
);
526 bytestream_put_byte(&p
, header_type
);
527 bytestream_put_buffer(&p
, cstr
, 6);
529 if (st
->codec
->codec_id
== AV_CODEC_ID_THEORA
) {
530 /** KFGSHIFT is the width of the less significant section of the granule position
531 The less significant section is the frame count since the last keyframe */
532 oggstream
->kfgshift
= ((oggstream
->header
[0][40]&3)<<3)|(oggstream
->header
[0][41]>>5);
533 oggstream
->vrev
= oggstream
->header
[0][9];
534 av_log(s
, AV_LOG_DEBUG
, "theora kfgshift %d, vrev %d\n",
535 oggstream
->kfgshift
, oggstream
->vrev
);
540 for (j
= 0; j
< s
->nb_streams
; j
++) {
541 OGGStreamContext
*oggstream
= s
->streams
[j
]->priv_data
;
542 ogg_buffer_data(s
, s
->streams
[j
], oggstream
->header
[0],
543 oggstream
->header_len
[0], 0, 1);
544 oggstream
->page
.flags
|= 2; // bos
545 ogg_buffer_page(s
, oggstream
);
547 for (j
= 0; j
< s
->nb_streams
; j
++) {
548 AVStream
*st
= s
->streams
[j
];
549 OGGStreamContext
*oggstream
= st
->priv_data
;
550 for (i
= 1; i
< 3; i
++) {
551 if (oggstream
->header_len
[i
])
552 ogg_buffer_data(s
, st
, oggstream
->header
[i
],
553 oggstream
->header_len
[i
], 0, 1);
555 ogg_buffer_page(s
, oggstream
);
558 oggstream
->page
.start_granule
= AV_NOPTS_VALUE
;
560 ogg_write_pages(s
, 2);
565 static int ogg_write_packet_internal(AVFormatContext
*s
, AVPacket
*pkt
)
567 AVStream
*st
= s
->streams
[pkt
->stream_index
];
568 OGGStreamContext
*oggstream
= st
->priv_data
;
572 if (st
->codec
->codec_id
== AV_CODEC_ID_THEORA
) {
573 int64_t pts
= oggstream
->vrev
< 1 ? pkt
->pts
: pkt
->pts
+ pkt
->duration
;
575 if (pkt
->flags
& AV_PKT_FLAG_KEY
)
576 oggstream
->last_kf_pts
= pts
;
577 pframe_count
= pts
- oggstream
->last_kf_pts
;
578 // prevent frame count from overflow if key frame flag is not set
579 if (pframe_count
>= (1<<oggstream
->kfgshift
)) {
580 oggstream
->last_kf_pts
+= pframe_count
;
583 granule
= (oggstream
->last_kf_pts
<<oggstream
->kfgshift
) | pframe_count
;
584 } else if (st
->codec
->codec_id
== AV_CODEC_ID_OPUS
)
585 granule
= pkt
->pts
+ pkt
->duration
+ av_rescale_q(st
->codec
->delay
, (AVRational
){ 1, st
->codec
->sample_rate
}, st
->time_base
);
587 granule
= pkt
->pts
+ pkt
->duration
;
589 if (oggstream
->page
.start_granule
== AV_NOPTS_VALUE
)
590 oggstream
->page
.start_granule
= pkt
->pts
;
592 ret
= ogg_buffer_data(s
, st
, pkt
->data
, pkt
->size
, granule
, 0);
596 ogg_write_pages(s
, 0);
598 oggstream
->last_granule
= granule
;
603 static int ogg_write_packet(AVFormatContext
*s
, AVPacket
*pkt
)
608 return ogg_write_packet_internal(s
, pkt
);
610 for (i
= 0; i
< s
->nb_streams
; i
++) {
611 OGGStreamContext
*oggstream
= s
->streams
[i
]->priv_data
;
612 if (oggstream
->page
.segments_count
)
613 ogg_buffer_page(s
, oggstream
);
616 ogg_write_pages(s
, 2);
620 static int ogg_write_trailer(AVFormatContext
*s
)
624 /* flush current page if needed */
625 for (i
= 0; i
< s
->nb_streams
; i
++) {
626 OGGStreamContext
*oggstream
= s
->streams
[i
]->priv_data
;
628 if (oggstream
->page
.size
> 0)
629 ogg_buffer_page(s
, oggstream
);
632 ogg_write_pages(s
, 1);
634 for (i
= 0; i
< s
->nb_streams
; i
++) {
635 AVStream
*st
= s
->streams
[i
];
636 OGGStreamContext
*oggstream
= st
->priv_data
;
637 if (st
->codec
->codec_id
== AV_CODEC_ID_FLAC
||
638 st
->codec
->codec_id
== AV_CODEC_ID_SPEEX
||
639 st
->codec
->codec_id
== AV_CODEC_ID_OPUS
) {
640 av_freep(&oggstream
->header
[0]);
642 av_freep(&oggstream
->header
[1]);
643 av_freep(&st
->priv_data
);
650 AVOutputFormat ff_ogg_muxer
= {
652 .long_name
= NULL_IF_CONFIG_SMALL("Ogg"),
653 .mime_type
= "application/ogg",
654 .extensions
= "ogg,ogv"
655 #if !CONFIG_SPX_MUXER
658 #if !CONFIG_OPUS_MUXER
662 .priv_data_size
= sizeof(OGGContext
),
663 .audio_codec
= CONFIG_LIBVORBIS_ENCODER
?
664 AV_CODEC_ID_VORBIS
: AV_CODEC_ID_FLAC
,
665 .video_codec
= AV_CODEC_ID_THEORA
,
666 .write_header
= ogg_write_header
,
667 .write_packet
= ogg_write_packet
,
668 .write_trailer
= ogg_write_trailer
,
669 .flags
= AVFMT_TS_NEGATIVE
| AVFMT_ALLOW_FLUSH
,
670 .priv_class
= &ogg_muxer_class
,
675 OGG_CLASS(oga
, Ogg audio
)
676 AVOutputFormat ff_oga_muxer
= {
678 .long_name
= NULL_IF_CONFIG_SMALL("Ogg Audio"),
679 .mime_type
= "audio/ogg",
681 .priv_data_size
= sizeof(OGGContext
),
682 .audio_codec
= CONFIG_LIBVORBIS_ENCODER
?
683 AV_CODEC_ID_VORBIS
: AV_CODEC_ID_FLAC
,
684 .write_header
= ogg_write_header
,
685 .write_packet
= ogg_write_packet
,
686 .write_trailer
= ogg_write_trailer
,
687 .flags
= AVFMT_TS_NEGATIVE
| AVFMT_ALLOW_FLUSH
,
688 .priv_class
= &oga_muxer_class
,
693 OGG_CLASS(spx
, Ogg Speex
)
694 AVOutputFormat ff_spx_muxer
= {
696 .long_name
= NULL_IF_CONFIG_SMALL("Ogg Speex"),
697 .mime_type
= "audio/ogg",
699 .priv_data_size
= sizeof(OGGContext
),
700 .audio_codec
= AV_CODEC_ID_SPEEX
,
701 .write_header
= ogg_write_header
,
702 .write_packet
= ogg_write_packet
,
703 .write_trailer
= ogg_write_trailer
,
704 .flags
= AVFMT_TS_NEGATIVE
| AVFMT_ALLOW_FLUSH
,
705 .priv_class
= &spx_muxer_class
,
709 #if CONFIG_OPUS_MUXER
710 OGG_CLASS(opus
, Ogg Opus
)
711 AVOutputFormat ff_opus_muxer
= {
713 .long_name
= NULL_IF_CONFIG_SMALL("Ogg Opus"),
714 .mime_type
= "audio/ogg",
715 .extensions
= "opus",
716 .priv_data_size
= sizeof(OGGContext
),
717 .audio_codec
= AV_CODEC_ID_OPUS
,
718 .write_header
= ogg_write_header
,
719 .write_packet
= ogg_write_packet
,
720 .write_trailer
= ogg_write_trailer
,
721 .flags
= AVFMT_TS_NEGATIVE
| AVFMT_ALLOW_FLUSH
,
722 .priv_class
= &opus_muxer_class
,