avformat/mux: implement AVFMT_FLAG_SHORTEST

This will allow fixing several bugs with the -shortest option

Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
pull/232/head
Michael Niedermayer 9 years ago
parent 09317e3e06
commit cb114ed464
  1. 4
      doc/formats.texi
  2. 1
      libavformat/avformat.h
  3. 5
      libavformat/internal.h
  4. 39
      libavformat/mux.c
  5. 1
      libavformat/options.c
  6. 1
      libavformat/options_table.h

@ -61,6 +61,10 @@ Reduce the latency introduced by optional buffering
Only write platform-, build- and time-independent data. Only write platform-, build- and time-independent data.
This ensures that file and data checksums are reproducible and match between This ensures that file and data checksums are reproducible and match between
platforms. Its primary use is for regression testing. platforms. Its primary use is for regression testing.
@item shortest
Stop muxing at the end of the shortest stream.
It may be needed to increase max_interleave_delta to avoid flusing the longer
streams before EOF.
@end table @end table
@item seek2any @var{integer} (@emph{input}) @item seek2any @var{integer} (@emph{input})

@ -1448,6 +1448,7 @@ typedef struct AVFormatContext {
#define AVFMT_FLAG_PRIV_OPT 0x20000 ///< Enable use of private options by delaying codec open (this could be made default once all code is converted) #define AVFMT_FLAG_PRIV_OPT 0x20000 ///< Enable use of private options by delaying codec open (this could be made default once all code is converted)
#define AVFMT_FLAG_KEEP_SIDE_DATA 0x40000 ///< Don't merge side data but keep it separate. #define AVFMT_FLAG_KEEP_SIDE_DATA 0x40000 ///< Don't merge side data but keep it separate.
#define AVFMT_FLAG_FAST_SEEK 0x80000 ///< Enable fast, but inaccurate seeks for some formats #define AVFMT_FLAG_FAST_SEEK 0x80000 ///< Enable fast, but inaccurate seeks for some formats
#define AVFMT_FLAG_SHORTEST 0x100000 ///< Stop muxing when the shortest stream stops.
/** /**
* Maximum size of the data read from input for determining * Maximum size of the data read from input for determining

@ -125,6 +125,11 @@ struct AVFormatInternal {
*/ */
int header_written; int header_written;
int write_header_ret; int write_header_ret;
/**
* Timestamp of the end of the shortest stream.
*/
int64_t shortest_end;
}; };
struct AVStreamInternal { struct AVStreamInternal {

@ -1032,6 +1032,7 @@ int ff_interleave_packet_per_dts(AVFormatContext *s, AVPacket *out,
int stream_count = 0; int stream_count = 0;
int noninterleaved_count = 0; int noninterleaved_count = 0;
int i, ret; int i, ret;
int eof = flush;
if (pkt) { if (pkt) {
if ((ret = ff_interleave_add_packet(s, pkt, interleave_compare_dts)) < 0) if ((ret = ff_interleave_add_packet(s, pkt, interleave_compare_dts)) < 0)
@ -1084,6 +1085,44 @@ int ff_interleave_packet_per_dts(AVFormatContext *s, AVPacket *out,
} }
} }
if (s->internal->packet_buffer &&
eof &&
(s->flags & AVFMT_FLAG_SHORTEST) &&
s->internal->shortest_end == AV_NOPTS_VALUE) {
AVPacket *top_pkt = &s->internal->packet_buffer->pkt;
s->internal->shortest_end = av_rescale_q(top_pkt->dts,
s->streams[top_pkt->stream_index]->time_base,
AV_TIME_BASE_Q);
}
if (s->internal->shortest_end != AV_NOPTS_VALUE) {
while (s->internal->packet_buffer) {
AVPacket *top_pkt = &s->internal->packet_buffer->pkt;
AVStream *st;
int64_t top_dts = av_rescale_q(top_pkt->dts,
s->streams[top_pkt->stream_index]->time_base,
AV_TIME_BASE_Q);
if (s->internal->shortest_end + 1 >= top_dts)
break;
pktl = s->internal->packet_buffer;
st = s->streams[pktl->pkt.stream_index];
s->internal->packet_buffer = pktl->next;
if (!s->internal->packet_buffer)
s->internal->packet_buffer_end = NULL;
if (st->last_in_packet_buffer == pktl)
st->last_in_packet_buffer = NULL;
av_packet_unref(&pktl->pkt);
av_freep(&pktl);
flush = 0;
}
}
if (stream_count && flush) { if (stream_count && flush) {
AVStream *st; AVStream *st;
pktl = s->internal->packet_buffer; pktl = s->internal->packet_buffer;

@ -143,6 +143,7 @@ AVFormatContext *avformat_alloc_context(void)
} }
ic->internal->offset = AV_NOPTS_VALUE; ic->internal->offset = AV_NOPTS_VALUE;
ic->internal->raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE; ic->internal->raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE;
ic->internal->shortest_end = AV_NOPTS_VALUE;
return ic; return ic;
} }

@ -54,6 +54,7 @@ static const AVOption avformat_options[] = {
{"nobuffer", "reduce the latency introduced by optional buffering", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_NOBUFFER }, 0, INT_MAX, D, "fflags"}, {"nobuffer", "reduce the latency introduced by optional buffering", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_NOBUFFER }, 0, INT_MAX, D, "fflags"},
{"seek2any", "allow seeking to non-keyframes on demuxer level when supported", OFFSET(seek2any), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, D}, {"seek2any", "allow seeking to non-keyframes on demuxer level when supported", OFFSET(seek2any), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, D},
{"bitexact", "do not write random/volatile data", 0, AV_OPT_TYPE_CONST, { .i64 = AVFMT_FLAG_BITEXACT }, 0, 0, E, "fflags" }, {"bitexact", "do not write random/volatile data", 0, AV_OPT_TYPE_CONST, { .i64 = AVFMT_FLAG_BITEXACT }, 0, 0, E, "fflags" },
{"shortest", "stop muxing with the shortest stream", 0, AV_OPT_TYPE_CONST, { .i64 = AVFMT_FLAG_SHORTEST }, 0, 0, E, "fflags" },
{"analyzeduration", "specify how many microseconds are analyzed to probe the input", OFFSET(max_analyze_duration), AV_OPT_TYPE_INT64, {.i64 = 0 }, 0, INT64_MAX, D}, {"analyzeduration", "specify how many microseconds are analyzed to probe the input", OFFSET(max_analyze_duration), AV_OPT_TYPE_INT64, {.i64 = 0 }, 0, INT64_MAX, D},
{"cryptokey", "decryption key", OFFSET(key), AV_OPT_TYPE_BINARY, {.dbl = 0}, 0, 0, D}, {"cryptokey", "decryption key", OFFSET(key), AV_OPT_TYPE_BINARY, {.dbl = 0}, 0, 0, D},
{"indexmem", "max memory used for timestamp index (per stream)", OFFSET(max_index_size), AV_OPT_TYPE_INT, {.i64 = 1<<20 }, 0, INT_MAX, D}, {"indexmem", "max memory used for timestamp index (per stream)", OFFSET(max_index_size), AV_OPT_TYPE_INT, {.i64 = 1<<20 }, 0, INT_MAX, D},

Loading…
Cancel
Save