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