Remove the file:// URI decode hack
[vlc/asuraparaju-public.git] / modules / access / imem.c
blobc3e17fbd03fd12472bc320e9ee63828463fd407c
1 /*****************************************************************************
2 * imem.c : Memory input for VLC
3 *****************************************************************************
4 * Copyright (C) 2009-2010 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_access.h>
37 #include <vlc_demux.h>
38 #include <vlc_charset.h>
40 /*****************************************************************************
41 * Module descriptior
42 *****************************************************************************/
43 static int OpenAccess (vlc_object_t *);
44 static void CloseAccess(vlc_object_t *);
46 static int OpenDemux (vlc_object_t *);
47 static void CloseDemux(vlc_object_t *);
49 #define CACHING_TEXT N_("Caching value in ms")
50 #define CACHING_LONGTEXT N_(\
51 "Caching value for imem streams. This " \
52 "value should be set in milliseconds.")
54 #define ID_TEXT N_("ID")
55 #define ID_LONGTEXT N_(\
56 "Set the ID of the elementary stream")
58 #define GROUP_TEXT N_("Group")
59 #define GROUP_LONGTEXT N_(\
60 "Set the group of the elementary stream")
62 #define CAT_TEXT N_("Category")
63 #define CAT_LONGTEXT N_(\
64 "Set the category of the elementary stream")
65 static const int cat_values[] = {
66 0, 1, 2, 3, 4,
68 static const char *cat_texts[] = {
69 N_("Unknown"), N_("Audio"), N_("Video"), N_("Subtitle"), N_("Data")
72 #define CODEC_TEXT N_("Codec")
73 #define CODEC_LONGTEXT N_(\
74 "Set the codec of the elementary stream")
76 #define LANGUAGE_TEXT N_("Language")
77 #define LANGUAGE_LONGTEXT N_(\
78 "Language of the elementary stream as described by ISO639")
80 #define SAMPLERATE_TEXT N_("Sample rate")
81 #define SAMPLERATE_LONGTEXT N_(\
82 "Sample rate of an audio elementary stream")
84 #define CHANNELS_TEXT N_("Channels count")
85 #define CHANNELS_LONGTEXT N_(\
86 "Channels count of an audio elementary stream")
88 #define WIDTH_TEXT N_("Width")
89 #define WIDTH_LONGTEXT N_("Width of video or subtitle elementary streams")
91 #define HEIGHT_TEXT N_("Height")
92 #define HEIGHT_LONGTEXT N_("Height of video or subtitle elementary streams")
94 #define DAR_TEXT N_("Display aspect ratio")
95 #define DAR_LONGTEXT N_(\
96 "Display aspect ratio of a video elementary stream")
98 #define FPS_TEXT N_("Frame rate")
99 #define FPS_LONGTEXT N_(\
100 "Frame rate of a video elementary stream")
102 #define COOKIE_TEXT N_("Callback cookie string")
103 #define COOKIE_LONGTEXT N_(\
104 "Text identifier for the callback functions")
106 #define DATA_TEXT N_("Callback data")
107 #define DATA_LONGTEXT N_(\
108 "Data for the get and release functions")
110 #define GET_TEXT N_("Get function")
111 #define GET_LONGTEXT N_(\
112 "Address of the get callback function")
114 #define RELEASE_TEXT N_("Release function")
115 #define RELEASE_LONGTEXT N_(\
116 "Address of the release callback function")
118 vlc_module_begin()
119 set_shortname(N_("Memory input"))
120 set_description(N_("Memory input"))
121 set_category(CAT_INPUT)
122 set_subcategory(SUBCAT_INPUT_ACCESS)
124 add_integer("imem-caching", DEFAULT_PTS_DELAY / 1000, NULL, CACHING_TEXT, CACHING_LONGTEXT, true)
125 change_private()
126 add_string ("imem-get", "0", NULL, GET_TEXT, GET_LONGTEXT, true)
127 change_volatile()
128 add_string ("imem-release", "0", NULL, RELEASE_TEXT, RELEASE_LONGTEXT, true)
129 change_volatile()
130 add_string ("imem-cookie", NULL, NULL, COOKIE_TEXT, COOKIE_LONGTEXT, true)
131 change_volatile()
132 change_safe()
133 add_string ("imem-data", "0", NULL, DATA_TEXT, DATA_LONGTEXT, true)
134 change_volatile()
136 add_integer("imem-id", -1, NULL, ID_TEXT, ID_LONGTEXT, true)
137 change_private()
138 change_safe()
139 add_integer("imem-group", 0, NULL, GROUP_TEXT, GROUP_LONGTEXT, true)
140 change_private()
141 change_safe()
142 add_integer("imem-cat", 0, NULL, CAT_TEXT, CAT_LONGTEXT, true)
143 change_integer_list(cat_values, cat_texts, NULL)
144 change_private()
145 change_safe()
146 add_string ("imem-codec", NULL, NULL, CODEC_TEXT, CODEC_LONGTEXT, true)
147 change_private()
148 change_safe()
149 add_string( "imem-language", NULL, NULL, LANGUAGE_TEXT, LANGUAGE_LONGTEXT, false)
150 change_private()
151 change_safe()
153 add_integer("imem-samplerate", 0, NULL, SAMPLERATE_TEXT, SAMPLERATE_LONGTEXT, true)
154 change_private()
155 change_safe()
156 add_integer("imem-channels", 0, NULL, CHANNELS_TEXT, CHANNELS_LONGTEXT, true)
157 change_private()
158 change_safe()
160 add_integer("imem-width", 0, NULL, WIDTH_TEXT, WIDTH_LONGTEXT, true)
161 change_private()
162 change_safe()
163 add_integer("imem-height", 0, NULL, HEIGHT_TEXT, HEIGHT_LONGTEXT, true)
164 change_private()
165 change_safe()
166 add_string ("imem-dar", NULL, NULL, DAR_TEXT, DAR_LONGTEXT, true)
167 change_private()
168 change_safe()
169 add_string ("imem-fps", NULL, NULL, FPS_TEXT, FPS_LONGTEXT, true)
170 change_private()
171 change_safe()
173 add_shortcut("imem")
174 set_capability("access_demux", 0)
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(access_t *);
203 static int ControlAccess(access_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 mtime_t pts_delay;
221 mtime_t dts;
223 mtime_t deadline;
224 } imem_sys_t;
226 static void ParseMRL(vlc_object_t *, const char *);
227 #define var_InheritRational(a,b,c,d) var_InheritRational(VLC_OBJECT(a),b,c,d)
228 static int (var_InheritRational)(vlc_object_t *,
229 unsigned *num, unsigned *den,
230 const char *var);
233 * It closes the common part of the access and access_demux
235 static void CloseCommon(imem_sys_t *sys)
237 free(sys->source.cookie);
238 free(sys);
242 * It initializes the common part for imem access/access_demux.
244 static int OpenCommon(vlc_object_t *object, imem_sys_t **sys_ptr, const char *psz_path)
246 char *tmp;
248 /* */
249 imem_sys_t *sys = calloc(1, sizeof(*sys));
250 if (!sys)
251 return VLC_ENOMEM;
253 /* Read the user functions */
254 tmp = var_InheritString(object, "imem-get");
255 if (tmp)
256 sys->source.get = (imem_get_t)(intptr_t)strtoll(tmp, NULL, 0);
257 free(tmp);
259 tmp = var_InheritString(object, "imem-release");
260 if (tmp)
261 sys->source.release = (imem_release_t)(intptr_t)strtoll(tmp, NULL, 0);
262 free(tmp);
264 if (!sys->source.get || !sys->source.release) {
265 msg_Err(object, "Invalid get/release function pointers");
266 free(sys);
267 return VLC_EGENERIC;
270 tmp = var_InheritString(object, "imem-data");
271 if (tmp)
272 sys->source.data = (void *)(uintptr_t)strtoull(tmp, NULL, 0);
273 free(tmp);
275 /* Now we can parse the MRL (get/release must not be parsed to avoid
276 * security risks) */
277 if (*psz_path)
278 ParseMRL(object, psz_path);
280 sys->source.cookie = var_InheritString(object, "imem-cookie");
282 msg_Dbg(object, "Using get(%p), release(%p), data(%p), cookie(%s)",
283 sys->source.get, sys->source.release, sys->source.data,
284 sys->source.cookie ? sys->source.cookie : "(null)");
286 /* */
287 sys->pts_delay = var_InheritInteger(object, "imem-caching") * INT64_C(1000);
288 sys->dts = 0;
289 sys->deadline = VLC_TS_INVALID;
291 *sys_ptr = sys;
292 return VLC_SUCCESS;
296 * It opens an imem access.
298 static int OpenAccess(vlc_object_t *object)
300 access_t *access = (access_t *)object;
301 imem_sys_t *sys;
303 if (OpenCommon(object, &sys, access->psz_location))
304 return VLC_EGENERIC;
306 if (var_InheritInteger(object, "imem-cat") != 4) {
307 CloseCommon(sys);
308 return VLC_EGENERIC;
311 /* */
312 access_InitFields(access);
313 access->pf_control = ControlAccess;
314 access->pf_read = NULL;
315 access->pf_block = Block;
316 access->pf_seek = NULL;
317 access->p_sys = (access_sys_t*)sys;
319 return VLC_SUCCESS;
323 * It closes an imem access
325 static void CloseAccess(vlc_object_t *object)
327 access_t *access = (access_t *)object;
329 CloseCommon((imem_sys_t*)access->p_sys);
333 * It controls an imem access
335 static int ControlAccess(access_t *access, int i_query, va_list args)
337 imem_sys_t *sys = (imem_sys_t*)access->p_sys;
339 switch (i_query)
341 case ACCESS_CAN_SEEK:
342 case ACCESS_CAN_FASTSEEK: {
343 bool *b = va_arg( args, bool* );
344 *b = false;
345 return VLC_SUCCESS;
347 case ACCESS_CAN_PAUSE:
348 case ACCESS_CAN_CONTROL_PACE: {
349 bool *b = va_arg( args, bool* );
350 *b = true;
351 return VLC_SUCCESS;
353 case ACCESS_GET_PTS_DELAY: {
354 int64_t *delay = va_arg(args, int64_t *);
355 *delay = sys->pts_delay;
356 return VLC_SUCCESS;
358 case ACCESS_SET_PAUSE_STATE:
359 return VLC_SUCCESS;
361 case ACCESS_GET_TITLE_INFO:
362 case ACCESS_SET_TITLE:
363 case ACCESS_SET_SEEKPOINT:
364 case ACCESS_SET_PRIVATE_ID_STATE:
365 case ACCESS_GET_META:
366 case ACCESS_GET_PRIVATE_ID_STATE:
367 case ACCESS_GET_CONTENT_TYPE:
368 default:
369 return VLC_EGENERIC;
374 * It retreives data using the get() callback, copies them,
375 * and then release them using the release() callback.
377 static block_t *Block(access_t *access)
379 imem_sys_t *sys = (imem_sys_t*)access->p_sys;
381 unsigned flags;
382 size_t buffer_size;
383 void *buffer;
385 if (sys->source.get(sys->source.data, sys->source.cookie,
386 NULL, NULL, &flags, &buffer_size, &buffer)) {
387 access->info.b_eof = true;
388 return NULL;
391 block_t *block = NULL;
392 if (buffer_size > 0) {
393 block = block_New(access, buffer_size);
394 if (block)
395 memcpy(block->p_buffer, buffer, buffer_size);
398 sys->source.release(sys->source.data, sys->source.cookie,
399 buffer_size, buffer);
400 return block;
404 * It opens an imem access_demux.
406 static int OpenDemux(vlc_object_t *object)
408 demux_t *demux = (demux_t *)object;
409 imem_sys_t *sys;
411 if (OpenCommon(object, &sys, demux->psz_path))
412 return VLC_EGENERIC;
414 /* ES format */
415 es_format_t fmt;
416 es_format_Init(&fmt, UNKNOWN_ES, 0);
418 fmt.i_id = var_InheritInteger(object, "imem-id");
419 fmt.i_group = var_InheritInteger(object, "imem-group");
421 char *tmp = var_InheritString(object, "imem-codec");
422 if (tmp)
423 fmt.i_codec = vlc_fourcc_GetCodecFromString(UNKNOWN_ES, tmp);
424 free(tmp);
426 const int cat = var_InheritInteger(object, "imem-cat");
427 switch (cat) {
428 case 1: {
429 fmt.i_cat = AUDIO_ES;
430 fmt.audio.i_channels = var_InheritInteger(object, "imem-channels");
431 fmt.audio.i_rate = var_InheritInteger(object, "imem-samplerate");
433 msg_Dbg(object, "Audio %4.4s %d channels %d Hz",
434 (const char *)&fmt.i_codec,
435 fmt.audio.i_channels, fmt.audio.i_rate);
436 break;
438 case 2: {
439 fmt.i_cat = VIDEO_ES;
440 fmt.video.i_width = var_InheritInteger(object, "imem-width");
441 fmt.video.i_height = var_InheritInteger(object, "imem-height");
442 unsigned num, den;
443 if (!var_InheritRational(object, &num, &den, "imem-dar") && num > 0 && den > 0) {
444 if (fmt.video.i_width > 0 && fmt.video.i_height > 0) {
445 fmt.video.i_sar_num = num * fmt.video.i_height;
446 fmt.video.i_sar_den = den * fmt.video.i_width;
449 if (!var_InheritRational(object, &num, &den, "imem-fps") && num > 0 && den > 0) {
450 fmt.video.i_frame_rate = num;
451 fmt.video.i_frame_rate_base = den;
454 msg_Dbg(object, "Video %4.4s %dx%d SAR %d:%d frame rate %u/%u",
455 (const char *)&fmt.i_codec,
456 fmt.video.i_width, fmt.video.i_height,
457 fmt.video.i_sar_num, fmt.video.i_sar_den,
458 fmt.video.i_frame_rate, fmt.video.i_frame_rate_base);
459 break;
461 case 3: {
462 fmt.i_cat = SPU_ES;
463 fmt.subs.spu.i_original_frame_width =
464 var_InheritInteger(object, "imem-width");
465 fmt.subs.spu.i_original_frame_height =
466 var_InheritInteger(object, "imem-height");
468 msg_Dbg(object, "Subtitle %4.4s",
469 (const char *)&fmt.i_codec);
470 break;
472 default:
473 if (cat != 4)
474 msg_Err(object, "Invalid ES category");
475 es_format_Clean(&fmt);
476 CloseCommon(sys);
477 return VLC_EGENERIC;
480 fmt.psz_language = var_InheritString(object, "imem-language");
482 sys->es = es_out_Add(demux->out, &fmt);
483 es_format_Clean(&fmt);
485 if (!sys->es) {
486 CloseCommon(sys);
487 return VLC_EGENERIC;
490 /* */
491 demux->pf_control = ControlDemux;
492 demux->pf_demux = Demux;
493 demux->p_sys = (demux_sys_t*)sys;
495 demux->info.i_update = 0;
496 demux->info.i_title = 0;
497 demux->info.i_seekpoint = 0;
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 int64_t *delay = va_arg(args, int64_t *);
531 *delay = sys->pts_delay;
532 return VLC_SUCCESS;
534 case DEMUX_GET_POSITION: {
535 double *position = va_arg(args, double *);
536 *position = 0.0;
537 return VLC_SUCCESS;
539 case DEMUX_GET_TIME: {
540 int64_t *t = va_arg(args, int64_t *);
541 *t = sys->dts;
542 return VLC_SUCCESS;
544 case DEMUX_GET_LENGTH: {
545 int64_t *l = va_arg(args, int64_t *);
546 *l = 0;
547 return VLC_SUCCESS;
549 case DEMUX_SET_NEXT_DEMUX_TIME:
550 sys->deadline = va_arg(args, int64_t);
551 return VLC_SUCCESS;
553 /* */
554 case DEMUX_CAN_SEEK:
555 case DEMUX_SET_POSITION:
556 case DEMUX_SET_TIME:
557 default:
558 return VLC_EGENERIC;
561 return VLC_EGENERIC;
565 * It retreives data using the get() callback, sends them to es_out
566 * and the release it using the release() callback.
568 static int Demux(demux_t *demux)
570 imem_sys_t *sys = (imem_sys_t*)demux->p_sys;
572 if (sys->deadline == VLC_TS_INVALID)
573 sys->deadline = sys->dts + 1;
575 for (;;) {
576 if (sys->deadline <= sys->dts)
577 break;
579 /* */
580 int64_t dts, pts;
581 unsigned flags;
582 size_t buffer_size;
583 void *buffer;
585 if (sys->source.get(sys->source.data, sys->source.cookie,
586 &dts, &pts, &flags, &buffer_size, &buffer))
587 return 0;
589 if (dts < 0)
590 dts = pts;
592 if (buffer_size > 0) {
593 block_t *block = block_New(demux, buffer_size);
594 if (block) {
595 block->i_dts = dts >= 0 ? (1 + dts) : VLC_TS_INVALID;
596 block->i_pts = pts >= 0 ? (1 + pts) : VLC_TS_INVALID;
597 memcpy(block->p_buffer, buffer, buffer_size);
599 es_out_Control(demux->out, ES_OUT_SET_PCR, block->i_dts);
600 es_out_Send(demux->out, sys->es, block);
604 sys->dts = dts;
606 sys->source.release(sys->source.data, sys->source.cookie,
607 buffer_size, buffer);
609 sys->deadline = VLC_TS_INVALID;
610 return 1;
614 * It parses a rational number (it also accepts basic float number).
616 * It returns an error if the rational number cannot be parsed (0/0 is valid).
618 static int (var_InheritRational)(vlc_object_t *object,
619 unsigned *num, unsigned *den,
620 const char *var)
622 /* */
623 *num = 0;
624 *den = 0;
626 /* */
627 char *tmp = var_InheritString(object, var);
628 if (!tmp)
629 goto error;
631 char *next;
632 unsigned n = strtol(tmp, &next, 0);
633 unsigned d = strtol(*next ? &next[1] : "0", NULL, 0);
635 if (*next == '.') {
636 /* Interpret as a float number */
637 double r = us_atof(tmp);
638 double c = ceil(r);
639 if (c >= UINT_MAX)
640 goto error;
641 unsigned m = c;
642 if (m > 0) {
643 d = UINT_MAX / m;
644 n = r * d;
645 } else {
646 n = 0;
647 d = 0;
651 if (n > 0 && d > 0)
652 vlc_ureduce(num, den, n, d, 0);
654 free(tmp);
655 return VLC_SUCCESS;
657 error:
658 free(tmp);
659 return VLC_EGENERIC;
663 * Parse the MRL and extract configuration from it.
665 * Syntax: option1=value1[:option2=value2[...]]
667 * XXX get and release are not supported on purpose.
669 static void ParseMRL(vlc_object_t *object, const char *psz_path)
671 static const struct {
672 const char *name;
673 int type;
674 } options[] = {
675 { "caching", VLC_VAR_INTEGER },
676 { "id", VLC_VAR_INTEGER },
677 { "group", VLC_VAR_INTEGER },
678 { "cat", VLC_VAR_INTEGER },
679 { "samplerate", VLC_VAR_INTEGER },
680 { "channels", VLC_VAR_INTEGER },
681 { "width", VLC_VAR_INTEGER },
682 { "height", VLC_VAR_INTEGER },
683 { "cookie", VLC_VAR_STRING },
684 { "codec", VLC_VAR_STRING },
685 { "language", VLC_VAR_STRING },
686 { "dar", VLC_VAR_STRING },
687 { "fps", VLC_VAR_STRING },
688 { NULL, -1 }
691 char *dup = strdup(psz_path);
692 if (!dup)
693 return;
694 char *current = dup;
696 while (current) {
697 char *next = strchr(current, ':');
698 if (next)
699 *next++ = '\0';
701 char *option = current;
702 char *value = strchr(current, '=');
703 if (value) {
704 *value++ = '\0';
705 msg_Dbg(object, "option '%s' value '%s'", option, value);
706 } else {
707 msg_Dbg(object, "option '%s' without value (unsupported)", option);
710 char *name;
711 if (asprintf(&name, "imem-%s", option) < 0)
712 name = NULL;
713 for (unsigned i = 0; name && options[i].name; i++) {
714 if (strcmp(options[i].name, option))
715 continue;
716 /* */
717 var_Create(object, name, options[i].type | VLC_VAR_DOINHERIT);
718 if (options[i].type == VLC_VAR_INTEGER && value) {
719 var_SetInteger(object, name, strtol(value, NULL, 0));
720 } else if (options[i].type == VLC_VAR_STRING && value) {
721 var_SetString(object, name, value);
723 break;
725 free(name);
727 /* */
728 current = next;
730 free(dup);