compatibility fix for new GST_DEBUG stuff.
[platform/upstream/gstreamer.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
28 #define JIFFIE  (GST_SECOND/70)
29
30 static GstCaps* flxdec_type_find(GstBuffer *buf, gpointer private);
31
32 /* flx element information */
33 static GstElementDetails flxdec_details = {
34   "FLX Decoder",
35   "Codec/Audio/Decoder",
36   "LGPL",
37   "FLX decoder",
38   VERSION,
39   "Sepp Wijnands <mrrazz@garbage-coderz.net>"
40   "(C) 2001",
41 };
42
43 static GstTypeDefinition flxdec_definition = {
44   "flxdec_video/fli",
45   "video/fli",
46   ".flc .fli",
47   flxdec_type_find,
48 };
49
50 /* Flx signals and args */
51 enum {
52   /* FILL ME */
53   LAST_SIGNAL
54 };
55
56 enum {
57   ARG_0
58 };
59
60 /* input */
61 GST_PAD_TEMPLATE_FACTORY (sink_factory,
62   "sink",          
63   GST_PAD_SINK, 
64   GST_PAD_ALWAYS,
65   GST_CAPS_NEW (
66     "flxdec_sink",         
67     "video/fli",
68      NULL
69   )
70 )
71
72 /* output */
73 GST_PAD_TEMPLATE_FACTORY (src_video_factory,
74   "src",
75   GST_PAD_SRC,
76   GST_PAD_ALWAYS,
77   GST_CAPS_NEW (
78     "src_video",
79     "video/raw",
80       "format",       GST_PROPS_FOURCC (GST_MAKE_FOURCC ('R', 'G', 'B', ' ')),
81         "bpp",        GST_PROPS_INT (32),
82         "depth",      GST_PROPS_INT (32),
83         "endianness", GST_PROPS_INT (G_LITTLE_ENDIAN),
84         "red_mask",   GST_PROPS_INT (0x00ff0000),
85         "green_mask", GST_PROPS_INT (0x0000ff00),
86         "blue_mask",  GST_PROPS_INT (0x000000ff),
87         "width",      GST_PROPS_INT_RANGE(320, 1280), 
88         "height",     GST_PROPS_INT_RANGE(200, 1024)
89   )
90 )
91
92
93 static void     gst_flxdec_class_init   (GstFlxDecClass *klass);
94 static void     gst_flxdec_init         (GstFlxDec *flxdec);
95
96 static void     gst_flxdec_loop         (GstElement *element);
97
98 static GstElementStateReturn 
99                 gst_flxdec_change_state (GstElement *element);
100
101 static void     gst_flxdec_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
102 static void     gst_flxdec_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
103
104
105 static void     flx_decode_color        (GstFlxDec *, guchar *, guchar *, gint);
106 static void     flx_decode_brun         (GstFlxDec *, guchar *, guchar *);
107 static void     flx_decode_delta_fli    (GstFlxDec *, guchar *, guchar *);
108 static void     flx_decode_delta_flc    (GstFlxDec *, guchar *, guchar *);
109
110 #define rndalign(off) ((off) + ((off) % 2))
111
112 static GstElementClass *parent_class = NULL;
113
114 static GstCaps* 
115 flxdec_type_find (GstBuffer *buf, gpointer private)
116 {
117   guchar *data = GST_BUFFER_DATA(buf);
118   GstCaps *new;
119
120   if(GST_BUFFER_SIZE(buf) < 134){
121     return NULL;
122   }
123
124   /* check magic */
125   if ((data[4] == 0x11 || data[4] == 0x12
126        || data[4] == 0x30 || data[4] == 0x44) && data[5] == 0xaf) {
127       /* check the frame type of the first frame */
128       if ((data[132] == 0x00 || data[132] == 0xfa) && data[133] == 0xf1) {
129         g_print("GstFlxDec: found supported flx format\n");
130         new = gst_caps_new("flxdec_type_find","video/fli", NULL);
131         return new;
132       }
133   }
134   
135   return NULL; 
136 }
137
138
139 GType
140 gst_flxdec_get_type(void) 
141 {
142   static GType flxdec_type = 0;
143
144   if (!flxdec_type) {
145     static const GTypeInfo flxdec_info = {
146       sizeof(GstFlxDecClass),      NULL,
147       NULL,
148       (GClassInitFunc)gst_flxdec_class_init,
149       NULL,
150       NULL,
151       sizeof(GstFlxDec),
152       0,
153       (GInstanceInitFunc)gst_flxdec_init,
154     };
155     flxdec_type = g_type_register_static(GST_TYPE_ELEMENT, "GstFlxDec", &flxdec_info, 0);
156   }
157   return flxdec_type;
158 }
159
160 static void 
161 gst_flxdec_class_init (GstFlxDecClass *klass) 
162 {
163   GObjectClass *gobject_class;
164   GstElementClass *gstelement_class;
165
166   gobject_class = (GObjectClass*)klass;
167   gstelement_class = (GstElementClass*)klass;
168
169   parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
170
171   gobject_class->set_property = gst_flxdec_set_property;  
172   gobject_class->get_property = gst_flxdec_get_property;
173
174   gstelement_class->change_state = gst_flxdec_change_state;
175 }
176
177
178   
179 static void 
180 gst_flxdec_init(GstFlxDec *flxdec) 
181 {
182   flxdec->sinkpad = gst_pad_new_from_template (
183                   GST_PAD_TEMPLATE_GET (sink_factory), "sink");
184   gst_element_add_pad(GST_ELEMENT(flxdec),flxdec->sinkpad);
185   gst_element_set_loop_function(GST_ELEMENT(flxdec),gst_flxdec_loop);
186
187   flxdec->srcpad = gst_pad_new_from_template (
188                   GST_PAD_TEMPLATE_GET (src_video_factory), "src");
189   gst_element_add_pad(GST_ELEMENT(flxdec),flxdec->srcpad);
190
191   flxdec->bs = NULL;
192   flxdec->frame = NULL;
193   flxdec->delta = NULL;
194 }
195
196 static void
197 flx_decode_chunks (GstFlxDec *flxdec , gulong count, gchar *data, gchar *dest)
198 {
199   FlxFrameChunk  *hdr;
200
201   g_return_if_fail(data != NULL);
202
203   while (count--) {
204     hdr  = (FlxFrameChunk *) data;
205     data += FlxFrameChunkSize;
206
207     switch(hdr->id) 
208     {
209       case FLX_COLOR64:
210         flx_decode_color(flxdec, data, dest, 2);
211         data += rndalign(hdr->size) - FlxFrameChunkSize;
212         break;
213
214       case FLX_COLOR256:
215         flx_decode_color(flxdec, data, dest, 0);
216         data += rndalign(hdr->size) - FlxFrameChunkSize;
217         break;
218
219       case FLX_BRUN:
220         flx_decode_brun(flxdec, data, dest);
221         data += rndalign(hdr->size) - FlxFrameChunkSize;
222         break;
223
224       case FLX_LC:
225         flx_decode_delta_fli(flxdec, data, dest);
226         data += rndalign(hdr->size) - FlxFrameChunkSize;
227         break;
228
229       case FLX_SS2:
230         flx_decode_delta_flc(flxdec, data, dest);
231         data += rndalign(hdr->size) - FlxFrameChunkSize;
232         break;
233
234       case FLX_BLACK:
235         memset(dest, 0, flxdec->size);
236         break;
237
238       case FLX_MINI:
239         data += rndalign(hdr->size) - FlxFrameChunkSize;
240         break;
241
242       default:
243         g_print("GstFlxDec: Unimplented chunk type: 0x%02x size: %d\n",
244                  hdr->id, hdr->size);
245         g_print("GstFlxDec: Skipping...\n");
246         data += rndalign(hdr->size) - FlxFrameChunkSize;
247         break;
248     }
249   }
250 }
251
252
253 static void
254 flx_decode_color(GstFlxDec *flxdec, guchar *data, guchar *dest, gint scale)
255 {
256   guint packs, count, indx;
257
258   g_return_if_fail(flxdec != NULL);
259
260   packs = (data[0] + (data[1] << 8));
261
262   data += 2;
263   indx  = 0;
264
265   g_print("GstFlxDec: cmap packs: %d\n", packs);
266   while (packs--) {
267     /* color map index + skip count */
268     indx += *data++;
269
270     /* number of rgb triplets */
271     count = *data++ & 0xff;
272     if (count == 0)
273       count = 256;
274
275     g_print("GstFlxDec: cmap count: %d (indx: %d)\n", count, indx);
276     flx_set_palette_vector(flxdec->converter, indx, count, data, scale);
277
278     data += (count * 3);
279   }
280 }
281
282 static void 
283 flx_decode_brun(GstFlxDec *flxdec, guchar *data, guchar *dest)
284 {
285   gulong  count, lines, row;
286   guchar  x;
287   
288   g_return_if_fail(flxdec != NULL);
289
290   lines = flxdec->hdr.height;
291   while(lines--) {
292     /* packet count.  
293      * should not be used anymore, since the flc format can
294      * contain more then 255 RLE packets. we use the frame 
295      * width instead. 
296      */
297     data++;
298
299     row = flxdec->hdr.width;
300     while(row) {
301       count = *data++;
302
303       if (count > 0x7f) { 
304         /* literal run */
305         count = 0x100 - count;
306         row -= count;
307
308         while(count--) 
309           *dest++ = *data++;
310         
311       } else {
312         /* replicate run */
313         row -= count;
314         x = *data++;
315
316         while(count--) 
317           *dest++ = x;
318       }
319     }
320   }
321 }
322
323 static void 
324 flx_decode_delta_fli(GstFlxDec *flxdec, guchar *data, guchar *dest)
325 {
326   gulong  count, packets, lines, start_line, start_l;
327   guchar  *start_p,  x;
328   
329   g_return_if_fail(flxdec != NULL);
330   g_return_if_fail(flxdec->delta != NULL);
331
332
333   /* use last frame for delta */
334   memcpy(dest, GST_BUFFER_DATA(flxdec->delta), 
335          GST_BUFFER_SIZE(flxdec->delta));
336
337   start_line = (data[0] + (data[1] << 8));
338   lines      = (data[2] + (data[3] << 8));
339   data    += 4;
340
341   /* start position of delta */
342   dest += (flxdec->hdr.width * start_line);
343   start_p = dest;
344   start_l = lines;
345
346   while(lines--) {
347     /* packet count */
348     packets = *data++;
349
350     while(packets--) {
351       /* skip count */
352       dest += *data++;
353
354       /* RLE count */
355       count = *data++;
356
357       if (count > 0x7f) { 
358         /* literal run */
359         count = 0x100 - count;
360         x = *data++;
361
362         while (count--)
363           *dest++ = x;
364
365       } else {
366         /* replicate run */
367         while (count--) 
368           *dest++ = *data++;
369       }
370     }
371     start_p += flxdec->hdr.width;
372     dest = start_p;
373   }                  
374 }
375
376 static void 
377 flx_decode_delta_flc(GstFlxDec *flxdec, guchar *data, guchar *dest)
378 {
379   gulong  count, lines, start_l, opcode;
380   guchar  *start_p;
381   
382   g_return_if_fail(flxdec != NULL);
383   g_return_if_fail(flxdec->delta != NULL);
384
385
386   /* use last frame for delta */
387   memcpy(dest, GST_BUFFER_DATA(flxdec->delta), 
388          GST_BUFFER_SIZE(flxdec->delta));
389
390   lines      = (data[0] + (data[1] << 8));
391   data    += 2;
392
393   start_p    = dest;
394   start_l    = lines;
395
396   while (lines) {
397     dest = start_p + (flxdec->hdr.width * (start_l - lines));
398
399     /* process opcode(s) */
400     while ((opcode = (data[0] + (data[1] << 8))) & 0xc000) {
401       data += 2;
402       if ((opcode & 0xc000) == 0xc000) {
403         /* skip count */
404         start_l += (0x10000 - opcode);  
405         dest    += flxdec->hdr.width * (0x10000 - opcode);
406       } else {
407         /* last pixel */
408         dest    += flxdec->hdr.width;
409         *dest++  = (opcode & 0xff);
410       }        
411     }
412     data += 2;
413
414     /* last opcode is the packet count */
415     while(opcode--) {
416       /* skip count */
417       dest += *data++;
418   
419       /* RLE count */
420       count = *data++;
421       
422       if (count > 0x7f) {
423         /* replicate word run */
424         count = 0x100 - count;
425         while (count--) {
426           *dest++ = data[0];
427           *dest++ = data[1];
428         }
429         data += 2;
430       } else {
431         /* literal word run */
432         while (count--) {
433           *dest++ = *data++;
434           *dest++ = *data++;
435         }
436       }
437     }
438     lines--;
439   }
440 }
441           
442 static GstBuffer*
443 flx_get_data(GstFlxDec *flxdec, gulong size)
444 {
445   GstBuffer *retbuf;
446   guint32 got_bytes;
447
448   g_return_val_if_fail (flxdec != NULL, NULL);
449
450   got_bytes = gst_bytestream_read (flxdec->bs, &retbuf, size);
451   if (got_bytes < size) {
452     GstEvent *event;
453     guint32 remaining;
454
455     gst_bytestream_get_status (flxdec->bs, &remaining, &event);
456     gst_pad_event_default (flxdec->sinkpad, event);
457   }
458
459   return retbuf;
460 }
461
462
463 static void 
464 gst_flxdec_loop (GstElement *element) 
465 {
466   GstBuffer  *buf;  
467   GstBuffer  *databuf;
468   guchar     *data, *chunk;
469
470   GstFlxDec         *flxdec;  
471   FlxHeader      *flxh;
472   FlxFrameChunk  *flxfh;
473   
474   g_return_if_fail (element != NULL);
475   g_return_if_fail (GST_IS_FLXDEC(element));
476
477   GST_DEBUG ("entering loop function");
478   
479   flxdec = GST_FLXDEC(element);
480
481   if (flxdec->state == GST_FLXDEC_READ_HEADER) {
482     databuf = flx_get_data(flxdec, FlxHeaderSize);
483
484     if (!databuf) {
485       g_print ("empty buffer\n");
486       return;
487     }
488
489     data = GST_BUFFER_DATA(databuf);
490
491     memcpy((char *) &flxdec->hdr, data, sizeof(FlxHeader));
492
493     gst_buffer_unref (databuf);
494
495     flxh = &flxdec->hdr;
496
497     /* check header */
498     if (flxh->type != FLX_MAGICHDR_FLI &&
499       flxh->type != FLX_MAGICHDR_FLC &&
500       flxh->type != FLX_MAGICHDR_FLX) {
501       gst_element_error (element, "not a flx file (type %d)\n", flxh->type);
502       return;
503     }
504   
505   
506     g_print("GstFlxDec:       size      :  %d\n", flxh->size);
507     g_print("GstFlxDec:       frames    :  %d\n", flxh->frames);
508     g_print("GstFlxDec:       width     :  %d\n", flxh->width);
509     g_print("GstFlxDec:       height    :  %d\n", flxh->height);
510     g_print("GstFlxDec:       depth     :  %d\n", flxh->depth);
511     g_print("GstFlxDec:       speed     :  %d\n", flxh->speed);
512
513     flxdec->next_time = 0;
514
515     if (flxh->type == FLX_MAGICHDR_FLI) {
516       flxdec->frame_time = JIFFIE * flxh->speed;
517     }
518     else {
519       flxdec->frame_time = flxh->speed * GST_MSECOND;
520     }
521     
522     gst_pad_try_set_caps (flxdec->srcpad,
523                 gst_caps_new (
524                   "src_video",
525                   "video/raw",
526                   gst_props_new (
527                     "format",       GST_PROPS_FOURCC (GST_MAKE_FOURCC ('R', 'G', 'B', ' ')),
528                       "bpp",        GST_PROPS_INT (32),
529                       "depth",      GST_PROPS_INT (32),
530                       "endianness", GST_PROPS_INT (G_LITTLE_ENDIAN),
531                       "red_mask",   GST_PROPS_INT (0x00ff0000),
532                       "green_mask", GST_PROPS_INT (0x0000ff00),
533                       "blue_mask",  GST_PROPS_INT (0x000000ff),
534                       "width",      GST_PROPS_INT (flxh->width), 
535                       "height",     GST_PROPS_INT (flxh->height),
536                     NULL)));
537
538     if (flxh->depth <= 8) 
539       flxdec->converter = flx_colorspace_converter_new(flxh->width, flxh->height);
540
541     if (flxh->type == FLX_MAGICHDR_FLC || 
542         flxh->type == FLX_MAGICHDR_FLX) {
543       g_print("GstFlxDec: (FLC) aspect_dx :  %d\n", flxh->aspect_dx);
544       g_print("GstFlxDec: (FLC) aspect_dy :  %d\n", flxh->aspect_dy);
545       g_print("GstFlxDec: (FLC) oframe1   :  0x%08x\n", flxh->oframe1);
546       g_print("GstFlxDec: (FLC) oframe2   :  0x%08x\n", flxh->oframe2);
547     }
548
549   
550     flxdec->size = (flxh->width * flxh->height);
551   
552     /* create delta and output frame */
553     flxdec->frame = gst_buffer_new();
554     flxdec->delta = gst_buffer_new();
555     GST_BUFFER_DATA(flxdec->frame) = g_malloc(flxdec->size);
556     GST_BUFFER_SIZE(flxdec->frame) = flxdec->size;
557     GST_BUFFER_DATA(flxdec->delta) = g_malloc(flxdec->size);
558     GST_BUFFER_SIZE(flxdec->delta) = flxdec->size;
559
560     flxdec->state = GST_FLXDEC_PLAYING;
561   }
562   else if (flxdec->state == GST_FLXDEC_PLAYING) {
563     GstBuffer *out;
564
565     databuf = flx_get_data(flxdec, FlxFrameChunkSize);
566     if (!databuf)
567       return;
568
569     flxfh = (FlxFrameChunk *) GST_BUFFER_DATA(databuf);
570     
571     switch(flxfh->id) {
572       case FLX_FRAME_TYPE:
573         buf = flx_get_data(flxdec, flxfh->size-FlxFrameChunkSize);
574  
575         chunk = GST_BUFFER_DATA(buf);
576  
577         if (((FlxFrameType *)chunk)->chunks == 0)
578           break;
579
580         /* create 32 bits output frame */
581         out = gst_buffer_new();
582         GST_BUFFER_DATA(out) = g_malloc(flxdec->size * 4);
583         GST_BUFFER_SIZE(out) = flxdec->size * 4;
584
585         /* decode chunks */
586         flx_decode_chunks(flxdec, 
587                          ((FlxFrameType *)chunk)->chunks, 
588                          GST_BUFFER_DATA(buf) + FlxFrameTypeSize,
589                          GST_BUFFER_DATA(flxdec->frame));
590  
591         /* destroy input buffer*/
592         gst_buffer_unref(buf);
593     
594         /* save copy of the current frame for possible delta. */
595         memcpy(GST_BUFFER_DATA(flxdec->delta), 
596                GST_BUFFER_DATA(flxdec->frame), 
597                GST_BUFFER_SIZE(flxdec->delta));
598
599         /* convert current frame. */
600         flx_colorspace_convert(flxdec->converter,
601              GST_BUFFER_DATA(flxdec->frame),
602              GST_BUFFER_DATA(out));
603
604         GST_BUFFER_TIMESTAMP (out) = flxdec->next_time;
605         flxdec->next_time += flxdec->frame_time;
606
607         gst_pad_push(flxdec->srcpad, out);
608         
609         break;
610     }
611
612     /* destroy header buffer */
613     gst_buffer_unref(databuf);
614   }
615 }
616
617 static GstElementStateReturn 
618 gst_flxdec_change_state (GstElement *element)
619 {
620   GstFlxDec *flxdec;
621
622   flxdec = GST_FLXDEC(element);
623
624   switch (GST_STATE_TRANSITION (element)) {
625     case GST_STATE_NULL_TO_READY:
626       break;
627     case GST_STATE_READY_TO_PAUSED:
628       flxdec->bs = gst_bytestream_new (flxdec->sinkpad);
629       flxdec->state = GST_FLXDEC_READ_HEADER;
630       break;
631     case GST_STATE_PAUSED_TO_PLAYING:
632       break;
633     case GST_STATE_PLAYING_TO_PAUSED:
634       break;
635     case GST_STATE_PAUSED_TO_READY:
636       gst_buffer_unref (flxdec->frame);
637       flxdec->frame = NULL;
638       gst_buffer_unref (flxdec->delta);
639       flxdec->delta = NULL;
640       gst_bytestream_destroy (flxdec->bs);
641       break;
642     case GST_STATE_READY_TO_NULL:
643       break;
644   }
645   
646   parent_class->change_state (element);
647
648   return GST_STATE_SUCCESS;
649 }
650
651 static void 
652 gst_flxdec_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) 
653 {
654   GstFlxDec *flxdec;
655
656   /* it's not null if we got it, but it might not be ours */
657   g_return_if_fail(GST_IS_FLXDEC(object));
658   flxdec = GST_FLXDEC(object);
659
660   switch (prop_id) {
661     default:
662       break;
663   }
664 }
665
666 static void 
667 gst_flxdec_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) 
668 {
669   GstFlxDec *flxdec;
670
671   /* it's not null if we got it, but it might not be ours */
672   g_return_if_fail(GST_IS_FLXDEC(object));
673   flxdec = GST_FLXDEC(object);
674
675   switch (prop_id) {
676     default:
677       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
678       break;
679   }
680 }
681
682 static gboolean
683 plugin_init (GModule *module, GstPlugin *plugin)
684 {
685   GstElementFactory *factory;
686   GstTypeFactory *type;
687
688   /* this filter needs the bytestream package */
689   if (!gst_library_load ("gstbytestream"))
690     return FALSE;
691
692   factory = gst_element_factory_new("flxdec", GST_TYPE_FLXDEC, &flxdec_details);
693   g_return_val_if_fail(factory != NULL, FALSE);
694   gst_element_factory_set_rank (factory, GST_ELEMENT_RANK_PRIMARY);
695
696   gst_element_factory_add_pad_template (factory, GST_PAD_TEMPLATE_GET (sink_factory));
697   gst_element_factory_add_pad_template (factory, GST_PAD_TEMPLATE_GET (src_video_factory));
698
699   gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
700
701   type = gst_type_factory_new (&flxdec_definition);
702   gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (type));
703
704   return TRUE;
705 }
706
707 GstPluginDesc plugin_desc = {
708   GST_VERSION_MAJOR,
709   GST_VERSION_MINOR,
710   "flxdec",
711   plugin_init
712 };