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