1 /*****************************************************************************
2 * imem.c : Memory input for VLC
3 *****************************************************************************
4 * Copyright (C) 2009-2010 Laurent Aimar
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 /*****************************************************************************
26 *****************************************************************************/
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 /*****************************************************************************
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[] = {
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")
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)
125 add_string ("imem-release", "0", RELEASE_TEXT, RELEASE_LONGTEXT, true)
127 add_string ("imem-cookie", NULL, COOKIE_TEXT, COOKIE_LONGTEXT, true)
130 add_string ("imem-data", "0", DATA_TEXT, DATA_LONGTEXT, true)
133 add_integer("imem-id", -1, ID_TEXT, ID_LONGTEXT, true)
136 add_integer("imem-group", 0, GROUP_TEXT, GROUP_LONGTEXT, true)
139 add_integer("imem-cat", 0, CAT_TEXT, CAT_LONGTEXT, true)
140 change_integer_list(cat_values, cat_texts)
143 add_string ("imem-codec", NULL, CODEC_TEXT, CODEC_LONGTEXT, true)
146 add_string( "imem-language", NULL, LANGUAGE_TEXT, LANGUAGE_LONGTEXT, false)
150 add_integer("imem-samplerate", 0, SAMPLERATE_TEXT, SAMPLERATE_LONGTEXT, true)
153 add_integer("imem-channels", 0, CHANNELS_TEXT, CHANNELS_LONGTEXT, true)
157 add_integer("imem-width", 0, WIDTH_TEXT, WIDTH_LONGTEXT, true)
160 add_integer("imem-height", 0, HEIGHT_TEXT, HEIGHT_LONGTEXT, true)
163 add_string ("imem-dar", NULL, DAR_TEXT, DAR_LONGTEXT, true)
166 add_string ("imem-fps", NULL, FPS_TEXT, FPS_LONGTEXT, true)
170 add_integer ("imem-size", 0, SIZE_TEXT, SIZE_LONGTEXT, true)
175 set_capability("access_demux", 0)
176 set_callbacks(OpenDemux, CloseDemux)
180 set_capability("access", 0)
181 set_callbacks(OpenAccess, CloseAccess)
184 /*****************************************************************************
186 *****************************************************************************/
188 /* The clock origin for the DTS and PTS is assumed to be 0.
189 * A negative value means unknown.
193 typedef int (*imem_get_t)(void *data, const char *cookie,
194 int64_t *dts, int64_t *pts, unsigned *flags,
196 typedef void (*imem_release_t)(void *data, const char *cookie, size_t, void *);
198 /*****************************************************************************
200 *****************************************************************************/
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);
213 imem_release_t release;
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);
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)
244 imem_sys_t *sys = calloc(1, sizeof(*sys));
248 /* Read the user functions */
249 tmp = var_InheritString(object, "imem-get");
251 sys->source.get = (imem_get_t)(intptr_t)strtoll(tmp, NULL, 0);
254 tmp = var_InheritString(object, "imem-release");
256 sys->source.release = (imem_release_t)(intptr_t)strtoll(tmp, NULL, 0);
259 if (!sys->source.get || !sys->source.release) {
260 msg_Err(object, "Invalid get/release function pointers");
265 tmp = var_InheritString(object, "imem-data");
267 sys->source.data = (void *)(uintptr_t)strtoull(tmp, NULL, 0);
270 /* Now we can parse the MRL (get/release must not be parsed to avoid
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)");
283 sys->deadline = VLC_TS_INVALID;
290 * It opens an imem access.
292 static int OpenAccess(vlc_object_t *object)
294 access_t *access = (access_t *)object;
297 if (OpenCommon(object, &sys, access->psz_location))
300 if (var_InheritInteger(object, "imem-cat") != 4) {
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;
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)
334 case ACCESS_CAN_SEEK:
335 case ACCESS_CAN_FASTSEEK: {
336 bool *b = va_arg( args, bool* );
340 case ACCESS_CAN_PAUSE:
341 case ACCESS_CAN_CONTROL_PACE: {
342 bool *b = va_arg( args, bool* );
346 case ACCESS_GET_SIZE: {
347 uint64_t *s = va_arg(args, uint64_t *);
348 *s = var_InheritInteger(access, "imem-size");
351 case ACCESS_GET_PTS_DELAY: {
352 int64_t *delay = va_arg(args, int64_t *);
353 *delay = DEFAULT_PTS_DELAY; /* FIXME? */
356 case ACCESS_SET_PAUSE_STATE:
359 case ACCESS_GET_TITLE_INFO:
360 case ACCESS_SET_TITLE:
361 case ACCESS_SET_SEEKPOINT:
362 case ACCESS_SET_PRIVATE_ID_STATE:
363 case ACCESS_GET_META:
364 case ACCESS_GET_PRIVATE_ID_STATE:
365 case ACCESS_GET_CONTENT_TYPE:
372 * It retreives data using the get() callback, copies them,
373 * and then release them using the release() callback.
375 static block_t *Block(access_t *access)
377 imem_sys_t *sys = (imem_sys_t*)access->p_sys;
383 if (sys->source.get(sys->source.data, sys->source.cookie,
384 NULL, NULL, &flags, &buffer_size, &buffer)) {
385 access->info.b_eof = true;
389 block_t *block = NULL;
390 if (buffer_size > 0) {
391 block = block_Alloc(buffer_size);
393 memcpy(block->p_buffer, buffer, buffer_size);
396 sys->source.release(sys->source.data, sys->source.cookie,
397 buffer_size, buffer);
402 * It opens an imem access_demux.
404 static int OpenDemux(vlc_object_t *object)
406 demux_t *demux = (demux_t *)object;
409 if (OpenCommon(object, &sys, demux->psz_location))
414 es_format_Init(&fmt, UNKNOWN_ES, 0);
416 fmt.i_id = var_InheritInteger(object, "imem-id");
417 fmt.i_group = var_InheritInteger(object, "imem-group");
419 char *tmp = var_InheritString(object, "imem-codec");
421 fmt.i_codec = vlc_fourcc_GetCodecFromString(UNKNOWN_ES, tmp);
424 const int cat = var_InheritInteger(object, "imem-cat");
427 fmt.i_cat = AUDIO_ES;
428 fmt.audio.i_channels = var_InheritInteger(object, "imem-channels");
429 fmt.audio.i_rate = var_InheritInteger(object, "imem-samplerate");
431 msg_Dbg(object, "Audio %4.4s %d channels %d Hz",
432 (const char *)&fmt.i_codec,
433 fmt.audio.i_channels, fmt.audio.i_rate);
437 fmt.i_cat = VIDEO_ES;
438 fmt.video.i_width = var_InheritInteger(object, "imem-width");
439 fmt.video.i_height = var_InheritInteger(object, "imem-height");
441 if (!var_InheritURational(object, &num, &den, "imem-dar") && num > 0 && den > 0) {
442 if (fmt.video.i_width > 0 && fmt.video.i_height > 0) {
443 fmt.video.i_sar_num = num * fmt.video.i_height;
444 fmt.video.i_sar_den = den * fmt.video.i_width;
447 if (!var_InheritURational(object, &num, &den, "imem-fps") && num > 0 && den > 0) {
448 fmt.video.i_frame_rate = num;
449 fmt.video.i_frame_rate_base = den;
452 msg_Dbg(object, "Video %4.4s %dx%d SAR %d:%d frame rate %u/%u",
453 (const char *)&fmt.i_codec,
454 fmt.video.i_width, fmt.video.i_height,
455 fmt.video.i_sar_num, fmt.video.i_sar_den,
456 fmt.video.i_frame_rate, fmt.video.i_frame_rate_base);
461 fmt.subs.spu.i_original_frame_width =
462 var_InheritInteger(object, "imem-width");
463 fmt.subs.spu.i_original_frame_height =
464 var_InheritInteger(object, "imem-height");
466 msg_Dbg(object, "Subtitle %4.4s",
467 (const char *)&fmt.i_codec);
472 msg_Err(object, "Invalid ES category");
473 es_format_Clean(&fmt);
478 fmt.psz_language = var_InheritString(object, "imem-language");
480 sys->es = es_out_Add(demux->out, &fmt);
481 es_format_Clean(&fmt);
489 demux->pf_control = ControlDemux;
490 demux->pf_demux = Demux;
491 demux->p_sys = (demux_sys_t*)sys;
493 demux->info.i_update = 0;
494 demux->info.i_title = 0;
495 demux->info.i_seekpoint = 0;
500 * It closes an imem access_demux
502 static void CloseDemux(vlc_object_t *object)
504 demux_t *demux = (demux_t *)object;
506 CloseCommon((imem_sys_t*)demux->p_sys);
510 * It controls an imem access_demux
512 static int ControlDemux(demux_t *demux, int i_query, va_list args)
514 imem_sys_t *sys = (imem_sys_t*)demux->p_sys;
518 case DEMUX_CAN_PAUSE:
519 case DEMUX_CAN_CONTROL_PACE: {
520 bool *b = va_arg(args, bool *);
524 case DEMUX_SET_PAUSE_STATE:
527 case DEMUX_GET_PTS_DELAY: {
528 int64_t *delay = va_arg(args, int64_t *);
529 *delay = DEFAULT_PTS_DELAY; /* FIXME? */
532 case DEMUX_GET_POSITION: {
533 double *position = va_arg(args, double *);
537 case DEMUX_GET_TIME: {
538 int64_t *t = va_arg(args, int64_t *);
542 case DEMUX_GET_LENGTH: {
543 int64_t *l = va_arg(args, int64_t *);
547 case DEMUX_SET_NEXT_DEMUX_TIME:
548 sys->deadline = va_arg(args, int64_t);
553 case DEMUX_SET_POSITION:
563 * It retreives data using the get() callback, sends them to es_out
564 * and the release it using the release() callback.
566 static int Demux(demux_t *demux)
568 imem_sys_t *sys = (imem_sys_t*)demux->p_sys;
570 if (sys->deadline == VLC_TS_INVALID)
571 sys->deadline = sys->dts + 1;
574 if (sys->deadline <= sys->dts)
583 if (sys->source.get(sys->source.data, sys->source.cookie,
584 &dts, &pts, &flags, &buffer_size, &buffer))
590 if (buffer_size > 0) {
591 block_t *block = block_Alloc(buffer_size);
593 block->i_dts = dts >= 0 ? (1 + dts) : VLC_TS_INVALID;
594 block->i_pts = pts >= 0 ? (1 + pts) : VLC_TS_INVALID;
595 memcpy(block->p_buffer, buffer, buffer_size);
597 es_out_Control(demux->out, ES_OUT_SET_PCR, block->i_dts);
598 es_out_Send(demux->out, sys->es, block);
604 sys->source.release(sys->source.data, sys->source.cookie,
605 buffer_size, buffer);
607 sys->deadline = VLC_TS_INVALID;
612 * Parse the MRL and extract configuration from it.
614 * Syntax: option1=value1[:option2=value2[...]]
616 * XXX get and release are not supported on purpose.
618 static void ParseMRL(vlc_object_t *object, const char *psz_path)
620 static const struct {
624 { "id", VLC_VAR_INTEGER },
625 { "group", VLC_VAR_INTEGER },
626 { "cat", VLC_VAR_INTEGER },
627 { "samplerate", VLC_VAR_INTEGER },
628 { "channels", VLC_VAR_INTEGER },
629 { "width", VLC_VAR_INTEGER },
630 { "height", VLC_VAR_INTEGER },
631 { "cookie", VLC_VAR_STRING },
632 { "codec", VLC_VAR_STRING },
633 { "language", VLC_VAR_STRING },
634 { "dar", VLC_VAR_STRING },
635 { "fps", VLC_VAR_STRING },
639 char *dup = strdup(psz_path);
645 char *next = strchr(current, ':');
649 char *option = current;
650 char *value = strchr(current, '=');
653 msg_Dbg(object, "option '%s' value '%s'", option, value);
655 msg_Dbg(object, "option '%s' without value (unsupported)", option);
659 if (asprintf(&name, "imem-%s", option) < 0)
661 for (unsigned i = 0; name && options[i].name; i++) {
662 if (strcmp(options[i].name, option))
665 var_Create(object, name, options[i].type | VLC_VAR_DOINHERIT);
666 if (options[i].type == VLC_VAR_INTEGER && value) {
667 var_SetInteger(object, name, strtol(value, NULL, 0));
668 } else if (options[i].type == VLC_VAR_STRING && value) {
669 var_SetString(object, name, value);