2016-08-07 16:10:05 +00:00
|
|
|
/* Permission to use, copy, modify, and/or distribute this software for any
|
|
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
|
|
* copyright notice and this permission notice appear in all copies.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Note: the client API is licensed under ISC (see above) to ease
|
|
|
|
* interoperability with other licenses. But keep in mind that the
|
|
|
|
* mpv core is still mostly GPLv2+. It's up to lawyers to decide
|
|
|
|
* whether applications using this API are affected by the GPL.
|
|
|
|
* One argument against this is that proprietary applications
|
|
|
|
* using mplayer in slave mode is apparently tolerated, and this
|
|
|
|
* API is basically equivalent to slave mode.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef MPV_CLIENT_API_STREAM_CB_H_
|
|
|
|
#define MPV_CLIENT_API_STREAM_CB_H_
|
|
|
|
|
|
|
|
#include "client.h"
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
extern "C" {
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Warning: this API is not stable yet.
|
|
|
|
*
|
|
|
|
* Overview
|
|
|
|
* --------
|
|
|
|
*
|
|
|
|
* This API can be used to make mpv read from a stream with a custom
|
|
|
|
* implementation. This interface is inspired by funopen on BSD and
|
|
|
|
* fopencookie on linux. The stream is backed by user-defined callbacks
|
|
|
|
* which can implement customized open, read, seek, size and close behaviors.
|
|
|
|
*
|
|
|
|
* Usage
|
|
|
|
* -----
|
|
|
|
*
|
|
|
|
* Register your stream callbacks with the mpv_stream_cb_add_ro() function. You
|
|
|
|
* have to provide a mpv_stream_cb_open_ro_fn callback to it (open_fn argument).
|
|
|
|
*
|
|
|
|
* Once registered, you can `loadfile myprotocol://myfile`. Your open_fn will be
|
|
|
|
* invoked with the URI and you must fill out the provided mpv_stream_cb_info
|
|
|
|
* struct. This includes your stream callbacks (like read_fn), and an opaque
|
|
|
|
* cookie, which will be passed as the first argument to all the remaining
|
|
|
|
* stream callbacks.
|
|
|
|
*
|
|
|
|
* Note that your custom callbacks must not invoke libmpv APIs as that would
|
2017-03-17 03:54:39 +00:00
|
|
|
* cause a deadlock. (Unless you call a different mpv_handle than the one the
|
|
|
|
* callback was registered for, and the mpv_handles refer to different mpv
|
|
|
|
* instances.)
|
2016-08-07 16:10:05 +00:00
|
|
|
*
|
|
|
|
* Stream lifetime
|
|
|
|
* ---------------
|
|
|
|
*
|
|
|
|
* A stream remains valid until its close callback has been called. It's up to
|
|
|
|
* libmpv to call the close callback, and the libmpv user cannot close it
|
|
|
|
* directly with the stream_cb API.
|
|
|
|
*
|
|
|
|
* For example, if you consider your custom stream to become suddenly invalid
|
|
|
|
* (maybe because the underlying stream died), libmpv will continue using your
|
|
|
|
* stream. All you can do is returning errors from each callback, until libmpv
|
|
|
|
* gives up and closes it.
|
|
|
|
*
|
|
|
|
* Protocol registration and lifetime
|
|
|
|
* ----------------------------------
|
|
|
|
*
|
|
|
|
* Protocols remain registered until the mpv instance is terminated. This means
|
|
|
|
* in particular that it can outlive the mpv_handle that was used to register
|
|
|
|
* it, but once mpv_terminate_destroy() is called, your registered callbacks
|
|
|
|
* will not be called again.
|
|
|
|
*
|
|
|
|
* Protocol unregistration is finished after the mpv core has been destroyed
|
|
|
|
* (e.g. after mpv_terminate_destroy() has returned).
|
|
|
|
*
|
|
|
|
* If you do not call mpv_terminate_destroy() yourself (e.g. plugin-style code),
|
|
|
|
* you will have to deal with the registration or even streams outliving your
|
|
|
|
* code. Here are some possible ways to do this:
|
|
|
|
* - call mpv_terminate_destroy(), which destroys the core, and will make sure
|
|
|
|
* all streams are closed once this function returns
|
|
|
|
* - you refcount all resources your stream "cookies" reference, so that it
|
|
|
|
* doesn't matter if streams live longer than expected
|
|
|
|
* - create "cancellation" semantics: after your protocol has been unregistered,
|
|
|
|
* notify all your streams that are still opened, and make them drop all
|
|
|
|
* referenced resources - then return errors from the stream callbacks as
|
|
|
|
* long as the stream is still opened
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Read callback used to implement a custom stream. The semantics of the
|
|
|
|
* callback match read(2) in blocking mode. Short reads are allowed (you can
|
|
|
|
* return less bytes than requested, and libmpv will retry reading the rest
|
|
|
|
* with a nother call). If no data can be immediately read, the callback must
|
|
|
|
* block until there is new data. A return of 0 will be interpreted as final
|
|
|
|
* EOF, although libmpv might retry the read, or seek to a different position.
|
|
|
|
*
|
|
|
|
* @param cookie opaque cookie identifying the stream,
|
|
|
|
* returned from mpv_stream_cb_open_fn
|
|
|
|
* @param buf buffer to read data into
|
|
|
|
* @param size of the buffer
|
|
|
|
* @return number of bytes read into the buffer
|
|
|
|
* @return 0 on EOF
|
|
|
|
* @return -1 on error
|
|
|
|
*/
|
|
|
|
typedef int64_t (*mpv_stream_cb_read_fn)(void *cookie, char *buf, uint64_t nbytes);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Seek callback used to implement a custom stream.
|
|
|
|
*
|
|
|
|
* Note that mpv will issue a seek to position 0 immediately after opening. This
|
|
|
|
* is used to test whether the stream is seekable (since seekability might
|
|
|
|
* depend on the URI contents, not just the protocol). Return
|
|
|
|
* MPV_ERROR_UNSUPPORTED if seeking is not implemented for this stream. This
|
|
|
|
* seek also servies to establish the fact that streams start at position 0.
|
|
|
|
*
|
|
|
|
* This callback can be NULL, in which it behaves as if always returning
|
|
|
|
* MPV_ERROR_UNSUPPORTED.
|
|
|
|
*
|
|
|
|
* @param cookie opaque cookie identifying the stream,
|
|
|
|
* returned from mpv_stream_cb_open_fn
|
|
|
|
* @param offset target absolut stream position
|
|
|
|
* @return the resulting offset of the stream
|
|
|
|
* MPV_ERROR_UNSUPPORTED or MPV_ERROR_GENERIC if the seek failed
|
|
|
|
*/
|
|
|
|
typedef int64_t (*mpv_stream_cb_seek_fn)(void *cookie, int64_t offset);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Size callback used to implement a custom stream.
|
|
|
|
*
|
|
|
|
* Return MPV_ERROR_UNSUPPORTED if no size is known.
|
|
|
|
*
|
|
|
|
* This callback can be NULL, in which it behaves as if always returning
|
|
|
|
* MPV_ERROR_UNSUPPORTED.
|
|
|
|
*
|
|
|
|
* @param cookie opaque cookie identifying the stream,
|
|
|
|
* returned from mpv_stream_cb_open_fn
|
|
|
|
* @return the total size in bytes of the stream
|
|
|
|
*/
|
|
|
|
typedef int64_t (*mpv_stream_cb_size_fn)(void *cookie);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Close callback used to implement a custom stream.
|
|
|
|
*
|
|
|
|
* @param cookie opaque cookie identifying the stream,
|
|
|
|
* returned from mpv_stream_cb_open_fn
|
|
|
|
*/
|
|
|
|
typedef void (*mpv_stream_cb_close_fn)(void *cookie);
|
|
|
|
|
|
|
|
/**
|
2016-08-08 08:34:12 +00:00
|
|
|
* See mpv_stream_cb_open_ro_fn callback.
|
2016-08-07 16:10:05 +00:00
|
|
|
*/
|
|
|
|
typedef struct mpv_stream_cb_info {
|
|
|
|
/**
|
|
|
|
* Opaque user-provided value, which will be passed to the other callbacks.
|
|
|
|
* The close callback will be called to release the cookie. It is not
|
|
|
|
* interpreted by mpv. It doesn't even need to be a valid pointer.
|
|
|
|
*
|
|
|
|
* The user sets this in the mpv_stream_cb_open_ro_fn callback.
|
|
|
|
*/
|
|
|
|
void *cookie;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Callbacks set by the user in the mpv_stream_cb_open_ro_fn callback. Some
|
|
|
|
* of them are optional, and can be left unset.
|
|
|
|
*
|
|
|
|
* The following callbacks are mandatory: read_fn, close_fn
|
|
|
|
*/
|
|
|
|
mpv_stream_cb_read_fn read_fn;
|
|
|
|
mpv_stream_cb_seek_fn seek_fn;
|
|
|
|
mpv_stream_cb_size_fn size_fn;
|
|
|
|
mpv_stream_cb_close_fn close_fn;
|
|
|
|
} mpv_stream_cb_info;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Open callback used to implement a custom read-only (ro) stream. The user
|
|
|
|
* must set the callback fields in the passed info struct. The cookie field
|
|
|
|
* also can be set to store state associated to the stream instance.
|
|
|
|
*
|
|
|
|
* Note that the info struct is valid only for the duration of this callback.
|
|
|
|
* You can't change the callbacks or the pointer to the cookie at a later point.
|
|
|
|
*
|
|
|
|
* Each stream instance created by the open callback can have different
|
|
|
|
* callbacks.
|
|
|
|
*
|
|
|
|
* The close_fn callback will terminate the stream instance. The pointers to
|
|
|
|
* your callbacks and cookie will be discarded, and the callbacks will not be
|
|
|
|
* called again.
|
|
|
|
*
|
|
|
|
* @param user_data opaque user data provided via mpv_stream_cb_add()
|
|
|
|
* @param uri name of the stream to be opened (with protocol prefix)
|
|
|
|
* @param info fields which the user should fill
|
|
|
|
* @return 0 on success, MPV_ERROR_LOADING_FAILED if the URI cannot be opened.
|
|
|
|
*/
|
|
|
|
typedef int (*mpv_stream_cb_open_ro_fn)(void *user_data, char *uri,
|
|
|
|
mpv_stream_cb_info *info);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add a custom stream protocol. This will register a protocol handler under
|
|
|
|
* the given protocol prefix, and invoke the given callbacks if an URI with the
|
|
|
|
* matching protocol prefix is opened.
|
|
|
|
*
|
|
|
|
* The "ro" is for read-only - only read-only streams can be registered with
|
|
|
|
* this function.
|
|
|
|
*
|
|
|
|
* The callback remains registered until the mpv core is registered.
|
|
|
|
*
|
|
|
|
* If a custom stream with the same name is already registered, then the
|
|
|
|
* MPV_ERROR_INVALID_PARAMETER error is returned.
|
|
|
|
*
|
|
|
|
* @param protocol protocol prefix, for example "foo" for "foo://" URIs
|
|
|
|
* @param user_data opaque pointer passed into the mpv_stream_cb_open_fn
|
|
|
|
* callback.
|
|
|
|
* @return error code
|
|
|
|
*/
|
|
|
|
int mpv_stream_cb_add_ro(mpv_handle *ctx, const char *protocol, void *user_data,
|
|
|
|
mpv_stream_cb_open_ro_fn open_fn);
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#endif
|