summaryrefslogtreecommitdiffstats
path: root/stream/stream.c
diff options
context:
space:
mode:
Diffstat (limited to 'stream/stream.c')
-rw-r--r--stream/stream.c141
1 files changed, 59 insertions, 82 deletions
diff --git a/stream/stream.c b/stream/stream.c
index e24ea69e08..d4f0fbc320 100644
--- a/stream/stream.c
+++ b/stream/stream.c
@@ -121,7 +121,7 @@ static const stream_info_t *const stream_list[] = {
NULL
};
-static int stream_seek_unbuffered(stream_t *s, int64_t newpos);
+static bool stream_seek_unbuffered(stream_t *s, int64_t newpos);
static int from_hex(unsigned char c)
{
@@ -414,32 +414,29 @@ stream_t *open_output_stream(const char *filename, struct mpv_global *global)
return stream_create(filename, STREAM_WRITE, NULL, global);
}
-static int stream_reconnect(stream_t *s)
+static bool stream_reconnect(stream_t *s)
{
- if (!s->streaming || s->uncached_stream)
- return 0;
- if (!s->seekable)
- return 0;
- if (mp_cancel_test(s->cancel) || !s->cancel)
- return 0;
+ if (!s->streaming || s->uncached_stream || !s->seekable || !s->cancel)
+ return false;
+
int64_t pos = s->pos;
double sleep_secs = 0;
for (int retry = 0; retry < 6; retry++) {
- MP_WARN(s, "Connection lost! Attempting to reconnect (%d)...\n", retry + 1);
-
if (mp_cancel_wait(s->cancel, sleep_secs))
break;
- sleep_secs = MPMAX(sleep_secs, 0.1);
- sleep_secs = MPMIN(sleep_secs * 4, 10.0);
+ MP_WARN(s, "Connection lost! Attempting to reconnect (%d)...\n", retry + 1);
int r = stream_control(s, STREAM_CTRL_RECONNECT, NULL);
if (r == STREAM_UNSUPPORTED)
break;
- if (r == STREAM_OK && stream_seek_unbuffered(s, pos) < 0 && s->pos == pos)
- return 1;
+ if (r == STREAM_OK && stream_seek_unbuffered(s, pos) && s->pos == pos)
+ return true;
+
+ sleep_secs = MPMAX(sleep_secs, 0.1);
+ sleep_secs = MPMIN(sleep_secs * 4, 10.0);
}
- return 0;
+ return false;
}
static void stream_capture_write(stream_t *s, void *buf, size_t len)
@@ -475,7 +472,7 @@ void stream_set_capture_file(stream_t *s, const char *filename)
// Read function bypassing the local stream buffer. This will not write into
// s->buffer, but into buf[0..len] instead.
-// Returns < 0 on error, 0 on EOF, and length of bytes read on success.
+// Returns 0 on error or EOF, and length of bytes read on success.
// Partial reads are possible, even if EOF is not reached.
static int stream_read_unbuffered(stream_t *s, void *buf, int len)
{
@@ -486,21 +483,16 @@ static int stream_read_unbuffered(stream_t *s, void *buf, int len)
if (len < 0)
len = 0;
if (len == 0) {
+ // just in case this is an error e.g. due to network
+ // timeout reset and retry
// do not retry if this looks like proper eof
int64_t size = -1;
stream_control(s, STREAM_CTRL_GET_SIZE, &size);
- if (s->eof || s->pos == size)
- goto eof_out;
-
- // just in case this is an error e.g. due to network
- // timeout reset and retry
- if (!stream_reconnect(s))
- goto eof_out;
- // make sure EOF is set to ensure no endless loops
- s->eof = 1;
- return stream_read_unbuffered(s, buf, orig_len);
+ if (!s->eof && s->pos != size && stream_reconnect(s)) {
+ s->eof = 1; // make sure EOF is set to ensure no endless recursion
+ return stream_read_unbuffered(s, buf, orig_len);
+ }
-eof_out:
s->eof = 1;
return 0;
}
@@ -613,13 +605,13 @@ int stream_write_buffer(stream_t *s, unsigned char *buf, int len)
return rd;
}
-static int stream_skip_read(struct stream *s, int64_t len)
+static bool stream_skip_read(struct stream *s, int64_t len)
{
while (len > 0) {
int x = s->buf_len - s->buf_pos;
if (x == 0) {
if (!stream_fill_buffer_by(s, len))
- return 0; // EOF
+ return false; // EOF
x = s->buf_len - s->buf_pos;
}
if (x > len)
@@ -627,7 +619,7 @@ static int stream_skip_read(struct stream *s, int64_t len)
s->buf_pos += x;
len -= x;
}
- return 1;
+ return true;
}
// Drop the internal buffer. Note that this will advance the stream position
@@ -641,85 +633,72 @@ void stream_drop_buffers(stream_t *s)
}
// Seek function bypassing the local stream buffer.
-static int stream_seek_unbuffered(stream_t *s, int64_t newpos)
+static bool stream_seek_unbuffered(stream_t *s, int64_t newpos)
{
if (newpos != s->pos) {
if (newpos > s->pos && !s->seekable) {
MP_ERR(s, "Cannot seek forward in this stream\n");
- return 0;
+ return false;
}
if (newpos < s->pos && !s->seekable) {
MP_ERR(s, "Cannot seek backward in linear streams!\n");
- return 1;
+ return false;
}
if (s->seek(s, newpos) <= 0) {
MP_ERR(s, "Seek failed\n");
- return 0;
+ return false;
}
stream_drop_buffers(s);
s->pos = newpos;
}
- s->eof = 0; // EOF reset when seek succeeds.
- return -1;
+ return true;
}
-// Unlike stream_seek, does not try to seek within local buffer.
-// Unlike stream_seek_unbuffered(), it still fills the local buffer.
-static int stream_seek_long(stream_t *s, int64_t pos)
+bool stream_seek(stream_t *s, int64_t pos)
{
- if (s->mode == STREAM_WRITE) {
- if (!s->seekable || !s->seek(s, pos))
- return 0;
- return 1;
- }
-
- int64_t newpos = pos;
- if (s->sector_size)
- newpos = (pos / s->sector_size) * s->sector_size;
+ MP_TRACE(s, "seek to %lld\n", (long long)pos);
- MP_TRACE(s, "Seek from %" PRId64 " to %" PRId64
- " (with offset %d)\n", s->pos, pos, (int)(pos - newpos));
-
- if (pos >= s->pos && !s->seekable && s->fast_skip) {
- // skipping is handled by generic code below
- } else if (stream_seek_unbuffered(s, newpos) >= 0) {
- return 0;
- }
-
- if (pos >= s->pos && stream_skip_read(s, pos - s->pos) > 0)
- return 1; // success
-
- // Fill failed, but seek still is a success (partially).
- s->eof = 0; // eof should be set only on read
-
- MP_VERBOSE(s, "Seek to/past EOF: no buffer preloaded.\n");
- return 1;
-}
-
-int stream_seek(stream_t *s, int64_t pos)
-{
- MP_TRACE(s, "seek to 0x%llX\n", (long long)pos);
+ s->eof = 0; // eof should be set only on read; seeking always clears it
if (pos == stream_tell(s))
- return 1;
+ return true;
if (pos < 0) {
- MP_ERR(s, "Invalid seek to negative position %llx!\n", (long long)pos);
+ MP_ERR(s, "Invalid seek to negative position %lld!\n", (long long)pos);
pos = 0;
}
if (pos < s->pos) {
int64_t x = pos - (s->pos - (int)s->buf_len);
if (x >= 0) {
s->buf_pos = x;
- s->eof = 0;
- return 1;
+ return true;
}
}
- return stream_seek_long(s, pos);
+ if (s->mode == STREAM_WRITE)
+ return s->seekable && s->seek(s, pos));
+
+ int64_t newpos = pos;
+ if (s->sector_size)
+ newpos = (pos / s->sector_size) * s->sector_size;
+
+ MP_TRACE(s, "Seek from %" PRId64 " to %" PRId64
+ " (with offset %d)\n", s->pos, pos, (int)(pos - newpos));
+
+ if (pos >= s->pos && !s->seekable && s->fast_skip) {
+ // skipping is handled by generic code below
+ } else if (!stream_seek_unbuffered(s, newpos)) {
+ return false;
+ }
+
+ bool r = pos >= s->pos && stream_skip_read(s, pos - s->pos);
+ if (!r)
+ MP_VERBOSE(s, "Seek to/past EOF: no buffer preloaded.\n");
+ s->eof = 0;
+ return r;
}
-int stream_skip(stream_t *s, int64_t len)
+bool stream_skip(stream_t *s, int64_t len)
{
int64_t target = stream_tell(s) + len;
if (len < 0)
@@ -728,12 +707,10 @@ int stream_skip(stream_t *s, int64_t len)
// 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) && stream_tell(s) == target;
- }
- return r;
+ if (!stream_seek(s, target - 1))
+ return false;
+ stream_read_char(s);
+ return !stream_eof(s) && stream_tell(s) == target;
}
return stream_skip_read(s, len);
}