1 /*****************************************************************************
2 * imem.c : Memory input for VLC
3 *****************************************************************************
4 * Copyright (C) 2009 Laurent Aimar
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 /*****************************************************************************
26 *****************************************************************************/
34 #include <vlc_common.h>
35 #include <vlc_plugin.h>
36 #include <vlc_demux.h>
37 #include <vlc_charset.h>
39 /*****************************************************************************
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
[] = {
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")
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)
122 add_string ("imem-get", "0", NULL
, GET_TEXT
, GET_LONGTEXT
, true)
124 add_string ("imem-release", "0", NULL
, RELEASE_TEXT
, RELEASE_LONGTEXT
, true)
126 add_string ("imem-cookie", NULL
, NULL
, COOKIE_TEXT
, COOKIE_LONGTEXT
, true)
129 add_string ("imem-data", "0", NULL
, DATA_TEXT
, DATA_LONGTEXT
, true)
132 add_integer("imem-id", -1, NULL
, ID_TEXT
, ID_LONGTEXT
, true)
135 add_integer("imem-group", 0, NULL
, GROUP_TEXT
, GROUP_LONGTEXT
, true)
138 add_integer("imem-cat", 0, NULL
, CAT_TEXT
, CAT_LONGTEXT
, true)
139 change_integer_list(cat_values
, cat_texts
, NULL
)
142 add_string ("imem-codec", NULL
, NULL
, CODEC_TEXT
, CODEC_LONGTEXT
, true)
145 add_string( "imem-language", NULL
, NULL
, LANGUAGE_TEXT
, LANGUAGE_LONGTEXT
, false)
149 add_integer("imem-samplerate", 0, NULL
, SAMPLERATE_TEXT
, SAMPLERATE_LONGTEXT
, true)
152 add_integer("imem-channels", 0, NULL
, CHANNELS_TEXT
, CHANNELS_LONGTEXT
, true)
156 add_integer("imem-width", 0, NULL
, WIDTH_TEXT
, WIDTH_LONGTEXT
, true)
159 add_integer("imem-height", 0, NULL
, HEIGHT_TEXT
, HEIGHT_LONGTEXT
, true)
162 add_string ("imem-dar", NULL
, NULL
, DAR_TEXT
, DAR_LONGTEXT
, true)
165 add_string ("imem-fps", NULL
, NULL
, FPS_TEXT
, FPS_LONGTEXT
, true)
170 set_capability("access_demux", 0)
171 set_callbacks(Open
, Close
)
174 /*****************************************************************************
176 *****************************************************************************/
178 /* The clock origin for the DTS and PTS is assumed to be 0.
179 * A negative value means unknown.
183 typedef int (*imem_get_t
)(void *data
, const char *cookie
,
184 int64_t *dts
, int64_t *pts
, unsigned *flags
,
186 typedef void (*imem_release_t
)(void *data
, const char *cookie
, size_t, void *);
188 /*****************************************************************************
190 *****************************************************************************/
193 static int Demux(demux_t
*);
194 static int Control(demux_t
*, int, va_list);
200 imem_release_t release
;
214 static void ParseMRL(demux_t
*);
215 static int var_CreateGetRational(demux_t
*,
216 unsigned *num
, unsigned *den
,
220 * It opens an imem access_demux
222 static int Open(vlc_object_t
*object
)
224 demux_t
*demux
= (demux_t
*)object
;
228 demux_sys_t
*sys
= calloc(1, sizeof(*sys
));
232 /* Read the user functions */
233 tmp
= var_CreateGetString(demux
, "imem-get");
235 sys
->source
.get
= (imem_get_t
)(intptr_t)strtoll(tmp
, NULL
, 0);
238 tmp
= var_CreateGetString(demux
, "imem-release");
240 sys
->source
.release
= (imem_release_t
)(intptr_t)strtoll(tmp
, NULL
, 0);
243 if (!sys
->source
.get
|| !sys
->source
.release
) {
244 msg_Err(demux
, "Invalid get/release function pointers");
249 tmp
= var_CreateGetString(demux
, "imem-data");
251 sys
->source
.data
= (void *)(uintptr_t)strtoull(tmp
, NULL
, 0);
254 /* Now we can parse the MRL (get/release must not be parsed to avoid
256 if (*demux
->psz_path
)
259 /* Now we can parse the MRL (get/release must not be parsed to avoid
261 if (*demux
->psz_path
)
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)");
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");
279 fmt
.i_codec
= vlc_fourcc_GetCodecFromString(UNKNOWN_ES
, tmp
);
282 switch (var_CreateGetInteger(demux
, "imem-cat")) {
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
);
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");
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
);
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
);
328 msg_Err(demux
, "Invalid ES category");
329 es_format_Clean(&fmt
);
334 fmt
.psz_language
= var_CreateGetString(demux
, "imem-language");
337 sys
->es
= es_out_Add(demux
->out
, &fmt
);
338 es_format_Clean(&fmt
);
341 free(sys
->source
.data
);
347 sys
->pts_delay
= var_CreateGetInteger(demux
, "imem-caching") * INT64_C(1000);
349 sys
->deadline
= VLC_TS_INVALID
;
352 demux
->pf_control
= Control
;
353 demux
->pf_demux
= Demux
;
356 demux
->info
.i_update
= 0;
357 demux
->info
.i_title
= 0;
358 demux
->info
.i_seekpoint
= 0;
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
);
377 static int Control(demux_t
*demux
, int i_query
, va_list args
)
379 demux_sys_t
*sys
= demux
->p_sys
;
383 case DEMUX_CAN_PAUSE
:
384 case DEMUX_CAN_CONTROL_PACE
: {
385 bool *b
= va_arg(args
, bool *);
389 case DEMUX_SET_PAUSE_STATE
:
392 case DEMUX_GET_PTS_DELAY
: {
393 int64_t *delay
= va_arg(args
, int64_t *);
394 *delay
= sys
->pts_delay
;
397 case DEMUX_GET_POSITION
: {
398 double *position
= va_arg(args
, double *);
402 case DEMUX_GET_TIME
: {
403 int64_t *t
= va_arg(args
, int64_t *);
407 case DEMUX_GET_LENGTH
: {
408 int64_t *l
= va_arg(args
, int64_t *);
412 case DEMUX_SET_NEXT_DEMUX_TIME
:
413 sys
->deadline
= va_arg(args
, int64_t);
418 case DEMUX_SET_POSITION
:
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;
439 if (sys
->deadline
<= sys
->dts
)
448 if (sys
->source
.get(sys
->source
.data
, sys
->source
.cookie
,
449 &dts
, &pts
, &flags
, &buffer_size
, &buffer
))
455 if (buffer_size
> 0) {
456 block_t
*block
= block_New(demux
, buffer_size
);
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
);
469 sys
->source
.release(sys
->source
.data
, sys
->source
.cookie
,
470 buffer_size
, buffer
);
472 sys
->deadline
= VLC_TS_INVALID
;
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
,
490 char *tmp
= var_CreateGetString(demux
, var
);
495 unsigned n
= strtol(tmp
, &next
, 0);
496 unsigned d
= strtol(*next
? &next
[1] : "0", NULL
, 0);
499 /* Interpret as a float number */
500 double r
= us_atof(tmp
);
515 vlc_ureduce(num
, den
, n
, d
, 0);
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 {
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
},
554 char *dup
= strdup(demux
->psz_path
);
560 char *next
= strchr(current
, ':');
564 char *option
= current
;
565 char *value
= strchr(current
, '=');
568 msg_Dbg(demux
, "option '%s' value '%s'", option
, value
);
570 msg_Dbg(demux
, "option '%s' without value (unsupported)", option
);
574 if (asprintf(&name
, "imem-%s", option
) < 0)
576 for (unsigned i
= 0; name
&& options
[i
].name
; i
++) {
577 if (strcmp(options
[i
].name
, option
))
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
);