1 /* Copyright (C) 2017 the mpv developers
2  * Copyright (C) 2020 fence
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 module mpv.stream_cb;
18 
19 import mpv.client;
20 import core.stdc.config;
21 
22 extern (C):
23 
24 /**
25  * Warning: this API is not stable yet.
26  *
27  * Overview
28  * --------
29  *
30  * This API can be used to make mpv read from a stream with a custom
31  * implementation. This interface is inspired by funopen on BSD and
32  * fopencookie on linux. The stream is backed by user-defined callbacks
33  * which can implement customized open, read, seek, size and close behaviors.
34  *
35  * Usage
36  * -----
37  *
38  * Register your stream callbacks with the mpv_stream_cb_add_ro() function. You
39  * have to provide a mpv_stream_cb_open_ro_fn callback to it (open_fn argument).
40  *
41  * Once registered, you can `loadfile myprotocol://myfile`. Your open_fn will be
42  * invoked with the URI and you must fill out the provided mpv_stream_cb_info
43  * struct. This includes your stream callbacks (like read_fn), and an opaque
44  * cookie, which will be passed as the first argument to all the remaining
45  * stream callbacks.
46  *
47  * Note that your custom callbacks must not invoke libmpv APIs as that would
48  * cause a deadlock. (Unless you call a different mpv_handle than the one the
49  * callback was registered for, and the mpv_handles refer to different mpv
50  * instances.)
51  *
52  * Stream lifetime
53  * ---------------
54  *
55  * A stream remains valid until its close callback has been called. It's up to
56  * libmpv to call the close callback, and the libmpv user cannot close it
57  * directly with the stream_cb API.
58  *
59  * For example, if you consider your custom stream to become suddenly invalid
60  * (maybe because the underlying stream died), libmpv will continue using your
61  * stream. All you can do is returning errors from each callback, until libmpv
62  * gives up and closes it.
63  *
64  * Protocol registration and lifetime
65  * ----------------------------------
66  *
67  * Protocols remain registered until the mpv instance is terminated. This means
68  * in particular that it can outlive the mpv_handle that was used to register
69  * it, but once mpv_terminate_destroy() is called, your registered callbacks
70  * will not be called again.
71  *
72  * Protocol unregistration is finished after the mpv core has been destroyed
73  * (e.g. after mpv_terminate_destroy() has returned).
74  *
75  * If you do not call mpv_terminate_destroy() yourself (e.g. plugin-style code),
76  * you will have to deal with the registration or even streams outliving your
77  * code. Here are some possible ways to do this:
78  * - call mpv_terminate_destroy(), which destroys the core, and will make sure
79  *   all streams are closed once this function returns
80  * - you refcount all resources your stream "cookies" reference, so that it
81  *   doesn't matter if streams live longer than expected
82  * - create "cancellation" semantics: after your protocol has been unregistered,
83  *   notify all your streams that are still opened, and make them drop all
84  *   referenced resources - then return errors from the stream callbacks as
85  *   long as the stream is still opened
86  *
87  */
88 
89 /**
90  * Read callback used to implement a custom stream. The semantics of the
91  * callback match read(2) in blocking mode. Short reads are allowed (you can
92  * return less bytes than requested, and libmpv will retry reading the rest
93  * with another call). If no data can be immediately read, the callback must
94  * block until there is new data. A return of 0 will be interpreted as final
95  * EOF, although libmpv might retry the read, or seek to a different position.
96  *
97  * @param cookie opaque cookie identifying the stream,
98  *               returned from mpv_stream_cb_open_fn
99  * @param buf buffer to read data into
100  * @param size of the buffer
101  * @return number of bytes read into the buffer
102  * @return 0 on EOF
103  * @return -1 on error
104  */
105 alias mpv_stream_cb_read_fn = c_long function (void* cookie, char* buf, ulong nbytes);
106 
107 /**
108  * Seek callback used to implement a custom stream.
109  *
110  * Note that mpv will issue a seek to position 0 immediately after opening. This
111  * is used to test whether the stream is seekable (since seekability might
112  * depend on the URI contents, not just the protocol). Return
113  * MPV_ERROR_UNSUPPORTED if seeking is not implemented for this stream. This
114  * seek also serves to establish the fact that streams start at position 0.
115  *
116  * This callback can be NULL, in which it behaves as if always returning
117  * MPV_ERROR_UNSUPPORTED.
118  *
119  * @param cookie opaque cookie identifying the stream,
120  *               returned from mpv_stream_cb_open_fn
121  * @param offset target absolut stream position
122  * @return the resulting offset of the stream
123  *         MPV_ERROR_UNSUPPORTED or MPV_ERROR_GENERIC if the seek failed
124  */
125 alias mpv_stream_cb_seek_fn = c_long function (void* cookie, long offset);
126 
127 /**
128  * Size callback used to implement a custom stream.
129  *
130  * Return MPV_ERROR_UNSUPPORTED if no size is known.
131  *
132  * This callback can be NULL, in which it behaves as if always returning
133  * MPV_ERROR_UNSUPPORTED.
134  *
135  * @param cookie opaque cookie identifying the stream,
136  *               returned from mpv_stream_cb_open_fn
137  * @return the total size in bytes of the stream
138  */
139 alias mpv_stream_cb_size_fn = c_long function (void* cookie);
140 
141 /**
142  * Close callback used to implement a custom stream.
143  *
144  * @param cookie opaque cookie identifying the stream,
145  *               returned from mpv_stream_cb_open_fn
146  */
147 alias mpv_stream_cb_close_fn = void function (void* cookie);
148 
149 /**
150  * Cancel callback used to implement a custom stream.
151  *
152  * This callback is used to interrupt any current or future read and seek
153  * operations. It will be called from a separate thread than the demux
154  * thread, and should not block.
155  *
156  * This callback can be NULL.
157  *
158  * Available since API 1.106.
159  *
160  * @param cookie opaque cookie identifying the stream,
161  *               returned from mpv_stream_cb_open_fn
162  */
163 alias mpv_stream_cb_cancel_fn = void function (void* cookie);
164 
165 /**
166  * See mpv_stream_cb_open_ro_fn callback.
167  */
168 struct mpv_stream_cb_info
169 {
170     /**
171      * Opaque user-provided value, which will be passed to the other callbacks.
172      * The close callback will be called to release the cookie. It is not
173      * interpreted by mpv. It doesn't even need to be a valid pointer.
174      *
175      * The user sets this in the mpv_stream_cb_open_ro_fn callback.
176      */
177     void* cookie;
178 
179     /**
180      * Callbacks set by the user in the mpv_stream_cb_open_ro_fn callback. Some
181      * of them are optional, and can be left unset.
182      *
183      * The following callbacks are mandatory: read_fn, close_fn
184      */
185     mpv_stream_cb_read_fn read_fn;
186     mpv_stream_cb_seek_fn seek_fn;
187     mpv_stream_cb_size_fn size_fn;
188     mpv_stream_cb_close_fn close_fn;
189     mpv_stream_cb_cancel_fn cancel_fn; /* since API 1.106 */
190 }
191 
192 /**
193  * Open callback used to implement a custom read-only (ro) stream. The user
194  * must set the callback fields in the passed info struct. The cookie field
195  * also can be set to store state associated to the stream instance.
196  *
197  * Note that the info struct is valid only for the duration of this callback.
198  * You can't change the callbacks or the pointer to the cookie at a later point.
199  *
200  * Each stream instance created by the open callback can have different
201  * callbacks.
202  *
203  * The close_fn callback will terminate the stream instance. The pointers to
204  * your callbacks and cookie will be discarded, and the callbacks will not be
205  * called again.
206  *
207  * @param user_data opaque user data provided via mpv_stream_cb_add()
208  * @param uri name of the stream to be opened (with protocol prefix)
209  * @param info fields which the user should fill
210  * @return 0 on success, MPV_ERROR_LOADING_FAILED if the URI cannot be opened.
211  */
212 alias mpv_stream_cb_open_ro_fn = int function (
213     void* user_data,
214     char* uri,
215     mpv_stream_cb_info* info);
216 
217 /**
218  * Add a custom stream protocol. This will register a protocol handler under
219  * the given protocol prefix, and invoke the given callbacks if an URI with the
220  * matching protocol prefix is opened.
221  *
222  * The "ro" is for read-only - only read-only streams can be registered with
223  * this function.
224  *
225  * The callback remains registered until the mpv core is registered.
226  *
227  * If a custom stream with the same name is already registered, then the
228  * MPV_ERROR_INVALID_PARAMETER error is returned.
229  *
230  * @param protocol protocol prefix, for example "foo" for "foo://" URIs
231  * @param user_data opaque pointer passed into the mpv_stream_cb_open_fn
232  *                  callback.
233  * @return error code
234  */
235 int mpv_stream_cb_add_ro (
236     mpv_handle* ctx,
237     const(char)* protocol,
238     void* user_data,
239     mpv_stream_cb_open_ro_fn open_fn);
240