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