Way, way, way too many files: Remove crack comment from the 2000 era.
[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   gst_pad_use_explicit_caps (flxdec->srcpad);
163
164   flxdec->bs = NULL;
165   flxdec->frame = NULL;
166   flxdec->delta = NULL;
167 }
168
169 static void
170 flx_decode_chunks (GstFlxDec * flxdec, gulong count, gchar * data, gchar * dest)
171 {
172   FlxFrameChunk *hdr;
173
174   g_return_if_fail (data != NULL);
175
176   while (count--) {
177     hdr = (FlxFrameChunk *) data;
178     data += FlxFrameChunkSize;
179
180     switch (hdr->id) {
181       case FLX_COLOR64:
182         flx_decode_color (flxdec, data, dest, 2);
183         data += rndalign (hdr->size) - FlxFrameChunkSize;
184         break;
185
186       case FLX_COLOR256:
187         flx_decode_color (flxdec, data, dest, 0);
188         data += rndalign (hdr->size) - FlxFrameChunkSize;
189         break;
190
191       case FLX_BRUN:
192         flx_decode_brun (flxdec, data, dest);
193         data += rndalign (hdr->size) - FlxFrameChunkSize;
194         break;
195
196       case FLX_LC:
197         flx_decode_delta_fli (flxdec, data, dest);
198         data += rndalign (hdr->size) - FlxFrameChunkSize;
199         break;
200
201       case FLX_SS2:
202         flx_decode_delta_flc (flxdec, data, dest);
203         data += rndalign (hdr->size) - FlxFrameChunkSize;
204         break;
205
206       case FLX_BLACK:
207         memset (dest, 0, flxdec->size);
208         break;
209
210       case FLX_MINI:
211         data += rndalign (hdr->size) - FlxFrameChunkSize;
212         break;
213
214       default:
215         GST_WARNING ("Unimplented chunk type: 0x%02x size: %d - skipping",
216             hdr->id, hdr->size);
217         data += rndalign (hdr->size) - FlxFrameChunkSize;
218         break;
219     }
220   }
221 }
222
223
224 static void
225 flx_decode_color (GstFlxDec * flxdec, guchar * data, guchar * dest, gint scale)
226 {
227   guint packs, count, indx;
228
229   g_return_if_fail (flxdec != NULL);
230
231   packs = (data[0] + (data[1] << 8));
232
233   data += 2;
234   indx = 0;
235
236   GST_LOG ("GstFlxDec: cmap packs: %d", packs);
237   while (packs--) {
238     /* color map index + skip count */
239     indx += *data++;
240
241     /* number of rgb triplets */
242     count = *data++ & 0xff;
243     if (count == 0)
244       count = 256;
245
246     GST_LOG ("GstFlxDec: cmap count: %d (indx: %d)\n", count, indx);
247     flx_set_palette_vector (flxdec->converter, indx, count, data, scale);
248
249     data += (count * 3);
250   }
251 }
252
253 static void
254 flx_decode_brun (GstFlxDec * flxdec, guchar * data, guchar * dest)
255 {
256   gulong count, lines, row;
257   guchar x;
258
259   g_return_if_fail (flxdec != NULL);
260
261   lines = flxdec->hdr.height;
262   while (lines--) {
263     /* packet count.  
264      * should not be used anymore, since the flc format can
265      * contain more then 255 RLE packets. we use the frame 
266      * width instead. 
267      */
268     data++;
269
270     row = flxdec->hdr.width;
271     while (row) {
272       count = *data++;
273
274       if (count > 0x7f) {
275         /* literal run */
276         count = 0x100 - count;
277         row -= count;
278
279         while (count--)
280           *dest++ = *data++;
281
282       } else {
283         /* replicate run */
284         row -= count;
285         x = *data++;
286
287         while (count--)
288           *dest++ = x;
289       }
290     }
291   }
292 }
293
294 static void
295 flx_decode_delta_fli (GstFlxDec * flxdec, guchar * data, guchar * dest)
296 {
297   gulong count, packets, lines, start_line, start_l;
298   guchar *start_p, x;
299
300   g_return_if_fail (flxdec != NULL);
301   g_return_if_fail (flxdec->delta != NULL);
302
303
304   /* use last frame for delta */
305   memcpy (dest, GST_BUFFER_DATA (flxdec->delta),
306       GST_BUFFER_SIZE (flxdec->delta));
307
308   start_line = (data[0] + (data[1] << 8));
309   lines = (data[2] + (data[3] << 8));
310   data += 4;
311
312   /* start position of delta */
313   dest += (flxdec->hdr.width * start_line);
314   start_p = dest;
315   start_l = lines;
316
317   while (lines--) {
318     /* packet count */
319     packets = *data++;
320
321     while (packets--) {
322       /* skip count */
323       dest += *data++;
324
325       /* RLE count */
326       count = *data++;
327
328       if (count > 0x7f) {
329         /* literal run */
330         count = 0x100 - count;
331         x = *data++;
332
333         while (count--)
334           *dest++ = x;
335
336       } else {
337         /* replicate run */
338         while (count--)
339           *dest++ = *data++;
340       }
341     }
342     start_p += flxdec->hdr.width;
343     dest = start_p;
344   }
345 }
346
347 static void
348 flx_decode_delta_flc (GstFlxDec * flxdec, guchar * data, guchar * dest)
349 {
350   gulong count, lines, start_l, opcode;
351   guchar *start_p;
352
353   g_return_if_fail (flxdec != NULL);
354   g_return_if_fail (flxdec->delta != NULL);
355
356
357   /* use last frame for delta */
358   memcpy (dest, GST_BUFFER_DATA (flxdec->delta),
359       GST_BUFFER_SIZE (flxdec->delta));
360
361   lines = (data[0] + (data[1] << 8));
362   data += 2;
363
364   start_p = dest;
365   start_l = lines;
366
367   while (lines) {
368     dest = start_p + (flxdec->hdr.width * (start_l - lines));
369
370     /* process opcode(s) */
371     while ((opcode = (data[0] + (data[1] << 8))) & 0xc000) {
372       data += 2;
373       if ((opcode & 0xc000) == 0xc000) {
374         /* skip count */
375         start_l += (0x10000 - opcode);
376         dest += flxdec->hdr.width * (0x10000 - opcode);
377       } else {
378         /* last pixel */
379         dest += flxdec->hdr.width;
380         *dest++ = (opcode & 0xff);
381       }
382     }
383     data += 2;
384
385     /* last opcode is the packet count */
386     while (opcode--) {
387       /* skip count */
388       dest += *data++;
389
390       /* RLE count */
391       count = *data++;
392
393       if (count > 0x7f) {
394         /* replicate word run */
395         count = 0x100 - count;
396         while (count--) {
397           *dest++ = data[0];
398           *dest++ = data[1];
399         }
400         data += 2;
401       } else {
402         /* literal word run */
403         while (count--) {
404           *dest++ = *data++;
405           *dest++ = *data++;
406         }
407       }
408     }
409     lines--;
410   }
411 }
412
413 static GstBuffer *
414 flx_get_data (GstFlxDec * flxdec, gulong size)
415 {
416   GstBuffer *retbuf;
417   guint32 got_bytes;
418
419   g_return_val_if_fail (flxdec != NULL, NULL);
420
421   got_bytes = gst_bytestream_read (flxdec->bs, &retbuf, size);
422   if (got_bytes < size) {
423     GstEvent *event;
424     guint32 remaining;
425
426     gst_bytestream_get_status (flxdec->bs, &remaining, &event);
427     gst_pad_event_default (flxdec->sinkpad, event);
428   }
429
430   return retbuf;
431 }
432
433
434 static void
435 gst_flxdec_loop (GstElement * element)
436 {
437   GstBuffer *buf;
438   GstBuffer *databuf;
439   guchar *data, *chunk;
440   GstCaps *caps;
441
442   GstFlxDec *flxdec;
443   FlxHeader *flxh;
444   FlxFrameChunk *flxfh;
445
446   g_return_if_fail (element != NULL);
447   g_return_if_fail (GST_IS_FLXDEC (element));
448
449   GST_DEBUG ("entering loop function");
450
451   flxdec = GST_FLXDEC (element);
452
453   if (flxdec->state == GST_FLXDEC_READ_HEADER) {
454     databuf = flx_get_data (flxdec, FlxHeaderSize);
455
456     if (!databuf) {
457       GST_LOG ("empty buffer");
458       return;
459     }
460
461     data = GST_BUFFER_DATA (databuf);
462
463     memcpy ((char *) &flxdec->hdr, data, sizeof (FlxHeader));
464
465     gst_buffer_unref (databuf);
466
467     flxh = &flxdec->hdr;
468
469     /* check header */
470     if (flxh->type != FLX_MAGICHDR_FLI &&
471         flxh->type != FLX_MAGICHDR_FLC && flxh->type != FLX_MAGICHDR_FLX) {
472       GST_ELEMENT_ERROR (element, STREAM, WRONG_TYPE, (NULL),
473           ("not a flx file (type %d)\n", flxh->type));
474       return;
475     }
476
477
478     GST_LOG ("size      :  %d\n", flxh->size);
479     GST_LOG ("frames    :  %d\n", flxh->frames);
480     GST_LOG ("width     :  %d\n", flxh->width);
481     GST_LOG ("height    :  %d\n", flxh->height);
482     GST_LOG ("depth     :  %d\n", flxh->depth);
483     GST_LOG ("speed     :  %d\n", flxh->speed);
484
485     flxdec->next_time = 0;
486
487     if (flxh->type == FLX_MAGICHDR_FLI) {
488       flxdec->frame_time = JIFFIE * flxh->speed;
489     } else {
490       flxdec->frame_time = flxh->speed * GST_MSECOND;
491     }
492
493     caps = gst_caps_from_string (GST_VIDEO_CAPS_xRGB_HOST_ENDIAN);
494     gst_caps_set_simple (caps,
495         "width", G_TYPE_INT, flxh->width,
496         "height", G_TYPE_INT, flxh->height,
497         "framerate", G_TYPE_DOUBLE, (gdouble) (GST_SECOND / flxdec->frame_time),
498         NULL);
499
500     gst_pad_set_explicit_caps (flxdec->srcpad, caps);
501
502     if (flxh->depth <= 8)
503       flxdec->converter =
504           flx_colorspace_converter_new (flxh->width, flxh->height);
505
506     if (flxh->type == FLX_MAGICHDR_FLC || flxh->type == FLX_MAGICHDR_FLX) {
507       GST_LOG ("(FLC) aspect_dx :  %d\n", flxh->aspect_dx);
508       GST_LOG ("(FLC) aspect_dy :  %d\n", flxh->aspect_dy);
509       GST_LOG ("(FLC) oframe1   :  0x%08x\n", flxh->oframe1);
510       GST_LOG ("(FLC) oframe2   :  0x%08x\n", flxh->oframe2);
511     }
512
513     flxdec->size = (flxh->width * flxh->height);
514
515     /* create delta and output frame */
516     flxdec->frame = gst_buffer_new ();
517     flxdec->delta = gst_buffer_new ();
518     GST_BUFFER_DATA (flxdec->frame) = g_malloc (flxdec->size);
519     GST_BUFFER_SIZE (flxdec->frame) = flxdec->size;
520     GST_BUFFER_DATA (flxdec->delta) = g_malloc (flxdec->size);
521     GST_BUFFER_SIZE (flxdec->delta) = flxdec->size;
522
523     flxdec->state = GST_FLXDEC_PLAYING;
524   } else if (flxdec->state == GST_FLXDEC_PLAYING) {
525     GstBuffer *out;
526
527     databuf = flx_get_data (flxdec, FlxFrameChunkSize);
528     if (!databuf)
529       return;
530
531     flxfh = (FlxFrameChunk *) GST_BUFFER_DATA (databuf);
532
533     switch (flxfh->id) {
534       case FLX_FRAME_TYPE:
535         buf = flx_get_data (flxdec, flxfh->size - FlxFrameChunkSize);
536
537         chunk = GST_BUFFER_DATA (buf);
538
539         if (((FlxFrameType *) chunk)->chunks == 0)
540           break;
541
542         /* create 32 bits output frame */
543         out = gst_buffer_new ();
544         GST_BUFFER_DATA (out) = g_malloc (flxdec->size * 4);
545         GST_BUFFER_SIZE (out) = flxdec->size * 4;
546
547         /* decode chunks */
548         flx_decode_chunks (flxdec,
549             ((FlxFrameType *) chunk)->chunks,
550             GST_BUFFER_DATA (buf) + FlxFrameTypeSize,
551             GST_BUFFER_DATA (flxdec->frame));
552
553         /* destroy input buffer */
554         gst_buffer_unref (buf);
555
556         /* save copy of the current frame for possible delta. */
557         memcpy (GST_BUFFER_DATA (flxdec->delta),
558             GST_BUFFER_DATA (flxdec->frame), GST_BUFFER_SIZE (flxdec->delta));
559
560         /* convert current frame. */
561         flx_colorspace_convert (flxdec->converter,
562             GST_BUFFER_DATA (flxdec->frame), GST_BUFFER_DATA (out));
563
564         GST_BUFFER_TIMESTAMP (out) = flxdec->next_time;
565         flxdec->next_time += flxdec->frame_time;
566
567         gst_pad_push (flxdec->srcpad, GST_DATA (out));
568
569         break;
570     }
571
572     /* destroy header buffer */
573     gst_buffer_unref (databuf);
574   }
575 }
576
577 static GstElementStateReturn
578 gst_flxdec_change_state (GstElement * element)
579 {
580   GstFlxDec *flxdec;
581
582   flxdec = GST_FLXDEC (element);
583
584   switch (GST_STATE_TRANSITION (element)) {
585     case GST_STATE_NULL_TO_READY:
586       break;
587     case GST_STATE_READY_TO_PAUSED:
588       flxdec->bs = gst_bytestream_new (flxdec->sinkpad);
589       flxdec->state = GST_FLXDEC_READ_HEADER;
590       break;
591     case GST_STATE_PAUSED_TO_PLAYING:
592       break;
593     case GST_STATE_PLAYING_TO_PAUSED:
594       break;
595     case GST_STATE_PAUSED_TO_READY:
596       gst_buffer_unref (flxdec->frame);
597       flxdec->frame = NULL;
598       gst_buffer_unref (flxdec->delta);
599       flxdec->delta = NULL;
600       gst_bytestream_destroy (flxdec->bs);
601       break;
602     case GST_STATE_READY_TO_NULL:
603       break;
604   }
605
606   parent_class->change_state (element);
607
608   return GST_STATE_SUCCESS;
609 }
610
611 static void
612 gst_flxdec_set_property (GObject * object, guint prop_id, const GValue * value,
613     GParamSpec * pspec)
614 {
615   GstFlxDec *flxdec;
616
617   g_return_if_fail (GST_IS_FLXDEC (object));
618   flxdec = GST_FLXDEC (object);
619
620   switch (prop_id) {
621     default:
622       break;
623   }
624 }
625
626 static void
627 gst_flxdec_get_property (GObject * object, guint prop_id, GValue * value,
628     GParamSpec * pspec)
629 {
630   GstFlxDec *flxdec;
631
632   g_return_if_fail (GST_IS_FLXDEC (object));
633   flxdec = GST_FLXDEC (object);
634
635   switch (prop_id) {
636     default:
637       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
638       break;
639   }
640 }
641
642 static gboolean
643 plugin_init (GstPlugin * plugin)
644 {
645   if (!gst_library_load ("gstbytestream"))
646     return FALSE;
647
648   return gst_element_register (plugin, "flxdec",
649       GST_RANK_PRIMARY, GST_TYPE_FLXDEC);
650 }
651
652 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
653     GST_VERSION_MINOR,
654     "flxdec",
655     "FLX video decoder",
656     plugin_init, VERSION, GST_LICENSE, GST_PACKAGE, GST_ORIGIN)