1 /*****************************************************************************
2 * imem.c : Memory input for VLC
3 *****************************************************************************
4 * Copyright (C) 2009-2010 Laurent Aimar
6 * Author: Laurent Aimar <fenrir _AT_ videolan _DOT org>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
23 /*****************************************************************************
25 *****************************************************************************/
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
35 #include <vlc_access.h>
36 #include <vlc_demux.h>
37 #include <vlc_charset.h>
39 /*****************************************************************************
41 *****************************************************************************/
42 static int OpenAccess (vlc_object_t
*);
43 static void CloseAccess(vlc_object_t
*);
45 static int OpenDemux (vlc_object_t
*);
46 static void CloseDemux(vlc_object_t
*);
48 #define ID_TEXT N_("ID")
49 #define ID_LONGTEXT N_(\
50 "Set the ID of the elementary stream")
52 #define GROUP_TEXT N_("Group")
53 #define GROUP_LONGTEXT N_(\
54 "Set the group of the elementary stream")
56 #define CAT_TEXT N_("Category")
57 #define CAT_LONGTEXT N_(\
58 "Set the category of the elementary stream")
59 static const int cat_values
[] = {
62 static const char *cat_texts
[] = {
63 N_("Unknown"), N_("Audio"), N_("Video"), N_("Subtitle"), N_("Data")
66 #define CODEC_TEXT N_("Codec")
67 #define CODEC_LONGTEXT N_(\
68 "Set the codec of the elementary stream")
70 #define LANGUAGE_TEXT N_("Language")
71 #define LANGUAGE_LONGTEXT N_(\
72 "Language of the elementary stream as described by ISO639")
74 #define SAMPLERATE_TEXT N_("Sample rate")
75 #define SAMPLERATE_LONGTEXT N_(\
76 "Sample rate of an audio elementary stream")
78 #define CHANNELS_TEXT N_("Channels count")
79 #define CHANNELS_LONGTEXT N_(\
80 "Channels count of an audio elementary stream")
82 #define WIDTH_TEXT N_("Width")
83 #define WIDTH_LONGTEXT N_("Width of video or subtitle elementary streams")
85 #define HEIGHT_TEXT N_("Height")
86 #define HEIGHT_LONGTEXT N_("Height of video or subtitle elementary streams")
88 #define DAR_TEXT N_("Display aspect ratio")
89 #define DAR_LONGTEXT N_(\
90 "Display aspect ratio of a video elementary stream")
92 #define FPS_TEXT N_("Frame rate")
93 #define FPS_LONGTEXT N_(\
94 "Frame rate of a video elementary stream")
96 #define COOKIE_TEXT N_("Callback cookie string")
97 #define COOKIE_LONGTEXT N_(\
98 "Text identifier for the callback functions")
100 #define DATA_TEXT N_("Callback data")
101 #define DATA_LONGTEXT N_(\
102 "Data for the get and release functions")
104 #define GET_TEXT N_("Get function")
105 #define GET_LONGTEXT N_(\
106 "Address of the get callback function")
108 #define RELEASE_TEXT N_("Release function")
109 #define RELEASE_LONGTEXT N_(\
110 "Address of the release callback function")
112 #define SIZE_TEXT N_("Size")
113 #define SIZE_LONGTEXT N_(\
114 "Size of stream in bytes")
117 set_shortname(N_("Memory input"))
118 set_description(N_("Memory input"))
119 set_category(CAT_INPUT
)
120 set_subcategory(SUBCAT_INPUT_ACCESS
)
122 add_string ("imem-get", "0", GET_TEXT
, GET_LONGTEXT
, true)
124 add_string ("imem-release", "0", RELEASE_TEXT
, RELEASE_LONGTEXT
, true)
126 add_string ("imem-cookie", NULL
, COOKIE_TEXT
, COOKIE_LONGTEXT
, true)
129 add_string ("imem-data", "0", DATA_TEXT
, DATA_LONGTEXT
, true)
132 add_integer("imem-id", -1, ID_TEXT
, ID_LONGTEXT
, true)
135 add_integer("imem-group", 0, GROUP_TEXT
, GROUP_LONGTEXT
, true)
138 add_integer("imem-cat", 0, CAT_TEXT
, CAT_LONGTEXT
, true)
139 change_integer_list(cat_values
, cat_texts
)
142 add_string ("imem-codec", NULL
, CODEC_TEXT
, CODEC_LONGTEXT
, true)
145 add_string( "imem-language", NULL
, LANGUAGE_TEXT
, LANGUAGE_LONGTEXT
, false)
149 add_integer("imem-samplerate", 0, SAMPLERATE_TEXT
, SAMPLERATE_LONGTEXT
, true)
152 add_integer("imem-channels", 0, CHANNELS_TEXT
, CHANNELS_LONGTEXT
, true)
156 add_integer("imem-width", 0, WIDTH_TEXT
, WIDTH_LONGTEXT
, true)
159 add_integer("imem-height", 0, HEIGHT_TEXT
, HEIGHT_LONGTEXT
, true)
162 add_string ("imem-dar", NULL
, DAR_TEXT
, DAR_LONGTEXT
, true)
165 add_string ("imem-fps", NULL
, FPS_TEXT
, FPS_LONGTEXT
, true)
169 add_integer ("imem-size", 0, SIZE_TEXT
, SIZE_LONGTEXT
, true)
174 set_capability("access", 1)
175 set_callbacks(OpenDemux
, CloseDemux
)
179 set_capability("access", 0)
180 set_callbacks(OpenAccess
, CloseAccess
)
183 /*****************************************************************************
185 *****************************************************************************/
187 /* The clock origin for the DTS and PTS is assumed to be 0.
188 * A negative value means unknown.
192 typedef int (*imem_get_t
)(void *data
, const char *cookie
,
193 int64_t *dts
, int64_t *pts
, unsigned *flags
,
195 typedef void (*imem_release_t
)(void *data
, const char *cookie
, size_t, void *);
197 /*****************************************************************************
199 *****************************************************************************/
202 static block_t
*Block(stream_t
*, bool *);
203 static int ControlAccess(stream_t
*, int, va_list);
205 static int Demux(demux_t
*);
206 static int ControlDemux(demux_t
*, int, va_list);
212 imem_release_t release
;
224 static void ParseMRL(vlc_object_t
*, const char *);
227 * It closes the common part of the access and access_demux
229 static void CloseCommon(imem_sys_t
*sys
)
231 free(sys
->source
.cookie
);
235 * It initializes the common part for imem access/access_demux.
237 static int OpenCommon(vlc_object_t
*object
, imem_sys_t
**sys_ptr
, const char *psz_path
)
242 imem_sys_t
*sys
= vlc_obj_calloc(object
, 1, sizeof(*sys
));
246 /* Read the user functions */
247 tmp
= var_InheritString(object
, "imem-get");
249 sys
->source
.get
= (imem_get_t
)(intptr_t)strtoll(tmp
, NULL
, 0);
252 tmp
= var_InheritString(object
, "imem-release");
254 sys
->source
.release
= (imem_release_t
)(intptr_t)strtoll(tmp
, NULL
, 0);
257 if (!sys
->source
.get
|| !sys
->source
.release
) {
258 msg_Err(object
, "Invalid get/release function pointers");
262 tmp
= var_InheritString(object
, "imem-data");
264 sys
->source
.data
= (void *)(uintptr_t)strtoull(tmp
, NULL
, 0);
267 /* Now we can parse the MRL (get/release must not be parsed to avoid
270 ParseMRL(object
, psz_path
);
272 sys
->source
.cookie
= var_InheritString(object
, "imem-cookie");
274 msg_Dbg(object
, "Using get(%p), release(%p), data(%p), cookie(%s)",
275 (void *)sys
->source
.get
, (void *)sys
->source
.release
,
277 sys
->source
.cookie
? sys
->source
.cookie
: "(null)");
281 sys
->deadline
= VLC_TICK_INVALID
;
288 * It opens an imem access.
290 static int OpenAccess(vlc_object_t
*object
)
292 stream_t
*access
= (stream_t
*)object
;
295 if (OpenCommon(object
, &sys
, access
->psz_location
))
298 if (var_InheritInteger(object
, "imem-cat") != 4) {
304 access
->pf_control
= ControlAccess
;
305 access
->pf_read
= NULL
;
306 access
->pf_block
= Block
;
307 access
->pf_seek
= NULL
;
314 * It closes an imem access
316 static void CloseAccess(vlc_object_t
*object
)
318 stream_t
*access
= (stream_t
*)object
;
320 CloseCommon((imem_sys_t
*)access
->p_sys
);
324 * It controls an imem access
326 static int ControlAccess(stream_t
*access
, int i_query
, va_list args
)
331 case STREAM_CAN_SEEK
:
332 case STREAM_CAN_FASTSEEK
: {
333 bool *b
= va_arg( args
, bool* );
337 case STREAM_CAN_PAUSE
:
338 case STREAM_CAN_CONTROL_PACE
: {
339 bool *b
= va_arg( args
, bool* );
343 case STREAM_GET_SIZE
: {
344 uint64_t *s
= va_arg(args
, uint64_t *);
345 *s
= var_InheritInteger(access
, "imem-size");
346 return *s
? VLC_SUCCESS
: VLC_EGENERIC
;
348 case STREAM_GET_PTS_DELAY
:
349 *va_arg(args
, vlc_tick_t
*) = DEFAULT_PTS_DELAY
; /* FIXME? */
352 case STREAM_SET_PAUSE_STATE
:
361 * It retreives data using the get() callback, copies them,
362 * and then release them using the release() callback.
364 static block_t
*Block(stream_t
*access
, bool *restrict eof
)
366 imem_sys_t
*sys
= (imem_sys_t
*)access
->p_sys
;
372 if (sys
->source
.get(sys
->source
.data
, sys
->source
.cookie
,
373 NULL
, NULL
, &flags
, &buffer_size
, &buffer
)) {
378 block_t
*block
= NULL
;
379 if (buffer_size
> 0) {
380 block
= block_Alloc(buffer_size
);
382 memcpy(block
->p_buffer
, buffer
, buffer_size
);
385 sys
->source
.release(sys
->source
.data
, sys
->source
.cookie
,
386 buffer_size
, buffer
);
390 static inline int GetCategory(vlc_object_t
*object
)
392 const int cat
= var_InheritInteger(object
, "imem-cat");
402 msg_Err(object
, "Invalid ES category");
410 * It opens an imem access_demux.
412 static int OpenDemux(vlc_object_t
*object
)
414 demux_t
*demux
= (demux_t
*)object
;
417 if (demux
->out
== NULL
)
420 if (OpenCommon(object
, &sys
, demux
->psz_location
))
425 es_format_Init(&fmt
, GetCategory(object
), 0);
427 fmt
.i_id
= var_InheritInteger(object
, "imem-id");
428 fmt
.i_group
= var_InheritInteger(object
, "imem-group");
430 char *tmp
= var_InheritString(object
, "imem-codec");
432 fmt
.i_codec
= vlc_fourcc_GetCodecFromString(fmt
.i_cat
, tmp
);
437 fmt
.audio
.i_channels
= var_InheritInteger(object
, "imem-channels");
438 fmt
.audio
.i_rate
= var_InheritInteger(object
, "imem-samplerate");
440 msg_Dbg(object
, "Audio %4.4s %d channels %d Hz",
441 (const char *)&fmt
.i_codec
,
442 fmt
.audio
.i_channels
, fmt
.audio
.i_rate
);
446 fmt
.video
.i_width
= var_InheritInteger(object
, "imem-width");
447 fmt
.video
.i_height
= var_InheritInteger(object
, "imem-height");
449 if (!var_InheritURational(object
, &num
, &den
, "imem-dar") && num
> 0 && den
> 0) {
450 if (fmt
.video
.i_width
!= 0 && fmt
.video
.i_height
!= 0) {
451 fmt
.video
.i_sar_num
= num
* fmt
.video
.i_height
;
452 fmt
.video
.i_sar_den
= den
* fmt
.video
.i_width
;
455 if (!var_InheritURational(object
, &num
, &den
, "imem-fps") && num
> 0 && den
> 0) {
456 fmt
.video
.i_frame_rate
= num
;
457 fmt
.video
.i_frame_rate_base
= den
;
460 msg_Dbg(object
, "Video %4.4s %dx%d SAR %d:%d frame rate %u/%u",
461 (const char *)&fmt
.i_codec
,
462 fmt
.video
.i_width
, fmt
.video
.i_height
,
463 fmt
.video
.i_sar_num
, fmt
.video
.i_sar_den
,
464 fmt
.video
.i_frame_rate
, fmt
.video
.i_frame_rate_base
);
468 fmt
.subs
.spu
.i_original_frame_width
=
469 var_InheritInteger(object
, "imem-width");
470 fmt
.subs
.spu
.i_original_frame_height
=
471 var_InheritInteger(object
, "imem-height");
473 msg_Dbg(object
, "Subtitle %4.4s",
474 (const char *)&fmt
.i_codec
);
478 es_format_Clean(&fmt
);
483 fmt
.psz_language
= var_InheritString(object
, "imem-language");
485 sys
->es
= es_out_Add(demux
->out
, &fmt
);
486 es_format_Clean(&fmt
);
494 demux
->pf_control
= ControlDemux
;
495 demux
->pf_demux
= Demux
;
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
;
520 case DEMUX_CAN_PAUSE
:
521 case DEMUX_CAN_CONTROL_PACE
: {
522 bool *b
= va_arg(args
, bool *);
526 case DEMUX_SET_PAUSE_STATE
:
529 case DEMUX_GET_PTS_DELAY
: {
530 *va_arg(args
, vlc_tick_t
*) = DEFAULT_PTS_DELAY
; /* FIXME? */
533 case DEMUX_GET_POSITION
: {
534 double *position
= va_arg(args
, double *);
538 case DEMUX_GET_TIME
: {
539 *va_arg(args
, vlc_tick_t
*) = sys
->dts
;
542 case DEMUX_GET_LENGTH
: {
543 *va_arg(args
, vlc_tick_t
*) = 0;
546 case DEMUX_SET_NEXT_DEMUX_TIME
:
547 sys
->deadline
= va_arg(args
, vlc_tick_t
);
552 case DEMUX_SET_POSITION
:
562 * It retreives data using the get() callback, sends them to es_out
563 * and the release it using the release() callback.
565 static int Demux(demux_t
*demux
)
567 imem_sys_t
*sys
= (imem_sys_t
*)demux
->p_sys
;
569 if (sys
->deadline
== VLC_TICK_INVALID
)
570 sys
->deadline
= sys
->dts
+ 1;
573 if (sys
->deadline
<= sys
->dts
)
582 if (sys
->source
.get(sys
->source
.data
, sys
->source
.cookie
,
583 &dts
, &pts
, &flags
, &buffer_size
, &buffer
))
589 if (buffer_size
> 0) {
590 block_t
*block
= block_Alloc(buffer_size
);
592 block
->i_dts
= dts
>= 0 ? (1 + dts
) : VLC_TICK_INVALID
;
593 block
->i_pts
= pts
>= 0 ? (1 + pts
) : VLC_TICK_INVALID
;
594 memcpy(block
->p_buffer
, buffer
, buffer_size
);
596 es_out_SetPCR(demux
->out
, block
->i_dts
);
597 es_out_Send(demux
->out
, sys
->es
, block
);
603 sys
->source
.release(sys
->source
.data
, sys
->source
.cookie
,
604 buffer_size
, buffer
);
606 sys
->deadline
= VLC_TICK_INVALID
;
611 * Parse the MRL and extract configuration from it.
613 * Syntax: option1=value1[:option2=value2[...]]
615 * XXX get and release are not supported on purpose.
617 static void ParseMRL(vlc_object_t
*object
, const char *psz_path
)
619 static const struct {
623 { "id", VLC_VAR_INTEGER
},
624 { "group", VLC_VAR_INTEGER
},
625 { "cat", VLC_VAR_INTEGER
},
626 { "samplerate", VLC_VAR_INTEGER
},
627 { "channels", VLC_VAR_INTEGER
},
628 { "width", VLC_VAR_INTEGER
},
629 { "height", VLC_VAR_INTEGER
},
630 { "cookie", VLC_VAR_STRING
},
631 { "codec", VLC_VAR_STRING
},
632 { "language", VLC_VAR_STRING
},
633 { "dar", VLC_VAR_STRING
},
634 { "fps", VLC_VAR_STRING
},
638 char *dup
= strdup(psz_path
);
644 char *next
= strchr(current
, ':');
648 char *option
= current
;
649 char *value
= strchr(current
, '=');
652 msg_Dbg(object
, "option '%s' value '%s'", option
, value
);
654 msg_Dbg(object
, "option '%s' without value (unsupported)", option
);
658 if (asprintf(&name
, "imem-%s", option
) < 0)
660 for (unsigned i
= 0; name
&& options
[i
].name
; i
++) {
661 if (strcmp(options
[i
].name
, option
))
664 var_Create(object
, name
, options
[i
].type
| VLC_VAR_DOINHERIT
);
665 if (options
[i
].type
== VLC_VAR_INTEGER
&& value
) {
666 var_SetInteger(object
, name
, strtol(value
, NULL
, 0));
667 } else if (options
[i
].type
== VLC_VAR_STRING
&& value
) {
668 var_SetString(object
, name
, value
);