gstjpegdec.c 35.4 KB
Newer Older
Christian Schaller's avatar
Christian Schaller committed
1
/* GStreamer
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
 *
 * 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.
 */


21
22
23
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
24
25
26
#include <string.h>

#include "gstjpegdec.h"
Iain Holmes's avatar
Iain Holmes committed
27
#include <gst/video/video.h>
28
29
#include "gst/gst-i18n-plugin.h"
#include <jerror.h>
30

31
static const GstElementDetails gst_jpeg_dec_details =
Wim Taymans's avatar
Wim Taymans committed
32
33
34
GST_ELEMENT_DETAILS ("JPEG image decoder",
    "Codec/Decoder/Image",
    "Decode images from JPEG format",
35
    "Wim Taymans <wim@fluendo.com>");
36

37
38
39
40
#define MIN_WIDTH  16
#define MAX_WIDTH  4096
#define MIN_HEIGHT 16
#define MAX_HEIGHT 4096
41

42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#define DEFAULT_IDCT_METHOD	JDCT_FASTEST

enum
{
  PROP_0,
  PROP_IDCT_METHOD
};

#define GST_TYPE_IDCT_METHOD (gst_idct_method_get_type())
static GType
gst_idct_method_get_type (void)
{
  static GType idct_method_type = 0;
  static const GEnumValue idct_method[] = {
    {JDCT_ISLOW, "Slow but accurate integer algorithm", "islow"},
    {JDCT_IFAST, "Faster, less accurate integer method", "ifast"},
    {JDCT_FLOAT, "Floating-point: accurate, fast on fast HW", "float"},
    {0, NULL, NULL},
  };

  if (!idct_method_type) {
    idct_method_type = g_enum_register_static ("GstIDCTMethod", idct_method);
  }
  return idct_method_type;
}

68
69
70
71
72
73
74
75
76
77
78
79
80
81
static GstStaticPadTemplate gst_jpeg_dec_src_pad_template =
GST_STATIC_PAD_TEMPLATE ("src",
    GST_PAD_SRC,
    GST_PAD_ALWAYS,
    GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("I420"))
    );

static GstStaticPadTemplate gst_jpeg_dec_sink_pad_template =
GST_STATIC_PAD_TEMPLATE ("sink",
    GST_PAD_SINK,
    GST_PAD_ALWAYS,
    GST_STATIC_CAPS ("image/jpeg, "
        "width = (int) [ " G_STRINGIFY (MIN_WIDTH) ", " G_STRINGIFY (MAX_WIDTH)
        " ], " "height = (int) [ " G_STRINGIFY (MIN_HEIGHT) ", "
82
        G_STRINGIFY (MAX_HEIGHT) " ], " "framerate = (fraction) [ 0/1, MAX ]")
83
84
    );

85
GST_DEBUG_CATEGORY_STATIC (jpeg_dec_debug);
86
#define GST_CAT_DEFAULT jpeg_dec_debug
87

Tim-Philipp Müller's avatar
Tim-Philipp Müller committed
88
89
/* These macros are adapted from videotestsrc.c 
 *  and/or gst-plugins/gst/games/gstvideoimage.c */
90
91
92
#define I420_Y_ROWSTRIDE(width) (GST_ROUND_UP_4(width))
#define I420_U_ROWSTRIDE(width) (GST_ROUND_UP_8(width)/2)
#define I420_V_ROWSTRIDE(width) ((GST_ROUND_UP_8(I420_Y_ROWSTRIDE(width)))/2)
Tim-Philipp Müller's avatar
Tim-Philipp Müller committed
93
94

#define I420_Y_OFFSET(w,h) (0)
95
96
#define I420_U_OFFSET(w,h) (I420_Y_OFFSET(w,h)+(I420_Y_ROWSTRIDE(w)*GST_ROUND_UP_2(h)))
#define I420_V_OFFSET(w,h) (I420_U_OFFSET(w,h)+(I420_U_ROWSTRIDE(w)*GST_ROUND_UP_2(h)/2))
Tim-Philipp Müller's avatar
Tim-Philipp Müller committed
97

98
#define I420_SIZE(w,h)     (I420_V_OFFSET(w,h)+(I420_V_ROWSTRIDE(w)*GST_ROUND_UP_2(h)/2))
Tim-Philipp Müller's avatar
Tim-Philipp Müller committed
99

100
static GstElementClass *parent_class;   /* NULL */
101

102
103
104
static void gst_jpeg_dec_base_init (gpointer g_class);
static void gst_jpeg_dec_class_init (GstJpegDecClass * klass);
static void gst_jpeg_dec_init (GstJpegDec * jpegdec);
105

106
107
108
109
110
static void gst_jpeg_dec_set_property (GObject * object, guint prop_id,
    const GValue * value, GParamSpec * pspec);
static void gst_jpeg_dec_get_property (GObject * object, guint prop_id,
    GValue * value, GParamSpec * pspec);

111
static GstFlowReturn gst_jpeg_dec_chain (GstPad * pad, GstBuffer * buffer);
112
static gboolean gst_jpeg_dec_setcaps (GstPad * pad, GstCaps * caps);
113
static gboolean gst_jpeg_dec_sink_event (GstPad * pad, GstEvent * event);
114
115
static GstStateChangeReturn gst_jpeg_dec_change_state (GstElement * element,
    GstStateChange transition);
116
117

GType
118
gst_jpeg_dec_get_type (void)
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
119
{
120
  static GType type = 0;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
121

122
123
124
125
  if (!type) {
    static const GTypeInfo jpeg_dec_info = {
      sizeof (GstJpegDecClass),
      (GBaseInitFunc) gst_jpeg_dec_base_init,
126
      NULL,
127
      (GClassInitFunc) gst_jpeg_dec_class_init,
128
129
      NULL,
      NULL,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
130
      sizeof (GstJpegDec),
131
      0,
132
      (GInstanceInitFunc) gst_jpeg_dec_init,
133
    };
134

135
136
    type = g_type_register_static (GST_TYPE_ELEMENT, "GstJpegDec",
        &jpeg_dec_info, 0);
137
  }
138
  return type;
139
140
}

141
142
143
144
static void
gst_jpeg_dec_finalize (GObject * object)
{
  GstJpegDec *dec = GST_JPEG_DEC (object);
145

146
147
148
149
150
  jpeg_destroy_decompress (&dec->cinfo);

  if (dec->tempbuf)
    gst_buffer_unref (dec->tempbuf);

151
152
153
  if (dec->segment)
    gst_segment_free (dec->segment);

154
155
  G_OBJECT_CLASS (parent_class)->finalize (object);
}
Iain Holmes's avatar
Iain Holmes committed
156
157

static void
158
gst_jpeg_dec_base_init (gpointer g_class)
Iain Holmes's avatar
Iain Holmes committed
159
160
{
  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
161

162
  gst_element_class_add_pad_template (element_class,
163
      gst_static_pad_template_get (&gst_jpeg_dec_src_pad_template));
164
  gst_element_class_add_pad_template (element_class,
165
166
      gst_static_pad_template_get (&gst_jpeg_dec_sink_pad_template));
  gst_element_class_set_details (element_class, &gst_jpeg_dec_details);
Iain Holmes's avatar
Iain Holmes committed
167
168
}

169
static void
170
gst_jpeg_dec_class_init (GstJpegDecClass * klass)
171
172
{
  GstElementClass *gstelement_class;
173
  GObjectClass *gobject_class;
174

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
175
  gstelement_class = (GstElementClass *) klass;
176
  gobject_class = (GObjectClass *) klass;
177

178
  parent_class = g_type_class_peek_parent (klass);
179

180
  gobject_class->finalize = gst_jpeg_dec_finalize;
181
182
183
184
185
186
187
  gobject_class->set_property = gst_jpeg_dec_set_property;
  gobject_class->get_property = gst_jpeg_dec_get_property;

  g_object_class_install_property (gobject_class, PROP_IDCT_METHOD,
      g_param_spec_enum ("idct-method", "IDCT Method",
          "The IDCT algorithm to use", GST_TYPE_IDCT_METHOD,
          DEFAULT_IDCT_METHOD, G_PARAM_READWRITE));
188
189
190

  gstelement_class->change_state =
      GST_DEBUG_FUNCPTR (gst_jpeg_dec_change_state);
191

192
  GST_DEBUG_CATEGORY_INIT (jpeg_dec_debug, "jpegdec", 0, "JPEG decoder");
193
}
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
194

195
static gboolean
196
gst_jpeg_dec_fill_input_buffer (j_decompress_ptr cinfo)
197
{
198
199
200
201
202
203
204
/*
  struct GstJpegDecSourceMgr *src_mgr;
  GstJpegDec *dec;

  src_mgr = (struct GstJpegDecSourceMgr*) &cinfo->src;
  dec = GST_JPEG_DEC (src_mgr->dec);
*/
205
  GST_DEBUG ("fill_input_buffer");
206
207
208
209
210
211
/*
  g_return_val_if_fail (dec != NULL, TRUE);

  src_mgr->pub.next_input_byte = GST_BUFFER_DATA (dec->tempbuf);
  src_mgr->pub.bytes_in_buffer = GST_BUFFER_SIZE (dec->tempbuf);
*/
212
213
214
215
  return TRUE;
}

static void
216
gst_jpeg_dec_init_source (j_decompress_ptr cinfo)
217
{
218
219
220
221
222
223
224
225
226
227
228
229
230
  GST_DEBUG ("init_source");
}


static void
gst_jpeg_dec_skip_input_data (j_decompress_ptr cinfo, glong num_bytes)
{
  GST_DEBUG ("skip_input_data: %ld bytes", num_bytes);

  if (num_bytes > 0 && cinfo->src->bytes_in_buffer >= num_bytes) {
    cinfo->src->next_input_byte += (size_t) num_bytes;
    cinfo->src->bytes_in_buffer -= (size_t) num_bytes;
  }
231
232
233
}

static gboolean
234
gst_jpeg_dec_resync_to_restart (j_decompress_ptr cinfo, gint desired)
235
{
236
  GST_DEBUG ("resync_to_start");
237
238
239
240
  return TRUE;
}

static void
241
gst_jpeg_dec_term_source (j_decompress_ptr cinfo)
242
{
243
  GST_DEBUG ("term_source");
244
  return;
245
246
}

247
METHODDEF (void)
248
    gst_jpeg_dec_my_output_message (j_common_ptr cinfo)
249
{
250
  return;                       /* do nothing */
251
252
253
}

METHODDEF (void)
254
    gst_jpeg_dec_my_emit_message (j_common_ptr cinfo, int msg_level)
255
{
256
257
258
259
260
261
262
263
264
265
266
  /* GST_DEBUG ("emit_message: msg_level = %d", msg_level); */
  return;
}

METHODDEF (void)
    gst_jpeg_dec_my_error_exit (j_common_ptr cinfo)
{
  struct GstJpegDecErrorMgr *err_mgr = (struct GstJpegDecErrorMgr *) cinfo->err;

  (*cinfo->err->output_message) (cinfo);
  longjmp (err_mgr->setjmp_buffer, 1);
267
268
}

269
static void
270
gst_jpeg_dec_init (GstJpegDec * dec)
271
{
272
  GST_DEBUG ("initializing");
273

274
275
  /* create the sink and src pads */
  dec->sinkpad =
276
277
      gst_pad_new_from_static_template (&gst_jpeg_dec_sink_pad_template,
      "sink");
278
  gst_element_add_pad (GST_ELEMENT (dec), dec->sinkpad);
279
280
  gst_pad_set_setcaps_function (dec->sinkpad,
      GST_DEBUG_FUNCPTR (gst_jpeg_dec_setcaps));
281
282
  gst_pad_set_chain_function (dec->sinkpad,
      GST_DEBUG_FUNCPTR (gst_jpeg_dec_chain));
283
284
  gst_pad_set_event_function (dec->sinkpad,
      GST_DEBUG_FUNCPTR (gst_jpeg_dec_sink_event));
285

286
  dec->srcpad =
287
      gst_pad_new_from_static_template (&gst_jpeg_dec_src_pad_template, "src");
288
  gst_pad_use_fixed_caps (dec->srcpad);
289
  gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad);
290

291
292
  dec->segment = gst_segment_new ();

293
  /* setup jpeglib */
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
  memset (&dec->cinfo, 0, sizeof (dec->cinfo));
  memset (&dec->jerr, 0, sizeof (dec->jerr));
  dec->cinfo.err = jpeg_std_error (&dec->jerr.pub);
  dec->jerr.pub.output_message = gst_jpeg_dec_my_output_message;
  dec->jerr.pub.emit_message = gst_jpeg_dec_my_emit_message;
  dec->jerr.pub.error_exit = gst_jpeg_dec_my_error_exit;

  jpeg_create_decompress (&dec->cinfo);

  dec->cinfo.src = (struct jpeg_source_mgr *) &dec->jsrc;
  dec->cinfo.src->init_source = gst_jpeg_dec_init_source;
  dec->cinfo.src->fill_input_buffer = gst_jpeg_dec_fill_input_buffer;
  dec->cinfo.src->skip_input_data = gst_jpeg_dec_skip_input_data;
  dec->cinfo.src->resync_to_restart = gst_jpeg_dec_resync_to_restart;
  dec->cinfo.src->term_source = gst_jpeg_dec_term_source;
  dec->jsrc.dec = dec;
310
311
312

  /* init properties */
  dec->idct_method = DEFAULT_IDCT_METHOD;
313
314
315
316
317
318
319
320
321
322
323
324
325
}

static inline gboolean
is_jpeg_start_marker (const guint8 * data)
{
  return (data[0] == 0xff && data[1] == 0xd8);
}

static inline gboolean
is_jpeg_end_marker (const guint8 * data)
{
  return (data[0] == 0xff && data[1] == 0xd9);
}
326

327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
static gboolean
gst_jpeg_dec_find_jpeg_header (GstJpegDec * dec)
{
  const guint8 *data;
  guint size;

  data = GST_BUFFER_DATA (dec->tempbuf);
  size = GST_BUFFER_SIZE (dec->tempbuf);

  g_return_val_if_fail (size >= 2, FALSE);

  while (!is_jpeg_start_marker (data) || data[2] != 0xff) {
    const guint8 *marker;
    GstBuffer *tmp;
    guint off;
342

343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
    marker = memchr (data + 1, 0xff, size - 1 - 2);
    if (marker == NULL) {
      off = size - 1;           /* keep last byte */
    } else {
      off = marker - data;
    }

    tmp = gst_buffer_create_sub (dec->tempbuf, off, size - off);
    gst_buffer_unref (dec->tempbuf);
    dec->tempbuf = tmp;

    data = GST_BUFFER_DATA (dec->tempbuf);
    size = GST_BUFFER_SIZE (dec->tempbuf);

    if (size < 2)
      return FALSE;             /* wait for more data */
  }
360

361
  return TRUE;                  /* got header */
362
363
}

364
365
static gboolean
gst_jpeg_dec_ensure_header (GstJpegDec * dec)
366
{
367
  g_return_val_if_fail (dec->tempbuf != NULL, FALSE);
368

369
check_header:
370

371
372
373
374
375
376
  /* we need at least a start marker (0xff 0xd8)
   *   and an end marker (0xff 0xd9) */
  if (GST_BUFFER_SIZE (dec->tempbuf) <= 4) {
    GST_DEBUG ("Not enough data");
    return FALSE;               /* we need more data */
  }
377

378
379
380
381
382
383
384
385
386
  if (!is_jpeg_start_marker (GST_BUFFER_DATA (dec->tempbuf))) {
    GST_DEBUG ("Not a JPEG header, resyncing to header...");
    if (!gst_jpeg_dec_find_jpeg_header (dec)) {
      GST_DEBUG ("No JPEG header in current buffer");
      return FALSE;             /* we need more data */
    }
    GST_DEBUG ("Found JPEG header");
    goto check_header;          /* buffer might have changed */
  }
387

388
389
  return TRUE;
}
390

391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
#if 0
static gboolean
gst_jpeg_dec_have_end_marker (GstJpegDec * dec)
{
  guint8 *data = GST_BUFFER_DATA (dec->tempbuf);
  guint size = GST_BUFFER_SIZE (dec->tempbuf);

  return (size > 2 && data && is_jpeg_end_marker (data + size - 2));
}
#endif

static inline gboolean
gst_jpeg_dec_parse_tag_has_entropy_segment (guint8 tag)
{
  if (tag == 0xda || (tag >= 0xd0 && tag <= 0xd7))
    return TRUE;
  return FALSE;
}

/* returns image length in bytes if parsed 
 * successfully, otherwise 0 */
static guint
gst_jpeg_dec_parse_image_data (GstJpegDec * dec)
{
  guint8 *start, *data, *end;
  guint size;

  size = GST_BUFFER_SIZE (dec->tempbuf);
  start = GST_BUFFER_DATA (dec->tempbuf);
  end = start + size;
  data = start;

  g_return_val_if_fail (is_jpeg_start_marker (data), 0);

  GST_DEBUG ("Parsing jpeg image data (%u bytes)", size);

  /* skip start marker */
  data += 2;

  while (1) {
    guint frame_len;

    /* enough bytes left for EOI marker? (we need 0xff 0xNN, thus end-1) */
    if (data >= end - 1) {
      GST_DEBUG ("at end of input and no EOI marker found, need more data");
      return 0;
    }

    if (is_jpeg_end_marker (data)) {
      GST_DEBUG ("0x%08x: end marker", data - start);
      goto found_eoi;
    }

    /* do we need to resync? */
    if (*data != 0xff) {
      GST_DEBUG ("Lost sync at 0x%08x, resyncing", data - start);
      /* at the very least we expect 0xff 0xNN, thus end-1 */
      while (*data != 0xff && data < end - 1)
        ++data;
      if (is_jpeg_end_marker (data)) {
        GST_DEBUG ("resynced to end marker");
        goto found_eoi;
      }
      /* we need 0xFF 0xNN 0xLL 0xLL */
      if (data >= end - 1 - 2) {
        GST_DEBUG ("at end of input, without new sync, need more data");
        return 0;
      }
      /* check if we will still be in sync if we interpret
       * this as a sync point and skip this frame */
      frame_len = GST_READ_UINT16_BE (data + 2);
      GST_DEBUG ("possible sync at 0x%08x, frame_len=%u", data - start,
          frame_len);
      if (data + 2 + frame_len >= end - 1 || data[2 + frame_len] != 0xff) {
        /* ignore and continue resyncing until we hit the end
         * of our data or find a sync point that looks okay */
        ++data;
        continue;
      }
      GST_DEBUG ("found sync at 0x%08x", data - size);
    }
    while (*data == 0xff)
      ++data;
    if (data + 2 >= end)
      return 0;
    if (*data >= 0xd0 && *data <= 0xd7)
      frame_len = 0;
    else
      frame_len = GST_READ_UINT16_BE (data + 1);
    GST_DEBUG ("0x%08x: tag %02x, frame_len=%u", data - start - 1, *data,
        frame_len);
    /* the frame length includes the 2 bytes for the length; here we want at
     * least 2 more bytes at the end for an end marker, thus end-2 */
    if (data + 1 + frame_len >= end - 2) {
      /* theoretically we could have lost sync and not really need more
       * data, but that's just tough luck and a broken image then */
      GST_DEBUG ("at end of input and no EOI marker found, need more data");
      return 0;
    }
    if (gst_jpeg_dec_parse_tag_has_entropy_segment (*data)) {
      guint8 *d2 = data + 1 + frame_len;
      guint eseglen = 0;

      GST_DEBUG ("0x%08x: finding entropy segment length", data - start - 1);
      while (1) {
        if (d2[eseglen] == 0xff && d2[eseglen + 1] != 0x00)
          break;
        if (d2 + eseglen >= end - 1)
          return 0;             /* need more data */
        ++eseglen;
      }
      frame_len += eseglen;
      GST_DEBUG ("entropy segment length=%u => frame_len=%u", eseglen,
          frame_len);
    }
    data += 1 + frame_len;
  }

found_eoi:
  /* data is assumed to point to the 0xff sync point of the
   *  EOI marker (so there is one more byte after that) */
  g_assert (is_jpeg_end_marker (data));
  return ((data + 1) - start + 1);
514
515
}

516
/* shamelessly ripped from jpegutils.c in mjpegtools */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
517
518
519
static void
add_huff_table (j_decompress_ptr dinfo,
    JHUFF_TBL ** htblptr, const UINT8 * bits, const UINT8 * val)
520
521
522
523
524
/* Define a Huffman table */
{
  int nsymbols, len;

  if (*htblptr == NULL)
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
525
    *htblptr = jpeg_alloc_huff_table ((j_common_ptr) dinfo);
526
527

  /* Copy the number-of-symbols-of-each-code-length counts */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
528
  memcpy ((*htblptr)->bits, bits, sizeof ((*htblptr)->bits));
529
530
531
532
533
534
535
536
537

  /* Validate the counts.  We do this here mainly so we can copy the right
   * number of symbols from the val[] array, without risking marching off
   * the end of memory.  jchuff.c will do a more thorough test later.
   */
  nsymbols = 0;
  for (len = 1; len <= 16; len++)
    nsymbols += bits[len];
  if (nsymbols < 1 || nsymbols > 256)
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
538
    g_error ("jpegutils.c:  add_huff_table failed badly. ");
539

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
540
  memcpy ((*htblptr)->huffval, val, nsymbols * sizeof (UINT8));
541
542
543
544
}



Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
545
546
static void
std_huff_tables (j_decompress_ptr dinfo)
547
548
549
550
/* Set up the standard Huffman tables (cf. JPEG standard section K.3) */
/* IMPORTANT: these are only valid for 8-bit data precision! */
{
  static const UINT8 bits_dc_luminance[17] =
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
551
      { /* 0-base */ 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 };
552
  static const UINT8 val_dc_luminance[] =
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
553
554
      { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };

555
  static const UINT8 bits_dc_chrominance[17] =
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
556
      { /* 0-base */ 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 };
557
  static const UINT8 val_dc_chrominance[] =
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
558
559
      { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };

560
  static const UINT8 bits_ac_luminance[17] =
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
561
      { /* 0-base */ 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d };
562
  static const UINT8 val_ac_luminance[] =
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
      { 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
    0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
    0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
    0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
    0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
    0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
    0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
    0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
    0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
    0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
    0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
    0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
    0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
    0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
    0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
    0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
    0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
    0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
    0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
    0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
    0xf9, 0xfa
  };

586
  static const UINT8 bits_ac_chrominance[17] =
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
587
      { /* 0-base */ 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77 };
588
  static const UINT8 val_ac_chrominance[] =
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
      { 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
    0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
    0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
    0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
    0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
    0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
    0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
    0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
    0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
    0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
    0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
    0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
    0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
    0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
    0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
    0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
    0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
    0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
    0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
    0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
    0xf9, 0xfa
  };

  add_huff_table (dinfo, &dinfo->dc_huff_tbl_ptrs[0],
      bits_dc_luminance, val_dc_luminance);
  add_huff_table (dinfo, &dinfo->ac_huff_tbl_ptrs[0],
      bits_ac_luminance, val_ac_luminance);
  add_huff_table (dinfo, &dinfo->dc_huff_tbl_ptrs[1],
      bits_dc_chrominance, val_dc_chrominance);
  add_huff_table (dinfo, &dinfo->ac_huff_tbl_ptrs[1],
      bits_ac_chrominance, val_ac_chrominance);
620
621
622
623
}



Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
624
625
static void
guarantee_huff_tables (j_decompress_ptr dinfo)
626
{
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
627
628
629
630
631
632
  if ((dinfo->dc_huff_tbl_ptrs[0] == NULL) &&
      (dinfo->dc_huff_tbl_ptrs[1] == NULL) &&
      (dinfo->ac_huff_tbl_ptrs[0] == NULL) &&
      (dinfo->ac_huff_tbl_ptrs[1] == NULL)) {
    GST_DEBUG ("Generating standard Huffman tables for this frame.");
    std_huff_tables (dinfo);
633
634
635
  }
}

636
637
638
639
640
static gboolean
gst_jpeg_dec_setcaps (GstPad * pad, GstCaps * caps)
{
  GstStructure *s;
  GstJpegDec *dec;
641
  const GValue *framerate;
642
643
644
645

  dec = GST_JPEG_DEC (GST_OBJECT_PARENT (pad));
  s = gst_caps_get_structure (caps, 0);

646
647
648
  if ((framerate = gst_structure_get_value (s, "framerate")) != NULL) {
    dec->framerate_numerator = gst_value_get_fraction_numerator (framerate);
    dec->framerate_denominator = gst_value_get_fraction_denominator (framerate);
649
    dec->packetized = TRUE;
650
651
    GST_DEBUG ("got framerate of %d/%d fps => packetized mode",
        dec->framerate_numerator, dec->framerate_denominator);
652
653
  }

654
655
656
  /* do not extract width/height here. we do that in the chain
   * function on a per-frame basis (including the line[] array
   * setup) */
657
658
659

  /* But we can take the framerate values and set them on the src pad */

660
661
662
  return TRUE;
}

663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
/* yuk */
static void
hresamplecpy1 (guint8 * dest, const guint8 * src, guint len)
{
  gint i;

  for (i = 0; i < len; ++i) {
    /* equivalent to: dest[i] = src[i << 1] */
    *dest = *src;
    ++dest;
    ++src;
    ++src;
  }
}

678
679
static void
gst_jpeg_dec_decode_indirect (GstJpegDec * dec, guchar * base[3],
680
    guchar * last[3], guint width, guint height, gint r_v, gint r_h)
681
682
{
  guchar y[16][MAX_WIDTH];
683
684
  guchar u[16][MAX_WIDTH];
  guchar v[16][MAX_WIDTH];
685
686
687
  guchar *y_rows[16] = { y[0], y[1], y[2], y[3], y[4], y[5], y[6], y[7],
    y[8], y[9], y[10], y[11], y[12], y[13], y[14], y[15]
  };
688
689
690
691
692
693
  guchar *u_rows[16] = { u[0], u[1], u[2], u[3], u[4], u[5], u[6], u[7],
    u[8], u[9], u[10], u[11], u[12], u[13], u[14], u[15]
  };
  guchar *v_rows[16] = { v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7],
    v[8], v[9], v[10], v[11], v[12], v[13], v[14], v[15]
  };
694
695
696
697
  guchar **scanarray[3] = { y_rows, u_rows, v_rows };
  gint i, j, k;

  GST_DEBUG_OBJECT (dec,
698
      "unadvantageous width or r_h, taking slow route involving memcpy");
699
700
701
702
703
704
705
706
707
708
709
710

  for (i = 0; i < height; i += r_v * DCTSIZE) {
    jpeg_read_raw_data (&dec->cinfo, scanarray, r_v * DCTSIZE);
    for (j = 0, k = 0; j < (r_v * DCTSIZE); j += r_v, k++) {
      memcpy (base[0], y_rows[j], I420_Y_ROWSTRIDE (width));
      if (base[0] < last[0])
        base[0] += I420_Y_ROWSTRIDE (width);
      if (r_v == 2) {
        memcpy (base[0], y_rows[j + 1], I420_Y_ROWSTRIDE (width));
        if (base[0] < last[0])
          base[0] += I420_Y_ROWSTRIDE (width);
      }
711
712
713
714
715
716
717
718
719
720
      if (G_LIKELY (r_h == 2)) {
        memcpy (base[1], u_rows[k], I420_U_ROWSTRIDE (width));
        memcpy (base[2], v_rows[k], I420_V_ROWSTRIDE (width));
      } else if (G_UNLIKELY (r_h == 1)) {
        hresamplecpy1 (base[1], u_rows[k], I420_U_ROWSTRIDE (width));
        hresamplecpy1 (base[2], v_rows[k], I420_V_ROWSTRIDE (width));
      } else {
        /* FIXME: implement (at least we avoid crashing by doing nothing) */
      }

721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
      if (r_v == 2 || (k & 1) != 0) {
        if (base[1] < last[1] && base[2] < last[2]) {
          base[1] += I420_U_ROWSTRIDE (width);
          base[2] += I420_V_ROWSTRIDE (width);
        }
      }
    }
  }
}

static void
gst_jpeg_dec_decode_direct (GstJpegDec * dec, guchar * base[3],
    guchar * last[3], guint width, guint height, gint r_v)
{
  guchar **line[3];             /* the jpeg line buffer */
736
737
738
  guchar *y[4 * DCTSIZE];       /* alloc enough for the lines */
  guchar *u[4 * DCTSIZE];
  guchar *v[4 * DCTSIZE];
739
740
  gint i, j, k;

741
742
743
  line[0] = y;
  line[1] = u;
  line[2] = v;
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769

  /* let jpeglib decode directly into our final buffer */
  GST_DEBUG_OBJECT (dec, "decoding directly into output buffer");
  for (i = 0; i < height; i += r_v * DCTSIZE) {
    for (j = 0, k = 0; j < (r_v * DCTSIZE); j += r_v, k++) {
      line[0][j] = base[0];
      if (base[0] < last[0])
        base[0] += I420_Y_ROWSTRIDE (width);
      if (r_v == 2) {
        line[0][j + 1] = base[0];
        if (base[0] < last[0])
          base[0] += I420_Y_ROWSTRIDE (width);
      }
      line[1][k] = base[1];
      line[2][k] = base[2];
      if (r_v == 2 || (k & 1) != 0) {
        if (base[1] < last[1] && base[2] < last[2]) {
          base[1] += I420_U_ROWSTRIDE (width);
          base[2] += I420_V_ROWSTRIDE (width);
        }
      }
    }
    jpeg_read_raw_data (&dec->cinfo, line, r_v * DCTSIZE);
  }
}

770
771
static GstFlowReturn
gst_jpeg_dec_chain (GstPad * pad, GstBuffer * buf)
772
{
773
774
  GstFlowReturn ret;
  GstJpegDec *dec;
775
  GstBuffer *outbuf;
776
  gulong size;
777
  guchar *data, *outdata;
778
  guchar *base[3], *last[3];
779
  guint img_len, outsize;
780
  gint width, height;
781
  gint r_h, r_v;
782
  gint i;
783
784
  guint code;
  GstClockTime timestamp, duration;
785

786
  dec = GST_JPEG_DEC (gst_pad_get_parent (pad));
787

788
  timestamp = GST_BUFFER_TIMESTAMP (buf);
789
790
  duration = GST_BUFFER_DURATION (buf);

791
  if (GST_CLOCK_TIME_IS_VALID (timestamp))
792
    dec->next_ts = timestamp;
793
794
795
796
797
798
799
800
801

  if (dec->tempbuf) {
    dec->tempbuf = gst_buffer_join (dec->tempbuf, buf);
  } else {
    dec->tempbuf = buf;
  }
  buf = NULL;

  if (!gst_jpeg_dec_ensure_header (dec))
802
    goto need_more_data;
803

804
805
806
807
808
809
810
811
812
813
  /* If we know that each input buffer contains data
   * for a whole jpeg image (e.g. MJPEG streams), just 
   * do some sanity checking instead of parsing all of 
   * the jpeg data */
  if (dec->packetized) {
    img_len = GST_BUFFER_SIZE (dec->tempbuf);
  } else {
    /* Parse jpeg image to handle jpeg input that
     * is not aligned to buffer boundaries */
    img_len = gst_jpeg_dec_parse_image_data (dec);
814

815
    if (img_len == 0)
816
      goto need_more_data;
817
  }
818

819
820
821
822
823
824
825
826
  data = (guchar *) GST_BUFFER_DATA (dec->tempbuf);
  size = img_len;
  GST_LOG_OBJECT (dec, "image size = %u", img_len);

  dec->jsrc.pub.next_input_byte = data;
  dec->jsrc.pub.bytes_in_buffer = size;

  if (setjmp (dec->jerr.setjmp_buffer)) {
827
    code = dec->jerr.pub.msg_code;
828
829

    if (code == JERR_INPUT_EOF) {
830
      GST_DEBUG ("jpeg input EOF error, we probably need more data");
831
      goto need_more_data;
832
    }
833
    goto decode_error;
834
835
  }

836
837
  GST_LOG_OBJECT (dec, "reading header %02x %02x %02x %02x", data[0], data[1],
      data[2], data[3]);
838
839

  /* read header */
840
841
842
843
844
  jpeg_read_header (&dec->cinfo, TRUE);

  r_h = dec->cinfo.cur_comp_info[0]->h_samp_factor;
  r_v = dec->cinfo.cur_comp_info[0]->v_samp_factor;

845
  GST_DEBUG ("r_h = %d, r_v = %d", r_h, r_v);
846
  GST_DEBUG ("num_components=%d, comps_in_scan=%d",
847
      dec->cinfo.num_components, dec->cinfo.comps_in_scan);
848

849
  for (i = 0; i < dec->cinfo.comps_in_scan; ++i) {
850
    GST_DEBUG ("[%d] h_samp_factor=%d, v_samp_factor=%d", i,
851
852
        dec->cinfo.cur_comp_info[i]->h_samp_factor,
        dec->cinfo.cur_comp_info[i]->v_samp_factor);
853
854
  }

855
  /* prepare for raw output */
856
857
858
  dec->cinfo.do_fancy_upsampling = FALSE;
  dec->cinfo.do_block_smoothing = FALSE;
  dec->cinfo.out_color_space = JCS_YCbCr;
859
  dec->cinfo.dct_method = dec->idct_method;
860
  dec->cinfo.raw_data_out = TRUE;
861

862
863
864
  GST_LOG_OBJECT (dec, "starting decompress");
  guarantee_huff_tables (&dec->cinfo);
  jpeg_start_decompress (&dec->cinfo);
865

866
867
868
869
  width = dec->cinfo.output_width;
  height = dec->cinfo.output_height;

  if (width < MIN_WIDTH || width > MAX_WIDTH ||
870
871
872
873
      height < MIN_HEIGHT || height > MAX_HEIGHT)
    goto wrong_size;

  if (width != dec->caps_width || height != dec->caps_height ||
874
875
      dec->framerate_numerator != dec->caps_framerate_numerator ||
      dec->framerate_denominator != dec->caps_framerate_denominator) {
876
    GstCaps *caps;
877

878
879
880
881
882
883
    /* framerate == 0/1 is a still frame */
    if (dec->framerate_denominator == 0) {
      dec->framerate_numerator = 0;
      dec->framerate_denominator = 1;
    }

884
885
886
887
    caps = gst_caps_new_simple ("video/x-raw-yuv",
        "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('I', '4', '2', '0'),
        "width", G_TYPE_INT, width,
        "height", G_TYPE_INT, height,
888
889
        "framerate", GST_TYPE_FRACTION, dec->framerate_numerator,
        dec->framerate_denominator, NULL);
890

891
892
893
    GST_DEBUG_OBJECT (dec, "setting caps %" GST_PTR_FORMAT, caps);
    GST_DEBUG_OBJECT (dec, "max_v_samp_factor=%d",
        dec->cinfo.max_v_samp_factor);
894

895
    gst_pad_set_caps (dec->srcpad, caps);
896
    gst_caps_unref (caps);
897
898
899

    dec->caps_width = width;
    dec->caps_height = height;
900
901
    dec->caps_framerate_numerator = dec->framerate_numerator;
    dec->caps_framerate_denominator = dec->framerate_denominator;
902
    dec->outsize = I420_SIZE (width, height);
903
904
  }

905
  ret = gst_pad_alloc_buffer_and_set_caps (dec->srcpad, GST_BUFFER_OFFSET_NONE,
906
      dec->outsize, GST_PAD_CAPS (dec->srcpad), &outbuf);
907
908
  if (ret != GST_FLOW_OK)
    goto alloc_failed;
909

910
  outdata = GST_BUFFER_DATA (outbuf);
911
912
913
914
915
  outsize = GST_BUFFER_SIZE (outbuf);

  GST_LOG_OBJECT (dec, "width %d, height %d, buffer size %d, required size %d",
      width, height, outsize, dec->outsize);

916
  GST_BUFFER_TIMESTAMP (outbuf) = dec->next_ts;
917

918
919
920
921
922
923
924
925
926
927
928
929
  if (dec->packetized && GST_CLOCK_TIME_IS_VALID (dec->next_ts)) {
    if (GST_CLOCK_TIME_IS_VALID (duration)) {
      /* use duration from incoming buffer for outgoing buffer */
      dec->next_ts += duration;
    } else if (dec->framerate_numerator != 0) {
      duration = gst_util_uint64_scale (GST_SECOND,
          dec->framerate_denominator, dec->framerate_numerator);
      dec->next_ts += duration;
    } else {
      duration = GST_CLOCK_TIME_NONE;
      dec->next_ts = GST_CLOCK_TIME_NONE;
    }
930
931
932
933
934
935
  } else {
    duration = GST_CLOCK_TIME_NONE;
    dec->next_ts = GST_CLOCK_TIME_NONE;
  }
  GST_BUFFER_DURATION (outbuf) = duration;

936
  /* mind the swap, jpeglib outputs blue chroma first */
Tim-Philipp Müller's avatar
Tim-Philipp Müller committed
937
938
939
  base[0] = outdata + I420_Y_OFFSET (width, height);
  base[1] = outdata + I420_U_OFFSET (width, height);
  base[2] = outdata + I420_V_OFFSET (width, height);
940

941
942
  /* make sure we don't make jpeglib write beyond our buffer,
   * which might happen if (height % (r_v*DCTSIZE)) != 0 */
943
944
945
946
947
948
949
  last[0] = base[0] + (I420_Y_ROWSTRIDE (width) * (height - 1));
  last[1] =
      base[1] + (I420_U_ROWSTRIDE (width) * ((GST_ROUND_UP_2 (height) / 2) -
          1));
  last[2] =
      base[2] + (I420_V_ROWSTRIDE (width) * ((GST_ROUND_UP_2 (height) / 2) -
          1));
950

951
  GST_LOG_OBJECT (dec, "decompressing %u", dec->cinfo.rec_outbuf_height);
952
953
954
955
956
957
958
  GST_LOG_OBJECT (dec, "max_h_samp_factor=%u", dec->cinfo.max_h_samp_factor);

  /* For some widths jpeglib requires more horizontal padding than I420 
   * provides. In those cases we need to decode into separate buffers and then
   * copy over the data into our final picture buffer, otherwise jpeglib might
   * write over the end of a line into the beginning of the next line,
   * resulting in blocky artifacts on the left side of the picture. */
959
960
  if (r_h != 2 || width % (dec->cinfo.max_h_samp_factor * DCTSIZE) != 0) {
    gst_jpeg_dec_decode_indirect (dec, base, last, width, height, r_v, r_h);
961
962
  } else {
    gst_jpeg_dec_decode_direct (dec, base, last, width, height, r_v);
963
964
  }

965
966
967
  GST_LOG_OBJECT (dec, "decompressing finished");
  jpeg_finish_decompress (&dec->cinfo);

968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
  /* Clipping */
  if (dec->segment->format == GST_FORMAT_TIME) {
    gint64 start, stop, clip_start, clip_stop;

    GST_LOG_OBJECT (dec, "Attempting clipping");

    start = GST_BUFFER_TIMESTAMP (outbuf);
    if (GST_BUFFER_DURATION (outbuf) == GST_CLOCK_TIME_NONE)
      stop = start;
    else
      stop = start + GST_BUFFER_DURATION (outbuf);

    if (gst_segment_clip (dec->segment, GST_FORMAT_TIME,
            start, stop, &clip_start, &clip_stop)) {
      GST_LOG_OBJECT (dec, "Clipping start to %" GST_TIME_FORMAT,
          GST_TIME_ARGS (clip_start));
      GST_BUFFER_TIMESTAMP (outbuf) = clip_start;
      if (GST_BUFFER_DURATION (outbuf) != GST_CLOCK_TIME_NONE) {
        GST_LOG_OBJECT (dec, "Clipping duration to %" GST_TIME_FORMAT,
            GST_TIME_ARGS (clip_stop - clip_start));
        GST_BUFFER_DURATION (outbuf) = clip_stop - clip_start;
      }
    } else {
991
      GST_WARNING_OBJECT (dec, "Outgoing buffer is outside configured segment");
992
993
994
    }
  }

995
996
997
998
  GST_LOG_OBJECT (dec, "pushing buffer (ts=%" GST_TIME_FORMAT ", dur=%"
      GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
      GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)));

999
  ret = gst_pad_push (dec->srcpad, outbuf);
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011

done:
  if (GST_BUFFER_SIZE (dec->tempbuf) == img_len) {
    gst_buffer_unref (dec->tempbuf);
    dec->tempbuf = NULL;
  } else {
    GstBuffer *buf = gst_buffer_create_sub (dec->tempbuf, img_len,
        GST_BUFFER_SIZE (dec->tempbuf) - img_len);

    gst_buffer_unref (dec->tempbuf);
    dec->tempbuf = buf;
  }
1012
1013
1014
1015

exit:
  gst_object_unref (dec);

1016
  return ret;
1017
1018
1019
1020
1021

  /* special cases */
need_more_data:
  {
    GST_LOG_OBJECT (dec, "we need more data");
1022
1023
    ret = GST_FLOW_OK;
    goto exit;
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
  }
  /* ERRORS */
wrong_size:
  {
    GST_ELEMENT_ERROR (dec, STREAM, DECODE,
        ("Picture is too small or too big (%ux%u)", width, height),
        ("Picture is too small or too big (%ux%u)", width, height));
    ret = GST_FLOW_ERROR;
    goto done;
  }
decode_error:
  {
    GST_ELEMENT_ERROR (dec, STREAM, DECODE,
        (_("Failed to decode JPEG image")),
        ("Error #%u: %s", code, dec->jerr.pub.jpeg_message_table[code]));
    ret = GST_FLOW_ERROR;
    goto done;
  }
alloc_failed:
  {
    const gchar *reason;

    reason = gst_flow_get_name (ret);

    GST_DEBUG_OBJECT (dec, "failed to alloc buffer, reason %s", reason);
1049
1050
    /* Reset for next time */
    jpeg_abort_decompress (&dec->cinfo);
1051
1052
1053
1054
1055
    if (GST_FLOW_IS_FATAL (ret)) {
      GST_ELEMENT_ERROR (dec, STREAM, DECODE,
          ("Buffer allocation failed, reason: %s", reason),
          ("Buffer allocation failed, reason: %s", reason));
    }
1056
    goto exit;
1057
  }
1058
1059
}

1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
static gboolean
gst_jpeg_dec_sink_event (GstPad * pad, GstEvent * event)
{
  gboolean ret = TRUE;
  GstJpegDec *dec = GST_JPEG_DEC (GST_OBJECT_PARENT (pad));

  GST_DEBUG_OBJECT (dec, "event : %s", GST_EVENT_TYPE_NAME (event));

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_FLUSH_STOP:
      GST_DEBUG_OBJECT (dec, "Aborting decompress");
      jpeg_abort_decompress (&dec->cinfo);
      break;
1073
1074
1075
1076
1077
1078
1079
1080
1081
    case GST_EVENT_NEWSEGMENT:{
      gboolean update;
      gdouble rate;
      GstFormat format;
      gint64 start, stop, position;

      /* Once -good depends on core >= 0.10.6, use newsegment_full */
      gst_event_parse_new_segment (event, &update, &rate, &format,
          &start, &stop, &position);
1082

1083
1084
1085
1086
      GST_DEBUG_OBJECT (dec, "Got NEWSEGMENT [%" GST_TIME_FORMAT
          " - %" GST_TIME_FORMAT " / %" GST_TIME_FORMAT "]",
          GST_TIME_ARGS (start), GST_TIME_ARGS (stop),
          GST_TIME_ARGS (position));
1087

1088
1089
      gst_segment_set_newsegment (dec->segment, update, rate, format,
          start, stop, position);
1090

1091
      break;
1092
    }
1093
1094
1095
1096
1097
1098
1099
1100
1101
    default:
      break;
  }

  ret = gst_pad_push_event (dec->srcpad, event);

  return ret;
}

1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
static void
gst_jpeg_dec_set_property (GObject * object, guint prop_id,
    const GValue * value, GParamSpec * pspec)
{
  GstJpegDec *dec;

  dec = GST_JPEG_DEC (object);

  switch (prop_id) {
    case PROP_IDCT_METHOD:
      dec->idct_method = g_value_get_enum (value);
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}

static void
gst_jpeg_dec_get_property (GObject * object, guint prop_id, GValue * value,
    GParamSpec * pspec)
{
  GstJpegDec *dec;

  dec = GST_JPEG_DEC (object);

  switch (prop_id) {
    case PROP_IDCT_METHOD:
      g_value_set_enum (value, dec->idct_method);
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}

1140
1141
static GstStateChangeReturn
gst_jpeg_dec_change_state (GstElement * element, GstStateChange transition)
1142
{
1143
  GstStateChangeReturn ret;
1144
1145
1146
  GstJpegDec *dec;

  dec = GST_JPEG_DEC (element);
1147

1148
  switch (transition) {
1149
    case GST_STATE_CHANGE_READY_TO_PAUSED:
1150
1151
1152
      dec->framerate_numerator = 0;
      dec->framerate_denominator = 1;
      dec->caps_framerate_numerator = dec->caps_framerate_denominator = 0;
1153
1154
      dec->caps_width = -1;
      dec->caps_height = -1;
1155
      dec->packetized = FALSE;
1156
      dec->next_ts = 0;
1157
      gst_segment_init (dec->segment, GST_FORMAT_UNDEFINED);
1158
    default:
1159
      break;
1160
1161
  }

1162
  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1163
1164
  if (ret != GST_STATE_CHANGE_SUCCESS)
    return ret;
1165

1166
1167
  switch (transition) {
    case GST_STATE_CHANGE_PAUSED_TO_READY:
1168
1169
1170
1171
1172
1173
1174
1175
      if (dec->tempbuf) {
        gst_buffer_unref (dec->tempbuf);
        dec->tempbuf = NULL;
      }
      break;
    default:
      break;
  }
1176

1177
  return ret;
1178
}