summaryrefslogtreecommitdiffstats
path: root/stream/stream.c
diff options
context:
space:
mode:
Diffstat (limited to 'stream/stream.c')
-rw-r--r--stream/stream.c124
1 files changed, 73 insertions, 51 deletions
diff --git a/stream/stream.c b/stream/stream.c
index a3285e4d8f..43a7f51a60 100644
--- a/stream/stream.c
+++ b/stream/stream.c
@@ -30,6 +30,7 @@
#include "common/common.h"
#include "common/global.h"
+#include "demux/demux.h"
#include "misc/bstr.h"
#include "misc/thread_tools.h"
#include "common/msg.h"
@@ -44,7 +45,6 @@
extern const stream_info_t stream_info_cdda;
extern const stream_info_t stream_info_dvb;
-extern const stream_info_t stream_info_smb;
extern const stream_info_t stream_info_null;
extern const stream_info_t stream_info_memory;
extern const stream_info_t stream_info_mf;
@@ -52,6 +52,8 @@ extern const stream_info_t stream_info_ffmpeg;
extern const stream_info_t stream_info_ffmpeg_unsafe;
extern const stream_info_t stream_info_avdevice;
extern const stream_info_t stream_info_file;
+extern const stream_info_t stream_info_slice;
+extern const stream_info_t stream_info_fd;
extern const stream_info_t stream_info_ifo_dvdnav;
extern const stream_info_t stream_info_dvdnav;
extern const stream_info_t stream_info_bdmv_dir;
@@ -71,9 +73,6 @@ static const stream_info_t *const stream_list[] = {
#if HAVE_DVBIN
&stream_info_dvb,
#endif
-#if HAVE_LIBSMBCLIENT
- &stream_info_smb,
-#endif
#if HAVE_DVDNAV
&stream_info_ifo_dvdnav,
&stream_info_dvdnav,
@@ -91,26 +90,30 @@ static const stream_info_t *const stream_list[] = {
&stream_info_mf,
&stream_info_edl,
&stream_info_file,
+ &stream_info_slice,
+ &stream_info_fd,
&stream_info_cb,
- NULL
};
// Because of guarantees documented on STREAM_BUFFER_SIZE.
// Half the buffer is used as forward buffer, the other for seek-back.
#define STREAM_MIN_BUFFER_SIZE (STREAM_BUFFER_SIZE * 2)
+// Sort of arbitrary; keep *2 of it comfortably within integer limits.
+// Must be power of 2.
+#define STREAM_MAX_BUFFER_SIZE (512 * 1024 * 1024)
struct stream_opts {
int64_t buffer_size;
- int load_unsafe_playlists;
+ bool load_unsafe_playlists;
};
#define OPT_BASE_STRUCT struct stream_opts
const struct m_sub_options stream_conf = {
.opts = (const struct m_option[]){
- OPT_BYTE_SIZE("stream-buffer-size", buffer_size, 0,
- STREAM_MIN_BUFFER_SIZE, 512 * 1024 * 1024),
- OPT_FLAG("load-unsafe-playlists", load_unsafe_playlists, 0),
+ {"stream-buffer-size", OPT_BYTE_SIZE(buffer_size),
+ M_RANGE(STREAM_MIN_BUFFER_SIZE, STREAM_MAX_BUFFER_SIZE)},
+ {"load-unsafe-playlists", OPT_BOOL(load_unsafe_playlists)},
{0}
},
.size = sizeof(struct stream_opts),
@@ -263,27 +266,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);
new = MPMAX(new, s->requested_buffer_size);
-
- // This much is always required.
- new = MPMAX(new, STREAM_MIN_BUFFER_SIZE);
-
+ new = MPMIN(new, STREAM_MAX_BUFFER_SIZE);
new = mp_round_next_power_of_2(new);
- if (!new || new > INT_MAX / 8)
- return false;
+
+ 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)
@@ -291,11 +295,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);
@@ -316,14 +321,20 @@ static int stream_create_instance(const stream_info_t *sinfo,
*ret = NULL;
const char *path = url;
- for (int n = 0; sinfo->protocols && sinfo->protocols[n]; n++) {
- path = match_proto(url, sinfo->protocols[n]);
- if (path)
- break;
- }
- if (!path)
- return STREAM_NO_MATCH;
+ if (flags & STREAM_LOCAL_FS_ONLY) {
+ if (!sinfo->local_fs)
+ return STREAM_NO_MATCH;
+ } else {
+ for (int n = 0; sinfo->protocols && sinfo->protocols[n]; n++) {
+ path = match_proto(url, sinfo->protocols[n]);
+ if (path)
+ break;
+ }
+
+ if (!path)
+ return STREAM_NO_MATCH;
+ }
stream_t *s = talloc_zero(NULL, stream_t);
s->global = args->global;
@@ -340,9 +351,12 @@ static int stream_create_instance(const stream_info_t *sinfo,
s->mode = flags & (STREAM_READ | STREAM_WRITE);
s->requested_buffer_size = opts->buffer_size;
- int opt;
- mp_read_option_raw(s->global, "access-references", &m_option_type_flag, &opt);
- s->access_references = opt;
+ if (flags & STREAM_LESS_NOISE)
+ mp_msg_set_max_level(s->log, MSGL_WARN);
+
+ struct demux_opts *demux_opts = mp_get_config_group(s, s->global, &demux_conf);
+ s->access_references = demux_opts->access_references;
+ talloc_free(demux_opts);
MP_VERBOSE(s, "Opening %s\n", url);
@@ -381,7 +395,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;
}
@@ -409,7 +423,7 @@ int stream_create_with_args(struct stream_open_args *args, struct stream **ret)
if (args->sinfo) {
r = stream_create_instance(args->sinfo, args, ret);
} else {
- for (int i = 0; stream_list[i]; i++) {
+ for (int i = 0; i < MP_ARRAY_SIZE(stream_list); i++) {
r = stream_create_instance(stream_list[i], args, ret);
if (r == STREAM_OK)
break;
@@ -427,8 +441,7 @@ int stream_create_with_args(struct stream_open_args *args, struct stream **ret)
if (r == STREAM_UNSAFE) {
mp_err(log, "\nRefusing to load potentially unsafe URL from a playlist.\n"
- "Use --playlist=file or the --load-unsafe-playlists option to "
- "load it anyway.\n\n");
+ "Use the --load-unsafe-playlists option to load it anyway.\n\n");
} else if (r == STREAM_NO_MATCH || r == STREAM_UNSUPPORTED) {
mp_err(log, "No protocol handler found to open URL %s\n", args->url);
mp_err(log, "The protocol is either unsupported, or was disabled "
@@ -481,6 +494,7 @@ static int stream_read_unbuffered(stream_t *s, void *buf, int len)
s->eof = 1;
return 0;
}
+ assert(res <= len);
// When reading succeeded we are obviously not at eof.
s->eof = 0;
s->pos += res;
@@ -502,11 +516,12 @@ static bool stream_read_more(struct stream *s, int forward)
// Avoid that many small reads will lead to many low-level read calls.
forward = MPMAX(forward, s->requested_buffer_size / 2);
+ assert(forward_avail < 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;
@@ -520,7 +535,7 @@ static bool stream_read_more(struct stream *s, int forward)
// Note: read as much as possible, even if forward is much smaller. Do
// this because the stream buffer is supposed to set an approx. minimum
// read size on it.
- int read = buf_alloc - buf_old - forward_avail; // free buffer past end
+ int read = buf_alloc - (buf_old + forward_avail); // free buffer past end
int pos = s->buf_end & s->buffer_mask;
read = MPMIN(read, buf_alloc - pos);
@@ -597,11 +612,19 @@ int stream_read(stream_t *s, void *mem, int total)
return total;
}
+// Read ahead so that at least forward_size bytes are readable ahead. Returns
+// the actual forward amount available (restricted by EOF or buffer limits).
+int stream_peek(stream_t *s, int forward_size)
+{
+ while (stream_read_more(s, forward_size)) {}
+ return s->buf_end - s->buf_cur;
+}
+
// Like stream_read(), but do not advance the current position. This may resize
// the buffer to satisfy the read request.
int stream_read_peek(stream_t *s, void *buf, int buf_size)
{
- while (stream_read_more(s, buf_size)) {}
+ stream_peek(s, buf_size);
return ring_copy(s, buf, buf_size, s->buf_cur);
}
@@ -648,7 +671,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.
@@ -780,7 +803,7 @@ int stream_skip_bom(struct stream *s)
struct bstr stream_read_complete(struct stream *s, void *talloc_ctx,
int max_size)
{
- if (max_size > 1000000000)
+ if (max_size <= 0 || max_size > STREAM_MAX_READ_SIZE)
abort();
int bufsize;
@@ -815,14 +838,13 @@ struct bstr stream_read_file(const char *filename, void *talloc_ctx,
struct mpv_global *global, int max_size)
{
struct bstr res = {0};
- char *fname = mp_get_user_path(NULL, global, filename);
- stream_t *s =
- stream_create(fname, STREAM_ORIGIN_DIRECT | STREAM_READ, NULL, global);
+ int flags = STREAM_ORIGIN_DIRECT | STREAM_READ | STREAM_LOCAL_FS_ONLY |
+ STREAM_LESS_NOISE;
+ stream_t *s = stream_create(filename, flags, NULL, global);
if (s) {
res = stream_read_complete(s, talloc_ctx, max_size);
free_stream(s);
}
- talloc_free(fname);
return res;
}
@@ -830,7 +852,7 @@ char **stream_get_proto_list(void)
{
char **list = NULL;
int num = 0;
- for (int i = 0; stream_list[i]; i++) {
+ for (int i = 0; i < MP_ARRAY_SIZE(stream_list); i++) {
const stream_info_t *stream_info = stream_list[i];
if (!stream_info->protocols)
@@ -865,7 +887,7 @@ void stream_print_proto_list(struct mp_log *log)
bool stream_has_proto(const char *proto)
{
- for (int i = 0; stream_list[i]; i++) {
+ for (int i = 0; i < MP_ARRAY_SIZE(stream_list); i++) {
const stream_info_t *stream_info = stream_list[i];
for (int j = 0; stream_info->protocols && stream_info->protocols[j]; j++) {