From 7ca4a453e03d76621c7740b71ba17157c7756737 Mon Sep 17 00:00:00 2001 From: Aman Gupta Date: Sun, 7 Aug 2016 18:10:05 +0200 Subject: client API: add stream_cb API for user-defined stream implementations Based on #2630. Some heavy changes by committer. Signed-off-by: wm4 --- stream/stream.c | 19 ++++++++++ stream/stream.h | 1 + stream/stream_cb.c | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 128 insertions(+) create mode 100644 stream/stream_cb.c (limited to 'stream') diff --git a/stream/stream.c b/stream/stream.c index 846765f326..4b55b1134a 100644 --- a/stream/stream.c +++ b/stream/stream.c @@ -75,6 +75,7 @@ extern const stream_info_t stream_info_bdnav; extern const stream_info_t stream_info_rar; extern const stream_info_t stream_info_edl; extern const stream_info_t stream_info_libarchive; +extern const stream_info_t stream_info_cb; static const stream_info_t *const stream_list[] = { #if HAVE_CDDA @@ -115,6 +116,7 @@ static const stream_info_t *const stream_list[] = { &stream_info_edl, &stream_info_rar, &stream_info_file, + &stream_info_cb, NULL }; @@ -243,6 +245,9 @@ static stream_t *new_stream(void) static const char *match_proto(const char *url, const char *proto) { + if (strcmp(proto, "*") == 0) + return url; + int l = strlen(proto); if (l > 0) { if (strncasecmp(url, proto, l) == 0 && strncmp("://", url + l, 3) == 0) @@ -1111,3 +1116,17 @@ void stream_print_proto_list(struct mp_log *log) talloc_free(list); mp_info(log, "\nTotal: %d protocols\n", count); } + +bool stream_has_proto(const char *proto) +{ + for (int i = 0; stream_list[i]; i++) { + const stream_info_t *stream_info = stream_list[i]; + + for (int j = 0; stream_info->protocols && stream_info->protocols[j]; j++) { + if (strcmp(stream_info->protocols[j], proto) == 0) + return true; + } + } + + return false; +} diff --git a/stream/stream.h b/stream/stream.h index 21e497e563..1112e09f50 100644 --- a/stream/stream.h +++ b/stream/stream.h @@ -299,5 +299,6 @@ void mp_setup_av_network_options(struct AVDictionary **dict, void stream_print_proto_list(struct mp_log *log); char **stream_get_proto_list(void); +bool stream_has_proto(const char *proto); #endif /* MPLAYER_STREAM_H */ diff --git a/stream/stream_cb.c b/stream/stream_cb.c new file mode 100644 index 0000000000..4496e63255 --- /dev/null +++ b/stream/stream_cb.c @@ -0,0 +1,108 @@ +#include "config.h" + +#include +#include +#include +#include +#include +#include + +#include "osdep/io.h" + +#include "common/common.h" +#include "common/msg.h" +#include "common/global.h" +#include "stream.h" +#include "options/m_option.h" +#include "options/path.h" +#include "player/client.h" +#include "libmpv/stream_cb.h" + +struct priv { + mpv_stream_cb_info info; +}; + +static int fill_buffer(stream_t *s, char *buffer, int max_len) +{ + struct priv *p = s->priv; + return (int)p->info.read_fn(p->info.cookie, buffer, (size_t)max_len); +} + +static int seek(stream_t *s, int64_t newpos) +{ + struct priv *p = s->priv; + return (int)p->info.seek_fn(p->info.cookie, newpos) >= 0; +} + +static int control(stream_t *s, int cmd, void *arg) +{ + struct priv *p = s->priv; + switch (cmd) { + case STREAM_CTRL_GET_SIZE: { + if (!p->info.size_fn) + break; + int64_t size = p->info.size_fn(p->info.cookie); + if (size >= 0) { + *(int64_t *)arg = size; + return 1; + } + break; + } + } + return STREAM_UNSUPPORTED; +} + +static void s_close(stream_t *s) +{ + struct priv *p = s->priv; + p->info.close_fn(p->info.cookie); +} + +static int open_cb(stream_t *stream) +{ + struct priv *p = talloc_ptrtype(stream, p); + stream->priv = p; + + bstr bproto = mp_split_proto(bstr0(stream->url), NULL); + char *proto = bstrto0(stream, bproto); + + void *user_data; + mpv_stream_cb_open_ro_fn open_fn; + + if (!mp_streamcb_lookup(stream->global, proto, &user_data, &open_fn)) + return STREAM_UNSUPPORTED; + + mpv_stream_cb_info info = {0}; + + int r = open_fn(user_data, stream->url, &info); + if (r < 0) { + if (r != MPV_ERROR_LOADING_FAILED) + MP_WARN(stream, "unknown error from user callback\n"); + return STREAM_ERROR; + } + + if (!info.read_fn || !info.close_fn) { + MP_FATAL(stream, "required read_fn or close_fn callbacks not set.\n"); + return STREAM_ERROR; + } + + p->info = info; + + if (p->info.seek_fn && p->info.seek_fn(p->info.cookie, 0) >= 0) { + stream->seek = seek; + stream->seekable = true; + } + stream->fast_skip = true; + stream->fill_buffer = fill_buffer; + stream->control = control; + stream->read_chunk = 64 * 1024; + stream->close = s_close; + + return STREAM_OK; +} + +const stream_info_t stream_info_cb = { + .name = "stream_callback", + .open = open_cb, + .protocols = (const char*const[]){ "*", NULL }, +}; -- cgit v1.2.3