contrib: cargo: use cargo/vendored-openssl if needed
[vlc.git] / modules / access / imem.c
blob7710d9112588f6692949a9416d8c680da6627c37
1 /*****************************************************************************
2 * imem.c : Memory input for VLC
3 *****************************************************************************
4 * Copyright (C) 2009-2010 Laurent Aimar
6 * Author: Laurent Aimar <fenrir _AT_ videolan _DOT org>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
23 /*****************************************************************************
24 * Preamble
25 *****************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30 #include <limits.h>
31 #include <math.h>
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
35 #include <vlc_access.h>
36 #include <vlc_demux.h>
37 #include <vlc_charset.h>
39 /*****************************************************************************
40 * Module descriptior
41 *****************************************************************************/
42 static int OpenAccess (vlc_object_t *);
43 static void CloseAccess(vlc_object_t *);
45 static int OpenDemux (vlc_object_t *);
46 static void CloseDemux(vlc_object_t *);
48 #define ID_TEXT N_("ID")
49 #define ID_LONGTEXT N_(\
50 "Set the ID of the elementary stream")
52 #define GROUP_TEXT N_("Group")
53 #define GROUP_LONGTEXT N_(\
54 "Set the group of the elementary stream")
56 #define CAT_TEXT N_("Category")
57 #define CAT_LONGTEXT N_(\
58 "Set the category of the elementary stream")
59 static const int cat_values[] = {
60 0, 1, 2, 3, 4,
62 static const char *cat_texts[] = {
63 N_("Unknown"), N_("Audio"), N_("Video"), N_("Subtitle"), N_("Data")
66 #define CODEC_TEXT N_("Codec")
67 #define CODEC_LONGTEXT N_(\
68 "Set the codec of the elementary stream")
70 #define LANGUAGE_TEXT N_("Language")
71 #define LANGUAGE_LONGTEXT N_(\
72 "Language of the elementary stream as described by ISO639")
74 #define SAMPLERATE_TEXT N_("Sample rate")
75 #define SAMPLERATE_LONGTEXT N_(\
76 "Sample rate of an audio elementary stream")
78 #define CHANNELS_TEXT N_("Channels count")
79 #define CHANNELS_LONGTEXT N_(\
80 "Channels count of an audio elementary stream")
82 #define WIDTH_TEXT N_("Width")
83 #define WIDTH_LONGTEXT N_("Width of video or subtitle elementary streams")
85 #define HEIGHT_TEXT N_("Height")
86 #define HEIGHT_LONGTEXT N_("Height of video or subtitle elementary streams")
88 #define DAR_TEXT N_("Display aspect ratio")
89 #define DAR_LONGTEXT N_(\
90 "Display aspect ratio of a video elementary stream")
92 #define FPS_TEXT N_("Frame rate")
93 #define FPS_LONGTEXT N_(\
94 "Frame rate of a video elementary stream")
96 #define COOKIE_TEXT N_("Callback cookie string")
97 #define COOKIE_LONGTEXT N_(\
98 "Text identifier for the callback functions")
100 #define DATA_TEXT N_("Callback data")
101 #define DATA_LONGTEXT N_(\
102 "Data for the get and release functions")
104 #define GET_TEXT N_("Get function")
105 #define GET_LONGTEXT N_(\
106 "Address of the get callback function")
108 #define RELEASE_TEXT N_("Release function")
109 #define RELEASE_LONGTEXT N_(\
110 "Address of the release callback function")
112 #define SIZE_TEXT N_("Size")
113 #define SIZE_LONGTEXT N_(\
114 "Size of stream in bytes")
116 vlc_module_begin()
117 set_shortname(N_("Memory input"))
118 set_description(N_("Memory input"))
119 set_category(CAT_INPUT)
120 set_subcategory(SUBCAT_INPUT_ACCESS)
122 add_string ("imem-get", "0", GET_TEXT, GET_LONGTEXT, true)
123 change_volatile()
124 add_string ("imem-release", "0", RELEASE_TEXT, RELEASE_LONGTEXT, true)
125 change_volatile()
126 add_string ("imem-cookie", NULL, COOKIE_TEXT, COOKIE_LONGTEXT, true)
127 change_volatile()
128 change_safe()
129 add_string ("imem-data", "0", DATA_TEXT, DATA_LONGTEXT, true)
130 change_volatile()
132 add_integer("imem-id", -1, ID_TEXT, ID_LONGTEXT, true)
133 change_private()
134 change_safe()
135 add_integer("imem-group", 0, GROUP_TEXT, GROUP_LONGTEXT, true)
136 change_private()
137 change_safe()
138 add_integer("imem-cat", 0, CAT_TEXT, CAT_LONGTEXT, true)
139 change_integer_list(cat_values, cat_texts)
140 change_private()
141 change_safe()
142 add_string ("imem-codec", NULL, CODEC_TEXT, CODEC_LONGTEXT, true)
143 change_private()
144 change_safe()
145 add_string( "imem-language", NULL, LANGUAGE_TEXT, LANGUAGE_LONGTEXT, false)
146 change_private()
147 change_safe()
149 add_integer("imem-samplerate", 0, SAMPLERATE_TEXT, SAMPLERATE_LONGTEXT, true)
150 change_private()
151 change_safe()
152 add_integer("imem-channels", 0, CHANNELS_TEXT, CHANNELS_LONGTEXT, true)
153 change_private()
154 change_safe()
156 add_integer("imem-width", 0, WIDTH_TEXT, WIDTH_LONGTEXT, true)
157 change_private()
158 change_safe()
159 add_integer("imem-height", 0, HEIGHT_TEXT, HEIGHT_LONGTEXT, true)
160 change_private()
161 change_safe()
162 add_string ("imem-dar", NULL, DAR_TEXT, DAR_LONGTEXT, true)
163 change_private()
164 change_safe()
165 add_string ("imem-fps", NULL, FPS_TEXT, FPS_LONGTEXT, true)
166 change_private()
167 change_safe()
169 add_integer ("imem-size", 0, SIZE_TEXT, SIZE_LONGTEXT, true)
170 change_private()
171 change_safe()
173 add_shortcut("imem")
174 set_capability("access", 1)
175 set_callbacks(OpenDemux, CloseDemux)
177 add_submodule()
178 add_shortcut("imem")
179 set_capability("access", 0)
180 set_callbacks(OpenAccess, CloseAccess)
181 vlc_module_end()
183 /*****************************************************************************
184 * Exported API
185 *****************************************************************************/
187 /* The clock origin for the DTS and PTS is assumed to be 0.
188 * A negative value means unknown.
190 * TODO define flags
192 typedef int (*imem_get_t)(void *data, const char *cookie,
193 int64_t *dts, int64_t *pts, unsigned *flags,
194 size_t *, void **);
195 typedef void (*imem_release_t)(void *data, const char *cookie, size_t, void *);
197 /*****************************************************************************
198 * Local prototypes
199 *****************************************************************************/
201 /* */
202 static block_t *Block(stream_t *, bool *);
203 static int ControlAccess(stream_t *, int, va_list);
205 static int Demux(demux_t *);
206 static int ControlDemux(demux_t *, int, va_list);
208 /* */
209 typedef struct {
210 struct {
211 imem_get_t get;
212 imem_release_t release;
213 void *data;
214 char *cookie;
215 } source;
217 es_out_id_t *es;
219 vlc_tick_t dts;
221 vlc_tick_t deadline;
222 } imem_sys_t;
224 static void ParseMRL(vlc_object_t *, const char *);
227 * It closes the common part of the access and access_demux
229 static void CloseCommon(imem_sys_t *sys)
231 free(sys->source.cookie);
235 * It initializes the common part for imem access/access_demux.
237 static int OpenCommon(vlc_object_t *object, imem_sys_t **sys_ptr, const char *psz_path)
239 char *tmp;
241 /* */
242 imem_sys_t *sys = vlc_obj_calloc(object, 1, sizeof(*sys));
243 if (!sys)
244 return VLC_ENOMEM;
246 /* Read the user functions */
247 tmp = var_InheritString(object, "imem-get");
248 if (tmp)
249 sys->source.get = (imem_get_t)(intptr_t)strtoll(tmp, NULL, 0);
250 free(tmp);
252 tmp = var_InheritString(object, "imem-release");
253 if (tmp)
254 sys->source.release = (imem_release_t)(intptr_t)strtoll(tmp, NULL, 0);
255 free(tmp);
257 if (!sys->source.get || !sys->source.release) {
258 msg_Err(object, "Invalid get/release function pointers");
259 return VLC_EGENERIC;
262 tmp = var_InheritString(object, "imem-data");
263 if (tmp)
264 sys->source.data = (void *)(uintptr_t)strtoull(tmp, NULL, 0);
265 free(tmp);
267 /* Now we can parse the MRL (get/release must not be parsed to avoid
268 * security risks) */
269 if (*psz_path)
270 ParseMRL(object, psz_path);
272 sys->source.cookie = var_InheritString(object, "imem-cookie");
274 msg_Dbg(object, "Using get(%p), release(%p), data(%p), cookie(%s)",
275 (void *)sys->source.get, (void *)sys->source.release,
276 sys->source.data,
277 sys->source.cookie ? sys->source.cookie : "(null)");
279 /* */
280 sys->dts = 0;
281 sys->deadline = VLC_TICK_INVALID;
283 *sys_ptr = sys;
284 return VLC_SUCCESS;
288 * It opens an imem access.
290 static int OpenAccess(vlc_object_t *object)
292 stream_t *access = (stream_t *)object;
293 imem_sys_t *sys;
295 if (OpenCommon(object, &sys, access->psz_location))
296 return VLC_EGENERIC;
298 if (var_InheritInteger(object, "imem-cat") != 4) {
299 CloseCommon(sys);
300 return VLC_EGENERIC;
303 /* */
304 access->pf_control = ControlAccess;
305 access->pf_read = NULL;
306 access->pf_block = Block;
307 access->pf_seek = NULL;
308 access->p_sys = sys;
310 return VLC_SUCCESS;
314 * It closes an imem access
316 static void CloseAccess(vlc_object_t *object)
318 stream_t *access = (stream_t *)object;
320 CloseCommon((imem_sys_t*)access->p_sys);
324 * It controls an imem access
326 static int ControlAccess(stream_t *access, int i_query, va_list args)
328 (void) access;
329 switch (i_query)
331 case STREAM_CAN_SEEK:
332 case STREAM_CAN_FASTSEEK: {
333 bool *b = va_arg( args, bool* );
334 *b = false;
335 return VLC_SUCCESS;
337 case STREAM_CAN_PAUSE:
338 case STREAM_CAN_CONTROL_PACE: {
339 bool *b = va_arg( args, bool* );
340 *b = true;
341 return VLC_SUCCESS;
343 case STREAM_GET_SIZE: {
344 uint64_t *s = va_arg(args, uint64_t *);
345 *s = var_InheritInteger(access, "imem-size");
346 return *s ? VLC_SUCCESS : VLC_EGENERIC;
348 case STREAM_GET_PTS_DELAY:
349 *va_arg(args, vlc_tick_t *) = DEFAULT_PTS_DELAY; /* FIXME? */
350 return VLC_SUCCESS;
352 case STREAM_SET_PAUSE_STATE:
353 return VLC_SUCCESS;
355 default:
356 return VLC_EGENERIC;
361 * It retreives data using the get() callback, copies them,
362 * and then release them using the release() callback.
364 static block_t *Block(stream_t *access, bool *restrict eof)
366 imem_sys_t *sys = (imem_sys_t*)access->p_sys;
368 unsigned flags;
369 size_t buffer_size;
370 void *buffer;
372 if (sys->source.get(sys->source.data, sys->source.cookie,
373 NULL, NULL, &flags, &buffer_size, &buffer)) {
374 *eof = true;
375 return NULL;
378 block_t *block = NULL;
379 if (buffer_size > 0) {
380 block = block_Alloc(buffer_size);
381 if (block)
382 memcpy(block->p_buffer, buffer, buffer_size);
385 sys->source.release(sys->source.data, sys->source.cookie,
386 buffer_size, buffer);
387 return block;
390 static inline int GetCategory(vlc_object_t *object)
392 const int cat = var_InheritInteger(object, "imem-cat");
393 switch (cat)
395 case 1:
396 return AUDIO_ES;
397 case 2:
398 return VIDEO_ES;
399 case 3:
400 return SPU_ES;
401 default:
402 msg_Err(object, "Invalid ES category");
403 /* fall through */
404 case 4:
405 return UNKNOWN_ES;
410 * It opens an imem access_demux.
412 static int OpenDemux(vlc_object_t *object)
414 demux_t *demux = (demux_t *)object;
415 imem_sys_t *sys;
417 if (demux->out == NULL)
418 return VLC_EGENERIC;
420 if (OpenCommon(object, &sys, demux->psz_location))
421 return VLC_EGENERIC;
423 /* ES format */
424 es_format_t fmt;
425 es_format_Init(&fmt, GetCategory(object), 0);
427 fmt.i_id = var_InheritInteger(object, "imem-id");
428 fmt.i_group = var_InheritInteger(object, "imem-group");
430 char *tmp = var_InheritString(object, "imem-codec");
431 if (tmp)
432 fmt.i_codec = vlc_fourcc_GetCodecFromString(fmt.i_cat, tmp);
433 free(tmp);
435 switch (fmt.i_cat) {
436 case AUDIO_ES: {
437 fmt.audio.i_channels = var_InheritInteger(object, "imem-channels");
438 fmt.audio.i_rate = var_InheritInteger(object, "imem-samplerate");
440 msg_Dbg(object, "Audio %4.4s %d channels %d Hz",
441 (const char *)&fmt.i_codec,
442 fmt.audio.i_channels, fmt.audio.i_rate);
443 break;
445 case VIDEO_ES: {
446 fmt.video.i_width = var_InheritInteger(object, "imem-width");
447 fmt.video.i_height = var_InheritInteger(object, "imem-height");
448 unsigned num, den;
449 if (!var_InheritURational(object, &num, &den, "imem-dar") && num > 0 && den > 0) {
450 if (fmt.video.i_width != 0 && fmt.video.i_height != 0) {
451 fmt.video.i_sar_num = num * fmt.video.i_height;
452 fmt.video.i_sar_den = den * fmt.video.i_width;
455 if (!var_InheritURational(object, &num, &den, "imem-fps") && num > 0 && den > 0) {
456 fmt.video.i_frame_rate = num;
457 fmt.video.i_frame_rate_base = den;
460 msg_Dbg(object, "Video %4.4s %dx%d SAR %d:%d frame rate %u/%u",
461 (const char *)&fmt.i_codec,
462 fmt.video.i_width, fmt.video.i_height,
463 fmt.video.i_sar_num, fmt.video.i_sar_den,
464 fmt.video.i_frame_rate, fmt.video.i_frame_rate_base);
465 break;
467 case SPU_ES: {
468 fmt.subs.spu.i_original_frame_width =
469 var_InheritInteger(object, "imem-width");
470 fmt.subs.spu.i_original_frame_height =
471 var_InheritInteger(object, "imem-height");
473 msg_Dbg(object, "Subtitle %4.4s",
474 (const char *)&fmt.i_codec);
475 break;
477 default:
478 es_format_Clean(&fmt);
479 CloseCommon(sys);
480 return VLC_EGENERIC;
483 fmt.psz_language = var_InheritString(object, "imem-language");
485 sys->es = es_out_Add(demux->out, &fmt);
486 es_format_Clean(&fmt);
488 if (!sys->es) {
489 CloseCommon(sys);
490 return VLC_EGENERIC;
493 /* */
494 demux->pf_control = ControlDemux;
495 demux->pf_demux = Demux;
496 demux->p_sys = sys;
498 return VLC_SUCCESS;
502 * It closes an imem access_demux
504 static void CloseDemux(vlc_object_t *object)
506 demux_t *demux = (demux_t *)object;
508 CloseCommon((imem_sys_t*)demux->p_sys);
512 * It controls an imem access_demux
514 static int ControlDemux(demux_t *demux, int i_query, va_list args)
516 imem_sys_t *sys = (imem_sys_t*)demux->p_sys;
518 switch (i_query)
520 case DEMUX_CAN_PAUSE:
521 case DEMUX_CAN_CONTROL_PACE: {
522 bool *b = va_arg(args, bool *);
523 *b = true;
524 return VLC_SUCCESS;
526 case DEMUX_SET_PAUSE_STATE:
527 return VLC_SUCCESS;
529 case DEMUX_GET_PTS_DELAY: {
530 *va_arg(args, vlc_tick_t *) = DEFAULT_PTS_DELAY; /* FIXME? */
531 return VLC_SUCCESS;
533 case DEMUX_GET_POSITION: {
534 double *position = va_arg(args, double *);
535 *position = 0.0;
536 return VLC_SUCCESS;
538 case DEMUX_GET_TIME: {
539 *va_arg(args, vlc_tick_t *) = sys->dts;
540 return VLC_SUCCESS;
542 case DEMUX_GET_LENGTH: {
543 *va_arg(args, vlc_tick_t *) = 0;
544 return VLC_SUCCESS;
546 case DEMUX_SET_NEXT_DEMUX_TIME:
547 sys->deadline = va_arg(args, vlc_tick_t);
548 return VLC_SUCCESS;
550 /* */
551 case DEMUX_CAN_SEEK:
552 case DEMUX_SET_POSITION:
553 case DEMUX_SET_TIME:
554 default:
555 return VLC_EGENERIC;
558 return VLC_EGENERIC;
562 * It retreives data using the get() callback, sends them to es_out
563 * and the release it using the release() callback.
565 static int Demux(demux_t *demux)
567 imem_sys_t *sys = (imem_sys_t*)demux->p_sys;
569 if (sys->deadline == VLC_TICK_INVALID)
570 sys->deadline = sys->dts + 1;
572 for (;;) {
573 if (sys->deadline <= sys->dts)
574 break;
576 /* */
577 int64_t dts, pts;
578 unsigned flags;
579 size_t buffer_size;
580 void *buffer;
582 if (sys->source.get(sys->source.data, sys->source.cookie,
583 &dts, &pts, &flags, &buffer_size, &buffer))
584 return 0;
586 if (dts < 0)
587 dts = pts;
589 if (buffer_size > 0) {
590 block_t *block = block_Alloc(buffer_size);
591 if (block) {
592 block->i_dts = dts >= 0 ? (1 + dts) : VLC_TICK_INVALID;
593 block->i_pts = pts >= 0 ? (1 + pts) : VLC_TICK_INVALID;
594 memcpy(block->p_buffer, buffer, buffer_size);
596 es_out_SetPCR(demux->out, block->i_dts);
597 es_out_Send(demux->out, sys->es, block);
601 sys->dts = dts;
603 sys->source.release(sys->source.data, sys->source.cookie,
604 buffer_size, buffer);
606 sys->deadline = VLC_TICK_INVALID;
607 return 1;
611 * Parse the MRL and extract configuration from it.
613 * Syntax: option1=value1[:option2=value2[...]]
615 * XXX get and release are not supported on purpose.
617 static void ParseMRL(vlc_object_t *object, const char *psz_path)
619 static const struct {
620 const char *name;
621 int type;
622 } options[] = {
623 { "id", VLC_VAR_INTEGER },
624 { "group", VLC_VAR_INTEGER },
625 { "cat", VLC_VAR_INTEGER },
626 { "samplerate", VLC_VAR_INTEGER },
627 { "channels", VLC_VAR_INTEGER },
628 { "width", VLC_VAR_INTEGER },
629 { "height", VLC_VAR_INTEGER },
630 { "cookie", VLC_VAR_STRING },
631 { "codec", VLC_VAR_STRING },
632 { "language", VLC_VAR_STRING },
633 { "dar", VLC_VAR_STRING },
634 { "fps", VLC_VAR_STRING },
635 { NULL, -1 }
638 char *dup = strdup(psz_path);
639 if (!dup)
640 return;
641 char *current = dup;
643 while (current) {
644 char *next = strchr(current, ':');
645 if (next)
646 *next++ = '\0';
648 char *option = current;
649 char *value = strchr(current, '=');
650 if (value) {
651 *value++ = '\0';
652 msg_Dbg(object, "option '%s' value '%s'", option, value);
653 } else {
654 msg_Dbg(object, "option '%s' without value (unsupported)", option);
657 char *name;
658 if (asprintf(&name, "imem-%s", option) < 0)
659 name = NULL;
660 for (unsigned i = 0; name && options[i].name; i++) {
661 if (strcmp(options[i].name, option))
662 continue;
663 /* */
664 var_Create(object, name, options[i].type | VLC_VAR_DOINHERIT);
665 if (options[i].type == VLC_VAR_INTEGER && value) {
666 var_SetInteger(object, name, strtol(value, NULL, 0));
667 } else if (options[i].type == VLC_VAR_STRING && value) {
668 var_SetString(object, name, value);
670 break;
672 free(name);
674 /* */
675 current = next;
677 free(dup);