A little more detail regarding using my github copies of the code with where it's...
[vlc/adversarial.git] / modules / access / imem.c
blob5b4b05600b052ce1ce928aa2c51f9ec4e909bed1
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_demux", 0)
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(access_t *);
204 static int ControlAccess(access_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 mtime_t dts;
222 mtime_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);
233 free(sys);
237 * It initializes the common part for imem access/access_demux.
239 static int OpenCommon(vlc_object_t *object, imem_sys_t **sys_ptr, const char *psz_path)
241 char *tmp;
243 /* */
244 imem_sys_t *sys = calloc(1, sizeof(*sys));
245 if (!sys)
246 return VLC_ENOMEM;
248 /* Read the user functions */
249 tmp = var_InheritString(object, "imem-get");
250 if (tmp)
251 sys->source.get = (imem_get_t)(intptr_t)strtoll(tmp, NULL, 0);
252 free(tmp);
254 tmp = var_InheritString(object, "imem-release");
255 if (tmp)
256 sys->source.release = (imem_release_t)(intptr_t)strtoll(tmp, NULL, 0);
257 free(tmp);
259 if (!sys->source.get || !sys->source.release) {
260 msg_Err(object, "Invalid get/release function pointers");
261 free(sys);
262 return VLC_EGENERIC;
265 tmp = var_InheritString(object, "imem-data");
266 if (tmp)
267 sys->source.data = (void *)(uintptr_t)strtoull(tmp, NULL, 0);
268 free(tmp);
270 /* Now we can parse the MRL (get/release must not be parsed to avoid
271 * security risks) */
272 if (*psz_path)
273 ParseMRL(object, psz_path);
275 sys->source.cookie = var_InheritString(object, "imem-cookie");
277 msg_Dbg(object, "Using get(%p), release(%p), data(%p), cookie(%s)",
278 sys->source.get, sys->source.release, sys->source.data,
279 sys->source.cookie ? sys->source.cookie : "(null)");
281 /* */
282 sys->dts = 0;
283 sys->deadline = VLC_TS_INVALID;
285 *sys_ptr = sys;
286 return VLC_SUCCESS;
290 * It opens an imem access.
292 static int OpenAccess(vlc_object_t *object)
294 access_t *access = (access_t *)object;
295 imem_sys_t *sys;
297 if (OpenCommon(object, &sys, access->psz_location))
298 return VLC_EGENERIC;
300 if (var_InheritInteger(object, "imem-cat") != 4) {
301 CloseCommon(sys);
302 return VLC_EGENERIC;
305 /* */
306 access_InitFields(access);
307 access->pf_control = ControlAccess;
308 access->pf_read = NULL;
309 access->pf_block = Block;
310 access->pf_seek = NULL;
311 access->p_sys = (access_sys_t*)sys;
313 return VLC_SUCCESS;
317 * It closes an imem access
319 static void CloseAccess(vlc_object_t *object)
321 access_t *access = (access_t *)object;
323 CloseCommon((imem_sys_t*)access->p_sys);
327 * It controls an imem access
329 static int ControlAccess(access_t *access, int i_query, va_list args)
331 (void) access;
332 switch (i_query)
334 case ACCESS_CAN_SEEK:
335 case ACCESS_CAN_FASTSEEK: {
336 bool *b = va_arg( args, bool* );
337 *b = false;
338 return VLC_SUCCESS;
340 case ACCESS_CAN_PAUSE:
341 case ACCESS_CAN_CONTROL_PACE: {
342 bool *b = va_arg( args, bool* );
343 *b = true;
344 return VLC_SUCCESS;
346 case ACCESS_GET_SIZE: {
347 uint64_t *s = va_arg(args, uint64_t *);
348 *s = var_InheritInteger(access, "imem-size");
349 return VLC_SUCCESS;
351 case ACCESS_GET_PTS_DELAY: {
352 int64_t *delay = va_arg(args, int64_t *);
353 *delay = DEFAULT_PTS_DELAY; /* FIXME? */
354 return VLC_SUCCESS;
356 case ACCESS_SET_PAUSE_STATE:
357 return VLC_SUCCESS;
359 default:
360 return VLC_EGENERIC;
365 * It retreives data using the get() callback, copies them,
366 * and then release them using the release() callback.
368 static block_t *Block(access_t *access)
370 imem_sys_t *sys = (imem_sys_t*)access->p_sys;
372 unsigned flags;
373 size_t buffer_size;
374 void *buffer;
376 if (sys->source.get(sys->source.data, sys->source.cookie,
377 NULL, NULL, &flags, &buffer_size, &buffer)) {
378 access->info.b_eof = true;
379 return NULL;
382 block_t *block = NULL;
383 if (buffer_size > 0) {
384 block = block_Alloc(buffer_size);
385 if (block)
386 memcpy(block->p_buffer, buffer, buffer_size);
389 sys->source.release(sys->source.data, sys->source.cookie,
390 buffer_size, buffer);
391 return block;
395 * It opens an imem access_demux.
397 static int OpenDemux(vlc_object_t *object)
399 demux_t *demux = (demux_t *)object;
400 imem_sys_t *sys;
402 if (OpenCommon(object, &sys, demux->psz_location))
403 return VLC_EGENERIC;
405 /* ES format */
406 es_format_t fmt;
407 es_format_Init(&fmt, UNKNOWN_ES, 0);
409 fmt.i_id = var_InheritInteger(object, "imem-id");
410 fmt.i_group = var_InheritInteger(object, "imem-group");
412 char *tmp = var_InheritString(object, "imem-codec");
413 if (tmp)
414 fmt.i_codec = vlc_fourcc_GetCodecFromString(UNKNOWN_ES, tmp);
415 free(tmp);
417 const int cat = var_InheritInteger(object, "imem-cat");
418 switch (cat) {
419 case 1: {
420 fmt.i_cat = AUDIO_ES;
421 fmt.audio.i_channels = var_InheritInteger(object, "imem-channels");
422 fmt.audio.i_rate = var_InheritInteger(object, "imem-samplerate");
424 msg_Dbg(object, "Audio %4.4s %d channels %d Hz",
425 (const char *)&fmt.i_codec,
426 fmt.audio.i_channels, fmt.audio.i_rate);
427 break;
429 case 2: {
430 fmt.i_cat = VIDEO_ES;
431 fmt.video.i_width = var_InheritInteger(object, "imem-width");
432 fmt.video.i_height = var_InheritInteger(object, "imem-height");
433 unsigned num, den;
434 if (!var_InheritURational(object, &num, &den, "imem-dar") && num > 0 && den > 0) {
435 if (fmt.video.i_width > 0 && fmt.video.i_height > 0) {
436 fmt.video.i_sar_num = num * fmt.video.i_height;
437 fmt.video.i_sar_den = den * fmt.video.i_width;
440 if (!var_InheritURational(object, &num, &den, "imem-fps") && num > 0 && den > 0) {
441 fmt.video.i_frame_rate = num;
442 fmt.video.i_frame_rate_base = den;
445 msg_Dbg(object, "Video %4.4s %dx%d SAR %d:%d frame rate %u/%u",
446 (const char *)&fmt.i_codec,
447 fmt.video.i_width, fmt.video.i_height,
448 fmt.video.i_sar_num, fmt.video.i_sar_den,
449 fmt.video.i_frame_rate, fmt.video.i_frame_rate_base);
450 break;
452 case 3: {
453 fmt.i_cat = SPU_ES;
454 fmt.subs.spu.i_original_frame_width =
455 var_InheritInteger(object, "imem-width");
456 fmt.subs.spu.i_original_frame_height =
457 var_InheritInteger(object, "imem-height");
459 msg_Dbg(object, "Subtitle %4.4s",
460 (const char *)&fmt.i_codec);
461 break;
463 default:
464 if (cat != 4)
465 msg_Err(object, "Invalid ES category");
466 es_format_Clean(&fmt);
467 CloseCommon(sys);
468 return VLC_EGENERIC;
471 fmt.psz_language = var_InheritString(object, "imem-language");
473 sys->es = es_out_Add(demux->out, &fmt);
474 es_format_Clean(&fmt);
476 if (!sys->es) {
477 CloseCommon(sys);
478 return VLC_EGENERIC;
481 /* */
482 demux->pf_control = ControlDemux;
483 demux->pf_demux = Demux;
484 demux->p_sys = (demux_sys_t*)sys;
486 demux->info.i_update = 0;
487 demux->info.i_title = 0;
488 demux->info.i_seekpoint = 0;
489 return VLC_SUCCESS;
493 * It closes an imem access_demux
495 static void CloseDemux(vlc_object_t *object)
497 demux_t *demux = (demux_t *)object;
499 CloseCommon((imem_sys_t*)demux->p_sys);
503 * It controls an imem access_demux
505 static int ControlDemux(demux_t *demux, int i_query, va_list args)
507 imem_sys_t *sys = (imem_sys_t*)demux->p_sys;
509 switch (i_query)
511 case DEMUX_CAN_PAUSE:
512 case DEMUX_CAN_CONTROL_PACE: {
513 bool *b = va_arg(args, bool *);
514 *b = true;
515 return VLC_SUCCESS;
517 case DEMUX_SET_PAUSE_STATE:
518 return VLC_SUCCESS;
520 case DEMUX_GET_PTS_DELAY: {
521 int64_t *delay = va_arg(args, int64_t *);
522 *delay = DEFAULT_PTS_DELAY; /* FIXME? */
523 return VLC_SUCCESS;
525 case DEMUX_GET_POSITION: {
526 double *position = va_arg(args, double *);
527 *position = 0.0;
528 return VLC_SUCCESS;
530 case DEMUX_GET_TIME: {
531 int64_t *t = va_arg(args, int64_t *);
532 *t = sys->dts;
533 return VLC_SUCCESS;
535 case DEMUX_GET_LENGTH: {
536 int64_t *l = va_arg(args, int64_t *);
537 *l = 0;
538 return VLC_SUCCESS;
540 case DEMUX_SET_NEXT_DEMUX_TIME:
541 sys->deadline = va_arg(args, int64_t);
542 return VLC_SUCCESS;
544 /* */
545 case DEMUX_CAN_SEEK:
546 case DEMUX_SET_POSITION:
547 case DEMUX_SET_TIME:
548 default:
549 return VLC_EGENERIC;
552 return VLC_EGENERIC;
556 * It retreives data using the get() callback, sends them to es_out
557 * and the release it using the release() callback.
559 static int Demux(demux_t *demux)
561 imem_sys_t *sys = (imem_sys_t*)demux->p_sys;
563 if (sys->deadline == VLC_TS_INVALID)
564 sys->deadline = sys->dts + 1;
566 for (;;) {
567 if (sys->deadline <= sys->dts)
568 break;
570 /* */
571 int64_t dts, pts;
572 unsigned flags;
573 size_t buffer_size;
574 void *buffer;
576 if (sys->source.get(sys->source.data, sys->source.cookie,
577 &dts, &pts, &flags, &buffer_size, &buffer))
578 return 0;
580 if (dts < 0)
581 dts = pts;
583 if (buffer_size > 0) {
584 block_t *block = block_Alloc(buffer_size);
585 if (block) {
586 block->i_dts = dts >= 0 ? (1 + dts) : VLC_TS_INVALID;
587 block->i_pts = pts >= 0 ? (1 + pts) : VLC_TS_INVALID;
588 memcpy(block->p_buffer, buffer, buffer_size);
590 es_out_Control(demux->out, ES_OUT_SET_PCR, block->i_dts);
591 es_out_Send(demux->out, sys->es, block);
595 sys->dts = dts;
597 sys->source.release(sys->source.data, sys->source.cookie,
598 buffer_size, buffer);
600 sys->deadline = VLC_TS_INVALID;
601 return 1;
605 * Parse the MRL and extract configuration from it.
607 * Syntax: option1=value1[:option2=value2[...]]
609 * XXX get and release are not supported on purpose.
611 static void ParseMRL(vlc_object_t *object, const char *psz_path)
613 static const struct {
614 const char *name;
615 int type;
616 } options[] = {
617 { "id", VLC_VAR_INTEGER },
618 { "group", VLC_VAR_INTEGER },
619 { "cat", VLC_VAR_INTEGER },
620 { "samplerate", VLC_VAR_INTEGER },
621 { "channels", VLC_VAR_INTEGER },
622 { "width", VLC_VAR_INTEGER },
623 { "height", VLC_VAR_INTEGER },
624 { "cookie", VLC_VAR_STRING },
625 { "codec", VLC_VAR_STRING },
626 { "language", VLC_VAR_STRING },
627 { "dar", VLC_VAR_STRING },
628 { "fps", VLC_VAR_STRING },
629 { NULL, -1 }
632 char *dup = strdup(psz_path);
633 if (!dup)
634 return;
635 char *current = dup;
637 while (current) {
638 char *next = strchr(current, ':');
639 if (next)
640 *next++ = '\0';
642 char *option = current;
643 char *value = strchr(current, '=');
644 if (value) {
645 *value++ = '\0';
646 msg_Dbg(object, "option '%s' value '%s'", option, value);
647 } else {
648 msg_Dbg(object, "option '%s' without value (unsupported)", option);
651 char *name;
652 if (asprintf(&name, "imem-%s", option) < 0)
653 name = NULL;
654 for (unsigned i = 0; name && options[i].name; i++) {
655 if (strcmp(options[i].name, option))
656 continue;
657 /* */
658 var_Create(object, name, options[i].type | VLC_VAR_DOINHERIT);
659 if (options[i].type == VLC_VAR_INTEGER && value) {
660 var_SetInteger(object, name, strtol(value, NULL, 0));
661 } else if (options[i].type == VLC_VAR_STRING && value) {
662 var_SetString(object, name, value);
664 break;
666 free(name);
668 /* */
669 current = next;
671 free(dup);