gstflxdec.c 17.6 KB
Newer Older
Christian Schaller's avatar
Christian Schaller committed
1
2
/* GStreamer
 * Copyright (C) <1999> Erik Walthinsen <omega@temple-baptist.com>
Andy Wingo's avatar
Andy Wingo committed
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */
19
20
21
22
23
24
25
26
27
/**
 * SECTION:element-flxdec
 *
 * This element decodes fli/flc/flx-video into raw video
 */
/*
 * http://www.coolutils.com/Formats/FLI
 * http://woodshole.er.usgs.gov/operations/modeling/flc.html
 */
Andy Wingo's avatar
Andy Wingo committed
28

29
30
31
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
Andy Wingo's avatar
Andy Wingo committed
32
33
34
35
#include <string.h>

#include "flx_fmt.h"
#include "gstflxdec.h"
36
#include <gst/video/video.h>
Andy Wingo's avatar
Andy Wingo committed
37

Wim Taymans's avatar
Wim Taymans committed
38
#define JIFFIE  (GST_SECOND/70)
39

40
41
42
GST_DEBUG_CATEGORY_STATIC (flxdec_debug);
#define GST_CAT_DEFAULT flxdec_debug

Andy Wingo's avatar
Andy Wingo committed
43
/* input */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
44
45
46
47
48
static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
    GST_PAD_SINK,
    GST_PAD_ALWAYS,
    GST_STATIC_CAPS ("video/x-fli")
    );
Andy Wingo's avatar
Andy Wingo committed
49
50

/* output */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
51
52
53
static GstStaticPadTemplate src_video_factory = GST_STATIC_PAD_TEMPLATE ("src",
    GST_PAD_SRC,
    GST_PAD_ALWAYS,
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
54
55
56
57
58
#if G_BYTE_ORDER == G_BIG_ENDIAN
    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("xRGB"))
#else
    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("BGRx"))
#endif
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
59
    );
Andy Wingo's avatar
Andy Wingo committed
60

61
static void gst_flxdec_dispose (GstFlxDec * flxdec);
Andy Wingo's avatar
Andy Wingo committed
62

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
63
64
static GstFlowReturn gst_flxdec_chain (GstPad * pad, GstObject * parent,
    GstBuffer * buf);
65
66
static gboolean gst_flxdec_sink_event_handler (GstPad * pad,
    GstObject * parent, GstEvent * event);
Andy Wingo's avatar
Andy Wingo committed
67

68
69
static GstStateChangeReturn gst_flxdec_change_state (GstElement * element,
    GstStateChange transition);
70

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
71
72
static gboolean gst_flxdec_src_query_handler (GstPad * pad, GstObject * parent,
    GstQuery * query);
Zeeshan Ali's avatar
Zeeshan Ali committed
73

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
74
75
76
77
static void flx_decode_color (GstFlxDec *, guchar *, guchar *, gint);
static void flx_decode_brun (GstFlxDec *, guchar *, guchar *);
static void flx_decode_delta_fli (GstFlxDec *, guchar *, guchar *);
static void flx_decode_delta_flc (GstFlxDec *, guchar *, guchar *);
Andy Wingo's avatar
Andy Wingo committed
78

79
#define rndalign(off) ((off) + ((off) & 1))
Andy Wingo's avatar
Andy Wingo committed
80

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
81
82
#define gst_flxdec_parent_class parent_class
G_DEFINE_TYPE (GstFlxDec, gst_flxdec, GST_TYPE_ELEMENT);
Ronald S. Bultje's avatar
Ronald S. Bultje committed
83

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
84
85
static void
gst_flxdec_class_init (GstFlxDecClass * klass)
Andy Wingo's avatar
Andy Wingo committed
86
87
88
89
{
  GObjectClass *gobject_class;
  GstElementClass *gstelement_class;

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
90
91
  gobject_class = (GObjectClass *) klass;
  gstelement_class = (GstElementClass *) klass;
Andy Wingo's avatar
Andy Wingo committed
92

93
  parent_class = g_type_class_peek_parent (klass);
Andy Wingo's avatar
Andy Wingo committed
94

95
96
  gobject_class->dispose = (GObjectFinalizeFunc) gst_flxdec_dispose;

97
98
  GST_DEBUG_CATEGORY_INIT (flxdec_debug, "flxdec", 0, "FLX video decoder");

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
99
100
101
102
103
104
105
106
107
108
  gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_flxdec_change_state);

  gst_element_class_set_static_metadata (gstelement_class, "FLX video decoder",
      "Codec/Decoder/Video",
      "FLC/FLI/FLX video decoder",
      "Sepp Wijnands <mrrazz@garbage-coderz.net>, Zeeshan Ali <zeenix@gmail.com>");
  gst_element_class_add_pad_template (gstelement_class,
      gst_static_pad_template_get (&sink_factory));
  gst_element_class_add_pad_template (gstelement_class,
      gst_static_pad_template_get (&src_video_factory));
Andy Wingo's avatar
Andy Wingo committed
109
110
}

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
111
112
static void
gst_flxdec_init (GstFlxDec * flxdec)
Andy Wingo's avatar
Andy Wingo committed
113
{
114
  flxdec->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
115
  gst_element_add_pad (GST_ELEMENT (flxdec), flxdec->sinkpad);
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
116
117
  gst_pad_set_chain_function (flxdec->sinkpad,
      GST_DEBUG_FUNCPTR (gst_flxdec_chain));
118
119
  gst_pad_set_event_function (flxdec->sinkpad,
      GST_DEBUG_FUNCPTR (gst_flxdec_sink_event_handler));
Andy Wingo's avatar
Andy Wingo committed
120

121
  flxdec->srcpad = gst_pad_new_from_static_template (&src_video_factory, "src");
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
122
  gst_element_add_pad (GST_ELEMENT (flxdec), flxdec->srcpad);
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
123
124
  gst_pad_set_query_function (flxdec->srcpad,
      GST_DEBUG_FUNCPTR (gst_flxdec_src_query_handler));
Zeeshan Ali's avatar
Zeeshan Ali committed
125
126

  gst_pad_use_fixed_caps (flxdec->srcpad);
Andy Wingo's avatar
Andy Wingo committed
127

Zeeshan Ali's avatar
Zeeshan Ali committed
128
129
130
  flxdec->adapter = gst_adapter_new ();
}

131
132
133
134
135
136
137
138
139
140
141
static void
gst_flxdec_dispose (GstFlxDec * flxdec)
{
  if (flxdec->adapter) {
    g_object_unref (flxdec->adapter);
    flxdec->adapter = NULL;
  }

  G_OBJECT_CLASS (parent_class)->dispose ((GObject *) flxdec);
}

142
static gboolean
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
143
144
gst_flxdec_src_query_handler (GstPad * pad, GstObject * parent,
    GstQuery * query)
145
{
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
146
  GstFlxDec *flxdec = (GstFlxDec *) parent;
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
  gboolean ret = FALSE;

  switch (GST_QUERY_TYPE (query)) {
    case GST_QUERY_DURATION:
    {
      GstFormat format;

      gst_query_parse_duration (query, &format, NULL);

      if (format != GST_FORMAT_TIME)
        goto done;

      gst_query_set_duration (query, format, flxdec->duration);

      ret = TRUE;
    }
    default:
      break;
  }
done:
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
167
168
  if (!ret)
    ret = gst_pad_query_default (pad, parent, query);
169
170

  return ret;
Zeeshan Ali's avatar
Zeeshan Ali committed
171
172
}

173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
static gboolean
gst_flxdec_sink_event_handler (GstPad * pad, GstObject * parent,
    GstEvent * event)
{
  GstFlxDec *flxdec;
  gboolean ret;

  flxdec = GST_FLXDEC (parent);

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_SEGMENT:
    {
      GstSegment segment;

      gst_event_copy_segment (event, &segment);
      if (segment.format != GST_FORMAT_TIME) {
        GST_DEBUG_OBJECT (flxdec, "generating TIME segment");
        gst_segment_init (&segment, GST_FORMAT_TIME);
        gst_event_unref (event);
        event = gst_event_new_segment (&segment);
      }
      /* fall-through */
    }
    default:
      ret = gst_pad_event_default (pad, parent, event);
      break;
  }

  return ret;
}

Andy Wingo's avatar
Andy Wingo committed
204
static void
205
206
flx_decode_chunks (GstFlxDec * flxdec, gulong count, guchar * data,
    guchar * dest)
Andy Wingo's avatar
Andy Wingo committed
207
{
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
208
  FlxFrameChunk *hdr;
Andy Wingo's avatar
Andy Wingo committed
209

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
210
  g_return_if_fail (data != NULL);
Andy Wingo's avatar
Andy Wingo committed
211
212

  while (count--) {
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
213
    hdr = (FlxFrameChunk *) data;
214
    FLX_FRAME_CHUNK_FIX_ENDIANNESS (hdr);
Andy Wingo's avatar
Andy Wingo committed
215
216
    data += FlxFrameChunkSize;

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
217
    switch (hdr->id) {
Andy Wingo's avatar
Andy Wingo committed
218
      case FLX_COLOR64:
219
220
221
        flx_decode_color (flxdec, data, dest, 2);
        data += rndalign (hdr->size) - FlxFrameChunkSize;
        break;
222

Andy Wingo's avatar
Andy Wingo committed
223
      case FLX_COLOR256:
224
225
226
        flx_decode_color (flxdec, data, dest, 0);
        data += rndalign (hdr->size) - FlxFrameChunkSize;
        break;
Andy Wingo's avatar
Andy Wingo committed
227
228

      case FLX_BRUN:
229
230
231
        flx_decode_brun (flxdec, data, dest);
        data += rndalign (hdr->size) - FlxFrameChunkSize;
        break;
Andy Wingo's avatar
Andy Wingo committed
232
233

      case FLX_LC:
234
235
236
        flx_decode_delta_fli (flxdec, data, dest);
        data += rndalign (hdr->size) - FlxFrameChunkSize;
        break;
Andy Wingo's avatar
Andy Wingo committed
237
238

      case FLX_SS2:
239
240
241
        flx_decode_delta_flc (flxdec, data, dest);
        data += rndalign (hdr->size) - FlxFrameChunkSize;
        break;
Andy Wingo's avatar
Andy Wingo committed
242
243

      case FLX_BLACK:
244
245
        memset (dest, 0, flxdec->size);
        break;
Andy Wingo's avatar
Andy Wingo committed
246
247

      case FLX_MINI:
248
249
        data += rndalign (hdr->size) - FlxFrameChunkSize;
        break;
Andy Wingo's avatar
Andy Wingo committed
250
251

      default:
252
        GST_WARNING ("Unimplented chunk type: 0x%02x size: %d - skipping",
253
254
255
            hdr->id, hdr->size);
        data += rndalign (hdr->size) - FlxFrameChunkSize;
        break;
Andy Wingo's avatar
Andy Wingo committed
256
257
258
259
260
261
    }
  }
}


static void
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
262
flx_decode_color (GstFlxDec * flxdec, guchar * data, guchar * dest, gint scale)
Andy Wingo's avatar
Andy Wingo committed
263
264
265
{
  guint packs, count, indx;

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
266
  g_return_if_fail (flxdec != NULL);
Andy Wingo's avatar
Andy Wingo committed
267
268
269
270

  packs = (data[0] + (data[1] << 8));

  data += 2;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
271
  indx = 0;
Andy Wingo's avatar
Andy Wingo committed
272

273
  GST_LOG ("GstFlxDec: cmap packs: %d", packs);
Andy Wingo's avatar
Andy Wingo committed
274
275
276
277
278
279
280
281
282
  while (packs--) {
    /* color map index + skip count */
    indx += *data++;

    /* number of rgb triplets */
    count = *data++ & 0xff;
    if (count == 0)
      count = 256;

283
    GST_LOG ("GstFlxDec: cmap count: %d (indx: %d)", count, indx);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
284
    flx_set_palette_vector (flxdec->converter, indx, count, data, scale);
Andy Wingo's avatar
Andy Wingo committed
285
286
287
288
289

    data += (count * 3);
  }
}

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
290
291
static void
flx_decode_brun (GstFlxDec * flxdec, guchar * data, guchar * dest)
Andy Wingo's avatar
Andy Wingo committed
292
{
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
293
294
295
296
  gulong count, lines, row;
  guchar x;

  g_return_if_fail (flxdec != NULL);
Andy Wingo's avatar
Andy Wingo committed
297
298

  lines = flxdec->hdr.height;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
299
  while (lines--) {
Andy Wingo's avatar
Andy Wingo committed
300
301
302
303
304
305
306
307
    /* packet count.  
     * should not be used anymore, since the flc format can
     * contain more then 255 RLE packets. we use the frame 
     * width instead. 
     */
    data++;

    row = flxdec->hdr.width;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
308
    while (row) {
Andy Wingo's avatar
Andy Wingo committed
309
310
      count = *data++;

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
311
      if (count > 0x7f) {
312
313
314
        /* literal run */
        count = 0x100 - count;
        row -= count;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
315

316
317
        while (count--)
          *dest++ = *data++;
Andy Wingo's avatar
Andy Wingo committed
318
319

      } else {
320
321
322
        /* replicate run */
        row -= count;
        x = *data++;
Andy Wingo's avatar
Andy Wingo committed
323

324
325
        while (count--)
          *dest++ = x;
Andy Wingo's avatar
Andy Wingo committed
326
327
328
329
330
      }
    }
  }
}

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
331
332
static void
flx_decode_delta_fli (GstFlxDec * flxdec, guchar * data, guchar * dest)
Andy Wingo's avatar
Andy Wingo committed
333
{
334
  gulong count, packets, lines, start_line;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
335
336
337
  guchar *start_p, x;

  g_return_if_fail (flxdec != NULL);
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
338
  g_return_if_fail (flxdec->delta_data != NULL);
Andy Wingo's avatar
Andy Wingo committed
339
340

  /* use last frame for delta */
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
341
  memcpy (dest, flxdec->delta_data, flxdec->size);
Andy Wingo's avatar
Andy Wingo committed
342
343

  start_line = (data[0] + (data[1] << 8));
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
344
345
  lines = (data[2] + (data[3] << 8));
  data += 4;
Andy Wingo's avatar
Andy Wingo committed
346
347
348
349
350

  /* start position of delta */
  dest += (flxdec->hdr.width * start_line);
  start_p = dest;

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
351
  while (lines--) {
Andy Wingo's avatar
Andy Wingo committed
352
353
354
    /* packet count */
    packets = *data++;

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
355
    while (packets--) {
Andy Wingo's avatar
Andy Wingo committed
356
357
358
359
360
361
      /* skip count */
      dest += *data++;

      /* RLE count */
      count = *data++;

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
362
      if (count > 0x7f) {
363
364
365
        /* literal run */
        count = 0x100 - count;
        x = *data++;
Andy Wingo's avatar
Andy Wingo committed
366

367
368
        while (count--)
          *dest++ = x;
Andy Wingo's avatar
Andy Wingo committed
369
370

      } else {
371
372
373
        /* replicate run */
        while (count--)
          *dest++ = *data++;
Andy Wingo's avatar
Andy Wingo committed
374
375
      }
    }
376
377
    start_p += flxdec->hdr.width;
    dest = start_p;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
378
  }
Andy Wingo's avatar
Andy Wingo committed
379
380
}

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
381
382
static void
flx_decode_delta_flc (GstFlxDec * flxdec, guchar * data, guchar * dest)
Andy Wingo's avatar
Andy Wingo committed
383
{
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
384
385
386
387
  gulong count, lines, start_l, opcode;
  guchar *start_p;

  g_return_if_fail (flxdec != NULL);
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
388
  g_return_if_fail (flxdec->delta_data != NULL);
Andy Wingo's avatar
Andy Wingo committed
389
390

  /* use last frame for delta */
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
391
  memcpy (dest, flxdec->delta_data, flxdec->size);
Andy Wingo's avatar
Andy Wingo committed
392

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
393
394
  lines = (data[0] + (data[1] << 8));
  data += 2;
Andy Wingo's avatar
Andy Wingo committed
395

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
396
397
  start_p = dest;
  start_l = lines;
Andy Wingo's avatar
Andy Wingo committed
398

399
  while (lines) {
Andy Wingo's avatar
Andy Wingo committed
400
401
402
403
404
405
    dest = start_p + (flxdec->hdr.width * (start_l - lines));

    /* process opcode(s) */
    while ((opcode = (data[0] + (data[1] << 8))) & 0xc000) {
      data += 2;
      if ((opcode & 0xc000) == 0xc000) {
406
407
408
        /* skip count */
        start_l += (0x10000 - opcode);
        dest += flxdec->hdr.width * (0x10000 - opcode);
Andy Wingo's avatar
Andy Wingo committed
409
      } else {
410
411
412
        /* last pixel */
        dest += flxdec->hdr.width;
        *dest++ = (opcode & 0xff);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
413
      }
Andy Wingo's avatar
Andy Wingo committed
414
415
416
417
    }
    data += 2;

    /* last opcode is the packet count */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
418
    while (opcode--) {
Andy Wingo's avatar
Andy Wingo committed
419
420
      /* skip count */
      dest += *data++;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
421

Andy Wingo's avatar
Andy Wingo committed
422
423
      /* RLE count */
      count = *data++;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
424

Andy Wingo's avatar
Andy Wingo committed
425
      if (count > 0x7f) {
426
427
428
429
430
431
432
        /* replicate word run */
        count = 0x100 - count;
        while (count--) {
          *dest++ = data[0];
          *dest++ = data[1];
        }
        data += 2;
Andy Wingo's avatar
Andy Wingo committed
433
      } else {
434
435
436
437
438
        /* literal word run */
        while (count--) {
          *dest++ = *data++;
          *dest++ = *data++;
        }
Andy Wingo's avatar
Andy Wingo committed
439
440
      }
    }
441
    lines--;
Andy Wingo's avatar
Andy Wingo committed
442
443
  }
}
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
444

Zeeshan Ali's avatar
Zeeshan Ali committed
445
static GstFlowReturn
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
446
gst_flxdec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
Andy Wingo's avatar
Andy Wingo committed
447
{
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
448
  GstCaps *caps;
Zeeshan Ali's avatar
Zeeshan Ali committed
449
450
  guint avail;
  GstFlowReturn res = GST_FLOW_OK;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
451
452
453
454

  GstFlxDec *flxdec;
  FlxHeader *flxh;

Zeeshan Ali's avatar
Zeeshan Ali committed
455
  g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR);
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
456
  flxdec = (GstFlxDec *) parent;
Zeeshan Ali's avatar
Zeeshan Ali committed
457
  g_return_val_if_fail (flxdec != NULL, GST_FLOW_ERROR);
Andy Wingo's avatar
Andy Wingo committed
458

Zeeshan Ali's avatar
Zeeshan Ali committed
459
460
  gst_adapter_push (flxdec->adapter, buf);
  avail = gst_adapter_available (flxdec->adapter);
Andy Wingo's avatar
Andy Wingo committed
461

462
  if (flxdec->state == GST_FLXDEC_READ_HEADER) {
Zeeshan Ali's avatar
Zeeshan Ali committed
463
    if (avail >= FlxHeaderSize) {
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
464
465
      const guint8 *data = gst_adapter_map (flxdec->adapter, FlxHeaderSize);
      GstCaps *templ;
Wim Taymans's avatar
Wim Taymans committed
466

Zeeshan Ali's avatar
Zeeshan Ali committed
467
      memcpy ((gchar *) & flxdec->hdr, data, FlxHeaderSize);
468
      FLX_HDR_FIX_ENDIANNESS (&(flxdec->hdr));
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
469
      gst_adapter_unmap (flxdec->adapter);
Zeeshan Ali's avatar
Zeeshan Ali committed
470
      gst_adapter_flush (flxdec->adapter, FlxHeaderSize);
Andy Wingo's avatar
Andy Wingo committed
471

Zeeshan Ali's avatar
Zeeshan Ali committed
472
      flxh = &flxdec->hdr;
Andy Wingo's avatar
Andy Wingo committed
473

Zeeshan Ali's avatar
Zeeshan Ali committed
474
475
      /* check header */
      if (flxh->type != FLX_MAGICHDR_FLI &&
476
477
          flxh->type != FLX_MAGICHDR_FLC && flxh->type != FLX_MAGICHDR_FLX)
        goto wrong_type;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
478

479
480
481
482
483
484
      GST_LOG ("size      :  %d", flxh->size);
      GST_LOG ("frames    :  %d", flxh->frames);
      GST_LOG ("width     :  %d", flxh->width);
      GST_LOG ("height    :  %d", flxh->height);
      GST_LOG ("depth     :  %d", flxh->depth);
      GST_LOG ("speed     :  %d", flxh->speed);
485

Zeeshan Ali's avatar
Zeeshan Ali committed
486
      flxdec->next_time = 0;
487

Zeeshan Ali's avatar
Zeeshan Ali committed
488
489
      if (flxh->type == FLX_MAGICHDR_FLI) {
        flxdec->frame_time = JIFFIE * flxh->speed;
490
491
      } else if (flxh->speed == 0) {
        flxdec->frame_time = GST_SECOND / 70;
Zeeshan Ali's avatar
Zeeshan Ali committed
492
493
494
      } else {
        flxdec->frame_time = flxh->speed * GST_MSECOND;
      }
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
495

496
      flxdec->duration = flxh->frames * flxdec->frame_time;
497
498
      GST_LOG ("duration   :  %" GST_TIME_FORMAT,
          GST_TIME_ARGS (flxdec->duration));
499

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
500
501
502
      templ = gst_pad_get_pad_template_caps (flxdec->srcpad);
      caps = gst_caps_copy (templ);
      gst_caps_unref (templ);
Zeeshan Ali's avatar
Zeeshan Ali committed
503
504
505
      gst_caps_set_simple (caps,
          "width", G_TYPE_INT, flxh->width,
          "height", G_TYPE_INT, flxh->height,
506
507
          "framerate", GST_TYPE_FRACTION, (gint) GST_MSECOND,
          (gint) flxdec->frame_time / 1000, NULL);
Zeeshan Ali's avatar
Zeeshan Ali committed
508
509
510
511
512
513
514
515
516

      gst_pad_set_caps (flxdec->srcpad, caps);
      gst_caps_unref (caps);

      if (flxh->depth <= 8)
        flxdec->converter =
            flx_colorspace_converter_new (flxh->width, flxh->height);

      if (flxh->type == FLX_MAGICHDR_FLC || flxh->type == FLX_MAGICHDR_FLX) {
517
518
519
520
        GST_LOG ("(FLC) aspect_dx :  %d", flxh->aspect_dx);
        GST_LOG ("(FLC) aspect_dy :  %d", flxh->aspect_dy);
        GST_LOG ("(FLC) oframe1   :  0x%08x", flxh->oframe1);
        GST_LOG ("(FLC) oframe2   :  0x%08x", flxh->oframe2);
Zeeshan Ali's avatar
Zeeshan Ali committed
521
      }
522

Zeeshan Ali's avatar
Zeeshan Ali committed
523
      flxdec->size = (flxh->width * flxh->height);
Andy Wingo's avatar
Andy Wingo committed
524

Zeeshan Ali's avatar
Zeeshan Ali committed
525
      /* create delta and output frame */
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
526
527
      flxdec->frame_data = g_malloc (flxdec->size);
      flxdec->delta_data = g_malloc (flxdec->size);
528

Zeeshan Ali's avatar
Zeeshan Ali committed
529
      flxdec->state = GST_FLXDEC_PLAYING;
530
    }
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
531
  } else if (flxdec->state == GST_FLXDEC_PLAYING) {
532
    GstBuffer *out;
Andy Wingo's avatar
Andy Wingo committed
533

534
    /* while we have enough data in the adapter */
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
535
    while (avail >= FlxFrameChunkSize && res == GST_FLOW_OK) {
536
      FlxFrameChunk flxfh;
537
538
      guchar *chunk;
      const guint8 *data;
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
539
      GstMapInfo map;
540
541

      chunk = NULL;
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
542
      data = gst_adapter_map (flxdec->adapter, FlxFrameChunkSize);
543
      memcpy (&flxfh, data, FlxFrameChunkSize);
544
      FLX_FRAME_CHUNK_FIX_ENDIANNESS (&flxfh);
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
545
      gst_adapter_unmap (flxdec->adapter);
Zeeshan Ali's avatar
Zeeshan Ali committed
546

547
      switch (flxfh.id) {
Zeeshan Ali's avatar
Zeeshan Ali committed
548
        case FLX_FRAME_TYPE:
549
550
551
          /* check if we have the complete frame */
          if (avail < flxfh.size)
            goto need_more_data;
Zeeshan Ali's avatar
Zeeshan Ali committed
552

553
          /* flush header */
Zeeshan Ali's avatar
Zeeshan Ali committed
554
555
          gst_adapter_flush (flxdec->adapter, FlxFrameChunkSize);

556
557
          chunk = gst_adapter_take (flxdec->adapter,
              flxfh.size - FlxFrameChunkSize);
558
          FLX_FRAME_TYPE_FIX_ENDIANNESS ((FlxFrameType *) chunk);
Zeeshan Ali's avatar
Zeeshan Ali committed
559
560
561
562
          if (((FlxFrameType *) chunk)->chunks == 0)
            break;

          /* create 32 bits output frame */
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
563
564
565
566
567
568
569
//          res = gst_pad_alloc_buffer_and_set_caps (flxdec->srcpad,
//              GST_BUFFER_OFFSET_NONE,
//              flxdec->size * 4, GST_PAD_CAPS (flxdec->srcpad), &out);
//          if (res != GST_FLOW_OK)
//            break;

          out = gst_buffer_new_and_alloc (flxdec->size * 4);
Zeeshan Ali's avatar
Zeeshan Ali committed
570
571
572
573

          /* decode chunks */
          flx_decode_chunks (flxdec,
              ((FlxFrameType *) chunk)->chunks,
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
574
              chunk + FlxFrameTypeSize, flxdec->frame_data);
Zeeshan Ali's avatar
Zeeshan Ali committed
575
576

          /* save copy of the current frame for possible delta. */
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
577
          memcpy (flxdec->delta_data, flxdec->frame_data, flxdec->size);
Zeeshan Ali's avatar
Zeeshan Ali committed
578

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
579
          gst_buffer_map (out, &map, GST_MAP_WRITE);
Zeeshan Ali's avatar
Zeeshan Ali committed
580
          /* convert current frame. */
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
581
582
583
          flx_colorspace_convert (flxdec->converter, flxdec->frame_data,
              map.data);
          gst_buffer_unmap (out, &map);
Zeeshan Ali's avatar
Zeeshan Ali committed
584
585
586
587

          GST_BUFFER_TIMESTAMP (out) = flxdec->next_time;
          flxdec->next_time += flxdec->frame_time;

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
588
          res = gst_pad_push (flxdec->srcpad, out);
589
          break;
Zeeshan Ali's avatar
Zeeshan Ali committed
590
      }
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
591

Zeeshan Ali's avatar
Zeeshan Ali committed
592
593
      if (chunk)
        g_free (chunk);
594
595

      avail = gst_adapter_available (flxdec->adapter);
Andy Wingo's avatar
Andy Wingo committed
596
    }
597
  }
598
need_more_data:
Zeeshan Ali's avatar
Zeeshan Ali committed
599
  return res;
600
601
602
603
604
605

  /* ERRORS */
wrong_type:
  {
    GST_ELEMENT_ERROR (flxdec, STREAM, WRONG_TYPE, (NULL),
        ("not a flx file (type %x)", flxh->type));
606
    gst_object_unref (flxdec);
607
608
    return GST_FLOW_ERROR;
  }
609
610
}

611
612
static GstStateChangeReturn
gst_flxdec_change_state (GstElement * element, GstStateChange transition)
613
614
{
  GstFlxDec *flxdec;
615
  GstStateChangeReturn ret;
616

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
617
  flxdec = GST_FLXDEC (element);
Andy Wingo's avatar
Andy Wingo committed
618

619
620
  switch (transition) {
    case GST_STATE_CHANGE_NULL_TO_READY:
621
      break;
622
    case GST_STATE_CHANGE_READY_TO_PAUSED:
Zeeshan Ali's avatar
Zeeshan Ali committed
623
      gst_adapter_clear (flxdec->adapter);
624
625
      flxdec->state = GST_FLXDEC_READ_HEADER;
      break;
626
    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
627
      break;
628
629
630
631
    default:
      break;
  }

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
632
  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
633
634

  switch (transition) {
635
    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
636
      break;
637
    case GST_STATE_CHANGE_PAUSED_TO_READY:
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
638
639
640
641
642
643
644
      if (flxdec->frame_data) {
        g_free (flxdec->frame_data);
        flxdec->frame_data = NULL;
      }
      if (flxdec->delta_data) {
        g_free (flxdec->delta_data);
        flxdec->delta_data = NULL;
645
      }
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
646
647
648
      if (flxdec->converter) {
        flx_colorspace_converter_destroy (flxdec->converter);
        flxdec->converter = NULL;
649
      }
650
      break;
651
    case GST_STATE_CHANGE_READY_TO_NULL:
652
      break;
653
654
    default:
      break;
Andy Wingo's avatar
Andy Wingo committed
655
  }
656
  return ret;
Andy Wingo's avatar
Andy Wingo committed
657
658
659
}

static gboolean
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
660
plugin_init (GstPlugin * plugin)
Andy Wingo's avatar
Andy Wingo committed
661
{
Ronald S. Bultje's avatar
Ronald S. Bultje committed
662
  return gst_element_register (plugin, "flxdec",
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
663
      GST_RANK_PRIMARY, GST_TYPE_FLXDEC);
Andy Wingo's avatar
Andy Wingo committed
664
665
}

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
666
667
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
    GST_VERSION_MINOR,
668
    flxdec,
669
    "FLC/FLI/FLX video decoder",
670
    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)