mirror of https://github.com/mpv-player/mpv
stream: fix some aspects of EOF handling
The stream EOF flag should only be set when trying to read past the end of the file (relatively similar to unix files). Always clear the EOF flag on seeking. Trying to set it "properly" (depending whether data is available at seek destination or not) might be an ok idea, but would require attention to too many special cases. I suspect before this commit (and in MPlayer etc. too), the EOF flag wasn't handled consistently when the stream position was at the end of the file. Fix one special case in ebml.c and stream_skip(): this function couldn't distinguish between at-EOF and past-EOF either.
This commit is contained in:
parent
0d5e6084ae
commit
5999efb964
|
@ -308,11 +308,10 @@ int ebml_read_skip_or_resync_cluster(stream_t *s, uint64_t *length)
|
|||
*length = len + l;
|
||||
|
||||
int64_t pos = stream_tell(s);
|
||||
stream_skip(s, len);
|
||||
|
||||
// When reading corrupted elements, len will often be a random high number,
|
||||
// and stream_skip() will set EOF.
|
||||
if (s->eof) {
|
||||
// and stream_skip() will fail when skipping past EOF.
|
||||
if (!stream_skip(s, len)) {
|
||||
stream_seek(s, pos);
|
||||
goto resync;
|
||||
}
|
||||
|
|
|
@ -530,10 +530,10 @@ static int stream_seek_unbuffered(stream_t *s, int64_t newpos)
|
|||
// Unlike stream_seek_unbuffered(), it still fills the local buffer.
|
||||
static int stream_seek_long(stream_t *s, int64_t pos)
|
||||
{
|
||||
int res;
|
||||
int64_t newpos = 0;
|
||||
|
||||
int64_t oldpos = s->pos;
|
||||
s->buf_pos = s->buf_len = 0;
|
||||
s->eof = 0;
|
||||
|
||||
if (s->mode == STREAM_WRITE) {
|
||||
if (!s->seek || !s->seek(s, pos))
|
||||
|
@ -552,9 +552,10 @@ static int stream_seek_long(stream_t *s, int64_t pos)
|
|||
|
||||
pos -= newpos;
|
||||
|
||||
res = stream_seek_unbuffered(s, newpos);
|
||||
if (res >= 0)
|
||||
return res;
|
||||
if (stream_seek_unbuffered(s, newpos) >= 0) {
|
||||
s->pos = oldpos;
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (s->pos < newpos) {
|
||||
if (stream_fill_buffer(s) <= 0)
|
||||
|
@ -564,6 +565,7 @@ static int stream_seek_long(stream_t *s, int64_t pos)
|
|||
while (stream_fill_buffer(s) > 0) {
|
||||
if (pos <= s->buf_len) {
|
||||
s->buf_pos = pos; // byte position in sector
|
||||
s->eof = 0;
|
||||
return 1;
|
||||
}
|
||||
pos -= s->buf_len;
|
||||
|
@ -572,6 +574,7 @@ static int stream_seek_long(stream_t *s, int64_t pos)
|
|||
s->pos += pos;
|
||||
s->buf_pos = 0;
|
||||
s->buf_len = 0;
|
||||
s->eof = 0; // eof should be set only on read
|
||||
|
||||
mp_msg(MSGT_STREAM, MSGL_V,
|
||||
"stream_seek: Seek to/past EOF: no buffer preloaded.\n");
|
||||
|
@ -589,7 +592,7 @@ int stream_seek(stream_t *s, int64_t pos)
|
|||
pos = 0;
|
||||
}
|
||||
if (pos < s->pos) {
|
||||
int64_t x = pos - (s->pos - s->buf_len);
|
||||
int64_t x = pos - (s->pos - (int)s->buf_len);
|
||||
if (x >= 0) {
|
||||
s->buf_pos = x;
|
||||
s->eof = 0;
|
||||
|
@ -602,10 +605,19 @@ int stream_seek(stream_t *s, int64_t pos)
|
|||
|
||||
int stream_skip(stream_t *s, int64_t len)
|
||||
{
|
||||
if (len < 0 ||
|
||||
(len > 2 * STREAM_BUFFER_SIZE && (s->flags & MP_STREAM_SEEK_FW))) {
|
||||
// negative or big skip!
|
||||
return stream_seek(s, stream_tell(s) + len);
|
||||
int64_t target = stream_tell(s) + len;
|
||||
if (len < 0)
|
||||
return stream_seek(s, target);
|
||||
if (len > 2 * STREAM_BUFFER_SIZE && (s->flags & MP_STREAM_SEEK_FW)) {
|
||||
// Seek to 1 byte before target - this is the only way to distinguish
|
||||
// skip-to-EOF and skip-past-EOF in general. Successful seeking means
|
||||
// absolutely nothing, so test by doing a real read of the last byte.
|
||||
int r = stream_seek(s, target - 1);
|
||||
if (r) {
|
||||
stream_read_char(s);
|
||||
return !stream_eof(s);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
while (len > 0) {
|
||||
int x = s->buf_len - s->buf_pos;
|
||||
|
|
Loading…
Reference in New Issue