summaryrefslogtreecommitdiffstats
path: root/stream/stream.c
diff options
context:
space:
mode:
Diffstat (limited to 'stream/stream.c')
-rw-r--r--stream/stream.c37
1 files changed, 21 insertions, 16 deletions
diff --git a/stream/stream.c b/stream/stream.c
index 0a026713f6..0d72aa082f 100644
--- a/stream/stream.c
+++ b/stream/stream.c
@@ -264,24 +264,28 @@ static int ring_copy(struct stream *s, void *dst, int len, int pos)
// Does nothing if the size is adequate. Calling this with 0 ensures it uses the
// default buffer size if possible.
// The caller must check whether enough data was really allocated.
-// Returns false if buffer allocation failed.
-static bool stream_resize_buffer(struct stream *s, uint32_t new)
+// keep: keep at least [buf_end-keep, buf_end] (used for assert()s only)
+// new: new total size of buffer
+// returns: false if buffer allocation failed, true if reallocated or size ok
+static bool stream_resize_buffer(struct stream *s, int keep, int new)
{
- // Keep all valid buffer.
- int old_used_len = s->buf_end - s->buf_start;
- int old_pos = s->buf_cur - s->buf_start;
- new = MPMAX(new, old_used_len);
+ assert(keep >= s->buf_end - s->buf_cur);
+ assert(keep <= new);
- // This much is always required.
new = MPMAX(new, s->requested_buffer_size);
-
new = MPMIN(new, STREAM_MAX_BUFFER_SIZE);
new = mp_round_next_power_of_2(new);
+ assert(keep <= new); // can't fail (if old buffer size was valid)
+
if (new == s->buffer_mask + 1)
return true;
- MP_DBG(s, "resize stream to %d bytes\n", new);
+ int old_pos = s->buf_cur - s->buf_start;
+ int old_used_len = s->buf_end - s->buf_start;
+ int skip = old_used_len > new ? old_used_len - new : 0;
+
+ MP_DBG(s, "resize stream to %d bytes, drop %d bytes\n", new, skip);
void *nbuf = ta_alloc_size(s, new);
if (!nbuf)
@@ -289,11 +293,12 @@ static bool stream_resize_buffer(struct stream *s, uint32_t new)
int new_len = 0;
if (s->buffer)
- new_len = ring_copy(s, nbuf, new, s->buf_start);
- assert(new_len == old_used_len);
- assert(old_pos <= old_used_len);
+ new_len = ring_copy(s, nbuf, new, s->buf_start + skip);
+ assert(new_len == old_used_len - skip);
+ assert(old_pos >= skip); // "keep" too low
+ assert(old_pos - skip <= new_len);
s->buf_start = 0;
- s->buf_cur = old_pos;
+ s->buf_cur = old_pos - skip;
s->buf_end = new_len;
ta_free(s->buffer);
@@ -379,7 +384,7 @@ static int stream_create_instance(const stream_info_t *sinfo,
return r;
}
- if (!stream_resize_buffer(s, 0)) {
+ if (!stream_resize_buffer(s, 0, 0)) {
free_stream(s);
return STREAM_ERROR;
}
@@ -506,7 +511,7 @@ static bool stream_read_more(struct stream *s, int forward)
// Keep guaranteed seek-back.
int buf_old = MPMIN(s->buf_cur - s->buf_start, s->requested_buffer_size / 2);
- if (!stream_resize_buffer(s, buf_old + forward))
+ if (!stream_resize_buffer(s, buf_old + forward_avail, buf_old + forward))
return false;
int buf_alloc = s->buffer_mask + 1;
@@ -648,7 +653,7 @@ void stream_drop_buffers(stream_t *s)
s->pos = stream_tell(s);
s->buf_start = s->buf_cur = s->buf_end = 0;
s->eof = 0;
- stream_resize_buffer(s, 0);
+ stream_resize_buffer(s, 0, 0);
}
// Seek function bypassing the local stream buffer.