summaryrefslogtreecommitdiffstats
path: root/stream/stream.c
diff options
context:
space:
mode:
Diffstat (limited to 'stream/stream.c')
-rw-r--r--stream/stream.c150
1 files changed, 104 insertions, 46 deletions
diff --git a/stream/stream.c b/stream/stream.c
index 523fcc2e8e..a4d9238d46 100644
--- a/stream/stream.c
+++ b/stream/stream.c
@@ -44,7 +44,7 @@
#include "demux/demux.h"
#include "core/m_option.h"
-#include "core/m_struct.h"
+#include "core/m_config.h"
// Includes additional padding in case sizes get rounded up by sector size.
#define TOTAL_BUFFER_SIZE (STREAM_MAX_BUFFER_SIZE + STREAM_MAX_SECTOR_SIZE)
@@ -114,40 +114,97 @@ static const stream_info_t *const auto_open_streams[] = {
NULL
};
-static stream_t *new_stream(size_t min_size);
static int stream_seek_unbuffered(stream_t *s, int64_t newpos);
+static const char *find_url_opt(struct stream *s, const char *opt)
+{
+ for (int n = 0; s->info->url_options && s->info->url_options[n][0]; n++) {
+ if (strcmp(s->info->url_options[n][0], opt) == 0)
+ return s->info->url_options[n][1];
+ }
+ return NULL;
+}
+
+static bstr split_next(bstr *s, char end, const char *delim)
+{
+ int idx = bstrcspn(*s, delim);
+ if (end && (idx >= s->len || s->start[idx] != end))
+ return (bstr){0};
+ bstr r = bstr_splice(*s, 0, idx);
+ *s = bstr_cut(*s, idx + (end ? 1 : 0));
+ return r;
+}
+
+// Parse the stream URL, syntax:
+// proto:// [<username>@]<hostname>[:<port>][/<filename>]
+// (the proto:// part is already removed from s->path)
+// This code originates from times when http code used this, but now it's
+// just relict from other stream implementations reusing this code.
+static bool parse_url(struct stream *st, struct m_config *config)
+{
+ bstr s = bstr0(st->path);
+ const char *f_names[4] = {"username", "hostname", "port", "filename"};
+ bstr f[4];
+ f[0] = split_next(&s, '@', "@:/");
+ f[1] = split_next(&s, 0, ":/");
+ f[2] = bstr_eatstart0(&s, ":") ? split_next(&s, 0, "/") : (bstr){0};
+ f[3] = bstr_eatstart0(&s, "/") ? s : (bstr){0};
+ for (int n = 0; n < 4; n++) {
+ if (f[n].len) {
+ const char *opt = find_url_opt(st, f_names[n]);
+ if (!opt) {
+ mp_tmsg(MSGT_OPEN, MSGL_ERR, "Stream type '%s' accepts no '%s' "
+ "field in URLs.\n", st->info->name, f_names[n]);
+ return false;
+ }
+ int r = m_config_set_option(config, bstr0(opt), f[n]);
+ if (r < 0) {
+ mp_tmsg(MSGT_OPEN, MSGL_ERR, "Error setting stream option: %s\n",
+ m_option_strerror(r));
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+static stream_t *new_stream(void)
+{
+ stream_t *s = talloc_size(NULL, sizeof(stream_t) + TOTAL_BUFFER_SIZE);
+ memset(s, 0, sizeof(stream_t));
+ return s;
+}
+
static stream_t *open_stream_plugin(const stream_info_t *sinfo,
- const char *filename, int mode,
+ const char *url, const char *path, int mode,
struct MPOpts *options, int *ret)
{
- void *arg = NULL;
- stream_t *s;
- m_struct_t *desc = (m_struct_t *)sinfo->opts;
+ stream_t *s = new_stream();
+ s->info = sinfo;
+ s->opts = options;
+ s->url = talloc_strdup(s, url);
+ s->path = talloc_strdup(s, path);
// Parse options
- if (desc) {
- arg = m_struct_alloc(desc);
- if (sinfo->opts_url) {
- m_option_t url_opt = { "stream url", arg, CONF_TYPE_CUSTOM_URL, 0,
- 0, 0, (void *)sinfo->opts };
- if (m_option_parse(&url_opt, bstr0("stream url"), bstr0(filename),
- arg) < 0)
- {
- mp_tmsg(MSGT_OPEN, MSGL_ERR, "URL parsing failed on url %s\n",
- filename);
- m_struct_free(desc, arg);
- *ret = STREAM_ERROR;
- return NULL;
- }
+ if (sinfo->priv_size) {
+ struct m_obj_desc desc = {
+ .priv_size = sinfo->priv_size,
+ .priv_defaults = sinfo->priv_defaults,
+ .options = sinfo->options,
+ };
+ struct m_config *config = m_config_from_obj_desc(s, &desc);
+ s->priv = config->optstruct;
+ if (s->info->url_options && !parse_url(s, config)) {
+ mp_tmsg(MSGT_OPEN, MSGL_ERR, "URL parsing failed on url %s\n", url);
+ talloc_free(s);
+ *ret = STREAM_ERROR;
+ return NULL;
}
}
- s = new_stream(0);
- s->opts = options;
- s->url = talloc_strdup(s, filename);
+
s->flags = 0;
s->mode = mode;
- *ret = sinfo->open(s, mode, arg);
+ *ret = sinfo->open(s, mode);
if ((*ret) != STREAM_OK) {
talloc_free(s);
return NULL;
@@ -165,7 +222,7 @@ static stream_t *open_stream_plugin(const stream_info_t *sinfo,
s->uncached_type = s->type;
- mp_msg(MSGT_OPEN, MSGL_V, "[stream] [%s] %s\n", sinfo->name, filename);
+ mp_msg(MSGT_OPEN, MSGL_V, "[stream] [%s] %s\n", sinfo->name, url);
if (s->mime_type)
mp_msg(MSGT_OPEN, MSGL_V, "Mime-type: '%s'\n", s->mime_type);
@@ -173,15 +230,28 @@ static stream_t *open_stream_plugin(const stream_info_t *sinfo,
return s;
}
+static const char *match_proto(const char *url, const char *proto)
+{
+ int l = strlen(proto);
+ if (l > 0) {
+ if (strncasecmp(url, proto, l) == 0 && strncmp("://", url + l, 3) == 0)
+ return url + l + 3;
+ } else {
+ // pure filenames
+ if (!strstr(url, "://"))
+ return url;
+ }
+ return NULL;
+}
-static stream_t *open_stream_full(const char *filename, int mode,
+static stream_t *open_stream_full(const char *url, int mode,
struct MPOpts *options)
{
- int i, j, l, r;
+ int i, j, r;
const stream_info_t *sinfo;
stream_t *s;
- assert(filename);
+ assert(url);
for (i = 0; auto_open_streams[i]; i++) {
sinfo = auto_open_streams[i];
@@ -192,17 +262,13 @@ static stream_t *open_stream_full(const char *filename, int mode,
continue;
}
for (j = 0; sinfo->protocols[j]; j++) {
- l = strlen(sinfo->protocols[j]);
- // l == 0 => Don't do protocol matching (ie network and filenames)
- if ((l == 0 && !strstr(filename, "://")) ||
- ((strncasecmp(sinfo->protocols[j], filename, l) == 0) &&
- (strncmp("://", filename + l, 3) == 0))) {
- s = open_stream_plugin(sinfo, filename, mode, options, &r);
+ const char *path = match_proto(url, sinfo->protocols[j]);
+ if (path) {
+ s = open_stream_plugin(sinfo, url, path, mode, options, &r);
if (s)
return s;
if (r != STREAM_UNSUPPORTED) {
- mp_tmsg(MSGT_OPEN, MSGL_ERR, "Failed to open %s.\n",
- filename);
+ mp_tmsg(MSGT_OPEN, MSGL_ERR, "Failed to open %s.\n", url);
return NULL;
}
break;
@@ -210,7 +276,7 @@ static stream_t *open_stream_full(const char *filename, int mode,
}
}
- mp_tmsg(MSGT_OPEN, MSGL_ERR, "No stream found to handle url %s\n", filename);
+ mp_tmsg(MSGT_OPEN, MSGL_ERR, "No stream found to handle url %s\n", url);
return NULL;
}
@@ -558,14 +624,6 @@ void stream_update_size(stream_t *s)
}
}
-static stream_t *new_stream(size_t min_size)
-{
- min_size = FFMAX(min_size, TOTAL_BUFFER_SIZE);
- stream_t *s = talloc_size(NULL, sizeof(stream_t) + min_size);
- memset(s, 0, sizeof(stream_t));
- return s;
-}
-
void free_stream(stream_t *s)
{
if (!s)
@@ -638,7 +696,7 @@ static int stream_enable_cache(stream_t **stream, int64_t size, int64_t min,
// Can't handle a loaded buffer.
orig->buf_len = orig->buf_pos = 0;
- stream_t *cache = new_stream(0);
+ stream_t *cache = new_stream();
cache->uncached_type = orig->type;
cache->uncached_stream = orig;
cache->flags |= MP_STREAM_SEEK;