diff --git a/doc/APIchanges b/doc/APIchanges index d75c977dfb..7a01b80f75 100644 --- a/doc/APIchanges +++ b/doc/APIchanges @@ -15,6 +15,10 @@ libavutil: 2012-10-22 API changes, most recent first: +2014-02-xx - xxxxxxx - lavf 55.11.0 - avformat.h + Add AVFormatContext.max_interleave_delta for controlling amount of buffering + when interleaving. + 2014-02-02 - xxxxxxx - lavf 55.29.100 - avformat.h Add output_ts_offset muxing option to AVFormatContext. diff --git a/libavformat/avformat.h b/libavformat/avformat.h index fe3757a309..4d3cc1492b 100644 --- a/libavformat/avformat.h +++ b/libavformat/avformat.h @@ -1182,6 +1182,24 @@ typedef struct AVFormatContext { int debug; #define FF_FDEBUG_TS 0x0001 + /** + * Maximum buffering duration for interleaving. + * + * To ensure all the streams are interleaved correctly, + * av_interleaved_write_frame() will wait until it has at least one packet + * for each stream before actually writing any packets to the output file. + * When some streams are "sparse" (i.e. there are large gaps between + * successive packets), this can result in excessive buffering. + * + * This field specifies the maximum difference between the timestamps of the + * first and the last packet in the muxing queue, above which libavformat + * will output a packet regardless of whether it has queued a packet for all + * the streams. + * + * Muxing only, set by the caller before avformat_write_header(). + */ + int64_t max_interleave_delta; + /** * Transport stream id. * This will be moved into demuxer private options. Thus no API/ABI compatibility diff --git a/libavformat/mux.c b/libavformat/mux.c index 71a099f643..0b89406f4e 100644 --- a/libavformat/mux.c +++ b/libavformat/mux.c @@ -713,7 +713,6 @@ int ff_interleave_packet_per_dts(AVFormatContext *s, AVPacket *out, { AVPacketList *pktl; int stream_count = 0, noninterleaved_count = 0; - int64_t delta_dts_max = 0; int i, ret; if (pkt) { @@ -730,27 +729,38 @@ int ff_interleave_packet_per_dts(AVFormatContext *s, AVPacket *out, } } - if (s->internal->nb_interleaved_streams == stream_count) { + if (s->internal->nb_interleaved_streams == stream_count) flush = 1; - } else if (!flush) { - for (i=0; i < s->nb_streams; i++) { - if (s->streams[i]->last_in_packet_buffer) { - int64_t delta_dts = - av_rescale_q(s->streams[i]->last_in_packet_buffer->pkt.dts, - s->streams[i]->time_base, - AV_TIME_BASE_Q) - - av_rescale_q(s->packet_buffer->pkt.dts, - s->streams[s->packet_buffer->pkt.stream_index]->time_base, - AV_TIME_BASE_Q); - delta_dts_max= FFMAX(delta_dts_max, delta_dts); - } + + if (s->max_interleave_delta > 0 && s->packet_buffer && !flush) { + AVPacket *top_pkt = &s->packet_buffer->pkt; + int64_t delta_dts = INT64_MIN; + int64_t top_dts = av_rescale_q(top_pkt->dts, + s->streams[top_pkt->stream_index]->time_base, + AV_TIME_BASE_Q); + + for (i = 0; i < s->nb_streams; i++) { + int64_t last_dts; + const AVPacketList *last = s->streams[i]->last_in_packet_buffer; + + if (!last) + continue; + + last_dts = av_rescale_q(last->pkt.dts, + s->streams[i]->time_base, + AV_TIME_BASE_Q); + delta_dts = FFMAX(delta_dts, last_dts - top_dts); } - if (s->internal->nb_interleaved_streams == stream_count+noninterleaved_count && - delta_dts_max > 20*AV_TIME_BASE) { - av_log(s, AV_LOG_DEBUG, "flushing with %d noninterleaved\n", noninterleaved_count); + + if (delta_dts > s->max_interleave_delta) { + av_log(s, AV_LOG_DEBUG, + "Delay between the first packet and last packet in the " + "muxing queue is %"PRId64" > %"PRId64": forcing output\n", + delta_dts, s->max_interleave_delta); flush = 1; } } + if (stream_count && flush) { AVStream *st; pktl = s->packet_buffer; diff --git a/libavformat/options_table.h b/libavformat/options_table.h index b42a762738..ca30fd29e3 100644 --- a/libavformat/options_table.h +++ b/libavformat/options_table.h @@ -79,6 +79,7 @@ static const AVOption avformat_options[] = { {"flush_packets", "enable flushing of the I/O context after each packet", OFFSET(flush_packets), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, E}, {"metadata_header_padding", "set number of bytes to be written as padding in a metadata header", OFFSET(metadata_header_padding), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, E}, {"output_ts_offset", "set output timestamp offset", OFFSET(output_ts_offset), AV_OPT_TYPE_DURATION, {.i64 = 0}, -INT64_MAX, INT64_MAX, E}, +{"max_interleave_delta", "maximum buffering duration for interleaving", OFFSET(max_interleave_delta), AV_OPT_TYPE_INT64, { .i64 = 10000000 }, 0, INT64_MAX, E }, {NULL}, }; diff --git a/libavformat/version.h b/libavformat/version.h index 7a9aa4d4c7..0fcbe60eaa 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -30,8 +30,8 @@ #include "libavutil/version.h" #define LIBAVFORMAT_VERSION_MAJOR 55 -#define LIBAVFORMAT_VERSION_MINOR 29 -#define LIBAVFORMAT_VERSION_MICRO 101 +#define LIBAVFORMAT_VERSION_MINOR 30 +#define LIBAVFORMAT_VERSION_MICRO 100 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ LIBAVFORMAT_VERSION_MINOR, \