better/unified long descriptions
[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 GST_ELEMENT_DETAILS ("FLX audio decoder",
37     "Codec/Decoder/Audio",
38     "FLX decoder",
39     "Sepp Wijnands <mrrazz@garbage-coderz.net>, Zeeshan Ali <zeenix@gmail.com>");
40
41 /* Flx signals and args */
42 enum
43 {
44   /* FILL ME */
45   LAST_SIGNAL
46 };
47
48 enum
49 {
50   ARG_0
51 };
52
53 /* input */
54 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
55     GST_PAD_SINK,
56     GST_PAD_ALWAYS,
57     GST_STATIC_CAPS ("video/x-fli")
58     );
59
60 /* output */
61 static GstStaticPadTemplate src_video_factory = GST_STATIC_PAD_TEMPLATE ("src",
62     GST_PAD_SRC,
63     GST_PAD_ALWAYS,
64     GST_STATIC_CAPS (GST_VIDEO_CAPS_xRGB_HOST_ENDIAN)
65     );
66
67
68 static void gst_flxdec_class_init (GstFlxDecClass * klass);
69 static void gst_flxdec_base_init (GstFlxDecClass * klass);
70 static void gst_flxdec_init (GstFlxDec * flxdec);
71
72 static GstFlowReturn gst_flxdec_chain (GstPad * pad, GstBuffer * buf);
73
74 static GstStateChangeReturn gst_flxdec_change_state (GstElement * element,
75     GstStateChange transition);
76
77 static gboolean gst_flxdec_src_query_handler (GstPad * pad, GstQuery * query);
78 static gboolean gst_flxdec_src_event_handler (GstPad * pad, GstEvent * event);
79 static gboolean gst_flxdec_sink_event_handler (GstPad * pad, GstEvent * event);
80
81 static void gst_flxdec_set_property (GObject * object, guint prop_id,
82     const GValue * value, GParamSpec * pspec);
83 static void gst_flxdec_get_property (GObject * object, guint prop_id,
84     GValue * value, GParamSpec * pspec);
85
86
87 static void flx_decode_color (GstFlxDec *, guchar *, guchar *, gint);
88 static void flx_decode_brun (GstFlxDec *, guchar *, guchar *);
89 static void flx_decode_delta_fli (GstFlxDec *, guchar *, guchar *);
90 static void flx_decode_delta_flc (GstFlxDec *, guchar *, guchar *);
91
92 #define rndalign(off) ((off) + ((off) & 1))
93
94 static GstElementClass *parent_class = NULL;
95
96 GType
97 gst_flxdec_get_type (void)
98 {
99   static GType flxdec_type = 0;
100
101   if (!flxdec_type) {
102     static const GTypeInfo flxdec_info = {
103       sizeof (GstFlxDecClass),
104       (GBaseInitFunc) gst_flxdec_base_init,
105       NULL,
106       (GClassInitFunc) gst_flxdec_class_init,
107       NULL,
108       NULL,
109       sizeof (GstFlxDec),
110       0,
111       (GInstanceInitFunc) gst_flxdec_init,
112     };
113
114     flxdec_type =
115         g_type_register_static (GST_TYPE_ELEMENT, "GstFlxDec", &flxdec_info, 0);
116   }
117   return flxdec_type;
118 }
119
120 static void
121 gst_flxdec_base_init (GstFlxDecClass * klass)
122 {
123   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
124
125   gst_element_class_set_details (gstelement_class, &flxdec_details);
126   gst_element_class_add_pad_template (gstelement_class,
127       gst_static_pad_template_get (&sink_factory));
128   gst_element_class_add_pad_template (gstelement_class,
129       gst_static_pad_template_get (&src_video_factory));
130 }
131
132 static void
133 gst_flxdec_class_init (GstFlxDecClass * klass)
134 {
135   GObjectClass *gobject_class;
136   GstElementClass *gstelement_class;
137
138   gobject_class = (GObjectClass *) klass;
139   gstelement_class = (GstElementClass *) klass;
140
141   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
142
143   GST_DEBUG_CATEGORY_INIT (flxdec_debug, "flxdec", 0, "FLX video decoder");
144
145   gobject_class->set_property = gst_flxdec_set_property;
146   gobject_class->get_property = gst_flxdec_get_property;
147
148   gstelement_class->change_state = gst_flxdec_change_state;
149 }
150
151 static void
152 gst_flxdec_init (GstFlxDec * flxdec)
153 {
154   flxdec->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");
155   gst_element_add_pad (GST_ELEMENT (flxdec), flxdec->sinkpad);
156   gst_pad_set_chain_function (flxdec->sinkpad, gst_flxdec_chain);
157   gst_pad_set_event_function (flxdec->sinkpad, gst_flxdec_sink_event_handler);
158
159   flxdec->srcpad = gst_pad_new_from_static_template (&src_video_factory, "src");
160   gst_element_add_pad (GST_ELEMENT (flxdec), flxdec->srcpad);
161   gst_pad_set_query_function (flxdec->srcpad, gst_flxdec_src_query_handler);
162   gst_pad_set_event_function (flxdec->srcpad, gst_flxdec_src_event_handler);
163
164   gst_pad_use_fixed_caps (flxdec->srcpad);
165
166   flxdec->frame = NULL;
167   flxdec->delta = NULL;
168
169   flxdec->adapter = gst_adapter_new ();
170 }
171
172 static gboolean
173 gst_flxdec_src_query_handler (GstPad * pad, GstQuery * query)
174 {
175   GstFlxDec *flxdec = (GstFlxDec *) gst_pad_get_parent (pad);
176   gboolean ret = FALSE;
177
178   switch (GST_QUERY_TYPE (query)) {
179     case GST_QUERY_DURATION:
180     {
181       GstFormat format;
182
183       gst_query_parse_duration (query, &format, NULL);
184
185       if (format != GST_FORMAT_TIME)
186         goto done;
187
188       gst_query_set_duration (query, format, flxdec->duration);
189
190       ret = TRUE;
191     }
192     default:
193       break;
194   }
195 done:
196   gst_object_unref (flxdec);
197
198   return ret;
199 }
200
201 static gboolean
202 gst_flxdec_src_event_handler (GstPad * pad, GstEvent * event)
203 {
204   GstFlxDec *flxdec = (GstFlxDec *) gst_pad_get_parent (pad);
205   gboolean ret;
206
207   /* TODO: implement the seek and other event handling */
208
209   ret = gst_pad_push_event (flxdec->sinkpad, event);
210
211   gst_object_unref (flxdec);
212
213   return ret;
214 }
215
216 static gboolean
217 gst_flxdec_sink_event_handler (GstPad * pad, GstEvent * event)
218 {
219   GstFlxDec *flxdec;
220   gboolean ret;
221
222   flxdec = GST_FLXDEC (gst_pad_get_parent (pad));
223
224   ret = gst_pad_push_event (flxdec->srcpad, event);
225
226   gst_object_unref (flxdec);
227   return ret;
228 }
229
230 static void
231 flx_decode_chunks (GstFlxDec * flxdec, gulong count, guchar * data,
232     guchar * dest)
233 {
234   FlxFrameChunk *hdr;
235
236   g_return_if_fail (data != NULL);
237
238   while (count--) {
239     hdr = (FlxFrameChunk *) data;
240     FLX_FRAME_CHUNK_FIX_ENDIANNESS (hdr);
241     data += FlxFrameChunkSize;
242
243     switch (hdr->id) {
244       case FLX_COLOR64:
245         flx_decode_color (flxdec, data, dest, 2);
246         data += rndalign (hdr->size) - FlxFrameChunkSize;
247         break;
248
249       case FLX_COLOR256:
250         flx_decode_color (flxdec, data, dest, 0);
251         data += rndalign (hdr->size) - FlxFrameChunkSize;
252         break;
253
254       case FLX_BRUN:
255         flx_decode_brun (flxdec, data, dest);
256         data += rndalign (hdr->size) - FlxFrameChunkSize;
257         break;
258
259       case FLX_LC:
260         flx_decode_delta_fli (flxdec, data, dest);
261         data += rndalign (hdr->size) - FlxFrameChunkSize;
262         break;
263
264       case FLX_SS2:
265         flx_decode_delta_flc (flxdec, data, dest);
266         data += rndalign (hdr->size) - FlxFrameChunkSize;
267         break;
268
269       case FLX_BLACK:
270         memset (dest, 0, flxdec->size);
271         break;
272
273       case FLX_MINI:
274         data += rndalign (hdr->size) - FlxFrameChunkSize;
275         break;
276
277       default:
278         GST_WARNING ("Unimplented chunk type: 0x%02x size: %d - skipping",
279             hdr->id, hdr->size);
280         data += rndalign (hdr->size) - FlxFrameChunkSize;
281         break;
282     }
283   }
284 }
285
286
287 static void
288 flx_decode_color (GstFlxDec * flxdec, guchar * data, guchar * dest, gint scale)
289 {
290   guint packs, count, indx;
291
292   g_return_if_fail (flxdec != NULL);
293
294   packs = (data[0] + (data[1] << 8));
295
296   data += 2;
297   indx = 0;
298
299   GST_LOG ("GstFlxDec: cmap packs: %d", packs);
300   while (packs--) {
301     /* color map index + skip count */
302     indx += *data++;
303
304     /* number of rgb triplets */
305     count = *data++ & 0xff;
306     if (count == 0)
307       count = 256;
308
309     GST_LOG ("GstFlxDec: cmap count: %d (indx: %d)", count, indx);
310     flx_set_palette_vector (flxdec->converter, indx, count, data, scale);
311
312     data += (count * 3);
313   }
314 }
315
316 static void
317 flx_decode_brun (GstFlxDec * flxdec, guchar * data, guchar * dest)
318 {
319   gulong count, lines, row;
320   guchar x;
321
322   g_return_if_fail (flxdec != NULL);
323
324   lines = flxdec->hdr.height;
325   while (lines--) {
326     /* packet count.  
327      * should not be used anymore, since the flc format can
328      * contain more then 255 RLE packets. we use the frame 
329      * width instead. 
330      */
331     data++;
332
333     row = flxdec->hdr.width;
334     while (row) {
335       count = *data++;
336
337       if (count > 0x7f) {
338         /* literal run */
339         count = 0x100 - count;
340         row -= count;
341
342         while (count--)
343           *dest++ = *data++;
344
345       } else {
346         /* replicate run */
347         row -= count;
348         x = *data++;
349
350         while (count--)
351           *dest++ = x;
352       }
353     }
354   }
355 }
356
357 static void
358 flx_decode_delta_fli (GstFlxDec * flxdec, guchar * data, guchar * dest)
359 {
360   gulong count, packets, lines, start_line, start_l;
361   guchar *start_p, x;
362
363   g_return_if_fail (flxdec != NULL);
364   g_return_if_fail (flxdec->delta != NULL);
365
366   /* use last frame for delta */
367   memcpy (dest, GST_BUFFER_DATA (flxdec->delta),
368       GST_BUFFER_SIZE (flxdec->delta));
369
370   start_line = (data[0] + (data[1] << 8));
371   lines = (data[2] + (data[3] << 8));
372   data += 4;
373
374   /* start position of delta */
375   dest += (flxdec->hdr.width * start_line);
376   start_p = dest;
377   start_l = lines;
378
379   while (lines--) {
380     /* packet count */
381     packets = *data++;
382
383     while (packets--) {
384       /* skip count */
385       dest += *data++;
386
387       /* RLE count */
388       count = *data++;
389
390       if (count > 0x7f) {
391         /* literal run */
392         count = 0x100 - count;
393         x = *data++;
394
395         while (count--)
396           *dest++ = x;
397
398       } else {
399         /* replicate run */
400         while (count--)
401           *dest++ = *data++;
402       }
403     }
404     start_p += flxdec->hdr.width;
405     dest = start_p;
406   }
407 }
408
409 static void
410 flx_decode_delta_flc (GstFlxDec * flxdec, guchar * data, guchar * dest)
411 {
412   gulong count, lines, start_l, opcode;
413   guchar *start_p;
414
415   g_return_if_fail (flxdec != NULL);
416   g_return_if_fail (flxdec->delta != NULL);
417
418   /* use last frame for delta */
419   memcpy (dest, GST_BUFFER_DATA (flxdec->delta),
420       GST_BUFFER_SIZE (flxdec->delta));
421
422   lines = (data[0] + (data[1] << 8));
423   data += 2;
424
425   start_p = dest;
426   start_l = lines;
427
428   while (lines) {
429     dest = start_p + (flxdec->hdr.width * (start_l - lines));
430
431     /* process opcode(s) */
432     while ((opcode = (data[0] + (data[1] << 8))) & 0xc000) {
433       data += 2;
434       if ((opcode & 0xc000) == 0xc000) {
435         /* skip count */
436         start_l += (0x10000 - opcode);
437         dest += flxdec->hdr.width * (0x10000 - opcode);
438       } else {
439         /* last pixel */
440         dest += flxdec->hdr.width;
441         *dest++ = (opcode & 0xff);
442       }
443     }
444     data += 2;
445
446     /* last opcode is the packet count */
447     while (opcode--) {
448       /* skip count */
449       dest += *data++;
450
451       /* RLE count */
452       count = *data++;
453
454       if (count > 0x7f) {
455         /* replicate word run */
456         count = 0x100 - count;
457         while (count--) {
458           *dest++ = data[0];
459           *dest++ = data[1];
460         }
461         data += 2;
462       } else {
463         /* literal word run */
464         while (count--) {
465           *dest++ = *data++;
466           *dest++ = *data++;
467         }
468       }
469     }
470     lines--;
471   }
472 }
473
474 static GstFlowReturn
475 gst_flxdec_chain (GstPad * pad, GstBuffer * buf)
476 {
477   GstCaps *caps;
478   guint avail;
479   GstFlowReturn res = GST_FLOW_OK;
480
481   GstFlxDec *flxdec;
482   FlxHeader *flxh;
483
484   g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR);
485   flxdec = (GstFlxDec *) gst_pad_get_parent (pad);
486   g_return_val_if_fail (flxdec != NULL, GST_FLOW_ERROR);
487
488   gst_adapter_push (flxdec->adapter, buf);
489   avail = gst_adapter_available (flxdec->adapter);
490
491   if (flxdec->state == GST_FLXDEC_READ_HEADER) {
492     if (avail >= FlxHeaderSize) {
493       const guint8 *data = gst_adapter_peek (flxdec->adapter, FlxHeaderSize);
494
495       memcpy ((gchar *) & flxdec->hdr, data, FlxHeaderSize);
496       FLX_HDR_FIX_ENDIANNESS (&(flxdec->hdr));
497       gst_adapter_flush (flxdec->adapter, FlxHeaderSize);
498
499       flxh = &flxdec->hdr;
500
501       /* check header */
502       if (flxh->type != FLX_MAGICHDR_FLI &&
503           flxh->type != FLX_MAGICHDR_FLC && flxh->type != FLX_MAGICHDR_FLX)
504         goto wrong_type;
505
506       GST_LOG ("size      :  %d", flxh->size);
507       GST_LOG ("frames    :  %d", flxh->frames);
508       GST_LOG ("width     :  %d", flxh->width);
509       GST_LOG ("height    :  %d", flxh->height);
510       GST_LOG ("depth     :  %d", flxh->depth);
511       GST_LOG ("speed     :  %d", flxh->speed);
512
513       flxdec->next_time = 0;
514
515       if (flxh->type == FLX_MAGICHDR_FLI) {
516         flxdec->frame_time = JIFFIE * flxh->speed;
517       } else if (flxh->speed == 0) {
518         flxdec->frame_time = GST_SECOND / 70;
519       } else {
520         flxdec->frame_time = flxh->speed * GST_MSECOND;
521       }
522
523       flxdec->duration = flxh->frames * flxdec->frame_time;
524       GST_LOG ("duration   :  %" GST_TIME_FORMAT,
525           GST_TIME_ARGS (flxdec->duration));
526
527       caps = gst_caps_from_string (GST_VIDEO_CAPS_xRGB_HOST_ENDIAN);
528       gst_caps_set_simple (caps,
529           "width", G_TYPE_INT, flxh->width,
530           "height", G_TYPE_INT, flxh->height,
531           "framerate", GST_TYPE_FRACTION, (gint) GST_MSECOND,
532           (gint) flxdec->frame_time / 1000, NULL);
533
534       gst_pad_set_caps (flxdec->srcpad, caps);
535       gst_caps_unref (caps);
536
537       if (flxh->depth <= 8)
538         flxdec->converter =
539             flx_colorspace_converter_new (flxh->width, flxh->height);
540
541       if (flxh->type == FLX_MAGICHDR_FLC || flxh->type == FLX_MAGICHDR_FLX) {
542         GST_LOG ("(FLC) aspect_dx :  %d", flxh->aspect_dx);
543         GST_LOG ("(FLC) aspect_dy :  %d", flxh->aspect_dy);
544         GST_LOG ("(FLC) oframe1   :  0x%08x", flxh->oframe1);
545         GST_LOG ("(FLC) oframe2   :  0x%08x", flxh->oframe2);
546       }
547
548       flxdec->size = (flxh->width * flxh->height);
549
550       /* create delta and output frame */
551       flxdec->frame = gst_buffer_new ();
552       flxdec->delta = gst_buffer_new ();
553       GST_BUFFER_DATA (flxdec->frame) = g_malloc (flxdec->size);
554       GST_BUFFER_MALLOCDATA (flxdec->frame) = GST_BUFFER_DATA (flxdec->frame);
555       GST_BUFFER_SIZE (flxdec->frame) = flxdec->size;
556       GST_BUFFER_DATA (flxdec->delta) = g_malloc (flxdec->size);
557       GST_BUFFER_MALLOCDATA (flxdec->delta) = GST_BUFFER_DATA (flxdec->delta);
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     /* while we have enough data in the adapter */
566     while (avail >= FlxFrameChunkSize) {
567       FlxFrameChunk flxfh;
568       guchar *chunk;
569       const guint8 *data;
570
571       chunk = NULL;
572       data = gst_adapter_peek (flxdec->adapter, FlxFrameChunkSize);
573       memcpy (&flxfh, data, FlxFrameChunkSize);
574       FLX_FRAME_CHUNK_FIX_ENDIANNESS (&flxfh);
575
576       switch (flxfh.id) {
577         case FLX_FRAME_TYPE:
578           /* check if we have the complete frame */
579           if (avail < flxfh.size)
580             goto need_more_data;
581
582           /* flush header */
583           gst_adapter_flush (flxdec->adapter, FlxFrameChunkSize);
584
585           chunk = gst_adapter_take (flxdec->adapter,
586               flxfh.size - FlxFrameChunkSize);
587           FLX_FRAME_TYPE_FIX_ENDIANNESS ((FlxFrameType *) chunk);
588           if (((FlxFrameType *) chunk)->chunks == 0)
589             break;
590
591           /* create 32 bits output frame */
592           res = gst_pad_alloc_buffer_and_set_caps (flxdec->srcpad,
593               GST_BUFFER_OFFSET_NONE,
594               flxdec->size * 4, GST_PAD_CAPS (flxdec->srcpad), &out);
595           if (res != GST_FLOW_OK)
596             break;
597
598           /* decode chunks */
599           flx_decode_chunks (flxdec,
600               ((FlxFrameType *) chunk)->chunks,
601               chunk + FlxFrameTypeSize, GST_BUFFER_DATA (flxdec->frame));
602
603           /* save copy of the current frame for possible delta. */
604           memcpy (GST_BUFFER_DATA (flxdec->delta),
605               GST_BUFFER_DATA (flxdec->frame), GST_BUFFER_SIZE (flxdec->delta));
606
607           /* convert current frame. */
608           flx_colorspace_convert (flxdec->converter,
609               GST_BUFFER_DATA (flxdec->frame), GST_BUFFER_DATA (out));
610
611           GST_BUFFER_TIMESTAMP (out) = flxdec->next_time;
612           flxdec->next_time += flxdec->frame_time;
613
614           gst_pad_push (flxdec->srcpad, out);
615           break;
616       }
617
618       if (chunk)
619         g_free (chunk);
620
621       avail = gst_adapter_available (flxdec->adapter);
622     }
623   }
624 need_more_data:
625   gst_object_unref (flxdec);
626   return res;
627
628   /* ERRORS */
629 wrong_type:
630   {
631     GST_ELEMENT_ERROR (flxdec, STREAM, WRONG_TYPE, (NULL),
632         ("not a flx file (type %x)", flxh->type));
633     gst_object_unref (flxdec);
634     return GST_FLOW_ERROR;
635   }
636 }
637
638 static GstStateChangeReturn
639 gst_flxdec_change_state (GstElement * element, GstStateChange transition)
640 {
641   GstFlxDec *flxdec;
642   GstStateChangeReturn ret;
643
644   flxdec = GST_FLXDEC (element);
645
646   switch (transition) {
647     case GST_STATE_CHANGE_NULL_TO_READY:
648       break;
649     case GST_STATE_CHANGE_READY_TO_PAUSED:
650       gst_adapter_clear (flxdec->adapter);
651       flxdec->state = GST_FLXDEC_READ_HEADER;
652       break;
653     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
654       break;
655     default:
656       break;
657   }
658
659   ret = parent_class->change_state (element, transition);
660
661   switch (transition) {
662     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
663       break;
664     case GST_STATE_CHANGE_PAUSED_TO_READY:
665       if (flxdec->frame) {
666         gst_buffer_unref (flxdec->frame);
667         flxdec->frame = NULL;
668       }
669       if (flxdec->delta) {
670         gst_buffer_unref (flxdec->delta);
671         flxdec->delta = NULL;
672       }
673       break;
674     case GST_STATE_CHANGE_READY_TO_NULL:
675       break;
676     default:
677       break;
678   }
679   return ret;
680 }
681
682 static void
683 gst_flxdec_set_property (GObject * object, guint prop_id, const GValue * value,
684     GParamSpec * pspec)
685 {
686   GstFlxDec *flxdec;
687
688   g_return_if_fail (GST_IS_FLXDEC (object));
689   flxdec = GST_FLXDEC (object);
690
691   switch (prop_id) {
692     default:
693       break;
694   }
695 }
696
697 static void
698 gst_flxdec_get_property (GObject * object, guint prop_id, GValue * value,
699     GParamSpec * pspec)
700 {
701   GstFlxDec *flxdec;
702
703   g_return_if_fail (GST_IS_FLXDEC (object));
704   flxdec = GST_FLXDEC (object);
705
706   switch (prop_id) {
707     default:
708       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
709       break;
710   }
711 }
712
713 static gboolean
714 plugin_init (GstPlugin * plugin)
715 {
716   return gst_element_register (plugin, "flxdec",
717       GST_RANK_PRIMARY, GST_TYPE_FLXDEC);
718 }
719
720 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
721     GST_VERSION_MINOR,
722     "flxdec",
723     "FLX video decoder",
724     plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)