mirror of
https://github.com/mpv-player/mpv.git
synced 2025-12-28 05:33:14 +00:00
stream: turn into a ring buffer, make size configurable
In some corner cases (see #6802), it can be beneficial to use a larger stream buffer size. Use this as argument to rewrite everything for no reason. Turn stream.c itself into a ring buffer, with configurable size. The latter would have been easily achievable with minimal changes, and the ring buffer is the hard part. There is no reason to have a ring buffer at all, except possibly if ffmpeg don't fix their awful mp4 demuxer, and some subtle issues with demux_mkv.c wanting to seek back by small offsets (the latter was handled with small stream_peek() calls, which are unneeded now). In addition, this turns small forward seeks into reads (where data is simply skipped). Before this commit, only stream_skip() did this (which also mean that stream_skip() simply calls stream_seek() now). Replace all stream_peek() calls with something else (usually stream_read_peek()). The function was a problem, because it returned a pointer to the internal buffer, which is now a ring buffer with wrapping. The new function just copies the data into a buffer, and in some cases requires callers to dynamically allocate memory. (The most common case, demux_lavf.c, required a separate buffer allocation anyway due to FFmpeg "idiosyncrasies".) This is the bulk of the demuxer_* changes. I'm not happy with this. There still isn't a good reason why there should be a ring buffer, that is complex, and most of the time just wastes half of the available memory. Maybe another rewrite soon. It also contains bugs; you're an alpha tester now.
This commit is contained in:
@@ -265,8 +265,9 @@ static int try_open_file(struct demuxer *demuxer, enum demux_check check)
|
||||
|
||||
struct stream *s = demuxer->stream;
|
||||
if (check >= DEMUX_CHECK_UNSAFE) {
|
||||
bstr d = stream_peek(s, PROBE_SIZE);
|
||||
if (d.len < 1 || !mp_probe_cue(d))
|
||||
char probe[PROBE_SIZE];
|
||||
int len = stream_read_peek(s, probe, sizeof(probe));
|
||||
if (len < 1 || !mp_probe_cue((bstr){probe, len}))
|
||||
return -1;
|
||||
}
|
||||
struct priv *p = talloc_zero(demuxer, struct priv);
|
||||
|
||||
@@ -321,7 +321,7 @@ static int d_open(demuxer_t *demuxer, enum demux_check check)
|
||||
|
||||
// Initialize the playback time. We need to read _some_ data to get the
|
||||
// correct stream-layer time (at least with libdvdnav).
|
||||
stream_peek(demuxer->stream, 1);
|
||||
stream_read_peek(demuxer->stream, &(char){0}, 1);
|
||||
reset_pts(demuxer);
|
||||
|
||||
p->slave = demux_open_url("-", ¶ms, demuxer->cancel, demuxer->global);
|
||||
|
||||
@@ -459,7 +459,9 @@ static int try_open_file(struct demuxer *demuxer, enum demux_check check)
|
||||
return 0;
|
||||
}
|
||||
if (check >= DEMUX_CHECK_UNSAFE) {
|
||||
if (!bstr_equals0(stream_peek(s, strlen(HEADER)), HEADER))
|
||||
char header[sizeof(HEADER) - 1];
|
||||
int len = stream_read_peek(s, header, sizeof(header));
|
||||
if (len != strlen(HEADER) || memcmp(header, HEADER, len) != 0)
|
||||
return -1;
|
||||
}
|
||||
p->data = stream_read_complete(s, demuxer, 1000000);
|
||||
|
||||
@@ -458,11 +458,10 @@ static int lavf_check_file(demuxer_t *demuxer, enum demux_check check)
|
||||
} else {
|
||||
int nsize = av_clip(avpd.buf_size * 2, INITIAL_PROBE_SIZE,
|
||||
PROBE_BUF_SIZE);
|
||||
bstr buf = stream_peek(s, nsize);
|
||||
if (buf.len <= avpd.buf_size)
|
||||
nsize = stream_read_peek(s, avpd.buf, nsize);
|
||||
if (nsize <= avpd.buf_size)
|
||||
final_probe = true;
|
||||
memcpy(avpd.buf, buf.start, buf.len);
|
||||
avpd.buf_size = buf.len;
|
||||
avpd.buf_size = nsize;
|
||||
|
||||
priv->avif = av_probe_input_format2(&avpd, avpd.buf_size > 0, &score);
|
||||
}
|
||||
|
||||
@@ -43,15 +43,17 @@ static int open_file(struct demuxer *demuxer, enum demux_check check)
|
||||
probe_size *= 100;
|
||||
}
|
||||
|
||||
bstr probe = stream_peek(demuxer->stream, probe_size);
|
||||
if (probe.len == 0)
|
||||
void *probe = ta_alloc_size(NULL, probe_size);
|
||||
if (!probe)
|
||||
return -1;
|
||||
int probe_got = stream_read_peek(demuxer->stream, probe, probe_size);
|
||||
struct stream *probe_stream =
|
||||
stream_memory_open(demuxer->global, probe.start, probe.len);
|
||||
stream_memory_open(demuxer->global, probe, probe_got);
|
||||
struct mp_archive *mpa = mp_archive_new(mp_null_log, probe_stream, flags);
|
||||
bool ok = !!mpa;
|
||||
free_stream(probe_stream);
|
||||
mp_archive_free(mpa);
|
||||
ta_free(probe);
|
||||
if (!ok)
|
||||
return -1;
|
||||
|
||||
|
||||
@@ -1999,13 +1999,9 @@ static int demux_mkv_open(demuxer_t *demuxer, enum demux_check check)
|
||||
if (demuxer->params)
|
||||
mkv_d->probably_webm_dash_init = demuxer->params->init_fragment.len > 0;
|
||||
|
||||
bstr start = stream_peek(s, 4);
|
||||
uint32_t start_id = 0;
|
||||
for (int n = 0; n < start.len; n++)
|
||||
start_id = (start_id << 8) | start.start[n];
|
||||
if (start_id != EBML_ID_EBML)
|
||||
// Make sure you can seek back after read_ebml_header() if no EBML ID.
|
||||
if (stream_read_peek(s, &(char[4]){0}, 4) != 4)
|
||||
return -1;
|
||||
|
||||
if (!read_ebml_header(demuxer))
|
||||
return -1;
|
||||
MP_DBG(demuxer, "Found the head...\n");
|
||||
@@ -2027,7 +2023,6 @@ static int demux_mkv_open(demuxer_t *demuxer, enum demux_check check)
|
||||
|
||||
while (1) {
|
||||
start_pos = stream_tell(s);
|
||||
stream_peek(s, 4); // make sure we can always seek back
|
||||
uint32_t id = ebml_read_id(s);
|
||||
if (s->eof) {
|
||||
if (!mkv_d->probably_webm_dash_init)
|
||||
@@ -2836,7 +2831,6 @@ static int read_next_block_into_queue(demuxer_t *demuxer)
|
||||
find_next_cluster:
|
||||
mkv_d->cluster_end = 0;
|
||||
for (;;) {
|
||||
stream_peek(s, 4); // guarantee we can undo ebml_read_id() below
|
||||
mkv_d->cluster_start = stream_tell(s);
|
||||
uint32_t id = ebml_read_id(s);
|
||||
if (id == MATROSKA_ID_CLUSTER)
|
||||
|
||||
@@ -92,12 +92,13 @@ static int read_characters(stream_t *s, uint8_t *dst, int dstsize, int utf16)
|
||||
}
|
||||
return cur - dst;
|
||||
} else {
|
||||
bstr buf = stream_peek_buffer(s);
|
||||
uint8_t *end = memchr(buf.start, '\n', buf.len);
|
||||
int len = end ? end - buf.start + 1 : buf.len;
|
||||
uint8_t buf[1024];
|
||||
int buf_len = stream_read_peek(s, buf, sizeof(buf));
|
||||
uint8_t *end = memchr(buf, '\n', buf_len);
|
||||
int len = end ? end - buf + 1 : buf_len;
|
||||
if (len > dstsize)
|
||||
return -1; // line too long
|
||||
memcpy(dst, buf.start, len);
|
||||
memcpy(dst, buf, len);
|
||||
stream_skip(s, len);
|
||||
return len;
|
||||
}
|
||||
@@ -178,7 +179,9 @@ static int parse_m3u(struct pl_parser *p)
|
||||
// Last resort: if the file extension is m3u, it might be headerless.
|
||||
if (p->check_level == DEMUX_CHECK_UNSAFE) {
|
||||
char *ext = mp_splitext(p->real_stream->url, NULL);
|
||||
bstr data = stream_peek(p->real_stream, PROBE_SIZE);
|
||||
char probe[PROBE_SIZE];
|
||||
int len = stream_read_peek(p->real_stream, probe, sizeof(probe));
|
||||
bstr data = {probe, len};
|
||||
if (ext && data.len > 10 && maybe_text(data)) {
|
||||
const char *exts[] = {"m3u", "m3u8", NULL};
|
||||
for (int n = 0; exts[n]; n++) {
|
||||
@@ -437,8 +440,9 @@ static int open_file(struct demuxer *demuxer, enum demux_check check)
|
||||
p->real_stream = demuxer->stream;
|
||||
p->add_base = true;
|
||||
|
||||
bstr probe_buf = stream_peek(demuxer->stream, PROBE_SIZE);
|
||||
p->s = stream_memory_open(demuxer->global, probe_buf.start, probe_buf.len);
|
||||
char probe[PROBE_SIZE];
|
||||
int probe_len = stream_read_peek(p->real_stream, probe, sizeof(probe));
|
||||
p->s = stream_memory_open(demuxer->global, probe, probe_len);
|
||||
p->s->mime_type = demuxer->stream->mime_type;
|
||||
p->utf16 = stream_skip_bom(p->s);
|
||||
p->force = force;
|
||||
|
||||
Reference in New Issue
Block a user