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

Stefan Kost's avatar
Stefan Kost committed
21
22
23
/**
 * SECTION:element-jpegdec
 *
24
 * Decodes jpeg images.
25
26
27
28
29
30
31
32
 *
 * <refsect2>
 * <title>Example launch line</title>
 * |[
 * gst-launch -v v4l2src ! jpegddec ! ffmpegcolorspace ! xvimagesink
 * ]| The above pipeline reads a motion JPEG stream from a v4l2 camera
 * and renders it to the screen.
 * </refsect2>
Stefan Kost's avatar
Stefan Kost committed
33
 */
34

35
36
37
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
38
39
40
#include <string.h>

#include "gstjpegdec.h"
Iain Holmes's avatar
Iain Holmes committed
41
#include <gst/video/video.h>
42
43
#include "gst/gst-i18n-plugin.h"
#include <jerror.h>
44

45
static const GstElementDetails gst_jpeg_dec_details =
Wim Taymans's avatar
Wim Taymans committed
46
47
48
GST_ELEMENT_DETAILS ("JPEG image decoder",
    "Codec/Decoder/Image",
    "Decode images from JPEG format",
49
    "Wim Taymans <wim@fluendo.com>");
50

51
#define MIN_WIDTH  16
52
#define MAX_WIDTH  65535
53
#define MIN_HEIGHT 8
54
#define MAX_HEIGHT 65535
55

56
#define JPEG_DEFAULT_IDCT_METHOD	JDCT_FASTEST
57
58
59
60
61
62
63

enum
{
  PROP_0,
  PROP_IDCT_METHOD
};

Stefan Kost's avatar
Stefan Kost committed
64
extern GType gst_idct_method_get_type (void);
65
66
#define GST_TYPE_IDCT_METHOD (gst_idct_method_get_type())

67
68
69
70
71
72
73
74
75
76
77
78
79
80
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) ", "
81
        G_STRINGIFY (MAX_HEIGHT) " ], " "framerate = (fraction) [ 0/1, MAX ]")
82
83
    );

84
GST_DEBUG_CATEGORY_STATIC (jpeg_dec_debug);
85
#define GST_CAT_DEFAULT jpeg_dec_debug
86
GST_DEBUG_CATEGORY_STATIC (GST_CAT_PERFORMANCE);
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
static gboolean gst_jpeg_dec_src_event (GstPad * pad, GstEvent * event);
115
116
static GstStateChangeReturn gst_jpeg_dec_change_state (GstElement * element,
    GstStateChange transition);
117
static void gst_jpeg_dec_update_qos (GstJpegDec * dec, gdouble proportion,
118
    GstClockTimeDiff diff, GstClockTime ts);
119
120
121
static void gst_jpeg_dec_reset_qos (GstJpegDec * dec);
static void gst_jpeg_dec_read_qos (GstJpegDec * dec, gdouble * proportion,
    GstClockTime * time);
122
123

GType
124
gst_jpeg_dec_get_type (void)
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
125
{
126
  static GType type = 0;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
127

128
129
130
131
  if (!type) {
    static const GTypeInfo jpeg_dec_info = {
      sizeof (GstJpegDecClass),
      (GBaseInitFunc) gst_jpeg_dec_base_init,
132
      NULL,
133
      (GClassInitFunc) gst_jpeg_dec_class_init,
134
135
      NULL,
      NULL,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
136
      sizeof (GstJpegDec),
137
      0,
138
      (GInstanceInitFunc) gst_jpeg_dec_init,
139
    };
140

141
142
    type = g_type_register_static (GST_TYPE_ELEMENT, "GstJpegDec",
        &jpeg_dec_info, 0);
143
  }
144
  return type;
145
146
}

147
148
149
150
static void
gst_jpeg_dec_finalize (GObject * object)
{
  GstJpegDec *dec = GST_JPEG_DEC (object);
151

152
153
154
155
156
157
158
  jpeg_destroy_decompress (&dec->cinfo);

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

  G_OBJECT_CLASS (parent_class)->finalize (object);
}
Iain Holmes's avatar
Iain Holmes committed
159
160

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

165
  gst_element_class_add_pad_template (element_class,
166
      gst_static_pad_template_get (&gst_jpeg_dec_src_pad_template));
167
  gst_element_class_add_pad_template (element_class,
168
169
      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
170
171
}

172
static void
173
gst_jpeg_dec_class_init (GstJpegDecClass * klass)
174
175
{
  GstElementClass *gstelement_class;
176
  GObjectClass *gobject_class;
177

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
178
  gstelement_class = (GstElementClass *) klass;
179
  gobject_class = (GObjectClass *) klass;
180

181
  parent_class = g_type_class_peek_parent (klass);
182

183
  gobject_class->finalize = gst_jpeg_dec_finalize;
184
185
186
187
188
189
  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,
190
          JPEG_DEFAULT_IDCT_METHOD, G_PARAM_READWRITE));
191
192
193

  gstelement_class->change_state =
      GST_DEBUG_FUNCPTR (gst_jpeg_dec_change_state);
194

195
  GST_DEBUG_CATEGORY_INIT (jpeg_dec_debug, "jpegdec", 0, "JPEG decoder");
196
  GST_DEBUG_CATEGORY_GET (GST_CAT_PERFORMANCE, "GST_PERFORMANCE");
197
}
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
198

199
static boolean
200
gst_jpeg_dec_fill_input_buffer (j_decompress_ptr cinfo)
201
{
202
203
204
205
206
207
208
/*
  struct GstJpegDecSourceMgr *src_mgr;
  GstJpegDec *dec;

  src_mgr = (struct GstJpegDecSourceMgr*) &cinfo->src;
  dec = GST_JPEG_DEC (src_mgr->dec);
*/
209
  GST_DEBUG_OBJECT (CINFO_GET_JPEGDEC (cinfo), "fill_input_buffer");
210
211
212
213
214
215
/*
  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);
*/
216
217
218
219
  return TRUE;
}

static void
220
gst_jpeg_dec_init_source (j_decompress_ptr cinfo)
221
{
222
  GST_LOG_OBJECT (CINFO_GET_JPEGDEC (cinfo), "init_source");
223
224
225
226
227
228
}


static void
gst_jpeg_dec_skip_input_data (j_decompress_ptr cinfo, glong num_bytes)
{
229
  GST_DEBUG_OBJECT (CINFO_GET_JPEGDEC (cinfo), "skip %ld bytes", num_bytes);
230
231
232
233
234

  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;
  }
235
236
}

237
static boolean
238
gst_jpeg_dec_resync_to_restart (j_decompress_ptr cinfo, gint desired)
239
{
240
  GST_LOG_OBJECT (CINFO_GET_JPEGDEC (cinfo), "resync_to_start");
241
242
243
244
  return TRUE;
}

static void
245
gst_jpeg_dec_term_source (j_decompress_ptr cinfo)
246
{
247
  GST_LOG_OBJECT (CINFO_GET_JPEGDEC (cinfo), "term_source");
248
  return;
249
250
}

251
METHODDEF (void)
252
    gst_jpeg_dec_my_output_message (j_common_ptr cinfo)
253
{
254
  return;                       /* do nothing */
255
256
257
}

METHODDEF (void)
258
    gst_jpeg_dec_my_emit_message (j_common_ptr cinfo, int msg_level)
259
{
260
  /* GST_LOG_OBJECT (CINFO_GET_JPEGDEC (&cinfo), "msg_level=%d", msg_level); */
261
262
263
264
265
266
267
268
269
270
  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);
271
272
}

273
static void
274
gst_jpeg_dec_init (GstJpegDec * dec)
275
{
276
  GST_DEBUG ("initializing");
277

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

290
  dec->srcpad =
291
      gst_pad_new_from_static_template (&gst_jpeg_dec_src_pad_template, "src");
292
293
  gst_pad_set_event_function (dec->srcpad,
      GST_DEBUG_FUNCPTR (gst_jpeg_dec_src_event));
294
  gst_pad_use_fixed_caps (dec->srcpad);
295
  gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad);
296
297

  /* setup jpeglib */
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
  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;
314
315

  /* init properties */
316
  dec->idct_method = JPEG_DEFAULT_IDCT_METHOD;
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
}

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

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;
340

341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
    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 */
  }
358

359
  return TRUE;                  /* got header */
360
361
}

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

367
check_header:
368

369
370
371
372
373
374
  /* 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 */
  }
375

376
377
378
379
380
381
382
383
384
  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 */
  }
385

386
387
  return TRUE;
}
388

389
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
#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;
430
    gboolean resync;
431
432

    /* do we need to resync? */
433
434
    resync = (*data != 0xff);
    if (resync) {
435
436
      GST_DEBUG ("Lost sync at 0x%08" G_GINT64_MODIFIER "x, resyncing",
          (gint64) (data - start));
437
438
439
      /* at the very least we expect 0xff 0xNN, thus end-1 */
      while (*data != 0xff && data < end - 1)
        ++data;
440
441
442
443
      if (G_UNLIKELY (*data != 0xff)) {
        GST_DEBUG ("at end of input and no next marker found, need more data");
        return 0;
      }
444
    }
445
    /* Skip over extra 0xff */
446
    while (*data == 0xff && data < end)
447
      ++data;
448
    /* enough bytes left for marker? (we need 0xNN after the 0xff) */
449
450
451
452
453
    if (data >= end) {
      GST_DEBUG ("at end of input and no EOI marker found, need more data");
      return 0;
    }

454
    if (*data == 0xd9) {
455
456
      GST_DEBUG ("0x%08" G_GINT64_MODIFIER "x: EOI marker",
          (gint64) (data - start));
457
      return (data - start + 1);
458
459
    }

460
461
    if (*data >= 0xd0 && *data <= 0xd7)
      frame_len = 0;
462
463
    else if (data >= end - 2)
      return 0;
464
465
    else
      frame_len = GST_READ_UINT16_BE (data + 1);
466
467
    GST_DEBUG ("0x%08" G_GINT64_MODIFIER "x: tag %02x, frame_len=%u",
        (gint64) (data - start - 1), *data, frame_len);
468
469
470
    /* 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) {
471
472
473
474
475
      if (resync) {
        GST_DEBUG ("not a valid sync (not enough data).");
        /* Since *data != 0xff, the next iteration will go into resync again. */
        continue;
      }
476
477
478
479
480
      /* 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;
    }
481

482
483
484
485
    if (gst_jpeg_dec_parse_tag_has_entropy_segment (*data)) {
      guint8 *d2 = data + 1 + frame_len;
      guint eseglen = 0;

486
487
      GST_DEBUG ("0x%08" G_GINT64_MODIFIER "x: finding entropy segment length",
          (gint64) (data - start - 1));
488
489
490
      while (1) {
        if (d2 + eseglen >= end - 1)
          return 0;             /* need more data */
491
492
        if (d2[eseglen] == 0xff && d2[eseglen + 1] != 0x00)
          break;
493
494
495
496
497
498
        ++eseglen;
      }
      frame_len += eseglen;
      GST_DEBUG ("entropy segment length=%u => frame_len=%u", eseglen,
          frame_len);
    }
499
500
501
502
503
504
505
506
507
508
509
    if (resync) {
      /* check if we will still be in sync if we interpret
       * this as a sync point and skip this frame */
      if (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 */
        continue;
      }
      GST_DEBUG ("found sync at %p", data - size);
    }

510
511
    data += 1 + frame_len;
  }
512
513
}

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

  if (*htblptr == NULL)
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
523
    *htblptr = jpeg_alloc_huff_table ((j_common_ptr) dinfo);
524

525
526
  g_assert (*htblptr);

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
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
static void
gst_jpeg_dec_free_buffers (GstJpegDec * dec)
{
  gint i;

  for (i = 0; i < 16; i++) {
    g_free (dec->idr_y[i]);
    g_free (dec->idr_u[i]);
    g_free (dec->idr_v[i]);
    dec->idr_y[i] = NULL;
    dec->idr_u[i] = NULL;
    dec->idr_v[i] = NULL;
  }

  dec->idr_width_allocated = 0;
}

695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
static inline gboolean
gst_jpeg_dec_ensure_buffers (GstJpegDec * dec, guint maxrowbytes)
{
  gint i;

  if (G_LIKELY (dec->idr_width_allocated == maxrowbytes))
    return TRUE;

  /* FIXME: maybe just alloc one or three blocks altogether? */
  for (i = 0; i < 16; i++) {
    dec->idr_y[i] = g_try_realloc (dec->idr_y[i], maxrowbytes);
    dec->idr_u[i] = g_try_realloc (dec->idr_u[i], maxrowbytes);
    dec->idr_v[i] = g_try_realloc (dec->idr_v[i], maxrowbytes);

    if (G_UNLIKELY (!dec->idr_y[i] || !dec->idr_u[i] || !dec->idr_v[i])) {
      GST_WARNING_OBJECT (dec, "out of memory, i=%d, bytes=%u", i, maxrowbytes);
      return FALSE;
    }
  }

  dec->idr_width_allocated = maxrowbytes;
  GST_LOG_OBJECT (dec, "allocated temp memory, %u bytes/row", maxrowbytes);
  return TRUE;
}

720
721
static void
gst_jpeg_dec_decode_indirect (GstJpegDec * dec, guchar * base[3],
722
    guchar * last[3], guint width, guint height, gint r_v, gint r_h)
723
{
724
  guchar *y_rows[16], *u_rows[16], *v_rows[16];
725
726
  guchar **scanarray[3] = { y_rows, u_rows, v_rows };
  gint i, j, k;
727
  gint lines;
728
729

  GST_DEBUG_OBJECT (dec,
730
      "unadvantageous width or r_h, taking slow route involving memcpy");
731

732
733
  if (G_UNLIKELY (!gst_jpeg_dec_ensure_buffers (dec, GST_ROUND_UP_32 (width))))
    return;
734
735
736
737
738

  memcpy (y_rows, dec->idr_y, 16 * sizeof (gpointer));
  memcpy (u_rows, dec->idr_u, 16 * sizeof (gpointer));
  memcpy (v_rows, dec->idr_v, 16 * sizeof (gpointer));

739
  for (i = 0; i < height; i += r_v * DCTSIZE) {
740
    lines = jpeg_read_raw_data (&dec->cinfo, scanarray, r_v * DCTSIZE);
741
    if (G_LIKELY (lines > 0)) {
742
743
      for (j = 0, k = 0; j < (r_v * DCTSIZE); j += r_v, k++) {
        memcpy (base[0], y_rows[j], I420_Y_ROWSTRIDE (width));
744
        if (G_LIKELY (base[0] < last[0]))
745
          base[0] += I420_Y_ROWSTRIDE (width);
746
        if (r_v == 2) {
747
          memcpy (base[0], y_rows[j + 1], I420_Y_ROWSTRIDE (width));
748
          if (G_LIKELY (base[0] < last[0]))
749
750
            base[0] += I420_Y_ROWSTRIDE (width);
        }
751
        if (r_h == 2) {
752
753
          memcpy (base[1], u_rows[k], I420_U_ROWSTRIDE (width));
          memcpy (base[2], v_rows[k], I420_V_ROWSTRIDE (width));
754
        } else if (r_h == 1) {
755
756
757
758
759
          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) */
        }
760

761
        if (r_v == 2 || (k & 1) != 0) {
762
          if (G_LIKELY (base[1] < last[1] && base[2] < last[2])) {
763
764
765
            base[1] += I420_U_ROWSTRIDE (width);
            base[2] += I420_V_ROWSTRIDE (width);
          }
766
767
        }
      }
768
769
    } else {
      GST_INFO_OBJECT (dec, "jpeg_read_raw_data() returned 0");
770
771
772
773
    }
  }
}

774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
#ifndef GST_DISABLE_GST_DEBUG
static inline void
dump_lines (guchar * base[3], guchar ** line[3], int v_samp0, int width)
{
  int j;

  for (j = 0; j < (v_samp0 * DCTSIZE); ++j) {
    GST_LOG ("[%02d]  %5d  %5d  %5d", j,
        (line[0][j] >= base[0]) ?
        (int) (line[0][j] - base[0]) / I420_Y_ROWSTRIDE (width) : -1,
        (line[1][j] >= base[1]) ?
        (int) (line[1][j] - base[1]) / I420_U_ROWSTRIDE (width) : -1,
        (line[2][j] >= base[2]) ?
        (int) (line[2][j] - base[2]) / I420_V_ROWSTRIDE (width) : -1);
  }
}
#endif

792
static GstFlowReturn
793
gst_jpeg_dec_decode_direct (GstJpegDec * dec, guchar * base[3],
794
    guchar * last[3], guint width, guint height)
795
{
796
797
798
799
  guchar **line[3];             /* the jpeg line buffer         */
  guchar *y[4 * DCTSIZE] = { NULL, };   /* alloc enough for the lines   */
  guchar *u[4 * DCTSIZE] = { NULL, };   /* r_v will be <4               */
  guchar *v[4 * DCTSIZE] = { NULL, };
800
  gint i, j;
801
  gint lines, v_samp[3];
802

803
804
805
  line[0] = y;
  line[1] = u;
  line[2] = v;
806

807
808
809
  v_samp[0] = dec->cinfo.comp_info[0].v_samp_factor;
  v_samp[1] = dec->cinfo.comp_info[1].v_samp_factor;
  v_samp[2] = dec->cinfo.comp_info[2].v_samp_factor;
810

811
  if (G_UNLIKELY (v_samp[0] > 2 || v_samp[1] > 2 || v_samp[2] > 2))
812
813
    goto format_not_supported;

814
815
  /* let jpeglib decode directly into our final buffer */
  GST_DEBUG_OBJECT (dec, "decoding directly into output buffer");
816
817

  for (i = 0; i < height; i += v_samp[0] * DCTSIZE) {
818
819
820
821
822
823
824
825
826
827
    for (j = 0; j < (v_samp[0] * DCTSIZE); ++j) {
      /* Y */
      line[0][j] = base[0] + (i + j) * I420_Y_ROWSTRIDE (width);
      if (G_UNLIKELY (line[0][j] > last[0]))
        line[0][j] = last[0];
      /* U */
      if (v_samp[1] == v_samp[0]) {
        line[1][j] = base[1] + ((i + j) / 2) * I420_U_ROWSTRIDE (width);
      } else if (j < (v_samp[1] * DCTSIZE)) {
        line[1][j] = base[1] + ((i / 2) + j) * I420_U_ROWSTRIDE (width);
828
      }
829
830
831
832
833
834
835
      if (G_UNLIKELY (line[1][j] > last[1]))
        line[1][j] = last[1];
      /* V */
      if (v_samp[2] == v_samp[0]) {
        line[2][j] = base[2] + ((i + j) / 2) * I420_V_ROWSTRIDE (width);
      } else if (j < (v_samp[2] * DCTSIZE)) {
        line[2][j] = base[2] + ((i / 2) + j) * I420_V_ROWSTRIDE (width);
836
      }
837
838
      if (G_UNLIKELY (line[2][j] > last[2]))
        line[2][j] = last[2];
839
840
    }

841
842
    /* dump_lines (base, line, v_samp[0], width); */

843
    lines = jpeg_read_raw_data (&dec->cinfo, line, v_samp[0] * DCTSIZE);
844
845
846
    if (G_UNLIKELY (!lines)) {
      GST_INFO_OBJECT (dec, "jpeg_read_raw_data() returned 0");
    }
847
  }
848
849
850
851
852
853
854
855
856
857
  return GST_FLOW_OK;

format_not_supported:
  {
    GST_ELEMENT_ERROR (dec, STREAM, DECODE,
        (_("Failed to decode JPEG image")),
        ("Unsupported subsampling schema: v_samp factors: %u %u %u",
            v_samp[0], v_samp[1], v_samp[2]));
    return GST_FLOW_ERROR;
  }
858
859
}

860
861
static void
gst_jpeg_dec_update_qos (GstJpegDec * dec, gdouble proportion,
862
    GstClockTimeDiff diff, GstClockTime ts)
863
864
865
{
  GST_OBJECT_LOCK (dec);
  dec->proportion = proportion;
866
867
868
869
870
871
872
873
  if (G_LIKELY (ts != GST_CLOCK_TIME_NONE)) {
    if (G_UNLIKELY (diff > 0))
      dec->earliest_time = ts + 2 * diff + dec->qos_duration;
    else
      dec->earliest_time = ts + diff;
  } else {
    dec->earliest_time = GST_CLOCK_TIME_NONE;
  }
874
875
876
877
878
879
  GST_OBJECT_UNLOCK (dec);
}

static void
gst_jpeg_dec_reset_qos (GstJpegDec * dec)
{
880
  gst_jpeg_dec_update_qos (dec, 0.5, 0, GST_CLOCK_TIME_NONE);
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
}

static void
gst_jpeg_dec_read_qos (GstJpegDec * dec, gdouble * proportion,
    GstClockTime * time)
{
  GST_OBJECT_LOCK (dec);
  *proportion = dec->proportion;
  *time = dec->earliest_time;
  GST_OBJECT_UNLOCK (dec);
}

/* Perform qos calculations before decoding the next frame. Returns TRUE if the
 * frame should be decoded, FALSE if the frame can be dropped entirely */
static gboolean
gst_jpeg_dec_do_qos (GstJpegDec * dec, GstClockTime timestamp)
{
  GstClockTime qostime, earliest_time;
  gdouble proportion;

  /* no timestamp, can't do QoS => decode frame */
  if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp))) {
    GST_LOG_OBJECT (dec, "invalid timestamp, can't do QoS, decode frame");
    return TRUE;
  }

  /* get latest QoS observation values */
  gst_jpeg_dec_read_qos (dec, &proportion, &earliest_time);

  /* skip qos if we have no observation (yet) => decode frame */
  if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (earliest_time))) {
    GST_LOG_OBJECT (dec, "no observation yet, decode frame");
    return TRUE;
  }

  /* qos is done on running time */
  qostime = gst_segment_to_running_time (&dec->segment, GST_FORMAT_TIME,
      timestamp);

  /* see how our next timestamp relates to the latest qos timestamp */
  GST_LOG_OBJECT (dec, "qostime %" GST_TIME_FORMAT ", earliest %"
      GST_TIME_FORMAT, GST_TIME_ARGS (qostime), GST_TIME_ARGS (earliest_time));

  if (qostime != GST_CLOCK_TIME_NONE && qostime <= earliest_time) {
    GST_DEBUG_OBJECT (dec, "we are late, drop frame");
    return FALSE;
  }

  GST_LOG_OBJECT (dec, "decode frame");
  return TRUE;
}

933
934
static GstFlowReturn
gst_jpeg_dec_chain (GstPad * pad, GstBuffer * buf)
935
{
936
  GstFlowReturn ret = GST_FLOW_OK;
937
  GstJpegDec *dec;
938
  GstBuffer *outbuf = NULL;
939
  guchar *data, *outdata;
940
  guchar *base[3], *last[3];
941
  guint img_len, outsize;
942
  gint width, height;
943
  gint r_h, r_v;
944
  guint code, hdr_ok;
945
  GstClockTime timestamp, duration;
946

947
  dec = GST_JPEG_DEC (GST_PAD_PARENT (pad));
948

949
  timestamp = GST_BUFFER_TIMESTAMP (buf);
950
951
  duration = GST_BUFFER_DURATION (buf);

952
  if (GST_CLOCK_TIME_IS_VALID (timestamp))
953
    dec->next_ts = timestamp;
954

955
956
957
  if (GST_BUFFER_IS_DISCONT (buf)) {
    GST_DEBUG_OBJECT (dec, "buffer has DISCONT flag set");
    dec->discont = TRUE;
958
    if (!dec->packetized && dec->tempbuf != NULL) {
959
960
961
962
963
      GST_WARNING_OBJECT (dec, "DISCONT buffer in non-packetized mode, bad");
      gst_buffer_replace (&dec->tempbuf, NULL);
    }
  }

964
965
966
967
968
969
970
  if (dec->tempbuf) {
    dec->tempbuf = gst_buffer_join (dec->tempbuf, buf);
  } else {
    dec->tempbuf = buf;
  }
  buf = NULL;

971
972
973
974
975
976
977
  /* If we are non-packetized and know the total incoming size in bytes,
   * just wait until we have enough before doing any processing. */

  if (!dec->packetized && (dec->segment.format == GST_FORMAT_BYTES) &&
      (dec->segment.stop != -1) &&
      (GST_BUFFER_SIZE (dec->tempbuf) < dec->segment.stop)) {
    /* We assume that non-packetized input in bytes is *one* single jpeg image */
978
    GST_DEBUG ("Non-packetized mode. Got %d bytes, need %" G_GINT64_FORMAT,
979
980
981
982
        GST_BUFFER_SIZE (dec->tempbuf), dec->segment.stop);
    goto need_more_data;
  }

983
  if (!gst_jpeg_dec_ensure_header (dec))
984
    goto need_more_data;
985

986
987
988
989
990
991
992
993
994
995
  /* 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);
996

997
    if (img_len == 0)
998
      goto need_more_data;
999
  }
1000

1001
1002
1003
1004
  /* QoS: if we're too late anyway, skip decoding */
  if (dec->packetized && !gst_jpeg_dec_do_qos (dec, timestamp))
    goto skip_decoding;

1005
1006
1007
1008
  data = (guchar *) GST_BUFFER_DATA (dec->tempbuf);
  GST_LOG_OBJECT (dec, "image size = %u", img_len);

  dec->jsrc.pub.next_input_byte = data;
1009
  dec->jsrc.pub.bytes_in_buffer = img_len;
1010
1011

  if (setjmp (dec->jerr.setjmp_buffer)) {
1012
    code = dec->jerr.pub.msg_code;
1013
1014

    if (code == JERR_INPUT_EOF) {
1015
      GST_DEBUG ("jpeg input EOF error, we probably need more data");
1016
      goto need_more_data;
1017
    }
1018
    goto decode_error;
1019
1020
  }

1021
1022
  GST_LOG_OBJECT (dec, "reading header %02x %02x %02x %02x", data[0], data[1],
      data[2], data[3]);
1023
1024

  /* read header */
1025
1026
1027
1028
  hdr_ok = jpeg_read_header (&dec->cinfo, TRUE);
  if (G_UNLIKELY (hdr_ok != JPEG_HEADER_OK)) {
    GST_WARNING_OBJECT (dec, "reading the header failed, %d", hdr_ok);
  }
1029

1030
1031
  r_h = dec->cinfo.comp_info[0].h_samp_factor;
  r_v = dec->cinfo.comp_info[0].v_samp_factor;
1032

1033
  GST_LOG_OBJECT (dec, "r_h = %d, r_v = %d", r_h, r_v);
1034
1035
  GST_LOG_OBJECT (dec, "num_components=%d", dec->cinfo.num_components);
  GST_LOG_OBJECT (dec, "jpeg_color_space=%d", dec->cinfo.jpeg_color_space);
1036

1037
#ifndef GST_DISABLE_GST_DEBUG
1038
1039
1040
  {
    gint i;

1041
1042
1043
1044
1045
    for (i = 0; i < dec->cinfo.num_components; ++i) {
      GST_LOG_OBJECT (dec, "[%d] h_samp_factor=%d, v_samp_factor=%d, cid=%d",
          i, dec->cinfo.comp_info[i].h_samp_factor,
          dec->cinfo.comp_info[i].v_samp_factor,
          dec->cinfo.comp_info[i].component_id);
1046
    }
1047
  }
1048
#endif
1049

1050
  /* prepare for raw output */
1051
1052
1053