diff options
Diffstat (limited to 'stream')
-rw-r--r-- | stream/stream.c | 129 | ||||
-rw-r--r-- | stream/stream.h | 9 |
2 files changed, 83 insertions, 55 deletions
diff --git a/stream/stream.c b/stream/stream.c index e1b8efee83..474e46d96a 100644 --- a/stream/stream.c +++ b/stream/stream.c @@ -76,7 +76,7 @@ extern const stream_info_t stream_info_ifo; extern const stream_info_t stream_info_dvd; extern const stream_info_t stream_info_bluray; -static const stream_info_t *const auto_open_streams[] = { +static const stream_info_t *const stream_list[] = { #ifdef CONFIG_VCD &stream_info_vcd, #endif @@ -210,15 +210,48 @@ static stream_t *new_stream(void) return s; } -static stream_t *open_stream_plugin(const stream_info_t *sinfo, - const char *url, const char *path, int mode, - struct MPOpts *options, int *ret) +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 (including "/path" and "./path") + if (url[0] == '/' || url[0] == '.' || !strstr(url, "://")) + return url; + } + return NULL; +} + +static int open_internal(const stream_info_t *sinfo, struct stream *underlying, + const char *url, int flags, struct MPOpts *options, + struct stream **ret) { + if (sinfo->stream_filter != !!underlying) + return STREAM_NO_MATCH; + if (sinfo->stream_filter && (flags & STREAM_NO_FILTERS)) + return STREAM_NO_MATCH; + + const char *path = NULL; + // Stream filters use the original URL, with no protocol matching at all. + if (!sinfo->stream_filter) { + 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 = new_stream(); s->info = sinfo; s->opts = options; s->url = talloc_strdup(s, url); s->path = talloc_strdup(s, path); + s->source = underlying; // Parse options if (sinfo->priv_size) { @@ -232,17 +265,16 @@ static stream_t *open_stream_plugin(const stream_info_t *sinfo, 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; + return STREAM_ERROR; } } s->flags = 0; - s->mode = mode; - *ret = sinfo->open(s, mode); - if ((*ret) != STREAM_OK) { + s->mode = flags & (STREAM_READ | STREAM_WRITE); + int r = sinfo->open(s, s->mode); + if (r != STREAM_OK) { talloc_free(s); - return NULL; + return r; } if (!s->read_chunk) @@ -256,8 +288,6 @@ static stream_t *open_stream_plugin(const stream_info_t *sinfo, if (s->flags & MP_STREAM_FAST_SKIPPING) s->flags |= MP_STREAM_SEEK_FW; - s->mode = mode; - s->uncached_type = s->type; mp_msg(MSGT_OPEN, MSGL_V, "[stream] [%s] %s\n", sinfo->name, url); @@ -265,67 +295,57 @@ static stream_t *open_stream_plugin(const stream_info_t *sinfo, if (s->mime_type) mp_msg(MSGT_OPEN, MSGL_V, "Mime-type: '%s'\n", s->mime_type); - return s; + *ret = s; + return STREAM_OK; } -static const char *match_proto(const char *url, const char *proto) +struct stream *stream_create(const char *url, int flags, struct MPOpts *options) { - 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 *url, int mode, - struct MPOpts *options) -{ - int i, j, r; - const stream_info_t *sinfo; - stream_t *s; - + struct stream *s = NULL; assert(url); - for (i = 0; auto_open_streams[i]; i++) { - sinfo = auto_open_streams[i]; - if (!sinfo->protocols) { - mp_msg(MSGT_OPEN, MSGL_WARN, - "Stream type %s has protocols == NULL, it's a bug\n", - sinfo->name); + // Open stream proper + for (int i = 0; stream_list[i]; i++) { + int r = open_internal(stream_list[i], NULL, url, flags, options, &s); + if (r == STREAM_OK) + break; + if (r == STREAM_NO_MATCH || r == STREAM_UNSUPPORTED) continue; + if (r != STREAM_OK) { + mp_tmsg(MSGT_OPEN, MSGL_ERR, "Failed to open %s.\n", url); + return NULL; } - for (j = 0; sinfo->protocols[j]; j++) { - 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", url); - return NULL; - } + } + + if (!s) { + mp_tmsg(MSGT_OPEN, MSGL_ERR, "No stream found to handle url %s\n", url); + return NULL; + } + + // Open stream filters + for (;;) { + struct stream *new = NULL; + for (int i = 0; stream_list[i]; i++) { + int r = open_internal(stream_list[i], s, s->url, flags, options, &new); + if (r == STREAM_OK) break; - } } + if (!new) + break; + s = new; } - mp_tmsg(MSGT_OPEN, MSGL_ERR, "No stream found to handle url %s\n", url); - return NULL; + return s; } struct stream *stream_open(const char *filename, struct MPOpts *options) { - return open_stream_full(filename, STREAM_READ, options); + return stream_create(filename, STREAM_READ, options); } stream_t *open_output_stream(const char *filename, struct MPOpts *options) { - return open_stream_full(filename, STREAM_WRITE, options); + return stream_create(filename, STREAM_WRITE, options); } static int stream_reconnect(stream_t *s) @@ -673,6 +693,7 @@ void free_stream(stream_t *s) if (s->close) s->close(s); free_stream(s->uncached_stream); + free_stream(s->source); talloc_free(s); } diff --git a/stream/stream.h b/stream/stream.h index 1009a2a7b0..6f389ceb04 100644 --- a/stream/stream.h +++ b/stream/stream.h @@ -57,12 +57,16 @@ enum streamtype { #define STREAM_READ 0 #define STREAM_WRITE 1 +// flags for stream_open_ext (this includes STREAM_READ and STREAM_WRITE) +#define STREAM_NO_FILTERS 2 + // stream->flags #define MP_STREAM_FAST_SKIPPING 1 // allow forward seeks by skipping #define MP_STREAM_SEEK_BW 2 #define MP_STREAM_SEEK_FW 4 #define MP_STREAM_SEEK (MP_STREAM_SEEK_BW | MP_STREAM_SEEK_FW) +#define STREAM_NO_MATCH -2 #define STREAM_UNSUPPORTED -1 #define STREAM_ERROR 0 #define STREAM_OK 1 @@ -116,6 +120,7 @@ typedef struct stream_info_st { const void *priv_defaults; const struct m_option *options; const char **url_options; + bool stream_filter; } stream_info_t; typedef struct stream { @@ -156,7 +161,8 @@ typedef struct stream { FILE *capture_file; char *capture_filename; - struct stream *uncached_stream; + struct stream *uncached_stream; // underlying stream for cache wrapper + struct stream *source; // Includes additional padding in case sizes get rounded up by sector size. unsigned char buffer[]; @@ -234,6 +240,7 @@ struct bstr stream_read_complete(struct stream *s, void *talloc_ctx, int stream_control(stream_t *s, int cmd, void *arg); void stream_update_size(stream_t *s); void free_stream(stream_t *s); +struct stream *stream_create(const char *url, int flags, struct MPOpts *options); struct stream *stream_open(const char *filename, struct MPOpts *options); stream_t *open_output_stream(const char *filename, struct MPOpts *options); stream_t *open_memory_stream(void *data, int len); |