Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
* [FFmpeg-devel] [PATCH v2 1/2] avformat: add avformat_query_seekable
@ 2025-04-15 10:39 Gyan Doshi
  2025-04-15 10:39 ` [FFmpeg-devel] [PATCH v2 2/2] ffprobe: show seekability details in format section Gyan Doshi
                   ` (3 more replies)
  0 siblings, 4 replies; 8+ messages in thread
From: Gyan Doshi @ 2025-04-15 10:39 UTC (permalink / raw)
  To: ffmpeg-devel

Utility function to report seekability features for a given input.

Useful for ffprobe and to extend seek possibilities in fftools.
---
v2:
   made constants more descriptive
   add exception for rtsp false negative seekability

 doc/APIchanges         |  3 +++
 libavformat/avformat.h | 22 ++++++++++++++++++
 libavformat/seek.c     | 53 ++++++++++++++++++++++++++++++++++++++++++
 libavformat/version.h  |  2 +-
 4 files changed, 79 insertions(+), 1 deletion(-)

diff --git a/doc/APIchanges b/doc/APIchanges
index 65bf5a9419..879f56b572 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -2,6 +2,9 @@ The last version increases of all libraries were on 2025-03-28
 
 API changes, most recent first:
 
+2025-04-xx - xxxxxxxxxx - lavf 62.1.100 - avformat.h
+  Add avformat_query_seekable().
+
 2025-04-07 - 19e9a203b7 - lavu 60.01.100 - dict.h
   Add AV_DICT_DEDUP.
 
diff --git a/libavformat/avformat.h b/libavformat/avformat.h
index 498c3020a5..f9da5e9e79 100644
--- a/libavformat/avformat.h
+++ b/libavformat/avformat.h
@@ -2338,6 +2338,28 @@ int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp,
  */
 int avformat_seek_file(AVFormatContext *s, int stream_index, int64_t min_ts, int64_t ts, int64_t max_ts, int flags);
 
+#define AVSEEKABLE_IO_NORMAL       0x00000001 ///< I/O is seekable like a local file
+#define AVSEEKABLE_IO_PROTOCOL     0x00000002 ///< I/O seek is through protocol request via avio_seek_time
+#define AVSEEKABLE_VIA_DEMUXER     0x00000004 ///< demuxer has a seek function
+#define AVSEEKABLE_VIA_PKTSCAN     0x00000008 ///< seek is performed by consuming and scanning packet timestamps
+#define AVSEEKABLE_BY_TIME         0x00000100 ///< seek target can be a timestamp
+#define AVSEEKABLE_BY_BYTE         0x00000200 ///< seek target can be in bytes
+#define AVSEEKABLE_BY_FRAME        0x00000400 ///< seek target can be a frame index
+#define AVSEEKABLE_PROP_PTS        0x00010000 ///< seek target timestamp is expected to be PTS
+#define AVSEEKABLE_PROP_FAST       0x00020000 ///< demuxer allows fast but inaccurate seeking
+#define AVSEEKABLE_PROP_FWDONLY    0x00040000 ///< set seek will be equal or forward of specified seek point
+
+/**
+ * Report if and how a seek can be performed in a given input.
+ *
+ * @param s            media file handle
+ *
+ * @return 0 if no seek can be performed on input,
+ *         -1 if the fmt ctx is NULL or is not an input
+ *         else return AVSEEKABLE_ bitflags indicating seekability features.
+ */
+int avformat_query_seekable(AVFormatContext *s);
+
 /**
  * Discard all internally buffered data. This can be useful when dealing with
  * discontinuities in the byte stream. Generally works only with formats that
diff --git a/libavformat/seek.c b/libavformat/seek.c
index c0d94371e6..8be1bdec30 100644
--- a/libavformat/seek.c
+++ b/libavformat/seek.c
@@ -712,6 +712,59 @@ int avformat_seek_file(AVFormatContext *s, int stream_index, int64_t min_ts,
     return ret;
 }
 
+int avformat_query_seekable(AVFormatContext *s)
+{
+    int ret = 0;
+
+    if (!s || !s->iformat)
+        return -1;
+
+    if ( strcmp(s->iformat->name, "rtsp") && (!(s->pb && s->pb->seekable) || s->ctx_flags & AVFMTCTX_UNSEEKABLE) )
+        return 0;
+
+    if (s->pb->seekable & AVIO_SEEKABLE_NORMAL)
+        ret |= AVSEEKABLE_IO_NORMAL;
+
+    if (s->pb->seekable & AVIO_SEEKABLE_TIME)
+        ret |= AVSEEKABLE_IO_PROTOCOL;
+
+    if (ffifmt(s->iformat)->read_seek || ffifmt(s->iformat)->read_seek2)
+        ret |= AVSEEKABLE_VIA_DEMUXER;
+
+    if (ffifmt(s->iformat)->read_timestamp && !(s->iformat->flags & AVFMT_NOBINSEARCH))
+        ret |= AVSEEKABLE_VIA_PKTSCAN;
+
+    if (!(s->iformat->flags & AVFMT_NOTIMESTAMPS))
+        ret |= AVSEEKABLE_BY_TIME;
+
+    // TODO: incomplete, a few demuxers don't set flag but error out on byte seek
+    if (!(s->iformat->flags & AVFMT_NO_BYTE_SEEK))
+        ret |= AVSEEKABLE_BY_BYTE;
+
+    // TODO: no flag for frame seeking. Add flag and enable this check
+    if (s->iformat->flags & 0)
+        ret |= AVSEEKABLE_BY_FRAME;
+
+    if (s->iformat->flags & AVFMT_SEEK_TO_PTS)
+        ret |= AVSEEKABLE_PROP_PTS;
+
+    // TODO: flag exists but not added to the demuxers which support it
+    if (s->iformat->flags & AVFMT_FLAG_FAST_SEEK)
+        ret |= AVSEEKABLE_PROP_FAST;
+
+    if (!(ret & AVSEEKABLE_VIA_DEMUXER) && ret & AVSEEKABLE_VIA_PKTSCAN)
+        ret |= AVSEEKABLE_PROP_FWDONLY;
+
+    if ( !(ret & AVSEEKABLE_VIA_DEMUXER) &&
+         !(ret & AVSEEKABLE_VIA_PKTSCAN) &&
+         !(ret & AVSEEKABLE_BY_BYTE) &&
+         !(ret & AVSEEKABLE_IO_PROTOCOL) &&
+         (s->iformat->flags & AVFMT_NOGENSEARCH) )
+        ret = 0;
+
+    return ret;
+}
+
 /** Flush the frame reader. */
 void ff_read_frame_flush(AVFormatContext *s)
 {
diff --git a/libavformat/version.h b/libavformat/version.h
index 752aac16f7..a7c80dc564 100644
--- a/libavformat/version.h
+++ b/libavformat/version.h
@@ -31,7 +31,7 @@
 
 #include "version_major.h"
 
-#define LIBAVFORMAT_VERSION_MINOR   0
+#define LIBAVFORMAT_VERSION_MINOR   1
 #define LIBAVFORMAT_VERSION_MICRO 100
 
 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
-- 
2.49.0

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [FFmpeg-devel] [PATCH v2 2/2] ffprobe: show seekability details in format section
  2025-04-15 10:39 [FFmpeg-devel] [PATCH v2 1/2] avformat: add avformat_query_seekable Gyan Doshi
@ 2025-04-15 10:39 ` Gyan Doshi
  2025-04-15 11:49 ` [FFmpeg-devel] [PATCH v2 1/2] avformat: add avformat_query_seekable Zhao Zhili
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 8+ messages in thread
From: Gyan Doshi @ 2025-04-15 10:39 UTC (permalink / raw)
  To: ffmpeg-devel

---
 doc/ffprobe.xsd                      |  2 ++
 fftools/ffprobe.c                    | 15 ++++++++++++++-
 tests/ref/fate/cavs-demux            |  2 +-
 tests/ref/fate/ffprobe_compact       |  2 +-
 tests/ref/fate/ffprobe_csv           |  2 +-
 tests/ref/fate/ffprobe_default       |  2 ++
 tests/ref/fate/ffprobe_flat          |  2 ++
 tests/ref/fate/ffprobe_ini           |  2 ++
 tests/ref/fate/ffprobe_json          |  2 ++
 tests/ref/fate/ffprobe_xml           |  2 +-
 tests/ref/fate/ffprobe_xsd           |  2 +-
 tests/ref/fate/flv-demux             |  2 +-
 tests/ref/fate/gapless-mp3-side-data |  2 +-
 tests/ref/fate/oggopus-demux         |  2 +-
 tests/ref/fate/ts-demux              |  2 +-
 tests/ref/fate/ts-opus-demux         |  2 +-
 tests/ref/fate/ts-small-demux        |  2 +-
 tests/ref/fate/ts-timed-id3-demux    |  2 +-
 18 files changed, 36 insertions(+), 13 deletions(-)

diff --git a/doc/ffprobe.xsd b/doc/ffprobe.xsd
index b53b799227..ef9c9a006c 100644
--- a/doc/ffprobe.xsd
+++ b/doc/ffprobe.xsd
@@ -432,6 +432,8 @@
     <xsd:attribute name="size"             type="xsd:long"/>
     <xsd:attribute name="bit_rate"         type="xsd:long"/>
     <xsd:attribute name="probe_score"      type="xsd:int"/>
+    <xsd:attribute name="seekable"         type="xsd:boolean"/>
+    <xsd:attribute name="seek_backward"    type="xsd:boolean"/>
   </xsd:complexType>
 
   <xsd:complexType name="tagType">
diff --git a/fftools/ffprobe.c b/fftools/ffprobe.c
index e0a7322523..0fbf7ab057 100644
--- a/fftools/ffprobe.c
+++ b/fftools/ffprobe.c
@@ -2260,7 +2260,7 @@ static int show_format(AVTextFormatContext *tfc, InputFile *ifile)
 {
     AVFormatContext *fmt_ctx = ifile->fmt_ctx;
     int64_t size = fmt_ctx->pb ? avio_size(fmt_ctx->pb) : -1;
-    int ret = 0;
+    int seekable, ret = 0;
 
     avtext_print_section_header(tfc, NULL, SECTION_ID_FORMAT);
     print_str_validate("filename", fmt_ctx->url);
@@ -2279,6 +2279,19 @@ static int show_format(AVTextFormatContext *tfc, InputFile *ifile)
     if (fmt_ctx->bit_rate > 0) print_val    ("bit_rate", fmt_ctx->bit_rate, unit_bit_per_second_str);
     else                       print_str_opt("bit_rate", "N/A");
     print_int("probe_score", fmt_ctx->probe_score);
+
+    seekable = avformat_query_seekable(fmt_ctx);
+    if (seekable > 0) {
+        print_int("seekable",      1);
+        if (seekable & AVSEEKABLE_PROP_FWDONLY)
+            print_int("seek_backward", 0);
+        else
+            print_int("seek_backward", 1);
+    }
+    else {
+        print_int("seekable",      0);
+        print_int("seek_backward", 0);
+    }
     if (do_show_format_tags)
         ret = show_tags(tfc, fmt_ctx->metadata, SECTION_ID_FORMAT_TAGS);
 
diff --git a/tests/ref/fate/cavs-demux b/tests/ref/fate/cavs-demux
index b1e2c2fd25..a7f5eda73b 100644
--- a/tests/ref/fate/cavs-demux
+++ b/tests/ref/fate/cavs-demux
@@ -59,4 +59,4 @@ packet|codec_type=video|stream_index=0|pts=2320000|pts_time=1.933333|dts=2320000
 packet|codec_type=video|stream_index=0|pts=2360000|pts_time=1.966667|dts=2360000|dts_time=1.966667|duration=40000|duration_time=0.033333|size=83|pos=172252|flags=K__|data_hash=CRC32:a941bdf0
 packet|codec_type=video|stream_index=0|pts=2400000|pts_time=2.000000|dts=2400000|dts_time=2.000000|duration=40000|duration_time=0.033333|size=5417|pos=172335|flags=K__|data_hash=CRC32:9d0d503b
 stream|index=0|codec_name=cavs|profile=unknown|codec_type=video|codec_tag_string=[0][0][0][0]|codec_tag=0x0000|width=1280|height=720|coded_width=1280|coded_height=720|has_b_frames=0|sample_aspect_ratio=N/A|display_aspect_ratio=N/A|pix_fmt=yuv420p|level=-99|color_range=unknown|color_space=unknown|color_transfer=unknown|color_primaries=unknown|chroma_location=unspecified|field_order=unknown|refs=1|id=N/A|r_frame_rate=30/1|avg_frame_rate=25/1|time_base=1/1200000|start_pts=N/A|start_time=N/A|duration_ts=N/A|duration=N/A|bit_rate=N/A|max_bit_rate=N/A|bits_per_raw_sample=N/A|nb_frames=N/A|nb_read_frames=N/A|nb_read_packets=60|extradata_size=18|extradata_hash=CRC32:1255d52e|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0|disposition:multilayer=0
-format|filename=bunny.mp4|nb_streams=1|nb_programs=0|nb_stream_groups=0|format_name=cavsvideo|start_time=N/A|duration=N/A|size=177752|bit_rate=N/A|probe_score=51
+format|filename=bunny.mp4|nb_streams=1|nb_programs=0|nb_stream_groups=0|format_name=cavsvideo|start_time=N/A|duration=N/A|size=177752|bit_rate=N/A|probe_score=51|seekable=1|seek_backward=1
diff --git a/tests/ref/fate/ffprobe_compact b/tests/ref/fate/ffprobe_compact
index 68b9acf599..c4c0140656 100644
--- a/tests/ref/fate/ffprobe_compact
+++ b/tests/ref/fate/ffprobe_compact
@@ -29,4 +29,4 @@ frame|media_type=video|stream_index=2|key_frame=1|pts=6144|pts_time=0.120000|pkt
 stream|index=0|codec_name=pcm_s16le|profile=unknown|codec_type=audio|codec_tag_string=PSD[16]|codec_tag=0x10445350|sample_fmt=s16|sample_rate=44100|channels=1|channel_layout=unknown|bits_per_sample=16|initial_padding=0|id=N/A|r_frame_rate=0/0|avg_frame_rate=0/0|time_base=1/44100|start_pts=0|start_time=0.000000|duration_ts=N/A|duration=N/A|bit_rate=705600|max_bit_rate=N/A|bits_per_raw_sample=N/A|nb_frames=N/A|nb_read_frames=6|nb_read_packets=6|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0|disposition:multilayer=0|tag:encoder=Lavc pcm_s16le|tag:E=mc²
 stream|index=1|codec_name=rawvideo|profile=unknown|codec_type=video|codec_tag_string=RGB[24]|codec_tag=0x18424752|width=320|height=240|coded_width=320|coded_height=240|has_b_frames=0|sample_aspect_ratio=1:1|display_aspect_ratio=4:3|pix_fmt=rgb24|level=-99|color_range=unknown|color_space=unknown|color_transfer=unknown|color_primaries=unknown|chroma_location=unspecified|field_order=unknown|refs=1|id=N/A|r_frame_rate=25/1|avg_frame_rate=25/1|time_base=1/51200|start_pts=0|start_time=0.000000|duration_ts=N/A|duration=N/A|bit_rate=N/A|max_bit_rate=N/A|bits_per_raw_sample=N/A|nb_frames=N/A|nb_read_frames=4|nb_read_packets=4|disposition:default=1|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0|disposition:multilayer=0|tag:encoder=Lavc rawvideo|tag:title=foobar|tag:duration_ts=field-and-tags-conflict-attempt
 stream|index=2|codec_name=rawvideo|profile=unknown|codec_type=video|codec_tag_string=RGB[24]|codec_tag=0x18424752|width=100|height=100|coded_width=100|coded_height=100|has_b_frames=0|sample_aspect_ratio=1:1|display_aspect_ratio=1:1|pix_fmt=rgb24|level=-99|color_range=unknown|color_space=unknown|color_transfer=unknown|color_primaries=unknown|chroma_location=unspecified|field_order=unknown|refs=1|id=N/A|r_frame_rate=25/1|avg_frame_rate=25/1|time_base=1/51200|start_pts=0|start_time=0.000000|duration_ts=N/A|duration=N/A|bit_rate=N/A|max_bit_rate=N/A|bits_per_raw_sample=N/A|nb_frames=N/A|nb_read_frames=4|nb_read_packets=4|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0|disposition:multilayer=0|tag:encoder=Lavc rawvideo
-format|filename=tests/data/ffprobe-test.nut|nb_streams=3|nb_programs=0|nb_stream_groups=0|format_name=nut|start_time=0.000000|duration=0.120000|size=1053646|bit_rate=70243066|probe_score=100|tag:title=ffprobe test file|tag:comment='A comment with CSV, XML & JSON special chars': <tag value="x">|tag:comment2=I ♥ Üñîçød€
+format|filename=tests/data/ffprobe-test.nut|nb_streams=3|nb_programs=0|nb_stream_groups=0|format_name=nut|start_time=0.000000|duration=0.120000|size=1053646|bit_rate=70243066|probe_score=100|seekable=1|seek_backward=1|tag:title=ffprobe test file|tag:comment='A comment with CSV, XML & JSON special chars': <tag value="x">|tag:comment2=I ♥ Üñîçød€
diff --git a/tests/ref/fate/ffprobe_csv b/tests/ref/fate/ffprobe_csv
index 37c67bb4e3..af3840a2ef 100644
--- a/tests/ref/fate/ffprobe_csv
+++ b/tests/ref/fate/ffprobe_csv
@@ -29,4 +29,4 @@ frame,video,2,1,6144,0.120000,6144,0.120000,6144,0.120000,2048,0.040000,1023566,
 stream,0,pcm_s16le,unknown,audio,PSD[16],0x10445350,s16,44100,1,unknown,16,0,N/A,0/0,0/0,1/44100,0,0.000000,N/A,N/A,705600,N/A,N/A,N/A,6,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,Lavc pcm_s16le,mc²
 stream,1,rawvideo,unknown,video,RGB[24],0x18424752,320,240,320,240,0,1:1,4:3,rgb24,-99,unknown,unknown,unknown,unknown,unspecified,unknown,1,N/A,25/1,25/1,1/51200,0,0.000000,N/A,N/A,N/A,N/A,N/A,N/A,4,4,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,Lavc rawvideo,foobar,field-and-tags-conflict-attempt
 stream,2,rawvideo,unknown,video,RGB[24],0x18424752,100,100,100,100,0,1:1,1:1,rgb24,-99,unknown,unknown,unknown,unknown,unspecified,unknown,1,N/A,25/1,25/1,1/51200,0,0.000000,N/A,N/A,N/A,N/A,N/A,N/A,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,Lavc rawvideo
-format,tests/data/ffprobe-test.nut,3,0,0,nut,0.000000,0.120000,1053646,70243066,100,ffprobe test file,"'A comment with CSV, XML & JSON special chars': <tag value=""x"">",I ♥ Üñîçød€
+format,tests/data/ffprobe-test.nut,3,0,0,nut,0.000000,0.120000,1053646,70243066,100,1,1,ffprobe test file,"'A comment with CSV, XML & JSON special chars': <tag value=""x"">",I ♥ Üñîçød€
diff --git a/tests/ref/fate/ffprobe_default b/tests/ref/fate/ffprobe_default
index 2d38d4d211..172025c219 100644
--- a/tests/ref/fate/ffprobe_default
+++ b/tests/ref/fate/ffprobe_default
@@ -736,6 +736,8 @@ duration=0.120000
 size=1053646
 bit_rate=70243066
 probe_score=100
+seekable=1
+seek_backward=1
 TAG:title=ffprobe test file
 TAG:comment='A comment with CSV, XML & JSON special chars': <tag value="x">
 TAG:comment2=I ♥ Üñîçød€
diff --git a/tests/ref/fate/ffprobe_flat b/tests/ref/fate/ffprobe_flat
index b9aac8a007..b9301d6b23 100644
--- a/tests/ref/fate/ffprobe_flat
+++ b/tests/ref/fate/ffprobe_flat
@@ -673,6 +673,8 @@ format.duration="0.120000"
 format.size="1053646"
 format.bit_rate="70243066"
 format.probe_score=100
+format.seekable=1
+format.seek_backward=1
 format.tags.title="ffprobe test file"
 format.tags.comment="'A comment with CSV, XML & JSON special chars': <tag value=\"x\">"
 format.tags.comment2="I ♥ Üñîçød€"
diff --git a/tests/ref/fate/ffprobe_ini b/tests/ref/fate/ffprobe_ini
index d353c09339..1830a2544d 100644
--- a/tests/ref/fate/ffprobe_ini
+++ b/tests/ref/fate/ffprobe_ini
@@ -750,6 +750,8 @@ duration=0.120000
 size=1053646
 bit_rate=70243066
 probe_score=100
+seekable=1
+seek_backward=1
 
 [format.tags]
 title=ffprobe test file
diff --git a/tests/ref/fate/ffprobe_json b/tests/ref/fate/ffprobe_json
index ac295181b5..ee39c1f7d5 100644
--- a/tests/ref/fate/ffprobe_json
+++ b/tests/ref/fate/ffprobe_json
@@ -699,6 +699,8 @@
         "size": "1053646",
         "bit_rate": "70243066",
         "probe_score": 100,
+        "seekable": 1,
+        "seek_backward": 1,
         "tags": {
             "title": "ffprobe test file",
             "comment": "'A comment with CSV, XML & JSON special chars': <tag value=\"x\">",
diff --git a/tests/ref/fate/ffprobe_xml b/tests/ref/fate/ffprobe_xml
index 0917813fa5..42044b2a82 100644
--- a/tests/ref/fate/ffprobe_xml
+++ b/tests/ref/fate/ffprobe_xml
@@ -55,7 +55,7 @@
         </stream>
     </streams>
 
-    <format filename="tests/data/ffprobe-test.nut" nb_streams="3" nb_programs="0" nb_stream_groups="0" format_name="nut" start_time="0.000000" duration="0.120000" size="1053646" bit_rate="70243066" probe_score="100">
+    <format filename="tests/data/ffprobe-test.nut" nb_streams="3" nb_programs="0" nb_stream_groups="0" format_name="nut" start_time="0.000000" duration="0.120000" size="1053646" bit_rate="70243066" probe_score="100" seekable="1" seek_backward="1">
         <tags>
             <tag key="title" value="ffprobe test file"/>
             <tag key="comment" value="'A comment with CSV, XML &amp; JSON special chars': &lt;tag value=&quot;x&quot;&gt;"/>
diff --git a/tests/ref/fate/ffprobe_xsd b/tests/ref/fate/ffprobe_xsd
index 743746738d..b59f4567b2 100644
--- a/tests/ref/fate/ffprobe_xsd
+++ b/tests/ref/fate/ffprobe_xsd
@@ -55,7 +55,7 @@
         </stream>
     </streams>
 
-    <format filename="tests/data/ffprobe-test.nut" nb_streams="3" nb_programs="0" nb_stream_groups="0" format_name="nut" start_time="0.000000" duration="0.120000" size="1053646" bit_rate="70243066" probe_score="100">
+    <format filename="tests/data/ffprobe-test.nut" nb_streams="3" nb_programs="0" nb_stream_groups="0" format_name="nut" start_time="0.000000" duration="0.120000" size="1053646" bit_rate="70243066" probe_score="100" seekable="1" seek_backward="1">
         <tags>
             <tag key="title" value="ffprobe test file"/>
             <tag key="comment" value="'A comment with CSV, XML &amp; JSON special chars': &lt;tag value=&quot;x&quot;&gt;"/>
diff --git a/tests/ref/fate/flv-demux b/tests/ref/fate/flv-demux
index 429cc50874..80599e3f9a 100644
--- a/tests/ref/fate/flv-demux
+++ b/tests/ref/fate/flv-demux
@@ -603,4 +603,4 @@ packet|codec_type=audio|stream_index=1|pts=11656|pts_time=11.656000|dts=11656|dt
 packet|codec_type=video|stream_index=0|pts=11678|pts_time=11.678000|dts=11678|dts_time=11.678000|duration=33|duration_time=0.033000|size=1190|pos=510794|flags=__C|data_hash=CRC32:a0206c90
 stream|index=0|codec_name=h264|profile=77|codec_type=video|codec_tag_string=[0][0][0][0]|codec_tag=0x0000|width=426|height=240|coded_width=426|coded_height=240|has_b_frames=1|sample_aspect_ratio=1:1|display_aspect_ratio=71:40|pix_fmt=yuv420p|level=21|color_range=unknown|color_space=unknown|color_transfer=unknown|color_primaries=unknown|chroma_location=left|field_order=progressive|refs=1|is_avc=true|nal_length_size=4|id=N/A|r_frame_rate=30000/1001|avg_frame_rate=30/1|time_base=1/1000|start_pts=0|start_time=0.000000|duration_ts=N/A|duration=N/A|bit_rate=393929|max_bit_rate=N/A|bits_per_raw_sample=8|nb_frames=N/A|nb_read_frames=N/A|nb_read_packets=351|extradata_size=39|extradata_hash=CRC32:07b85ca9|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0|disposition:multilayer=0
 stream|index=1|codec_name=aac|profile=1|codec_type=audio|codec_tag_string=[0][0][0][0]|codec_tag=0x0000|sample_fmt=fltp|sample_rate=22050|channels=2|channel_layout=stereo|bits_per_sample=0|initial_padding=0|id=N/A|r_frame_rate=0/0|avg_frame_rate=0/0|time_base=1/1000|start_pts=0|start_time=0.000000|duration_ts=N/A|duration=N/A|bit_rate=67874|max_bit_rate=N/A|bits_per_raw_sample=N/A|nb_frames=N/A|nb_read_frames=N/A|nb_read_packets=252|extradata_size=2|extradata_hash=CRC32:d039c029|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0|disposition:multilayer=0
-format|filename=Enigma_Principles_of_Lust-part.flv|nb_streams=2|nb_programs=0|nb_stream_groups=0|format_name=flv|start_time=0.000000|duration=210.209999|size=512000|bit_rate=19485|probe_score=100|tag:hasKeyframes=true|tag:hasMetadata=true|tag:datasize=11970544|tag:hasVideo=true|tag:canSeekToEnd=false|tag:lasttimestamp=210|tag:lastkeyframetimestamp=210|tag:audiosize=1791332|tag:hasAudio=true|tag:audiodelay=0|tag:videosize=10176110|tag:metadatadate=2011-02-27T11:00:33.125000Z|tag:metadatacreator=inlet media FLVTool2 v1.0.6 - http://www.inlet-media.de/flvtool2|tag:hasCuePoints=false
+format|filename=Enigma_Principles_of_Lust-part.flv|nb_streams=2|nb_programs=0|nb_stream_groups=0|format_name=flv|start_time=0.000000|duration=210.209999|size=512000|bit_rate=19485|probe_score=100|seekable=1|seek_backward=1|tag:hasKeyframes=true|tag:hasMetadata=true|tag:datasize=11970544|tag:hasVideo=true|tag:canSeekToEnd=false|tag:lasttimestamp=210|tag:lastkeyframetimestamp=210|tag:audiosize=1791332|tag:hasAudio=true|tag:audiodelay=0|tag:videosize=10176110|tag:metadatadate=2011-02-27T11:00:33.125000Z|tag:metadatacreator=inlet media FLVTool2 v1.0.6 - http://www.inlet-media.de/flvtool2|tag:hasCuePoints=false
diff --git a/tests/ref/fate/gapless-mp3-side-data b/tests/ref/fate/gapless-mp3-side-data
index 878425f092..a5abc0508b 100644
--- a/tests/ref/fate/gapless-mp3-side-data
+++ b/tests/ref/fate/gapless-mp3-side-data
@@ -594,4 +594,4 @@ packet|codec_type=audio|stream_index=0|pts=218234880|pts_time=15.464490|dts=2182
 packet|codec_type=audio|stream_index=0|pts=218603520|pts_time=15.490612|dts=218603520|dts_time=15.490612|duration=368640|duration_time=0.026122|size=418|pos=249300|flags=K__|data_hash=CRC32:d5fb5f9c|side_datum/skip_samples:side_data_type=Skip Samples|side_datum/skip_samples:skip_samples=0|side_datum/skip_samples:discard_padding=303|side_datum/skip_samples:skip_reason=0|side_datum/skip_samples:discard_reason=0
 packet|codec_type=audio|stream_index=0|pts=218972160|pts_time=15.516735|dts=218972160|dts_time=15.516735|duration=368640|duration_time=0.026122|size=418|pos=249718|flags=K__|data_hash=CRC32:3789f3cf|side_datum/skip_samples:side_data_type=Skip Samples|side_datum/skip_samples:skip_samples=0|side_datum/skip_samples:discard_padding=1152|side_datum/skip_samples:skip_reason=0|side_datum/skip_samples:discard_reason=0
 stream|index=0|codec_name=mp3|profile=unknown|codec_type=audio|codec_tag_string=[0][0][0][0]|codec_tag=0x0000|sample_fmt=fltp|sample_rate=44100|channels=2|channel_layout=stereo|bits_per_sample=0|initial_padding=0|id=N/A|r_frame_rate=0/0|avg_frame_rate=0/0|time_base=1/14112000|start_pts=353600|start_time=0.025057|duration_ts=218521600|duration=15.484807|bit_rate=128000|max_bit_rate=N/A|bits_per_raw_sample=N/A|nb_frames=N/A|nb_read_frames=N/A|nb_read_packets=595|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0|disposition:multilayer=0|tag:encoder=LAME3.93 
-format|filename=gapless.mp3|nb_streams=1|nb_programs=0|nb_stream_groups=0|format_name=mp3|start_time=0.025057|duration=15.484807|size=250264|bit_rate=129295|probe_score=51|tag:title=test
+format|filename=gapless.mp3|nb_streams=1|nb_programs=0|nb_stream_groups=0|format_name=mp3|start_time=0.025057|duration=15.484807|size=250264|bit_rate=129295|probe_score=51|seekable=1|seek_backward=1|tag:title=test
diff --git a/tests/ref/fate/oggopus-demux b/tests/ref/fate/oggopus-demux
index 03b7b76cf2..38cbe4709a 100644
--- a/tests/ref/fate/oggopus-demux
+++ b/tests/ref/fate/oggopus-demux
@@ -40,4 +40,4 @@ packet|codec_type=audio|stream_index=0|pts=36124|pts_time=0.752583|dts=36124|dts
 packet|codec_type=audio|stream_index=0|pts=37084|pts_time=0.772583|dts=37084|dts_time=0.772583|duration=960|duration_time=0.020000|size=217|pos=841|flags=K__|data_hash=CRC32:06797ece
 packet|codec_type=audio|stream_index=0|pts=38044|pts_time=0.792583|dts=38044|dts_time=0.792583|duration=356|duration_time=0.007417|size=359|pos=841|flags=K__|data_hash=CRC32:01ca3f8f|side_datum/skip_samples:side_data_type=Skip Samples|side_datum/skip_samples:skip_samples=0|side_datum/skip_samples:discard_padding=604|side_datum/skip_samples:skip_reason=0|side_datum/skip_samples:discard_reason=0
 stream|index=0|codec_name=opus|profile=unknown|codec_type=audio|codec_tag_string=[0][0][0][0]|codec_tag=0x0000|sample_fmt=fltp|sample_rate=48000|channels=2|channel_layout=stereo|bits_per_sample=0|initial_padding=356|id=N/A|r_frame_rate=0/0|avg_frame_rate=0/0|time_base=1/48000|start_pts=0|start_time=0.000000|duration_ts=38756|duration=0.807417|bit_rate=N/A|max_bit_rate=N/A|bits_per_raw_sample=N/A|nb_frames=N/A|nb_read_frames=N/A|nb_read_packets=41|extradata_size=19|extradata_hash=CRC32:58ba5ff3|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0|disposition:multilayer=0|tag:ENCODER=opusenc from opus-tools 0.1.9|tag:ENCODER_OPTIONS=--discard-comments
-format|filename=intro-partial.opus|nb_streams=1|nb_programs=0|nb_stream_groups=0|format_name=ogg|start_time=0.000000|duration=0.807417|size=10250|bit_rate=101558|probe_score=100
+format|filename=intro-partial.opus|nb_streams=1|nb_programs=0|nb_stream_groups=0|format_name=ogg|start_time=0.000000|duration=0.807417|size=10250|bit_rate=101558|probe_score=100|seekable=1|seek_backward=1
diff --git a/tests/ref/fate/ts-demux b/tests/ref/fate/ts-demux
index 6a830d0d99..8f70f187b5 100644
--- a/tests/ref/fate/ts-demux
+++ b/tests/ref/fate/ts-demux
@@ -26,4 +26,4 @@ packet|codec_type=audio|stream_index=2|pts=3912645580|pts_time=43473.839778|dts=
 stream|index=0|codec_name=mpeg2video|profile=4|codec_type=video|codec_tag_string=[2][0][0][0]|codec_tag=0x0002|width=1280|height=720|coded_width=0|coded_height=0|has_b_frames=1|sample_aspect_ratio=1:1|display_aspect_ratio=16:9|pix_fmt=yuv420p|level=4|color_range=tv|color_space=unknown|color_transfer=unknown|color_primaries=unknown|chroma_location=left|field_order=progressive|refs=1|ts_id=32776|ts_packetsize=188|id=0x31|r_frame_rate=60000/1001|avg_frame_rate=60000/1001|time_base=1/90000|start_pts=3912669846|start_time=43474.109400|duration_ts=19519|duration=0.216878|bit_rate=15000000|max_bit_rate=N/A|bits_per_raw_sample=N/A|nb_frames=N/A|nb_read_frames=N/A|nb_read_packets=15|extradata_size=150|extradata_hash=CRC32:53134fa8|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0|disposition:multilayer=0|side_datum/cpb_properties:side_data_type=CPB properties|side_datum/cpb_properties:max_bitrate=15000000|side_datum/cpb_properties:min_bitrate=0|side_datum/cpb_properties:avg_bitrate=0|side_datum/cpb_properties:buffer_size=9781248|side_datum/cpb_properties:vbv_delay=-1
 stream|index=1|codec_name=ac3|profile=unknown|codec_type=audio|codec_tag_string=[4][0][0][0]|codec_tag=0x0004|sample_fmt=fltp|sample_rate=48000|channels=6|channel_layout=5.1(side)|bits_per_sample=0|initial_padding=0|dmix_mode=0|ltrt_cmixlev=0.000000|ltrt_surmixlev=0.000000|loro_cmixlev=0.000000|loro_surmixlev=0.000000|ts_id=32776|ts_packetsize=188|id=0x34|r_frame_rate=0/0|avg_frame_rate=0/0|time_base=1/90000|start_pts=3912633305|start_time=43473.703389|duration_ts=14400|duration=0.160000|bit_rate=384000|max_bit_rate=N/A|bits_per_raw_sample=N/A|nb_frames=N/A|nb_read_frames=N/A|nb_read_packets=5|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0|disposition:multilayer=0|tag:language=eng
 stream|index=2|codec_name=ac3|profile=unknown|codec_type=audio|codec_tag_string=[4][0][0][0]|codec_tag=0x0004|sample_fmt=fltp|sample_rate=48000|channels=2|channel_layout=stereo|bits_per_sample=0|initial_padding=0|dmix_mode=0|ltrt_cmixlev=0.000000|ltrt_surmixlev=0.000000|loro_cmixlev=0.000000|loro_surmixlev=0.000000|ts_id=32776|ts_packetsize=188|id=0x35|r_frame_rate=0/0|avg_frame_rate=0/0|time_base=1/90000|start_pts=3912634060|start_time=43473.711778|duration_ts=14400|duration=0.160000|bit_rate=192000|max_bit_rate=N/A|bits_per_raw_sample=N/A|nb_frames=N/A|nb_read_frames=N/A|nb_read_packets=5|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0|disposition:multilayer=0|tag:language=es
-format|filename=mp3ac325-4864-small.ts|nb_streams=3|nb_programs=1|nb_stream_groups=0|format_name=mpegts|start_time=43473.703389|duration=0.622889|size=512000|bit_rate=6575810|probe_score=50
+format|filename=mp3ac325-4864-small.ts|nb_streams=3|nb_programs=1|nb_stream_groups=0|format_name=mpegts|start_time=43473.703389|duration=0.622889|size=512000|bit_rate=6575810|probe_score=50|seekable=1|seek_backward=0
diff --git a/tests/ref/fate/ts-opus-demux b/tests/ref/fate/ts-opus-demux
index d13b97aa6f..d00014523d 100644
--- a/tests/ref/fate/ts-opus-demux
+++ b/tests/ref/fate/ts-opus-demux
@@ -511,4 +511,4 @@ packet|codec_type=audio|stream_index=0|pts=916200|pts_time=10.180000|dts=916200|
 packet|codec_type=audio|stream_index=0|pts=918000|pts_time=10.200000|dts=918000|dts_time=10.200000|duration=1800|duration_time=0.020000|size=761|pos=510044|flags=K__|data_hash=CRC32:75113c11|side_datum/mpegts_stream_id:side_data_type=MPEGTS Stream ID|side_datum/mpegts_stream_id:id=189
 packet|codec_type=audio|stream_index=0|pts=919800|pts_time=10.220000|dts=919800|dts_time=10.220000|duration=1800|duration_time=0.020000|size=759|pos=510984|flags=K__|data_hash=CRC32:59fc266f|side_datum/mpegts_stream_id:side_data_type=MPEGTS Stream ID|side_datum/mpegts_stream_id:id=189
 stream|index=0|codec_name=opus|profile=unknown|codec_type=audio|codec_tag_string=Opus|codec_tag=0x7375704f|sample_fmt=fltp|sample_rate=48000|channels=8|channel_layout=7.1|bits_per_sample=0|initial_padding=0|ts_id=51338|ts_packetsize=188|id=0x44|r_frame_rate=0/0|avg_frame_rate=0/0|time_base=1/90000|start_pts=0|start_time=0.000000|duration_ts=919800|duration=10.220000|bit_rate=N/A|max_bit_rate=N/A|bits_per_raw_sample=N/A|nb_frames=N/A|nb_read_frames=N/A|nb_read_packets=512|extradata_size=29|extradata_hash=CRC32:6d6089a7|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0|disposition:multilayer=0
-format|filename=test-8-7.1.opus-small.ts|nb_streams=1|nb_programs=1|nb_stream_groups=0|format_name=mpegts|start_time=0.000000|duration=10.220000|size=512000|bit_rate=400782|probe_score=50
+format|filename=test-8-7.1.opus-small.ts|nb_streams=1|nb_programs=1|nb_stream_groups=0|format_name=mpegts|start_time=0.000000|duration=10.220000|size=512000|bit_rate=400782|probe_score=50|seekable=1|seek_backward=0
diff --git a/tests/ref/fate/ts-small-demux b/tests/ref/fate/ts-small-demux
index 6e29b29896..b93184d083 100644
--- a/tests/ref/fate/ts-small-demux
+++ b/tests/ref/fate/ts-small-demux
@@ -73,4 +73,4 @@ packet|codec_type=video|stream_index=0|pts=552000|pts_time=6.133333|dts=552000|d
 packet|codec_type=video|stream_index=0|pts=558000|pts_time=6.200000|dts=558000|dts_time=6.200000|duration=6000|duration_time=0.066667|size=16|pos=15792|flags=___|data_hash=CRC32:27b943ef|side_datum/mpegts_stream_id:side_data_type=MPEGTS Stream ID|side_datum/mpegts_stream_id:id=224
 packet|codec_type=video|stream_index=0|pts=564000|pts_time=6.266667|dts=564000|dts_time=6.266667|duration=6000|duration_time=0.066667|size=16|pos=16356|flags=___|data_hash=CRC32:f7116111
 stream|index=0|codec_name=h264|profile=578|codec_type=video|codec_tag_string=[27][0][0][0]|codec_tag=0x001b|width=82|height=144|coded_width=82|coded_height=144|has_b_frames=0|sample_aspect_ratio=1:1|display_aspect_ratio=41:72|pix_fmt=yuv420p|level=10|color_range=unknown|color_space=unknown|color_transfer=unknown|color_primaries=unknown|chroma_location=left|field_order=progressive|refs=1|is_avc=false|nal_length_size=0|ts_id=1|ts_packetsize=188|id=0x100|r_frame_rate=15/1|avg_frame_rate=15/1|time_base=1/90000|start_pts=126000|start_time=1.400000|duration_ts=444000|duration=4.933333|bit_rate=N/A|max_bit_rate=N/A|bits_per_raw_sample=8|nb_frames=N/A|nb_read_frames=N/A|nb_read_packets=74|extradata_size=35|extradata_hash=CRC32:e62cae27|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0|disposition:multilayer=0
-format|filename=h264small.ts|nb_streams=1|nb_programs=1|nb_stream_groups=0|format_name=mpegts|start_time=1.400000|duration=4.933333|size=16544|bit_rate=26828|probe_score=50
+format|filename=h264small.ts|nb_streams=1|nb_programs=1|nb_stream_groups=0|format_name=mpegts|start_time=1.400000|duration=4.933333|size=16544|bit_rate=26828|probe_score=50|seekable=1|seek_backward=0
diff --git a/tests/ref/fate/ts-timed-id3-demux b/tests/ref/fate/ts-timed-id3-demux
index 3de1ca2990..b5a4bae50d 100644
--- a/tests/ref/fate/ts-timed-id3-demux
+++ b/tests/ref/fate/ts-timed-id3-demux
@@ -1,4 +1,4 @@
 packet|codec_type=data|stream_index=0|pts=126000|pts_time=1.400000|dts=126000|dts_time=1.400000|duration=N/A|duration_time=N/A|size=26|pos=564|flags=K__|data_hash=CRC32:469f474b|side_datum/mpegts_stream_id:side_data_type=MPEGTS Stream ID|side_datum/mpegts_stream_id:id=189
 packet|codec_type=data|stream_index=0|pts=577350|pts_time=6.415000|dts=577350|dts_time=6.415000|duration=N/A|duration_time=N/A|size=26|pos=1316|flags=K__|data_hash=CRC32:469f474b|side_datum/mpegts_stream_id:side_data_type=MPEGTS Stream ID|side_datum/mpegts_stream_id:id=189
 stream|index=0|codec_name=timed_id3|profile=unknown|codec_type=data|codec_tag_string=ID3 |codec_tag=0x20334449|ts_id=1|ts_packetsize=188|id=0x100|r_frame_rate=0/0|avg_frame_rate=0/0|time_base=1/90000|start_pts=126000|start_time=1.400000|duration_ts=451350|duration=5.015000|bit_rate=N/A|max_bit_rate=N/A|bits_per_raw_sample=N/A|nb_frames=N/A|nb_read_frames=N/A|nb_read_packets=2|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0|disposition:multilayer=0
-format|filename=id3.ts|nb_streams=1|nb_programs=1|nb_stream_groups=0|format_name=mpegts|start_time=1.400000|duration=5.015000|size=1504|bit_rate=2399|probe_score=2
+format|filename=id3.ts|nb_streams=1|nb_programs=1|nb_stream_groups=0|format_name=mpegts|start_time=1.400000|duration=5.015000|size=1504|bit_rate=2399|probe_score=2|seekable=1|seek_backward=0
-- 
2.49.0

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [FFmpeg-devel] [PATCH v2 1/2] avformat: add avformat_query_seekable
  2025-04-15 10:39 [FFmpeg-devel] [PATCH v2 1/2] avformat: add avformat_query_seekable Gyan Doshi
  2025-04-15 10:39 ` [FFmpeg-devel] [PATCH v2 2/2] ffprobe: show seekability details in format section Gyan Doshi
@ 2025-04-15 11:49 ` Zhao Zhili
  2025-04-16  5:07 ` Andreas Rheinhardt
  2025-04-21 18:29 ` Stefano Sabatini
  3 siblings, 0 replies; 8+ messages in thread
From: Zhao Zhili @ 2025-04-15 11:49 UTC (permalink / raw)
  To: FFmpeg development discussions and patches



> On Apr 15, 2025, at 18:39, Gyan Doshi <ffmpeg@gyani.pro> wrote:
> 
> Utility function to report seekability features for a given input.
> 
> Useful for ffprobe and to extend seek possibilities in fftools.
> ---
> v2:
>   made constants more descriptive
>   add exception for rtsp false negative seekability
> 
> doc/APIchanges         |  3 +++
> libavformat/avformat.h | 22 ++++++++++++++++++
> libavformat/seek.c     | 53 ++++++++++++++++++++++++++++++++++++++++++
> libavformat/version.h  |  2 +-
> 4 files changed, 79 insertions(+), 1 deletion(-)
> 
> diff --git a/doc/APIchanges b/doc/APIchanges
> index 65bf5a9419..879f56b572 100644
> --- a/doc/APIchanges
> +++ b/doc/APIchanges
> @@ -2,6 +2,9 @@ The last version increases of all libraries were on 2025-03-28
> 
> API changes, most recent first:
> 
> +2025-04-xx - xxxxxxxxxx - lavf 62.1.100 - avformat.h
> +  Add avformat_query_seekable().
> +
> 2025-04-07 - 19e9a203b7 - lavu 60.01.100 - dict.h
>   Add AV_DICT_DEDUP.
> 
> diff --git a/libavformat/avformat.h b/libavformat/avformat.h
> index 498c3020a5..f9da5e9e79 100644
> --- a/libavformat/avformat.h
> +++ b/libavformat/avformat.h
> @@ -2338,6 +2338,28 @@ int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp,
>  */
> int avformat_seek_file(AVFormatContext *s, int stream_index, int64_t min_ts, int64_t ts, int64_t max_ts, int flags);
> 
> +#define AVSEEKABLE_IO_NORMAL       0x00000001 ///< I/O is seekable like a local file
> +#define AVSEEKABLE_IO_PROTOCOL     0x00000002 ///< I/O seek is through protocol request via avio_seek_time
> +#define AVSEEKABLE_VIA_DEMUXER     0x00000004 ///< demuxer has a seek function
> +#define AVSEEKABLE_VIA_PKTSCAN     0x00000008 ///< seek is performed by consuming and scanning packet timestamps
> +#define AVSEEKABLE_BY_TIME         0x00000100 ///< seek target can be a timestamp
> +#define AVSEEKABLE_BY_BYTE         0x00000200 ///< seek target can be in bytes
> +#define AVSEEKABLE_BY_FRAME        0x00000400 ///< seek target can be a frame index
> +#define AVSEEKABLE_PROP_PTS        0x00010000 ///< seek target timestamp is expected to be PTS
> +#define AVSEEKABLE_PROP_FAST       0x00020000 ///< demuxer allows fast but inaccurate seeking
> +#define AVSEEKABLE_PROP_FWDONLY    0x00040000 ///< set seek will be equal or forward of specified seek point
> +
> +/**
> + * Report if and how a seek can be performed in a given input.
> + *
> + * @param s            media file handle
> + *
> + * @return 0 if no seek can be performed on input,
> + *         -1 if the fmt ctx is NULL or is not an input
> + *         else return AVSEEKABLE_ bitflags indicating seekability features.
> + */
> +int avformat_query_seekable(AVFormatContext *s);
> +
> /**
>  * Discard all internally buffered data. This can be useful when dealing with
>  * discontinuities in the byte stream. Generally works only with formats that
> diff --git a/libavformat/seek.c b/libavformat/seek.c
> index c0d94371e6..8be1bdec30 100644
> --- a/libavformat/seek.c
> +++ b/libavformat/seek.c
> @@ -712,6 +712,59 @@ int avformat_seek_file(AVFormatContext *s, int stream_index, int64_t min_ts,
>     return ret;
> }
> 
> +int avformat_query_seekable(AVFormatContext *s)
> +{
> +    int ret = 0;
> +
> +    if (!s || !s->iformat)
> +        return -1;
> +
> +    if ( strcmp(s->iformat->name, "rtsp") && (!(s->pb && s->pb->seekable) || s->ctx_flags & AVFMTCTX_UNSEEKABLE) )
> +        return 0;

dvdvideo is also seekable. How about check AVFMT_NOFILE flag and seek method in FFInputFormat.

For rtsp, I think there is no way to query whether it’s really seeable or not until try to do that, at least no such information is exported for now.

> +
> +    if (s->pb->seekable & AVIO_SEEKABLE_NORMAL)
> +        ret |= AVSEEKABLE_IO_NORMAL;
> +
> +    if (s->pb->seekable & AVIO_SEEKABLE_TIME)
> +        ret |= AVSEEKABLE_IO_PROTOCOL;
> +
> +    if (ffifmt(s->iformat)->read_seek || ffifmt(s->iformat)->read_seek2)
> +        ret |= AVSEEKABLE_VIA_DEMUXER;
> +
> +    if (ffifmt(s->iformat)->read_timestamp && !(s->iformat->flags & AVFMT_NOBINSEARCH))
> +        ret |= AVSEEKABLE_VIA_PKTSCAN;
> +
> +    if (!(s->iformat->flags & AVFMT_NOTIMESTAMPS))
> +        ret |= AVSEEKABLE_BY_TIME;
> +
> +    // TODO: incomplete, a few demuxers don't set flag but error out on byte seek
> +    if (!(s->iformat->flags & AVFMT_NO_BYTE_SEEK))
> +        ret |= AVSEEKABLE_BY_BYTE;
> +
> +    // TODO: no flag for frame seeking. Add flag and enable this check
> +    if (s->iformat->flags & 0)
> +        ret |= AVSEEKABLE_BY_FRAME;
> +
> +    if (s->iformat->flags & AVFMT_SEEK_TO_PTS)
> +        ret |= AVSEEKABLE_PROP_PTS;
> +
> +    // TODO: flag exists but not added to the demuxers which support it
> +    if (s->iformat->flags & AVFMT_FLAG_FAST_SEEK)
> +        ret |= AVSEEKABLE_PROP_FAST;
> +
> +    if (!(ret & AVSEEKABLE_VIA_DEMUXER) && ret & AVSEEKABLE_VIA_PKTSCAN)
> +        ret |= AVSEEKABLE_PROP_FWDONLY;
> +
> +    if ( !(ret & AVSEEKABLE_VIA_DEMUXER) &&
> +         !(ret & AVSEEKABLE_VIA_PKTSCAN) &&
> +         !(ret & AVSEEKABLE_BY_BYTE) &&
> +         !(ret & AVSEEKABLE_IO_PROTOCOL) &&
> +         (s->iformat->flags & AVFMT_NOGENSEARCH) )
> +        ret = 0;
> +
> +    return ret;
> +}
> +
> /** Flush the frame reader. */
> void ff_read_frame_flush(AVFormatContext *s)
> {
> diff --git a/libavformat/version.h b/libavformat/version.h
> index 752aac16f7..a7c80dc564 100644
> --- a/libavformat/version.h
> +++ b/libavformat/version.h
> @@ -31,7 +31,7 @@
> 
> #include "version_major.h"
> 
> -#define LIBAVFORMAT_VERSION_MINOR   0
> +#define LIBAVFORMAT_VERSION_MINOR   1
> #define LIBAVFORMAT_VERSION_MICRO 100
> 
> #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
> -- 
> 2.49.0
> 
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
> 
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [FFmpeg-devel] [PATCH v2 1/2] avformat: add avformat_query_seekable
  2025-04-15 10:39 [FFmpeg-devel] [PATCH v2 1/2] avformat: add avformat_query_seekable Gyan Doshi
  2025-04-15 10:39 ` [FFmpeg-devel] [PATCH v2 2/2] ffprobe: show seekability details in format section Gyan Doshi
  2025-04-15 11:49 ` [FFmpeg-devel] [PATCH v2 1/2] avformat: add avformat_query_seekable Zhao Zhili
@ 2025-04-16  5:07 ` Andreas Rheinhardt
  2025-04-16 12:25   ` Gyan Doshi
  2025-04-21 18:29 ` Stefano Sabatini
  3 siblings, 1 reply; 8+ messages in thread
From: Andreas Rheinhardt @ 2025-04-16  5:07 UTC (permalink / raw)
  To: ffmpeg-devel

Gyan Doshi:
> Utility function to report seekability features for a given input.
> 
> Useful for ffprobe and to extend seek possibilities in fftools.
> ---
> v2:
>    made constants more descriptive
>    add exception for rtsp false negative seekability
> 
>  doc/APIchanges         |  3 +++
>  libavformat/avformat.h | 22 ++++++++++++++++++
>  libavformat/seek.c     | 53 ++++++++++++++++++++++++++++++++++++++++++
>  libavformat/version.h  |  2 +-
>  4 files changed, 79 insertions(+), 1 deletion(-)
> 
> diff --git a/doc/APIchanges b/doc/APIchanges
> index 65bf5a9419..879f56b572 100644
> --- a/doc/APIchanges
> +++ b/doc/APIchanges
> @@ -2,6 +2,9 @@ The last version increases of all libraries were on 2025-03-28
>  
>  API changes, most recent first:
>  
> +2025-04-xx - xxxxxxxxxx - lavf 62.1.100 - avformat.h
> +  Add avformat_query_seekable().
> +
>  2025-04-07 - 19e9a203b7 - lavu 60.01.100 - dict.h
>    Add AV_DICT_DEDUP.
>  
> diff --git a/libavformat/avformat.h b/libavformat/avformat.h
> index 498c3020a5..f9da5e9e79 100644
> --- a/libavformat/avformat.h
> +++ b/libavformat/avformat.h
> @@ -2338,6 +2338,28 @@ int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp,
>   */
>  int avformat_seek_file(AVFormatContext *s, int stream_index, int64_t min_ts, int64_t ts, int64_t max_ts, int flags);
>  
> +#define AVSEEKABLE_IO_NORMAL       0x00000001 ///< I/O is seekable like a local file
> +#define AVSEEKABLE_IO_PROTOCOL     0x00000002 ///< I/O seek is through protocol request via avio_seek_time
> +#define AVSEEKABLE_VIA_DEMUXER     0x00000004 ///< demuxer has a seek function
> +#define AVSEEKABLE_VIA_PKTSCAN     0x00000008 ///< seek is performed by consuming and scanning packet timestamps
> +#define AVSEEKABLE_BY_TIME         0x00000100 ///< seek target can be a timestamp
> +#define AVSEEKABLE_BY_BYTE         0x00000200 ///< seek target can be in bytes
> +#define AVSEEKABLE_BY_FRAME        0x00000400 ///< seek target can be a frame index
> +#define AVSEEKABLE_PROP_PTS        0x00010000 ///< seek target timestamp is expected to be PTS
> +#define AVSEEKABLE_PROP_FAST       0x00020000 ///< demuxer allows fast but inaccurate seeking
> +#define AVSEEKABLE_PROP_FWDONLY    0x00040000 ///< set seek will be equal or forward of specified seek point
> +
> +/**
> + * Report if and how a seek can be performed in a given input.
> + *
> + * @param s            media file handle
> + *
> + * @return 0 if no seek can be performed on input,
> + *         -1 if the fmt ctx is NULL or is not an input
> + *         else return AVSEEKABLE_ bitflags indicating seekability features.
> + */
> +int avformat_query_seekable(AVFormatContext *s);
> +
>  /**
>   * Discard all internally buffered data. This can be useful when dealing with
>   * discontinuities in the byte stream. Generally works only with formats that
> diff --git a/libavformat/seek.c b/libavformat/seek.c
> index c0d94371e6..8be1bdec30 100644
> --- a/libavformat/seek.c
> +++ b/libavformat/seek.c
> @@ -712,6 +712,59 @@ int avformat_seek_file(AVFormatContext *s, int stream_index, int64_t min_ts,
>      return ret;
>  }
>  
> +int avformat_query_seekable(AVFormatContext *s)
> +{
> +    int ret = 0;
> +
> +    if (!s || !s->iformat)
> +        return -1;
> +
> +    if ( strcmp(s->iformat->name, "rtsp") && (!(s->pb && s->pb->seekable) || s->ctx_flags & AVFMTCTX_UNSEEKABLE) )
> +        return 0;
> +
> +    if (s->pb->seekable & AVIO_SEEKABLE_NORMAL)
> +        ret |= AVSEEKABLE_IO_NORMAL;
> +
> +    if (s->pb->seekable & AVIO_SEEKABLE_TIME)
> +        ret |= AVSEEKABLE_IO_PROTOCOL;
> +
> +    if (ffifmt(s->iformat)->read_seek || ffifmt(s->iformat)->read_seek2)
> +        ret |= AVSEEKABLE_VIA_DEMUXER;

The existence of these functions does not imply that a given input is
seekable: E.g. some read_seek functions rely on an index being present
in the file and are useless/not better than reading linearly in case the
index is absent.

> +
> +    if (ffifmt(s->iformat)->read_timestamp && !(s->iformat->flags & AVFMT_NOBINSEARCH))
> +        ret |= AVSEEKABLE_VIA_PKTSCAN;
> +
> +    if (!(s->iformat->flags & AVFMT_NOTIMESTAMPS))
> +        ret |= AVSEEKABLE_BY_TIME;
> +
> +    // TODO: incomplete, a few demuxers don't set flag but error out on byte seek
> +    if (!(s->iformat->flags & AVFMT_NO_BYTE_SEEK))
> +        ret |= AVSEEKABLE_BY_BYTE;
> +
> +    // TODO: no flag for frame seeking. Add flag and enable this check
> +    if (s->iformat->flags & 0)
> +        ret |= AVSEEKABLE_BY_FRAME;
> +
> +    if (s->iformat->flags & AVFMT_SEEK_TO_PTS)
> +        ret |= AVSEEKABLE_PROP_PTS;
> +
> +    // TODO: flag exists but not added to the demuxers which support it
> +    if (s->iformat->flags & AVFMT_FLAG_FAST_SEEK)
> +        ret |= AVSEEKABLE_PROP_FAST;
> +
> +    if (!(ret & AVSEEKABLE_VIA_DEMUXER) && ret & AVSEEKABLE_VIA_PKTSCAN)
> +        ret |= AVSEEKABLE_PROP_FWDONLY;
> +
> +    if ( !(ret & AVSEEKABLE_VIA_DEMUXER) &&
> +         !(ret & AVSEEKABLE_VIA_PKTSCAN) &&
> +         !(ret & AVSEEKABLE_BY_BYTE) &&
> +         !(ret & AVSEEKABLE_IO_PROTOCOL) &&
> +         (s->iformat->flags & AVFMT_NOGENSEARCH) )
> +        ret = 0;
> +
> +    return ret;
> +}
> +
>  /** Flush the frame reader. */
>  void ff_read_frame_flush(AVFormatContext *s)
>  {
> diff --git a/libavformat/version.h b/libavformat/version.h
> index 752aac16f7..a7c80dc564 100644
> --- a/libavformat/version.h
> +++ b/libavformat/version.h
> @@ -31,7 +31,7 @@
>  
>  #include "version_major.h"
>  
> -#define LIBAVFORMAT_VERSION_MINOR   0
> +#define LIBAVFORMAT_VERSION_MINOR   1
>  #define LIBAVFORMAT_VERSION_MICRO 100
>  
>  #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [FFmpeg-devel] [PATCH v2 1/2] avformat: add avformat_query_seekable
  2025-04-16  5:07 ` Andreas Rheinhardt
@ 2025-04-16 12:25   ` Gyan Doshi
  0 siblings, 0 replies; 8+ messages in thread
From: Gyan Doshi @ 2025-04-16 12:25 UTC (permalink / raw)
  To: ffmpeg-devel



On 2025-04-16 10:37 am, Andreas Rheinhardt wrote:
> Gyan Doshi:
>> Utility function to report seekability features for a given input.
>>
>> Useful for ffprobe and to extend seek possibilities in fftools.
>> ---
>> v2:
>>     made constants more descriptive
>>     add exception for rtsp false negative seekability
>>
>>   doc/APIchanges         |  3 +++
>>   libavformat/avformat.h | 22 ++++++++++++++++++
>>   libavformat/seek.c     | 53 ++++++++++++++++++++++++++++++++++++++++++
>>   libavformat/version.h  |  2 +-
>>   4 files changed, 79 insertions(+), 1 deletion(-)
>>
>> diff --git a/doc/APIchanges b/doc/APIchanges
>> index 65bf5a9419..879f56b572 100644
>> --- a/doc/APIchanges
>> +++ b/doc/APIchanges
>> @@ -2,6 +2,9 @@ The last version increases of all libraries were on 2025-03-28
>>   
>>   API changes, most recent first:
>>   
>> +2025-04-xx - xxxxxxxxxx - lavf 62.1.100 - avformat.h
>> +  Add avformat_query_seekable().
>> +
>>   2025-04-07 - 19e9a203b7 - lavu 60.01.100 - dict.h
>>     Add AV_DICT_DEDUP.
>>   
>> diff --git a/libavformat/avformat.h b/libavformat/avformat.h
>> index 498c3020a5..f9da5e9e79 100644
>> --- a/libavformat/avformat.h
>> +++ b/libavformat/avformat.h
>> @@ -2338,6 +2338,28 @@ int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp,
>>    */
>>   int avformat_seek_file(AVFormatContext *s, int stream_index, int64_t min_ts, int64_t ts, int64_t max_ts, int flags);
>>   
>> +#define AVSEEKABLE_IO_NORMAL       0x00000001 ///< I/O is seekable like a local file
>> +#define AVSEEKABLE_IO_PROTOCOL     0x00000002 ///< I/O seek is through protocol request via avio_seek_time
>> +#define AVSEEKABLE_VIA_DEMUXER     0x00000004 ///< demuxer has a seek function
>> +#define AVSEEKABLE_VIA_PKTSCAN     0x00000008 ///< seek is performed by consuming and scanning packet timestamps
>> +#define AVSEEKABLE_BY_TIME         0x00000100 ///< seek target can be a timestamp
>> +#define AVSEEKABLE_BY_BYTE         0x00000200 ///< seek target can be in bytes
>> +#define AVSEEKABLE_BY_FRAME        0x00000400 ///< seek target can be a frame index
>> +#define AVSEEKABLE_PROP_PTS        0x00010000 ///< seek target timestamp is expected to be PTS
>> +#define AVSEEKABLE_PROP_FAST       0x00020000 ///< demuxer allows fast but inaccurate seeking
>> +#define AVSEEKABLE_PROP_FWDONLY    0x00040000 ///< set seek will be equal or forward of specified seek point
>> +
>> +/**
>> + * Report if and how a seek can be performed in a given input.
>> + *
>> + * @param s            media file handle
>> + *
>> + * @return 0 if no seek can be performed on input,
>> + *         -1 if the fmt ctx is NULL or is not an input
>> + *         else return AVSEEKABLE_ bitflags indicating seekability features.
>> + */
>> +int avformat_query_seekable(AVFormatContext *s);
>> +
>>   /**
>>    * Discard all internally buffered data. This can be useful when dealing with
>>    * discontinuities in the byte stream. Generally works only with formats that
>> diff --git a/libavformat/seek.c b/libavformat/seek.c
>> index c0d94371e6..8be1bdec30 100644
>> --- a/libavformat/seek.c
>> +++ b/libavformat/seek.c
>> @@ -712,6 +712,59 @@ int avformat_seek_file(AVFormatContext *s, int stream_index, int64_t min_ts,
>>       return ret;
>>   }
>>   
>> +int avformat_query_seekable(AVFormatContext *s)
>> +{
>> +    int ret = 0;
>> +
>> +    if (!s || !s->iformat)
>> +        return -1;
>> +
>> +    if ( strcmp(s->iformat->name, "rtsp") && (!(s->pb && s->pb->seekable) || s->ctx_flags & AVFMTCTX_UNSEEKABLE) )
>> +        return 0;
>> +
>> +    if (s->pb->seekable & AVIO_SEEKABLE_NORMAL)
>> +        ret |= AVSEEKABLE_IO_NORMAL;
>> +
>> +    if (s->pb->seekable & AVIO_SEEKABLE_TIME)
>> +        ret |= AVSEEKABLE_IO_PROTOCOL;
>> +
>> +    if (ffifmt(s->iformat)->read_seek || ffifmt(s->iformat)->read_seek2)
>> +        ret |= AVSEEKABLE_VIA_DEMUXER;
> The existence of these functions does not imply that a given input is
> seekable: E.g. some read_seek functions rely on an index being present
> in the file and are useless/not better than reading linearly in case the
> index is absent.

Seek performance is a secondary concern.
Basic seek support means that the client can reduce the number of 
packets they have to deal with before they start receiving the desired 
packets.
If the demuxer or framework needs to scan and discard packets 
individually, that's still a seek being carried out.

Nonetheless, I've added a flag for 'slow' seeking and added that for 
packet scanned seeking.
Fur fully qualified reporting, the flags in demuxers will need to be 
updated. That's next on my todo after the basic functionality is present.

Regards,
Gyan

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [FFmpeg-devel] [PATCH v2 1/2] avformat: add avformat_query_seekable
  2025-04-15 10:39 [FFmpeg-devel] [PATCH v2 1/2] avformat: add avformat_query_seekable Gyan Doshi
                   ` (2 preceding siblings ...)
  2025-04-16  5:07 ` Andreas Rheinhardt
@ 2025-04-21 18:29 ` Stefano Sabatini
  2025-04-22  4:54   ` Gyan Doshi
  3 siblings, 1 reply; 8+ messages in thread
From: Stefano Sabatini @ 2025-04-21 18:29 UTC (permalink / raw)
  To: FFmpeg development discussions and patches

On date Tuesday 2025-04-15 16:09:56 +0530, Gyan Doshi wrote:
> Utility function to report seekability features for a given input.
> 
> Useful for ffprobe and to extend seek possibilities in fftools.
> ---
> v2:
>    made constants more descriptive
>    add exception for rtsp false negative seekability
> 
>  doc/APIchanges         |  3 +++
>  libavformat/avformat.h | 22 ++++++++++++++++++
>  libavformat/seek.c     | 53 ++++++++++++++++++++++++++++++++++++++++++
>  libavformat/version.h  |  2 +-
>  4 files changed, 79 insertions(+), 1 deletion(-)
> 
> diff --git a/doc/APIchanges b/doc/APIchanges
> index 65bf5a9419..879f56b572 100644
> --- a/doc/APIchanges
> +++ b/doc/APIchanges
> @@ -2,6 +2,9 @@ The last version increases of all libraries were on 2025-03-28
>  
>  API changes, most recent first:
>  
> +2025-04-xx - xxxxxxxxxx - lavf 62.1.100 - avformat.h
> +  Add avformat_query_seekable().
> +
>  2025-04-07 - 19e9a203b7 - lavu 60.01.100 - dict.h
>    Add AV_DICT_DEDUP.
>  
> diff --git a/libavformat/avformat.h b/libavformat/avformat.h
> index 498c3020a5..f9da5e9e79 100644
> --- a/libavformat/avformat.h
> +++ b/libavformat/avformat.h
> @@ -2338,6 +2338,28 @@ int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp,
>   */
>  int avformat_seek_file(AVFormatContext *s, int stream_index, int64_t min_ts, int64_t ts, int64_t max_ts, int flags);
>  
> +#define AVSEEKABLE_IO_NORMAL       0x00000001 ///< I/O is seekable like a local file
> +#define AVSEEKABLE_IO_PROTOCOL     0x00000002 ///< I/O seek is through protocol request via avio_seek_time
> +#define AVSEEKABLE_VIA_DEMUXER     0x00000004 ///< demuxer has a seek function
> +#define AVSEEKABLE_VIA_PKTSCAN     0x00000008 ///< seek is performed by consuming and scanning packet timestamps
> +#define AVSEEKABLE_BY_TIME         0x00000100 ///< seek target can be a timestamp
> +#define AVSEEKABLE_BY_BYTE         0x00000200 ///< seek target can be in bytes
> +#define AVSEEKABLE_BY_FRAME        0x00000400 ///< seek target can be a frame index
> +#define AVSEEKABLE_PROP_PTS        0x00010000 ///< seek target timestamp is expected to be PTS
> +#define AVSEEKABLE_PROP_FAST       0x00020000 ///< demuxer allows fast but inaccurate seeking

> +#define AVSEEKABLE_PROP_FWDONLY    0x00040000 ///< set seek will be equal or forward of specified seek point

Not sure I get this, can you clarify/expand?

> +/**
> + * Report if and how a seek can be performed in a given input.

I don't like the "can be performed in a given input" part, I'd use a
terminology closer to the function name: "for this format context".

Also, probably we want to specify that the method should be used after
the open operation or whatever.

> + *
> + * @param s            media file handle
> + *
> + * @return 0 if no seek can be performed on input,
> + *         -1 if the fmt ctx is NULL or is not an input
> + *         else return AVSEEKABLE_ bitflags indicating seekability features.
> + */
> +int avformat_query_seekable(AVFormatContext *s);
> +
>  /**
>   * Discard all internally buffered data. This can be useful when dealing with
>   * discontinuities in the byte stream. Generally works only with formats that
> diff --git a/libavformat/seek.c b/libavformat/seek.c
> index c0d94371e6..8be1bdec30 100644
> --- a/libavformat/seek.c
> +++ b/libavformat/seek.c
> @@ -712,6 +712,59 @@ int avformat_seek_file(AVFormatContext *s, int stream_index, int64_t min_ts,
>      return ret;
>  }
>  
> +int avformat_query_seekable(AVFormatContext *s)
> +{
> +    int ret = 0;
> +
> +    if (!s || !s->iformat)
> +        return -1;
> +
> +    if ( strcmp(s->iformat->name, "rtsp") && (!(s->pb && s->pb->seekable) || s->ctx_flags & AVFMTCTX_UNSEEKABLE) )
> +        return 0;
> +
> +    if (s->pb->seekable & AVIO_SEEKABLE_NORMAL)
> +        ret |= AVSEEKABLE_IO_NORMAL;
> +
> +    if (s->pb->seekable & AVIO_SEEKABLE_TIME)
> +        ret |= AVSEEKABLE_IO_PROTOCOL;
> +
> +    if (ffifmt(s->iformat)->read_seek || ffifmt(s->iformat)->read_seek2)
> +        ret |= AVSEEKABLE_VIA_DEMUXER;
> +
> +    if (ffifmt(s->iformat)->read_timestamp && !(s->iformat->flags & AVFMT_NOBINSEARCH))
> +        ret |= AVSEEKABLE_VIA_PKTSCAN;
> +
> +    if (!(s->iformat->flags & AVFMT_NOTIMESTAMPS))
> +        ret |= AVSEEKABLE_BY_TIME;
> +
> +    // TODO: incomplete, a few demuxers don't set flag but error out on byte seek
> +    if (!(s->iformat->flags & AVFMT_NO_BYTE_SEEK))
> +        ret |= AVSEEKABLE_BY_BYTE;
> +
> +    // TODO: no flag for frame seeking. Add flag and enable this check
> +    if (s->iformat->flags & 0)
> +        ret |= AVSEEKABLE_BY_FRAME;
> +
> +    if (s->iformat->flags & AVFMT_SEEK_TO_PTS)
> +        ret |= AVSEEKABLE_PROP_PTS;
> +
> +    // TODO: flag exists but not added to the demuxers which support it
> +    if (s->iformat->flags & AVFMT_FLAG_FAST_SEEK)
> +        ret |= AVSEEKABLE_PROP_FAST;
> +
> +    if (!(ret & AVSEEKABLE_VIA_DEMUXER) && ret & AVSEEKABLE_VIA_PKTSCAN)
> +        ret |= AVSEEKABLE_PROP_FWDONLY;
> +
> +    if ( !(ret & AVSEEKABLE_VIA_DEMUXER) &&
> +         !(ret & AVSEEKABLE_VIA_PKTSCAN) &&
> +         !(ret & AVSEEKABLE_BY_BYTE) &&
> +         !(ret & AVSEEKABLE_IO_PROTOCOL) &&
> +         (s->iformat->flags & AVFMT_NOGENSEARCH) )
> +        ret = 0;
> +
> +    return ret;
> +}
> +
>  /** Flush the frame reader. */
>  void ff_read_frame_flush(AVFormatContext *s)
>  {
> diff --git a/libavformat/version.h b/libavformat/version.h
> index 752aac16f7..a7c80dc564 100644
> --- a/libavformat/version.h
> +++ b/libavformat/version.h
> @@ -31,7 +31,7 @@
>  
>  #include "version_major.h"
>  
> -#define LIBAVFORMAT_VERSION_MINOR   0
> +#define LIBAVFORMAT_VERSION_MINOR   1
>  #define LIBAVFORMAT_VERSION_MICRO 100
>  
>  #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
> -- 
> 2.49.0
> 
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
> 
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [FFmpeg-devel] [PATCH v2 1/2] avformat: add avformat_query_seekable
  2025-04-21 18:29 ` Stefano Sabatini
@ 2025-04-22  4:54   ` Gyan Doshi
  2025-04-23 23:15     ` Stefano Sabatini
  0 siblings, 1 reply; 8+ messages in thread
From: Gyan Doshi @ 2025-04-22  4:54 UTC (permalink / raw)
  To: ffmpeg-devel



On 2025-04-21 11:59 pm, Stefano Sabatini wrote:
> On date Tuesday 2025-04-15 16:09:56 +0530, Gyan Doshi wrote:
>> Utility function to report seekability features for a given input.
>>
>> Useful for ffprobe and to extend seek possibilities in fftools.
>> ---
>> v2:
>>     made constants more descriptive
>>     add exception for rtsp false negative seekability
>>
>>   doc/APIchanges         |  3 +++
>>   libavformat/avformat.h | 22 ++++++++++++++++++
>>   libavformat/seek.c     | 53 ++++++++++++++++++++++++++++++++++++++++++
>>   libavformat/version.h  |  2 +-
>>   4 files changed, 79 insertions(+), 1 deletion(-)
>>
>> diff --git a/doc/APIchanges b/doc/APIchanges
>> index 65bf5a9419..879f56b572 100644
>> --- a/doc/APIchanges
>> +++ b/doc/APIchanges
>> @@ -2,6 +2,9 @@ The last version increases of all libraries were on 2025-03-28
>>   
>>   API changes, most recent first:
>>   
>> +2025-04-xx - xxxxxxxxxx - lavf 62.1.100 - avformat.h
>> +  Add avformat_query_seekable().
>> +
>>   2025-04-07 - 19e9a203b7 - lavu 60.01.100 - dict.h
>>     Add AV_DICT_DEDUP.
>>   
>> diff --git a/libavformat/avformat.h b/libavformat/avformat.h
>> index 498c3020a5..f9da5e9e79 100644
>> --- a/libavformat/avformat.h
>> +++ b/libavformat/avformat.h
>> @@ -2338,6 +2338,28 @@ int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp,
>>    */
>>   int avformat_seek_file(AVFormatContext *s, int stream_index, int64_t min_ts, int64_t ts, int64_t max_ts, int flags);
>>   
>> +#define AVSEEKABLE_IO_NORMAL       0x00000001 ///< I/O is seekable like a local file
>> +#define AVSEEKABLE_IO_PROTOCOL     0x00000002 ///< I/O seek is through protocol request via avio_seek_time
>> +#define AVSEEKABLE_VIA_DEMUXER     0x00000004 ///< demuxer has a seek function
>> +#define AVSEEKABLE_VIA_PKTSCAN     0x00000008 ///< seek is performed by consuming and scanning packet timestamps
>> +#define AVSEEKABLE_BY_TIME         0x00000100 ///< seek target can be a timestamp
>> +#define AVSEEKABLE_BY_BYTE         0x00000200 ///< seek target can be in bytes
>> +#define AVSEEKABLE_BY_FRAME        0x00000400 ///< seek target can be a frame index
>> +#define AVSEEKABLE_PROP_PTS        0x00010000 ///< seek target timestamp is expected to be PTS
>> +#define AVSEEKABLE_PROP_FAST       0x00020000 ///< demuxer allows fast but inaccurate seeking
>> +#define AVSEEKABLE_PROP_FWDONLY    0x00040000 ///< set seek will be equal or forward of specified seek point
> Not sure I get this, can you clarify/expand?

The framework does not seek to an earlier KF, e.g. if either avio is not 
AVIO_SEEKABLE_NORMAL or the index does not correctly mark keyframes. 
then a seek to 12s will return frames from 12s and decoding will start 
from next KF encountered.
I see now that my test for this can produce false postives. I'll try to 
fix it.

>> +/**
>> + * Report if and how a seek can be performed in a given input.
> I don't like the "can be performed in a given input" part, I'd use a
> terminology closer to the function name: "for this format context".
>
> Also, probably we want to specify that the method should be used after
> the open operation or whatever.

Will do.

Regards,
Gyan
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [FFmpeg-devel] [PATCH v2 1/2] avformat: add avformat_query_seekable
  2025-04-22  4:54   ` Gyan Doshi
@ 2025-04-23 23:15     ` Stefano Sabatini
  0 siblings, 0 replies; 8+ messages in thread
From: Stefano Sabatini @ 2025-04-23 23:15 UTC (permalink / raw)
  To: FFmpeg development discussions and patches

On date Tuesday 2025-04-22 10:24:01 +0530, Gyan Doshi wrote:
> On 2025-04-21 11:59 pm, Stefano Sabatini wrote:
> > On date Tuesday 2025-04-15 16:09:56 +0530, Gyan Doshi wrote:
> > > Utility function to report seekability features for a given input.
> > > 
> > > Useful for ffprobe and to extend seek possibilities in fftools.
> > > ---
> > > v2:
> > >     made constants more descriptive
> > >     add exception for rtsp false negative seekability
> > > 
> > >   doc/APIchanges         |  3 +++
> > >   libavformat/avformat.h | 22 ++++++++++++++++++
> > >   libavformat/seek.c     | 53 ++++++++++++++++++++++++++++++++++++++++++
> > >   libavformat/version.h  |  2 +-
> > >   4 files changed, 79 insertions(+), 1 deletion(-)
> > > 
> > > diff --git a/doc/APIchanges b/doc/APIchanges
> > > index 65bf5a9419..879f56b572 100644
> > > --- a/doc/APIchanges
> > > +++ b/doc/APIchanges
> > > @@ -2,6 +2,9 @@ The last version increases of all libraries were on 2025-03-28
> > >   API changes, most recent first:
> > > +2025-04-xx - xxxxxxxxxx - lavf 62.1.100 - avformat.h
> > > +  Add avformat_query_seekable().
> > > +
> > >   2025-04-07 - 19e9a203b7 - lavu 60.01.100 - dict.h
> > >     Add AV_DICT_DEDUP.
> > > diff --git a/libavformat/avformat.h b/libavformat/avformat.h
> > > index 498c3020a5..f9da5e9e79 100644
> > > --- a/libavformat/avformat.h
> > > +++ b/libavformat/avformat.h
> > > @@ -2338,6 +2338,28 @@ int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp,
> > >    */
> > >   int avformat_seek_file(AVFormatContext *s, int stream_index, int64_t min_ts, int64_t ts, int64_t max_ts, int flags);
> > > +#define AVSEEKABLE_IO_NORMAL       0x00000001 ///< I/O is seekable like a local file
> > > +#define AVSEEKABLE_IO_PROTOCOL     0x00000002 ///< I/O seek is through protocol request via avio_seek_time
> > > +#define AVSEEKABLE_VIA_DEMUXER     0x00000004 ///< demuxer has a seek function
> > > +#define AVSEEKABLE_VIA_PKTSCAN     0x00000008 ///< seek is performed by consuming and scanning packet timestamps
> > > +#define AVSEEKABLE_BY_TIME         0x00000100 ///< seek target can be a timestamp
> > > +#define AVSEEKABLE_BY_BYTE         0x00000200 ///< seek target can be in bytes
> > > +#define AVSEEKABLE_BY_FRAME        0x00000400 ///< seek target can be a frame index
> > > +#define AVSEEKABLE_PROP_PTS        0x00010000 ///< seek target timestamp is expected to be PTS
> > > +#define AVSEEKABLE_PROP_FAST       0x00020000 ///< demuxer allows fast but inaccurate seeking

> > > +#define AVSEEKABLE_PROP_FWDONLY    0x00040000 ///< set seek will be equal or forward of specified seek point
> > Not sure I get this, can you clarify/expand?
> 
> The framework does not seek to an earlier KF, e.g. if either avio is not
> AVIO_SEEKABLE_NORMAL or the index does not correctly mark keyframes. then a
> seek to 12s will return frames from 12s and decoding will start from next KF
> encountered.

Thanks for the clarification. This is my take to integrate this
comment into the doxy (also it's probably best to avoid contractions
to improve mnemonics):
#define AVSEEKABLE_PROP_FORWARDONLY    0x00040000 ///< seek result position will be equal or forward of the specified seek point

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2025-04-23 23:15 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-04-15 10:39 [FFmpeg-devel] [PATCH v2 1/2] avformat: add avformat_query_seekable Gyan Doshi
2025-04-15 10:39 ` [FFmpeg-devel] [PATCH v2 2/2] ffprobe: show seekability details in format section Gyan Doshi
2025-04-15 11:49 ` [FFmpeg-devel] [PATCH v2 1/2] avformat: add avformat_query_seekable Zhao Zhili
2025-04-16  5:07 ` Andreas Rheinhardt
2025-04-16 12:25   ` Gyan Doshi
2025-04-21 18:29 ` Stefano Sabatini
2025-04-22  4:54   ` Gyan Doshi
2025-04-23 23:15     ` Stefano Sabatini

Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
		ffmpegdev@gitmailbox.com
	public-inbox-index ffmpegdev

Example config snippet for mirrors.


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git