[FFmpeg-devel] [PATCH] avoid infinite loop when seeking flv and non seekable input
Michael Niedermayer
michaelni
Sun Jul 27 15:21:55 CEST 2008
On Sat, Jul 26, 2008 at 09:56:17PM -0700, Baptiste Coudurier wrote:
> Michael Niedermayer wrote:
> > On Wed, Jul 23, 2008 at 08:35:49PM -0700, Baptiste Coudurier wrote:
> >> Hi Michael,
> >>
> >> Michael Niedermayer wrote:
> >>> On Tue, Jul 22, 2008 at 07:41:51PM -0700, Baptiste Coudurier wrote:
> >>>> Hi,
> >>>>
> >>>> $subject,
> >>>>
> >>>> Reproduceable when trying to seek and input is non seekable (like http
> >>>> through ffserver).
> >>>>
> >>>> [flv @ 0x8e27eb0]skipping flv packet: type 32, size 2705408, flags 0
> >>>> [flv @ 0x8e27eb0]skipping flv packet: type 32, size 2763520, flags 0
> >>>> [flv @ 0x8e27eb0]skipping flv packet: type 32, size 2818048, flags 0
> >>>> [flv @ 0x8e27eb0]skipping flv packet: type 32, size 2856192, flags 0
> >>>> [flv @ 0x8e27eb0]skipping flv packet: type 32, size 2889728, flags 0
> >>>> [flv @ 0x8e27eb0]skipping flv packet: type 0, size 11469089, flags 0
> >>>> [flv @ 0x8e27eb0]skipping flv packet: type 32, size 2949120, flags 0
> >>>> [flv @ 0x8e27eb0]skipping flv packet: type 32, size 2987264, flags 0
> >>>>
> >>>> With patch resync happens faster:
> >>> I dont understand the problem, "trying to seek and input is non seekable"
> >>> makes no sense to me. If the input is unseekable, seeking wont succeed
> >>> anyway.
> >> It will it when seeking forward, aviobuf.c:
> >> } else if(s->is_streamed && !s->write_flag &&
> >> offset1 >= 0 && offset1 < (s->buf_end - s->buffer) + (1<<16)){
> >
> > indeed
> > this could be fixed by removing "offset1 < (s->buf_end - s->buffer) + (1<<16)"
> > or increasing (1<<16)
> > feel free to change that.
> >
>
> I checked more deeply and here comes patches.
>
> av_read_frame_flush needs to be done after seek in case of failure, this
> hunk will be applied before and separately.
>
> url_fseek is checked for error, and when is_streamed is set but seeking
> forward is not possible, return error.
[...]
> Index: libavformat/utils.c
> ===================================================================
> --- libavformat/utils.c (revision 14275)
> +++ libavformat/utils.c (working copy)
> @@ -1430,7 +1430,7 @@
> static int av_seek_frame_generic(AVFormatContext *s,
> int stream_index, int64_t timestamp, int flags)
> {
> - int index;
> + int index, ret;
> AVStream *st;
> AVIndexEntry *ie;
>
> @@ -1445,7 +1445,8 @@
> if(st->nb_index_entries){
> assert(st->index_entries);
> ie= &st->index_entries[st->nb_index_entries-1];
> - url_fseek(s->pb, ie->pos, SEEK_SET);
> + if ((ret = url_fseek(s->pb, ie->pos, SEEK_SET)) < 0)
> + return ret;
> av_update_cur_dts(s, st, ie->timestamp);
> }else
> url_fseek(s->pb, 0, SEEK_SET);
ok
> @@ -1465,14 +1466,14 @@
> return 0;
> }
> ie = &st->index_entries[index];
> - url_fseek(s->pb, ie->pos, SEEK_SET);
> -
> + if ((ret = url_fseek(s->pb, ie->pos, SEEK_SET)) < 0)
> + return ret;
> av_update_cur_dts(s, st, ie->timestamp);
>
> return 0;
ok
> @@ -1465,14 +1466,14 @@
> if (index < 0)
> return -1;
>
> - av_read_frame_flush(s);
> if (s->iformat->read_seek){
> if(s->iformat->read_seek(s, stream_index, timestamp, flags) >= 0)
> return 0;
> }
> ie = &st->index_entries[index];
> if ((ret = url_fseek(s->pb, ie->pos, SEEK_SET)) < 0)
> return ret;
> + av_read_frame_flush(s);
> av_update_cur_dts(s, st, ie->timestamp);
>
> return 0;
Does this pass the regression tests?
What concerns me is that av_read_frame_flush() is not done anymore when
s->iformat->read_seek is set and it succeeds
> Index: libavformat/aviobuf.c
> ===================================================================
> --- libavformat/aviobuf.c (revision 14275)
> +++ libavformat/aviobuf.c (working copy)
> @@ -149,13 +149,17 @@
> offset1 >= 0 && offset1 < (s->buf_end - s->buffer)) {
> /* can do the seek inside the buffer */
> s->buf_ptr = s->buffer + offset1;
> - } else if(s->is_streamed && !s->write_flag &&
> + } else if(s->is_streamed) {
> + if (!s->write_flag &&
> offset1 >= 0 && offset1 < (s->buf_end - s->buffer) + (1<<16)){
> while(s->pos < offset && !s->eof_reached)
> fill_buffer(s);
> if (s->eof_reached)
> return AVERROR(EPIPE);
> s->buf_ptr = s->buf_end + offset - s->pos;
> + } else {
> + return AVERROR(EPIPE);
> + }
> } else {
> offset_t res = AVERROR(EPIPE);
This is not the correct solution i think.
I think the code in the else below may be buggy when seek() fails, it can
fail for non streamed things as well (network problems, old scratched cd...)
I think moving
s->buf_end = s->buffer;
}
s->buf_ptr = s->buffer;
after
if (!s->seek || (res = s->seek(s->opaque, offset, SEEK_SET)) < 0)
return res;
might help ?
[...]
--
Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
I do not agree with what you have to say, but I'll defend to the death your
right to say it. -- Voltaire
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: Digital signature
URL: <http://lists.mplayerhq.hu/pipermail/ffmpeg-devel/attachments/20080727/a49a3cdc/attachment.pgp>
More information about the ffmpeg-devel
mailing list