/*****************************************************************************
* imem.c : Memory input for VLC
*****************************************************************************
- * Copyright (C) 2009 Laurent Aimar
+ * Copyright (C) 2009-2010 Laurent Aimar
* $Id$
*
* Author: Laurent Aimar <fenrir _AT_ videolan _DOT org>
#include <vlc_common.h>
#include <vlc_plugin.h>
+#include <vlc_access.h>
#include <vlc_demux.h>
#include <vlc_charset.h>
/*****************************************************************************
* Module descriptior
*****************************************************************************/
-static int Open (vlc_object_t *);
-static void Close(vlc_object_t *);
+static int OpenAccess (vlc_object_t *);
+static void CloseAccess(vlc_object_t *);
+
+static int OpenDemux (vlc_object_t *);
+static void CloseDemux(vlc_object_t *);
#define CACHING_TEXT N_("Caching value in ms")
#define CACHING_LONGTEXT N_(\
#define CAT_LONGTEXT N_(\
"Set the category of the elementary stream")
static const int cat_values[] = {
- 0, 1, 2, 3
+ 0, 1, 2, 3, 4,
};
static const char *cat_texts[] = {
- N_("Unknown"), N_("Audio"), N_("Video"), N_("Subtitle")
+ N_("Unknown"), N_("Audio"), N_("Video"), N_("Subtitle"), N_("Data")
};
#define CODEC_TEXT N_("Codec")
#define RELEASE_LONGTEXT N_(\
"Address of the release callback function")
+#define SIZE_TEXT N_("Size")
+#define SIZE_LONGTEXT N_(\
+ "Size of stream in bytes")
+
vlc_module_begin()
set_shortname(N_("Memory input"))
set_description(N_("Memory input"))
change_private()
change_safe()
+ add_integer ("imem-size", 0, NULL, SIZE_TEXT, SIZE_LONGTEXT, true)
+ change_private()
+ change_safe()
+
add_shortcut("imem")
set_capability("access_demux", 0)
- set_callbacks(Open, Close)
+ set_callbacks(OpenDemux, CloseDemux)
+
+ add_submodule()
+ add_shortcut("imem")
+ set_capability("access", 0)
+ set_callbacks(OpenAccess, CloseAccess)
vlc_module_end()
/*****************************************************************************
*****************************************************************************/
/* */
+static block_t *Block(access_t *);
+static int ControlAccess(access_t *, int, va_list);
+
static int Demux(demux_t *);
-static int Control(demux_t *, int, va_list);
+static int ControlDemux(demux_t *, int, va_list);
/* */
-struct demux_sys_t {
+typedef struct {
struct {
imem_get_t get;
imem_release_t release;
mtime_t dts;
mtime_t deadline;
-};
+} imem_sys_t;
+
+static void ParseMRL(vlc_object_t *, const char *);
-static void ParseMRL(demux_t *);
-static int var_CreateGetRational(demux_t *,
- unsigned *num, unsigned *den,
- const char *var);
+/**
+ * It closes the common part of the access and access_demux
+ */
+static void CloseCommon(imem_sys_t *sys)
+{
+ free(sys->source.cookie);
+ free(sys);
+}
/**
- * It opens an imem access_demux
+ * It initializes the common part for imem access/access_demux.
*/
-static int Open(vlc_object_t *object)
+static int OpenCommon(vlc_object_t *object, imem_sys_t **sys_ptr, const char *psz_path)
{
- demux_t *demux = (demux_t*)object;
char *tmp;
- /* */
- demux_sys_t *sys = calloc(1, sizeof(*sys));
- if (!sys)
- return VLC_ENOMEM;
+ /* */
+ imem_sys_t *sys = calloc(1, sizeof(*sys));
+ if (!sys)
+ return VLC_ENOMEM;
/* Read the user functions */
- tmp = var_CreateGetString(demux, "imem-get");
+ tmp = var_InheritString(object, "imem-get");
if (tmp)
sys->source.get = (imem_get_t)(intptr_t)strtoll(tmp, NULL, 0);
free(tmp);
- tmp = var_CreateGetString(demux, "imem-release");
+ tmp = var_InheritString(object, "imem-release");
if (tmp)
sys->source.release = (imem_release_t)(intptr_t)strtoll(tmp, NULL, 0);
free(tmp);
if (!sys->source.get || !sys->source.release) {
- msg_Err(demux, "Invalid get/release function pointers");
+ msg_Err(object, "Invalid get/release function pointers");
free(sys);
return VLC_EGENERIC;
}
- tmp = var_CreateGetString(demux, "imem-data");
+ tmp = var_InheritString(object, "imem-data");
if (tmp)
sys->source.data = (void *)(uintptr_t)strtoull(tmp, NULL, 0);
free(tmp);
/* Now we can parse the MRL (get/release must not be parsed to avoid
* security risks) */
- if (*demux->psz_path)
- ParseMRL(demux);
+ if (*psz_path)
+ ParseMRL(object, psz_path);
- sys->source.cookie = var_InheritString(demux, "imem-cookie");
+ sys->source.cookie = var_InheritString(object, "imem-cookie");
- msg_Dbg(demux, "Using get(%p), release(%p), data(%p), cookie(%s)",
+ msg_Dbg(object, "Using get(%p), release(%p), data(%p), cookie(%s)",
sys->source.get, sys->source.release, sys->source.data,
sys->source.cookie ? sys->source.cookie : "(null)");
- /* ES format */
+ /* */
+ sys->pts_delay = var_InheritInteger(object, "imem-caching") * INT64_C(1000);
+ sys->dts = 0;
+ sys->deadline = VLC_TS_INVALID;
+
+ *sys_ptr = sys;
+ return VLC_SUCCESS;
+}
+
+/**
+ * It opens an imem access.
+ */
+static int OpenAccess(vlc_object_t *object)
+{
+ access_t *access = (access_t *)object;
+ imem_sys_t *sys;
+
+ if (OpenCommon(object, &sys, access->psz_location))
+ return VLC_EGENERIC;
+
+ if (var_InheritInteger(object, "imem-cat") != 4) {
+ CloseCommon(sys);
+ return VLC_EGENERIC;
+ }
+
+ /* */
+ access_InitFields(access);
+ access->pf_control = ControlAccess;
+ access->pf_read = NULL;
+ access->pf_block = Block;
+ access->pf_seek = NULL;
+ access->p_sys = (access_sys_t*)sys;
+ access->info.i_size = var_InheritInteger(object, "imem-size");
+
+ return VLC_SUCCESS;
+}
+
+/**
+ * It closes an imem access
+ */
+static void CloseAccess(vlc_object_t *object)
+{
+ access_t *access = (access_t *)object;
+
+ CloseCommon((imem_sys_t*)access->p_sys);
+}
+
+/**
+ * It controls an imem access
+ */
+static int ControlAccess(access_t *access, int i_query, va_list args)
+{
+ imem_sys_t *sys = (imem_sys_t*)access->p_sys;
+
+ switch (i_query)
+ {
+ case ACCESS_CAN_SEEK:
+ case ACCESS_CAN_FASTSEEK: {
+ bool *b = va_arg( args, bool* );
+ *b = false;
+ return VLC_SUCCESS;
+ }
+ case ACCESS_CAN_PAUSE:
+ case ACCESS_CAN_CONTROL_PACE: {
+ bool *b = va_arg( args, bool* );
+ *b = true;
+ return VLC_SUCCESS;
+ }
+ case ACCESS_GET_PTS_DELAY: {
+ int64_t *delay = va_arg(args, int64_t *);
+ *delay = sys->pts_delay;
+ return VLC_SUCCESS;
+ }
+ case ACCESS_SET_PAUSE_STATE:
+ return VLC_SUCCESS;
+
+ case ACCESS_GET_TITLE_INFO:
+ case ACCESS_SET_TITLE:
+ case ACCESS_SET_SEEKPOINT:
+ case ACCESS_SET_PRIVATE_ID_STATE:
+ case ACCESS_GET_META:
+ case ACCESS_GET_PRIVATE_ID_STATE:
+ case ACCESS_GET_CONTENT_TYPE:
+ default:
+ return VLC_EGENERIC;
+ }
+}
+
+/**
+ * It retreives data using the get() callback, copies them,
+ * and then release them using the release() callback.
+ */
+static block_t *Block(access_t *access)
+{
+ imem_sys_t *sys = (imem_sys_t*)access->p_sys;
+
+ unsigned flags;
+ size_t buffer_size;
+ void *buffer;
+
+ if (sys->source.get(sys->source.data, sys->source.cookie,
+ NULL, NULL, &flags, &buffer_size, &buffer)) {
+ access->info.b_eof = true;
+ return NULL;
+ }
+
+ block_t *block = NULL;
+ if (buffer_size > 0) {
+ block = block_New(access, buffer_size);
+ if (block)
+ memcpy(block->p_buffer, buffer, buffer_size);
+ }
+
+ sys->source.release(sys->source.data, sys->source.cookie,
+ buffer_size, buffer);
+ return block;
+}
+
+/**
+ * It opens an imem access_demux.
+ */
+static int OpenDemux(vlc_object_t *object)
+{
+ demux_t *demux = (demux_t *)object;
+ imem_sys_t *sys;
+
+ if (OpenCommon(object, &sys, demux->psz_location))
+ return VLC_EGENERIC;
+
+ /* ES format */
es_format_t fmt;
- es_format_Init(&fmt, UNKNOWN_ES, 0);
+ es_format_Init(&fmt, UNKNOWN_ES, 0);
- fmt.i_id = var_CreateGetInteger(demux, "imem-id");
- fmt.i_group = var_CreateGetInteger(demux, "imem-group");
+ fmt.i_id = var_InheritInteger(object, "imem-id");
+ fmt.i_group = var_InheritInteger(object, "imem-group");
- tmp = var_CreateGetString(demux, "imem-codec");
+ char *tmp = var_InheritString(object, "imem-codec");
if (tmp)
fmt.i_codec = vlc_fourcc_GetCodecFromString(UNKNOWN_ES, tmp);
free(tmp);
- switch (var_CreateGetInteger(demux, "imem-cat")) {
+ const int cat = var_InheritInteger(object, "imem-cat");
+ switch (cat) {
case 1: {
fmt.i_cat = AUDIO_ES;
- fmt.audio.i_channels = var_CreateGetInteger(demux, "imem-channels");
- fmt.audio.i_rate = var_CreateGetInteger(demux, "imem-samplerate");
+ fmt.audio.i_channels = var_InheritInteger(object, "imem-channels");
+ fmt.audio.i_rate = var_InheritInteger(object, "imem-samplerate");
- msg_Dbg(demux, "Audio %4.4s %d channels %d Hz",
+ msg_Dbg(object, "Audio %4.4s %d channels %d Hz",
(const char *)&fmt.i_codec,
fmt.audio.i_channels, fmt.audio.i_rate);
break;
}
case 2: {
fmt.i_cat = VIDEO_ES;
- fmt.video.i_width = var_CreateGetInteger(demux, "imem-width");
- fmt.video.i_height = var_CreateGetInteger(demux, "imem-height");
+ fmt.video.i_width = var_InheritInteger(object, "imem-width");
+ fmt.video.i_height = var_InheritInteger(object, "imem-height");
unsigned num, den;
- if (!var_CreateGetRational(demux, &num, &den, "imem-dar") && num > 0 && den > 0) {
+ if (!var_InheritURational(object, &num, &den, "imem-dar") && num > 0 && den > 0) {
if (fmt.video.i_width > 0 && fmt.video.i_height > 0) {
fmt.video.i_sar_num = num * fmt.video.i_height;
fmt.video.i_sar_den = den * fmt.video.i_width;
}
}
- if (!var_CreateGetRational(demux, &num, &den, "imem-fps") && num > 0 && den > 0) {
+ if (!var_InheritURational(object, &num, &den, "imem-fps") && num > 0 && den > 0) {
fmt.video.i_frame_rate = num;
fmt.video.i_frame_rate_base = den;
}
- msg_Dbg(demux, "Video %4.4s %dx%d SAR %d:%d frame rate %u/%u",
+ msg_Dbg(object, "Video %4.4s %dx%d SAR %d:%d frame rate %u/%u",
(const char *)&fmt.i_codec,
fmt.video.i_width, fmt.video.i_height,
fmt.video.i_sar_num, fmt.video.i_sar_den,
case 3: {
fmt.i_cat = SPU_ES;
fmt.subs.spu.i_original_frame_width =
- var_CreateGetInteger(demux, "imem-width");
+ var_InheritInteger(object, "imem-width");
fmt.subs.spu.i_original_frame_height =
- var_CreateGetInteger(demux, "imem-height");
+ var_InheritInteger(object, "imem-height");
- msg_Dbg(demux, "Subtitle %4.4s",
+ msg_Dbg(object, "Subtitle %4.4s",
(const char *)&fmt.i_codec);
break;
}
default:
- msg_Err(demux, "Invalid ES category");
+ if (cat != 4)
+ msg_Err(object, "Invalid ES category");
es_format_Clean(&fmt);
- free(sys);
+ CloseCommon(sys);
return VLC_EGENERIC;
}
- fmt.psz_language = var_CreateGetString(demux, "imem-language");
+ fmt.psz_language = var_InheritString(object, "imem-language");
- /* */
- sys->es = es_out_Add(demux->out, &fmt);
+ sys->es = es_out_Add(demux->out, &fmt);
es_format_Clean(&fmt);
if (!sys->es) {
- free(sys->source.cookie);
- free(sys);
+ CloseCommon(sys);
return VLC_EGENERIC;
}
/* */
- sys->pts_delay = var_CreateGetInteger(demux, "imem-caching") * INT64_C(1000);
- sys->dts = 0;
- sys->deadline = VLC_TS_INVALID;
-
- /* Set up demux */
- demux->pf_control = Control;
+ demux->pf_control = ControlDemux;
demux->pf_demux = Demux;
- demux->p_sys = sys;
+ demux->p_sys = (demux_sys_t*)sys;
demux->info.i_update = 0;
demux->info.i_title = 0;
/**
* It closes an imem access_demux
*/
-static void Close(vlc_object_t *object)
+static void CloseDemux(vlc_object_t *object)
{
- demux_t *demux = (demux_t *)object;
- demux_sys_t *sys = demux->p_sys;
+ demux_t *demux = (demux_t *)object;
- free(sys->source.cookie);
- free(sys);
+ CloseCommon((imem_sys_t*)demux->p_sys);
}
/**
- * It controls imem
+ * It controls an imem access_demux
*/
-static int Control(demux_t *demux, int i_query, va_list args)
+static int ControlDemux(demux_t *demux, int i_query, va_list args)
{
- demux_sys_t *sys = demux->p_sys;
+ imem_sys_t *sys = (imem_sys_t*)demux->p_sys;
switch (i_query)
{
*/
static int Demux(demux_t *demux)
{
- demux_sys_t *sys = demux->p_sys;
+ imem_sys_t *sys = (imem_sys_t*)demux->p_sys;
if (sys->deadline == VLC_TS_INVALID)
sys->deadline = sys->dts + 1;
return 1;
}
-/**
- * It parses a rational number (it also accepts basic float number).
- *
- * It returns an error if the rational number cannot be parsed (0/0 is valid).
- */
-static int var_CreateGetRational(demux_t *demux,
- unsigned *num, unsigned *den,
- const char *var)
-{
- /* */
- *num = 0;
- *den = 0;
-
- /* */
- char *tmp = var_CreateGetString(demux, var);
- if (!tmp)
- goto error;
-
- char *next;
- unsigned n = strtol(tmp, &next, 0);
- unsigned d = strtol(*next ? &next[1] : "0", NULL, 0);
-
- if (*next == '.') {
- /* Interpret as a float number */
- double r = us_atof(tmp);
- double c = ceil(r);
- if (c >= UINT_MAX)
- goto error;
- unsigned m = c;
- if (m > 0) {
- d = UINT_MAX / m;
- n = r * d;
- } else {
- n = 0;
- d = 0;
- }
- }
-
- if (n > 0 && d > 0)
- vlc_ureduce(num, den, n, d, 0);
-
- free(tmp);
- return VLC_SUCCESS;
-
-error:
- free(tmp);
- return VLC_EGENERIC;
-}
-
/**
* Parse the MRL and extract configuration from it.
*
*
* XXX get and release are not supported on purpose.
*/
-static void ParseMRL(demux_t *demux)
+static void ParseMRL(vlc_object_t *object, const char *psz_path)
{
static const struct {
const char *name;
{ NULL, -1 }
};
- char *dup = strdup(demux->psz_path);
+ char *dup = strdup(psz_path);
if (!dup)
return;
char *current = dup;
char *value = strchr(current, '=');
if (value) {
*value++ = '\0';
- msg_Dbg(demux, "option '%s' value '%s'", option, value);
+ msg_Dbg(object, "option '%s' value '%s'", option, value);
} else {
- msg_Dbg(demux, "option '%s' without value (unsupported)", option);
+ msg_Dbg(object, "option '%s' without value (unsupported)", option);
}
char *name;
if (strcmp(options[i].name, option))
continue;
/* */
- var_Create(demux, name, options[i].type | VLC_VAR_DOINHERIT);
+ var_Create(object, name, options[i].type | VLC_VAR_DOINHERIT);
if (options[i].type == VLC_VAR_INTEGER && value) {
- var_SetInteger(demux, name, strtol(value, NULL, 0));
+ var_SetInteger(object, name, strtol(value, NULL, 0));
} else if (options[i].type == VLC_VAR_STRING && value) {
- var_SetString(demux, name, value);
+ var_SetString(object, name, value);
}
break;
}