chromecast: test encoder modules
[vlc.git] / modules / demux / image.c
blob7b7604156f1ea118d5120aa47ad1b476070f9f97
1 /*****************************************************************************
2 * image.c: Image demuxer
3 *****************************************************************************
4 * Copyright (C) 2010 Laurent Aimar
5 * $Id$
7 * Authors: 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
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
34 #include <vlc_demux.h>
35 #include <vlc_image.h>
36 #include "mxpeg_helper.h"
38 /*****************************************************************************
39 * Module descriptor
40 *****************************************************************************/
41 static int Open (vlc_object_t *);
42 static void Close(vlc_object_t *);
44 #define ID_TEXT N_("ES ID")
45 #define ID_LONGTEXT N_( \
46 "Set the ID of the elementary stream")
48 #define GROUP_TEXT N_("Group")
49 #define GROUP_LONGTEXT N_(\
50 "Set the group of the elementary stream")
52 #define DECODE_TEXT N_("Decode")
53 #define DECODE_LONGTEXT N_( \
54 "Decode at the demuxer stage")
56 #define CHROMA_TEXT N_("Forced chroma")
57 #define CHROMA_LONGTEXT N_( \
58 "If non empty and image-decode is true, the image will be " \
59 "converted to the specified chroma.")
61 #define DURATION_TEXT N_("Duration in seconds")
62 #define DURATION_LONGTEXT N_( \
63 "Duration in seconds before simulating an end of file. " \
64 "A negative value means an unlimited play time.")
66 #define FPS_TEXT N_("Frame rate")
67 #define FPS_LONGTEXT N_( \
68 "Frame rate of the elementary stream produced.")
70 #define RT_TEXT N_("Real-time")
71 #define RT_LONGTEXT N_( \
72 "Use real-time mode suitable for being used as a master input and " \
73 "real-time input slaves.")
75 vlc_module_begin()
76 set_description(N_("Image demuxer"))
77 set_shortname(N_("Image"))
78 set_category(CAT_INPUT)
79 set_subcategory(SUBCAT_INPUT_DEMUX)
80 add_integer("image-id", -1, ID_TEXT, ID_LONGTEXT, true)
81 change_safe()
82 add_integer("image-group", 0, GROUP_TEXT, GROUP_LONGTEXT, true)
83 change_safe()
84 add_bool("image-decode", true, DECODE_TEXT, DECODE_LONGTEXT, true)
85 change_safe()
86 add_string("image-chroma", "", CHROMA_TEXT, CHROMA_LONGTEXT, true)
87 change_safe()
88 add_float("image-duration", 10, DURATION_TEXT, DURATION_LONGTEXT, false)
89 change_safe()
90 add_string("image-fps", "10/1", FPS_TEXT, FPS_LONGTEXT, true)
91 change_safe()
92 add_bool("image-realtime", false, RT_TEXT, RT_LONGTEXT, true)
93 change_safe()
94 set_capability("demux", 10)
95 set_callbacks(Open, Close)
96 vlc_module_end()
98 /*****************************************************************************
99 * Local prototypes
100 *****************************************************************************/
101 struct demux_sys_t
103 block_t *data;
104 es_out_id_t *es;
105 mtime_t duration;
106 bool is_realtime;
107 mtime_t pts_origin;
108 mtime_t pts_next;
109 date_t pts;
112 static block_t *Load(demux_t *demux)
114 const unsigned max_size = 4096 * 4096 * 8;
115 uint64_t size;
117 if (vlc_stream_GetSize(demux->s, &size) == VLC_SUCCESS) {
118 if (size > max_size) {
119 msg_Err(demux, "image too large (%"PRIu64" > %u), rejected",
120 size, max_size);
121 return NULL;
123 } else
124 size = max_size;
126 block_t *block = block_Alloc(size);
127 if (block == NULL)
128 return NULL;
130 ssize_t val = vlc_stream_Read(demux->s, block->p_buffer, size);
131 if (val < 0) {
132 block_Release(block);
133 return NULL;
136 block->i_buffer = val;
137 return block;
140 static block_t *Decode(demux_t *demux,
141 video_format_t *fmt, vlc_fourcc_t chroma, block_t *data)
143 image_handler_t *handler = image_HandlerCreate(demux);
144 if (!handler) {
145 block_Release(data);
146 return NULL;
149 video_format_t decoded;
150 video_format_Init(&decoded, chroma);
152 picture_t *image = image_Read(handler, data, fmt, &decoded);
153 image_HandlerDelete(handler);
155 if (!image)
156 return NULL;
158 video_format_Clean(fmt);
159 *fmt = decoded;
161 size_t size = 0;
162 for (int i = 0; i < image->i_planes; i++)
163 size += image->p[i].i_pitch * image->p[i].i_lines;
165 data = block_Alloc(size);
166 if (!data) {
167 picture_Release(image);
168 return NULL;
171 size_t offset = 0;
172 for (int i = 0; i < image->i_planes; i++) {
173 const plane_t *src = &image->p[i];
174 for (int y = 0; y < src->i_visible_lines; y++) {
175 memcpy(&data->p_buffer[offset],
176 &src->p_pixels[y * src->i_pitch],
177 src->i_visible_pitch);
178 offset += src->i_visible_pitch;
182 picture_Release(image);
183 return data;
186 static int Demux(demux_t *demux)
188 demux_sys_t *sys = demux->p_sys;
190 if (!sys->data)
191 return 0;
193 mtime_t deadline;
194 const mtime_t pts_first = sys->pts_origin + date_Get(&sys->pts);
195 if (sys->pts_next > VLC_TS_INVALID) {
196 deadline = sys->pts_next;
197 } else if (sys->is_realtime) {
198 deadline = mdate();
199 const mtime_t max_wait = CLOCK_FREQ / 50;
200 if (deadline + max_wait < pts_first) {
201 es_out_SetPCR(demux->out, deadline);
202 /* That's ugly, but not yet easily fixable */
203 mwait(deadline + max_wait);
204 return 1;
206 } else {
207 deadline = 1 + pts_first;
210 for (;;) {
211 const mtime_t pts = sys->pts_origin + date_Get(&sys->pts);
212 if (sys->duration >= 0 && pts >= sys->pts_origin + sys->duration)
213 return 0;
215 if (pts >= deadline)
216 return 1;
218 block_t *data = block_Duplicate(sys->data);
219 if (!data)
220 return -1;
222 data->i_dts =
223 data->i_pts = VLC_TS_0 + pts;
224 es_out_SetPCR(demux->out, data->i_pts);
225 es_out_Send(demux->out, sys->es, data);
227 date_Increment(&sys->pts, 1);
231 static int Control(demux_t *demux, int query, va_list args)
233 demux_sys_t *sys = demux->p_sys;
235 switch (query) {
236 case DEMUX_CAN_SEEK:
237 *va_arg(args, bool *) = sys->duration >= 0 && !sys->is_realtime;
238 return VLC_SUCCESS;
239 case DEMUX_GET_POSITION: {
240 double *position = va_arg(args, double *);
241 if (sys->duration > 0)
242 *position = date_Get(&sys->pts) / (double)sys->duration;
243 else
244 *position = 0;
245 return VLC_SUCCESS;
247 case DEMUX_SET_POSITION: {
248 if (sys->duration < 0 || sys->is_realtime)
249 return VLC_EGENERIC;
250 double position = va_arg(args, double);
251 date_Set(&sys->pts, position * sys->duration);
252 return VLC_SUCCESS;
254 case DEMUX_GET_TIME: {
255 int64_t *time = va_arg(args, int64_t *);
256 *time = sys->pts_origin + date_Get(&sys->pts);
257 return VLC_SUCCESS;
259 case DEMUX_SET_TIME: {
260 if (sys->duration < 0 || sys->is_realtime)
261 return VLC_EGENERIC;
262 int64_t time = va_arg(args, int64_t);
263 date_Set(&sys->pts, VLC_CLIP(time - sys->pts_origin, 0, sys->duration));
264 return VLC_SUCCESS;
266 case DEMUX_SET_NEXT_DEMUX_TIME: {
267 int64_t pts_next = VLC_TS_0 + va_arg(args, int64_t);
268 if (sys->pts_next <= VLC_TS_INVALID)
269 sys->pts_origin = pts_next;
270 sys->pts_next = pts_next;
271 return VLC_SUCCESS;
273 case DEMUX_GET_LENGTH: {
274 int64_t *length = va_arg(args, int64_t *);
275 *length = __MAX(sys->duration, 0);
276 return VLC_SUCCESS;
278 case DEMUX_GET_FPS: {
279 double *fps = va_arg(args, double *);
280 *fps = (double)sys->pts.i_divider_num / sys->pts.i_divider_den;
281 return VLC_SUCCESS;
283 case DEMUX_GET_META:
284 case DEMUX_HAS_UNSUPPORTED_META:
285 case DEMUX_GET_ATTACHMENTS:
286 return VLC_EGENERIC;
288 case DEMUX_CAN_PAUSE:
289 case DEMUX_SET_PAUSE_STATE:
290 case DEMUX_CAN_CONTROL_PACE:
291 case DEMUX_GET_PTS_DELAY:
292 return demux_vaControlHelper( demux->s, 0, -1, 0, 1, query, args );
294 default:
295 return VLC_EGENERIC;
300 static bool IsBmp(stream_t *s)
302 const uint8_t *header;
303 if (vlc_stream_Peek(s, &header, 18) < 18)
304 return false;
305 if (memcmp(header, "BM", 2) &&
306 memcmp(header, "BA", 2) &&
307 memcmp(header, "CI", 2) &&
308 memcmp(header, "CP", 2) &&
309 memcmp(header, "IC", 2) &&
310 memcmp(header, "PT", 2))
311 return false;
312 uint32_t file_size = GetDWLE(&header[2]);
313 uint32_t data_offset = GetDWLE(&header[10]);
314 uint32_t header_size = GetDWLE(&header[14]);
315 if (file_size != 14 && file_size != 14 + header_size &&
316 file_size <= data_offset)
317 return false;
318 if (data_offset < header_size + 14)
319 return false;
320 if (header_size != 12 && header_size < 40)
321 return false;
322 return true;
325 static bool IsPcx(stream_t *s)
327 const uint8_t *header;
328 if (vlc_stream_Peek(s, &header, 66) < 66)
329 return false;
330 if (header[0] != 0x0A || /* marker */
331 (header[1] != 0x00 && header[1] != 0x02 &&
332 header[1] != 0x03 && header[1] != 0x05) || /* version */
333 (header[2] != 0 && header[2] != 1) || /* encoding */
334 (header[3] != 1 && header[3] != 2 &&
335 header[3] != 4 && header[3] != 8) || /* bits per pixel per plane */
336 header[64] != 0 || /* reserved */
337 header[65] == 0 || header[65] > 4) /* plane count */
338 return false;
339 if (GetWLE(&header[4]) > GetWLE(&header[8]) || /* xmin vs xmax */
340 GetWLE(&header[6]) > GetWLE(&header[10])) /* ymin vs ymax */
341 return false;
342 return true;
345 static bool IsLbm(stream_t *s)
347 const uint8_t *header;
348 if (vlc_stream_Peek(s, &header, 12) < 12)
349 return false;
350 if (memcmp(&header[0], "FORM", 4) ||
351 GetDWBE(&header[4]) <= 4 ||
352 (memcmp(&header[8], "ILBM", 4) && memcmp(&header[8], "PBM ", 4)))
353 return false;
354 return true;
356 static bool IsPnmBlank(uint8_t v)
358 return v == ' ' || v == '\t' || v == '\r' || v == '\n';
360 static bool IsPnm(stream_t *s)
362 const uint8_t *header;
363 int size = vlc_stream_Peek(s, &header, 256);
364 if (size < 3)
365 return false;
366 if (header[0] != 'P' ||
367 header[1] < '1' || header[1] > '6' ||
368 !IsPnmBlank(header[2]))
369 return false;
371 int number_count = 0;
372 for (int i = 3, parsing_number = 0; i < size && number_count < 2; i++) {
373 if (IsPnmBlank(header[i])) {
374 if (parsing_number) {
375 parsing_number = 0;
376 number_count++;
378 } else {
379 if (header[i] < '0' || header[i] > '9')
380 break;
381 parsing_number = 1;
384 if (number_count < 2)
385 return false;
386 return true;
389 static uint8_t FindJpegMarker(int *position, const uint8_t *data, int size)
391 for (int i = *position; i + 1 < size; i++) {
392 if (data[i + 0] != 0xff || data[i + 1] == 0x00)
393 return 0xff;
394 if (data[i + 1] != 0xff) {
395 *position = i + 2;
396 return data[i + 1];
399 return 0xff;
401 static bool IsJfif(stream_t *s)
403 const uint8_t *header;
404 int size = vlc_stream_Peek(s, &header, 256);
405 int position = 0;
407 if (FindJpegMarker(&position, header, size) != 0xd8)
408 return false;
409 if (FindJpegMarker(&position, header, size) != 0xe0)
410 return false;
411 position += 2; /* Skip size */
412 if (position + 5 > size)
413 return false;
414 if (memcmp(&header[position], "JFIF\0", 5))
415 return false;
416 return true;
419 static bool IsWebP(stream_t *s)
421 const uint8_t *header;
422 if (vlc_stream_Peek(s, &header, 20) < 20) /* WebP header size */
423 return false;
424 if (memcmp(&header[0], "RIFF", 4))
425 return false;
426 /* TODO: support other chunk types */
427 if (memcmp(&header[8], "WEBPVP8 ", 8))
428 return false;
429 /* skip headers */
430 vlc_stream_Seek(s, 20);
431 return true;
434 static bool IsSpiff(stream_t *s)
436 const uint8_t *header;
437 if (vlc_stream_Peek(s, &header, 36) < 36) /* SPIFF header size */
438 return false;
439 if (header[0] != 0xff || header[1] != 0xd8 ||
440 header[2] != 0xff || header[3] != 0xe8)
441 return false;
442 if (memcmp(&header[6], "SPIFF\0", 6))
443 return false;
444 return true;
447 static bool IsExif(stream_t *s)
449 const uint8_t *header;
450 ssize_t size = vlc_stream_Peek(s, &header, 256);
451 if (size == -1)
452 return false;
453 int position = 0;
455 if (FindJpegMarker(&position, header, size) != 0xd8)
456 return false;
457 if (FindJpegMarker(&position, header, size) != 0xe1)
458 return false;
459 position += 2; /* Skip size */
460 if (position + 5 > size)
461 return false;
462 if (memcmp(&header[position], "Exif\0", 5))
463 return false;
464 return true;
467 static bool FindSVGmarker(int *position, const uint8_t *data, const int size, const char *marker)
469 for( int i = *position; i < size; i++)
471 if (memcmp(&data[i], marker, strlen(marker)) == 0)
473 *position = i;
474 return true;
477 return false;
480 static bool IsSVG(stream_t *s)
482 if (s->psz_url == NULL)
483 return false;
485 char *ext = strstr(s->psz_url, ".svg");
486 if (!ext) return false;
488 const uint8_t *header;
489 ssize_t size = vlc_stream_Peek(s, &header, 4096);
490 if (size == -1)
491 return false;
492 int position = 0;
494 const char xml[] = "<?xml version=\"";
495 if (!FindSVGmarker(&position, header, size, xml))
496 return false;
497 if (position != 0)
498 return false;
500 const char endxml[] = ">\0";
501 if (!FindSVGmarker(&position, header, size, endxml))
502 return false;
503 if (position <= 15)
504 return false;
506 const char svg[] = "<svg";
507 if (!FindSVGmarker(&position, header, size, svg))
508 return false;
509 if (position < 19)
510 return false;
512 /* SVG Scalable Vector Graphics image */
514 /* NOTE: some SVG images have the mimetype set in a meta data section
515 * and some do not */
516 return true;
519 static bool IsTarga(stream_t *s)
521 /* The header is not enough to ensure proper detection, we need
522 * to have a look at the footer. But doing so can be slow. So
523 * try to avoid it when possible */
524 const uint8_t *header;
525 if (vlc_stream_Peek(s, &header, 18) < 18) /* Targa fixed header */
526 return false;
527 if (header[1] > 1) /* Color Map Type */
528 return false;
529 if ((header[1] != 0 || header[3 + 4] != 0) &&
530 header[3 + 4] != 8 &&
531 header[3 + 4] != 15 && header[3 + 4] != 16 &&
532 header[3 + 4] != 24 && header[3 + 4] != 32)
533 return false;
534 if ((header[2] > 3 && header[2] < 9) || header[2] > 11) /* Image Type */
535 return false;
536 if (GetWLE(&header[8 + 4]) <= 0 || /* Width */
537 GetWLE(&header[8 + 6]) <= 0) /* Height */
538 return false;
539 if (header[8 + 8] != 8 &&
540 header[8 + 8] != 15 && header[8 + 8] != 16 &&
541 header[8 + 8] != 24 && header[8 + 8] != 32)
542 return false;
543 if (header[8 + 9] & 0xc0) /* Reserved bits */
544 return false;
546 const int64_t size = stream_Size(s);
547 if (size <= 18 + 26)
548 return false;
549 bool can_seek;
550 if (vlc_stream_Control(s, STREAM_CAN_SEEK, &can_seek) || !can_seek)
551 return false;
553 const int64_t position = vlc_stream_Tell(s);
554 if (vlc_stream_Seek(s, size - 26))
555 return false;
557 const uint8_t *footer;
558 bool is_targa = vlc_stream_Peek(s, &footer, 26) >= 26 &&
559 !memcmp(&footer[8], "TRUEVISION-XFILE.\x00", 18);
560 vlc_stream_Seek(s, position);
561 return is_targa;
564 typedef struct {
565 vlc_fourcc_t codec;
566 size_t marker_size;
567 const uint8_t marker[14];
568 bool (*detect)(stream_t *s);
569 } image_format_t;
571 #define VLC_CODEC_XCF VLC_FOURCC('X', 'C', 'F', ' ')
572 #define VLC_CODEC_LBM VLC_FOURCC('L', 'B', 'M', ' ')
573 static const image_format_t formats[] = {
574 { .codec = VLC_CODEC_XCF,
575 .marker_size = 9 + 4 + 1,
576 .marker = { 'g', 'i', 'm', 'p', ' ', 'x', 'c', 'f', ' ',
577 'f', 'i', 'l', 'e', '\0' }
579 { .codec = VLC_CODEC_XCF,
580 .marker_size = 9 + 4 + 1,
581 .marker = { 'g', 'i', 'm', 'p', ' ', 'x', 'c', 'f', ' ',
582 'v', '0', '0', '1', '\0' }
584 { .codec = VLC_CODEC_XCF,
585 .marker_size = 9 + 4 + 1,
586 .marker = { 'g', 'i', 'm', 'p', ' ', 'x', 'c', 'f', ' ',
587 'v', '0', '0', '2', '\0' }
589 { .codec = VLC_CODEC_PNG,
590 .marker_size = 8,
591 .marker = { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }
593 { .codec = VLC_CODEC_GIF,
594 .marker_size = 6,
595 .marker = { 'G', 'I', 'F', '8', '7', 'a' }
597 { .codec = VLC_CODEC_GIF,
598 .marker_size = 6,
599 .marker = { 'G', 'I', 'F', '8', '9', 'a' }
601 /* XXX TIFF detection may be a bit weak */
602 { .codec = VLC_CODEC_TIFF,
603 .marker_size = 4,
604 .marker = { 'I', 'I', 0x2a, 0x00 },
606 { .codec = VLC_CODEC_TIFF,
607 .marker_size = 4,
608 .marker = { 'M', 'M', 0x00, 0x2a },
610 { .codec = VLC_CODEC_BMP,
611 .detect = IsBmp,
613 { .codec = VLC_CODEC_PCX,
614 .detect = IsPcx,
616 { .codec = VLC_CODEC_LBM,
617 .detect = IsLbm,
619 { .codec = VLC_CODEC_PNM,
620 .detect = IsPnm,
622 { .codec = VLC_CODEC_MXPEG,
623 .detect = IsMxpeg,
625 { .codec = VLC_CODEC_JPEG,
626 .detect = IsJfif,
628 { .codec = VLC_CODEC_JPEG,
629 .detect = IsSpiff,
631 { .codec = VLC_CODEC_JPEG,
632 .detect = IsExif,
634 { .codec = VLC_CODEC_WEBP,
635 .detect = IsWebP,
637 { .codec = VLC_CODEC_BPG,
638 .marker_size = 4,
639 .marker = { 'B', 'P', 'G', 0xFB },
641 { .codec = VLC_CODEC_SVG,
642 .detect = IsSVG,
644 { .codec = VLC_CODEC_TARGA,
645 .detect = IsTarga,
647 { .codec = 0 }
650 static int Open(vlc_object_t *object)
652 demux_t *demux = (demux_t*)object;
654 /* Detect the image type */
655 const image_format_t *img;
657 const uint8_t *peek;
658 ssize_t peek_size = 0;
659 for (int i = 0; ; i++) {
660 img = &formats[i];
661 if (!img->codec)
662 return VLC_EGENERIC;
664 if (img->detect) {
665 if (img->detect(demux->s))
666 break;
667 /* detect callbacks can invalidate the current peek buffer */
668 peek_size = 0;
669 } else {
670 if ((size_t) peek_size < img->marker_size)
672 peek_size = vlc_stream_Peek(demux->s, &peek, img->marker_size);
673 if (peek_size == -1)
674 return VLC_ENOMEM;
676 if ((size_t) peek_size >= img->marker_size &&
677 !memcmp(peek, img->marker, img->marker_size))
678 break;
681 msg_Dbg(demux, "Detected image: %s",
682 vlc_fourcc_GetDescription(VIDEO_ES, img->codec));
684 if( img->codec == VLC_CODEC_MXPEG )
686 return VLC_EGENERIC; //let avformat demux this file
689 /* Load and if selected decode */
690 es_format_t fmt;
691 es_format_Init(&fmt, VIDEO_ES, img->codec);
692 fmt.video.i_chroma = fmt.i_codec;
694 block_t *data = Load(demux);
695 if (data && var_InheritBool(demux, "image-decode")) {
696 char *string = var_InheritString(demux, "image-chroma");
697 vlc_fourcc_t chroma = vlc_fourcc_GetCodecFromString(VIDEO_ES, string);
698 free(string);
700 data = Decode(demux, &fmt.video, chroma, data);
701 fmt.i_codec = fmt.video.i_chroma;
703 fmt.i_id = var_InheritInteger(demux, "image-id");
704 fmt.i_group = var_InheritInteger(demux, "image-group");
705 if (var_InheritURational(demux,
706 &fmt.video.i_frame_rate,
707 &fmt.video.i_frame_rate_base,
708 "image-fps") ||
709 fmt.video.i_frame_rate <= 0 || fmt.video.i_frame_rate_base <= 0) {
710 msg_Err(demux, "Invalid frame rate, using 10/1 instead");
711 fmt.video.i_frame_rate = 10;
712 fmt.video.i_frame_rate_base = 1;
715 /* If loadind failed, we still continue to avoid mis-detection
716 * by other demuxers. */
717 if (!data)
718 msg_Err(demux, "Failed to load the image");
720 /* */
721 demux_sys_t *sys = malloc(sizeof(*sys));
722 if (!sys) {
723 if (data)
724 block_Release(data);
725 es_format_Clean(&fmt);
726 return VLC_ENOMEM;
729 sys->data = data;
730 sys->es = es_out_Add(demux->out, &fmt);
731 sys->duration = CLOCK_FREQ * var_InheritFloat(demux, "image-duration");
732 sys->is_realtime = var_InheritBool(demux, "image-realtime");
733 sys->pts_origin = sys->is_realtime ? mdate() : 0;
734 sys->pts_next = VLC_TS_INVALID;
735 date_Init(&sys->pts, fmt.video.i_frame_rate, fmt.video.i_frame_rate_base);
736 date_Set(&sys->pts, 0);
738 es_format_Clean(&fmt);
740 demux->pf_demux = Demux;
741 demux->pf_control = Control;
742 demux->p_sys = sys;
743 return VLC_SUCCESS;
746 static void Close(vlc_object_t *object)
748 demux_t *demux = (demux_t*)object;
749 demux_sys_t *sys = demux->p_sys;
751 if (sys->data)
752 block_Release(sys->data);
753 free(sys);