From patchwork Fri Aug 12 19:28:08 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael Niedermayer X-Patchwork-Id: 161 Delivered-To: ffmpegpatchwork@gmail.com Received: by 10.103.140.67 with SMTP id o64csp400793vsd; Fri, 12 Aug 2016 12:31:41 -0700 (PDT) X-Received: by 10.194.106.200 with SMTP id gw8mr17089160wjb.147.1471030301267; Fri, 12 Aug 2016 12:31:41 -0700 (PDT) Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id g2si8340268wjh.266.2016.08.12.12.31.40; Fri, 12 Aug 2016 12:31:41 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id B18AD68A034; Fri, 12 Aug 2016 22:31:29 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from vie01a-dmta-pe02-1.mx.upcmail.net (vie01a-dmta-pe02-1.mx.upcmail.net [62.179.121.157]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 4D533689FF1 for ; Fri, 12 Aug 2016 22:31:14 +0300 (EEST) Received: from [172.31.216.43] (helo=vie01a-pemc-psmtp-pe01) by vie01a-dmta-pe02.mx.upcmail.net with esmtp (Exim 4.87) (envelope-from ) id 1bYIAk-00007S-6o for ffmpeg-devel@ffmpeg.org; Fri, 12 Aug 2016 21:31:14 +0200 Received: from localhost ([213.47.41.20]) by vie01a-pemc-psmtp-pe01 with SMTP @ mailcloud.upcmail.net id WKXD1t0030S5wYM01KXE3r; Fri, 12 Aug 2016 21:31:14 +0200 X-SourceIP: 213.47.41.20 From: Michael Niedermayer To: FFmpeg development discussions and patches Date: Fri, 12 Aug 2016 21:28:08 +0200 Message-Id: <20160812192808.6153-1-michael@niedermayer.cc> X-Mailer: git-send-email 2.9.2 Subject: [FFmpeg-devel] [PATCH] avformat/mux: implement AVFMT_FLAG_SHORTEST X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" This will allow fixing several bugs with the -shortest option Signed-off-by: Michael Niedermayer --- libavformat/avformat.h | 1 + libavformat/internal.h | 5 +++++ libavformat/mux.c | 40 +++++++++++++++++++++++++++++++++++++++- libavformat/options.c | 1 + libavformat/options_table.h | 1 + 5 files changed, 47 insertions(+), 1 deletion(-) diff --git a/libavformat/avformat.h b/libavformat/avformat.h index d8a6cf3..eecae9f 100644 --- a/libavformat/avformat.h +++ b/libavformat/avformat.h @@ -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_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_SHORTEST 0x100000 ///< Stop muxing when the shortest stream stops. /** * Maximum size of the data read from input for determining diff --git a/libavformat/internal.h b/libavformat/internal.h index 0119749..b77f114 100644 --- a/libavformat/internal.h +++ b/libavformat/internal.h @@ -125,6 +125,11 @@ struct AVFormatInternal { */ int header_written; int write_header_ret; + + /** + * Timestamp of the end of the shortest stream. + */ + int64_t shortest_end; }; struct AVStreamInternal { diff --git a/libavformat/mux.c b/libavformat/mux.c index e9973ed..493d656 100644 --- a/libavformat/mux.c +++ b/libavformat/mux.c @@ -1040,7 +1040,7 @@ int ff_interleave_packet_per_dts(AVFormatContext *s, AVPacket *out, } if (s->internal->nb_interleaved_streams == stream_count) - flush = 1; + flush = 2; if (s->max_interleave_delta > 0 && s->internal->packet_buffer && @@ -1075,6 +1075,44 @@ int ff_interleave_packet_per_dts(AVFormatContext *s, AVPacket *out, } } + if (s->internal->packet_buffer && + flush == 1 && + (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) { AVStream *st; pktl = s->internal->packet_buffer; diff --git a/libavformat/options.c b/libavformat/options.c index 04d9c45..25a506e 100644 --- a/libavformat/options.c +++ b/libavformat/options.c @@ -143,6 +143,7 @@ AVFormatContext *avformat_alloc_context(void) } ic->internal->offset = AV_NOPTS_VALUE; ic->internal->raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE; + ic->internal->shortest_end = AV_NOPTS_VALUE; return ic; } diff --git a/libavformat/options_table.h b/libavformat/options_table.h index 3b74d1b..699809a 100644 --- a/libavformat/options_table.h +++ b/libavformat/options_table.h @@ -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"}, {"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" }, +{"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}, {"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},