+static int ogg_buffer_data(AVFormatContext *s, AVStream *st,
+ 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->codecpar->codec_id == AV_CODEC_ID_THEORA && !header &&
+ ogg_granule_to_timestamp(oggstream, granule) >
+ ogg_granule_to_timestamp(oggstream, oggstream->last_granule) + 1) {
+ if (oggstream->page.granule != -1)
+ ogg_buffer_page(s, oggstream);
+ flush = 1;
+ }
+
+ // avoid a continued page
+ if (!header && oggstream->page.size > 0 &&
+ MAX_PAGE_SIZE - oggstream->page.size < size) {
+ ogg_buffer_page(s, oggstream);
+ }
+
+ for (i = 0; i < total_segments; ) {
+ OGGPage *page = &oggstream->page;
+
+ segments = FFMIN(total_segments - i, 255 - page->segments_count);
+
+ if (i && !page->segments_count)
+ page->flags |= 1; // continued packet
+
+ memset(page->segments+page->segments_count, 255, segments - 1);
+ page->segments_count += segments - 1;
+
+ len = FFMIN(size, segments*255);
+ page->segments[page->segments_count++] = len - (segments-1)*255;
+ memcpy(page->data+page->size, p, len);
+ p += len;
+ size -= len;
+ i += segments;
+ page->size += len;
+
+ if (i == total_segments)
+ page->granule = granule;
+
+ if (!header) {
+ AVStream *st = s->streams[page->stream_index];
+
+ int64_t start = av_rescale_q(page->start_granule, st->time_base,
+ AV_TIME_BASE_Q);
+ int64_t next = av_rescale_q(page->granule, st->time_base,
+ AV_TIME_BASE_Q);
+
+ if (page->segments_count == 255 ||
+ (ogg->pref_size > 0 && page->size >= ogg->pref_size) ||
+ (ogg->pref_duration > 0 && next - start >= ogg->pref_duration)) {
+ ogg_buffer_page(s, oggstream);
+ }
+ }
+ }
+
+ if (flush && oggstream->page.granule != -1)
+ ogg_buffer_page(s, oggstream);
+
+ return 0;
+}
+
+static uint8_t *ogg_write_vorbiscomment(int offset, int bitexact,
+ int *header_len, AVDictionary **m, int framing_bit)
+{
+ const char *vendor = bitexact ? "Libav" : LIBAVFORMAT_IDENT;
+ int size;
+ uint8_t *p, *p0;
+
+ ff_metadata_conv(m, ff_vorbiscomment_metadata_conv, NULL);
+
+ size = offset + ff_vorbiscomment_length(*m, vendor) + framing_bit;
+ p = av_mallocz(size);
+ if (!p)
+ return NULL;
+ p0 = p;
+
+ p += offset;
+ ff_vorbiscomment_write(&p, m, vendor);
+ if (framing_bit)
+ bytestream_put_byte(&p, 1);
+
+ *header_len = size;
+ return p0;
+}
+
+static int ogg_build_flac_headers(AVCodecParameters *par,
+ OGGStreamContext *oggstream, int bitexact,
+ AVDictionary **m)