webrtc/nice: Support domain name as connection-address of ICE candidate
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-good / ext / jpeg / gstjpegdec.c
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  * Copyright (C) <2009> Tim-Philipp Müller <tim centricular net>
4  * Copyright (C) 2012 Collabora Ltd.
5  *      Author : Edward Hervey <edward@collabora.com>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22
23 /**
24  * SECTION:element-jpegdec
25  * @title: jpegdec
26  *
27  * Decodes jpeg images.
28  *
29  * ## Example launch line
30  * |[
31  * gst-launch-1.0 -v filesrc location=mjpeg.avi ! avidemux !  queue ! jpegdec ! videoconvert ! videoscale ! autovideosink
32  * ]| The above pipeline decode the mjpeg stream and renders it to the screen.
33  *
34  */
35
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
39 #include <string.h>
40
41 #include "gstjpeg.h"
42 #include "gstjpegdec.h"
43 #include "gstjpegelements.h"
44 #include <gst/video/video.h>
45 #include <gst/video/gstvideometa.h>
46 #include <gst/video/gstvideopool.h>
47 #include <glib/gi18n-lib.h>
48 #include <jerror.h>
49
50 /* Disable libjpeg-turbo support for now, due to unresolved cornercases */
51 #undef JCS_EXTENSIONS
52
53 #define MIN_WIDTH  1
54 #define MAX_WIDTH  65535
55 #define MIN_HEIGHT 1
56 #define MAX_HEIGHT 65535
57
58 #define CINFO_GET_JPEGDEC(cinfo_ptr) \
59         (((struct GstJpegDecSourceMgr*)((cinfo_ptr)->src))->dec)
60
61 #define JPEG_DEFAULT_IDCT_METHOD        JDCT_FASTEST
62 #define JPEG_DEFAULT_MAX_ERRORS         0
63
64 enum
65 {
66   PROP_0,
67   PROP_IDCT_METHOD,
68   PROP_MAX_ERRORS
69 };
70
71 /* *INDENT-OFF* */
72 static GstStaticPadTemplate gst_jpeg_dec_src_pad_template =
73 GST_STATIC_PAD_TEMPLATE ("src",
74     GST_PAD_SRC,
75     GST_PAD_ALWAYS,
76     GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE
77         ("{ I420, RGB, BGR, RGBx, xRGB, BGRx, xBGR, GRAY8 }"))
78     );
79 /* *INDENT-ON* */
80
81 /* FIXME: sof-marker is for IJG libjpeg 8, should be different for 6.2 */
82 /* FIXME: add back "sof-marker = (int) { 0, 1, 2, 5, 6, 7, 9, 10, 13, 14 }"
83  * once we have a parser and/or demuxer set caps properly */
84 static GstStaticPadTemplate gst_jpeg_dec_sink_pad_template =
85 GST_STATIC_PAD_TEMPLATE ("sink",
86     GST_PAD_SINK,
87     GST_PAD_ALWAYS,
88     GST_STATIC_CAPS ("image/jpeg")
89     );
90
91 GST_DEBUG_CATEGORY_STATIC (jpeg_dec_debug);
92 #define GST_CAT_DEFAULT jpeg_dec_debug
93 GST_DEBUG_CATEGORY_STATIC (GST_CAT_PERFORMANCE);
94
95 static void gst_jpeg_dec_set_property (GObject * object, guint prop_id,
96     const GValue * value, GParamSpec * pspec);
97 static void gst_jpeg_dec_get_property (GObject * object, guint prop_id,
98     GValue * value, GParamSpec * pspec);
99
100 static gboolean gst_jpeg_dec_set_format (GstVideoDecoder * dec,
101     GstVideoCodecState * state);
102 static gboolean gst_jpeg_dec_start (GstVideoDecoder * bdec);
103 static gboolean gst_jpeg_dec_stop (GstVideoDecoder * bdec);
104 static gboolean gst_jpeg_dec_flush (GstVideoDecoder * bdec);
105 static GstFlowReturn gst_jpeg_dec_parse (GstVideoDecoder * bdec,
106     GstVideoCodecFrame * frame, GstAdapter * adapter, gboolean at_eos);
107 static GstFlowReturn gst_jpeg_dec_handle_frame (GstVideoDecoder * bdec,
108     GstVideoCodecFrame * frame);
109 static gboolean gst_jpeg_dec_decide_allocation (GstVideoDecoder * bdec,
110     GstQuery * query);
111 static gboolean gst_jpeg_dec_sink_event (GstVideoDecoder * bdec,
112     GstEvent * event);
113
114 #define gst_jpeg_dec_parent_class parent_class
115 G_DEFINE_TYPE (GstJpegDec, gst_jpeg_dec, GST_TYPE_VIDEO_DECODER);
116 GST_ELEMENT_REGISTER_DEFINE (jpegdec, "jpegdec", GST_RANK_PRIMARY,
117     GST_TYPE_JPEG_DEC);
118
119 static void
120 gst_jpeg_dec_finalize (GObject * object)
121 {
122   GstJpegDec *dec = GST_JPEG_DEC (object);
123
124   jpeg_destroy_decompress (&dec->cinfo);
125   if (dec->input_state)
126     gst_video_codec_state_unref (dec->input_state);
127
128   G_OBJECT_CLASS (parent_class)->finalize (object);
129 }
130
131 static void
132 gst_jpeg_dec_class_init (GstJpegDecClass * klass)
133 {
134   GObjectClass *gobject_class;
135   GstElementClass *element_class;
136   GstVideoDecoderClass *vdec_class;
137
138   gobject_class = (GObjectClass *) klass;
139   element_class = (GstElementClass *) klass;
140   vdec_class = (GstVideoDecoderClass *) klass;
141
142   parent_class = g_type_class_peek_parent (klass);
143
144   gobject_class->finalize = gst_jpeg_dec_finalize;
145   gobject_class->set_property = gst_jpeg_dec_set_property;
146   gobject_class->get_property = gst_jpeg_dec_get_property;
147
148   g_object_class_install_property (gobject_class, PROP_IDCT_METHOD,
149       g_param_spec_enum ("idct-method", "IDCT Method",
150           "The IDCT algorithm to use", GST_TYPE_IDCT_METHOD,
151           JPEG_DEFAULT_IDCT_METHOD,
152           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
153
154   /**
155    * GstJpegDec:max-errors:
156    *
157    * Error out after receiving N consecutive decoding errors
158    * (-1 = never error out, 0 = automatic, 1 = fail on first error, etc.)
159    *
160    * Deprecated: 1.3.1: Property wasn't used internally
161    */
162 #ifndef GST_REMOVE_DEPRECATED
163   g_object_class_install_property (gobject_class, PROP_MAX_ERRORS,
164       g_param_spec_int ("max-errors", "Maximum Consecutive Decoding Errors",
165           "(Deprecated) Error out after receiving N consecutive decoding errors"
166           " (-1 = never fail, 0 = automatic, 1 = fail on first error)",
167           -1, G_MAXINT, JPEG_DEFAULT_MAX_ERRORS,
168           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_DEPRECATED));
169 #endif
170
171   gst_element_class_add_static_pad_template (element_class,
172       &gst_jpeg_dec_src_pad_template);
173   gst_element_class_add_static_pad_template (element_class,
174       &gst_jpeg_dec_sink_pad_template);
175   gst_element_class_set_static_metadata (element_class, "JPEG image decoder",
176       "Codec/Decoder/Image", "Decode images from JPEG format",
177       "Wim Taymans <wim@fluendo.com>");
178
179   vdec_class->start = gst_jpeg_dec_start;
180   vdec_class->stop = gst_jpeg_dec_stop;
181   vdec_class->flush = gst_jpeg_dec_flush;
182   vdec_class->parse = gst_jpeg_dec_parse;
183   vdec_class->set_format = gst_jpeg_dec_set_format;
184   vdec_class->handle_frame = gst_jpeg_dec_handle_frame;
185   vdec_class->decide_allocation = gst_jpeg_dec_decide_allocation;
186   vdec_class->sink_event = gst_jpeg_dec_sink_event;
187
188   GST_DEBUG_CATEGORY_INIT (jpeg_dec_debug, "jpegdec", 0, "JPEG decoder");
189   GST_DEBUG_CATEGORY_GET (GST_CAT_PERFORMANCE, "GST_PERFORMANCE");
190
191   gst_type_mark_as_plugin_api (GST_TYPE_IDCT_METHOD, 0);
192 }
193
194 static boolean
195 gst_jpeg_dec_fill_input_buffer (j_decompress_ptr cinfo)
196 {
197   /* We pass in full frame initially, if this get called, the frame is most likely
198    * corrupted */
199   return FALSE;
200 }
201
202 static void
203 gst_jpeg_dec_init_source (j_decompress_ptr cinfo)
204 {
205   GST_LOG_OBJECT (CINFO_GET_JPEGDEC (cinfo), "init_source");
206 }
207
208
209 static void
210 gst_jpeg_dec_skip_input_data (j_decompress_ptr cinfo, glong num_bytes)
211 {
212   GstJpegDec *dec = CINFO_GET_JPEGDEC (cinfo);
213
214   GST_DEBUG_OBJECT (dec, "skip %ld bytes", num_bytes);
215
216   if (num_bytes > 0 && cinfo->src->bytes_in_buffer >= num_bytes) {
217     cinfo->src->next_input_byte += (size_t) num_bytes;
218     cinfo->src->bytes_in_buffer -= (size_t) num_bytes;
219   }
220 }
221
222 static boolean
223 gst_jpeg_dec_resync_to_restart (j_decompress_ptr cinfo, gint desired)
224 {
225   GST_LOG_OBJECT (CINFO_GET_JPEGDEC (cinfo), "resync_to_start");
226   return TRUE;
227 }
228
229 static void
230 gst_jpeg_dec_term_source (j_decompress_ptr cinfo)
231 {
232   GST_LOG_OBJECT (CINFO_GET_JPEGDEC (cinfo), "term_source");
233   return;
234 }
235
236 METHODDEF (void)
237     gst_jpeg_dec_my_output_message (j_common_ptr cinfo)
238 {
239   return;                       /* do nothing */
240 }
241
242 METHODDEF (void)
243     gst_jpeg_dec_my_emit_message (j_common_ptr cinfo, int msg_level)
244 {
245   /* GST_LOG_OBJECT (CINFO_GET_JPEGDEC (&cinfo), "msg_level=%d", msg_level); */
246   return;
247 }
248
249 METHODDEF (void)
250     gst_jpeg_dec_my_error_exit (j_common_ptr cinfo)
251 {
252   struct GstJpegDecErrorMgr *err_mgr = (struct GstJpegDecErrorMgr *) cinfo->err;
253
254   (*cinfo->err->output_message) (cinfo);
255   longjmp (err_mgr->setjmp_buffer, 1);
256 }
257
258 static void
259 gst_jpeg_dec_init (GstJpegDec * dec)
260 {
261   GST_DEBUG ("initializing");
262
263   /* setup jpeglib */
264   memset (&dec->cinfo, 0, sizeof (dec->cinfo));
265   memset (&dec->jerr, 0, sizeof (dec->jerr));
266   dec->cinfo.err = jpeg_std_error (&dec->jerr.pub);
267   dec->jerr.pub.output_message = gst_jpeg_dec_my_output_message;
268   dec->jerr.pub.emit_message = gst_jpeg_dec_my_emit_message;
269   dec->jerr.pub.error_exit = gst_jpeg_dec_my_error_exit;
270
271   jpeg_create_decompress (&dec->cinfo);
272
273   dec->cinfo.src = (struct jpeg_source_mgr *) &dec->jsrc;
274   dec->cinfo.src->init_source = gst_jpeg_dec_init_source;
275   dec->cinfo.src->fill_input_buffer = gst_jpeg_dec_fill_input_buffer;
276   dec->cinfo.src->skip_input_data = gst_jpeg_dec_skip_input_data;
277   dec->cinfo.src->resync_to_restart = gst_jpeg_dec_resync_to_restart;
278   dec->cinfo.src->term_source = gst_jpeg_dec_term_source;
279   dec->jsrc.dec = dec;
280
281   /* init properties */
282   dec->idct_method = JPEG_DEFAULT_IDCT_METHOD;
283   dec->max_errors = JPEG_DEFAULT_MAX_ERRORS;
284
285   gst_video_decoder_set_use_default_pad_acceptcaps (GST_VIDEO_DECODER_CAST
286       (dec), TRUE);
287   GST_PAD_SET_ACCEPT_TEMPLATE (GST_VIDEO_DECODER_SINK_PAD (dec));
288 }
289
290 static inline gboolean
291 gst_jpeg_dec_parse_tag_has_entropy_segment (guint8 tag)
292 {
293   if (tag == 0xda || (tag >= 0xd0 && tag <= 0xd7))
294     return TRUE;
295   return FALSE;
296 }
297
298 static GstFlowReturn
299 gst_jpeg_dec_parse (GstVideoDecoder * bdec, GstVideoCodecFrame * frame,
300     GstAdapter * adapter, gboolean at_eos)
301 {
302   guint size;
303   gint toadd = 0;
304   gboolean resync;
305   gint offset = 0, noffset;
306   GstJpegDec *dec = (GstJpegDec *) bdec;
307
308   GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
309
310   /* FIXME : The overhead of using scan_uint32 is massive */
311
312   size = gst_adapter_available (adapter);
313   GST_DEBUG ("Parsing jpeg image data (%u bytes)", size);
314
315   if (at_eos) {
316     GST_DEBUG ("Flushing all data out");
317     toadd = size;
318
319     /* If we have leftover data, throw it away */
320     if (!dec->saw_header)
321       goto drop_frame;
322     goto have_full_frame;
323   }
324
325   if (size < 8)
326     goto need_more_data;
327
328   if (!dec->saw_header) {
329     gint ret;
330     /* we expect at least 4 bytes, first of which start marker */
331     ret =
332         gst_adapter_masked_scan_uint32 (adapter, 0xffff0000, 0xffd80000, 0,
333         size - 4);
334
335     GST_DEBUG ("ret:%d", ret);
336     if (ret < 0)
337       goto need_more_data;
338
339     if (ret) {
340       gst_adapter_flush (adapter, ret);
341       size -= ret;
342     }
343     dec->saw_header = TRUE;
344   }
345
346   while (1) {
347     guint frame_len;
348     guint32 value;
349
350     GST_DEBUG ("offset:%d, size:%d", offset, size);
351
352     noffset =
353         gst_adapter_masked_scan_uint32_peek (adapter, 0x0000ff00, 0x0000ff00,
354         offset, size - offset, &value);
355
356     /* lost sync if 0xff marker not where expected */
357     if ((resync = (noffset != offset))) {
358       GST_DEBUG ("Lost sync at 0x%08x, resyncing", offset + 2);
359     }
360     /* may have marker, but could have been resyncng */
361     resync = resync || dec->parse_resync;
362     /* Skip over extra 0xff */
363     while ((noffset >= 0) && ((value & 0xff) == 0xff)) {
364       noffset++;
365       noffset =
366           gst_adapter_masked_scan_uint32_peek (adapter, 0x0000ff00, 0x0000ff00,
367           noffset, size - noffset, &value);
368     }
369     /* enough bytes left for marker? (we need 0xNN after the 0xff) */
370     if (noffset < 0) {
371       GST_DEBUG ("at end of input and no EOI marker found, need more data");
372       goto need_more_data;
373     }
374
375     /* now lock on the marker we found */
376     offset = noffset;
377     value = value & 0xff;
378     if (value == 0xd9) {
379       GST_DEBUG ("0x%08x: EOI marker", offset + 2);
380       /* clear parse state */
381       dec->saw_header = FALSE;
382       dec->parse_resync = FALSE;
383       toadd = offset + 4;
384       goto have_full_frame;
385     }
386     if (value == 0xd8) {
387       GST_DEBUG ("0x%08x: SOI marker before EOI marker", offset + 2);
388
389       /* clear parse state */
390       dec->saw_header = FALSE;
391       dec->parse_resync = FALSE;
392       toadd = offset;
393       goto have_full_frame;
394     }
395
396
397     if (value >= 0xd0 && value <= 0xd7)
398       frame_len = 0;
399     else {
400       /* peek tag and subsequent length */
401       if (offset + 2 + 4 > size)
402         goto need_more_data;
403       else
404         gst_adapter_masked_scan_uint32_peek (adapter, 0x0, 0x0, offset + 2, 4,
405             &frame_len);
406       frame_len = frame_len & 0xffff;
407     }
408     GST_DEBUG ("0x%08x: tag %02x, frame_len=%u", offset + 2, value, frame_len);
409     /* the frame length includes the 2 bytes for the length; here we want at
410      * least 2 more bytes at the end for an end marker */
411     if (offset + 2 + 2 + frame_len + 2 > size) {
412       goto need_more_data;
413     }
414
415     if (gst_jpeg_dec_parse_tag_has_entropy_segment (value)) {
416       guint eseglen = dec->parse_entropy_len;
417
418       GST_DEBUG ("0x%08x: finding entropy segment length (eseglen:%d)",
419           offset + 2, eseglen);
420       if (size < offset + 2 + frame_len + eseglen)
421         goto need_more_data;
422       noffset = offset + 2 + frame_len + dec->parse_entropy_len;
423       while (1) {
424         GST_DEBUG ("noffset:%d, size:%d, size - noffset:%d",
425             noffset, size, size - noffset);
426         noffset = gst_adapter_masked_scan_uint32_peek (adapter, 0x0000ff00,
427             0x0000ff00, noffset, size - noffset, &value);
428         if (noffset < 0) {
429           /* need more data */
430           dec->parse_entropy_len = size - offset - 4 - frame_len - 2;
431           goto need_more_data;
432         }
433         if ((value & 0xff) != 0x00) {
434           eseglen = noffset - offset - frame_len - 2;
435           break;
436         }
437         noffset++;
438       }
439       dec->parse_entropy_len = 0;
440       frame_len += eseglen;
441       GST_DEBUG ("entropy segment length=%u => frame_len=%u", eseglen,
442           frame_len);
443     }
444     if (resync) {
445       /* check if we will still be in sync if we interpret
446        * this as a sync point and skip this frame */
447       noffset = offset + frame_len + 2;
448       noffset = gst_adapter_masked_scan_uint32 (adapter, 0x0000ff00, 0x0000ff00,
449           noffset, 4);
450       if (noffset < 0) {
451         /* ignore and continue resyncing until we hit the end
452          * of our data or find a sync point that looks okay */
453         offset++;
454         continue;
455       }
456       GST_DEBUG ("found sync at 0x%x", offset + 2);
457     }
458
459     /* Add current data to output buffer */
460     toadd += frame_len + 2;
461     offset += frame_len + 2;
462   }
463
464 need_more_data:
465   if (toadd)
466     gst_video_decoder_add_to_frame (bdec, toadd);
467   return GST_VIDEO_DECODER_FLOW_NEED_DATA;
468
469 have_full_frame:
470   if (toadd)
471     gst_video_decoder_add_to_frame (bdec, toadd);
472   GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
473   return gst_video_decoder_have_frame (bdec);
474
475 drop_frame:
476   gst_adapter_flush (adapter, size);
477   return GST_FLOW_OK;
478 }
479
480
481 /* shamelessly ripped from jpegutils.c in mjpegtools */
482 static void
483 add_huff_table (j_decompress_ptr dinfo,
484     JHUFF_TBL ** htblptr, const UINT8 * bits, const UINT8 * val)
485 /* Define a Huffman table */
486 {
487   int nsymbols, len;
488
489   if (*htblptr == NULL)
490     *htblptr = jpeg_alloc_huff_table ((j_common_ptr) dinfo);
491
492   g_assert (*htblptr);
493
494   /* Copy the number-of-symbols-of-each-code-length counts */
495   memcpy ((*htblptr)->bits, bits, sizeof ((*htblptr)->bits));
496
497   /* Validate the counts.  We do this here mainly so we can copy the right
498    * number of symbols from the val[] array, without risking marching off
499    * the end of memory.  jchuff.c will do a more thorough test later.
500    */
501   nsymbols = 0;
502   for (len = 1; len <= 16; len++)
503     nsymbols += bits[len];
504   if (nsymbols < 1 || nsymbols > 256)
505     g_error ("jpegutils.c:  add_huff_table failed badly. ");
506
507   memcpy ((*htblptr)->huffval, val, nsymbols * sizeof (UINT8));
508 }
509
510
511
512 static void
513 std_huff_tables (j_decompress_ptr dinfo)
514 /* Set up the standard Huffman tables (cf. JPEG standard section K.3) */
515 /* IMPORTANT: these are only valid for 8-bit data precision! */
516 {
517   static const UINT8 bits_dc_luminance[17] =
518       { /* 0-base */ 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 };
519   static const UINT8 val_dc_luminance[] =
520       { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
521
522   static const UINT8 bits_dc_chrominance[17] =
523       { /* 0-base */ 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 };
524   static const UINT8 val_dc_chrominance[] =
525       { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
526
527   static const UINT8 bits_ac_luminance[17] =
528       { /* 0-base */ 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d };
529   static const UINT8 val_ac_luminance[] =
530       { 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
531     0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
532     0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
533     0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
534     0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
535     0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
536     0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
537     0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
538     0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
539     0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
540     0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
541     0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
542     0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
543     0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
544     0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
545     0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
546     0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
547     0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
548     0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
549     0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
550     0xf9, 0xfa
551   };
552
553   static const UINT8 bits_ac_chrominance[17] =
554       { /* 0-base */ 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77 };
555   static const UINT8 val_ac_chrominance[] =
556       { 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
557     0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
558     0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
559     0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
560     0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
561     0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
562     0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
563     0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
564     0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
565     0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
566     0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
567     0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
568     0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
569     0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
570     0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
571     0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
572     0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
573     0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
574     0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
575     0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
576     0xf9, 0xfa
577   };
578
579   add_huff_table (dinfo, &dinfo->dc_huff_tbl_ptrs[0],
580       bits_dc_luminance, val_dc_luminance);
581   add_huff_table (dinfo, &dinfo->ac_huff_tbl_ptrs[0],
582       bits_ac_luminance, val_ac_luminance);
583   add_huff_table (dinfo, &dinfo->dc_huff_tbl_ptrs[1],
584       bits_dc_chrominance, val_dc_chrominance);
585   add_huff_table (dinfo, &dinfo->ac_huff_tbl_ptrs[1],
586       bits_ac_chrominance, val_ac_chrominance);
587 }
588
589
590
591 static void
592 guarantee_huff_tables (j_decompress_ptr dinfo)
593 {
594   if ((dinfo->dc_huff_tbl_ptrs[0] == NULL) &&
595       (dinfo->dc_huff_tbl_ptrs[1] == NULL) &&
596       (dinfo->ac_huff_tbl_ptrs[0] == NULL) &&
597       (dinfo->ac_huff_tbl_ptrs[1] == NULL)) {
598     GST_DEBUG ("Generating standard Huffman tables for this frame.");
599     std_huff_tables (dinfo);
600   }
601 }
602
603 static gboolean
604 gst_jpeg_dec_set_format (GstVideoDecoder * dec, GstVideoCodecState * state)
605 {
606   GstJpegDec *jpeg = GST_JPEG_DEC (dec);
607   GstStructure *structure;
608   gboolean parsed = FALSE;
609
610   if (jpeg->input_state)
611     gst_video_codec_state_unref (jpeg->input_state);
612   jpeg->input_state = gst_video_codec_state_ref (state);
613
614   structure = gst_caps_get_structure (state->caps, 0);
615   gst_structure_get_boolean (structure, "parsed", &parsed);
616   gst_video_decoder_set_packetized (dec, parsed);
617
618   return TRUE;
619 }
620
621
622 /* yuk */
623 static void
624 hresamplecpy1 (guint8 * dest, const guint8 * src, guint len)
625 {
626   gint i;
627
628   for (i = 0; i < len; ++i) {
629     /* equivalent to: dest[i] = src[i << 1] */
630     *dest = *src;
631     ++dest;
632     ++src;
633     ++src;
634   }
635 }
636
637 static void
638 gst_jpeg_dec_free_buffers (GstJpegDec * dec)
639 {
640   gint i;
641
642   for (i = 0; i < 16; i++) {
643     g_free (dec->idr_y[i]);
644     g_free (dec->idr_u[i]);
645     g_free (dec->idr_v[i]);
646     dec->idr_y[i] = NULL;
647     dec->idr_u[i] = NULL;
648     dec->idr_v[i] = NULL;
649   }
650
651   dec->idr_width_allocated = 0;
652 }
653
654 static inline gboolean
655 gst_jpeg_dec_ensure_buffers (GstJpegDec * dec, guint maxrowbytes)
656 {
657   gint i;
658
659   if (G_LIKELY (dec->idr_width_allocated == maxrowbytes))
660     return TRUE;
661
662   /* FIXME: maybe just alloc one or three blocks altogether? */
663   for (i = 0; i < 16; i++) {
664     dec->idr_y[i] = g_try_realloc (dec->idr_y[i], maxrowbytes);
665     dec->idr_u[i] = g_try_realloc (dec->idr_u[i], maxrowbytes);
666     dec->idr_v[i] = g_try_realloc (dec->idr_v[i], maxrowbytes);
667
668     if (G_UNLIKELY (!dec->idr_y[i] || !dec->idr_u[i] || !dec->idr_v[i])) {
669       GST_WARNING_OBJECT (dec, "out of memory, i=%d, bytes=%u", i, maxrowbytes);
670       return FALSE;
671     }
672   }
673
674   dec->idr_width_allocated = maxrowbytes;
675   GST_LOG_OBJECT (dec, "allocated temp memory, %u bytes/row", maxrowbytes);
676   return TRUE;
677 }
678
679 static void
680 gst_jpeg_dec_decode_grayscale (GstJpegDec * dec, GstVideoFrame * frame,
681     guint field, guint num_fields)
682 {
683   guchar *rows[16];
684   guchar **scanarray[1] = { rows };
685   gint i, j, k;
686   gint lines;
687   guint8 *base[1];
688   gint width, height;
689   gint pstride, rstride;
690
691   GST_DEBUG_OBJECT (dec, "indirect decoding of grayscale");
692
693   width = GST_VIDEO_FRAME_WIDTH (frame);
694   height = GST_VIDEO_FRAME_HEIGHT (frame) / num_fields;
695
696   if (G_UNLIKELY (!gst_jpeg_dec_ensure_buffers (dec, GST_ROUND_UP_32 (width))))
697     return;
698
699   base[0] = GST_VIDEO_FRAME_COMP_DATA (frame, 0);
700   if (field == 2) {
701     base[0] += GST_VIDEO_FRAME_COMP_STRIDE (frame, 0);
702   }
703
704   pstride = GST_VIDEO_FRAME_COMP_PSTRIDE (frame, 0);
705   rstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0) * num_fields;
706
707   memcpy (rows, dec->idr_y, 16 * sizeof (gpointer));
708
709   i = 0;
710   while (i < height) {
711     lines = jpeg_read_raw_data (&dec->cinfo, scanarray, DCTSIZE);
712     if (G_LIKELY (lines > 0)) {
713       for (j = 0; (j < DCTSIZE) && (i < height); j++, i++) {
714         gint p;
715
716         p = 0;
717         for (k = 0; k < width; k++) {
718           base[0][p] = rows[j][k];
719           p += pstride;
720         }
721         base[0] += rstride;
722       }
723     } else {
724       GST_INFO_OBJECT (dec, "jpeg_read_raw_data() returned 0");
725     }
726   }
727 }
728
729 static void
730 gst_jpeg_dec_decode_rgb (GstJpegDec * dec, GstVideoFrame * frame,
731     guint field, guint num_fields)
732 {
733   guchar *r_rows[16], *g_rows[16], *b_rows[16];
734   guchar **scanarray[3] = { r_rows, g_rows, b_rows };
735   gint i, j, k;
736   gint lines;
737   guint8 *base[3];
738   guint pstride, rstride;
739   gint width, height;
740
741   GST_DEBUG_OBJECT (dec, "indirect decoding of RGB");
742
743   width = GST_VIDEO_FRAME_WIDTH (frame);
744   height = GST_VIDEO_FRAME_HEIGHT (frame) / num_fields;
745
746   if (G_UNLIKELY (!gst_jpeg_dec_ensure_buffers (dec, GST_ROUND_UP_32 (width))))
747     return;
748
749   for (i = 0; i < 3; i++) {
750     base[i] = GST_VIDEO_FRAME_COMP_DATA (frame, i);
751     if (field == 2)
752       base[i] += GST_VIDEO_FRAME_COMP_STRIDE (frame, i);
753   }
754
755   pstride = GST_VIDEO_FRAME_COMP_PSTRIDE (frame, 0);
756   rstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0) * num_fields;
757
758   memcpy (r_rows, dec->idr_y, 16 * sizeof (gpointer));
759   memcpy (g_rows, dec->idr_u, 16 * sizeof (gpointer));
760   memcpy (b_rows, dec->idr_v, 16 * sizeof (gpointer));
761
762   i = 0;
763   while (i < height) {
764     lines = jpeg_read_raw_data (&dec->cinfo, scanarray, DCTSIZE);
765     if (G_LIKELY (lines > 0)) {
766       for (j = 0; (j < DCTSIZE) && (i < height); j++, i++) {
767         gint p;
768
769         p = 0;
770         for (k = 0; k < width; k++) {
771           base[0][p] = r_rows[j][k];
772           base[1][p] = g_rows[j][k];
773           base[2][p] = b_rows[j][k];
774           p += pstride;
775         }
776         base[0] += rstride;
777         base[1] += rstride;
778         base[2] += rstride;
779       }
780     } else {
781       GST_INFO_OBJECT (dec, "jpeg_read_raw_data() returned 0");
782     }
783   }
784 }
785
786 static void
787 gst_jpeg_dec_decode_indirect (GstJpegDec * dec, GstVideoFrame * frame, gint r_v,
788     gint r_h, gint comp, guint field, guint num_fields)
789 {
790   guchar *y_rows[16], *u_rows[16], *v_rows[16];
791   guchar **scanarray[3] = { y_rows, u_rows, v_rows };
792   gint i, j, k;
793   gint lines;
794   guchar *base[3], *last[3];
795   gint rowsize[3], stride[3];
796   gint width, height;
797
798   GST_DEBUG_OBJECT (dec,
799       "unadvantageous width or r_h, taking slow route involving memcpy");
800
801   width = GST_VIDEO_FRAME_WIDTH (frame);
802   height = GST_VIDEO_FRAME_HEIGHT (frame);
803
804   if (G_UNLIKELY (!gst_jpeg_dec_ensure_buffers (dec, GST_ROUND_UP_32 (width))))
805     return;
806
807   for (i = 0; i < 3; i++) {
808     base[i] = GST_VIDEO_FRAME_COMP_DATA (frame, i);
809     stride[i] = GST_VIDEO_FRAME_COMP_STRIDE (frame, i) * num_fields;
810     rowsize[i] = GST_VIDEO_FRAME_COMP_STRIDE (frame, i);
811     /* make sure we don't make jpeglib write beyond our buffer,
812      * which might happen if (height % (r_v*DCTSIZE)) != 0 */
813     last[i] = base[i] + (GST_VIDEO_FRAME_COMP_STRIDE (frame, i) *
814         (GST_VIDEO_FRAME_COMP_HEIGHT (frame, i) - 1));
815
816     if (field == 2) {
817       base[i] += GST_VIDEO_FRAME_COMP_STRIDE (frame, i);
818     }
819   }
820
821   memcpy (y_rows, dec->idr_y, 16 * sizeof (gpointer));
822   memcpy (u_rows, dec->idr_u, 16 * sizeof (gpointer));
823   memcpy (v_rows, dec->idr_v, 16 * sizeof (gpointer));
824
825   /* fill chroma components for grayscale */
826   if (comp == 1) {
827     GST_DEBUG_OBJECT (dec, "grayscale, filling chroma");
828     for (i = 0; i < 16; i++) {
829       memset (u_rows[i], GST_ROUND_UP_32 (width), 0x80);
830       memset (v_rows[i], GST_ROUND_UP_32 (width), 0x80);
831     }
832   }
833
834   for (i = 0; i < height; i += r_v * DCTSIZE) {
835     lines = jpeg_read_raw_data (&dec->cinfo, scanarray, r_v * DCTSIZE);
836     if (G_LIKELY (lines > 0)) {
837       for (j = 0, k = 0; j < (r_v * DCTSIZE); j += r_v, k++) {
838         if (G_LIKELY (base[0] <= last[0])) {
839           memcpy (base[0], y_rows[j], rowsize[0]);
840           base[0] += stride[0];
841         }
842         if (r_v == 2) {
843           if (G_LIKELY (base[0] <= last[0])) {
844             memcpy (base[0], y_rows[j + 1], rowsize[0]);
845             base[0] += stride[0];
846           }
847         }
848         if (G_LIKELY (base[1] <= last[1] && base[2] <= last[2])) {
849           if (r_h == 2) {
850             memcpy (base[1], u_rows[k], rowsize[1]);
851             memcpy (base[2], v_rows[k], rowsize[2]);
852           } else if (r_h == 1) {
853             hresamplecpy1 (base[1], u_rows[k], rowsize[1]);
854             hresamplecpy1 (base[2], v_rows[k], rowsize[2]);
855           } else {
856             /* FIXME: implement (at least we avoid crashing by doing nothing) */
857           }
858         }
859
860         if (r_v == 2 || (k & 1) != 0) {
861           base[1] += stride[1];
862           base[2] += stride[2];
863         }
864       }
865     } else {
866       GST_INFO_OBJECT (dec, "jpeg_read_raw_data() returned 0");
867     }
868   }
869 }
870
871 static GstFlowReturn
872 gst_jpeg_dec_decode_direct (GstJpegDec * dec, GstVideoFrame * frame,
873     guint field, guint num_fields)
874 {
875   guchar **line[3];             /* the jpeg line buffer         */
876   guchar *y[4 * DCTSIZE] = { NULL, };   /* alloc enough for the lines   */
877   guchar *u[4 * DCTSIZE] = { NULL, };   /* r_v will be <4               */
878   guchar *v[4 * DCTSIZE] = { NULL, };
879   gint i, j;
880   gint lines, v_samp[3];
881   guchar *base[3], *last[3];
882   gint stride[3];
883   guint field_height;
884
885   line[0] = y;
886   line[1] = u;
887   line[2] = v;
888
889   v_samp[0] = dec->cinfo.comp_info[0].v_samp_factor;
890   v_samp[1] = dec->cinfo.comp_info[1].v_samp_factor;
891   v_samp[2] = dec->cinfo.comp_info[2].v_samp_factor;
892
893   if (G_UNLIKELY (v_samp[0] > 2 || v_samp[1] > 2 || v_samp[2] > 2))
894     goto format_not_supported;
895
896   field_height = GST_VIDEO_FRAME_HEIGHT (frame);
897
898   /* XXX: division by 2 here might not be a good idea yes. But we are doing this
899    * already in gst_jpeg_dec_handle_frame() for interlaced jpeg */
900   if (num_fields == 2)
901     field_height /= 2;
902
903   for (i = 0; i < 3; i++) {
904     base[i] = GST_VIDEO_FRAME_COMP_DATA (frame, i);
905     stride[i] = GST_VIDEO_FRAME_COMP_STRIDE (frame, i) * num_fields;
906     /* make sure we don't make jpeglib write beyond our buffer,
907      * which might happen if (height % (r_v*DCTSIZE)) != 0 */
908     last[i] = base[i] + (GST_VIDEO_FRAME_COMP_STRIDE (frame, i) *
909         (GST_VIDEO_FRAME_COMP_HEIGHT (frame, i) - 1));
910
911     if (field == 2) {
912       base[i] += GST_VIDEO_FRAME_COMP_STRIDE (frame, i);
913     }
914   }
915
916   if (field_height % (v_samp[0] * DCTSIZE) && (dec->scratch_size < stride[0])) {
917     g_free (dec->scratch);
918     dec->scratch = g_malloc (stride[0]);
919     dec->scratch_size = stride[0];
920   }
921
922   /* let jpeglib decode directly into our final buffer */
923   GST_DEBUG_OBJECT (dec, "decoding directly into output buffer");
924
925 #ifdef JCS_EXTENSIONS
926   if (dec->format_convert) {
927     gint row_stride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0);
928     guchar *bufbase = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
929
930     if (num_fields == 2) {
931       row_stride *= 2;
932     }
933
934     if (field == 2) {
935       bufbase += GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0);
936     }
937
938     while (dec->cinfo.output_scanline < dec->cinfo.output_height) {
939       JSAMPARRAY buffer = { &bufbase, };
940       jpeg_read_scanlines (&dec->cinfo, buffer, 1);
941       bufbase += row_stride;
942     }
943   } else
944 #endif
945   {
946     for (i = 0; i < field_height; i += v_samp[0] * DCTSIZE) {
947       for (j = 0; j < (v_samp[0] * DCTSIZE); ++j) {
948         /* Y */
949         line[0][j] = base[0] + (i + j) * stride[0];
950         if (G_UNLIKELY (line[0][j] > last[0]))
951           line[0][j] = dec->scratch;
952         /* U */
953         if (v_samp[1] == v_samp[0]) {
954           line[1][j] = base[1] + ((i + j) / 2) * stride[1];
955         } else if (j < (v_samp[1] * DCTSIZE)) {
956           line[1][j] = base[1] + ((i / 2) + j) * stride[1];
957         }
958         if (G_UNLIKELY (line[1][j] > last[1]))
959           line[1][j] = dec->scratch;
960         /* V */
961         if (v_samp[2] == v_samp[0]) {
962           line[2][j] = base[2] + ((i + j) / 2) * stride[2];
963         } else if (j < (v_samp[2] * DCTSIZE)) {
964           line[2][j] = base[2] + ((i / 2) + j) * stride[2];
965         }
966         if (G_UNLIKELY (line[2][j] > last[2]))
967           line[2][j] = dec->scratch;
968       }
969
970       lines = jpeg_read_raw_data (&dec->cinfo, line, v_samp[0] * DCTSIZE);
971       if (G_UNLIKELY (!lines)) {
972         GST_INFO_OBJECT (dec, "jpeg_read_raw_data() returned 0");
973       }
974     }
975   }
976   return GST_FLOW_OK;
977
978 format_not_supported:
979   {
980     gboolean ret = GST_FLOW_OK;
981
982     GST_VIDEO_DECODER_ERROR (dec, 1, STREAM, DECODE,
983         (_("Failed to decode JPEG image")),
984         ("Unsupported subsampling schema: v_samp factors: %u %u %u", v_samp[0],
985             v_samp[1], v_samp[2]), ret);
986
987     return ret;
988   }
989 }
990
991 #ifdef JCS_EXTENSIONS
992 static J_COLOR_SPACE
993 gst_fmt_to_jpeg_turbo_ext_fmt (GstVideoFormat gstfmt)
994 {
995   switch (gstfmt) {
996     case GST_VIDEO_FORMAT_RGB:
997       return JCS_EXT_RGB;
998     case GST_VIDEO_FORMAT_RGBx:
999       return JCS_EXT_RGBX;
1000     case GST_VIDEO_FORMAT_xRGB:
1001       return JCS_EXT_XRGB;
1002     case GST_VIDEO_FORMAT_RGBA:
1003       return JCS_EXT_RGBA;
1004     case GST_VIDEO_FORMAT_ARGB:
1005       return JCS_EXT_ARGB;
1006     case GST_VIDEO_FORMAT_BGR:
1007       return JCS_EXT_BGR;
1008     case GST_VIDEO_FORMAT_BGRx:
1009       return JCS_EXT_BGRX;
1010     case GST_VIDEO_FORMAT_xBGR:
1011       return JCS_EXT_XBGR;
1012     case GST_VIDEO_FORMAT_BGRA:
1013       return JCS_EXT_BGRA;
1014     case GST_VIDEO_FORMAT_ABGR:
1015       return JCS_EXT_ABGR;
1016     default:
1017       return 0;
1018   }
1019 }
1020
1021 static void
1022 gst_jpeg_turbo_parse_ext_fmt_convert (GstJpegDec * dec, gint * clrspc)
1023 {
1024   GstCaps *peer_caps, *dec_caps;
1025
1026   dec_caps = gst_static_caps_get (&gst_jpeg_dec_src_pad_template.static_caps);
1027   peer_caps =
1028       gst_pad_peer_query_caps (GST_VIDEO_DECODER_SRC_PAD (dec), dec_caps);
1029   gst_caps_unref (dec_caps);
1030
1031   GST_DEBUG ("Received caps from peer: %" GST_PTR_FORMAT, peer_caps);
1032   dec->format_convert = FALSE;
1033   if (!gst_caps_is_empty (peer_caps)) {
1034     GstStructure *peerstruct;
1035     const gchar *peerformat;
1036     GstVideoFormat peerfmt;
1037
1038     if (!gst_caps_is_fixed (peer_caps))
1039       peer_caps = gst_caps_fixate (peer_caps);
1040
1041     peerstruct = gst_caps_get_structure (peer_caps, 0);
1042     peerformat = gst_structure_get_string (peerstruct, "format");
1043     peerfmt = gst_video_format_from_string (peerformat);
1044
1045     switch (peerfmt) {
1046       case GST_VIDEO_FORMAT_RGB:
1047       case GST_VIDEO_FORMAT_RGBx:
1048       case GST_VIDEO_FORMAT_xRGB:
1049       case GST_VIDEO_FORMAT_RGBA:
1050       case GST_VIDEO_FORMAT_ARGB:
1051       case GST_VIDEO_FORMAT_BGR:
1052       case GST_VIDEO_FORMAT_BGRx:
1053       case GST_VIDEO_FORMAT_xBGR:
1054       case GST_VIDEO_FORMAT_BGRA:
1055       case GST_VIDEO_FORMAT_ABGR:
1056         if (clrspc)
1057           *clrspc = JCS_RGB;
1058         dec->format = peerfmt;
1059         dec->format_convert = TRUE;
1060         dec->libjpeg_ext_format = gst_fmt_to_jpeg_turbo_ext_fmt (peerfmt);
1061         break;
1062       default:
1063         break;
1064     }
1065   }
1066   gst_caps_unref (peer_caps);
1067   GST_DEBUG_OBJECT (dec, "format_convert=%d", dec->format_convert);
1068 }
1069 #endif
1070
1071 static void
1072 gst_jpeg_dec_negotiate (GstJpegDec * dec, gint width, gint height, gint clrspc,
1073     gboolean interlaced)
1074 {
1075   GstVideoCodecState *outstate;
1076   GstVideoInfo *info;
1077   GstVideoFormat format;
1078
1079 #ifdef JCS_EXTENSIONS
1080   if (dec->format_convert) {
1081     format = dec->format;
1082   } else
1083 #endif
1084   {
1085     switch (clrspc) {
1086       case JCS_RGB:
1087         format = GST_VIDEO_FORMAT_RGB;
1088         break;
1089       case JCS_GRAYSCALE:
1090         format = GST_VIDEO_FORMAT_GRAY8;
1091         break;
1092       default:
1093         format = GST_VIDEO_FORMAT_I420;
1094         break;
1095     }
1096   }
1097
1098   /* Compare to currently configured output state */
1099   outstate = gst_video_decoder_get_output_state (GST_VIDEO_DECODER (dec));
1100   if (outstate) {
1101     info = &outstate->info;
1102
1103     if (width == GST_VIDEO_INFO_WIDTH (info) &&
1104         height == GST_VIDEO_INFO_HEIGHT (info) &&
1105         format == GST_VIDEO_INFO_FORMAT (info)) {
1106       gst_video_codec_state_unref (outstate);
1107       return;
1108     }
1109     gst_video_codec_state_unref (outstate);
1110   }
1111 #ifdef JCS_EXTENSIONS
1112   /* Determine if libjpeg-turbo direct format conversion can be used
1113    * with current caps and if so, adjust $dec to enable it and $clrspc
1114    * accordingly. */
1115   gst_jpeg_turbo_parse_ext_fmt_convert (dec, &clrspc);
1116 #endif
1117
1118   outstate =
1119       gst_video_decoder_set_output_state (GST_VIDEO_DECODER (dec), format,
1120       width, height, dec->input_state);
1121
1122   switch (clrspc) {
1123     case JCS_RGB:
1124     case JCS_GRAYSCALE:
1125       break;
1126     default:
1127       /* aka JPEG chroma siting */
1128       outstate->info.chroma_site = GST_VIDEO_CHROMA_SITE_NONE;
1129
1130       outstate->info.colorimetry.range = GST_VIDEO_COLOR_RANGE_0_255;
1131       outstate->info.colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT601;
1132       outstate->info.colorimetry.transfer = GST_VIDEO_TRANSFER_UNKNOWN;
1133       outstate->info.colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_UNKNOWN;
1134       break;
1135   }
1136
1137   if (interlaced) {
1138     outstate->info.interlace_mode = GST_VIDEO_INTERLACE_MODE_INTERLEAVED;
1139     GST_VIDEO_INFO_FIELD_ORDER (&outstate->info) =
1140         GST_VIDEO_FIELD_ORDER_TOP_FIELD_FIRST;
1141   }
1142
1143   gst_video_codec_state_unref (outstate);
1144
1145   gst_video_decoder_negotiate (GST_VIDEO_DECODER (dec));
1146
1147   GST_DEBUG_OBJECT (dec, "max_v_samp_factor=%d", dec->cinfo.max_v_samp_factor);
1148   GST_DEBUG_OBJECT (dec, "max_h_samp_factor=%d", dec->cinfo.max_h_samp_factor);
1149 }
1150
1151 static GstFlowReturn
1152 gst_jpeg_dec_prepare_decode (GstJpegDec * dec)
1153 {
1154   G_GNUC_UNUSED GstFlowReturn ret;
1155   guint r_h, r_v, hdr_ok;
1156
1157   /* read header */
1158   hdr_ok = jpeg_read_header (&dec->cinfo, TRUE);
1159   if (G_UNLIKELY (hdr_ok != JPEG_HEADER_OK)) {
1160     GST_WARNING_OBJECT (dec, "reading the header failed, %d", hdr_ok);
1161   }
1162
1163   GST_LOG_OBJECT (dec, "num_components=%d", dec->cinfo.num_components);
1164   GST_LOG_OBJECT (dec, "jpeg_color_space=%d", dec->cinfo.jpeg_color_space);
1165
1166   if (!dec->cinfo.num_components || !dec->cinfo.comp_info)
1167     goto components_not_supported;
1168
1169   r_h = dec->cinfo.comp_info[0].h_samp_factor;
1170   r_v = dec->cinfo.comp_info[0].v_samp_factor;
1171
1172   GST_LOG_OBJECT (dec, "r_h = %d, r_v = %d", r_h, r_v);
1173
1174   if (dec->cinfo.num_components > 3)
1175     goto components_not_supported;
1176
1177   /* verify color space expectation to avoid going *boom* or bogus output */
1178   if (dec->cinfo.jpeg_color_space != JCS_YCbCr &&
1179       dec->cinfo.jpeg_color_space != JCS_GRAYSCALE &&
1180       dec->cinfo.jpeg_color_space != JCS_RGB)
1181     goto unsupported_colorspace;
1182
1183 #ifndef GST_DISABLE_GST_DEBUG
1184   {
1185     gint i;
1186
1187     for (i = 0; i < dec->cinfo.num_components; ++i) {
1188       GST_LOG_OBJECT (dec, "[%d] h_samp_factor=%d, v_samp_factor=%d, cid=%d",
1189           i, dec->cinfo.comp_info[i].h_samp_factor,
1190           dec->cinfo.comp_info[i].v_samp_factor,
1191           dec->cinfo.comp_info[i].component_id);
1192     }
1193   }
1194 #endif
1195
1196   /* prepare for raw output */
1197   dec->cinfo.do_fancy_upsampling = FALSE;
1198   dec->cinfo.do_block_smoothing = FALSE;
1199   dec->cinfo.dct_method = dec->idct_method;
1200 #ifdef JCS_EXTENSIONS
1201   gst_jpeg_turbo_parse_ext_fmt_convert (dec, NULL);
1202   if (dec->format_convert) {
1203     dec->cinfo.out_color_space = dec->libjpeg_ext_format;
1204     dec->cinfo.raw_data_out = FALSE;
1205   } else
1206 #endif
1207   {
1208     dec->cinfo.out_color_space = dec->cinfo.jpeg_color_space;
1209     dec->cinfo.raw_data_out = TRUE;
1210   }
1211
1212   GST_LOG_OBJECT (dec, "starting decompress");
1213   guarantee_huff_tables (&dec->cinfo);
1214   if (!jpeg_start_decompress (&dec->cinfo)) {
1215     GST_WARNING_OBJECT (dec, "failed to start decompression cycle");
1216   }
1217
1218   /* sanity checks to get safe and reasonable output */
1219   switch (dec->cinfo.jpeg_color_space) {
1220     case JCS_GRAYSCALE:
1221       if (dec->cinfo.num_components != 1)
1222         goto invalid_yuvrgbgrayscale;
1223       break;
1224     case JCS_RGB:
1225       if (dec->cinfo.num_components != 3 || dec->cinfo.max_v_samp_factor > 1 ||
1226           dec->cinfo.max_h_samp_factor > 1)
1227         goto invalid_yuvrgbgrayscale;
1228       break;
1229     case JCS_YCbCr:
1230       if (dec->cinfo.num_components != 3 ||
1231           r_v > 2 || r_v < dec->cinfo.comp_info[0].v_samp_factor ||
1232           r_v < dec->cinfo.comp_info[1].v_samp_factor ||
1233           r_h < dec->cinfo.comp_info[0].h_samp_factor ||
1234           r_h < dec->cinfo.comp_info[1].h_samp_factor)
1235         goto invalid_yuvrgbgrayscale;
1236       break;
1237     default:
1238       g_assert_not_reached ();
1239       break;
1240   }
1241
1242   if (G_UNLIKELY (dec->cinfo.output_width < MIN_WIDTH ||
1243           dec->cinfo.output_width > MAX_WIDTH ||
1244           dec->cinfo.output_height < MIN_HEIGHT ||
1245           dec->cinfo.output_height > MAX_HEIGHT))
1246     goto wrong_size;
1247
1248   return GST_FLOW_OK;
1249
1250 /* ERRORS */
1251 wrong_size:
1252   {
1253     ret = GST_FLOW_ERROR;
1254     GST_VIDEO_DECODER_ERROR (dec, 1, STREAM, DECODE,
1255         (_("Failed to decode JPEG image")),
1256         ("Picture is too small or too big (%ux%u)", dec->cinfo.output_width,
1257             dec->cinfo.output_height), ret);
1258     return GST_FLOW_ERROR;
1259   }
1260 components_not_supported:
1261   {
1262     ret = GST_FLOW_ERROR;
1263     GST_VIDEO_DECODER_ERROR (dec, 1, STREAM, DECODE,
1264         (_("Failed to decode JPEG image")),
1265         ("number of components not supported: %d (max 3)",
1266             dec->cinfo.num_components), ret);
1267     jpeg_abort_decompress (&dec->cinfo);
1268     return GST_FLOW_ERROR;
1269   }
1270 unsupported_colorspace:
1271   {
1272     ret = GST_FLOW_ERROR;
1273     GST_VIDEO_DECODER_ERROR (dec, 1, STREAM, DECODE,
1274         (_("Failed to decode JPEG image")),
1275         ("Picture has unknown or unsupported colourspace"), ret);
1276     jpeg_abort_decompress (&dec->cinfo);
1277     return GST_FLOW_ERROR;
1278   }
1279 invalid_yuvrgbgrayscale:
1280   {
1281     ret = GST_FLOW_ERROR;
1282     GST_VIDEO_DECODER_ERROR (dec, 1, STREAM, DECODE,
1283         (_("Failed to decode JPEG image")),
1284         ("Picture is corrupt or unhandled YUV/RGB/grayscale layout"), ret);
1285     jpeg_abort_decompress (&dec->cinfo);
1286     return GST_FLOW_ERROR;
1287   }
1288 }
1289
1290 static GstFlowReturn
1291 gst_jpeg_dec_decode (GstJpegDec * dec, GstVideoFrame * vframe, guint width,
1292     guint height, guint field, guint num_fields)
1293 {
1294   GstFlowReturn ret = GST_FLOW_OK;
1295
1296   if (dec->cinfo.jpeg_color_space == JCS_RGB) {
1297     gst_jpeg_dec_decode_rgb (dec, vframe, field, num_fields);
1298   } else if (dec->cinfo.jpeg_color_space == JCS_GRAYSCALE) {
1299     gst_jpeg_dec_decode_grayscale (dec, vframe, field, num_fields);
1300   } else {
1301     GST_LOG_OBJECT (dec, "decompressing (required scanline buffer height = %u)",
1302         dec->cinfo.rec_outbuf_height);
1303
1304     /* For some widths jpeglib requires more horizontal padding than I420 
1305      * provides. In those cases we need to decode into separate buffers and then
1306      * copy over the data into our final picture buffer, otherwise jpeglib might
1307      * write over the end of a line into the beginning of the next line,
1308      * resulting in blocky artifacts on the left side of the picture. */
1309     if (G_UNLIKELY (width % (dec->cinfo.max_h_samp_factor * DCTSIZE) != 0
1310             || dec->cinfo.comp_info[0].h_samp_factor != 2
1311             || dec->cinfo.comp_info[1].h_samp_factor != 1
1312             || dec->cinfo.comp_info[2].h_samp_factor != 1)) {
1313       GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, dec,
1314           "indirect decoding using extra buffer copy");
1315       gst_jpeg_dec_decode_indirect (dec, vframe,
1316           dec->cinfo.comp_info[0].v_samp_factor,
1317           dec->cinfo.comp_info[0].h_samp_factor, dec->cinfo.num_components,
1318           field, num_fields);
1319     } else {
1320       ret = gst_jpeg_dec_decode_direct (dec, vframe, field, num_fields);
1321     }
1322   }
1323
1324   GST_LOG_OBJECT (dec, "decompressing finished: %s", gst_flow_get_name (ret));
1325
1326   if (G_UNLIKELY (ret != GST_FLOW_OK)) {
1327     jpeg_abort_decompress (&dec->cinfo);
1328   } else {
1329     jpeg_finish_decompress (&dec->cinfo);
1330   }
1331
1332   return ret;
1333 }
1334
1335 static GstFlowReturn
1336 gst_jpeg_dec_handle_frame (GstVideoDecoder * bdec, GstVideoCodecFrame * frame)
1337 {
1338   GstFlowReturn ret = GST_FLOW_OK;
1339   GstJpegDec *dec = (GstJpegDec *) bdec;
1340   GstVideoFrame vframe;
1341   gint num_fields;              /* number of fields (1 or 2) */
1342   gint output_height;           /* height of output image (one or two fields) */
1343   gint height;                  /* height of current frame (whole image or a field) */
1344   gint width;
1345   guint code;
1346   gboolean need_unmap = TRUE;
1347   GstVideoCodecState *state = NULL;
1348   gboolean release_frame = TRUE;
1349   gboolean has_eoi;
1350   guint8 *data;
1351   gsize nbytes;
1352
1353   if (!gst_buffer_map (frame->input_buffer, &dec->current_frame_map,
1354           GST_MAP_READ))
1355     goto map_failed;
1356
1357   data = dec->current_frame_map.data;
1358   nbytes = dec->current_frame_map.size;
1359   if (nbytes < 2)
1360     goto need_more_data;
1361   has_eoi = ((data[nbytes - 2] == 0xff) && (data[nbytes - 1] == 0xd9));
1362
1363   /* some cameras fail to send an end-of-image marker (EOI),
1364    * add it if that is the case. */
1365   if (!has_eoi) {
1366     GstMapInfo map;
1367     GstBuffer *eoibuf = gst_buffer_new_and_alloc (2);
1368
1369     /* unmap, will add EOI and remap at the end */
1370     gst_buffer_unmap (frame->input_buffer, &dec->current_frame_map);
1371
1372     gst_buffer_map (eoibuf, &map, GST_MAP_WRITE);
1373     map.data[0] = 0xff;
1374     map.data[1] = 0xd9;
1375     gst_buffer_unmap (eoibuf, &map);
1376
1377     /* append to input buffer, and remap */
1378     frame->input_buffer = gst_buffer_append (frame->input_buffer, eoibuf);
1379
1380     gst_buffer_map (frame->input_buffer, &dec->current_frame_map, GST_MAP_READ);
1381     GST_DEBUG ("fixup EOI marker added");
1382   }
1383
1384   dec->current_frame = frame;
1385   dec->cinfo.src->next_input_byte = dec->current_frame_map.data;
1386   dec->cinfo.src->bytes_in_buffer = dec->current_frame_map.size;
1387
1388   if (setjmp (dec->jerr.setjmp_buffer)) {
1389     code = dec->jerr.pub.msg_code;
1390
1391     if (code == JERR_INPUT_EOF) {
1392       GST_DEBUG ("jpeg input EOF error, we probably need more data");
1393       goto need_more_data;
1394     }
1395     goto decode_error;
1396   }
1397
1398   /* read header and check values */
1399   ret = gst_jpeg_dec_prepare_decode (dec);
1400   if (G_UNLIKELY (ret == GST_FLOW_ERROR))
1401     goto done;
1402
1403   width = dec->cinfo.output_width;
1404   height = dec->cinfo.output_height;
1405
1406   /* is it interlaced MJPEG? (we really don't want to scan the jpeg data
1407    * to see if there are two SOF markers in the packet to detect this) */
1408   if (gst_video_decoder_get_packetized (bdec) &&
1409       dec->input_state && height > DCTSIZE &&
1410       dec->input_state->info.height > (2 * (height - DCTSIZE)) &&
1411       dec->input_state->info.height <= (height * 2)
1412       && dec->input_state->info.width == width) {
1413     GST_LOG_OBJECT (dec,
1414         "looks like an interlaced image: "
1415         "input width/height of %dx%d with JPEG frame width/height of %dx%d",
1416         dec->input_state->info.width, dec->input_state->info.height, width,
1417         height);
1418     output_height = dec->input_state->info.height;
1419     height = dec->input_state->info.height / 2;
1420     num_fields = 2;
1421     GST_LOG_OBJECT (dec, "field height=%d", height);
1422   } else {
1423     output_height = height;
1424     num_fields = 1;
1425   }
1426
1427   gst_jpeg_dec_negotiate (dec, width, output_height,
1428       dec->cinfo.jpeg_color_space, num_fields == 2);
1429
1430   state = gst_video_decoder_get_output_state (bdec);
1431   ret = gst_video_decoder_allocate_output_frame (bdec, frame);
1432   if (G_UNLIKELY (ret != GST_FLOW_OK))
1433     goto alloc_failed;
1434
1435   if (!gst_video_frame_map (&vframe, &state->info, frame->output_buffer,
1436           GST_MAP_READWRITE))
1437     goto alloc_failed;
1438
1439   if (setjmp (dec->jerr.setjmp_buffer)) {
1440     code = dec->jerr.pub.msg_code;
1441     gst_video_frame_unmap (&vframe);
1442     goto decode_error;
1443   }
1444
1445   GST_LOG_OBJECT (dec, "width %d, height %d, fields %d", width, output_height,
1446       num_fields);
1447
1448   ret = gst_jpeg_dec_decode (dec, &vframe, width, height, 1, num_fields);
1449   if (G_UNLIKELY (ret != GST_FLOW_OK)) {
1450     gst_video_frame_unmap (&vframe);
1451     goto decode_failed;
1452   }
1453
1454   if (setjmp (dec->jerr.setjmp_buffer)) {
1455     code = dec->jerr.pub.msg_code;
1456     gst_video_frame_unmap (&vframe);
1457     goto decode_error;
1458   }
1459
1460   /* decode second field if there is one */
1461   if (num_fields == 2) {
1462     GstVideoFormat field2_format;
1463
1464     /* Checked above before setting num_fields to 2 */
1465     g_assert (dec->input_state != NULL);
1466
1467     /* skip any chunk or padding bytes before the next SOI marker; both fields
1468      * are in one single buffer here, so direct access should be fine here */
1469     while (dec->jsrc.pub.bytes_in_buffer > 2 &&
1470         GST_READ_UINT16_BE (dec->jsrc.pub.next_input_byte) != 0xffd8) {
1471       --dec->jsrc.pub.bytes_in_buffer;
1472       ++dec->jsrc.pub.next_input_byte;
1473     }
1474
1475     if (gst_jpeg_dec_prepare_decode (dec) != GST_FLOW_OK) {
1476       GST_WARNING_OBJECT (dec, "problem reading jpeg header of 2nd field");
1477       /* FIXME: post a warning message here? */
1478       gst_video_frame_unmap (&vframe);
1479       goto decode_failed;
1480     }
1481
1482     /* check if format has changed for the second field */
1483 #ifdef JCS_EXTENSIONS
1484     if (dec->format_convert) {
1485       field2_format = dec->format;
1486     } else
1487 #endif
1488     {
1489       switch (dec->cinfo.jpeg_color_space) {
1490         case JCS_RGB:
1491           field2_format = GST_VIDEO_FORMAT_RGB;
1492           break;
1493         case JCS_GRAYSCALE:
1494           field2_format = GST_VIDEO_FORMAT_GRAY8;
1495           break;
1496         default:
1497           field2_format = GST_VIDEO_FORMAT_I420;
1498           break;
1499       }
1500     }
1501
1502     GST_LOG_OBJECT (dec,
1503         "got for second field of interlaced image: "
1504         "input width/height of %dx%d with JPEG frame width/height of %dx%d",
1505         dec->input_state->info.width, dec->input_state->info.height,
1506         dec->cinfo.output_width, dec->cinfo.output_height);
1507
1508     if (dec->cinfo.output_width != GST_VIDEO_INFO_WIDTH (&state->info) ||
1509         GST_VIDEO_INFO_HEIGHT (&state->info) <= dec->cinfo.output_height ||
1510         GST_VIDEO_INFO_HEIGHT (&state->info) > (dec->cinfo.output_height * 2) ||
1511         field2_format != GST_VIDEO_INFO_FORMAT (&state->info)) {
1512       GST_WARNING_OBJECT (dec, "second field has different format than first");
1513       gst_video_frame_unmap (&vframe);
1514       goto decode_failed;
1515     }
1516
1517     ret = gst_jpeg_dec_decode (dec, &vframe, width, height, 2, 2);
1518     if (G_UNLIKELY (ret != GST_FLOW_OK)) {
1519       gst_video_frame_unmap (&vframe);
1520       goto decode_failed;
1521     }
1522   }
1523   gst_video_frame_unmap (&vframe);
1524
1525   gst_buffer_unmap (frame->input_buffer, &dec->current_frame_map);
1526   ret = gst_video_decoder_finish_frame (bdec, frame);
1527   release_frame = FALSE;
1528   need_unmap = FALSE;
1529
1530 done:
1531
1532 exit:
1533
1534   if (need_unmap)
1535     gst_buffer_unmap (frame->input_buffer, &dec->current_frame_map);
1536
1537   if (release_frame)
1538     gst_video_decoder_release_frame (bdec, frame);
1539
1540   if (state)
1541     gst_video_codec_state_unref (state);
1542
1543   return ret;
1544
1545   /* special cases */
1546 need_more_data:
1547   {
1548     GST_LOG_OBJECT (dec, "we need more data");
1549     ret = GST_FLOW_OK;
1550     goto exit;
1551   }
1552   /* ERRORS */
1553 map_failed:
1554   {
1555     GST_ELEMENT_ERROR (dec, RESOURCE, READ, (_("Failed to read memory")),
1556         ("gst_buffer_map() failed for READ access"));
1557     ret = GST_FLOW_ERROR;
1558     goto exit;
1559   }
1560 decode_error:
1561   {
1562     gchar err_msg[JMSG_LENGTH_MAX];
1563
1564     dec->jerr.pub.format_message ((j_common_ptr) (&dec->cinfo), err_msg);
1565
1566     GST_VIDEO_DECODER_ERROR (dec, 1, STREAM, DECODE,
1567         (_("Failed to decode JPEG image")), ("Decode error #%u: %s", code,
1568             err_msg), ret);
1569
1570     gst_buffer_unmap (frame->input_buffer, &dec->current_frame_map);
1571     gst_video_decoder_drop_frame (bdec, frame);
1572     release_frame = FALSE;
1573     need_unmap = FALSE;
1574     jpeg_abort_decompress (&dec->cinfo);
1575
1576     goto done;
1577   }
1578 decode_failed:
1579   {
1580     /* already posted an error message */
1581     goto done;
1582   }
1583 alloc_failed:
1584   {
1585     const gchar *reason;
1586
1587     reason = gst_flow_get_name (ret);
1588
1589     GST_DEBUG_OBJECT (dec, "failed to alloc buffer, reason %s", reason);
1590     /* Reset for next time */
1591     jpeg_abort_decompress (&dec->cinfo);
1592     if (ret != GST_FLOW_EOS && ret != GST_FLOW_FLUSHING &&
1593         ret != GST_FLOW_NOT_LINKED) {
1594       GST_VIDEO_DECODER_ERROR (dec, 1, STREAM, DECODE,
1595           (_("Failed to decode JPEG image")),
1596           ("Buffer allocation failed, reason: %s", reason), ret);
1597       jpeg_abort_decompress (&dec->cinfo);
1598     }
1599     goto exit;
1600   }
1601 }
1602
1603 static gboolean
1604 gst_jpeg_dec_decide_allocation (GstVideoDecoder * bdec, GstQuery * query)
1605 {
1606   GstBufferPool *pool = NULL;
1607   GstStructure *config;
1608
1609   if (!GST_VIDEO_DECODER_CLASS (parent_class)->decide_allocation (bdec, query))
1610     return FALSE;
1611
1612   if (gst_query_get_n_allocation_pools (query) > 0)
1613     gst_query_parse_nth_allocation_pool (query, 0, &pool, NULL, NULL, NULL);
1614
1615   if (pool == NULL)
1616     return FALSE;
1617
1618   config = gst_buffer_pool_get_config (pool);
1619   if (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL)) {
1620     gst_buffer_pool_config_add_option (config,
1621         GST_BUFFER_POOL_OPTION_VIDEO_META);
1622   }
1623   gst_buffer_pool_set_config (pool, config);
1624   gst_object_unref (pool);
1625
1626   return TRUE;
1627 }
1628
1629 static gboolean
1630 gst_jpeg_dec_sink_event (GstVideoDecoder * bdec, GstEvent * event)
1631 {
1632   const GstSegment *segment;
1633
1634   if (GST_EVENT_TYPE (event) != GST_EVENT_SEGMENT)
1635     goto done;
1636
1637   gst_event_parse_segment (event, &segment);
1638
1639   if (segment->format == GST_FORMAT_TIME)
1640     gst_video_decoder_set_packetized (bdec, TRUE);
1641   else
1642     gst_video_decoder_set_packetized (bdec, FALSE);
1643
1644 done:
1645   return GST_VIDEO_DECODER_CLASS (parent_class)->sink_event (bdec, event);
1646 }
1647
1648 static gboolean
1649 gst_jpeg_dec_start (GstVideoDecoder * bdec)
1650 {
1651   GstJpegDec *dec = (GstJpegDec *) bdec;
1652
1653 #ifdef JCS_EXTENSIONS
1654   dec->format_convert = FALSE;
1655 #endif
1656   dec->saw_header = FALSE;
1657   dec->parse_entropy_len = 0;
1658   dec->parse_resync = FALSE;
1659
1660   gst_video_decoder_set_packetized (bdec, FALSE);
1661
1662   return TRUE;
1663 }
1664
1665 static gboolean
1666 gst_jpeg_dec_flush (GstVideoDecoder * bdec)
1667 {
1668   GstJpegDec *dec = (GstJpegDec *) bdec;
1669
1670   jpeg_abort_decompress (&dec->cinfo);
1671   dec->parse_entropy_len = 0;
1672   dec->parse_resync = FALSE;
1673   dec->saw_header = FALSE;
1674 #ifdef JCS_EXTENSIONS
1675   dec->format_convert = FALSE;
1676 #endif
1677
1678   return TRUE;
1679 }
1680
1681 static void
1682 gst_jpeg_dec_set_property (GObject * object, guint prop_id,
1683     const GValue * value, GParamSpec * pspec)
1684 {
1685   GstJpegDec *dec;
1686
1687   dec = GST_JPEG_DEC (object);
1688
1689   switch (prop_id) {
1690     case PROP_IDCT_METHOD:
1691       dec->idct_method = g_value_get_enum (value);
1692       break;
1693 #ifndef GST_REMOVE_DEPRECATED
1694     case PROP_MAX_ERRORS:
1695       g_atomic_int_set (&dec->max_errors, g_value_get_int (value));
1696       break;
1697 #endif
1698     default:
1699       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1700       break;
1701   }
1702 }
1703
1704 static void
1705 gst_jpeg_dec_get_property (GObject * object, guint prop_id, GValue * value,
1706     GParamSpec * pspec)
1707 {
1708   GstJpegDec *dec;
1709
1710   dec = GST_JPEG_DEC (object);
1711
1712   switch (prop_id) {
1713     case PROP_IDCT_METHOD:
1714       g_value_set_enum (value, dec->idct_method);
1715       break;
1716 #ifndef GST_REMOVE_DEPRECATED
1717     case PROP_MAX_ERRORS:
1718       g_value_set_int (value, g_atomic_int_get (&dec->max_errors));
1719       break;
1720 #endif
1721     default:
1722       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1723       break;
1724   }
1725 }
1726
1727 static gboolean
1728 gst_jpeg_dec_stop (GstVideoDecoder * bdec)
1729 {
1730   GstJpegDec *dec = (GstJpegDec *) bdec;
1731
1732   gst_jpeg_dec_free_buffers (dec);
1733
1734   g_free (dec->scratch);
1735   dec->scratch = NULL;
1736   dec->scratch_size = 0;
1737
1738   return TRUE;
1739 }