*/
#include "libavutil/crc.h"
+#include "libavutil/mathematics.h"
+#include "libavutil/opt.h"
#include "libavutil/random_seed.h"
#include "libavcodec/xiph.h"
#include "libavcodec/bytestream.h"
} OGGPageList;
typedef struct {
+ const AVClass *class;
OGGPageList *page_list;
+ int pref_size; ///< preferred page size (0 => fill all segments)
} OGGContext;
+#define OFFSET(x) offsetof(OGGContext, x)
+#define PARAM AV_OPT_FLAG_ENCODING_PARAM
+
+static const AVOption options[] = {
+ { "pagesize", "preferred page size in bytes",
+ OFFSET(pref_size), AV_OPT_TYPE_INT, { 0 }, 0, MAX_PAGE_SIZE, PARAM },
+ { NULL },
+};
+
+static const AVClass ogg_muxer_class = {
+ .class_name = "Ogg muxer",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+
static void ogg_update_checksum(AVFormatContext *s, AVIOContext *pb, int64_t crc_offset)
{
int64_t pos = avio_tell(pb);
ogg_update_checksum(s, pb, crc_offset);
avio_flush(pb);
- size = url_close_dyn_buf(pb, &buf);
+ size = avio_close_dyn_buf(pb, &buf);
if (size < 0)
return size;
}
static int ogg_buffer_data(AVFormatContext *s, AVStream *st,
- uint8_t *data, unsigned size, int64_t granule)
+ uint8_t *data, unsigned size, int64_t granule,
+ int header)
{
OGGStreamContext *oggstream = st->priv_data;
+ OGGContext *ogg = s->priv_data;
int total_segments = size / 255 + 1;
uint8_t *p = data;
int i, segments, len, flush = 0;
// Handles VFR by flushing page because this frame needs to have a timestamp
- if (st->codec->codec_id == CODEC_ID_THEORA &&
+ if (st->codec->codec_id == CODEC_ID_THEORA && !header &&
ogg_granule_to_timestamp(oggstream, granule) >
ogg_granule_to_timestamp(oggstream, oggstream->last_granule) + 1) {
if (oggstream->page.granule != -1)
if (i == total_segments)
page->granule = granule;
- if (page->segments_count == 255) {
- ogg_buffer_page(s, oggstream);
+ if (!header && (page->segments_count == 255 ||
+ (ogg->pref_size > 0 && page->size >= ogg->pref_size))) {
+ ogg_buffer_page(s, oggstream);
}
}
}
static uint8_t *ogg_write_vorbiscomment(int offset, int bitexact,
- int *header_len, AVMetadata **m, int framing_bit)
+ int *header_len, AVDictionary **m, int framing_bit)
{
- const char *vendor = bitexact ? "ffmpeg" : LIBAVFORMAT_IDENT;
+ const char *vendor = bitexact ? "Libav" : LIBAVFORMAT_IDENT;
int size;
uint8_t *p, *p0;
unsigned int count;
static int ogg_build_flac_headers(AVCodecContext *avctx,
OGGStreamContext *oggstream, int bitexact,
- AVMetadata **m)
+ AVDictionary **m)
{
enum FLACExtradataFormat format;
uint8_t *streaminfo;
uint8_t *p;
- if (!ff_flac_is_extradata_valid(avctx, &format, &streaminfo))
+ if (!avpriv_flac_is_extradata_valid(avctx, &format, &streaminfo))
return -1;
// first packet: STREAMINFO
static int ogg_build_speex_headers(AVCodecContext *avctx,
OGGStreamContext *oggstream, int bitexact,
- AVMetadata **m)
+ AVDictionary **m)
{
uint8_t *p;
unsigned serial_num = i;
if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO)
- av_set_pts_info(st, 64, 1, st->codec->sample_rate);
+ avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
else if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
- av_set_pts_info(st, 64, st->codec->time_base.num, st->codec->time_base.den);
+ avpriv_set_pts_info(st, 64, st->codec->time_base.num, st->codec->time_base.den);
if (st->codec->codec_id != CODEC_ID_VORBIS &&
st->codec->codec_id != CODEC_ID_THEORA &&
st->codec->codec_id != CODEC_ID_SPEEX &&
int header_type = st->codec->codec_id == CODEC_ID_VORBIS ? 3 : 0x81;
int framing_bit = st->codec->codec_id == CODEC_ID_VORBIS ? 1 : 0;
- if (ff_split_xiph_headers(st->codec->extradata, st->codec->extradata_size,
+ if (avpriv_split_xiph_headers(st->codec->extradata, st->codec->extradata_size,
st->codec->codec_id == CODEC_ID_VORBIS ? 30 : 42,
oggstream->header, oggstream->header_len) < 0) {
av_log(s, AV_LOG_ERROR, "Extradata corrupted\n");
p = ogg_write_vorbiscomment(7, st->codec->flags & CODEC_FLAG_BITEXACT,
&oggstream->header_len[1], &s->metadata,
framing_bit);
+ oggstream->header[1] = p;
if (!p)
return AVERROR(ENOMEM);
- oggstream->header[1] = p;
bytestream_put_byte(&p, header_type);
bytestream_put_buffer(&p, cstr, 6);
for (j = 0; j < s->nb_streams; j++) {
OGGStreamContext *oggstream = s->streams[j]->priv_data;
ogg_buffer_data(s, s->streams[j], oggstream->header[0],
- oggstream->header_len[0], 0);
+ oggstream->header_len[0], 0, 1);
oggstream->page.flags |= 2; // bos
ogg_buffer_page(s, oggstream);
}
for (i = 1; i < 3; i++) {
if (oggstream && oggstream->header_len[i])
ogg_buffer_data(s, st, oggstream->header[i],
- oggstream->header_len[i], 0);
+ oggstream->header_len[i], 0, 1);
}
ogg_buffer_page(s, oggstream);
}
} else
granule = pkt->pts + pkt->duration;
- ret = ogg_buffer_data(s, st, pkt->data, pkt->size, granule);
+ ret = ogg_buffer_data(s, st, pkt->data, pkt->size, granule, 0);
if (ret < 0)
return ret;
if (st->codec->codec_id == CODEC_ID_FLAC ||
st->codec->codec_id == CODEC_ID_SPEEX) {
av_free(oggstream->header[0]);
- av_free(oggstream->header[1]);
}
+ av_freep(&oggstream->header[1]);
av_freep(&st->priv_data);
}
return 0;
}
AVOutputFormat ff_ogg_muxer = {
- "ogg",
- NULL_IF_CONFIG_SMALL("Ogg"),
- "application/ogg",
- "ogg,ogv,spx",
- sizeof(OGGContext),
- CODEC_ID_FLAC,
- CODEC_ID_THEORA,
- ogg_write_header,
- ogg_write_packet,
- ogg_write_trailer,
+ .name = "ogg",
+ .long_name = NULL_IF_CONFIG_SMALL("Ogg"),
+ .mime_type = "application/ogg",
+ .extensions = "ogg,ogv,spx",
+ .priv_data_size = sizeof(OGGContext),
+ .audio_codec = CODEC_ID_FLAC,
+ .video_codec = CODEC_ID_THEORA,
+ .write_header = ogg_write_header,
+ .write_packet = ogg_write_packet,
+ .write_trailer = ogg_write_trailer,
+ .priv_class = &ogg_muxer_class,
};