1 /* GStreamer demultiplexer plugin for Interplay MVE movie files
3 * Copyright (C) 2006-2008 Jens Granseuer <jensgr@gmx.net>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
20 * For more information about the Interplay MVE format, visit:
21 * http://www.pcisys.net/~melanson/codecs/interplay-mve.txt
29 #include "gstmvedemux.h"
32 GST_DEBUG_CATEGORY_STATIC (mvedemux_debug);
33 #define GST_CAT_DEFAULT mvedemux_debug
37 MVEDEMUX_STATE_INITIAL, /* initial state, header not read */
38 MVEDEMUX_STATE_NEXT_CHUNK, /* parsing chunk/segment header */
39 MVEDEMUX_STATE_MOVIE, /* reading the stream */
40 MVEDEMUX_STATE_SKIP /* skipping chunk */
43 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
46 GST_STATIC_CAPS ("video/x-mve")
49 static GstStaticPadTemplate vidsrc_template = GST_STATIC_PAD_TEMPLATE ("video",
52 GST_STATIC_CAPS ("video/x-raw-rgb, "
53 "width = (int) [ 1, MAX ], "
54 "height = (int) [ 1, MAX ], "
55 "framerate = (fraction) [ 0, MAX ], "
58 "endianness = (int) BYTE_ORDER, "
59 "red_mask = (int) 31744, "
60 "green_mask = (int) 992, "
61 "blue_mask = (int) 31; "
63 "width = (int) [ 1, MAX ], "
64 "height = (int) [ 1, MAX ], "
65 "framerate = (fraction) [ 0, MAX ], "
66 "bpp = (int) 8, " "depth = (int) 8, " "endianness = (int) BYTE_ORDER")
69 static GstStaticPadTemplate audsrc_template = GST_STATIC_PAD_TEMPLATE ("audio",
72 GST_STATIC_CAPS ("audio/x-raw-int, "
74 "rate = (int) [ 1, MAX ], "
75 "channels = (int) [ 1, 2 ], "
77 "signed = (boolean) false; "
80 "rate = (int) [ 1, MAX ], "
81 "channels = (int) [ 1, 2 ], "
83 "signed = (boolean) true, "
84 "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }")
87 #define MVE_DEFAULT_AUDIO_STREAM 0x01
89 static void gst_mve_demux_class_init (GstMveDemuxClass * klass);
90 static void gst_mve_demux_base_init (GstMveDemuxClass * klass);
91 static void gst_mve_demux_init (GstMveDemux * mve);
93 #define GST_MVE_SEGMENT_SIZE(data) (GST_READ_UINT16_LE (data))
94 #define GST_MVE_SEGMENT_TYPE(data) (GST_READ_UINT8 (data + 2))
95 #define GST_MVE_SEGMENT_VERSION(data) (GST_READ_UINT8 (data + 3))
97 static GstElementClass *parent_class = NULL;
100 gst_mve_demux_reset (GstMveDemux * mve)
102 gst_adapter_clear (mve->adapter);
104 if (mve->video_stream != NULL) {
105 if (mve->video_stream->pad)
106 gst_element_remove_pad (GST_ELEMENT (mve), mve->video_stream->pad);
107 if (mve->video_stream->caps)
108 gst_caps_unref (mve->video_stream->caps);
109 if (mve->video_stream->palette)
110 gst_buffer_unref (mve->video_stream->palette);
111 g_free (mve->video_stream->code_map);
112 if (mve->video_stream->buffer)
113 gst_buffer_unref (mve->video_stream->buffer);
114 g_free (mve->video_stream);
115 mve->video_stream = NULL;
118 if (mve->audio_stream != NULL) {
119 if (mve->audio_stream->pad)
120 gst_element_remove_pad (GST_ELEMENT (mve), mve->audio_stream->pad);
121 if (mve->audio_stream->caps)
122 gst_caps_unref (mve->audio_stream->caps);
123 if (mve->audio_stream->buffer)
124 gst_buffer_unref (mve->audio_stream->buffer);
125 g_free (mve->audio_stream);
126 mve->audio_stream = NULL;
129 mve->state = MVEDEMUX_STATE_INITIAL;
130 mve->needed_bytes = MVE_PREAMBLE_SIZE;
131 mve->frame_duration = GST_CLOCK_TIME_NONE;
134 mve->chunk_offset = 0;
137 static const GstQueryType *
138 gst_mve_demux_get_src_query_types (GstPad * pad)
140 static const GstQueryType src_types[] = {
150 gst_mve_demux_handle_src_query (GstPad * pad, GstQuery * query)
152 gboolean res = FALSE;
154 switch (GST_QUERY_TYPE (query)) {
155 case GST_QUERY_POSITION:{
158 gst_query_parse_position (query, &format, NULL);
160 /* we only support TIME */
161 if (format == GST_FORMAT_TIME) {
162 GstMveDemuxStream *s = gst_pad_get_element_private (pad);
166 gst_query_set_position (query, GST_FORMAT_TIME, s->last_ts);
167 GST_OBJECT_UNLOCK (s);
173 case GST_QUERY_SEEKING:{
176 gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
177 if (format == GST_FORMAT_TIME) {
178 gst_query_set_seeking (query, GST_FORMAT_TIME, FALSE, 0, -1);
183 case GST_QUERY_DURATION:{
184 /* FIXME: really should implement/estimate this somehow */
189 res = gst_pad_query_default (pad, query);
197 gst_mve_demux_handle_src_event (GstPad * pad, GstEvent * event)
201 switch (GST_EVENT_TYPE (event)) {
203 GST_DEBUG ("seeking not supported");
207 res = gst_pad_event_default (pad, event);
215 static GstStateChangeReturn
216 gst_mve_demux_change_state (GstElement * element, GstStateChange transition)
218 GstMveDemux *mve = GST_MVE_DEMUX (element);
220 if (GST_ELEMENT_CLASS (parent_class)->change_state) {
221 GstStateChangeReturn ret;
223 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
224 if (ret != GST_STATE_CHANGE_SUCCESS)
228 switch (transition) {
229 case GST_STATE_CHANGE_PAUSED_TO_READY:
230 gst_mve_demux_reset (mve);
236 return GST_STATE_CHANGE_SUCCESS;
240 gst_mve_add_stream (GstMveDemux * mve, GstMveDemuxStream * stream,
243 GstPadTemplate *templ;
244 gboolean ret = FALSE;
246 if (stream->pad == NULL) {
247 if (stream == mve->video_stream) {
248 templ = gst_static_pad_template_get (&vidsrc_template);
249 stream->pad = gst_pad_new_from_template (templ, "video");
251 templ = gst_static_pad_template_get (&audsrc_template);
252 stream->pad = gst_pad_new_from_template (templ, "audio");
254 gst_object_unref (templ);
256 gst_pad_set_query_type_function (stream->pad,
257 GST_DEBUG_FUNCPTR (gst_mve_demux_get_src_query_types));
258 gst_pad_set_query_function (stream->pad,
259 GST_DEBUG_FUNCPTR (gst_mve_demux_handle_src_query));
260 gst_pad_set_event_function (stream->pad,
261 GST_DEBUG_FUNCPTR (gst_mve_demux_handle_src_event));
262 gst_pad_set_element_private (stream->pad, stream);
264 GST_DEBUG_OBJECT (mve, "adding pad %s", GST_PAD_NAME (stream->pad));
265 gst_pad_set_active (stream->pad, TRUE);
266 gst_element_add_pad (GST_ELEMENT (mve), stream->pad);
270 GST_DEBUG_OBJECT (mve, "setting caps %" GST_PTR_FORMAT, stream->caps);
271 gst_pad_set_caps (stream->pad, stream->caps);
274 gst_element_found_tags_for_pad (GST_ELEMENT (mve), stream->pad, list);
280 gst_mve_stream_error (GstMveDemux * mve, guint16 req, guint16 avail)
282 GST_ELEMENT_ERROR (mve, STREAM, DECODE, (NULL),
283 ("wanted to read %d bytes from stream, %d available", req, avail));
284 return GST_FLOW_ERROR;
288 gst_mve_buffer_alloc_for_pad (GstMveDemuxStream * stream,
289 guint32 size, GstBuffer ** buffer)
291 *buffer = gst_buffer_new_and_alloc (size);
292 gst_buffer_set_caps (*buffer, stream->caps);
293 GST_BUFFER_TIMESTAMP (*buffer) = stream->last_ts;
294 GST_BUFFER_OFFSET (*buffer) = stream->offset;
299 gst_mve_video_init (GstMveDemux * mve, const guint8 * data)
301 GST_DEBUG_OBJECT (mve, "init video");
303 if (mve->video_stream == NULL) {
304 GstMveDemuxStream *stream = g_new0 (GstMveDemuxStream, 1);
306 stream->buffer = NULL;
307 stream->back_buf1 = NULL;
308 stream->back_buf2 = NULL;
312 stream->code_map = NULL;
313 stream->code_map_avail = FALSE;
314 stream->palette = NULL;
316 stream->last_ts = GST_CLOCK_TIME_NONE;
317 stream->last_flow = GST_FLOW_OK;
318 mve->video_stream = stream;
325 gst_mve_video_create_buffer (GstMveDemux * mve, guint8 version,
326 const guint8 * data, guint16 len)
329 guint16 w, h, n, true_color, bpp;
330 guint required, size;
332 GST_DEBUG_OBJECT (mve, "create video buffer");
334 if (mve->video_stream == NULL) {
335 GST_ELEMENT_ERROR (mve, STREAM, DECODE, (NULL),
336 ("trying to create video buffer for uninitialized stream"));
337 return GST_FLOW_ERROR;
340 /* need 4 to 8 more bytes */
341 required = (version > 1) ? 8 : (version * 2);
343 return gst_mve_stream_error (mve, required, len);
345 w = GST_READ_UINT16_LE (data) << 3;
346 h = GST_READ_UINT16_LE (data + 2) << 3;
349 n = GST_READ_UINT16_LE (data + 4);
354 true_color = GST_READ_UINT16_LE (data + 6);
358 bpp = (true_color ? 2 : 1);
361 if (mve->video_stream->buffer != NULL) {
362 GST_DEBUG_OBJECT (mve, "video buffer already created");
364 if (GST_BUFFER_SIZE (mve->video_stream->buffer) == size * 2)
367 GST_DEBUG_OBJECT (mve, "video buffer size has changed");
368 gst_buffer_unref (mve->video_stream->buffer);
371 GST_DEBUG_OBJECT (mve,
372 "allocating video buffer, w:%u, h:%u, n:%u, true_color:%u", w, h, n,
375 /* we need a buffer to keep the last 2 frames, since those may be
376 needed for decoding the next one */
377 buf = gst_buffer_new_and_alloc (size * 2);
379 mve->video_stream->bpp = bpp;
380 mve->video_stream->width = w;
381 mve->video_stream->height = h;
382 mve->video_stream->buffer = buf;
383 mve->video_stream->back_buf1 = GST_BUFFER_DATA (buf);
384 mve->video_stream->back_buf2 = mve->video_stream->back_buf1 + size;
385 mve->video_stream->max_block_offset = (h - 7) * w - 8;
386 memset (mve->video_stream->back_buf1, 0, size * 2);
392 gst_mve_video_palette (GstMveDemux * mve, const guint8 * data, guint16 len)
395 guint16 start, count;
400 GST_DEBUG_OBJECT (mve, "video palette");
402 if (mve->video_stream == NULL) {
403 GST_ELEMENT_ERROR (mve, STREAM, DECODE, (NULL),
404 ("found palette before video stream was initialized"));
405 return GST_FLOW_ERROR;
408 /* need 4 more bytes now, more later */
410 return gst_mve_stream_error (mve, 4, len);
414 start = GST_READ_UINT16_LE (data);
415 count = GST_READ_UINT16_LE (data + 2);
416 GST_DEBUG_OBJECT (mve, "found palette start:%u, count:%u", start, count);
418 /* need more bytes */
420 return gst_mve_stream_error (mve, count * 3, len);
422 /* make sure we don't exceed the buffer */
423 if (start + count > MVE_PALETTE_COUNT) {
424 GST_ELEMENT_ERROR (mve, STREAM, DECODE, (NULL),
425 ("palette too large for buffer"));
426 return GST_FLOW_ERROR;
429 if (mve->video_stream->palette != NULL) {
430 /* older buffers floating around might still use the old
431 palette, so make sure we can update it */
432 buf = gst_buffer_make_writable (mve->video_stream->palette);
434 buf = gst_buffer_new_and_alloc (MVE_PALETTE_COUNT * 4);
435 memset (GST_BUFFER_DATA (buf), 0, GST_BUFFER_SIZE (buf));
438 mve->video_stream->palette = buf;
441 pal_ptr = ((guint32 *) GST_BUFFER_DATA (buf)) + start;
442 for (i = 0; i < count; ++i) {
443 /* convert from 6-bit VGA to 8-bit palette */
452 *pal_ptr = (r << 16) | (g << 8) | (b);
459 gst_mve_video_palette_compressed (GstMveDemux * mve, const guint8 * data,
466 GST_DEBUG_OBJECT (mve, "compressed video palette");
468 if (mve->video_stream == NULL) {
469 GST_ELEMENT_ERROR (mve, STREAM, DECODE, (NULL),
470 ("found palette before video stream was initialized"));
471 return GST_FLOW_ERROR;
474 if (mve->video_stream->palette == NULL) {
475 GST_ELEMENT_ERROR (mve, STREAM, DECODE, (NULL),
476 ("no palette available for modification"));
477 return GST_FLOW_ERROR;
480 /* need at least 32 more bytes */
482 return gst_mve_stream_error (mve, 32, len);
486 for (i = 0; i < 32; ++i) {
487 mask = GST_READ_UINT8 (data);
491 for (j = 0; j < 8; ++j) {
492 if (mask & (1 << j)) {
495 /* need 3 more bytes */
497 return gst_mve_stream_error (mve, 3, len);
508 ((guint32 *) GST_BUFFER_DATA (mve->video_stream->palette)) +
510 *col = (r << 16) | (g << 8) | (b);
520 gst_mve_video_code_map (GstMveDemux * mve, const guint8 * data, guint16 len)
524 if (mve->video_stream == NULL || mve->video_stream->code_map == NULL) {
525 GST_WARNING_OBJECT (mve, "video stream not initialized");
526 return GST_FLOW_ERROR;
529 GST_DEBUG_OBJECT (mve, "found code map, size:%u", len);
531 /* decoding is done in 8x8 blocks using 4-bit opcodes */
532 min = (mve->video_stream->width * mve->video_stream->height) / (8 * 8 * 2);
535 return gst_mve_stream_error (mve, min, len);
537 memcpy (mve->video_stream->code_map, data, min);
538 mve->video_stream->code_map_avail = TRUE;
543 gst_mve_video_data (GstMveDemux * mve, const guint8 * data, guint16 len,
546 GstFlowReturn ret = GST_FLOW_OK;
547 gint16 cur_frame, last_frame;
548 gint16 x_offset, y_offset;
549 gint16 x_size, y_size;
552 GstBuffer *buf = NULL;
553 GstMveDemuxStream *s = mve->video_stream;
555 GST_LOG_OBJECT (mve, "video data");
558 GST_ELEMENT_ERROR (mve, STREAM, DECODE, (NULL),
559 ("trying to decode video data before stream was initialized"));
560 return GST_FLOW_ERROR;
563 if (GST_CLOCK_TIME_IS_VALID (mve->frame_duration)) {
564 if (GST_CLOCK_TIME_IS_VALID (s->last_ts))
565 s->last_ts += mve->frame_duration;
570 if (!s->code_map_avail) {
571 GST_ELEMENT_ERROR (mve, STREAM, DECODE, (NULL),
572 ("no code map available for decoding"));
573 return GST_FLOW_ERROR;
576 /* need at least 14 more bytes */
578 return gst_mve_stream_error (mve, 14, len);
582 cur_frame = GST_READ_UINT16_LE (data);
583 last_frame = GST_READ_UINT16_LE (data + 2);
584 x_offset = GST_READ_UINT16_LE (data + 4);
585 y_offset = GST_READ_UINT16_LE (data + 6);
586 x_size = GST_READ_UINT16_LE (data + 8);
587 y_size = GST_READ_UINT16_LE (data + 10);
588 flags = GST_READ_UINT16_LE (data + 12);
591 GST_DEBUG_OBJECT (mve,
592 "video data hot:%d, cold:%d, xoff:%d, yoff:%d, w:%d, h:%d, flags:%x",
593 cur_frame, last_frame, x_offset, y_offset, x_size, y_size, flags);
595 if (flags & MVE_VIDEO_DELTA_FRAME) {
596 guint8 *temp = s->back_buf1;
598 s->back_buf1 = s->back_buf2;
602 ret = gst_mve_buffer_alloc_for_pad (s, s->width * s->height * s->bpp, &buf);
603 if (ret != GST_FLOW_OK)
607 dec = ipvideo_decode_frame16 (s, data, len);
609 if (s->palette == NULL) {
610 GST_ELEMENT_ERROR (mve, STREAM, DECODE, (NULL), ("no palette available"));
614 dec = ipvideo_decode_frame8 (s, data, len);
619 memcpy (GST_BUFFER_DATA (buf), s->back_buf1, GST_BUFFER_SIZE (buf));
620 GST_BUFFER_DURATION (buf) = mve->frame_duration;
621 GST_BUFFER_OFFSET_END (buf) = ++s->offset;
626 /* set the palette on the outgoing buffer */
627 caps = gst_caps_copy (s->caps);
628 gst_caps_set_simple (caps,
629 "palette_data", GST_TYPE_BUFFER, s->palette, NULL);
630 gst_buffer_set_caps (buf, caps);
631 gst_caps_unref (caps);
638 gst_buffer_unref (buf);
639 return GST_FLOW_ERROR;
643 gst_mve_audio_init (GstMveDemux * mve, guint8 version, const guint8 * data,
646 GstMveDemuxStream *stream;
648 guint32 requested_buffer;
652 GST_DEBUG_OBJECT (mve, "init audio");
654 /* need 8 more bytes */
656 return gst_mve_stream_error (mve, 8, len);
658 if (mve->audio_stream == NULL) {
659 stream = g_new0 (GstMveDemuxStream, 1);
662 stream->last_flow = GST_FLOW_OK;
663 mve->audio_stream = stream;
665 stream = mve->audio_stream;
666 gst_caps_unref (stream->caps);
669 flags = GST_READ_UINT16_LE (data + 2);
670 stream->sample_rate = GST_READ_UINT16_LE (data + 4);
671 requested_buffer = GST_READ_UINT32_LE (data + 6);
673 /* bit 0: 0 = mono, 1 = stereo */
674 stream->n_channels = (flags & MVE_AUDIO_STEREO) + 1;
675 /* bit 1: 0 = 8 bit, 1 = 16 bit */
676 stream->sample_size = (((flags & MVE_AUDIO_16BIT) >> 1) + 1) * 8;
677 /* bit 2: 0 = uncompressed, 1 = compressed */
678 stream->compression = ((version > 0) && (flags & MVE_AUDIO_COMPRESSED)) ?
681 GST_DEBUG_OBJECT (mve, "audio init, sample_rate:%d, channels:%d, "
682 "bits_per_sample:%d, compression:%d, buffer:%u",
683 stream->sample_rate, stream->n_channels,
684 stream->sample_size, stream->compression, requested_buffer);
686 stream->caps = gst_caps_from_string ("audio/x-raw-int");
687 if (stream->caps == NULL)
688 return GST_FLOW_ERROR;
690 gst_caps_set_simple (stream->caps,
691 "signed", G_TYPE_BOOLEAN, (stream->sample_size == 8) ? FALSE : TRUE,
692 "depth", G_TYPE_INT, stream->sample_size,
693 "width", G_TYPE_INT, stream->sample_size,
694 "channels", G_TYPE_INT, stream->n_channels,
695 "rate", G_TYPE_INT, stream->sample_rate, NULL);
696 if (stream->sample_size > 8) {
697 /* for uncompressed audio we can simply copy the incoming buffer
698 which is always in little endian format */
699 gst_caps_set_simple (stream->caps, "endianness", G_TYPE_INT,
700 (stream->compression ? G_BYTE_ORDER : G_LITTLE_ENDIAN), NULL);
701 } else if (stream->compression) {
702 GST_WARNING_OBJECT (mve,
703 "compression is only supported for 16-bit samples");
704 stream->compression = FALSE;
707 list = gst_tag_list_new ();
708 name = g_strdup_printf ("Raw %d-bit PCM audio", stream->sample_size);
709 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
710 GST_TAG_AUDIO_CODEC, name, NULL);
713 if (gst_mve_add_stream (mve, stream, list))
714 return gst_pad_push_event (mve->audio_stream->pad,
715 gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME,
716 0, GST_CLOCK_TIME_NONE, 0)) ? GST_FLOW_OK : GST_FLOW_ERROR;
722 gst_mve_audio_data (GstMveDemux * mve, guint8 type, const guint8 * data,
723 guint16 len, GstBuffer ** output)
726 GstMveDemuxStream *s = mve->audio_stream;
727 GstBuffer *buf = NULL;
731 GST_LOG_OBJECT (mve, "audio data");
734 GST_ELEMENT_ERROR (mve, STREAM, DECODE, (NULL),
735 ("trying to queue samples with no audio stream"));
736 return GST_FLOW_ERROR;
739 /* need at least 6 more bytes */
741 return gst_mve_stream_error (mve, 6, len);
745 stream_mask = GST_READ_UINT16_LE (data + 2);
746 size = GST_READ_UINT16_LE (data + 4);
749 if (stream_mask & MVE_DEFAULT_AUDIO_STREAM) {
750 guint16 n_samples = size / s->n_channels / (s->sample_size / 8);
751 GstClockTime duration = (GST_SECOND / s->sample_rate) * n_samples;
753 if (type == MVE_OC_AUDIO_DATA) {
754 guint16 required = (s->compression ? size / 2 + s->n_channels : size);
757 return gst_mve_stream_error (mve, required, len);
759 ret = gst_mve_buffer_alloc_for_pad (s, size, &buf);
761 if (ret != GST_FLOW_OK)
765 ipaudio_uncompress ((gint16 *) GST_BUFFER_DATA (buf), size,
766 data, s->n_channels);
768 memcpy (GST_BUFFER_DATA (buf), data, size);
770 GST_DEBUG_OBJECT (mve, "created audio buffer, size:%u, stream_mask:%x",
773 /* silence - create a minimal buffer with no sound */
774 size = s->n_channels * (s->sample_size / 8);
775 ret = gst_mve_buffer_alloc_for_pad (s, size, &buf);
776 memset (GST_BUFFER_DATA (buf), 0, size);
779 GST_BUFFER_DURATION (buf) = duration;
780 GST_BUFFER_OFFSET_END (buf) = s->offset + n_samples;
783 s->offset += n_samples;
784 s->last_ts += duration;
786 /* alternate audio streams not supported.
787 are there any movies which use them? */
788 if (type == MVE_OC_AUDIO_DATA)
789 GST_WARNING_OBJECT (mve, "found non-empty alternate audio stream");
796 gst_mve_timer_create (GstMveDemux * mve, const guint8 * data, guint16 len,
801 GstMveDemuxStream *s;
803 gint rate_nom, rate_den;
805 g_return_val_if_fail (mve->video_stream != NULL, GST_FLOW_ERROR);
807 /* need 6 more bytes */
809 return gst_mve_stream_error (mve, 6, len);
811 t_rate = GST_READ_UINT32_LE (data);
812 t_subdiv = GST_READ_UINT16_LE (data + 4);
814 GST_DEBUG_OBJECT (mve, "found timer:%ux%u", t_rate, t_subdiv);
815 mve->frame_duration = t_rate * t_subdiv * GST_USECOND;
817 /* now really start rolling... */
818 s = mve->video_stream;
820 if ((s->buffer == NULL) || (s->width == 0) || (s->height == 0)) {
821 GST_ELEMENT_ERROR (mve, STREAM, DECODE, (NULL),
822 ("missing or invalid create-video-buffer segment (%dx%d)",
823 s->width, s->height));
824 return GST_FLOW_ERROR;
827 if (s->pad != NULL) {
828 if (s->caps != NULL) {
829 gst_caps_unref (s->caps);
832 if (s->code_map != NULL) {
833 g_free (s->code_map);
838 list = gst_tag_list_new ();
839 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
840 GST_TAG_VIDEO_CODEC, "Raw RGB video", NULL);
843 s->caps = gst_caps_from_string ("video/x-raw-rgb");
845 return GST_FLOW_ERROR;
847 rate_nom = GST_SECOND / GST_USECOND;
848 rate_den = mve->frame_duration / GST_USECOND;
850 gst_caps_set_simple (s->caps,
851 "bpp", G_TYPE_INT, s->bpp * 8,
852 "depth", G_TYPE_INT, (s->bpp == 1) ? 8 : 15,
853 "width", G_TYPE_INT, s->width,
854 "height", G_TYPE_INT, s->height,
855 "framerate", GST_TYPE_FRACTION, rate_nom, rate_den,
856 "endianness", G_TYPE_INT, G_BYTE_ORDER, NULL);
858 gst_caps_set_simple (s->caps, "red_mask", G_TYPE_INT, 0x7C00, /* 31744 */
859 "green_mask", G_TYPE_INT, 0x03E0, /* 992 */
860 "blue_mask", G_TYPE_INT, 0x001F, /* 31 */
864 s->code_map = g_malloc ((s->width * s->height) / (8 * 8 * 2));
866 if (gst_mve_add_stream (mve, s, list))
867 return gst_pad_push_event (s->pad,
868 gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME,
869 0, GST_CLOCK_TIME_NONE, 0)) ? GST_FLOW_OK : GST_FLOW_ERROR;
875 gst_mve_end_chunk (GstMveDemux * mve)
877 GST_LOG_OBJECT (mve, "end of chunk");
879 if (mve->video_stream != NULL)
880 mve->video_stream->code_map_avail = FALSE;
885 gst_mve_parse_segment (GstMveDemux * mve, GstMveDemuxStream ** stream,
888 GstFlowReturn ret = GST_FLOW_OK;
889 const guint8 *buffer, *data;
890 guint8 type, version;
893 buffer = gst_adapter_peek (mve->adapter, mve->needed_bytes);
895 type = GST_MVE_SEGMENT_TYPE (buffer);
897 /* check whether to handle the segment */
899 version = GST_MVE_SEGMENT_VERSION (buffer);
900 len = GST_MVE_SEGMENT_SIZE (buffer);
905 case MVE_OC_END_OF_CHUNK:
906 gst_mve_end_chunk (mve);
908 case MVE_OC_CREATE_TIMER:
909 ret = gst_mve_timer_create (mve, data, len, send);
910 *stream = mve->audio_stream;
912 case MVE_OC_AUDIO_BUFFERS:
913 ret = gst_mve_audio_init (mve, version, data, len);
915 case MVE_OC_VIDEO_BUFFERS:
916 ret = gst_mve_video_create_buffer (mve, version, data, len);
918 case MVE_OC_AUDIO_DATA:
919 case MVE_OC_AUDIO_SILENCE:
920 ret = gst_mve_audio_data (mve, type, data, len, send);
921 *stream = mve->audio_stream;
923 case MVE_OC_VIDEO_MODE:
924 ret = gst_mve_video_init (mve, data);
927 ret = gst_mve_video_palette (mve, data, len);
929 case MVE_OC_PALETTE_COMPRESSED:
930 ret = gst_mve_video_palette_compressed (mve, data, len);
932 case MVE_OC_CODE_MAP:
933 ret = gst_mve_video_code_map (mve, data, len);
935 case MVE_OC_VIDEO_DATA:
936 ret = gst_mve_video_data (mve, data, len, send);
937 *stream = mve->video_stream;
940 case MVE_OC_END_OF_STREAM:
941 case MVE_OC_PLAY_AUDIO:
942 case MVE_OC_PLAY_VIDEO:
943 /* these are chunks we don't need to handle */
944 GST_LOG_OBJECT (mve, "ignored segment type:0x%02x, version:0x%02x",
950 /* these are chunks we know exist but we don't care about */
951 GST_DEBUG_OBJECT (mve,
952 "known but unhandled segment type:0x%02x, version:0x%02x", type,
956 GST_WARNING_OBJECT (mve,
957 "unhandled segment type:0x%02x, version:0x%02x", type, version);
962 gst_adapter_flush (mve->adapter, mve->needed_bytes);
967 gst_mve_demux_chain (GstPad * sinkpad, GstBuffer * inbuf)
969 GstMveDemux *mve = GST_MVE_DEMUX (GST_PAD_PARENT (sinkpad));
970 GstFlowReturn ret = GST_FLOW_OK;
972 gst_adapter_push (mve->adapter, inbuf);
974 GST_DEBUG_OBJECT (mve, "queuing buffer, needed:%d, available:%u",
975 mve->needed_bytes, gst_adapter_available (mve->adapter));
977 while ((gst_adapter_available (mve->adapter) >= mve->needed_bytes) &&
978 (ret == GST_FLOW_OK)) {
979 GstMveDemuxStream *stream = NULL;
980 GstBuffer *outbuf = NULL;
982 switch (mve->state) {
983 case MVEDEMUX_STATE_INITIAL:
984 gst_adapter_flush (mve->adapter, mve->needed_bytes);
986 mve->chunk_offset += mve->needed_bytes;
987 mve->needed_bytes = 4;
988 mve->state = MVEDEMUX_STATE_NEXT_CHUNK;
991 case MVEDEMUX_STATE_NEXT_CHUNK:{
995 data = gst_adapter_peek (mve->adapter, mve->needed_bytes);
996 size = GST_MVE_SEGMENT_SIZE (data);
998 if (mve->chunk_offset >= mve->chunk_size) {
999 /* new chunk, flush buffer and proceed with next segment */
1000 guint16 chunk_type = GST_READ_UINT16_LE (data + 2);
1002 gst_adapter_flush (mve->adapter, mve->needed_bytes);
1003 mve->chunk_size = size;
1004 mve->chunk_offset = 0;
1006 if (chunk_type > MVE_CHUNK_END) {
1007 GST_WARNING_OBJECT (mve,
1008 "skipping unknown chunk type 0x%02x of size:%u", chunk_type,
1010 mve->needed_bytes += size;
1011 mve->state = MVEDEMUX_STATE_SKIP;
1013 GST_DEBUG_OBJECT (mve, "found new chunk type 0x%02x of size:%u",
1016 } else if (mve->chunk_offset <= mve->chunk_size) {
1018 GST_DEBUG_OBJECT (mve, "found segment type 0x%02x of size:%u",
1019 GST_MVE_SEGMENT_TYPE (data), size);
1021 mve->needed_bytes += size;
1022 mve->state = MVEDEMUX_STATE_MOVIE;
1027 case MVEDEMUX_STATE_MOVIE:
1028 ret = gst_mve_parse_segment (mve, &stream, &outbuf);
1030 if ((ret == GST_FLOW_OK) && (outbuf != NULL)) {
1032 GST_DEBUG_OBJECT (mve,
1033 "pushing buffer with time %" GST_TIME_FORMAT
1034 " (%u bytes) on pad %s",
1035 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1036 GST_BUFFER_SIZE (outbuf), GST_PAD_NAME (stream->pad));
1038 ret = gst_pad_push (stream->pad, outbuf);
1039 stream->last_flow = ret;
1042 if (ret == GST_FLOW_NOT_LINKED) {
1043 if (mve->audio_stream
1044 && mve->audio_stream->last_flow != GST_FLOW_NOT_LINKED)
1046 if (mve->video_stream
1047 && mve->video_stream->last_flow != GST_FLOW_NOT_LINKED)
1051 /* update current offset */
1052 mve->chunk_offset += mve->needed_bytes;
1054 mve->state = MVEDEMUX_STATE_NEXT_CHUNK;
1055 mve->needed_bytes = 4;
1058 case MVEDEMUX_STATE_SKIP:
1059 mve->chunk_offset += mve->needed_bytes;
1060 gst_adapter_flush (mve->adapter, mve->needed_bytes);
1061 mve->state = MVEDEMUX_STATE_NEXT_CHUNK;
1062 mve->needed_bytes = 4;
1066 GST_ERROR_OBJECT (mve, "invalid state: %d", mve->state);
1075 gst_mve_demux_dispose (GObject * obj)
1077 GstMveDemux *mve = GST_MVE_DEMUX (obj);
1080 g_object_unref (mve->adapter);
1081 mve->adapter = NULL;
1084 G_OBJECT_CLASS (parent_class)->dispose (obj);
1088 gst_mve_demux_base_init (GstMveDemuxClass * klass)
1091 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
1093 gst_element_class_add_static_pad_template (element_class, &sink_template);
1094 gst_element_class_add_static_pad_template (element_class, &vidsrc_template);
1095 gst_element_class_add_static_pad_template (element_class, &audsrc_template);
1096 gst_element_class_set_details_simple (element_class, "MVE Demuxer",
1098 "Demultiplex an Interplay movie (MVE) stream into audio and video",
1099 "Jens Granseuer <jensgr@gmx.net>");
1103 gst_mve_demux_class_init (GstMveDemuxClass * klass)
1105 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1106 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
1108 parent_class = g_type_class_peek_parent (klass);
1110 gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_mve_demux_dispose);
1112 element_class->change_state = GST_DEBUG_FUNCPTR (gst_mve_demux_change_state);
1116 gst_mve_demux_init (GstMveDemux * mve)
1118 mve->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink");
1119 gst_pad_set_chain_function (mve->sinkpad,
1120 GST_DEBUG_FUNCPTR (gst_mve_demux_chain));
1121 gst_element_add_pad (GST_ELEMENT (mve), mve->sinkpad);
1123 mve->adapter = gst_adapter_new ();
1124 gst_mve_demux_reset (mve);
1128 gst_mve_demux_get_type (void)
1130 static GType plugin_type = 0;
1133 const GTypeInfo plugin_info = {
1134 sizeof (GstMveDemuxClass),
1135 (GBaseInitFunc) gst_mve_demux_base_init,
1137 (GClassInitFunc) gst_mve_demux_class_init,
1140 sizeof (GstMveDemux),
1142 (GInstanceInitFunc) gst_mve_demux_init,
1145 GST_DEBUG_CATEGORY_INIT (mvedemux_debug, "mvedemux",
1146 0, "Interplay MVE movie demuxer");
1148 plugin_type = g_type_register_static (GST_TYPE_ELEMENT,
1149 "GstMveDemux", &plugin_info, 0);