demux: ts: only seek on pcr for current program
[vlc.git] / modules / access / imem.c
blobba7c1ea1e06f515b0e474b18c6330a44f0c6ded4
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(stream_t *, bool *);
204 static int ControlAccess(stream_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);
236 * It initializes the common part for imem access/access_demux.
238 static int OpenCommon(vlc_object_t *object, imem_sys_t **sys_ptr, const char *psz_path)
240 char *tmp;
242 /* */
243 imem_sys_t *sys = vlc_obj_calloc(object, 1, sizeof(*sys));
244 if (!sys)
245 return VLC_ENOMEM;
247 /* Read the user functions */
248 tmp = var_InheritString(object, "imem-get");
249 if (tmp)
250 sys->source.get = (imem_get_t)(intptr_t)strtoll(tmp, NULL, 0);
251 free(tmp);
253 tmp = var_InheritString(object, "imem-release");
254 if (tmp)
255 sys->source.release = (imem_release_t)(intptr_t)strtoll(tmp, NULL, 0);
256 free(tmp);
258 if (!sys->source.get || !sys->source.release) {
259 msg_Err(object, "Invalid get/release function pointers");
260 return VLC_EGENERIC;
263 tmp = var_InheritString(object, "imem-data");
264 if (tmp)
265 sys->source.data = (void *)(uintptr_t)strtoull(tmp, NULL, 0);
266 free(tmp);
268 /* Now we can parse the MRL (get/release must not be parsed to avoid
269 * security risks) */
270 if (*psz_path)
271 ParseMRL(object, psz_path);
273 sys->source.cookie = var_InheritString(object, "imem-cookie");
275 msg_Dbg(object, "Using get(%p), release(%p), data(%p), cookie(%s)",
276 (void *)sys->source.get, (void *)sys->source.release,
277 sys->source.data,
278 sys->source.cookie ? sys->source.cookie : "(null)");
280 /* */
281 sys->dts = 0;
282 sys->deadline = VLC_TS_INVALID;
284 *sys_ptr = sys;
285 return VLC_SUCCESS;
289 * It opens an imem access.
291 static int OpenAccess(vlc_object_t *object)
293 stream_t *access = (stream_t *)object;
294 imem_sys_t *sys;
296 if (OpenCommon(object, &sys, access->psz_location))
297 return VLC_EGENERIC;
299 if (var_InheritInteger(object, "imem-cat") != 4) {
300 CloseCommon(sys);
301 return VLC_EGENERIC;
304 /* */
305 access->pf_control = ControlAccess;
306 access->pf_read = NULL;
307 access->pf_block = Block;
308 access->pf_seek = NULL;
309 access->p_sys = (access_sys_t*)sys;
311 return VLC_SUCCESS;
315 * It closes an imem access
317 static void CloseAccess(vlc_object_t *object)
319 stream_t *access = (stream_t *)object;
321 CloseCommon((imem_sys_t*)access->p_sys);
325 * It controls an imem access
327 static int ControlAccess(stream_t *access, int i_query, va_list args)
329 (void) access;
330 switch (i_query)
332 case STREAM_CAN_SEEK:
333 case STREAM_CAN_FASTSEEK: {
334 bool *b = va_arg( args, bool* );
335 *b = false;
336 return VLC_SUCCESS;
338 case STREAM_CAN_PAUSE:
339 case STREAM_CAN_CONTROL_PACE: {
340 bool *b = va_arg( args, bool* );
341 *b = true;
342 return VLC_SUCCESS;
344 case STREAM_GET_SIZE: {
345 uint64_t *s = va_arg(args, uint64_t *);
346 *s = var_InheritInteger(access, "imem-size");
347 return *s ? VLC_SUCCESS : VLC_EGENERIC;
349 case STREAM_GET_PTS_DELAY: {
350 int64_t *delay = va_arg(args, int64_t *);
351 *delay = DEFAULT_PTS_DELAY; /* FIXME? */
352 return VLC_SUCCESS;
354 case STREAM_SET_PAUSE_STATE:
355 return VLC_SUCCESS;
357 default:
358 return VLC_EGENERIC;
363 * It retreives data using the get() callback, copies them,
364 * and then release them using the release() callback.
366 static block_t *Block(stream_t *access, bool *restrict eof)
368 imem_sys_t *sys = (imem_sys_t*)access->p_sys;
370 unsigned flags;
371 size_t buffer_size;
372 void *buffer;
374 if (sys->source.get(sys->source.data, sys->source.cookie,
375 NULL, NULL, &flags, &buffer_size, &buffer)) {
376 *eof = true;
377 return NULL;
380 block_t *block = NULL;
381 if (buffer_size > 0) {
382 block = block_Alloc(buffer_size);
383 if (block)
384 memcpy(block->p_buffer, buffer, buffer_size);
387 sys->source.release(sys->source.data, sys->source.cookie,
388 buffer_size, buffer);
389 return block;
392 static inline int GetCategory(vlc_object_t *object)
394 const int cat = var_InheritInteger(object, "imem-cat");
395 switch (cat)
397 case 1:
398 return AUDIO_ES;
399 case 2:
400 return VIDEO_ES;
401 case 3:
402 return SPU_ES;
403 default:
404 msg_Err(object, "Invalid ES category");
405 /* fall through */
406 case 4:
407 return UNKNOWN_ES;
412 * It opens an imem access_demux.
414 static int OpenDemux(vlc_object_t *object)
416 demux_t *demux = (demux_t *)object;
417 imem_sys_t *sys;
419 if (OpenCommon(object, &sys, demux->psz_location))
420 return VLC_EGENERIC;
422 /* ES format */
423 es_format_t fmt;
424 es_format_Init(&fmt, GetCategory(object), 0);
426 fmt.i_id = var_InheritInteger(object, "imem-id");
427 fmt.i_group = var_InheritInteger(object, "imem-group");
429 char *tmp = var_InheritString(object, "imem-codec");
430 if (tmp)
431 fmt.i_codec = vlc_fourcc_GetCodecFromString(fmt.i_cat, tmp);
432 free(tmp);
434 switch (fmt.i_cat) {
435 case AUDIO_ES: {
436 fmt.audio.i_channels = var_InheritInteger(object, "imem-channels");
437 fmt.audio.i_rate = var_InheritInteger(object, "imem-samplerate");
439 msg_Dbg(object, "Audio %4.4s %d channels %d Hz",
440 (const char *)&fmt.i_codec,
441 fmt.audio.i_channels, fmt.audio.i_rate);
442 break;
444 case VIDEO_ES: {
445 fmt.video.i_width = var_InheritInteger(object, "imem-width");
446 fmt.video.i_height = var_InheritInteger(object, "imem-height");
447 unsigned num, den;
448 if (!var_InheritURational(object, &num, &den, "imem-dar") && num > 0 && den > 0) {
449 if (fmt.video.i_width != 0 && fmt.video.i_height != 0) {
450 fmt.video.i_sar_num = num * fmt.video.i_height;
451 fmt.video.i_sar_den = den * fmt.video.i_width;
454 if (!var_InheritURational(object, &num, &den, "imem-fps") && num > 0 && den > 0) {
455 fmt.video.i_frame_rate = num;
456 fmt.video.i_frame_rate_base = den;
459 msg_Dbg(object, "Video %4.4s %dx%d SAR %d:%d frame rate %u/%u",
460 (const char *)&fmt.i_codec,
461 fmt.video.i_width, fmt.video.i_height,
462 fmt.video.i_sar_num, fmt.video.i_sar_den,
463 fmt.video.i_frame_rate, fmt.video.i_frame_rate_base);
464 break;
466 case SPU_ES: {
467 fmt.subs.spu.i_original_frame_width =
468 var_InheritInteger(object, "imem-width");
469 fmt.subs.spu.i_original_frame_height =
470 var_InheritInteger(object, "imem-height");
472 msg_Dbg(object, "Subtitle %4.4s",
473 (const char *)&fmt.i_codec);
474 break;
476 default:
477 es_format_Clean(&fmt);
478 CloseCommon(sys);
479 return VLC_EGENERIC;
482 fmt.psz_language = var_InheritString(object, "imem-language");
484 sys->es = es_out_Add(demux->out, &fmt);
485 es_format_Clean(&fmt);
487 if (!sys->es) {
488 CloseCommon(sys);
489 return VLC_EGENERIC;
492 /* */
493 demux->pf_control = ControlDemux;
494 demux->pf_demux = Demux;
495 demux->p_sys = (demux_sys_t*)sys;
497 demux->info.i_update = 0;
498 demux->info.i_title = 0;
499 demux->info.i_seekpoint = 0;
500 return VLC_SUCCESS;
504 * It closes an imem access_demux
506 static void CloseDemux(vlc_object_t *object)
508 demux_t *demux = (demux_t *)object;
510 CloseCommon((imem_sys_t*)demux->p_sys);
514 * It controls an imem access_demux
516 static int ControlDemux(demux_t *demux, int i_query, va_list args)
518 imem_sys_t *sys = (imem_sys_t*)demux->p_sys;
520 switch (i_query)
522 case DEMUX_CAN_PAUSE:
523 case DEMUX_CAN_CONTROL_PACE: {
524 bool *b = va_arg(args, bool *);
525 *b = true;
526 return VLC_SUCCESS;
528 case DEMUX_SET_PAUSE_STATE:
529 return VLC_SUCCESS;
531 case DEMUX_GET_PTS_DELAY: {
532 int64_t *delay = va_arg(args, int64_t *);
533 *delay = DEFAULT_PTS_DELAY; /* FIXME? */
534 return VLC_SUCCESS;
536 case DEMUX_GET_POSITION: {
537 double *position = va_arg(args, double *);
538 *position = 0.0;
539 return VLC_SUCCESS;
541 case DEMUX_GET_TIME: {
542 int64_t *t = va_arg(args, int64_t *);
543 *t = sys->dts;
544 return VLC_SUCCESS;
546 case DEMUX_GET_LENGTH: {
547 int64_t *l = va_arg(args, int64_t *);
548 *l = 0;
549 return VLC_SUCCESS;
551 case DEMUX_SET_NEXT_DEMUX_TIME:
552 sys->deadline = va_arg(args, int64_t);
553 return VLC_SUCCESS;
555 /* */
556 case DEMUX_CAN_SEEK:
557 case DEMUX_SET_POSITION:
558 case DEMUX_SET_TIME:
559 default:
560 return VLC_EGENERIC;
563 return VLC_EGENERIC;
567 * It retreives data using the get() callback, sends them to es_out
568 * and the release it using the release() callback.
570 static int Demux(demux_t *demux)
572 imem_sys_t *sys = (imem_sys_t*)demux->p_sys;
574 if (sys->deadline == VLC_TS_INVALID)
575 sys->deadline = sys->dts + 1;
577 for (;;) {
578 if (sys->deadline <= sys->dts)
579 break;
581 /* */
582 int64_t dts, pts;
583 unsigned flags;
584 size_t buffer_size;
585 void *buffer;
587 if (sys->source.get(sys->source.data, sys->source.cookie,
588 &dts, &pts, &flags, &buffer_size, &buffer))
589 return 0;
591 if (dts < 0)
592 dts = pts;
594 if (buffer_size > 0) {
595 block_t *block = block_Alloc(buffer_size);
596 if (block) {
597 block->i_dts = dts >= 0 ? (1 + dts) : VLC_TS_INVALID;
598 block->i_pts = pts >= 0 ? (1 + pts) : VLC_TS_INVALID;
599 memcpy(block->p_buffer, buffer, buffer_size);
601 es_out_SetPCR(demux->out, block->i_dts);
602 es_out_Send(demux->out, sys->es, block);
606 sys->dts = dts;
608 sys->source.release(sys->source.data, sys->source.cookie,
609 buffer_size, buffer);
611 sys->deadline = VLC_TS_INVALID;
612 return 1;
616 * Parse the MRL and extract configuration from it.
618 * Syntax: option1=value1[:option2=value2[...]]
620 * XXX get and release are not supported on purpose.
622 static void ParseMRL(vlc_object_t *object, const char *psz_path)
624 static const struct {
625 const char *name;
626 int type;
627 } options[] = {
628 { "id", VLC_VAR_INTEGER },
629 { "group", VLC_VAR_INTEGER },
630 { "cat", VLC_VAR_INTEGER },
631 { "samplerate", VLC_VAR_INTEGER },
632 { "channels", VLC_VAR_INTEGER },
633 { "width", VLC_VAR_INTEGER },
634 { "height", VLC_VAR_INTEGER },
635 { "cookie", VLC_VAR_STRING },
636 { "codec", VLC_VAR_STRING },
637 { "language", VLC_VAR_STRING },
638 { "dar", VLC_VAR_STRING },
639 { "fps", VLC_VAR_STRING },
640 { NULL, -1 }
643 char *dup = strdup(psz_path);
644 if (!dup)
645 return;
646 char *current = dup;
648 while (current) {
649 char *next = strchr(current, ':');
650 if (next)
651 *next++ = '\0';
653 char *option = current;
654 char *value = strchr(current, '=');
655 if (value) {
656 *value++ = '\0';
657 msg_Dbg(object, "option '%s' value '%s'", option, value);
658 } else {
659 msg_Dbg(object, "option '%s' without value (unsupported)", option);
662 char *name;
663 if (asprintf(&name, "imem-%s", option) < 0)
664 name = NULL;
665 for (unsigned i = 0; name && options[i].name; i++) {
666 if (strcmp(options[i].name, option))
667 continue;
668 /* */
669 var_Create(object, name, options[i].type | VLC_VAR_DOINHERIT);
670 if (options[i].type == VLC_VAR_INTEGER && value) {
671 var_SetInteger(object, name, strtol(value, NULL, 0));
672 } else if (options[i].type == VLC_VAR_STRING && value) {
673 var_SetString(object, name, value);
675 break;
677 free(name);
679 /* */
680 current = next;
682 free(dup);