From patchwork Tue Mar 5 17:50:48 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicolas Gaullier X-Patchwork-Id: 46816 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a21:3944:b0:19e:cdac:8cce with SMTP id ac4csp565917pzc; Tue, 5 Mar 2024 09:51:14 -0800 (PST) X-Forwarded-Encrypted: i=2; AJvYcCVNIKZV7REJge06z6z/uuWk/qoqqdIzfWtFCAjCY3AHL3dvbrZG/D+ZtsS0wA64HyI1RQ6D4kbf3Xqz7dKoX3ISA4TBCC4cwZkNfw== X-Google-Smtp-Source: AGHT+IG6tZOJ3IYP+22lCXxW1yB5FwdrCzzeTpMVlWPu3tJv59tvnkDhj/+9H0YJ9WrpImmB8ZUx X-Received: by 2002:a17:906:f2d1:b0:a45:7d04:c1fa with SMTP id gz17-20020a170906f2d100b00a457d04c1famr3069840ejb.67.1709661074282; Tue, 05 Mar 2024 09:51:14 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1709661074; cv=none; d=google.com; s=arc-20160816; b=1JryrfmEprGhm78qhEeGIWT1QLv2riGBTgaxwZvFIeeGlrcpn3XaKqI8hxiFbJi4hO lqiDbi6rGvILxz2lijZCoTGeBYIHpcqynJa55gs/8MRpuyLmpp5guFaw6s+8jthEn6aE gw0ws3Zl8bQ5tY8XpYHFPTY9+tdHISI8ASWmd08wuLVo/ogzjJgdXaWknH9Jnn6YaCHt odoIYYUaamE/cQJBQYtfEffdO4tTooAdtgdnLM9G+QCQKUsTsZ9yjfONqpnbak/VZVEB O8sC60RdCWcccAaiPwLPu33ZvOGt0VbPRieNqIO2WPJmh+V/9E3b0pO9z1/ZSW3z/Gil C1jg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:cc:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:mime-version:references:in-reply-to :message-id:date:to:from:delivered-to; bh=cY4n1TBfrclFy9CjxDagb3mu8TJDOkJg5+pn29YQbh0=; fh=zgMS+X4RExv2k7fU8QdWClnqVJdqO/9UbUuBS5xxJDs=; b=iKBdfwtbvHb1tAnDwP2YGEJvnt7PSzjsxId2cWJfcNV7EqFEVAdyDLZhdNJadlcuWA aRmYbEIpIymDUeEroqIeY9CDS524X3w57pZbswfNgMpKc8SfN3wA7E/ivZ55MEc0pr/T Q5IZLKEo/bZEbCUDK8hn2alZJhETruZLG4rV8QTlV0eoZ1Egdy5YT4b2YE4bKRI+cf7R YyaZxWOnpmNKDvJiUOho94Cv1UVfdmCjiTjG21yzVksYIL2D78dsdTKsEiYzkfXxnjdW 6hHT9ujh8V0t4x+4I9pRsH97Wn5JLCXeKOSyqVSmipWFr63sLgHNucScRfMrbQVL2IxD ByRg==; dara=google.com ARC-Authentication-Results: i=1; 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 Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id ji1-20020a170907980100b00a45473db476si2096553ejc.288.2024.03.05.09.51.13; Tue, 05 Mar 2024 09:51:14 -0800 (PST) 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 81A9F68D0AF; Tue, 5 Mar 2024 19:51:02 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from srv-infra-1.infra.inf.glb.tvvideoms.com (www.inf.tvvideoms.com [213.205.126.156]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id A7E7B68CE09 for ; Tue, 5 Mar 2024 19:50:54 +0200 (EET) Received: from cji.paris (unknown [172.16.3.159]) by srv-infra-1.infra.inf.glb.tvvideoms.com (Postfix) with ESMTP id 7EB842062B; Tue, 5 Mar 2024 17:50:53 +0000 (UTC) From: Nicolas Gaullier To: ffmpeg-devel@ffmpeg.org Date: Tue, 5 Mar 2024 18:50:48 +0100 Message-Id: <20240305175048.2062540-2-nicolas.gaullier@cji.paris> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20240305175048.2062540-1-nicolas.gaullier@cji.paris> References: <20240305175048.2062540-1-nicolas.gaullier@cji.paris> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v3 1/1] avformat/demux: Add durationprobesize AVOption X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 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 Cc: Nicolas Gaullier Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: 4eDa/DR4AhSi Yet another probesize used to get the durations when estimate_timings_from_pts is required. It is aimed at users interested in better durations probing for itself, or because using avformat_find_stream_info indirectly and requiring exact values: for concatdec for example, especially if streamcopying above it. The current code is a performance trade-off that can fail to get video stream durations in a scenario with high bitrates and buffering for files ending cleanly (as opposed to live captures): the physical gap between the last video packet and the last audio packet is very high in such a case. Default behaviour is unchanged: 250k up to 250k << 6 (step by step) Setting this new option has two effects: - override the maximum probesize (currently 250k << 6) - reduce the number of steps to 1 instead of 6, this is to avoid detecting the audio "too early" and failing to reach a video packet. Even if a single audio stream duration is found but not the other audio/video stream durations, there will be a retry, so at the end the full user-overriden probesize will be used as expected by the user. Signed-off-by: Nicolas Gaullier --- doc/APIchanges | 3 +++ doc/formats.texi | 16 +++++++++++++++- libavformat/avformat.h | 12 ++++++++++++ libavformat/demux.c | 13 ++++++++----- libavformat/options_table.h | 1 + libavformat/version.h | 2 +- 6 files changed, 40 insertions(+), 7 deletions(-) diff --git a/doc/APIchanges b/doc/APIchanges index 523945e511..c87d52fdbc 100644 --- a/doc/APIchanges +++ b/doc/APIchanges @@ -2,6 +2,9 @@ The last version increases of all libraries were on 2023-02-09 API changes, most recent first: +2024-03-05 - xxxxxxxxxx - lavf 60.25.100 - avformat.h + Add AVFormatContext.duration_probesize + 2024-03-05 - xxxxxxxxxx - lavf 60.24.100 - avformat.h Add avformat_stream_group_name(). diff --git a/doc/formats.texi b/doc/formats.texi index 69fc1457a4..9cada03a6e 100644 --- a/doc/formats.texi +++ b/doc/formats.texi @@ -225,9 +225,23 @@ Specifies the maximum number of streams. This can be used to reject files that would require too many resources due to a large number of streams. @item skip_estimate_duration_from_pts @var{bool} (@emph{input}) -Skip estimation of input duration when calculated using PTS. +Skip estimation of input duration if it requires an additional probing for pts at end of file. At present, applicable for MPEG-PS and MPEG-TS. +@item durationprobesize @var{integer} (@emph{input}) +Set probing size for input duration estimation when it actually requires an additional probing +for pts at end of file. +At present, applicable for MPEG-PS and MPEG-TS. +It is aimed at users interested in better durations probing for itself, or indirectly +for specific use cases like using the concat demuxer. +Files with high bitrates and ending cleanly (as opposed to live captures), can lead +to a large physical gap between the last video packet and the last audio packet, +so many bytes have to be read in order to get a video stream duration. +Setting this value has a performance impact even for small files because the probing size is fixed. +Default behaviour is a trade-off, largely adaptive: the probing size may range from +250K up to 16M, but it is not extended to get streams durations at all costs. +Must be an integer not lesser than 1, or 0 for default behaviour. + @item strict, f_strict @var{integer} (@emph{input/output}) Specify how strictly to follow the standards. @code{f_strict} is deprecated and should be used only via the @command{ffmpeg} tool. diff --git a/libavformat/avformat.h b/libavformat/avformat.h index 3a584993dd..d904ff0cd3 100644 --- a/libavformat/avformat.h +++ b/libavformat/avformat.h @@ -1952,6 +1952,8 @@ typedef struct AVFormatContext { * Skip duration calcuation in estimate_timings_from_pts. * - encoding: unused * - decoding: set by user + * + * @sa duration_probesize */ int skip_estimate_duration_from_pts; @@ -1994,6 +1996,16 @@ typedef struct AVFormatContext { * Freed by libavformat in avformat_free_context(). */ AVStreamGroup **stream_groups; + + /** + * Maximum number of bytes read from input in order to determine stream durations + * when using estimate_timings_from_pts in avformat_find_stream_info(). + * Demuxing only, set by the caller before avformat_find_stream_info(). + * Can be set to 0 to let avformat choose using a heuristic. + * + * @sa skip_estimate_duration_from_pts + */ + int64_t duration_probesize; } AVFormatContext; /** diff --git a/libavformat/demux.c b/libavformat/demux.c index 2e1d0ed66d..4a570ca2ce 100644 --- a/libavformat/demux.c +++ b/libavformat/demux.c @@ -1836,8 +1836,9 @@ static void estimate_timings_from_bit_rate(AVFormatContext *ic) "Estimating duration from bitrate, this may be inaccurate\n"); } -#define DURATION_MAX_READ_SIZE 250000LL -#define DURATION_MAX_RETRY 6 +#define DURATION_MAX_READ_SIZE_DEFAULT 250000LL +#define DURATION_MAX_RETRY_DEFAULT 6 +#define DURATION_MAX_RETRY_USER 1 /* only usable for MPEG-PS streams */ static void estimate_timings_from_pts(AVFormatContext *ic, int64_t old_offset) @@ -1845,6 +1846,8 @@ static void estimate_timings_from_pts(AVFormatContext *ic, int64_t old_offset) FFFormatContext *const si = ffformatcontext(ic); AVPacket *const pkt = si->pkt; int num, den, read_size, ret; + int64_t duration_max_read_size = ic->duration_probesize ? ic->duration_probesize >> DURATION_MAX_RETRY_USER : DURATION_MAX_READ_SIZE_DEFAULT; + int duration_max_retry = ic->duration_probesize ? DURATION_MAX_RETRY_USER : DURATION_MAX_RETRY_DEFAULT; int found_duration = 0; int is_end; int64_t filesize, offset, duration; @@ -1880,7 +1883,7 @@ static void estimate_timings_from_pts(AVFormatContext *ic, int64_t old_offset) filesize = ic->pb ? avio_size(ic->pb) : 0; do { is_end = found_duration; - offset = filesize - (DURATION_MAX_READ_SIZE << retry); + offset = filesize - (duration_max_read_size << retry); if (offset < 0) offset = 0; @@ -1889,7 +1892,7 @@ static void estimate_timings_from_pts(AVFormatContext *ic, int64_t old_offset) for (;;) { AVStream *st; FFStream *sti; - if (read_size >= DURATION_MAX_READ_SIZE << (FFMAX(retry - 1, 0))) + if (read_size >= duration_max_read_size << (FFMAX(retry - 1, 0))) break; do { @@ -1943,7 +1946,7 @@ static void estimate_timings_from_pts(AVFormatContext *ic, int64_t old_offset) } } while (!is_end && offset && - ++retry <= DURATION_MAX_RETRY); + ++retry <= duration_max_retry); av_opt_set_int(ic, "skip_changes", 0, AV_OPT_SEARCH_CHILDREN); diff --git a/libavformat/options_table.h b/libavformat/options_table.h index b9dca147f9..0cc921a28d 100644 --- a/libavformat/options_table.h +++ b/libavformat/options_table.h @@ -108,6 +108,7 @@ static const AVOption avformat_options[] = { {"max_streams", "maximum number of streams", OFFSET(max_streams), AV_OPT_TYPE_INT, { .i64 = 1000 }, 0, INT_MAX, D }, {"skip_estimate_duration_from_pts", "skip duration calculation in estimate_timings_from_pts", OFFSET(skip_estimate_duration_from_pts), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, D}, {"max_probe_packets", "Maximum number of packets to probe a codec", OFFSET(max_probe_packets), AV_OPT_TYPE_INT, { .i64 = 2500 }, 0, INT_MAX, D }, +{"durationprobesize", "maximum number of bytes to probe the durations of the streams in estimate_timings_from_pts", OFFSET(duration_probesize), AV_OPT_TYPE_INT64, {.i64 = 0 }, 0, INT64_MAX, D}, {NULL}, }; diff --git a/libavformat/version.h b/libavformat/version.h index 6c2776460b..966ebb7ed3 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -31,7 +31,7 @@ #include "version_major.h" -#define LIBAVFORMAT_VERSION_MINOR 24 +#define LIBAVFORMAT_VERSION_MINOR 25 #define LIBAVFORMAT_VERSION_MICRO 100 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \