From ac7f67b3f23a63e463fb881d960bc8f31a230292 Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 14 Nov 2019 12:59:14 +0100 Subject: demux_mkv, stream: attempt to improve behavior in unseekable streams stream_skip() semantics were kind of bad, especially after the recent change to the stream code. Forward stream_skip() calls could still trigger a seek and fail, even if it was supposed to actually skip data. (Maybe the idea that stream_skip() should try to seek is worthless in the first place.) Rename it to stream_seek_skip() (takes absolute position now because I think that's better), and make it always skip if the stream is marked as forward. While we're at it, make EOF detection more robust. I guess s->eof shouldn't exist at all, since it's valid only "sometimes". It should be removed... but not today. A 1-byte stream_read_peek() call is good to get the s->eof flag set to a correct value. --- demux/demux_mkv.c | 4 ++-- demux/demux_playlist.c | 2 +- demux/ebml.c | 5 +++-- stream/stream.c | 14 +++++++------- stream/stream.h | 4 ++-- stream/stream_libarchive.c | 2 +- 6 files changed, 16 insertions(+), 15 deletions(-) diff --git a/demux/demux_mkv.c b/demux/demux_mkv.c index bd36edb784..4c5f376137 100644 --- a/demux/demux_mkv.c +++ b/demux/demux_mkv.c @@ -1954,7 +1954,7 @@ static int read_mkv_segment_header(demuxer_t *demuxer, int64_t *segment_end) if (demuxer->params) num_skip = demuxer->params->matroska_wanted_segment; - while (!s->eof) { + while (stream_read_peek(s, &(char){0}, 1)) { if (ebml_read_id(s) != MATROSKA_ID_SEGMENT) { MP_VERBOSE(demuxer, "segment not found\n"); return 0; @@ -2580,7 +2580,7 @@ static int read_block(demuxer_t *demuxer, int64_t end, struct block_info *block) exit: if (res <= 0) free_block(block); - stream_seek(s, endpos); + stream_seek_skip(s, endpos); return res; } diff --git a/demux/demux_playlist.c b/demux/demux_playlist.c index a7650b2b69..b51edad86c 100644 --- a/demux/demux_playlist.c +++ b/demux/demux_playlist.c @@ -99,7 +99,7 @@ static int read_characters(stream_t *s, uint8_t *dst, int dstsize, int utf16) if (len > dstsize) return -1; // line too long memcpy(dst, buf, len); - stream_skip(s, len); + stream_seek_skip(s, len); return len; } } diff --git a/demux/ebml.c b/demux/ebml.c index 44fa0c0793..143a5fe57b 100644 --- a/demux/ebml.c +++ b/demux/ebml.c @@ -180,14 +180,14 @@ int ebml_read_skip(struct mp_log *log, int64_t end, stream_t *s) if (len >= INT64_MAX - pos2 || (end > 0 && pos2 + len > end)) goto invalid; - if (!stream_skip(s, len)) + if (!stream_seek_skip(s, pos2 + len)) goto invalid; return 0; invalid: mp_err(log, "Invalid EBML length at position %"PRId64"\n", pos); - stream_seek(s, pos); + stream_seek_skip(s, pos); return 1; } @@ -198,6 +198,7 @@ int ebml_resync_cluster(struct mp_log *log, stream_t *s) { int64_t pos = stream_tell(s); uint32_t last_4_bytes = 0; + stream_read_peek(s, &(char){0}, 1); if (!s->eof) { mp_err(log, "Corrupt file detected. " "Trying to resync starting from position %"PRId64"...\n", pos); diff --git a/stream/stream.c b/stream/stream.c index 7fd6700cdd..271e268a1c 100644 --- a/stream/stream.c +++ b/stream/stream.c @@ -692,13 +692,13 @@ bool stream_seek(stream_t *s, int64_t pos) return stream_seek_unbuffered(s, pos); } -bool stream_skip(stream_t *s, int64_t len) +// Like stream_seek(), but strictly prefer skipping data instead of failing, if +// it's a forward-seek. +bool stream_seek_skip(stream_t *s, int64_t pos) { - if (!stream_seek(s, stream_tell(s) + len)) - return false; - // Make sure s->eof is set correctly, even if a seek happened. - stream_read_more(s, 1); - return true; + return !s->seekable && pos > stream_tell(s) + ? stream_skip_read(s, pos - stream_tell(s)) + : stream_seek(s, pos); } int stream_control(stream_t *s, int cmd, void *arg) @@ -732,7 +732,7 @@ int stream_skip_bom(struct stream *s) bstr data = {buf, len}; for (int n = 0; n < 3; n++) { if (bstr_startswith0(data, bom[n])) { - stream_skip(s, strlen(bom[n])); + stream_seek_skip(s, stream_tell(s) + strlen(bom[n])); return n; } } diff --git a/stream/stream.h b/stream/stream.h index 4a38d28109..d054e54914 100644 --- a/stream/stream.h +++ b/stream/stream.h @@ -121,7 +121,7 @@ typedef struct stream { void (*close)(struct stream *s); int64_t pos; - int eof; + int eof; // valid only after read calls that returned a short result int mode; //STREAM_READ or STREAM_WRITE void *priv; // used for DVD, TV, RTSP etc char *url; // filename/url (possibly including protocol prefix) @@ -194,7 +194,7 @@ inline static int64_t stream_tell(stream_t *s) return s->pos + s->buf_cur - s->buf_end; } -bool stream_skip(stream_t *s, int64_t len); +bool stream_seek_skip(stream_t *s, int64_t pos); bool stream_seek(stream_t *s, int64_t pos); int stream_read(stream_t *s, void *mem, int total); int stream_read_partial(stream_t *s, void *buf, int buf_size); diff --git a/stream/stream_libarchive.c b/stream/stream_libarchive.c index ab8fda0f34..e3109dfb0a 100644 --- a/stream/stream_libarchive.c +++ b/stream/stream_libarchive.c @@ -84,7 +84,7 @@ static int64_t skip_cb(struct archive *arch, void *priv, int64_t request) if (!volume_seek(vol)) return -1; int64_t old = stream_tell(vol->src); - stream_skip(vol->src, request); + stream_seek_skip(vol->src, old + request); return stream_tell(vol->src) - old; } -- cgit v1.2.3