Tizen 2.0 Release
[framework/multimedia/gst-plugins-bad0.10.git] / gst / mve / gstmvedemux.c
1 /* GStreamer demultiplexer plugin for Interplay MVE movie files
2  *
3  * Copyright (C) 2006-2008 Jens Granseuer <jensgr@gmx.net>
4  *
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.
9  *
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.
14  *
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.
19  *
20  * For more information about the Interplay MVE format, visit:
21  *   http://www.pcisys.net/~melanson/codecs/interplay-mve.txt
22  */
23
24 #ifdef HAVE_CONFIG_H
25 # include <config.h>
26 #endif
27
28 #include <string.h>
29 #include "gstmvedemux.h"
30 #include "mve.h"
31
32 GST_DEBUG_CATEGORY_STATIC (mvedemux_debug);
33 #define GST_CAT_DEFAULT mvedemux_debug
34
35 enum MveDemuxState
36 {
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 */
41 };
42
43 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
44     GST_PAD_SINK,
45     GST_PAD_ALWAYS,
46     GST_STATIC_CAPS ("video/x-mve")
47     );
48
49 static GstStaticPadTemplate vidsrc_template = GST_STATIC_PAD_TEMPLATE ("video",
50     GST_PAD_SRC,
51     GST_PAD_SOMETIMES,
52     GST_STATIC_CAPS ("video/x-raw-rgb, "
53         "width = (int) [ 1, MAX ], "
54         "height = (int) [ 1, MAX ], "
55         "framerate = (fraction) [ 0, MAX ], "
56         "bpp = (int) 16, "
57         "depth = (int) 15, "
58         "endianness = (int) BYTE_ORDER, "
59         "red_mask = (int) 31744, "
60         "green_mask = (int) 992, "
61         "blue_mask = (int) 31; "
62         "video/x-raw-rgb, "
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")
67     );
68
69 static GstStaticPadTemplate audsrc_template = GST_STATIC_PAD_TEMPLATE ("audio",
70     GST_PAD_SRC,
71     GST_PAD_SOMETIMES,
72     GST_STATIC_CAPS ("audio/x-raw-int, "
73         "width = (int) 8, "
74         "rate = (int) [ 1, MAX ], "
75         "channels = (int) [ 1, 2 ], "
76         "depth = (int) 8, "
77         "signed = (boolean) false; "
78         "audio/x-raw-int, "
79         "width = (int) 16, "
80         "rate = (int) [ 1, MAX ], "
81         "channels = (int) [ 1, 2 ], "
82         "depth = (int) 16, "
83         "signed = (boolean) true, "
84         "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }")
85     );
86
87 #define MVE_DEFAULT_AUDIO_STREAM 0x01
88
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);
92
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))
96
97 static GstElementClass *parent_class = NULL;
98
99 static void
100 gst_mve_demux_reset (GstMveDemux * mve)
101 {
102   gst_adapter_clear (mve->adapter);
103
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;
116   }
117
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;
127   }
128
129   mve->state = MVEDEMUX_STATE_INITIAL;
130   mve->needed_bytes = MVE_PREAMBLE_SIZE;
131   mve->frame_duration = GST_CLOCK_TIME_NONE;
132
133   mve->chunk_size = 0;
134   mve->chunk_offset = 0;
135 }
136
137 static const GstQueryType *
138 gst_mve_demux_get_src_query_types (GstPad * pad)
139 {
140   static const GstQueryType src_types[] = {
141     GST_QUERY_POSITION,
142     GST_QUERY_SEEKING,
143     0
144   };
145
146   return src_types;
147 }
148
149 static gboolean
150 gst_mve_demux_handle_src_query (GstPad * pad, GstQuery * query)
151 {
152   gboolean res = FALSE;
153
154   switch (GST_QUERY_TYPE (query)) {
155     case GST_QUERY_POSITION:{
156       GstFormat format;
157
158       gst_query_parse_position (query, &format, NULL);
159
160       /* we only support TIME */
161       if (format == GST_FORMAT_TIME) {
162         GstMveDemuxStream *s = gst_pad_get_element_private (pad);
163
164         if (s != NULL) {
165           GST_OBJECT_LOCK (s);
166           gst_query_set_position (query, GST_FORMAT_TIME, s->last_ts);
167           GST_OBJECT_UNLOCK (s);
168           res = TRUE;
169         }
170       }
171       break;
172     }
173     case GST_QUERY_SEEKING:{
174       GstFormat format;
175
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);
179         res = TRUE;
180       }
181       break;
182     }
183     case GST_QUERY_DURATION:{
184       /* FIXME: really should implement/estimate this somehow */
185       res = FALSE;
186       break;
187     }
188     default:
189       res = gst_pad_query_default (pad, query);
190       break;
191   }
192
193   return res;
194 }
195
196 static gboolean
197 gst_mve_demux_handle_src_event (GstPad * pad, GstEvent * event)
198 {
199   gboolean res;
200
201   switch (GST_EVENT_TYPE (event)) {
202     case GST_EVENT_SEEK:
203       GST_DEBUG ("seeking not supported");
204       res = FALSE;
205       break;
206     default:
207       res = gst_pad_event_default (pad, event);
208       break;
209   }
210
211   return res;
212 }
213
214
215 static GstStateChangeReturn
216 gst_mve_demux_change_state (GstElement * element, GstStateChange transition)
217 {
218   GstMveDemux *mve = GST_MVE_DEMUX (element);
219
220   if (GST_ELEMENT_CLASS (parent_class)->change_state) {
221     GstStateChangeReturn ret;
222
223     ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
224     if (ret != GST_STATE_CHANGE_SUCCESS)
225       return ret;
226   }
227
228   switch (transition) {
229     case GST_STATE_CHANGE_PAUSED_TO_READY:
230       gst_mve_demux_reset (mve);
231       break;
232     default:
233       break;
234   }
235
236   return GST_STATE_CHANGE_SUCCESS;
237 }
238
239 static gboolean
240 gst_mve_add_stream (GstMveDemux * mve, GstMveDemuxStream * stream,
241     GstTagList * list)
242 {
243   GstPadTemplate *templ;
244   gboolean ret = FALSE;
245
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");
250     } else {
251       templ = gst_static_pad_template_get (&audsrc_template);
252       stream->pad = gst_pad_new_from_template (templ, "audio");
253     }
254     gst_object_unref (templ);
255
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);
263
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);
267     ret = TRUE;
268   }
269
270   GST_DEBUG_OBJECT (mve, "setting caps %" GST_PTR_FORMAT, stream->caps);
271   gst_pad_set_caps (stream->pad, stream->caps);
272
273   if (list)
274     gst_element_found_tags_for_pad (GST_ELEMENT (mve), stream->pad, list);
275
276   return ret;
277 }
278
279 static GstFlowReturn
280 gst_mve_stream_error (GstMveDemux * mve, guint16 req, guint16 avail)
281 {
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;
285 }
286
287 static GstFlowReturn
288 gst_mve_buffer_alloc_for_pad (GstMveDemuxStream * stream,
289     guint32 size, GstBuffer ** buffer)
290 {
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;
295   return GST_FLOW_OK;
296 }
297
298 static GstFlowReturn
299 gst_mve_video_init (GstMveDemux * mve, const guint8 * data)
300 {
301   GST_DEBUG_OBJECT (mve, "init video");
302
303   if (mve->video_stream == NULL) {
304     GstMveDemuxStream *stream = g_new0 (GstMveDemuxStream, 1);
305
306     stream->buffer = NULL;
307     stream->back_buf1 = NULL;
308     stream->back_buf2 = NULL;
309     stream->offset = 0;
310     stream->width = 0;
311     stream->height = 0;
312     stream->code_map = NULL;
313     stream->code_map_avail = FALSE;
314     stream->palette = NULL;
315     stream->caps = NULL;
316     stream->last_ts = GST_CLOCK_TIME_NONE;
317     stream->last_flow = GST_FLOW_OK;
318     mve->video_stream = stream;
319   }
320
321   return GST_FLOW_OK;
322 }
323
324 static GstFlowReturn
325 gst_mve_video_create_buffer (GstMveDemux * mve, guint8 version,
326     const guint8 * data, guint16 len)
327 {
328   GstBuffer *buf;
329   guint16 w, h, n, true_color, bpp;
330   guint required, size;
331
332   GST_DEBUG_OBJECT (mve, "create video buffer");
333
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;
338   }
339
340   /* need 4 to 8 more bytes */
341   required = (version > 1) ? 8 : (version * 2);
342   if (len < required)
343     return gst_mve_stream_error (mve, required, len);
344
345   w = GST_READ_UINT16_LE (data) << 3;
346   h = GST_READ_UINT16_LE (data + 2) << 3;
347
348   if (version > 0)
349     n = GST_READ_UINT16_LE (data + 4);
350   else
351     n = 1;
352
353   if (version > 1)
354     true_color = GST_READ_UINT16_LE (data + 6);
355   else
356     true_color = 0;
357
358   bpp = (true_color ? 2 : 1);
359   size = w * h * bpp;
360
361   if (mve->video_stream->buffer != NULL) {
362     GST_DEBUG_OBJECT (mve, "video buffer already created");
363
364     if (GST_BUFFER_SIZE (mve->video_stream->buffer) == size * 2)
365       return GST_FLOW_OK;
366
367     GST_DEBUG_OBJECT (mve, "video buffer size has changed");
368     gst_buffer_unref (mve->video_stream->buffer);
369   }
370
371   GST_DEBUG_OBJECT (mve,
372       "allocating video buffer, w:%u, h:%u, n:%u, true_color:%u", w, h, n,
373       true_color);
374
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);
378
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);
387
388   return GST_FLOW_OK;
389 }
390
391 static GstFlowReturn
392 gst_mve_video_palette (GstMveDemux * mve, const guint8 * data, guint16 len)
393 {
394   GstBuffer *buf;
395   guint16 start, count;
396   const guint8 *pal;
397   guint32 *pal_ptr;
398   gint i;
399
400   GST_DEBUG_OBJECT (mve, "video palette");
401
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;
406   }
407
408   /* need 4 more bytes now, more later */
409   if (len < 4)
410     return gst_mve_stream_error (mve, 4, len);
411
412   len -= 4;
413
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);
417
418   /* need more bytes */
419   if (len < count * 3)
420     return gst_mve_stream_error (mve, count * 3, len);
421
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;
427   }
428
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);
433   } else {
434     buf = gst_buffer_new_and_alloc (MVE_PALETTE_COUNT * 4);
435     memset (GST_BUFFER_DATA (buf), 0, GST_BUFFER_SIZE (buf));
436   }
437
438   mve->video_stream->palette = buf;
439
440   pal = data + 4;
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 */
444     guint8 r, g, b;
445
446     r = (*pal) << 2;
447     ++pal;
448     g = (*pal) << 2;
449     ++pal;
450     b = (*pal) << 2;
451     ++pal;
452     *pal_ptr = (r << 16) | (g << 8) | (b);
453     ++pal_ptr;
454   }
455   return GST_FLOW_OK;
456 }
457
458 static GstFlowReturn
459 gst_mve_video_palette_compressed (GstMveDemux * mve, const guint8 * data,
460     guint16 len)
461 {
462   guint8 mask;
463   gint i, j;
464   guint32 *col;
465
466   GST_DEBUG_OBJECT (mve, "compressed video palette");
467
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;
472   }
473
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;
478   }
479
480   /* need at least 32 more bytes */
481   if (len < 32)
482     return gst_mve_stream_error (mve, 32, len);
483
484   len -= 32;
485
486   for (i = 0; i < 32; ++i) {
487     mask = GST_READ_UINT8 (data);
488     ++data;
489
490     if (mask != 0) {
491       for (j = 0; j < 8; ++j) {
492         if (mask & (1 << j)) {
493           guint8 r, g, b;
494
495           /* need 3 more bytes */
496           if (len < 3)
497             return gst_mve_stream_error (mve, 3, len);
498
499           len -= 3;
500
501           r = (*data) << 2;
502           ++data;
503           g = (*data) << 2;
504           ++data;
505           b = (*data) << 2;
506           ++data;
507           col =
508               ((guint32 *) GST_BUFFER_DATA (mve->video_stream->palette)) +
509               i * 8 + j;
510           *col = (r << 16) | (g << 8) | (b);
511         }
512       }
513     }
514   }
515
516   return GST_FLOW_OK;
517 }
518
519 static GstFlowReturn
520 gst_mve_video_code_map (GstMveDemux * mve, const guint8 * data, guint16 len)
521 {
522   gint min;
523
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;
527   }
528
529   GST_DEBUG_OBJECT (mve, "found code map, size:%u", len);
530
531   /* decoding is done in 8x8 blocks using 4-bit opcodes */
532   min = (mve->video_stream->width * mve->video_stream->height) / (8 * 8 * 2);
533
534   if (len < min)
535     return gst_mve_stream_error (mve, min, len);
536
537   memcpy (mve->video_stream->code_map, data, min);
538   mve->video_stream->code_map_avail = TRUE;
539   return GST_FLOW_OK;
540 }
541
542 static GstFlowReturn
543 gst_mve_video_data (GstMveDemux * mve, const guint8 * data, guint16 len,
544     GstBuffer ** output)
545 {
546   GstFlowReturn ret = GST_FLOW_OK;
547   gint16 cur_frame, last_frame;
548   gint16 x_offset, y_offset;
549   gint16 x_size, y_size;
550   guint16 flags;
551   gint dec;
552   GstBuffer *buf = NULL;
553   GstMveDemuxStream *s = mve->video_stream;
554
555   GST_LOG_OBJECT (mve, "video data");
556
557   if (s == NULL) {
558     GST_ELEMENT_ERROR (mve, STREAM, DECODE, (NULL),
559         ("trying to decode video data before stream was initialized"));
560     return GST_FLOW_ERROR;
561   }
562
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;
566     else
567       s->last_ts = 0;
568   }
569
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;
574   }
575
576   /* need at least 14 more bytes */
577   if (len < 14)
578     return gst_mve_stream_error (mve, 14, len);
579
580   len -= 14;
581
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);
589   data += 14;
590
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);
594
595   if (flags & MVE_VIDEO_DELTA_FRAME) {
596     guint8 *temp = s->back_buf1;
597
598     s->back_buf1 = s->back_buf2;
599     s->back_buf2 = temp;
600   }
601
602   ret = gst_mve_buffer_alloc_for_pad (s, s->width * s->height * s->bpp, &buf);
603   if (ret != GST_FLOW_OK)
604     return ret;
605
606   if (s->bpp == 2) {
607     dec = ipvideo_decode_frame16 (s, data, len);
608   } else {
609     if (s->palette == NULL) {
610       GST_ELEMENT_ERROR (mve, STREAM, DECODE, (NULL), ("no palette available"));
611       goto error;
612     }
613
614     dec = ipvideo_decode_frame8 (s, data, len);
615   }
616   if (dec != 0)
617     goto error;
618
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;
622
623   if (s->bpp == 1) {
624     GstCaps *caps;
625
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);
632   }
633
634   *output = buf;
635   return GST_FLOW_OK;
636
637 error:
638   gst_buffer_unref (buf);
639   return GST_FLOW_ERROR;
640 }
641
642 static GstFlowReturn
643 gst_mve_audio_init (GstMveDemux * mve, guint8 version, const guint8 * data,
644     guint16 len)
645 {
646   GstMveDemuxStream *stream;
647   guint16 flags;
648   guint32 requested_buffer;
649   GstTagList *list;
650   gchar *name;
651
652   GST_DEBUG_OBJECT (mve, "init audio");
653
654   /* need 8 more bytes */
655   if (len < 8)
656     return gst_mve_stream_error (mve, 8, len);
657
658   if (mve->audio_stream == NULL) {
659     stream = g_new0 (GstMveDemuxStream, 1);
660     stream->offset = 0;
661     stream->last_ts = 0;
662     stream->last_flow = GST_FLOW_OK;
663     mve->audio_stream = stream;
664   } else {
665     stream = mve->audio_stream;
666     gst_caps_unref (stream->caps);
667   }
668
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);
672
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)) ?
679       TRUE : FALSE;
680
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);
685
686   stream->caps = gst_caps_from_string ("audio/x-raw-int");
687   if (stream->caps == NULL)
688     return GST_FLOW_ERROR;
689
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;
705   }
706
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);
711   g_free (name);
712
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;
717   else
718     return GST_FLOW_OK;
719 }
720
721 static GstFlowReturn
722 gst_mve_audio_data (GstMveDemux * mve, guint8 type, const guint8 * data,
723     guint16 len, GstBuffer ** output)
724 {
725   GstFlowReturn ret;
726   GstMveDemuxStream *s = mve->audio_stream;
727   GstBuffer *buf = NULL;
728   guint16 stream_mask;
729   guint16 size;
730
731   GST_LOG_OBJECT (mve, "audio data");
732
733   if (s == NULL) {
734     GST_ELEMENT_ERROR (mve, STREAM, DECODE, (NULL),
735         ("trying to queue samples with no audio stream"));
736     return GST_FLOW_ERROR;
737   }
738
739   /* need at least 6 more bytes */
740   if (len < 6)
741     return gst_mve_stream_error (mve, 6, len);
742
743   len -= 6;
744
745   stream_mask = GST_READ_UINT16_LE (data + 2);
746   size = GST_READ_UINT16_LE (data + 4);
747   data += 6;
748
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;
752
753     if (type == MVE_OC_AUDIO_DATA) {
754       guint16 required = (s->compression ? size / 2 + s->n_channels : size);
755
756       if (len < required)
757         return gst_mve_stream_error (mve, required, len);
758
759       ret = gst_mve_buffer_alloc_for_pad (s, size, &buf);
760
761       if (ret != GST_FLOW_OK)
762         return ret;
763
764       if (s->compression)
765         ipaudio_uncompress ((gint16 *) GST_BUFFER_DATA (buf), size,
766             data, s->n_channels);
767       else
768         memcpy (GST_BUFFER_DATA (buf), data, size);
769
770       GST_DEBUG_OBJECT (mve, "created audio buffer, size:%u, stream_mask:%x",
771           size, stream_mask);
772     } else {
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);
777     }
778
779     GST_BUFFER_DURATION (buf) = duration;
780     GST_BUFFER_OFFSET_END (buf) = s->offset + n_samples;
781     *output = buf;
782
783     s->offset += n_samples;
784     s->last_ts += duration;
785   } else {
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");
790   }
791
792   return GST_FLOW_OK;
793 }
794
795 static GstFlowReturn
796 gst_mve_timer_create (GstMveDemux * mve, const guint8 * data, guint16 len,
797     GstBuffer ** buf)
798 {
799   guint32 t_rate;
800   guint16 t_subdiv;
801   GstMveDemuxStream *s;
802   GstTagList *list;
803   gint rate_nom, rate_den;
804
805   g_return_val_if_fail (mve->video_stream != NULL, GST_FLOW_ERROR);
806
807   /* need 6 more bytes */
808   if (len < 6)
809     return gst_mve_stream_error (mve, 6, len);
810
811   t_rate = GST_READ_UINT32_LE (data);
812   t_subdiv = GST_READ_UINT16_LE (data + 4);
813
814   GST_DEBUG_OBJECT (mve, "found timer:%ux%u", t_rate, t_subdiv);
815   mve->frame_duration = t_rate * t_subdiv * GST_USECOND;
816
817   /* now really start rolling... */
818   s = mve->video_stream;
819
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;
825   }
826
827   if (s->pad != NULL) {
828     if (s->caps != NULL) {
829       gst_caps_unref (s->caps);
830       s->caps = NULL;
831     }
832     if (s->code_map != NULL) {
833       g_free (s->code_map);
834       s->code_map = NULL;
835     }
836     list = NULL;
837   } else {
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);
841   }
842
843   s->caps = gst_caps_from_string ("video/x-raw-rgb");
844   if (s->caps == NULL)
845     return GST_FLOW_ERROR;
846
847   rate_nom = GST_SECOND / GST_USECOND;
848   rate_den = mve->frame_duration / GST_USECOND;
849
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);
857   if (s->bpp > 1) {
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 */
861         NULL);
862   }
863
864   s->code_map = g_malloc ((s->width * s->height) / (8 * 8 * 2));
865
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;
870   else
871     return GST_FLOW_OK;
872 }
873
874 static void
875 gst_mve_end_chunk (GstMveDemux * mve)
876 {
877   GST_LOG_OBJECT (mve, "end of chunk");
878
879   if (mve->video_stream != NULL)
880     mve->video_stream->code_map_avail = FALSE;
881 }
882
883 /* parse segment */
884 static GstFlowReturn
885 gst_mve_parse_segment (GstMveDemux * mve, GstMveDemuxStream ** stream,
886     GstBuffer ** send)
887 {
888   GstFlowReturn ret = GST_FLOW_OK;
889   const guint8 *buffer, *data;
890   guint8 type, version;
891   guint16 len;
892
893   buffer = gst_adapter_peek (mve->adapter, mve->needed_bytes);
894
895   type = GST_MVE_SEGMENT_TYPE (buffer);
896
897   /* check whether to handle the segment */
898   if (type < 32) {
899     version = GST_MVE_SEGMENT_VERSION (buffer);
900     len = GST_MVE_SEGMENT_SIZE (buffer);
901     data = buffer + 4;
902
903     switch (type) {
904
905       case MVE_OC_END_OF_CHUNK:
906         gst_mve_end_chunk (mve);
907         break;
908       case MVE_OC_CREATE_TIMER:
909         ret = gst_mve_timer_create (mve, data, len, send);
910         *stream = mve->audio_stream;
911         break;
912       case MVE_OC_AUDIO_BUFFERS:
913         ret = gst_mve_audio_init (mve, version, data, len);
914         break;
915       case MVE_OC_VIDEO_BUFFERS:
916         ret = gst_mve_video_create_buffer (mve, version, data, len);
917         break;
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;
922         break;
923       case MVE_OC_VIDEO_MODE:
924         ret = gst_mve_video_init (mve, data);
925         break;
926       case MVE_OC_PALETTE:
927         ret = gst_mve_video_palette (mve, data, len);
928         break;
929       case MVE_OC_PALETTE_COMPRESSED:
930         ret = gst_mve_video_palette_compressed (mve, data, len);
931         break;
932       case MVE_OC_CODE_MAP:
933         ret = gst_mve_video_code_map (mve, data, len);
934         break;
935       case MVE_OC_VIDEO_DATA:
936         ret = gst_mve_video_data (mve, data, len, send);
937         *stream = mve->video_stream;
938         break;
939
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",
945             type, version);
946         break;
947       case 0x13:               /* ??? */
948       case 0x14:               /* ??? */
949       case 0x15:               /* ??? */
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,
953             version);
954         break;
955       default:
956         GST_WARNING_OBJECT (mve,
957             "unhandled segment type:0x%02x, version:0x%02x", type, version);
958         break;
959     }
960   }
961
962   gst_adapter_flush (mve->adapter, mve->needed_bytes);
963   return ret;
964 }
965
966 static GstFlowReturn
967 gst_mve_demux_chain (GstPad * sinkpad, GstBuffer * inbuf)
968 {
969   GstMveDemux *mve = GST_MVE_DEMUX (GST_PAD_PARENT (sinkpad));
970   GstFlowReturn ret = GST_FLOW_OK;
971
972   gst_adapter_push (mve->adapter, inbuf);
973
974   GST_DEBUG_OBJECT (mve, "queuing buffer, needed:%d, available:%u",
975       mve->needed_bytes, gst_adapter_available (mve->adapter));
976
977   while ((gst_adapter_available (mve->adapter) >= mve->needed_bytes) &&
978       (ret == GST_FLOW_OK)) {
979     GstMveDemuxStream *stream = NULL;
980     GstBuffer *outbuf = NULL;
981
982     switch (mve->state) {
983       case MVEDEMUX_STATE_INITIAL:
984         gst_adapter_flush (mve->adapter, mve->needed_bytes);
985
986         mve->chunk_offset += mve->needed_bytes;
987         mve->needed_bytes = 4;
988         mve->state = MVEDEMUX_STATE_NEXT_CHUNK;
989         break;
990
991       case MVEDEMUX_STATE_NEXT_CHUNK:{
992         const guint8 *data;
993         guint16 size;
994
995         data = gst_adapter_peek (mve->adapter, mve->needed_bytes);
996         size = GST_MVE_SEGMENT_SIZE (data);
997
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);
1001
1002           gst_adapter_flush (mve->adapter, mve->needed_bytes);
1003           mve->chunk_size = size;
1004           mve->chunk_offset = 0;
1005
1006           if (chunk_type > MVE_CHUNK_END) {
1007             GST_WARNING_OBJECT (mve,
1008                 "skipping unknown chunk type 0x%02x of size:%u", chunk_type,
1009                 size);
1010             mve->needed_bytes += size;
1011             mve->state = MVEDEMUX_STATE_SKIP;
1012           } else {
1013             GST_DEBUG_OBJECT (mve, "found new chunk type 0x%02x of size:%u",
1014                 chunk_type, size);
1015           }
1016         } else if (mve->chunk_offset <= mve->chunk_size) {
1017           /* new segment */
1018           GST_DEBUG_OBJECT (mve, "found segment type 0x%02x of size:%u",
1019               GST_MVE_SEGMENT_TYPE (data), size);
1020
1021           mve->needed_bytes += size;
1022           mve->state = MVEDEMUX_STATE_MOVIE;
1023         }
1024       }
1025         break;
1026
1027       case MVEDEMUX_STATE_MOVIE:
1028         ret = gst_mve_parse_segment (mve, &stream, &outbuf);
1029
1030         if ((ret == GST_FLOW_OK) && (outbuf != NULL)) {
1031           /* send buffer */
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));
1037
1038           ret = gst_pad_push (stream->pad, outbuf);
1039           stream->last_flow = ret;
1040         }
1041
1042         if (ret == GST_FLOW_NOT_LINKED) {
1043           if (mve->audio_stream
1044               && mve->audio_stream->last_flow != GST_FLOW_NOT_LINKED)
1045             ret = GST_FLOW_OK;
1046           if (mve->video_stream
1047               && mve->video_stream->last_flow != GST_FLOW_NOT_LINKED)
1048             ret = GST_FLOW_OK;
1049         }
1050
1051         /* update current offset */
1052         mve->chunk_offset += mve->needed_bytes;
1053
1054         mve->state = MVEDEMUX_STATE_NEXT_CHUNK;
1055         mve->needed_bytes = 4;
1056         break;
1057
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;
1063         break;
1064
1065       default:
1066         GST_ERROR_OBJECT (mve, "invalid state: %d", mve->state);
1067         break;
1068     }
1069   }
1070
1071   return ret;
1072 }
1073
1074 static void
1075 gst_mve_demux_dispose (GObject * obj)
1076 {
1077   GstMveDemux *mve = GST_MVE_DEMUX (obj);
1078
1079   if (mve->adapter) {
1080     g_object_unref (mve->adapter);
1081     mve->adapter = NULL;
1082   }
1083
1084   G_OBJECT_CLASS (parent_class)->dispose (obj);
1085 }
1086
1087 static void
1088 gst_mve_demux_base_init (GstMveDemuxClass * klass)
1089 {
1090
1091   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
1092
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",
1097       "Codec/Demuxer",
1098       "Demultiplex an Interplay movie (MVE) stream into audio and video",
1099       "Jens Granseuer <jensgr@gmx.net>");
1100 }
1101
1102 static void
1103 gst_mve_demux_class_init (GstMveDemuxClass * klass)
1104 {
1105   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1106   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
1107
1108   parent_class = g_type_class_peek_parent (klass);
1109
1110   gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_mve_demux_dispose);
1111
1112   element_class->change_state = GST_DEBUG_FUNCPTR (gst_mve_demux_change_state);
1113 }
1114
1115 static void
1116 gst_mve_demux_init (GstMveDemux * mve)
1117 {
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);
1122
1123   mve->adapter = gst_adapter_new ();
1124   gst_mve_demux_reset (mve);
1125 }
1126
1127 GType
1128 gst_mve_demux_get_type (void)
1129 {
1130   static GType plugin_type = 0;
1131
1132   if (!plugin_type) {
1133     const GTypeInfo plugin_info = {
1134       sizeof (GstMveDemuxClass),
1135       (GBaseInitFunc) gst_mve_demux_base_init,
1136       NULL,
1137       (GClassInitFunc) gst_mve_demux_class_init,
1138       NULL,
1139       NULL,
1140       sizeof (GstMveDemux),
1141       0,
1142       (GInstanceInitFunc) gst_mve_demux_init,
1143     };
1144
1145     GST_DEBUG_CATEGORY_INIT (mvedemux_debug, "mvedemux",
1146         0, "Interplay MVE movie demuxer");
1147
1148     plugin_type = g_type_register_static (GST_TYPE_ELEMENT,
1149         "GstMveDemux", &plugin_info, 0);
1150   }
1151   return plugin_type;
1152 }