ext/flac/gstflacdec.c: Only return true if we actually filled something in. Prevents...
[platform/upstream/gst-plugins-good.git] / gst / flx / gstflxdec.c
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@temple-baptist.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23 #include <string.h>
24
25 #include "flx_fmt.h"
26 #include "gstflxdec.h"
27 #include <gst/video/video.h>
28
29 #define JIFFIE  (GST_SECOND/70)
30
31 GST_DEBUG_CATEGORY_STATIC (flxdec_debug);
32 #define GST_CAT_DEFAULT flxdec_debug
33
34 /* flx element information */
35 static GstElementDetails flxdec_details = {
36   "FLX Decoder",
37   "Codec/Decoder/Audio",
38   "FLX decoder",
39   "Sepp Wijnands <mrrazz@garbage-coderz.net>"
40 };
41
42 /* Flx signals and args */
43 enum
44 {
45   /* FILL ME */
46   LAST_SIGNAL
47 };
48
49 enum
50 {
51   ARG_0
52 };
53
54 /* input */
55 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
56     GST_PAD_SINK,
57     GST_PAD_ALWAYS,
58     GST_STATIC_CAPS ("video/x-fli")
59     );
60
61 /* output */
62 static GstStaticPadTemplate src_video_factory = GST_STATIC_PAD_TEMPLATE ("src",
63     GST_PAD_SRC,
64     GST_PAD_ALWAYS,
65     GST_STATIC_CAPS (GST_VIDEO_CAPS_xRGB_HOST_ENDIAN)
66     );
67
68
69 static void gst_flxdec_class_init (GstFlxDecClass * klass);
70 static void gst_flxdec_base_init (GstFlxDecClass * klass);
71 static void gst_flxdec_init (GstFlxDec * flxdec);
72
73 static void gst_flxdec_loop (GstElement * element);
74
75 static GstElementStateReturn gst_flxdec_change_state (GstElement * element);
76
77 static void gst_flxdec_set_property (GObject * object, guint prop_id,
78     const GValue * value, GParamSpec * pspec);
79 static void gst_flxdec_get_property (GObject * object, guint prop_id,
80     GValue * value, GParamSpec * pspec);
81
82
83 static void flx_decode_color (GstFlxDec *, guchar *, guchar *, gint);
84 static void flx_decode_brun (GstFlxDec *, guchar *, guchar *);
85 static void flx_decode_delta_fli (GstFlxDec *, guchar *, guchar *);
86 static void flx_decode_delta_flc (GstFlxDec *, guchar *, guchar *);
87
88 #define rndalign(off) ((off) + ((off) % 2))
89
90 static GstElementClass *parent_class = NULL;
91
92 GType
93 gst_flxdec_get_type (void)
94 {
95   static GType flxdec_type = 0;
96
97   if (!flxdec_type) {
98     static const GTypeInfo flxdec_info = {
99       sizeof (GstFlxDecClass),
100       (GBaseInitFunc) gst_flxdec_base_init,
101       NULL,
102       (GClassInitFunc) gst_flxdec_class_init,
103       NULL,
104       NULL,
105       sizeof (GstFlxDec),
106       0,
107       (GInstanceInitFunc) gst_flxdec_init,
108     };
109
110     flxdec_type =
111         g_type_register_static (GST_TYPE_ELEMENT, "GstFlxDec", &flxdec_info, 0);
112   }
113   return flxdec_type;
114 }
115
116 static void
117 gst_flxdec_base_init (GstFlxDecClass * klass)
118 {
119   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
120
121   gst_element_class_set_details (gstelement_class, &flxdec_details);
122   gst_element_class_add_pad_template (gstelement_class,
123       gst_static_pad_template_get (&sink_factory));
124   gst_element_class_add_pad_template (gstelement_class,
125       gst_static_pad_template_get (&src_video_factory));
126 }
127
128 static void
129 gst_flxdec_class_init (GstFlxDecClass * klass)
130 {
131   GObjectClass *gobject_class;
132   GstElementClass *gstelement_class;
133
134   gobject_class = (GObjectClass *) klass;
135   gstelement_class = (GstElementClass *) klass;
136
137   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
138
139   GST_DEBUG_CATEGORY_INIT (flxdec_debug, "flxdec", 0, "FLX video decoder");
140
141   gobject_class->set_property = gst_flxdec_set_property;
142   gobject_class->get_property = gst_flxdec_get_property;
143
144   gstelement_class->change_state = gst_flxdec_change_state;
145 }
146
147
148
149 static void
150 gst_flxdec_init (GstFlxDec * flxdec)
151 {
152   flxdec->sinkpad =
153       gst_pad_new_from_template (gst_static_pad_template_get (&sink_factory),
154       "sink");
155   gst_element_add_pad (GST_ELEMENT (flxdec), flxdec->sinkpad);
156   gst_element_set_loop_function (GST_ELEMENT (flxdec), gst_flxdec_loop);
157
158   flxdec->srcpad =
159       gst_pad_new_from_template (gst_static_pad_template_get
160       (&src_video_factory), "src");
161   gst_element_add_pad (GST_ELEMENT (flxdec), flxdec->srcpad);
162
163   flxdec->bs = NULL;
164   flxdec->frame = NULL;
165   flxdec->delta = NULL;
166 }
167
168 static void
169 flx_decode_chunks (GstFlxDec * flxdec, gulong count, gchar * data, gchar * dest)
170 {
171   FlxFrameChunk *hdr;
172
173   g_return_if_fail (data != NULL);
174
175   while (count--) {
176     hdr = (FlxFrameChunk *) data;
177     data += FlxFrameChunkSize;
178
179     switch (hdr->id) {
180       case FLX_COLOR64:
181         flx_decode_color (flxdec, data, dest, 2);
182         data += rndalign (hdr->size) - FlxFrameChunkSize;
183         break;
184
185       case FLX_COLOR256:
186         flx_decode_color (flxdec, data, dest, 0);
187         data += rndalign (hdr->size) - FlxFrameChunkSize;
188         break;
189
190       case FLX_BRUN:
191         flx_decode_brun (flxdec, data, dest);
192         data += rndalign (hdr->size) - FlxFrameChunkSize;
193         break;
194
195       case FLX_LC:
196         flx_decode_delta_fli (flxdec, data, dest);
197         data += rndalign (hdr->size) - FlxFrameChunkSize;
198         break;
199
200       case FLX_SS2:
201         flx_decode_delta_flc (flxdec, data, dest);
202         data += rndalign (hdr->size) - FlxFrameChunkSize;
203         break;
204
205       case FLX_BLACK:
206         memset (dest, 0, flxdec->size);
207         break;
208
209       case FLX_MINI:
210         data += rndalign (hdr->size) - FlxFrameChunkSize;
211         break;
212
213       default:
214         GST_WARNING ("Unimplented chunk type: 0x%02x size: %d - skipping",
215             hdr->id, hdr->size);
216         data += rndalign (hdr->size) - FlxFrameChunkSize;
217         break;
218     }
219   }
220 }
221
222
223 static void
224 flx_decode_color (GstFlxDec * flxdec, guchar * data, guchar * dest, gint scale)
225 {
226   guint packs, count, indx;
227
228   g_return_if_fail (flxdec != NULL);
229
230   packs = (data[0] + (data[1] << 8));
231
232   data += 2;
233   indx = 0;
234
235   GST_LOG ("GstFlxDec: cmap packs: %d", packs);
236   while (packs--) {
237     /* color map index + skip count */
238     indx += *data++;
239
240     /* number of rgb triplets */
241     count = *data++ & 0xff;
242     if (count == 0)
243       count = 256;
244
245     GST_LOG ("GstFlxDec: cmap count: %d (indx: %d)\n", count, indx);
246     flx_set_palette_vector (flxdec->converter, indx, count, data, scale);
247
248     data += (count * 3);
249   }
250 }
251
252 static void
253 flx_decode_brun (GstFlxDec * flxdec, guchar * data, guchar * dest)
254 {
255   gulong count, lines, row;
256   guchar x;
257
258   g_return_if_fail (flxdec != NULL);
259
260   lines = flxdec->hdr.height;
261   while (lines--) {
262     /* packet count.  
263      * should not be used anymore, since the flc format can
264      * contain more then 255 RLE packets. we use the frame 
265      * width instead. 
266      */
267     data++;
268
269     row = flxdec->hdr.width;
270     while (row) {
271       count = *data++;
272
273       if (count > 0x7f) {
274         /* literal run */
275         count = 0x100 - count;
276         row -= count;
277
278         while (count--)
279           *dest++ = *data++;
280
281       } else {
282         /* replicate run */
283         row -= count;
284         x = *data++;
285
286         while (count--)
287           *dest++ = x;
288       }
289     }
290   }
291 }
292
293 static void
294 flx_decode_delta_fli (GstFlxDec * flxdec, guchar * data, guchar * dest)
295 {
296   gulong count, packets, lines, start_line, start_l;
297   guchar *start_p, x;
298
299   g_return_if_fail (flxdec != NULL);
300   g_return_if_fail (flxdec->delta != NULL);
301
302
303   /* use last frame for delta */
304   memcpy (dest, GST_BUFFER_DATA (flxdec->delta),
305       GST_BUFFER_SIZE (flxdec->delta));
306
307   start_line = (data[0] + (data[1] << 8));
308   lines = (data[2] + (data[3] << 8));
309   data += 4;
310
311   /* start position of delta */
312   dest += (flxdec->hdr.width * start_line);
313   start_p = dest;
314   start_l = lines;
315
316   while (lines--) {
317     /* packet count */
318     packets = *data++;
319
320     while (packets--) {
321       /* skip count */
322       dest += *data++;
323
324       /* RLE count */
325       count = *data++;
326
327       if (count > 0x7f) {
328         /* literal run */
329         count = 0x100 - count;
330         x = *data++;
331
332         while (count--)
333           *dest++ = x;
334
335       } else {
336         /* replicate run */
337         while (count--)
338           *dest++ = *data++;
339       }
340     }
341     start_p += flxdec->hdr.width;
342     dest = start_p;
343   }
344 }
345
346 static void
347 flx_decode_delta_flc (GstFlxDec * flxdec, guchar * data, guchar * dest)
348 {
349   gulong count, lines, start_l, opcode;
350   guchar *start_p;
351
352   g_return_if_fail (flxdec != NULL);
353   g_return_if_fail (flxdec->delta != NULL);
354
355
356   /* use last frame for delta */
357   memcpy (dest, GST_BUFFER_DATA (flxdec->delta),
358       GST_BUFFER_SIZE (flxdec->delta));
359
360   lines = (data[0] + (data[1] << 8));
361   data += 2;
362
363   start_p = dest;
364   start_l = lines;
365
366   while (lines) {
367     dest = start_p + (flxdec->hdr.width * (start_l - lines));
368
369     /* process opcode(s) */
370     while ((opcode = (data[0] + (data[1] << 8))) & 0xc000) {
371       data += 2;
372       if ((opcode & 0xc000) == 0xc000) {
373         /* skip count */
374         start_l += (0x10000 - opcode);
375         dest += flxdec->hdr.width * (0x10000 - opcode);
376       } else {
377         /* last pixel */
378         dest += flxdec->hdr.width;
379         *dest++ = (opcode & 0xff);
380       }
381     }
382     data += 2;
383
384     /* last opcode is the packet count */
385     while (opcode--) {
386       /* skip count */
387       dest += *data++;
388
389       /* RLE count */
390       count = *data++;
391
392       if (count > 0x7f) {
393         /* replicate word run */
394         count = 0x100 - count;
395         while (count--) {
396           *dest++ = data[0];
397           *dest++ = data[1];
398         }
399         data += 2;
400       } else {
401         /* literal word run */
402         while (count--) {
403           *dest++ = *data++;
404           *dest++ = *data++;
405         }
406       }
407     }
408     lines--;
409   }
410 }
411
412 static GstBuffer *
413 flx_get_data (GstFlxDec * flxdec, gulong size)
414 {
415   GstBuffer *retbuf;
416   guint32 got_bytes;
417
418   g_return_val_if_fail (flxdec != NULL, NULL);
419
420   got_bytes = gst_bytestream_read (flxdec->bs, &retbuf, size);
421   if (got_bytes < size) {
422     GstEvent *event;
423     guint32 remaining;
424
425     gst_bytestream_get_status (flxdec->bs, &remaining, &event);
426     gst_pad_event_default (flxdec->sinkpad, event);
427   }
428
429   return retbuf;
430 }
431
432
433 static void
434 gst_flxdec_loop (GstElement * element)
435 {
436   GstBuffer *buf;
437   GstBuffer *databuf;
438   guchar *data, *chunk;
439   GstCaps *caps;
440
441   GstFlxDec *flxdec;
442   FlxHeader *flxh;
443   FlxFrameChunk *flxfh;
444
445   g_return_if_fail (element != NULL);
446   g_return_if_fail (GST_IS_FLXDEC (element));
447
448   GST_DEBUG ("entering loop function");
449
450   flxdec = GST_FLXDEC (element);
451
452   if (flxdec->state == GST_FLXDEC_READ_HEADER) {
453     databuf = flx_get_data (flxdec, FlxHeaderSize);
454
455     if (!databuf) {
456       GST_LOG ("empty buffer");
457       return;
458     }
459
460     data = GST_BUFFER_DATA (databuf);
461
462     memcpy ((char *) &flxdec->hdr, data, sizeof (FlxHeader));
463
464     gst_buffer_unref (databuf);
465
466     flxh = &flxdec->hdr;
467
468     /* check header */
469     if (flxh->type != FLX_MAGICHDR_FLI &&
470         flxh->type != FLX_MAGICHDR_FLC && flxh->type != FLX_MAGICHDR_FLX) {
471       GST_ELEMENT_ERROR (element, STREAM, WRONG_TYPE, (NULL),
472           ("not a flx file (type %d)\n", flxh->type));
473       return;
474     }
475
476
477     GST_LOG ("size      :  %d\n", flxh->size);
478     GST_LOG ("frames    :  %d\n", flxh->frames);
479     GST_LOG ("width     :  %d\n", flxh->width);
480     GST_LOG ("height    :  %d\n", flxh->height);
481     GST_LOG ("depth     :  %d\n", flxh->depth);
482     GST_LOG ("speed     :  %d\n", flxh->speed);
483
484     flxdec->next_time = 0;
485
486     if (flxh->type == FLX_MAGICHDR_FLI) {
487       flxdec->frame_time = JIFFIE * flxh->speed;
488     } else {
489       flxdec->frame_time = flxh->speed * GST_MSECOND;
490     }
491
492     caps = gst_caps_from_string (GST_VIDEO_CAPS_xRGB_HOST_ENDIAN);
493     gst_caps_set_simple (caps,
494         "width", G_TYPE_INT, flxh->width,
495         "height", G_TYPE_INT, flxh->height,
496         "framerate", G_TYPE_DOUBLE, GST_SECOND / flxdec->frame_time, NULL);
497
498     if (flxh->depth <= 8)
499       flxdec->converter =
500           flx_colorspace_converter_new (flxh->width, flxh->height);
501
502     if (flxh->type == FLX_MAGICHDR_FLC || flxh->type == FLX_MAGICHDR_FLX) {
503       GST_LOG ("(FLC) aspect_dx :  %d\n", flxh->aspect_dx);
504       GST_LOG ("(FLC) aspect_dy :  %d\n", flxh->aspect_dy);
505       GST_LOG ("(FLC) oframe1   :  0x%08x\n", flxh->oframe1);
506       GST_LOG ("(FLC) oframe2   :  0x%08x\n", flxh->oframe2);
507     }
508
509     flxdec->size = (flxh->width * flxh->height);
510
511     /* create delta and output frame */
512     flxdec->frame = gst_buffer_new ();
513     flxdec->delta = gst_buffer_new ();
514     GST_BUFFER_DATA (flxdec->frame) = g_malloc (flxdec->size);
515     GST_BUFFER_SIZE (flxdec->frame) = flxdec->size;
516     GST_BUFFER_DATA (flxdec->delta) = g_malloc (flxdec->size);
517     GST_BUFFER_SIZE (flxdec->delta) = flxdec->size;
518
519     flxdec->state = GST_FLXDEC_PLAYING;
520   } else if (flxdec->state == GST_FLXDEC_PLAYING) {
521     GstBuffer *out;
522
523     databuf = flx_get_data (flxdec, FlxFrameChunkSize);
524     if (!databuf)
525       return;
526
527     flxfh = (FlxFrameChunk *) GST_BUFFER_DATA (databuf);
528
529     switch (flxfh->id) {
530       case FLX_FRAME_TYPE:
531         buf = flx_get_data (flxdec, flxfh->size - FlxFrameChunkSize);
532
533         chunk = GST_BUFFER_DATA (buf);
534
535         if (((FlxFrameType *) chunk)->chunks == 0)
536           break;
537
538         /* create 32 bits output frame */
539         out = gst_buffer_new ();
540         GST_BUFFER_DATA (out) = g_malloc (flxdec->size * 4);
541         GST_BUFFER_SIZE (out) = flxdec->size * 4;
542
543         /* decode chunks */
544         flx_decode_chunks (flxdec,
545             ((FlxFrameType *) chunk)->chunks,
546             GST_BUFFER_DATA (buf) + FlxFrameTypeSize,
547             GST_BUFFER_DATA (flxdec->frame));
548
549         /* destroy input buffer */
550         gst_buffer_unref (buf);
551
552         /* save copy of the current frame for possible delta. */
553         memcpy (GST_BUFFER_DATA (flxdec->delta),
554             GST_BUFFER_DATA (flxdec->frame), GST_BUFFER_SIZE (flxdec->delta));
555
556         /* convert current frame. */
557         flx_colorspace_convert (flxdec->converter,
558             GST_BUFFER_DATA (flxdec->frame), GST_BUFFER_DATA (out));
559
560         GST_BUFFER_TIMESTAMP (out) = flxdec->next_time;
561         flxdec->next_time += flxdec->frame_time;
562
563         gst_pad_push (flxdec->srcpad, GST_DATA (out));
564
565         break;
566     }
567
568     /* destroy header buffer */
569     gst_buffer_unref (databuf);
570   }
571 }
572
573 static GstElementStateReturn
574 gst_flxdec_change_state (GstElement * element)
575 {
576   GstFlxDec *flxdec;
577
578   flxdec = GST_FLXDEC (element);
579
580   switch (GST_STATE_TRANSITION (element)) {
581     case GST_STATE_NULL_TO_READY:
582       break;
583     case GST_STATE_READY_TO_PAUSED:
584       flxdec->bs = gst_bytestream_new (flxdec->sinkpad);
585       flxdec->state = GST_FLXDEC_READ_HEADER;
586       break;
587     case GST_STATE_PAUSED_TO_PLAYING:
588       break;
589     case GST_STATE_PLAYING_TO_PAUSED:
590       break;
591     case GST_STATE_PAUSED_TO_READY:
592       gst_buffer_unref (flxdec->frame);
593       flxdec->frame = NULL;
594       gst_buffer_unref (flxdec->delta);
595       flxdec->delta = NULL;
596       gst_bytestream_destroy (flxdec->bs);
597       break;
598     case GST_STATE_READY_TO_NULL:
599       break;
600   }
601
602   parent_class->change_state (element);
603
604   return GST_STATE_SUCCESS;
605 }
606
607 static void
608 gst_flxdec_set_property (GObject * object, guint prop_id, const GValue * value,
609     GParamSpec * pspec)
610 {
611   GstFlxDec *flxdec;
612
613   /* it's not null if we got it, but it might not be ours */
614   g_return_if_fail (GST_IS_FLXDEC (object));
615   flxdec = GST_FLXDEC (object);
616
617   switch (prop_id) {
618     default:
619       break;
620   }
621 }
622
623 static void
624 gst_flxdec_get_property (GObject * object, guint prop_id, GValue * value,
625     GParamSpec * pspec)
626 {
627   GstFlxDec *flxdec;
628
629   /* it's not null if we got it, but it might not be ours */
630   g_return_if_fail (GST_IS_FLXDEC (object));
631   flxdec = GST_FLXDEC (object);
632
633   switch (prop_id) {
634     default:
635       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
636       break;
637   }
638 }
639
640 static gboolean
641 plugin_init (GstPlugin * plugin)
642 {
643   if (!gst_library_load ("gstbytestream"))
644     return FALSE;
645
646   return gst_element_register (plugin, "flxdec",
647       GST_RANK_PRIMARY, GST_TYPE_FLXDEC);
648 }
649
650 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
651     GST_VERSION_MINOR,
652     "flxdec",
653     "FLX video decoder",
654     plugin_init, VERSION, GST_LICENSE, GST_PACKAGE, GST_ORIGIN)