imem: mark MRL options as safe
[vlc/asuraparaju-public.git] / modules / access / imem.c
blob222a7708fbb37f373d09c49c27ffe8ec114e0ef5
1 /*****************************************************************************
2 * imem.c : Memory input for VLC
3 *****************************************************************************
4 * Copyright (C) 2009 Laurent Aimar
5 * $Id$
7 * Author: Laurent Aimar <fenrir _AT_ videolan _DOT org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
25 * Preamble
26 *****************************************************************************/
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31 #include <limits.h>
32 #include <math.h>
34 #include <vlc_common.h>
35 #include <vlc_plugin.h>
36 #include <vlc_demux.h>
37 #include <vlc_charset.h>
39 /*****************************************************************************
40 * Module descriptior
41 *****************************************************************************/
42 static int Open (vlc_object_t *);
43 static void Close(vlc_object_t *);
45 #define CACHING_TEXT N_("Caching value in ms")
46 #define CACHING_LONGTEXT N_(\
47 "Caching value for imem streams. This " \
48 "value should be set in milliseconds.")
50 #define ID_TEXT N_("ID")
51 #define ID_LONGTEXT N_(\
52 "Set the ID of the elementary stream")
54 #define GROUP_TEXT N_("Group")
55 #define GROUP_LONGTEXT N_(\
56 "Set the group of the elementary stream")
58 #define CAT_TEXT N_("Category")
59 #define CAT_LONGTEXT N_(\
60 "Set the category of the elementary stream")
61 static const int cat_values[] = {
62 0, 1, 2, 3
64 static const char *cat_texts[] = {
65 N_("Unknown"), N_("Audio"), N_("Video"), N_("Subtitle")
68 #define CODEC_TEXT N_("Codec")
69 #define CODEC_LONGTEXT N_(\
70 "Set the codec of the elementary stream")
72 #define LANGUAGE_TEXT N_("Language")
73 #define LANGUAGE_LONGTEXT N_(\
74 "Language of the elementary stream as described by ISO639")
76 #define SAMPLERATE_TEXT N_("Sample rate")
77 #define SAMPLERATE_LONGTEXT N_(\
78 "Sample rate of an audio elementary stream")
80 #define CHANNELS_TEXT N_("Channels count")
81 #define CHANNELS_LONGTEXT N_(\
82 "Channels count of an audio elementary stream")
84 #define WIDTH_TEXT N_("Width")
85 #define WIDTH_LONGTEXT N_("Width of video or subtitle elementary streams")
87 #define HEIGHT_TEXT N_("Height")
88 #define HEIGHT_LONGTEXT N_("Height of video or subtitle elementary streams")
90 #define DAR_TEXT N_("Display aspect ratio")
91 #define DAR_LONGTEXT N_(\
92 "Display aspect ratio of a video elementary stream")
94 #define FPS_TEXT N_("Frame rate")
95 #define FPS_LONGTEXT N_(\
96 "Frame rate of a video elementary stream")
98 #define COOKIE_TEXT N_("Callback cookie string")
99 #define COOKIE_LONGTEXT N_(\
100 "Text identifier for the callback functions")
102 #define DATA_TEXT N_("Callback data")
103 #define DATA_LONGTEXT N_(\
104 "Data for the get and release functions")
106 #define GET_TEXT N_("Get function")
107 #define GET_LONGTEXT N_(\
108 "Address of the get callback function")
110 #define RELEASE_TEXT N_("Release function")
111 #define RELEASE_LONGTEXT N_(\
112 "Address of the release callback function")
114 vlc_module_begin()
115 set_shortname(N_("Memory input"))
116 set_description(N_("Memory input"))
117 set_category(CAT_INPUT)
118 set_subcategory(SUBCAT_INPUT_ACCESS)
120 add_integer("imem-caching", DEFAULT_PTS_DELAY / 1000, NULL, CACHING_TEXT, CACHING_LONGTEXT, true)
121 change_private()
122 add_string ("imem-get", "0", NULL, GET_TEXT, GET_LONGTEXT, true)
123 change_volatile()
124 add_string ("imem-release", "0", NULL, RELEASE_TEXT, RELEASE_LONGTEXT, true)
125 change_volatile()
126 add_string ("imem-cookie", NULL, NULL, COOKIE_TEXT, COOKIE_LONGTEXT, true)
127 change_volatile()
128 change_safe()
129 add_string ("imem-data", "0", NULL, DATA_TEXT, DATA_LONGTEXT, true)
130 change_volatile()
132 add_integer("imem-id", -1, NULL, ID_TEXT, ID_LONGTEXT, true)
133 change_private()
134 change_safe()
135 add_integer("imem-group", 0, NULL, GROUP_TEXT, GROUP_LONGTEXT, true)
136 change_private()
137 change_safe()
138 add_integer("imem-cat", 0, NULL, CAT_TEXT, CAT_LONGTEXT, true)
139 change_integer_list(cat_values, cat_texts, NULL)
140 change_private()
141 change_safe()
142 add_string ("imem-codec", NULL, NULL, CODEC_TEXT, CODEC_LONGTEXT, true)
143 change_private()
144 change_safe()
145 add_string( "imem-language", NULL, NULL, LANGUAGE_TEXT, LANGUAGE_LONGTEXT, false)
146 change_private()
147 change_safe()
149 add_integer("imem-samplerate", 0, NULL, SAMPLERATE_TEXT, SAMPLERATE_LONGTEXT, true)
150 change_private()
151 change_safe()
152 add_integer("imem-channels", 0, NULL, CHANNELS_TEXT, CHANNELS_LONGTEXT, true)
153 change_private()
154 change_safe()
156 add_integer("imem-width", 0, NULL, WIDTH_TEXT, WIDTH_LONGTEXT, true)
157 change_private()
158 change_safe()
159 add_integer("imem-height", 0, NULL, HEIGHT_TEXT, HEIGHT_LONGTEXT, true)
160 change_private()
161 change_safe()
162 add_string ("imem-dar", NULL, NULL, DAR_TEXT, DAR_LONGTEXT, true)
163 change_private()
164 change_safe()
165 add_string ("imem-fps", NULL, NULL, FPS_TEXT, FPS_LONGTEXT, true)
166 change_private()
167 change_safe()
169 add_shortcut("imem")
170 set_capability("access_demux", 0)
171 set_callbacks(Open, Close)
172 vlc_module_end()
174 /*****************************************************************************
175 * Exported API
176 *****************************************************************************/
178 /* The clock origin for the DTS and PTS is assumed to be 0.
179 * A negative value means unknown.
181 * TODO define flags
183 typedef int (*imem_get_t)(void *data, const char *cookie,
184 int64_t *dts, int64_t *pts, unsigned *flags,
185 size_t *, void **);
186 typedef void (*imem_release_t)(void *data, const char *cookie, size_t, void *);
188 /*****************************************************************************
189 * Local prototypes
190 *****************************************************************************/
192 /* */
193 static int Demux(demux_t *);
194 static int Control(demux_t *, int, va_list);
196 /* */
197 struct demux_sys_t {
198 struct {
199 imem_get_t get;
200 imem_release_t release;
201 void *data;
202 char *cookie;
203 } source;
205 es_out_id_t *es;
207 mtime_t pts_delay;
209 mtime_t dts;
211 mtime_t deadline;
214 static void ParseMRL(demux_t *);
215 static int var_CreateGetRational(demux_t *,
216 unsigned *num, unsigned *den,
217 const char *var);
220 * It opens an imem access_demux
222 static int Open(vlc_object_t *object)
224 demux_t *demux = (demux_t*)object;
225 char *tmp;
227 /* */
228 demux_sys_t *sys = calloc(1, sizeof(*sys));
229 if (!sys)
230 return VLC_ENOMEM;
232 /* Read the user functions */
233 tmp = var_CreateGetString(demux, "imem-get");
234 if (tmp)
235 sys->source.get = (imem_get_t)(intptr_t)strtoll(tmp, NULL, 0);
236 free(tmp);
238 tmp = var_CreateGetString(demux, "imem-release");
239 if (tmp)
240 sys->source.release = (imem_release_t)(intptr_t)strtoll(tmp, NULL, 0);
241 free(tmp);
243 if (!sys->source.get || !sys->source.release) {
244 msg_Err(demux, "Invalid get/release function pointers");
245 free(sys);
246 return VLC_EGENERIC;
249 tmp = var_CreateGetString(demux, "imem-data");
250 if (tmp)
251 sys->source.data = (void *)(uintptr_t)strtoull(tmp, NULL, 0);
252 free(tmp);
254 /* Now we can parse the MRL (get/release must not be parsed to avoid
255 * security risks) */
256 if (*demux->psz_path)
257 ParseMRL(demux);
259 /* Now we can parse the MRL (get/release must not be parsed to avoid
260 * security risks) */
261 if (*demux->psz_path)
262 ParseMRL(demux);
264 sys->source.cookie = var_InheritString(demux, "imem-cookie");
266 msg_Dbg(demux, "Using get(%p), release(%p), data(%p), cookie(%s)",
267 sys->source.get, sys->source.release, sys->source.data,
268 sys->source.cookie ? sys->source.cookie : "(null)");
270 /* ES format */
271 es_format_t fmt;
272 es_format_Init(&fmt, UNKNOWN_ES, 0);
274 fmt.i_id = var_CreateGetInteger(demux, "imem-id");
275 fmt.i_group = var_CreateGetInteger(demux, "imem-group");
277 tmp = var_CreateGetString(demux, "imem-codec");
278 if (tmp)
279 fmt.i_codec = vlc_fourcc_GetCodecFromString(UNKNOWN_ES, tmp);
280 free(tmp);
282 switch (var_CreateGetInteger(demux, "imem-cat")) {
283 case 1: {
284 fmt.i_cat = AUDIO_ES;
285 fmt.audio.i_channels = var_CreateGetInteger(demux, "imem-channels");
286 fmt.audio.i_rate = var_CreateGetInteger(demux, "imem-samplerate");
288 msg_Dbg(demux, "Audio %4.4s %d channels %d Hz",
289 (const char *)&fmt.i_codec,
290 fmt.audio.i_channels, fmt.audio.i_rate);
291 break;
293 case 2: {
294 fmt.i_cat = VIDEO_ES;
295 fmt.video.i_width = var_CreateGetInteger(demux, "imem-width");
296 fmt.video.i_height = var_CreateGetInteger(demux, "imem-height");
297 unsigned num, den;
298 if (!var_CreateGetRational(demux, &num, &den, "imem-dar") && num > 0 && den > 0) {
299 if (fmt.video.i_width > 0 && fmt.video.i_height > 0) {
300 fmt.video.i_sar_num = num * fmt.video.i_height;
301 fmt.video.i_sar_den = den * fmt.video.i_width;
304 if (!var_CreateGetRational(demux, &num, &den, "imem-fps") && num > 0 && den > 0) {
305 fmt.video.i_frame_rate = num;
306 fmt.video.i_frame_rate_base = den;
309 msg_Dbg(demux, "Video %4.4s %dx%d SAR %d:%d frame rate %u/%u",
310 (const char *)&fmt.i_codec,
311 fmt.video.i_width, fmt.video.i_height,
312 fmt.video.i_sar_num, fmt.video.i_sar_den,
313 fmt.video.i_frame_rate, fmt.video.i_frame_rate_base);
314 break;
316 case 3: {
317 fmt.i_cat = SPU_ES;
318 fmt.subs.spu.i_original_frame_width =
319 var_CreateGetInteger(demux, "imem-width");
320 fmt.subs.spu.i_original_frame_height =
321 var_CreateGetInteger(demux, "imem-height");
323 msg_Dbg(demux, "Subtitle %4.4s",
324 (const char *)&fmt.i_codec);
325 break;
327 default:
328 msg_Err(demux, "Invalid ES category");
329 es_format_Clean(&fmt);
330 free(sys);
331 return VLC_EGENERIC;
334 fmt.psz_language = var_CreateGetString(demux, "imem-language");
336 /* */
337 sys->es = es_out_Add(demux->out, &fmt);
338 es_format_Clean(&fmt);
340 if (!sys->es) {
341 free(sys->source.data);
342 free(sys);
343 return VLC_EGENERIC;
346 /* */
347 sys->pts_delay = var_CreateGetInteger(demux, "imem-caching") * INT64_C(1000);
348 sys->dts = 0;
349 sys->deadline = VLC_TS_INVALID;
351 /* Set up demux */
352 demux->pf_control = Control;
353 demux->pf_demux = Demux;
354 demux->p_sys = sys;
356 demux->info.i_update = 0;
357 demux->info.i_title = 0;
358 demux->info.i_seekpoint = 0;
359 return VLC_SUCCESS;
363 * It closes an imem access_demux
365 static void Close(vlc_object_t *object)
367 demux_t *demux = (demux_t *)object;
368 demux_sys_t *sys = demux->p_sys;
370 free(sys->source.cookie);
371 free(sys);
375 * It controls imem
377 static int Control(demux_t *demux, int i_query, va_list args)
379 demux_sys_t *sys = demux->p_sys;
381 switch (i_query)
383 case DEMUX_CAN_PAUSE:
384 case DEMUX_CAN_CONTROL_PACE: {
385 bool *b = va_arg(args, bool *);
386 *b = true;
387 return VLC_SUCCESS;
389 case DEMUX_SET_PAUSE_STATE:
390 return VLC_SUCCESS;
392 case DEMUX_GET_PTS_DELAY: {
393 int64_t *delay = va_arg(args, int64_t *);
394 *delay = sys->pts_delay;
395 return VLC_SUCCESS;
397 case DEMUX_GET_POSITION: {
398 double *position = va_arg(args, double *);
399 *position = 0.0;
400 return VLC_SUCCESS;
402 case DEMUX_GET_TIME: {
403 int64_t *t = va_arg(args, int64_t *);
404 *t = sys->dts;
405 return VLC_SUCCESS;
407 case DEMUX_GET_LENGTH: {
408 int64_t *l = va_arg(args, int64_t *);
409 *l = 0;
410 return VLC_SUCCESS;
412 case DEMUX_SET_NEXT_DEMUX_TIME:
413 sys->deadline = va_arg(args, int64_t);
414 return VLC_SUCCESS;
416 /* */
417 case DEMUX_CAN_SEEK:
418 case DEMUX_SET_POSITION:
419 case DEMUX_SET_TIME:
420 default:
421 return VLC_EGENERIC;
424 return VLC_EGENERIC;
428 * It retreives data using the get() callback, sends them to es_out
429 * and the release it using the release() callback.
431 static int Demux(demux_t *demux)
433 demux_sys_t *sys = demux->p_sys;
435 if (sys->deadline == VLC_TS_INVALID)
436 sys->deadline = sys->dts + 1;
438 for (;;) {
439 if (sys->deadline <= sys->dts)
440 break;
442 /* */
443 int64_t dts, pts;
444 unsigned flags;
445 size_t buffer_size;
446 void *buffer;
448 if (sys->source.get(sys->source.data, sys->source.cookie,
449 &dts, &pts, &flags, &buffer_size, &buffer))
450 return 0;
452 if (dts < 0)
453 dts = pts;
455 if (buffer_size > 0) {
456 block_t *block = block_New(demux, buffer_size);
457 if (block) {
458 block->i_dts = dts >= 0 ? (1 + dts) : VLC_TS_INVALID;
459 block->i_pts = pts >= 0 ? (1 + pts) : VLC_TS_INVALID;
460 memcpy(block->p_buffer, buffer, buffer_size);
462 es_out_Control(demux->out, ES_OUT_SET_PCR, block->i_dts);
463 es_out_Send(demux->out, sys->es, block);
467 sys->dts = dts;
469 sys->source.release(sys->source.data, sys->source.cookie,
470 buffer_size, buffer);
472 sys->deadline = VLC_TS_INVALID;
473 return 1;
477 * It parses a rational number (it also accepts basic float number).
479 * It returns an error if the rational number cannot be parsed (0/0 is valid).
481 static int var_CreateGetRational(demux_t *demux,
482 unsigned *num, unsigned *den,
483 const char *var)
485 /* */
486 *num = 0;
487 *den = 0;
489 /* */
490 char *tmp = var_CreateGetString(demux, var);
491 if (!tmp)
492 goto error;
494 char *next;
495 unsigned n = strtol(tmp, &next, 0);
496 unsigned d = strtol(*next ? &next[1] : "0", NULL, 0);
498 if (*next == '.') {
499 /* Interpret as a float number */
500 double r = us_atof(tmp);
501 double c = ceil(r);
502 if (c >= UINT_MAX)
503 goto error;
504 unsigned m = c;
505 if (m > 0) {
506 d = UINT_MAX / m;
507 n = r * d;
508 } else {
509 n = 0;
510 d = 0;
514 if (n > 0 && d > 0)
515 vlc_ureduce(num, den, n, d, 0);
517 free(tmp);
518 return VLC_SUCCESS;
520 error:
521 free(tmp);
522 return VLC_EGENERIC;
526 * Parse the MRL and extract configuration from it.
528 * Syntax: option1=value1[:option2=value2[...]]
530 * XXX get and release are not supported on purpose.
532 static void ParseMRL(demux_t *demux)
534 static const struct {
535 const char *name;
536 int type;
537 } options[] = {
538 { "caching", VLC_VAR_INTEGER },
539 { "id", VLC_VAR_INTEGER },
540 { "group", VLC_VAR_INTEGER },
541 { "cat", VLC_VAR_INTEGER },
542 { "samplerate", VLC_VAR_INTEGER },
543 { "channels", VLC_VAR_INTEGER },
544 { "width", VLC_VAR_INTEGER },
545 { "height", VLC_VAR_INTEGER },
546 { "cookie", VLC_VAR_STRING },
547 { "codec", VLC_VAR_STRING },
548 { "language", VLC_VAR_STRING },
549 { "dar", VLC_VAR_STRING },
550 { "fps", VLC_VAR_STRING },
551 { NULL, -1 }
554 char *dup = strdup(demux->psz_path);
555 if (!dup)
556 return;
557 char *current = dup;
559 while (current) {
560 char *next = strchr(current, ':');
561 if (next)
562 *next++ = '\0';
564 char *option = current;
565 char *value = strchr(current, '=');
566 if (value) {
567 *value++ = '\0';
568 msg_Dbg(demux, "option '%s' value '%s'", option, value);
569 } else {
570 msg_Dbg(demux, "option '%s' without value (unsupported)", option);
573 char *name;
574 if (asprintf(&name, "imem-%s", option) < 0)
575 name = NULL;
576 for (unsigned i = 0; name && options[i].name; i++) {
577 if (strcmp(options[i].name, option))
578 continue;
579 /* */
580 var_Create(demux, name, options[i].type | VLC_VAR_DOINHERIT);
581 if (options[i].type == VLC_VAR_INTEGER && value) {
582 var_SetInteger(demux, name, strtol(value, NULL, 0));
583 } else if (options[i].type == VLC_VAR_STRING && value) {
584 var_SetString(demux, name, value);
586 break;
588 free(name);
590 /* */
591 current = next;
593 free(dup);