PR #23519 opened by Kacper Michajłow (kasper93) URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23519 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23519.patch
From 8da63f6e4490f5ad7c92969c435e68db37cce29e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= <[email protected]> Date: Tue, 12 May 2026 13:19:20 +0200 Subject: [PATCH 1/5] avformat/hls: deduplicate playlists shared by multiple variants MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Master playlists can reference the same media playlist URI from several rendition group. new_playlist() allocated a separate playlist struct for each reference, this is unndeded work and we can fold duplicates into single probe. Signed-off-by: Kacper Michajłow <[email protected]> --- libavformat/hls.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/libavformat/hls.c b/libavformat/hls.c index b03201c690..7a2488cfb9 100644 --- a/libavformat/hls.c +++ b/libavformat/hls.c @@ -317,7 +317,19 @@ static void free_rendition_list(HLSContext *c) static struct playlist *new_playlist(HLSContext *c, const char *url, const char *base) { - struct playlist *pls = av_mallocz(sizeof(struct playlist)); + struct playlist *pls; + char abs_url[MAX_URL_SIZE]; + + ff_make_absolute_url(abs_url, sizeof(abs_url), base, url); + if (!abs_url[0]) + return NULL; + + for (int i = 0; i < c->n_playlists; i++) { + if (!strcmp(c->playlists[i]->url, abs_url)) + return c->playlists[i]; + } + + pls = av_mallocz(sizeof(struct playlist)); if (!pls) return NULL; pls->pkt = av_packet_alloc(); @@ -325,12 +337,7 @@ static struct playlist *new_playlist(HLSContext *c, const char *url, av_free(pls); return NULL; } - ff_make_absolute_url(pls->url, sizeof(pls->url), base, url); - if (!pls->url[0]) { - av_packet_free(&pls->pkt); - av_free(pls); - return NULL; - } + av_strlcpy(pls->url, abs_url, sizeof(pls->url)); pls->seek_timestamp = AV_NOPTS_VALUE; pls->is_id3_timestamped = -1; -- 2.52.0 From c4e6d471bb097b6b071fd98bdc3fc5a43ef168b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= <[email protected]> Date: Wed, 17 Jun 2026 02:31:51 +0200 Subject: [PATCH 2/5] avformat/hls: reuse the open connection for contiguous byte-range segments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CMAF and other EXT-X-BYTERANGE playlists address consecutive segments as contiguous byte ranges of a single resource. Each segment was fetched with a separate bounded request, paying a request/response round-trip per segment even though the connection was kept alive. Keep the AVIOContext open across segments of the same resource and seek to the next segment instead of reopening, for contiguous ranges the seek targets the current position and issues no request in practice. Non-contiguous, encrypted and non-seekable cases fall back to the previous reopen behaviour. Signed-off-by: Kacper Michajłow <[email protected]> --- libavformat/hls.c | 75 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 69 insertions(+), 6 deletions(-) diff --git a/libavformat/hls.c b/libavformat/hls.c index 7a2488cfb9..3ae4a9d466 100644 --- a/libavformat/hls.c +++ b/libavformat/hls.c @@ -105,6 +105,7 @@ struct playlist { uint8_t* read_buffer; AVIOContext *input; int input_read_done; + int input_reuse; AVIOContext *input_next; int input_next_requested; AVFormatContext *parent; @@ -281,6 +282,7 @@ static void free_playlist_list(HLSContext *c) av_freep(&pls->pb.pub.buffer); ff_format_io_close(c->ctx, &pls->input); pls->input_read_done = 0; + pls->input_reuse = 0; ff_format_io_close(c->ctx, &pls->input_next); pls->input_next_requested = 0; if (pls->ctx) { @@ -1157,6 +1159,21 @@ static struct segment *next_segment(struct playlist *pls) return pls->segments[n]; } +/* True if 'next' can be reached by seeking the open 'in' instead of reopening. + * An unencrypted, contiguous byte range directly following 'cur' in the same + * seekable resource (i.e. consecutive EXT-X-BYTERANGE segments). */ +static int segment_reusable(AVIOContext *in, const struct segment *cur, + const struct segment *next) +{ + return in && cur && next && + (in->seekable & AVIO_SEEKABLE_NORMAL) && + cur->size >= 0 && next->size >= 0 && + next->url_offset == cur->url_offset + cur->size && + cur->key_type == KEY_NONE && next->key_type == KEY_NONE && + next->init_section == cur->init_section && + !strcmp(next->url, cur->url); +} + static int read_from_url(struct playlist *pls, struct segment *seg, uint8_t *buf, int buf_size) { @@ -1411,14 +1428,48 @@ static int open_input(HLSContext *c, struct playlist *pls, struct segment *seg, int ret; int is_http = 0; + /* Reuse a kept-open connection to the same resource by seeking instead of + * reopening. For contiguous ranges the seek is a no-op and issues no request. */ + if (*in && pls->input_reuse && seg->key_type == KEY_NONE && + ((*in)->seekable & AVIO_SEEKABLE_NORMAL)) { + int64_t seek_ret = avio_seek(*in, seg->url_offset, SEEK_SET); + pls->input_reuse = 0; + if (seek_ret >= 0) { + av_log(pls->parent, AV_LOG_VERBOSE, + "HLS reusing connection for url '%s', offset %"PRId64", playlist %d\n", + seg->url, seg->url_offset, pls->index); + pls->input_read_done = 0; + pls->cur_seg_offset = 0; + return 0; + } + /* Seek failed: drop the connection and reopen. */ + ff_format_io_close(pls->parent, in); + } + pls->input_reuse = 0; + if (c->http_persistent) av_dict_set(&opts, "multiple_requests", "1", 0); if (seg->size >= 0) { - /* try to restrict the HTTP request to the part we want - * (if this is in fact a HTTP request) */ + /* Restrict the request to the wanted byte range. The end is extended + * across following contiguous segments of the same resource so one + * connection serves the whole run. */ + int64_t end_offset = seg->url_offset + seg->size; + if (seg == current_segment(pls)) { + int64_t n = pls->cur_seq_no - pls->start_seq_no + 1; + while (n < pls->n_segments) { + struct segment *ns = pls->segments[n]; + if (ns->size < 0 || ns->url_offset != end_offset || + ns->key_type != KEY_NONE || + ns->init_section != seg->init_section || + strcmp(ns->url, seg->url)) + break; + end_offset = ns->url_offset + ns->size; + n++; + } + } av_dict_set_int(&opts, "offset", seg->url_offset, 0); - av_dict_set_int(&opts, "end_offset", seg->url_offset + seg->size, 0); + av_dict_set_int(&opts, "end_offset", end_offset, 0); } av_log(pls->parent, AV_LOG_VERBOSE, "HLS request for url '%s', offset %"PRId64", playlist %d\n", @@ -1689,7 +1740,7 @@ restart: seg = current_segment(v); - if (!v->input || (c->http_persistent && v->input_read_done)) { + if (!v->input || v->input_read_done) { /* load/update Media Initialization Section, if any */ ret = update_init_section(v, seg); if (ret) @@ -1735,7 +1786,8 @@ restart: seg = next_segment(v); if (c->http_multiple == 1 && !v->input_next_requested && - seg && seg->key_type == KEY_NONE && av_strstart(seg->url, "http", NULL)) { + seg && seg->key_type == KEY_NONE && av_strstart(seg->url, "http", NULL) && + !segment_reusable(v->input, current_segment(v), seg)) { ret = open_input(c, v, seg, &v->input_next); if (ret < 0) { if (ff_check_interrupt(c->interrupt_callback)) @@ -1767,7 +1819,15 @@ restart: return ret; } - if (c->http_persistent && + if (ret == 0 && segment_reusable(v->input, seg, next_segment(v))) { + /* Clean boundary, and the next segment continues this resource. Keep + * the connection open and read it as a whole. Note that splitting + * segments in these cases is useful for dynamic variant/quality + * switching, but this is not supported by our HLS demuxer, so we + * join the ranges. */ + v->input_reuse = 1; + v->input_read_done = 1; + } else if (c->http_persistent && seg->key_type == KEY_NONE && av_strstart(seg->url, "http", NULL)) { v->input_read_done = 1; } else { @@ -2336,6 +2396,7 @@ static int hls_read_header(AVFormatContext *s) ff_format_io_close(pls->parent, &pls->input); pls->input = NULL; pls->input_read_done = 0; + pls->input_reuse = 0; ff_format_io_close(pls->parent, &pls->input_next); pls->input_next = NULL; pls->input_next_requested = 0; @@ -2506,6 +2567,7 @@ static int recheck_discard_flags(AVFormatContext *s, int first) } else if (first && !cur_needed && pls->needed) { ff_format_io_close(pls->parent, &pls->input); pls->input_read_done = 0; + pls->input_reuse = 0; ff_format_io_close(pls->parent, &pls->input_next); pls->input_next_requested = 0; if (pls->is_subtitle) @@ -2787,6 +2849,7 @@ static int hls_read_seek(AVFormatContext *s, int stream_index, AVIOContext *const pb = &pls->pb.pub; ff_format_io_close(pls->parent, &pls->input); pls->input_read_done = 0; + pls->input_reuse = 0; ff_format_io_close(pls->parent, &pls->input_next); pls->input_next_requested = 0; av_packet_unref(pls->pkt); -- 2.52.0 From 98d85642b0173ba66ba88fd7d4806f8bdbef7158 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= <[email protected]> Date: Wed, 17 Jun 2026 03:03:44 +0200 Subject: [PATCH 3/5] avformat/hls: fix seeking to before the first timestamp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit find_timestamp_in_playlist() already selects the first segment when the target is below the playlist's first timestamp, but returns 0. hls_read_seek() treats that as a failure, and all seek operation is failed. This breaks seeking to the very start whenever the requested timestamp is slightly below the first one. Clamp such targets to the first segment and report success instead. Fixes: https://github.com/mpv-player/mpv/issues/14840#issuecomment-4703186169 Signed-off-by: Kacper Michajłow <[email protected]> --- libavformat/hls.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libavformat/hls.c b/libavformat/hls.c index 3ae4a9d466..8d3e5871ca 100644 --- a/libavformat/hls.c +++ b/libavformat/hls.c @@ -2009,8 +2009,11 @@ static int find_timestamp_in_playlist(HLSContext *c, struct playlist *pls, 0 : c->first_timestamp; if (timestamp < pos) { + /* Seeking before the start of the playlist, clamp to the first segment. */ *seq_no = pls->start_seq_no; - return 0; + if (seg_start_ts) + *seg_start_ts = pos; + return 1; } for (i = 0; i < pls->n_segments; i++) { -- 2.52.0 From 595837619673b2f4ff6e3bf8d69bc60d05b5f3cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= <[email protected]> Date: Wed, 17 Jun 2026 07:00:42 +0200 Subject: [PATCH 4/5] avformat/hls: rebase seek discard threshold to each playlist's DTS baseline MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After a seek, hls_read_packet drops packets until each playlist reaches seek_timestamp. That threshold lives on c->first_timestamp's baseline, i.e. the DTS of whichever stream produced the very first packet. Streams can have different DTS baselines though. So comparing one stream's threshold against another stream's DTS is wrong. A stream whose first keyframe precedes the global baseline gets its segment keyframe dropped and resumes a segment (or more) late. Track the first DTS per playlist and rebase the threshold onto each playlist's own baseline. Since HLS segments are presentation-aligned across renditions, every stream then resumes at the same presentation time. seek_timestamp keeps its meaning on the global timeline, only the per-playlist comparison value is translated. This fixes playlists that would be unable to play from the start, and instead skip one or more segments, before data is output. Signed-off-by: Kacper Michajłow <[email protected]> --- libavformat/hls.c | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/libavformat/hls.c b/libavformat/hls.c index 8d3e5871ca..9afe78b37c 100644 --- a/libavformat/hls.c +++ b/libavformat/hls.c @@ -159,6 +159,8 @@ struct playlist { HLSAudioSetupInfo audio_setup_info; + /* First DTS seen on this playlist, in AV_TIME_BASE units. */ + int64_t first_timestamp; int64_t seek_timestamp; int seek_flags; int seek_stream_index; /* into subdemuxer stream array */ @@ -340,6 +342,7 @@ static struct playlist *new_playlist(HLSContext *c, const char *url, return NULL; } av_strlcpy(pls->url, abs_url, sizeof(pls->url)); + pls->first_timestamp = AV_NOPTS_VALUE; pls->seek_timestamp = AV_NOPTS_VALUE; pls->is_id3_timestamped = -1; @@ -2657,23 +2660,29 @@ static int hls_read_packet(AVFormatContext *s, AVPacket *pkt) fill_timing_for_id3_timestamped_stream(pls); } - if (c->first_timestamp == AV_NOPTS_VALUE && + if (pls->first_timestamp == AV_NOPTS_VALUE && pls->pkt->dts != AV_NOPTS_VALUE) { int64_t seg_idx = pls->cur_seq_no - pls->start_seq_no; - c->first_timestamp = av_rescale_q(pls->pkt->dts, + int64_t ts = av_rescale_q(pls->pkt->dts, get_timebase(pls), AV_TIME_BASE_Q); /* EVENT playlists preserve all segments from the start */ - if (pls->type == PLS_TYPE_EVENT) { + if (pls->type == PLS_TYPE_EVENT) for (int64_t k = 0; k < seg_idx && k < pls->n_segments; k++) - c->first_timestamp -= pls->segments[k]->duration; + ts -= pls->segments[k]->duration; - for (unsigned k = 0; k < s->nb_streams; k++) { - AVStream *st = s->streams[k]; - if (st->start_time == AV_NOPTS_VALUE) - st->start_time = av_rescale_q(c->first_timestamp, - AV_TIME_BASE_Q, st->time_base); - } + pls->first_timestamp = ts; + + if (c->first_timestamp == AV_NOPTS_VALUE) { + c->first_timestamp = ts; + + if (pls->type == PLS_TYPE_EVENT) + for (unsigned k = 0; k < s->nb_streams; k++) { + AVStream *st = s->streams[k]; + if (st->start_time == AV_NOPTS_VALUE) + st->start_time = av_rescale_q(ts, + AV_TIME_BASE_Q, st->time_base); + } } } } @@ -2873,7 +2882,15 @@ static int hls_read_seek(AVFormatContext *s, int stream_index, /* Reset the init segment so it's re-fetched and served appropriately */ pls->cur_init_section = NULL; - pls->seek_timestamp = seek_timestamp; + /* The discard in hls_read_packet compares this playlist's packet DTS + * against seek_timestamp, but seek_timestamp is on c->first_timestamp's + * baseline (whichever stream produced the first packet). Streams can + * have different DTS baselines, so rebase the threshold onto this + * playlist's own baseline. */ + if (pls->first_timestamp != AV_NOPTS_VALUE && c->first_timestamp != AV_NOPTS_VALUE) + pls->seek_timestamp = seek_timestamp + pls->first_timestamp - c->first_timestamp; + else + pls->seek_timestamp = seek_timestamp; pls->seek_flags = flags; if (pls != seek_pls) { -- 2.52.0 From 7e43b517cf129eb1156cc1c5243eed6976babc90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= <[email protected]> Date: Wed, 17 Jun 2026 17:18:58 +0200 Subject: [PATCH 5/5] tests/fate/seek: add HLS multi-playlist seek test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a seek test for an HLS master playlist with separate audio and video media playlists with different DTS baselines. Signed-off-by: Kacper Michajłow <[email protected]> --- tests/fate/seek.mak | 19 ++++++++++++++-- tests/ref/seek/hls | 53 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 tests/ref/seek/hls diff --git a/tests/fate/seek.mak b/tests/fate/seek.mak index f0a9f44d94..5121b3f7f3 100644 --- a/tests/fate/seek.mak +++ b/tests/fate/seek.mak @@ -199,15 +199,30 @@ fate-seek-test-iibbibb-neg-ctts-mp4: CMD = run libavformat/tests/seek$(EXESUF) fate-seek-cache-pipe: CMD = cat $(SAMPLES)/gapless/gapless.mp3 | run libavformat/tests/seek$(EXESUF) cache:pipe:0 -read_ahead_limit -1 fate-seek-mkv-codec-delay: CMD = run libavformat/tests/seek$(EXESUF) $(TARGET_SAMPLES)/mkv/codec_delay_opus.mkv +# A master playlist with separate audio and video media playlists with different DTS. +tests/data/hls-seek.m3u8: ffmpeg$(PROGSSUF)$(EXESUF) | tests/data + $(M)$(TARGET_EXEC) $(TARGET_PATH)/$< -nostdin \ + -f lavfi -i "testsrc2=size=128x72:rate=10:d=6" \ + -f lavfi -i "aevalsrc=cos(2*PI*t)*sin(2*PI*(440+4*t)*t):d=6" \ + -map 0:v -map 1:a -c:v mpeg2video -bf 2 -g 15 -flags +bitexact -c:a mp2fixed \ + -f hls -hls_time 2 -hls_list_size 0 \ + -var_stream_map "v:0,agroup:a a:0,agroup:a,default:yes" -master_pl_name hls-seek.m3u8 \ + -hls_segment_filename $(TARGET_PATH)/tests/data/hls-seek-s%v-%d.ts \ + $(TARGET_PATH)/tests/data/hls-seek-v%v.m3u8 2>/dev/null + FATE_SEEK_EXTRA += $(FATE_SEEK_EXTRA-yes) +FATE_SEEK_FFMPEG-$(call ALLYES, TESTSRC2_FILTER AEVALSRC_FILTER LAVFI_INDEV MPEG2VIDEO_ENCODER MP2FIXED_ENCODER HLS_MUXER MPEGTS_MUXER HLS_DEMUXER MPEGTS_DEMUXER FILE_PROTOCOL) += fate-seek-hls +fate-seek-hls: tests/data/hls-seek.m3u8 +fate-seek-hls: CMD = run libavformat/tests/seek$(EXESUF) $(TARGET_PATH)/tests/data/hls-seek.m3u8 -duration 6 -$(FATE_SEEK) $(FATE_SAMPLES_SEEK) $(FATE_SEEK_EXTRA): libavformat/tests/seek$(EXESUF) +$(FATE_SEEK) $(FATE_SAMPLES_SEEK) $(FATE_SEEK_EXTRA) $(FATE_SEEK_FFMPEG-yes): libavformat/tests/seek$(EXESUF) $(FATE_SEEK) $(FATE_SAMPLES_SEEK): CMD = run libavformat/tests/seek$(EXESUF) $(TARGET_PATH)/tests/data/$(SRC) $(FATE_SEEK) $(FATE_SAMPLES_SEEK): fate-seek-%: fate-% $(subst fate-seek-,fate-,$(FATE_SAMPLES_SEEK) $(FATE_SEEK)): KEEP_FILES ?= 1 fate-seek-%: REF = $(SRC_PATH)/tests/ref/seek/$(@:fate-seek-%=%) FATE_AVCONV += $(FATE_SEEK) +FATE_FFMPEG += $(FATE_SEEK_FFMPEG-yes) FATE_SAMPLES_AVCONV += $(FATE_SAMPLES_SEEK) $(FATE_SEEK_EXTRA) -fate-seek: $(FATE_SEEK) $(FATE_SAMPLES_SEEK) $(FATE_SEEK_EXTRA) +fate-seek: $(FATE_SEEK) $(FATE_SAMPLES_SEEK) $(FATE_SEEK_EXTRA) $(FATE_SEEK_FFMPEG-yes) diff --git a/tests/ref/seek/hls b/tests/ref/seek/hls new file mode 100644 index 0000000000..958f00d711 --- /dev/null +++ b/tests/ref/seek/hls @@ -0,0 +1,53 @@ +ret: 0 st: 1 flags:1 dts: 1.400000 pts: 1.500000 pos: 564 size: 3909 +ret: 0 st:-1 flags:0 ts:-1.000000 +ret: 0 st: 1 flags:1 dts: 1.400000 pts: 1.500000 pos: 564 size: 3909 +ret: 0 st:-1 flags:1 ts:-0.105833 +ret: 0 st: 1 flags:1 dts: 1.400000 pts: 1.500000 pos: 564 size: 3909 +ret: 0 st: 0 flags:0 ts: 0.788333 +ret: 0 st: 1 flags:1 dts: 1.400000 pts: 1.500000 pos: 564 size: 3909 +ret: 0 st: 0 flags:1 ts: 1.682500 +ret: 0 st: 1 flags:0 dts: 1.600000 pts: 1.600000 pos: 8836 size: 2315 +ret: 0 st: 1 flags:0 ts: 2.576667 +ret: 0 st: 0 flags:1 dts: 2.586233 pts: 2.586233 pos: 55836 size: 1254 +ret: 0 st: 1 flags:1 ts: 3.470833 +ret: 0 st: 1 flags:1 dts: 1.400000 pts: 1.500000 pos: 564 size: 3909 +ret: 0 st:-1 flags:0 ts: 4.365002 +ret: 0 st: 0 flags:1 dts: 4.388689 pts: 4.388689 pos: 45308 size: 1254 +ret: 0 st:-1 flags:1 ts:-0.740831 +ret: 0 st: 1 flags:1 dts: 1.400000 pts: 1.500000 pos: 564 size: 3909 +ret: 0 st: 0 flags:0 ts: 0.153333 +ret: 0 st: 1 flags:1 dts: 1.400000 pts: 1.500000 pos: 564 size: 3909 +ret: 0 st: 0 flags:1 ts: 1.047500 +ret: 0 st: 1 flags:1 dts: 1.400000 pts: 1.500000 pos: 564 size: 3909 +ret: 0 st: 1 flags:0 ts: 1.941667 +ret: 0 st: 0 flags:1 dts: 1.959300 pts: 1.959300 pos: 24252 size: 1254 +ret: 0 st: 1 flags:1 ts: 2.835833 +ret: 0 st: 1 flags:1 dts: 1.400000 pts: 1.500000 pos: 564 size: 3909 +ret: 0 st:-1 flags:0 ts: 3.730004 +ret: 0 st: 0 flags:1 dts: 3.735622 pts: 3.735622 pos: -1 size: 1254 +ret: 0 st:-1 flags:1 ts: 4.624171 +ret: 0 st: 0 flags:1 dts: 4.493178 pts: 4.493178 pos: 50572 size: 1254 +ret: 0 st: 0 flags:0 ts:-0.481667 +ret: 0 st: 1 flags:1 dts: 1.400000 pts: 1.500000 pos: 564 size: 3909 +ret: 0 st: 0 flags:1 ts: 0.412500 +ret: 0 st: 1 flags:1 dts: 1.400000 pts: 1.500000 pos: 564 size: 3909 +ret: 0 st: 1 flags:0 ts: 1.306667 +ret: 0 st: 1 flags:1 dts: 1.400000 pts: 1.500000 pos: 564 size: 3909 +ret: 0 st: 1 flags:1 ts: 2.200844 +ret: 0 st: 1 flags:1 dts: 1.400000 pts: 1.500000 pos: 564 size: 3909 +ret: 0 st:-1 flags:0 ts: 3.095006 +ret: 0 st: 0 flags:1 dts: 3.108689 pts: 3.108689 pos: 82156 size: 1254 +ret: 0 st:-1 flags:1 ts: 3.989173 +ret: 0 st: 1 flags:1 dts: 1.400000 pts: 1.500000 pos: 564 size: 3909 +ret: 0 st: 0 flags:0 ts: 4.883344 +ret: 0 st: 1 flags:0 dts: 4.800000 pts: 5.100000 pos: 20492 size: 3867 +ret: 0 st: 0 flags:1 ts:-0.222489 +ret: 0 st: 1 flags:1 dts: 1.400000 pts: 1.500000 pos: 564 size: 3909 +ret: 0 st: 1 flags:0 ts: 0.671678 +ret: 0 st: 1 flags:1 dts: 1.400000 pts: 1.500000 pos: 564 size: 3909 +ret: 0 st: 1 flags:1 ts: 1.565844 +ret: 0 st: 1 flags:1 dts: 1.400000 pts: 1.500000 pos: 564 size: 3909 +ret: 0 st:-1 flags:0 ts: 2.460008 +ret: 0 st: 0 flags:1 dts: 2.481744 pts: 2.481744 pos: 50572 size: 1254 +ret: 0 st:-1 flags:1 ts: 3.354175 +ret: 0 st: 1 flags:1 dts: 1.400000 pts: 1.500000 pos: 564 size: 3909 -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
