1 /* GStreamer
2 * Copyright (C) <1999> Erik Walthinsen <omega@temple-baptist.com>
3 * Copyright (C) <2016> Matthew Waters <matthew@centricular.com>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20 /**
21 * SECTION:element-flxdec
22 * @title: flxdec
23 *
24 * This element decodes fli/flc/flx-video into raw video
25 */
26 /*
27 * http://www.coolutils.com/Formats/FLI
28 * http://woodshole.er.usgs.gov/operations/modeling/flc.html
29 * http://www.compuphase.com/flic.htm
30 */
31
32 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
35 #include <string.h>
36
37 #include "flx_fmt.h"
38 #include "gstflxdec.h"
39 #include <gst/video/video.h>
40
41 #define JIFFIE (GST_SECOND/70)
42
43 GST_DEBUG_CATEGORY_STATIC (flxdec_debug);
44 #define GST_CAT_DEFAULT flxdec_debug
45
46 /* input */
47 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
48 GST_PAD_SINK,
49 GST_PAD_ALWAYS,
50 GST_STATIC_CAPS ("video/x-fli")
51 );
52
53 #if G_BYTE_ORDER == G_BIG_ENDIAN
54 #define RGB_ORDER "xRGB"
55 #else
56 #define RGB_ORDER "BGRx"
57 #endif
58
59 /* output */
60 static GstStaticPadTemplate src_video_factory = GST_STATIC_PAD_TEMPLATE ("src",
61 GST_PAD_SRC,
62 GST_PAD_ALWAYS,
63 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (RGB_ORDER))
64 );
65
66 static void gst_flxdec_dispose (GstFlxDec * flxdec);
67
68 static GstFlowReturn gst_flxdec_chain (GstPad * pad, GstObject * parent,
69 GstBuffer * buf);
70 static gboolean gst_flxdec_sink_event_handler (GstPad * pad,
71 GstObject * parent, GstEvent * event);
72
73 static GstStateChangeReturn gst_flxdec_change_state (GstElement * element,
74 GstStateChange transition);
75
76 static gboolean gst_flxdec_src_query_handler (GstPad * pad, GstObject * parent,
77 GstQuery * query);
78
79 static gboolean flx_decode_color (GstFlxDec * flxdec, GstByteReader * reader,
80 GstByteWriter * writer, gint scale);
81 static gboolean flx_decode_brun (GstFlxDec * flxdec,
82 GstByteReader * reader, GstByteWriter * writer);
83 static gboolean flx_decode_delta_fli (GstFlxDec * flxdec,
84 GstByteReader * reader, GstByteWriter * writer);
85 static gboolean flx_decode_delta_flc (GstFlxDec * flxdec,
86 GstByteReader * reader, GstByteWriter * writer);
87
88 #define rndalign(off) ((off) + ((off) & 1))
89
90 #define gst_flxdec_parent_class parent_class
91 G_DEFINE_TYPE (GstFlxDec, gst_flxdec, GST_TYPE_ELEMENT);
92 GST_ELEMENT_REGISTER_DEFINE (flxdec, "flxdec",
93 GST_RANK_PRIMARY, GST_TYPE_FLXDEC);
94
95 static void
gst_flxdec_class_init(GstFlxDecClass * klass)96 gst_flxdec_class_init (GstFlxDecClass * klass)
97 {
98 GObjectClass *gobject_class;
99 GstElementClass *gstelement_class;
100
101 gobject_class = (GObjectClass *) klass;
102 gstelement_class = (GstElementClass *) klass;
103
104 parent_class = g_type_class_peek_parent (klass);
105
106 gobject_class->dispose = (GObjectFinalizeFunc) gst_flxdec_dispose;
107
108 GST_DEBUG_CATEGORY_INIT (flxdec_debug, "flxdec", 0, "FLX video decoder");
109
110 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_flxdec_change_state);
111
112 gst_element_class_set_static_metadata (gstelement_class, "FLX video decoder",
113 "Codec/Decoder/Video",
114 "FLC/FLI/FLX video decoder",
115 "Sepp Wijnands <mrrazz@garbage-coderz.net>, Zeeshan Ali <zeenix@gmail.com>");
116 gst_element_class_add_pad_template (gstelement_class,
117 gst_static_pad_template_get (&sink_factory));
118 gst_element_class_add_pad_template (gstelement_class,
119 gst_static_pad_template_get (&src_video_factory));
120 }
121
122 static void
gst_flxdec_init(GstFlxDec * flxdec)123 gst_flxdec_init (GstFlxDec * flxdec)
124 {
125 flxdec->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");
126 gst_element_add_pad (GST_ELEMENT (flxdec), flxdec->sinkpad);
127 gst_pad_set_chain_function (flxdec->sinkpad,
128 GST_DEBUG_FUNCPTR (gst_flxdec_chain));
129 gst_pad_set_event_function (flxdec->sinkpad,
130 GST_DEBUG_FUNCPTR (gst_flxdec_sink_event_handler));
131
132 flxdec->srcpad = gst_pad_new_from_static_template (&src_video_factory, "src");
133 gst_element_add_pad (GST_ELEMENT (flxdec), flxdec->srcpad);
134 gst_pad_set_query_function (flxdec->srcpad,
135 GST_DEBUG_FUNCPTR (gst_flxdec_src_query_handler));
136
137 gst_pad_use_fixed_caps (flxdec->srcpad);
138
139 flxdec->adapter = gst_adapter_new ();
140 }
141
142 static void
gst_flxdec_dispose(GstFlxDec * flxdec)143 gst_flxdec_dispose (GstFlxDec * flxdec)
144 {
145 if (flxdec->adapter) {
146 g_object_unref (flxdec->adapter);
147 flxdec->adapter = NULL;
148 }
149
150 G_OBJECT_CLASS (parent_class)->dispose ((GObject *) flxdec);
151 }
152
153 static gboolean
gst_flxdec_src_query_handler(GstPad * pad,GstObject * parent,GstQuery * query)154 gst_flxdec_src_query_handler (GstPad * pad, GstObject * parent,
155 GstQuery * query)
156 {
157 GstFlxDec *flxdec = (GstFlxDec *) parent;
158 gboolean ret = FALSE;
159
160 switch (GST_QUERY_TYPE (query)) {
161 case GST_QUERY_DURATION:
162 {
163 GstFormat format;
164
165 gst_query_parse_duration (query, &format, NULL);
166
167 if (format != GST_FORMAT_TIME)
168 goto done;
169
170 gst_query_set_duration (query, format, flxdec->duration);
171
172 ret = TRUE;
173 }
174 default:
175 break;
176 }
177 done:
178 if (!ret)
179 ret = gst_pad_query_default (pad, parent, query);
180
181 return ret;
182 }
183
184 static gboolean
gst_flxdec_sink_event_handler(GstPad * pad,GstObject * parent,GstEvent * event)185 gst_flxdec_sink_event_handler (GstPad * pad, GstObject * parent,
186 GstEvent * event)
187 {
188 GstFlxDec *flxdec;
189 gboolean ret;
190
191 flxdec = GST_FLXDEC (parent);
192
193 switch (GST_EVENT_TYPE (event)) {
194 case GST_EVENT_SEGMENT:
195 {
196 gst_event_copy_segment (event, &flxdec->segment);
197 if (flxdec->segment.format != GST_FORMAT_TIME) {
198 GST_DEBUG_OBJECT (flxdec, "generating TIME segment");
199 gst_segment_init (&flxdec->segment, GST_FORMAT_TIME);
200 gst_event_unref (event);
201 event = gst_event_new_segment (&flxdec->segment);
202 }
203
204 if (gst_pad_has_current_caps (flxdec->srcpad)) {
205 ret = gst_pad_event_default (pad, parent, event);
206 } else {
207 flxdec->need_segment = TRUE;
208 gst_event_unref (event);
209 ret = TRUE;
210 }
211 break;
212 }
213 case GST_EVENT_FLUSH_STOP:
214 gst_segment_init (&flxdec->segment, GST_FORMAT_UNDEFINED);
215 ret = gst_pad_event_default (pad, parent, event);
216 break;
217 default:
218 ret = gst_pad_event_default (pad, parent, event);
219 break;
220 }
221
222 return ret;
223 }
224
225 static gboolean
flx_decode_chunks(GstFlxDec * flxdec,gulong n_chunks,GstByteReader * reader,GstByteWriter * writer)226 flx_decode_chunks (GstFlxDec * flxdec, gulong n_chunks, GstByteReader * reader,
227 GstByteWriter * writer)
228 {
229 gboolean ret = TRUE;
230
231 while (n_chunks--) {
232 GstByteReader chunk;
233 guint32 size;
234 guint16 type;
235
236 if (!gst_byte_reader_get_uint32_le (reader, &size))
237 goto parse_error;
238 if (!gst_byte_reader_get_uint16_le (reader, &type))
239 goto parse_error;
240 GST_LOG_OBJECT (flxdec, "chunk has type 0x%02x size %d", type, size);
241
242 if (!gst_byte_reader_get_sub_reader (reader, &chunk,
243 size - FlxFrameChunkSize)) {
244 GST_ERROR_OBJECT (flxdec, "Incorrect size in the chunk header");
245 goto error;
246 }
247
248 switch (type) {
249 case FLX_COLOR64:
250 ret = flx_decode_color (flxdec, &chunk, writer, 2);
251 break;
252
253 case FLX_COLOR256:
254 ret = flx_decode_color (flxdec, &chunk, writer, 0);
255 break;
256
257 case FLX_BRUN:
258 ret = flx_decode_brun (flxdec, &chunk, writer);
259 break;
260
261 case FLX_LC:
262 ret = flx_decode_delta_fli (flxdec, &chunk, writer);
263 break;
264
265 case FLX_SS2:
266 ret = flx_decode_delta_flc (flxdec, &chunk, writer);
267 break;
268
269 case FLX_BLACK:
270 ret = gst_byte_writer_fill (writer, 0, flxdec->size);
271 break;
272
273 case FLX_MINI:
274 break;
275
276 default:
277 GST_WARNING ("Unimplemented chunk type: 0x%02x size: %d - skipping",
278 type, size);
279 break;
280 }
281
282 if (!ret)
283 break;
284 }
285
286 return ret;
287
288 parse_error:
289 GST_ERROR_OBJECT (flxdec, "Failed to decode chunk");
290 error:
291 return FALSE;
292 }
293
294
295 static gboolean
flx_decode_color(GstFlxDec * flxdec,GstByteReader * reader,GstByteWriter * writer,gint scale)296 flx_decode_color (GstFlxDec * flxdec, GstByteReader * reader,
297 GstByteWriter * writer, gint scale)
298 {
299 guint8 count, indx;
300 guint16 packs;
301
302 if (!gst_byte_reader_get_uint16_le (reader, &packs))
303 goto error;
304 indx = 0;
305
306 GST_LOG ("GstFlxDec: cmap packs: %d", (guint) packs);
307 while (packs--) {
308 const guint8 *data;
309 guint16 actual_count;
310
311 /* color map index + skip count */
312 if (!gst_byte_reader_get_uint8 (reader, &indx))
313 goto error;
314
315 /* number of rgb triplets */
316 if (!gst_byte_reader_get_uint8 (reader, &count))
317 goto error;
318
319 actual_count = count == 0 ? 256 : count;
320
321 if (!gst_byte_reader_get_data (reader, count * 3, &data))
322 goto error;
323
324 GST_LOG_OBJECT (flxdec, "cmap count: %d (indx: %d)", actual_count, indx);
325 flx_set_palette_vector (flxdec->converter, indx, actual_count,
326 (guchar *) data, scale);
327 }
328
329 return TRUE;
330
331 error:
332 GST_ERROR_OBJECT (flxdec, "Error decoding color palette");
333 return FALSE;
334 }
335
336 static gboolean
flx_decode_brun(GstFlxDec * flxdec,GstByteReader * reader,GstByteWriter * writer)337 flx_decode_brun (GstFlxDec * flxdec, GstByteReader * reader,
338 GstByteWriter * writer)
339 {
340 gulong lines, row;
341
342 g_return_val_if_fail (flxdec != NULL, FALSE);
343
344 lines = flxdec->hdr.height;
345 while (lines--) {
346 /* packet count.
347 * should not be used anymore, since the flc format can
348 * contain more then 255 RLE packets. we use the frame
349 * width instead.
350 */
351 if (!gst_byte_reader_skip (reader, 1))
352 goto error;
353
354 row = flxdec->hdr.width;
355 while (row) {
356 gint8 count;
357
358 if (!gst_byte_reader_get_int8 (reader, &count))
359 goto error;
360
361 if (count <= 0) {
362 const guint8 *data;
363
364 /* literal run */
365 count = ABS (count);
366
367 GST_LOG_OBJECT (flxdec, "have literal run of size %d", count);
368
369 if (count > row) {
370 GST_ERROR_OBJECT (flxdec, "Invalid BRUN line detected. "
371 "bytes to write exceeds the end of the row");
372 return FALSE;
373 }
374 row -= count;
375
376 if (!gst_byte_reader_get_data (reader, count, &data))
377 goto error;
378 if (!gst_byte_writer_put_data (writer, data, count))
379 goto error;
380 } else {
381 guint8 x;
382
383 GST_LOG_OBJECT (flxdec, "have replicate run of size %d", count);
384
385 if (count > row) {
386 GST_ERROR_OBJECT (flxdec, "Invalid BRUN packet detected."
387 "bytes to write exceeds the end of the row");
388 return FALSE;
389 }
390
391 /* replicate run */
392 row -= count;
393
394 if (!gst_byte_reader_get_uint8 (reader, &x))
395 goto error;
396 if (!gst_byte_writer_fill (writer, x, count))
397 goto error;
398 }
399 }
400 }
401
402 return TRUE;
403
404 error:
405 GST_ERROR_OBJECT (flxdec, "Failed to decode BRUN packet");
406 return FALSE;
407 }
408
409 static gboolean
flx_decode_delta_fli(GstFlxDec * flxdec,GstByteReader * reader,GstByteWriter * writer)410 flx_decode_delta_fli (GstFlxDec * flxdec, GstByteReader * reader,
411 GstByteWriter * writer)
412 {
413 guint16 start_line, lines;
414 guint line_start_i;
415
416 g_return_val_if_fail (flxdec != NULL, FALSE);
417 g_return_val_if_fail (flxdec->delta_data != NULL, FALSE);
418
419 /* use last frame for delta */
420 if (!gst_byte_writer_put_data (writer, flxdec->delta_data, flxdec->size))
421 goto error;
422
423 if (!gst_byte_reader_get_uint16_le (reader, &start_line))
424 goto error;
425 if (!gst_byte_reader_get_uint16_le (reader, &lines))
426 goto error;
427 GST_LOG_OBJECT (flxdec, "height %d start line %d line count %d",
428 flxdec->hdr.height, start_line, lines);
429
430 if (start_line + lines > flxdec->hdr.height) {
431 GST_ERROR_OBJECT (flxdec, "Invalid FLI packet detected. too many lines.");
432 return FALSE;
433 }
434
435 line_start_i = flxdec->hdr.width * start_line;
436 if (!gst_byte_writer_set_pos (writer, line_start_i))
437 goto error;
438
439 while (lines--) {
440 guint8 packets;
441
442 /* packet count */
443 if (!gst_byte_reader_get_uint8 (reader, &packets))
444 goto error;
445 GST_LOG_OBJECT (flxdec, "have %d packets", packets);
446
447 while (packets--) {
448 /* skip count */
449 guint8 skip;
450 gint8 count;
451 if (!gst_byte_reader_get_uint8 (reader, &skip))
452 goto error;
453
454 /* skip bytes */
455 if (!gst_byte_writer_set_pos (writer,
456 gst_byte_writer_get_pos (writer) + skip))
457 goto error;
458
459 /* RLE count */
460 if (!gst_byte_reader_get_int8 (reader, &count))
461 goto error;
462
463 if (count < 0) {
464 guint8 x;
465
466 /* literal run */
467 count = ABS (count);
468 GST_LOG_OBJECT (flxdec, "have literal run of size %d at offset %d",
469 count, skip);
470
471 if (skip + count > flxdec->hdr.width) {
472 GST_ERROR_OBJECT (flxdec, "Invalid FLI packet detected. "
473 "line too long.");
474 return FALSE;
475 }
476
477 if (!gst_byte_reader_get_uint8 (reader, &x))
478 goto error;
479 if (!gst_byte_writer_fill (writer, x, count))
480 goto error;
481 } else {
482 const guint8 *data;
483
484 GST_LOG_OBJECT (flxdec, "have replicate run of size %d at offset %d",
485 count, skip);
486
487 if (skip + count > flxdec->hdr.width) {
488 GST_ERROR_OBJECT (flxdec, "Invalid FLI packet detected. "
489 "line too long.");
490 return FALSE;
491 }
492
493 /* replicate run */
494 if (!gst_byte_reader_get_data (reader, count, &data))
495 goto error;
496 if (!gst_byte_writer_put_data (writer, data, count))
497 goto error;
498 }
499 }
500 line_start_i += flxdec->hdr.width;
501 if (!gst_byte_writer_set_pos (writer, line_start_i))
502 goto error;
503 }
504
505 return TRUE;
506
507 error:
508 GST_ERROR_OBJECT (flxdec, "Failed to decode FLI packet");
509 return FALSE;
510 }
511
512 static gboolean
flx_decode_delta_flc(GstFlxDec * flxdec,GstByteReader * reader,GstByteWriter * writer)513 flx_decode_delta_flc (GstFlxDec * flxdec, GstByteReader * reader,
514 GstByteWriter * writer)
515 {
516 guint16 lines, start_l;
517
518 g_return_val_if_fail (flxdec != NULL, FALSE);
519 g_return_val_if_fail (flxdec->delta_data != NULL, FALSE);
520
521 /* use last frame for delta */
522 if (!gst_byte_writer_put_data (writer, flxdec->delta_data, flxdec->size))
523 goto error;
524 if (!gst_byte_reader_get_uint16_le (reader, &lines))
525 goto error;
526
527 if (lines > flxdec->hdr.height) {
528 GST_ERROR_OBJECT (flxdec, "Invalid FLC packet detected. too many lines.");
529 return FALSE;
530 }
531
532 start_l = lines;
533
534 while (lines) {
535 guint16 opcode;
536
537 if (!gst_byte_writer_set_pos (writer,
538 flxdec->hdr.width * (start_l - lines)))
539 goto error;
540
541 /* process opcode(s) */
542 while (TRUE) {
543 if (!gst_byte_reader_get_uint16_le (reader, &opcode))
544 goto error;
545 if ((opcode & 0xc000) == 0)
546 break;
547
548 if ((opcode & 0xc000) == 0xc000) {
549 /* line skip count */
550 gulong skip = (0x10000 - opcode);
551 if (skip > flxdec->hdr.height) {
552 GST_ERROR_OBJECT (flxdec, "Invalid FLC packet detected. "
553 "skip line count too big.");
554 return FALSE;
555 }
556 start_l += skip;
557 if (!gst_byte_writer_set_pos (writer,
558 gst_byte_writer_get_pos (writer) + flxdec->hdr.width * skip))
559 goto error;
560 } else {
561 /* last pixel */
562 if (!gst_byte_writer_set_pos (writer,
563 gst_byte_writer_get_pos (writer) + flxdec->hdr.width))
564 goto error;
565 if (!gst_byte_writer_put_uint8 (writer, opcode & 0xff))
566 goto error;
567 }
568 }
569
570 /* last opcode is the packet count */
571 GST_LOG_OBJECT (flxdec, "have %d packets", opcode);
572 while (opcode--) {
573 /* skip count */
574 guint8 skip;
575 gint8 count;
576
577 if (!gst_byte_reader_get_uint8 (reader, &skip))
578 goto error;
579 if (!gst_byte_writer_set_pos (writer,
580 gst_byte_writer_get_pos (writer) + skip))
581 goto error;
582
583 /* RLE count */
584 if (!gst_byte_reader_get_int8 (reader, &count))
585 goto error;
586
587 if (count < 0) {
588 guint16 x;
589
590 /* replicate word run */
591 count = ABS (count);
592
593 GST_LOG_OBJECT (flxdec, "have replicate run of size %d at offset %d",
594 count, skip);
595
596 if (skip + count > flxdec->hdr.width) {
597 GST_ERROR_OBJECT (flxdec, "Invalid FLC packet detected. "
598 "line too long.");
599 return FALSE;
600 }
601
602 if (!gst_byte_reader_get_uint16_le (reader, &x))
603 goto error;
604
605 while (count--) {
606 if (!gst_byte_writer_put_uint16_le (writer, x)) {
607 goto error;
608 }
609 }
610 } else {
611 GST_LOG_OBJECT (flxdec, "have literal run of size %d at offset %d",
612 count, skip);
613
614 if (skip + count > flxdec->hdr.width) {
615 GST_ERROR_OBJECT (flxdec, "Invalid FLC packet detected. "
616 "line too long.");
617 return FALSE;
618 }
619
620 while (count--) {
621 guint16 x;
622
623 if (!gst_byte_reader_get_uint16_le (reader, &x))
624 goto error;
625 if (!gst_byte_writer_put_uint16_le (writer, x))
626 goto error;
627 }
628 }
629 }
630 lines--;
631 }
632
633 return TRUE;
634
635 error:
636 GST_ERROR_OBJECT (flxdec, "Failed to decode FLI packet");
637 return FALSE;
638 }
639
640 static gboolean
_read_flx_header(GstFlxDec * flxdec,GstByteReader * reader,FlxHeader * flxh)641 _read_flx_header (GstFlxDec * flxdec, GstByteReader * reader, FlxHeader * flxh)
642 {
643 memset (flxh, 0, sizeof (*flxh));
644
645 if (!gst_byte_reader_get_uint32_le (reader, &flxh->size))
646 goto error;
647 if (flxh->size < FlxHeaderSize) {
648 GST_ERROR_OBJECT (flxdec, "Invalid file size in the header");
649 return FALSE;
650 }
651
652 if (!gst_byte_reader_get_uint16_le (reader, &flxh->type))
653 goto error;
654 if (!gst_byte_reader_get_uint16_le (reader, &flxh->frames))
655 goto error;
656 if (!gst_byte_reader_get_uint16_le (reader, &flxh->width))
657 goto error;
658 if (!gst_byte_reader_get_uint16_le (reader, &flxh->height))
659 goto error;
660 if (!gst_byte_reader_get_uint16_le (reader, &flxh->depth))
661 goto error;
662 if (!gst_byte_reader_get_uint16_le (reader, &flxh->flags))
663 goto error;
664 if (!gst_byte_reader_get_uint32_le (reader, &flxh->speed))
665 goto error;
666 if (!gst_byte_reader_skip (reader, 2)) /* reserved */
667 goto error;
668 /* FLC */
669 if (!gst_byte_reader_get_uint32_le (reader, &flxh->created))
670 goto error;
671 if (!gst_byte_reader_get_uint32_le (reader, &flxh->creator))
672 goto error;
673 if (!gst_byte_reader_get_uint32_le (reader, &flxh->updated))
674 goto error;
675 if (!gst_byte_reader_get_uint32_le (reader, &flxh->updater))
676 goto error;
677 if (!gst_byte_reader_get_uint16_le (reader, &flxh->aspect_dx))
678 goto error;
679 if (!gst_byte_reader_get_uint16_le (reader, &flxh->aspect_dy))
680 goto error;
681 /* EGI */
682 if (!gst_byte_reader_get_uint16_le (reader, &flxh->ext_flags))
683 goto error;
684 if (!gst_byte_reader_get_uint16_le (reader, &flxh->keyframes))
685 goto error;
686 if (!gst_byte_reader_get_uint16_le (reader, &flxh->totalframes))
687 goto error;
688 if (!gst_byte_reader_get_uint32_le (reader, &flxh->req_memory))
689 goto error;
690 if (!gst_byte_reader_get_uint16_le (reader, &flxh->max_regions))
691 goto error;
692 if (!gst_byte_reader_get_uint16_le (reader, &flxh->transp_num))
693 goto error;
694 if (!gst_byte_reader_skip (reader, 24)) /* reserved */
695 goto error;
696 /* FLC */
697 if (!gst_byte_reader_get_uint32_le (reader, &flxh->oframe1))
698 goto error;
699 if (!gst_byte_reader_get_uint32_le (reader, &flxh->oframe2))
700 goto error;
701 if (!gst_byte_reader_skip (reader, 40)) /* reserved */
702 goto error;
703
704 return TRUE;
705
706 error:
707 GST_ERROR_OBJECT (flxdec, "Error reading file header");
708 return FALSE;
709 }
710
711 static GstFlowReturn
gst_flxdec_chain(GstPad * pad,GstObject * parent,GstBuffer * buf)712 gst_flxdec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
713 {
714 GstByteReader reader;
715 GstBuffer *input;
716 GstMapInfo map_info;
717 GstCaps *caps;
718 guint available;
719 GstFlowReturn res = GST_FLOW_OK;
720
721 GstFlxDec *flxdec;
722 FlxHeader *flxh;
723
724 g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR);
725 flxdec = (GstFlxDec *) parent;
726 g_return_val_if_fail (flxdec != NULL, GST_FLOW_ERROR);
727
728 gst_adapter_push (flxdec->adapter, buf);
729 available = gst_adapter_available (flxdec->adapter);
730 input = gst_adapter_get_buffer (flxdec->adapter, available);
731 if (!gst_buffer_map (input, &map_info, GST_MAP_READ)) {
732 GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
733 ("%s", "Failed to map buffer"), (NULL));
734 goto error;
735 }
736 gst_byte_reader_init (&reader, map_info.data, map_info.size);
737
738 if (flxdec->state == GST_FLXDEC_READ_HEADER) {
739 if (available >= FlxHeaderSize) {
740 GstByteReader header;
741 GstCaps *templ;
742
743 if (!gst_byte_reader_get_sub_reader (&reader, &header, FlxHeaderSize)) {
744 GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
745 ("%s", "Could not read header"), (NULL));
746 goto unmap_input_error;
747 }
748 gst_adapter_flush (flxdec->adapter, FlxHeaderSize);
749 available -= FlxHeaderSize;
750
751 if (!_read_flx_header (flxdec, &header, &flxdec->hdr)) {
752 GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
753 ("%s", "Failed to parse header"), (NULL));
754 goto unmap_input_error;
755 }
756
757 flxh = &flxdec->hdr;
758
759 /* check header */
760 if (flxh->type != FLX_MAGICHDR_FLI &&
761 flxh->type != FLX_MAGICHDR_FLC && flxh->type != FLX_MAGICHDR_FLX) {
762 GST_ELEMENT_ERROR (flxdec, STREAM, WRONG_TYPE, (NULL),
763 ("not a flx file (type %x)", flxh->type));
764 goto unmap_input_error;
765 }
766
767 GST_INFO_OBJECT (flxdec, "size : %d", flxh->size);
768 GST_INFO_OBJECT (flxdec, "frames : %d", flxh->frames);
769 GST_INFO_OBJECT (flxdec, "width : %d", flxh->width);
770 GST_INFO_OBJECT (flxdec, "height : %d", flxh->height);
771 GST_INFO_OBJECT (flxdec, "depth : %d", flxh->depth);
772 GST_INFO_OBJECT (flxdec, "speed : %d", flxh->speed);
773
774 flxdec->next_time = 0;
775
776 if (flxh->type == FLX_MAGICHDR_FLI) {
777 flxdec->frame_time = JIFFIE * flxh->speed;
778 } else if (flxh->speed == 0) {
779 flxdec->frame_time = GST_SECOND / 70;
780 } else {
781 flxdec->frame_time = flxh->speed * GST_MSECOND;
782 }
783
784 flxdec->duration = flxh->frames * flxdec->frame_time;
785 GST_LOG ("duration : %" GST_TIME_FORMAT,
786 GST_TIME_ARGS (flxdec->duration));
787
788 templ = gst_pad_get_pad_template_caps (flxdec->srcpad);
789 caps = gst_caps_copy (templ);
790 gst_caps_unref (templ);
791 gst_caps_set_simple (caps,
792 "width", G_TYPE_INT, flxh->width,
793 "height", G_TYPE_INT, flxh->height,
794 "framerate", GST_TYPE_FRACTION, (gint) GST_MSECOND,
795 (gint) flxdec->frame_time / 1000, NULL);
796
797 gst_pad_set_caps (flxdec->srcpad, caps);
798 gst_caps_unref (caps);
799
800 if (flxdec->need_segment) {
801 gst_pad_push_event (flxdec->srcpad,
802 gst_event_new_segment (&flxdec->segment));
803 flxdec->need_segment = FALSE;
804 }
805
806 /* zero means 8 */
807 if (flxh->depth == 0)
808 flxh->depth = 8;
809
810 if (flxh->depth != 8) {
811 GST_ELEMENT_ERROR (flxdec, STREAM, WRONG_TYPE,
812 ("%s", "Don't know how to decode non 8 bit depth streams"), (NULL));
813 goto unmap_input_error;
814 }
815
816 flxdec->converter =
817 flx_colorspace_converter_new (flxh->width, flxh->height);
818
819 if (flxh->type == FLX_MAGICHDR_FLC || flxh->type == FLX_MAGICHDR_FLX) {
820 GST_INFO_OBJECT (flxdec, "(FLC) aspect_dx : %d", flxh->aspect_dx);
821 GST_INFO_OBJECT (flxdec, "(FLC) aspect_dy : %d", flxh->aspect_dy);
822 GST_INFO_OBJECT (flxdec, "(FLC) oframe1 : 0x%08x", flxh->oframe1);
823 GST_INFO_OBJECT (flxdec, "(FLC) oframe2 : 0x%08x", flxh->oframe2);
824 }
825
826 flxdec->size = ((guint) flxh->width * (guint) flxh->height);
827 if (flxdec->size >= G_MAXSIZE / 4) {
828 GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
829 ("%s", "Cannot allocate required memory"), (NULL));
830 goto unmap_input_error;
831 }
832
833 /* create delta and output frame */
834 flxdec->frame_data = g_malloc0 (flxdec->size);
835 flxdec->delta_data = g_malloc0 (flxdec->size);
836
837 flxdec->state = GST_FLXDEC_PLAYING;
838 }
839 } else if (flxdec->state == GST_FLXDEC_PLAYING) {
840 GstBuffer *out;
841
842 /* while we have enough data in the adapter */
843 while (available >= FlxFrameChunkSize && res == GST_FLOW_OK) {
844 guint32 size;
845 guint16 type;
846
847 if (!gst_byte_reader_get_uint32_le (&reader, &size))
848 goto parse_error;
849 if (available < size)
850 goto need_more_data;
851
852 available -= size;
853 gst_adapter_flush (flxdec->adapter, size);
854
855 if (!gst_byte_reader_get_uint16_le (&reader, &type))
856 goto parse_error;
857
858 switch (type) {
859 case FLX_FRAME_TYPE:{
860 GstByteReader chunks;
861 GstByteWriter writer;
862 guint16 n_chunks;
863 GstMapInfo map;
864
865 GST_LOG_OBJECT (flxdec, "Have frame type 0x%02x of size %d", type,
866 size);
867
868 if (!gst_byte_reader_get_sub_reader (&reader, &chunks,
869 size - FlxFrameChunkSize))
870 goto parse_error;
871
872 if (!gst_byte_reader_get_uint16_le (&chunks, &n_chunks))
873 goto parse_error;
874 GST_LOG_OBJECT (flxdec, "Have %d chunks", n_chunks);
875
876 if (n_chunks == 0)
877 break;
878 if (!gst_byte_reader_skip (&chunks, 8)) /* reserved */
879 goto parse_error;
880
881 gst_byte_writer_init_with_data (&writer, flxdec->frame_data,
882 flxdec->size, TRUE);
883
884 /* decode chunks */
885 if (!flx_decode_chunks (flxdec, n_chunks, &chunks, &writer)) {
886 GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
887 ("%s", "Could not decode chunk"), NULL);
888 goto unmap_input_error;
889 }
890 gst_byte_writer_reset (&writer);
891
892 /* save copy of the current frame for possible delta. */
893 memcpy (flxdec->delta_data, flxdec->frame_data, flxdec->size);
894
895 out = gst_buffer_new_and_alloc (flxdec->size * 4);
896 if (!gst_buffer_map (out, &map, GST_MAP_WRITE)) {
897 GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
898 ("%s", "Could not map output buffer"), NULL);
899 gst_buffer_unref (out);
900 goto unmap_input_error;
901 }
902
903 /* convert current frame. */
904 flx_colorspace_convert (flxdec->converter, flxdec->frame_data,
905 map.data);
906 gst_buffer_unmap (out, &map);
907
908 GST_BUFFER_TIMESTAMP (out) = flxdec->next_time;
909 flxdec->next_time += flxdec->frame_time;
910
911 res = gst_pad_push (flxdec->srcpad, out);
912 break;
913 }
914 default:
915 GST_DEBUG_OBJECT (flxdec, "Unknown frame type 0x%02x, skipping %d",
916 type, size);
917 if (!gst_byte_reader_skip (&reader, size - FlxFrameChunkSize))
918 goto parse_error;
919 break;
920 }
921 }
922 }
923
924 need_more_data:
925 gst_buffer_unmap (input, &map_info);
926 gst_buffer_unref (input);
927 return res;
928
929 /* ERRORS */
930 parse_error:
931 GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
932 ("%s", "Failed to parse stream"), (NULL));
933 unmap_input_error:
934 gst_buffer_unmap (input, &map_info);
935 error:
936 gst_buffer_unref (input);
937 return GST_FLOW_ERROR;
938 }
939
940 static GstStateChangeReturn
gst_flxdec_change_state(GstElement * element,GstStateChange transition)941 gst_flxdec_change_state (GstElement * element, GstStateChange transition)
942 {
943 GstFlxDec *flxdec;
944 GstStateChangeReturn ret;
945
946 flxdec = GST_FLXDEC (element);
947
948 switch (transition) {
949 case GST_STATE_CHANGE_NULL_TO_READY:
950 break;
951 case GST_STATE_CHANGE_READY_TO_PAUSED:
952 gst_adapter_clear (flxdec->adapter);
953 flxdec->state = GST_FLXDEC_READ_HEADER;
954 gst_segment_init (&flxdec->segment, GST_FORMAT_UNDEFINED);
955 flxdec->need_segment = TRUE;
956 break;
957 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
958 break;
959 default:
960 break;
961 }
962
963 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
964
965 switch (transition) {
966 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
967 break;
968 case GST_STATE_CHANGE_PAUSED_TO_READY:
969 if (flxdec->frame_data) {
970 g_free (flxdec->frame_data);
971 flxdec->frame_data = NULL;
972 }
973 if (flxdec->delta_data) {
974 g_free (flxdec->delta_data);
975 flxdec->delta_data = NULL;
976 }
977 if (flxdec->converter) {
978 flx_colorspace_converter_destroy (flxdec->converter);
979 flxdec->converter = NULL;
980 }
981 break;
982 case GST_STATE_CHANGE_READY_TO_NULL:
983 break;
984 default:
985 break;
986 }
987 return ret;
988 }
989
990 static gboolean
plugin_init(GstPlugin * plugin)991 plugin_init (GstPlugin * plugin)
992 {
993 return GST_ELEMENT_REGISTER (flxdec, plugin);
994 }
995
996 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
997 GST_VERSION_MINOR,
998 flxdec,
999 "FLC/FLI/FLX video decoder",
1000 plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
1001