mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-01-08 13:22:53 +02:00
oggenc: add a page_duration option and deprecate the pagesize option
This uses page duration instead of byte size to determine when to buffer the page. Also, it tries to avoid continued pages by buffering the current page if there are already packets in the page and adding the next packet would require it to be continued on a new page. This can improve seeking performance. The default page duration is 1 second, which is much saner than filling all page segments by default.
This commit is contained in:
parent
a6a3164b13
commit
59220d559b
@ -434,4 +434,19 @@ avconv -i input.mp3 -i cover.png -c copy -metadata:s:v title="Album cover"
|
||||
-metadata:s:v comment="Cover (Front)" out.mp3
|
||||
@end example
|
||||
|
||||
@section ogg
|
||||
|
||||
Ogg container muxer.
|
||||
|
||||
@table @option
|
||||
@item -page_duration @var{duration}
|
||||
Preferred page duration, in microseconds. The muxer will attempt to create
|
||||
pages that are approximately @var{duration} microseconds long. This allows the
|
||||
user to compromise between seek granularity and container overhead. The default
|
||||
is 1 second. A value of 0 will fill all segments, making pages as large as
|
||||
possible. A value of 1 will effectively use 1 packet-per-page in most
|
||||
situations, giving a small seek granularity at the cost of additional container
|
||||
overhead.
|
||||
@end table
|
||||
|
||||
@c man end MUXERS
|
||||
|
@ -34,6 +34,7 @@
|
||||
#define MAX_PAGE_SIZE 65025
|
||||
|
||||
typedef struct {
|
||||
int64_t start_granule;
|
||||
int64_t granule;
|
||||
int stream_index;
|
||||
uint8_t flags;
|
||||
@ -67,14 +68,17 @@ typedef struct {
|
||||
const AVClass *class;
|
||||
OGGPageList *page_list;
|
||||
int pref_size; ///< preferred page size (0 => fill all segments)
|
||||
int64_t pref_duration; ///< preferred page duration (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",
|
||||
{ "pagesize", "preferred page size in bytes (deprecated)",
|
||||
OFFSET(pref_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, MAX_PAGE_SIZE, PARAM },
|
||||
{ "page_duration", "preferred page duration, in microseconds",
|
||||
OFFSET(pref_duration), AV_OPT_TYPE_INT, { .i64 = 1000000 }, 0, INT64_MAX, PARAM },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
@ -177,6 +181,7 @@ static int ogg_buffer_page(AVFormatContext *s, OGGStreamContext *oggstream)
|
||||
return AVERROR(ENOMEM);
|
||||
l->page = oggstream->page;
|
||||
|
||||
oggstream->page.start_granule = oggstream->page.granule;
|
||||
oggstream->page_count++;
|
||||
ogg_reset_cur_page(oggstream);
|
||||
|
||||
@ -210,6 +215,12 @@ static int ogg_buffer_data(AVFormatContext *s, AVStream *st,
|
||||
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;
|
||||
|
||||
@ -232,9 +243,19 @@ static int ogg_buffer_data(AVFormatContext *s, AVStream *st,
|
||||
if (i == total_segments)
|
||||
page->granule = granule;
|
||||
|
||||
if (!header && (page->segments_count == 255 ||
|
||||
(ogg->pref_size > 0 && page->size >= ogg->pref_size))) {
|
||||
ogg_buffer_page(s, oggstream);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -367,9 +388,13 @@ static int ogg_build_opus_headers(AVCodecContext *avctx,
|
||||
|
||||
static int ogg_write_header(AVFormatContext *s)
|
||||
{
|
||||
OGGContext *ogg = s->priv_data;
|
||||
OGGStreamContext *oggstream;
|
||||
int i, j;
|
||||
|
||||
if (ogg->pref_size)
|
||||
av_log(s, AV_LOG_WARNING, "The pagesize option is deprecated\n");
|
||||
|
||||
for (i = 0; i < s->nb_streams; i++) {
|
||||
AVStream *st = s->streams[i];
|
||||
unsigned serial_num = i;
|
||||
@ -489,6 +514,9 @@ static int ogg_write_header(AVFormatContext *s)
|
||||
}
|
||||
ogg_buffer_page(s, oggstream);
|
||||
}
|
||||
|
||||
oggstream->page.start_granule = AV_NOPTS_VALUE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -538,6 +566,9 @@ static int ogg_write_packet(AVFormatContext *s, AVPacket *pkt)
|
||||
else
|
||||
granule = pkt->pts + pkt->duration;
|
||||
|
||||
if (oggstream->page.start_granule == AV_NOPTS_VALUE)
|
||||
oggstream->page.start_granule = pkt->pts;
|
||||
|
||||
ret = ogg_buffer_data(s, st, pkt->data, pkt->size, granule, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@ -553,9 +584,13 @@ static int ogg_write_trailer(AVFormatContext *s)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* flush current page */
|
||||
for (i = 0; i < s->nb_streams; i++)
|
||||
ogg_buffer_page(s, s->streams[i]->priv_data);
|
||||
/* flush current page if needed */
|
||||
for (i = 0; i < s->nb_streams; i++) {
|
||||
OGGStreamContext *oggstream = s->streams[i]->priv_data;
|
||||
|
||||
if (oggstream->page.size > 0)
|
||||
ogg_buffer_page(s, oggstream);
|
||||
}
|
||||
|
||||
ogg_write_pages(s, 1);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user