demux: mkv: ProcessNavAction: negate if to prevent nesting
[vlc.git] / modules / access / imem.c
blob3b42a65bd0910def3db51581320dd083f5342b62
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 it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * 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 ID_TEXT N_("ID")
50 #define ID_LONGTEXT N_(\
51 "Set the ID of the elementary stream")
53 #define GROUP_TEXT N_("Group")
54 #define GROUP_LONGTEXT N_(\
55 "Set the group of the elementary stream")
57 #define CAT_TEXT N_("Category")
58 #define CAT_LONGTEXT N_(\
59 "Set the category of the elementary stream")
60 static const int cat_values[] = {
61 0, 1, 2, 3, 4,
63 static const char *cat_texts[] = {
64 N_("Unknown"), N_("Audio"), N_("Video"), N_("Subtitle"), N_("Data")
67 #define CODEC_TEXT N_("Codec")
68 #define CODEC_LONGTEXT N_(\
69 "Set the codec of the elementary stream")
71 #define LANGUAGE_TEXT N_("Language")
72 #define LANGUAGE_LONGTEXT N_(\
73 "Language of the elementary stream as described by ISO639")
75 #define SAMPLERATE_TEXT N_("Sample rate")
76 #define SAMPLERATE_LONGTEXT N_(\
77 "Sample rate of an audio elementary stream")
79 #define CHANNELS_TEXT N_("Channels count")
80 #define CHANNELS_LONGTEXT N_(\
81 "Channels count of an audio elementary stream")
83 #define WIDTH_TEXT N_("Width")
84 #define WIDTH_LONGTEXT N_("Width of video or subtitle elementary streams")
86 #define HEIGHT_TEXT N_("Height")
87 #define HEIGHT_LONGTEXT N_("Height of video or subtitle elementary streams")
89 #define DAR_TEXT N_("Display aspect ratio")
90 #define DAR_LONGTEXT N_(\
91 "Display aspect ratio of a video elementary stream")
93 #define FPS_TEXT N_("Frame rate")
94 #define FPS_LONGTEXT N_(\
95 "Frame rate of a video elementary stream")
97 #define COOKIE_TEXT N_("Callback cookie string")
98 #define COOKIE_LONGTEXT N_(\
99 "Text identifier for the callback functions")
101 #define DATA_TEXT N_("Callback data")
102 #define DATA_LONGTEXT N_(\
103 "Data for the get and release functions")
105 #define GET_TEXT N_("Get function")
106 #define GET_LONGTEXT N_(\
107 "Address of the get callback function")
109 #define RELEASE_TEXT N_("Release function")
110 #define RELEASE_LONGTEXT N_(\
111 "Address of the release callback function")
113 #define SIZE_TEXT N_("Size")
114 #define SIZE_LONGTEXT N_(\
115 "Size of stream in bytes")
117 vlc_module_begin()
118 set_shortname(N_("Memory input"))
119 set_description(N_("Memory input"))
120 set_category(CAT_INPUT)
121 set_subcategory(SUBCAT_INPUT_ACCESS)
123 add_string ("imem-get", "0", GET_TEXT, GET_LONGTEXT, true)
124 change_volatile()
125 add_string ("imem-release", "0", RELEASE_TEXT, RELEASE_LONGTEXT, true)
126 change_volatile()
127 add_string ("imem-cookie", NULL, COOKIE_TEXT, COOKIE_LONGTEXT, true)
128 change_volatile()
129 change_safe()
130 add_string ("imem-data", "0", DATA_TEXT, DATA_LONGTEXT, true)
131 change_volatile()
133 add_integer("imem-id", -1, ID_TEXT, ID_LONGTEXT, true)
134 change_private()
135 change_safe()
136 add_integer("imem-group", 0, GROUP_TEXT, GROUP_LONGTEXT, true)
137 change_private()
138 change_safe()
139 add_integer("imem-cat", 0, CAT_TEXT, CAT_LONGTEXT, true)
140 change_integer_list(cat_values, cat_texts)
141 change_private()
142 change_safe()
143 add_string ("imem-codec", NULL, CODEC_TEXT, CODEC_LONGTEXT, true)
144 change_private()
145 change_safe()
146 add_string( "imem-language", NULL, LANGUAGE_TEXT, LANGUAGE_LONGTEXT, false)
147 change_private()
148 change_safe()
150 add_integer("imem-samplerate", 0, SAMPLERATE_TEXT, SAMPLERATE_LONGTEXT, true)
151 change_private()
152 change_safe()
153 add_integer("imem-channels", 0, CHANNELS_TEXT, CHANNELS_LONGTEXT, true)
154 change_private()
155 change_safe()
157 add_integer("imem-width", 0, WIDTH_TEXT, WIDTH_LONGTEXT, true)
158 change_private()
159 change_safe()
160 add_integer("imem-height", 0, HEIGHT_TEXT, HEIGHT_LONGTEXT, true)
161 change_private()
162 change_safe()
163 add_string ("imem-dar", NULL, DAR_TEXT, DAR_LONGTEXT, true)
164 change_private()
165 change_safe()
166 add_string ("imem-fps", NULL, FPS_TEXT, FPS_LONGTEXT, true)
167 change_private()
168 change_safe()
170 add_integer ("imem-size", 0, SIZE_TEXT, SIZE_LONGTEXT, true)
171 change_private()
172 change_safe()
174 add_shortcut("imem")
175 set_capability("access", 1)
176 set_callbacks(OpenDemux, CloseDemux)
178 add_submodule()
179 add_shortcut("imem")
180 set_capability("access", 0)
181 set_callbacks(OpenAccess, CloseAccess)
182 vlc_module_end()
184 /*****************************************************************************
185 * Exported API
186 *****************************************************************************/
188 /* The clock origin for the DTS and PTS is assumed to be 0.
189 * A negative value means unknown.
191 * TODO define flags
193 typedef int (*imem_get_t)(void *data, const char *cookie,
194 int64_t *dts, int64_t *pts, unsigned *flags,
195 size_t *, void **);
196 typedef void (*imem_release_t)(void *data, const char *cookie, size_t, void *);
198 /*****************************************************************************
199 * Local prototypes
200 *****************************************************************************/
202 /* */
203 static block_t *Block(stream_t *, bool *);
204 static int ControlAccess(stream_t *, int, va_list);
206 static int Demux(demux_t *);
207 static int ControlDemux(demux_t *, int, va_list);
209 /* */
210 typedef struct {
211 struct {
212 imem_get_t get;
213 imem_release_t release;
214 void *data;
215 char *cookie;
216 } source;
218 es_out_id_t *es;
220 vlc_tick_t dts;
222 vlc_tick_t deadline;
223 } imem_sys_t;
225 static void ParseMRL(vlc_object_t *, const char *);
228 * It closes the common part of the access and access_demux
230 static void CloseCommon(imem_sys_t *sys)
232 free(sys->source.cookie);
236 * It initializes the common part for imem access/access_demux.
238 static int OpenCommon(vlc_object_t *object, imem_sys_t **sys_ptr, const char *psz_path)
240 char *tmp;
242 /* */
243 imem_sys_t *sys = vlc_obj_calloc(object, 1, sizeof(*sys));
244 if (!sys)
245 return VLC_ENOMEM;
247 /* Read the user functions */
248 tmp = var_InheritString(object, "imem-get");
249 if (tmp)
250 sys->source.get = (imem_get_t)(intptr_t)strtoll(tmp, NULL, 0);
251 free(tmp);
253 tmp = var_InheritString(object, "imem-release");
254 if (tmp)
255 sys->source.release = (imem_release_t)(intptr_t)strtoll(tmp, NULL, 0);
256 free(tmp);
258 if (!sys->source.get || !sys->source.release) {
259 msg_Err(object, "Invalid get/release function pointers");
260 return VLC_EGENERIC;
263 tmp = var_InheritString(object, "imem-data");
264 if (tmp)
265 sys->source.data = (void *)(uintptr_t)strtoull(tmp, NULL, 0);
266 free(tmp);
268 /* Now we can parse the MRL (get/release must not be parsed to avoid
269 * security risks) */
270 if (*psz_path)
271 ParseMRL(object, psz_path);
273 sys->source.cookie = var_InheritString(object, "imem-cookie");
275 msg_Dbg(object, "Using get(%p), release(%p), data(%p), cookie(%s)",
276 (void *)sys->source.get, (void *)sys->source.release,
277 sys->source.data,
278 sys->source.cookie ? sys->source.cookie : "(null)");
280 /* */
281 sys->dts = 0;
282 sys->deadline = VLC_TICK_INVALID;
284 *sys_ptr = sys;
285 return VLC_SUCCESS;
289 * It opens an imem access.
291 static int OpenAccess(vlc_object_t *object)
293 stream_t *access = (stream_t *)object;
294 imem_sys_t *sys;
296 if (OpenCommon(object, &sys, access->psz_location))
297 return VLC_EGENERIC;
299 if (var_InheritInteger(object, "imem-cat") != 4) {
300 CloseCommon(sys);
301 return VLC_EGENERIC;
304 /* */
305 access->pf_control = ControlAccess;
306 access->pf_read = NULL;
307 access->pf_block = Block;
308 access->pf_seek = NULL;
309 access->p_sys = sys;
311 return VLC_SUCCESS;
315 * It closes an imem access
317 static void CloseAccess(vlc_object_t *object)
319 stream_t *access = (stream_t *)object;
321 CloseCommon((imem_sys_t*)access->p_sys);
325 * It controls an imem access
327 static int ControlAccess(stream_t *access, int i_query, va_list args)
329 (void) access;
330 switch (i_query)
332 case STREAM_CAN_SEEK:
333 case STREAM_CAN_FASTSEEK: {
334 bool *b = va_arg( args, bool* );
335 *b = false;
336 return VLC_SUCCESS;
338 case STREAM_CAN_PAUSE:
339 case STREAM_CAN_CONTROL_PACE: {
340 bool *b = va_arg( args, bool* );
341 *b = true;
342 return VLC_SUCCESS;
344 case STREAM_GET_SIZE: {
345 uint64_t *s = va_arg(args, uint64_t *);
346 *s = var_InheritInteger(access, "imem-size");
347 return *s ? VLC_SUCCESS : VLC_EGENERIC;
349 case STREAM_GET_PTS_DELAY:
350 *va_arg(args, vlc_tick_t *) = DEFAULT_PTS_DELAY; /* FIXME? */
351 return VLC_SUCCESS;
353 case STREAM_SET_PAUSE_STATE:
354 return VLC_SUCCESS;
356 default:
357 return VLC_EGENERIC;
362 * It retreives data using the get() callback, copies them,
363 * and then release them using the release() callback.
365 static block_t *Block(stream_t *access, bool *restrict eof)
367 imem_sys_t *sys = (imem_sys_t*)access->p_sys;
369 unsigned flags;
370 size_t buffer_size;
371 void *buffer;
373 if (sys->source.get(sys->source.data, sys->source.cookie,
374 NULL, NULL, &flags, &buffer_size, &buffer)) {
375 *eof = true;
376 return NULL;
379 block_t *block = NULL;
380 if (buffer_size > 0) {
381 block = block_Alloc(buffer_size);
382 if (block)
383 memcpy(block->p_buffer, buffer, buffer_size);
386 sys->source.release(sys->source.data, sys->source.cookie,
387 buffer_size, buffer);
388 return block;
391 static inline int GetCategory(vlc_object_t *object)
393 const int cat = var_InheritInteger(object, "imem-cat");
394 switch (cat)
396 case 1:
397 return AUDIO_ES;
398 case 2:
399 return VIDEO_ES;
400 case 3:
401 return SPU_ES;
402 default:
403 msg_Err(object, "Invalid ES category");
404 /* fall through */
405 case 4:
406 return UNKNOWN_ES;
411 * It opens an imem access_demux.
413 static int OpenDemux(vlc_object_t *object)
415 demux_t *demux = (demux_t *)object;
416 imem_sys_t *sys;
418 if (demux->out == NULL)
419 return VLC_EGENERIC;
421 if (OpenCommon(object, &sys, demux->psz_location))
422 return VLC_EGENERIC;
424 /* ES format */
425 es_format_t fmt;
426 es_format_Init(&fmt, GetCategory(object), 0);
428 fmt.i_id = var_InheritInteger(object, "imem-id");
429 fmt.i_group = var_InheritInteger(object, "imem-group");
431 char *tmp = var_InheritString(object, "imem-codec");
432 if (tmp)
433 fmt.i_codec = vlc_fourcc_GetCodecFromString(fmt.i_cat, tmp);
434 free(tmp);
436 switch (fmt.i_cat) {
437 case AUDIO_ES: {
438 fmt.audio.i_channels = var_InheritInteger(object, "imem-channels");
439 fmt.audio.i_rate = var_InheritInteger(object, "imem-samplerate");
441 msg_Dbg(object, "Audio %4.4s %d channels %d Hz",
442 (const char *)&fmt.i_codec,
443 fmt.audio.i_channels, fmt.audio.i_rate);
444 break;
446 case VIDEO_ES: {
447 fmt.video.i_width = var_InheritInteger(object, "imem-width");
448 fmt.video.i_height = var_InheritInteger(object, "imem-height");
449 unsigned num, den;
450 if (!var_InheritURational(object, &num, &den, "imem-dar") && num > 0 && den > 0) {
451 if (fmt.video.i_width != 0 && fmt.video.i_height != 0) {
452 fmt.video.i_sar_num = num * fmt.video.i_height;
453 fmt.video.i_sar_den = den * fmt.video.i_width;
456 if (!var_InheritURational(object, &num, &den, "imem-fps") && num > 0 && den > 0) {
457 fmt.video.i_frame_rate = num;
458 fmt.video.i_frame_rate_base = den;
461 msg_Dbg(object, "Video %4.4s %dx%d SAR %d:%d frame rate %u/%u",
462 (const char *)&fmt.i_codec,
463 fmt.video.i_width, fmt.video.i_height,
464 fmt.video.i_sar_num, fmt.video.i_sar_den,
465 fmt.video.i_frame_rate, fmt.video.i_frame_rate_base);
466 break;
468 case SPU_ES: {
469 fmt.subs.spu.i_original_frame_width =
470 var_InheritInteger(object, "imem-width");
471 fmt.subs.spu.i_original_frame_height =
472 var_InheritInteger(object, "imem-height");
474 msg_Dbg(object, "Subtitle %4.4s",
475 (const char *)&fmt.i_codec);
476 break;
478 default:
479 es_format_Clean(&fmt);
480 CloseCommon(sys);
481 return VLC_EGENERIC;
484 fmt.psz_language = var_InheritString(object, "imem-language");
486 sys->es = es_out_Add(demux->out, &fmt);
487 es_format_Clean(&fmt);
489 if (!sys->es) {
490 CloseCommon(sys);
491 return VLC_EGENERIC;
494 /* */
495 demux->pf_control = ControlDemux;
496 demux->pf_demux = Demux;
497 demux->p_sys = sys;
499 return VLC_SUCCESS;
503 * It closes an imem access_demux
505 static void CloseDemux(vlc_object_t *object)
507 demux_t *demux = (demux_t *)object;
509 CloseCommon((imem_sys_t*)demux->p_sys);
513 * It controls an imem access_demux
515 static int ControlDemux(demux_t *demux, int i_query, va_list args)
517 imem_sys_t *sys = (imem_sys_t*)demux->p_sys;
519 switch (i_query)
521 case DEMUX_CAN_PAUSE:
522 case DEMUX_CAN_CONTROL_PACE: {
523 bool *b = va_arg(args, bool *);
524 *b = true;
525 return VLC_SUCCESS;
527 case DEMUX_SET_PAUSE_STATE:
528 return VLC_SUCCESS;
530 case DEMUX_GET_PTS_DELAY: {
531 *va_arg(args, vlc_tick_t *) = DEFAULT_PTS_DELAY; /* FIXME? */
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, vlc_tick_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_TICK_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_Alloc(buffer_size);
594 if (block) {
595 block->i_dts = dts >= 0 ? (1 + dts) : VLC_TICK_INVALID;
596 block->i_pts = pts >= 0 ? (1 + pts) : VLC_TICK_INVALID;
597 memcpy(block->p_buffer, buffer, buffer_size);
599 es_out_SetPCR(demux->out, 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_TICK_INVALID;
610 return 1;
614 * Parse the MRL and extract configuration from it.
616 * Syntax: option1=value1[:option2=value2[...]]
618 * XXX get and release are not supported on purpose.
620 static void ParseMRL(vlc_object_t *object, const char *psz_path)
622 static const struct {
623 const char *name;
624 int type;
625 } options[] = {
626 { "id", VLC_VAR_INTEGER },
627 { "group", VLC_VAR_INTEGER },
628 { "cat", VLC_VAR_INTEGER },
629 { "samplerate", VLC_VAR_INTEGER },
630 { "channels", VLC_VAR_INTEGER },
631 { "width", VLC_VAR_INTEGER },
632 { "height", VLC_VAR_INTEGER },
633 { "cookie", VLC_VAR_STRING },
634 { "codec", VLC_VAR_STRING },
635 { "language", VLC_VAR_STRING },
636 { "dar", VLC_VAR_STRING },
637 { "fps", VLC_VAR_STRING },
638 { NULL, -1 }
641 char *dup = strdup(psz_path);
642 if (!dup)
643 return;
644 char *current = dup;
646 while (current) {
647 char *next = strchr(current, ':');
648 if (next)
649 *next++ = '\0';
651 char *option = current;
652 char *value = strchr(current, '=');
653 if (value) {
654 *value++ = '\0';
655 msg_Dbg(object, "option '%s' value '%s'", option, value);
656 } else {
657 msg_Dbg(object, "option '%s' without value (unsupported)", option);
660 char *name;
661 if (asprintf(&name, "imem-%s", option) < 0)
662 name = NULL;
663 for (unsigned i = 0; name && options[i].name; i++) {
664 if (strcmp(options[i].name, option))
665 continue;
666 /* */
667 var_Create(object, name, options[i].type | VLC_VAR_DOINHERIT);
668 if (options[i].type == VLC_VAR_INTEGER && value) {
669 var_SetInteger(object, name, strtol(value, NULL, 0));
670 } else if (options[i].type == VLC_VAR_STRING && value) {
671 var_SetString(object, name, value);
673 break;
675 free(name);
677 /* */
678 current = next;
680 free(dup);