Message ID | 20220128202320.1711694-1-gustav.grusell@gmail.com |
---|---|
State | New |
Headers | show |
Series | [FFmpeg-devel,v4] avformat/hls: Implement support for using AVSEEK_FLAG_BACKWARD when seeking | expand |
Context | Check | Description |
---|---|---|
andriy/make_x86 | success | Make finished |
andriy/make_fate_x86 | success | Make fate finished |
andriy/make_ppc | success | Make finished |
andriy/make_fate_ppc | success | Make fate finished |
andriy/make_aarch64_jetson | success | Make finished |
andriy/make_fate_aarch64_jetson | success | Make fate finished |
andriy/make_armv7_RPi4 | success | Make finished |
andriy/make_fate_armv7_RPi4 | success | Make fate finished |
Any comments on this? cheers, Gustav On Fri, Jan 28, 2022 at 9:24 PM Gustav Grusell <gustav.grusell@gmail.com> wrote: > Before, seeking in hls streams would always seek to the next keyframe > after the given timestamp. With this fix, if seeking in videostream and > AVSEEK_FLAG_BACKWARD is set, seeking will be to the first keyframe of > the segment containing the given timestamp. This fixes #7485. > > Signed-off-by: Gustav Grusell <gustav.grusell@gmail.com> > --- > libavformat/hls.c | 24 +++++++++++++++++------- > 1 file changed, 17 insertions(+), 7 deletions(-) > > diff --git a/libavformat/hls.c b/libavformat/hls.c > index 4568e72cb2..44afdaab42 100644 > --- a/libavformat/hls.c > +++ b/libavformat/hls.c > @@ -1653,7 +1653,8 @@ static void > add_metadata_from_renditions(AVFormatContext *s, struct playlist *pl > /* if timestamp was in valid range: returns 1 and sets seq_no > * if not: returns 0 and sets seq_no to closest segment */ > static int find_timestamp_in_playlist(HLSContext *c, struct playlist *pls, > - int64_t timestamp, int64_t *seq_no) > + int64_t timestamp, int64_t *seq_no, > + int64_t *seg_start_ts) > { > int i; > int64_t pos = c->first_timestamp == AV_NOPTS_VALUE ? > @@ -1668,6 +1669,9 @@ static int find_timestamp_in_playlist(HLSContext *c, > struct playlist *pls, > int64_t diff = pos + pls->segments[i]->duration - timestamp; > if (diff > 0) { > *seq_no = pls->start_seq_no + i; > + if (seg_start_ts) { > + *seg_start_ts = pos; > + } > return 1; > } > pos += pls->segments[i]->duration; > @@ -1691,7 +1695,7 @@ static int64_t select_cur_seq_no(HLSContext *c, > struct playlist *pls) > * playlist) and this is a complete file, find the matching segment > * by counting durations. */ > if (pls->finished && c->cur_timestamp != AV_NOPTS_VALUE) { > - find_timestamp_in_playlist(c, pls, c->cur_timestamp, &seq_no); > + find_timestamp_in_playlist(c, pls, c->cur_timestamp, &seq_no, > NULL); > return seq_no; > } > > @@ -2362,7 +2366,7 @@ static int hls_read_seek(AVFormatContext *s, int > stream_index, > int i, j; > int stream_subdemuxer_index; > int64_t first_timestamp, seek_timestamp, duration; > - int64_t seq_no; > + int64_t seq_no, seg_start_ts; > > if ((flags & AVSEEK_FLAG_BYTE) || (c->ctx->ctx_flags & > AVFMTCTX_UNSEEKABLE)) > return AVERROR(ENOSYS); > @@ -2372,8 +2376,7 @@ static int hls_read_seek(AVFormatContext *s, int > stream_index, > > seek_timestamp = av_rescale_rnd(timestamp, AV_TIME_BASE, > > s->streams[stream_index]->time_base.den, > - flags & AVSEEK_FLAG_BACKWARD ? > - AV_ROUND_DOWN : AV_ROUND_UP); > + AV_ROUND_DOWN); > > duration = s->duration == AV_NOPTS_VALUE ? > 0 : s->duration; > @@ -2394,9 +2397,16 @@ static int hls_read_seek(AVFormatContext *s, int > stream_index, > } > /* check if the timestamp is valid for the playlist with the > * specified stream index */ > - if (!seek_pls || !find_timestamp_in_playlist(c, seek_pls, > seek_timestamp, &seq_no)) > + if (!seek_pls || !find_timestamp_in_playlist(c, seek_pls, > seek_timestamp, &seq_no, &seg_start_ts)) > return AVERROR(EIO); > > + if (s->streams[stream_index]->codecpar->codec_type == > AVMEDIA_TYPE_VIDEO && > + flags & AVSEEK_FLAG_BACKWARD && !(flags & AVSEEK_FLAG_ANY)) { > + /* Seeking to start of segment ensures we seek to a keyframe > located > + * before the given timestamp. */ > + seek_timestamp = seg_start_ts; > + } > + > /* set segment now so we do not need to search again below */ > seek_pls->cur_seq_no = seq_no; > seek_pls->seek_stream_index = stream_subdemuxer_index; > @@ -2423,7 +2433,7 @@ static int hls_read_seek(AVFormatContext *s, int > stream_index, > > if (pls != seek_pls) { > /* set closest segment seq_no for playlists not handled above > */ > - find_timestamp_in_playlist(c, pls, seek_timestamp, > &pls->cur_seq_no); > + find_timestamp_in_playlist(c, pls, seek_timestamp, > &pls->cur_seq_no, NULL); > /* seek the playlist to the given position without taking > * keyframes into account since this playlist does not have > the > * specified stream where we should look for the keyframes */ > -- > 2.25.1 > >
> 2022年1月29日 上午4:23,Gustav Grusell <gustav.grusell@gmail.com> 写道: > > Before, seeking in hls streams would always seek to the next keyframe > after the given timestamp. With this fix, if seeking in videostream and > AVSEEK_FLAG_BACKWARD is set, seeking will be to the first keyframe of > the segment containing the given timestamp. This fixes #7485. > > Signed-off-by: Gustav Grusell <gustav.grusell@gmail.com> > --- > libavformat/hls.c | 24 +++++++++++++++++------- > 1 file changed, 17 insertions(+), 7 deletions(-) > > diff --git a/libavformat/hls.c b/libavformat/hls.c > index 4568e72cb2..44afdaab42 100644 > --- a/libavformat/hls.c > +++ b/libavformat/hls.c > @@ -1653,7 +1653,8 @@ static void add_metadata_from_renditions(AVFormatContext *s, struct playlist *pl > /* if timestamp was in valid range: returns 1 and sets seq_no > * if not: returns 0 and sets seq_no to closest segment */ > static int find_timestamp_in_playlist(HLSContext *c, struct playlist *pls, > - int64_t timestamp, int64_t *seq_no) > + int64_t timestamp, int64_t *seq_no, > + int64_t *seg_start_ts) > { > int i; > int64_t pos = c->first_timestamp == AV_NOPTS_VALUE ? > @@ -1668,6 +1669,9 @@ static int find_timestamp_in_playlist(HLSContext *c, struct playlist *pls, > int64_t diff = pos + pls->segments[i]->duration - timestamp; > if (diff > 0) { > *seq_no = pls->start_seq_no + i; > + if (seg_start_ts) { > + *seg_start_ts = pos; > + } > return 1; > } > pos += pls->segments[i]->duration; > @@ -1691,7 +1695,7 @@ static int64_t select_cur_seq_no(HLSContext *c, struct playlist *pls) > * playlist) and this is a complete file, find the matching segment > * by counting durations. */ > if (pls->finished && c->cur_timestamp != AV_NOPTS_VALUE) { > - find_timestamp_in_playlist(c, pls, c->cur_timestamp, &seq_no); > + find_timestamp_in_playlist(c, pls, c->cur_timestamp, &seq_no, NULL); > return seq_no; > } > > @@ -2362,7 +2366,7 @@ static int hls_read_seek(AVFormatContext *s, int stream_index, > int i, j; > int stream_subdemuxer_index; > int64_t first_timestamp, seek_timestamp, duration; > - int64_t seq_no; > + int64_t seq_no, seg_start_ts; > > if ((flags & AVSEEK_FLAG_BYTE) || (c->ctx->ctx_flags & AVFMTCTX_UNSEEKABLE)) > return AVERROR(ENOSYS); > @@ -2372,8 +2376,7 @@ static int hls_read_seek(AVFormatContext *s, int stream_index, > > seek_timestamp = av_rescale_rnd(timestamp, AV_TIME_BASE, > s->streams[stream_index]->time_base.den, > - flags & AVSEEK_FLAG_BACKWARD ? > - AV_ROUND_DOWN : AV_ROUND_UP); > + AV_ROUND_DOWN); > > duration = s->duration == AV_NOPTS_VALUE ? > 0 : s->duration; > @@ -2394,9 +2397,16 @@ static int hls_read_seek(AVFormatContext *s, int stream_index, > } > /* check if the timestamp is valid for the playlist with the > * specified stream index */ > - if (!seek_pls || !find_timestamp_in_playlist(c, seek_pls, seek_timestamp, &seq_no)) > + if (!seek_pls || !find_timestamp_in_playlist(c, seek_pls, seek_timestamp, &seq_no, &seg_start_ts)) > return AVERROR(EIO); > > + if (s->streams[stream_index]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && > + flags & AVSEEK_FLAG_BACKWARD && !(flags & AVSEEK_FLAG_ANY)) { > + /* Seeking to start of segment ensures we seek to a keyframe located > + * before the given timestamp. */ > + seek_timestamp = seg_start_ts; > + } > + > /* set segment now so we do not need to search again below */ > seek_pls->cur_seq_no = seq_no; > seek_pls->seek_stream_index = stream_subdemuxer_index; > @@ -2423,7 +2433,7 @@ static int hls_read_seek(AVFormatContext *s, int stream_index, > > if (pls != seek_pls) { > /* set closest segment seq_no for playlists not handled above */ > - find_timestamp_in_playlist(c, pls, seek_timestamp, &pls->cur_seq_no); > + find_timestamp_in_playlist(c, pls, seek_timestamp, &pls->cur_seq_no, NULL); > /* seek the playlist to the given position without taking > * keyframes into account since this playlist does not have the > * specified stream where we should look for the keyframes */ > -- > 2.25.1 > > _______________________________________________ > 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". > LGTM Thanks Steven Liu
Steven Liu <lq@chinaffmpeg.org> 于2022年2月3日周四 18:22写道: > > > > > 2022年1月29日 上午4:23,Gustav Grusell <gustav.grusell@gmail.com> 写道: > > > > Before, seeking in hls streams would always seek to the next keyframe > > after the given timestamp. With this fix, if seeking in videostream and > > AVSEEK_FLAG_BACKWARD is set, seeking will be to the first keyframe of > > the segment containing the given timestamp. This fixes #7485. > > > > Signed-off-by: Gustav Grusell <gustav.grusell@gmail.com> > > --- > > libavformat/hls.c | 24 +++++++++++++++++------- > > 1 file changed, 17 insertions(+), 7 deletions(-) > > > > diff --git a/libavformat/hls.c b/libavformat/hls.c > > index 4568e72cb2..44afdaab42 100644 > > --- a/libavformat/hls.c > > +++ b/libavformat/hls.c > > @@ -1653,7 +1653,8 @@ static void add_metadata_from_renditions(AVFormatContext *s, struct playlist *pl > > /* if timestamp was in valid range: returns 1 and sets seq_no > > * if not: returns 0 and sets seq_no to closest segment */ > > static int find_timestamp_in_playlist(HLSContext *c, struct playlist *pls, > > - int64_t timestamp, int64_t *seq_no) > > + int64_t timestamp, int64_t *seq_no, > > + int64_t *seg_start_ts) > > { > > int i; > > int64_t pos = c->first_timestamp == AV_NOPTS_VALUE ? > > @@ -1668,6 +1669,9 @@ static int find_timestamp_in_playlist(HLSContext *c, struct playlist *pls, > > int64_t diff = pos + pls->segments[i]->duration - timestamp; > > if (diff > 0) { > > *seq_no = pls->start_seq_no + i; > > + if (seg_start_ts) { > > + *seg_start_ts = pos; > > + } > > return 1; > > } > > pos += pls->segments[i]->duration; > > @@ -1691,7 +1695,7 @@ static int64_t select_cur_seq_no(HLSContext *c, struct playlist *pls) > > * playlist) and this is a complete file, find the matching segment > > * by counting durations. */ > > if (pls->finished && c->cur_timestamp != AV_NOPTS_VALUE) { > > - find_timestamp_in_playlist(c, pls, c->cur_timestamp, &seq_no); > > + find_timestamp_in_playlist(c, pls, c->cur_timestamp, &seq_no, NULL); > > return seq_no; > > } > > > > @@ -2362,7 +2366,7 @@ static int hls_read_seek(AVFormatContext *s, int stream_index, > > int i, j; > > int stream_subdemuxer_index; > > int64_t first_timestamp, seek_timestamp, duration; > > - int64_t seq_no; > > + int64_t seq_no, seg_start_ts; > > > > if ((flags & AVSEEK_FLAG_BYTE) || (c->ctx->ctx_flags & AVFMTCTX_UNSEEKABLE)) > > return AVERROR(ENOSYS); > > @@ -2372,8 +2376,7 @@ static int hls_read_seek(AVFormatContext *s, int stream_index, > > > > seek_timestamp = av_rescale_rnd(timestamp, AV_TIME_BASE, > > s->streams[stream_index]->time_base.den, > > - flags & AVSEEK_FLAG_BACKWARD ? > > - AV_ROUND_DOWN : AV_ROUND_UP); > > + AV_ROUND_DOWN); > > > > duration = s->duration == AV_NOPTS_VALUE ? > > 0 : s->duration; > > @@ -2394,9 +2397,16 @@ static int hls_read_seek(AVFormatContext *s, int stream_index, > > } > > /* check if the timestamp is valid for the playlist with the > > * specified stream index */ > > - if (!seek_pls || !find_timestamp_in_playlist(c, seek_pls, seek_timestamp, &seq_no)) > > + if (!seek_pls || !find_timestamp_in_playlist(c, seek_pls, seek_timestamp, &seq_no, &seg_start_ts)) > > return AVERROR(EIO); > > > > + if (s->streams[stream_index]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && > > + flags & AVSEEK_FLAG_BACKWARD && !(flags & AVSEEK_FLAG_ANY)) { > > + /* Seeking to start of segment ensures we seek to a keyframe located > > + * before the given timestamp. */ > > + seek_timestamp = seg_start_ts; > > + } > > + > > /* set segment now so we do not need to search again below */ > > seek_pls->cur_seq_no = seq_no; > > seek_pls->seek_stream_index = stream_subdemuxer_index; > > @@ -2423,7 +2433,7 @@ static int hls_read_seek(AVFormatContext *s, int stream_index, > > > > if (pls != seek_pls) { > > /* set closest segment seq_no for playlists not handled above */ > > - find_timestamp_in_playlist(c, pls, seek_timestamp, &pls->cur_seq_no); > > + find_timestamp_in_playlist(c, pls, seek_timestamp, &pls->cur_seq_no, NULL); > > /* seek the playlist to the given position without taking > > * keyframes into account since this playlist does not have the > > * specified stream where we should look for the keyframes */ > > -- > > 2.25.1 > > > > _______________________________________________ > > 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". > > > > LGTM Applied as e78d0810d1741535c95e5ae0f198977626b1cdff Thanks Steven
diff --git a/libavformat/hls.c b/libavformat/hls.c index 4568e72cb2..44afdaab42 100644 --- a/libavformat/hls.c +++ b/libavformat/hls.c @@ -1653,7 +1653,8 @@ static void add_metadata_from_renditions(AVFormatContext *s, struct playlist *pl /* if timestamp was in valid range: returns 1 and sets seq_no * if not: returns 0 and sets seq_no to closest segment */ static int find_timestamp_in_playlist(HLSContext *c, struct playlist *pls, - int64_t timestamp, int64_t *seq_no) + int64_t timestamp, int64_t *seq_no, + int64_t *seg_start_ts) { int i; int64_t pos = c->first_timestamp == AV_NOPTS_VALUE ? @@ -1668,6 +1669,9 @@ static int find_timestamp_in_playlist(HLSContext *c, struct playlist *pls, int64_t diff = pos + pls->segments[i]->duration - timestamp; if (diff > 0) { *seq_no = pls->start_seq_no + i; + if (seg_start_ts) { + *seg_start_ts = pos; + } return 1; } pos += pls->segments[i]->duration; @@ -1691,7 +1695,7 @@ static int64_t select_cur_seq_no(HLSContext *c, struct playlist *pls) * playlist) and this is a complete file, find the matching segment * by counting durations. */ if (pls->finished && c->cur_timestamp != AV_NOPTS_VALUE) { - find_timestamp_in_playlist(c, pls, c->cur_timestamp, &seq_no); + find_timestamp_in_playlist(c, pls, c->cur_timestamp, &seq_no, NULL); return seq_no; } @@ -2362,7 +2366,7 @@ static int hls_read_seek(AVFormatContext *s, int stream_index, int i, j; int stream_subdemuxer_index; int64_t first_timestamp, seek_timestamp, duration; - int64_t seq_no; + int64_t seq_no, seg_start_ts; if ((flags & AVSEEK_FLAG_BYTE) || (c->ctx->ctx_flags & AVFMTCTX_UNSEEKABLE)) return AVERROR(ENOSYS); @@ -2372,8 +2376,7 @@ static int hls_read_seek(AVFormatContext *s, int stream_index, seek_timestamp = av_rescale_rnd(timestamp, AV_TIME_BASE, s->streams[stream_index]->time_base.den, - flags & AVSEEK_FLAG_BACKWARD ? - AV_ROUND_DOWN : AV_ROUND_UP); + AV_ROUND_DOWN); duration = s->duration == AV_NOPTS_VALUE ? 0 : s->duration; @@ -2394,9 +2397,16 @@ static int hls_read_seek(AVFormatContext *s, int stream_index, } /* check if the timestamp is valid for the playlist with the * specified stream index */ - if (!seek_pls || !find_timestamp_in_playlist(c, seek_pls, seek_timestamp, &seq_no)) + if (!seek_pls || !find_timestamp_in_playlist(c, seek_pls, seek_timestamp, &seq_no, &seg_start_ts)) return AVERROR(EIO); + if (s->streams[stream_index]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && + flags & AVSEEK_FLAG_BACKWARD && !(flags & AVSEEK_FLAG_ANY)) { + /* Seeking to start of segment ensures we seek to a keyframe located + * before the given timestamp. */ + seek_timestamp = seg_start_ts; + } + /* set segment now so we do not need to search again below */ seek_pls->cur_seq_no = seq_no; seek_pls->seek_stream_index = stream_subdemuxer_index; @@ -2423,7 +2433,7 @@ static int hls_read_seek(AVFormatContext *s, int stream_index, if (pls != seek_pls) { /* set closest segment seq_no for playlists not handled above */ - find_timestamp_in_playlist(c, pls, seek_timestamp, &pls->cur_seq_no); + find_timestamp_in_playlist(c, pls, seek_timestamp, &pls->cur_seq_no, NULL); /* seek the playlist to the given position without taking * keyframes into account since this playlist does not have the * specified stream where we should look for the keyframes */
Before, seeking in hls streams would always seek to the next keyframe after the given timestamp. With this fix, if seeking in videostream and AVSEEK_FLAG_BACKWARD is set, seeking will be to the first keyframe of the segment containing the given timestamp. This fixes #7485. Signed-off-by: Gustav Grusell <gustav.grusell@gmail.com> --- libavformat/hls.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-)