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>
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.
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.
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.
24 * SECTION:element-jpegdec
26 * Decodes jpeg images.
29 * <title>Example launch line</title>
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.
41 #include "gstjpegdec.h"
43 #include <gst/video/video.h>
44 #include <gst/video/gstvideometa.h>
45 #include <gst/video/gstvideopool.h>
46 #include "gst/gst-i18n-plugin.h"
50 #define MAX_WIDTH 65535
52 #define MAX_HEIGHT 65535
54 #define CINFO_GET_JPEGDEC(cinfo_ptr) \
55 (((struct GstJpegDecSourceMgr*)((cinfo_ptr)->src))->dec)
57 #define JPEG_DEFAULT_IDCT_METHOD JDCT_FASTEST
58 #define JPEG_DEFAULT_MAX_ERRORS 0
68 static GstStaticPadTemplate gst_jpeg_dec_src_pad_template =
69 GST_STATIC_PAD_TEMPLATE ("src",
72 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE
73 ("{ I420, RGB, BGR, RGBx, xRGB, BGRx, xBGR, GRAY8 }"))
77 /* FIXME: sof-marker is for IJG libjpeg 8, should be different for 6.2 */
78 /* FIXME: add back "sof-marker = (int) { 0, 1, 2, 5, 6, 7, 9, 10, 13, 14 }"
79 * once we have a parser and/or demuxer set caps properly */
80 static GstStaticPadTemplate gst_jpeg_dec_sink_pad_template =
81 GST_STATIC_PAD_TEMPLATE ("sink",
84 GST_STATIC_CAPS ("image/jpeg, "
85 "width = (int) [ " G_STRINGIFY (MIN_WIDTH) ", " G_STRINGIFY (MAX_WIDTH)
86 " ], " "height = (int) [ " G_STRINGIFY (MIN_HEIGHT) ", "
87 G_STRINGIFY (MAX_HEIGHT) " ] ")
90 GST_DEBUG_CATEGORY_STATIC (jpeg_dec_debug);
91 #define GST_CAT_DEFAULT jpeg_dec_debug
92 GST_DEBUG_CATEGORY_STATIC (GST_CAT_PERFORMANCE);
94 static void gst_jpeg_dec_set_property (GObject * object, guint prop_id,
95 const GValue * value, GParamSpec * pspec);
96 static void gst_jpeg_dec_get_property (GObject * object, guint prop_id,
97 GValue * value, GParamSpec * pspec);
99 static gboolean gst_jpeg_dec_set_format (GstVideoDecoder * dec,
100 GstVideoCodecState * state);
101 static gboolean gst_jpeg_dec_stop (GstVideoDecoder * bdec);
102 static gboolean gst_jpeg_dec_reset (GstVideoDecoder * bdec, gboolean hard);
103 static GstFlowReturn gst_jpeg_dec_parse (GstVideoDecoder * bdec,
104 GstVideoCodecFrame * frame, GstAdapter * adapter, gboolean at_eos);
105 static GstFlowReturn gst_jpeg_dec_handle_frame (GstVideoDecoder * bdec,
106 GstVideoCodecFrame * frame);
107 static gboolean gst_jpeg_dec_decide_allocation (GstVideoDecoder * bdec,
110 #define gst_jpeg_dec_parent_class parent_class
111 G_DEFINE_TYPE (GstJpegDec, gst_jpeg_dec, GST_TYPE_VIDEO_DECODER);
114 gst_jpeg_dec_finalize (GObject * object)
116 GstJpegDec *dec = GST_JPEG_DEC (object);
118 jpeg_destroy_decompress (&dec->cinfo);
119 if (dec->input_state)
120 gst_video_codec_state_unref (dec->input_state);
122 G_OBJECT_CLASS (parent_class)->finalize (object);
126 gst_jpeg_dec_class_init (GstJpegDecClass * klass)
128 GObjectClass *gobject_class;
129 GstElementClass *element_class;
130 GstVideoDecoderClass *vdec_class;
132 gobject_class = (GObjectClass *) klass;
133 element_class = (GstElementClass *) klass;
134 vdec_class = (GstVideoDecoderClass *) klass;
136 parent_class = g_type_class_peek_parent (klass);
138 gobject_class->finalize = gst_jpeg_dec_finalize;
139 gobject_class->set_property = gst_jpeg_dec_set_property;
140 gobject_class->get_property = gst_jpeg_dec_get_property;
142 g_object_class_install_property (gobject_class, PROP_IDCT_METHOD,
143 g_param_spec_enum ("idct-method", "IDCT Method",
144 "The IDCT algorithm to use", GST_TYPE_IDCT_METHOD,
145 JPEG_DEFAULT_IDCT_METHOD,
146 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
149 * GstJpegDec:max-errors
151 * Error out after receiving N consecutive decoding errors
152 * (-1 = never error out, 0 = automatic, 1 = fail on first error, etc.)
156 g_object_class_install_property (gobject_class, PROP_MAX_ERRORS,
157 g_param_spec_int ("max-errors", "Maximum Consecutive Decoding Errors",
158 "Error out after receiving N consecutive decoding errors "
159 "(-1 = never fail, 0 = automatic, 1 = fail on first error)",
160 -1, G_MAXINT, JPEG_DEFAULT_MAX_ERRORS,
161 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
163 gst_element_class_add_pad_template (element_class,
164 gst_static_pad_template_get (&gst_jpeg_dec_src_pad_template));
165 gst_element_class_add_pad_template (element_class,
166 gst_static_pad_template_get (&gst_jpeg_dec_sink_pad_template));
167 gst_element_class_set_static_metadata (element_class, "JPEG image decoder",
168 "Codec/Decoder/Image",
169 "Decode images from JPEG format", "Wim Taymans <wim@fluendo.com>");
171 vdec_class->stop = gst_jpeg_dec_stop;
172 vdec_class->reset = gst_jpeg_dec_reset;
173 vdec_class->parse = gst_jpeg_dec_parse;
174 vdec_class->set_format = gst_jpeg_dec_set_format;
175 vdec_class->handle_frame = gst_jpeg_dec_handle_frame;
176 vdec_class->decide_allocation = gst_jpeg_dec_decide_allocation;
178 GST_DEBUG_CATEGORY_INIT (jpeg_dec_debug, "jpegdec", 0, "JPEG decoder");
179 GST_DEBUG_CATEGORY_GET (GST_CAT_PERFORMANCE, "GST_PERFORMANCE");
183 gst_jpeg_dec_fill_input_buffer (j_decompress_ptr cinfo)
187 dec = CINFO_GET_JPEGDEC (cinfo);
188 g_return_val_if_fail (dec != NULL, FALSE);
189 g_return_val_if_fail (dec->current_frame != NULL, FALSE);
190 g_return_val_if_fail (dec->current_frame_map.data != NULL, FALSE);
192 cinfo->src->next_input_byte = dec->current_frame_map.data;
193 cinfo->src->bytes_in_buffer = dec->current_frame_map.size;
199 gst_jpeg_dec_init_source (j_decompress_ptr cinfo)
201 GST_LOG_OBJECT (CINFO_GET_JPEGDEC (cinfo), "init_source");
206 gst_jpeg_dec_skip_input_data (j_decompress_ptr cinfo, glong num_bytes)
208 GstJpegDec *dec = CINFO_GET_JPEGDEC (cinfo);
210 GST_DEBUG_OBJECT (dec, "skip %ld bytes", num_bytes);
212 if (num_bytes > 0 && cinfo->src->bytes_in_buffer >= num_bytes) {
213 cinfo->src->next_input_byte += (size_t) num_bytes;
214 cinfo->src->bytes_in_buffer -= (size_t) num_bytes;
219 gst_jpeg_dec_resync_to_restart (j_decompress_ptr cinfo, gint desired)
221 GST_LOG_OBJECT (CINFO_GET_JPEGDEC (cinfo), "resync_to_start");
226 gst_jpeg_dec_term_source (j_decompress_ptr cinfo)
228 GST_LOG_OBJECT (CINFO_GET_JPEGDEC (cinfo), "term_source");
233 gst_jpeg_dec_my_output_message (j_common_ptr cinfo)
235 return; /* do nothing */
239 gst_jpeg_dec_my_emit_message (j_common_ptr cinfo, int msg_level)
241 /* GST_LOG_OBJECT (CINFO_GET_JPEGDEC (&cinfo), "msg_level=%d", msg_level); */
246 gst_jpeg_dec_my_error_exit (j_common_ptr cinfo)
248 struct GstJpegDecErrorMgr *err_mgr = (struct GstJpegDecErrorMgr *) cinfo->err;
250 (*cinfo->err->output_message) (cinfo);
251 longjmp (err_mgr->setjmp_buffer, 1);
255 gst_jpeg_dec_init (GstJpegDec * dec)
257 GST_DEBUG ("initializing");
260 memset (&dec->cinfo, 0, sizeof (dec->cinfo));
261 memset (&dec->jerr, 0, sizeof (dec->jerr));
262 dec->cinfo.err = jpeg_std_error (&dec->jerr.pub);
263 dec->jerr.pub.output_message = gst_jpeg_dec_my_output_message;
264 dec->jerr.pub.emit_message = gst_jpeg_dec_my_emit_message;
265 dec->jerr.pub.error_exit = gst_jpeg_dec_my_error_exit;
267 jpeg_create_decompress (&dec->cinfo);
269 dec->cinfo.src = (struct jpeg_source_mgr *) &dec->jsrc;
270 dec->cinfo.src->init_source = gst_jpeg_dec_init_source;
271 dec->cinfo.src->fill_input_buffer = gst_jpeg_dec_fill_input_buffer;
272 dec->cinfo.src->skip_input_data = gst_jpeg_dec_skip_input_data;
273 dec->cinfo.src->resync_to_restart = gst_jpeg_dec_resync_to_restart;
274 dec->cinfo.src->term_source = gst_jpeg_dec_term_source;
277 /* init properties */
278 dec->idct_method = JPEG_DEFAULT_IDCT_METHOD;
279 dec->max_errors = JPEG_DEFAULT_MAX_ERRORS;
282 static inline gboolean
283 gst_jpeg_dec_parse_tag_has_entropy_segment (guint8 tag)
285 if (tag == 0xda || (tag >= 0xd0 && tag <= 0xd7))
291 gst_jpeg_dec_parse (GstVideoDecoder * bdec, GstVideoCodecFrame * frame,
292 GstAdapter * adapter, gboolean at_eos)
297 gint offset = 0, noffset;
298 GstJpegDec *dec = (GstJpegDec *) bdec;
300 /* FIXME : The overhead of using scan_uint32 is massive */
302 size = gst_adapter_available (adapter);
303 GST_DEBUG ("Parsing jpeg image data (%u bytes)", size);
306 GST_DEBUG ("Flushing all data out");
309 /* If we have leftover data, throw it away */
310 if (!dec->saw_header)
312 goto have_full_frame;
318 if (!dec->saw_header) {
320 /* we expect at least 4 bytes, first of which start marker */
322 gst_adapter_masked_scan_uint32 (adapter, 0xffff0000, 0xffd80000, 0,
325 GST_DEBUG ("ret:%d", ret);
330 gst_adapter_flush (adapter, ret);
333 dec->saw_header = TRUE;
340 GST_DEBUG ("offset:%d, size:%d", offset, size);
343 gst_adapter_masked_scan_uint32_peek (adapter, 0x0000ff00, 0x0000ff00,
344 offset, size - offset, &value);
346 /* lost sync if 0xff marker not where expected */
347 if ((resync = (noffset != offset))) {
348 GST_DEBUG ("Lost sync at 0x%08x, resyncing", offset + 2);
350 /* may have marker, but could have been resyncng */
351 resync = resync || dec->parse_resync;
352 /* Skip over extra 0xff */
353 while ((noffset >= 0) && ((value & 0xff) == 0xff)) {
356 gst_adapter_masked_scan_uint32_peek (adapter, 0x0000ff00, 0x0000ff00,
357 noffset, size - noffset, &value);
359 /* enough bytes left for marker? (we need 0xNN after the 0xff) */
361 GST_DEBUG ("at end of input and no EOI marker found, need more data");
365 /* now lock on the marker we found */
367 value = value & 0xff;
369 GST_DEBUG ("0x%08x: EOI marker", offset + 2);
370 /* clear parse state */
371 dec->saw_header = FALSE;
372 dec->parse_resync = FALSE;
374 goto have_full_frame;
377 /* Skip this frame if we found another SOI marker */
378 GST_DEBUG ("0x%08x: SOI marker before EOI, skipping", offset + 2);
379 dec->parse_resync = FALSE;
380 /* FIXME : Need to skip data */
382 goto have_full_frame;
386 if (value >= 0xd0 && value <= 0xd7)
389 /* peek tag and subsequent length */
390 if (offset + 2 + 4 > size)
393 gst_adapter_masked_scan_uint32_peek (adapter, 0x0, 0x0, offset + 2, 4,
395 frame_len = frame_len & 0xffff;
397 GST_DEBUG ("0x%08x: tag %02x, frame_len=%u", offset + 2, value, frame_len);
398 /* the frame length includes the 2 bytes for the length; here we want at
399 * least 2 more bytes at the end for an end marker */
400 if (offset + 2 + 2 + frame_len + 2 > size) {
404 if (gst_jpeg_dec_parse_tag_has_entropy_segment (value)) {
405 guint eseglen = dec->parse_entropy_len;
407 GST_DEBUG ("0x%08x: finding entropy segment length (eseglen:%d)",
408 offset + 2, eseglen);
409 if (size < offset + 2 + frame_len + eseglen)
411 noffset = offset + 2 + frame_len + dec->parse_entropy_len;
413 GST_DEBUG ("noffset:%d, size:%d, size - noffset:%d",
414 noffset, size, size - noffset);
415 noffset = gst_adapter_masked_scan_uint32_peek (adapter, 0x0000ff00,
416 0x0000ff00, noffset, size - noffset, &value);
419 dec->parse_entropy_len = size - offset - 4 - frame_len - 2;
422 if ((value & 0xff) != 0x00) {
423 eseglen = noffset - offset - frame_len - 2;
428 dec->parse_entropy_len = 0;
429 frame_len += eseglen;
430 GST_DEBUG ("entropy segment length=%u => frame_len=%u", eseglen,
434 /* check if we will still be in sync if we interpret
435 * this as a sync point and skip this frame */
436 noffset = offset + frame_len + 2;
437 noffset = gst_adapter_masked_scan_uint32 (adapter, 0x0000ff00, 0x0000ff00,
440 /* ignore and continue resyncing until we hit the end
441 * of our data or find a sync point that looks okay */
445 GST_DEBUG ("found sync at 0x%x", offset + 2);
448 /* Add current data to output buffer */
449 toadd += frame_len + 2;
450 offset += frame_len + 2;
455 gst_video_decoder_add_to_frame (bdec, toadd);
456 return GST_VIDEO_DECODER_FLOW_NEED_DATA;
460 gst_video_decoder_add_to_frame (bdec, toadd);
461 return gst_video_decoder_have_frame (bdec);
464 gst_adapter_flush (adapter, size);
469 /* shamelessly ripped from jpegutils.c in mjpegtools */
471 add_huff_table (j_decompress_ptr dinfo,
472 JHUFF_TBL ** htblptr, const UINT8 * bits, const UINT8 * val)
473 /* Define a Huffman table */
477 if (*htblptr == NULL)
478 *htblptr = jpeg_alloc_huff_table ((j_common_ptr) dinfo);
482 /* Copy the number-of-symbols-of-each-code-length counts */
483 memcpy ((*htblptr)->bits, bits, sizeof ((*htblptr)->bits));
485 /* Validate the counts. We do this here mainly so we can copy the right
486 * number of symbols from the val[] array, without risking marching off
487 * the end of memory. jchuff.c will do a more thorough test later.
490 for (len = 1; len <= 16; len++)
491 nsymbols += bits[len];
492 if (nsymbols < 1 || nsymbols > 256)
493 g_error ("jpegutils.c: add_huff_table failed badly. ");
495 memcpy ((*htblptr)->huffval, val, nsymbols * sizeof (UINT8));
501 std_huff_tables (j_decompress_ptr dinfo)
502 /* Set up the standard Huffman tables (cf. JPEG standard section K.3) */
503 /* IMPORTANT: these are only valid for 8-bit data precision! */
505 static const UINT8 bits_dc_luminance[17] =
506 { /* 0-base */ 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 };
507 static const UINT8 val_dc_luminance[] =
508 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
510 static const UINT8 bits_dc_chrominance[17] =
511 { /* 0-base */ 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 };
512 static const UINT8 val_dc_chrominance[] =
513 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
515 static const UINT8 bits_ac_luminance[17] =
516 { /* 0-base */ 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d };
517 static const UINT8 val_ac_luminance[] =
518 { 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
519 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
520 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
521 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
522 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
523 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
524 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
525 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
526 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
527 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
528 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
529 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
530 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
531 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
532 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
533 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
534 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
535 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
536 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
537 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
541 static const UINT8 bits_ac_chrominance[17] =
542 { /* 0-base */ 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77 };
543 static const UINT8 val_ac_chrominance[] =
544 { 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
545 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
546 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
547 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
548 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
549 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
550 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
551 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
552 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
553 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
554 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
555 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
556 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
557 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
558 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
559 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
560 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
561 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
562 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
563 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
567 add_huff_table (dinfo, &dinfo->dc_huff_tbl_ptrs[0],
568 bits_dc_luminance, val_dc_luminance);
569 add_huff_table (dinfo, &dinfo->ac_huff_tbl_ptrs[0],
570 bits_ac_luminance, val_ac_luminance);
571 add_huff_table (dinfo, &dinfo->dc_huff_tbl_ptrs[1],
572 bits_dc_chrominance, val_dc_chrominance);
573 add_huff_table (dinfo, &dinfo->ac_huff_tbl_ptrs[1],
574 bits_ac_chrominance, val_ac_chrominance);
580 guarantee_huff_tables (j_decompress_ptr dinfo)
582 if ((dinfo->dc_huff_tbl_ptrs[0] == NULL) &&
583 (dinfo->dc_huff_tbl_ptrs[1] == NULL) &&
584 (dinfo->ac_huff_tbl_ptrs[0] == NULL) &&
585 (dinfo->ac_huff_tbl_ptrs[1] == NULL)) {
586 GST_DEBUG ("Generating standard Huffman tables for this frame.");
587 std_huff_tables (dinfo);
592 gst_jpeg_dec_set_format (GstVideoDecoder * dec, GstVideoCodecState * state)
594 GstJpegDec *jpeg = GST_JPEG_DEC (dec);
595 GstVideoInfo *info = &state->info;
597 /* FIXME : previously jpegdec would handled input as packetized
598 * if the framerate was present. Here we consider it packetized if
599 * the fps is != 1/1 */
600 if (GST_VIDEO_INFO_FPS_N (info) != 1 && GST_VIDEO_INFO_FPS_D (info) != 1)
601 gst_video_decoder_set_packetized (dec, TRUE);
603 gst_video_decoder_set_packetized (dec, FALSE);
605 if (jpeg->input_state)
606 gst_video_codec_state_unref (jpeg->input_state);
607 jpeg->input_state = gst_video_codec_state_ref (state);
615 hresamplecpy1 (guint8 * dest, const guint8 * src, guint len)
619 for (i = 0; i < len; ++i) {
620 /* equivalent to: dest[i] = src[i << 1] */
629 gst_jpeg_dec_free_buffers (GstJpegDec * dec)
633 for (i = 0; i < 16; i++) {
634 g_free (dec->idr_y[i]);
635 g_free (dec->idr_u[i]);
636 g_free (dec->idr_v[i]);
637 dec->idr_y[i] = NULL;
638 dec->idr_u[i] = NULL;
639 dec->idr_v[i] = NULL;
642 dec->idr_width_allocated = 0;
645 static inline gboolean
646 gst_jpeg_dec_ensure_buffers (GstJpegDec * dec, guint maxrowbytes)
650 if (G_LIKELY (dec->idr_width_allocated == maxrowbytes))
653 /* FIXME: maybe just alloc one or three blocks altogether? */
654 for (i = 0; i < 16; i++) {
655 dec->idr_y[i] = g_try_realloc (dec->idr_y[i], maxrowbytes);
656 dec->idr_u[i] = g_try_realloc (dec->idr_u[i], maxrowbytes);
657 dec->idr_v[i] = g_try_realloc (dec->idr_v[i], maxrowbytes);
659 if (G_UNLIKELY (!dec->idr_y[i] || !dec->idr_u[i] || !dec->idr_v[i])) {
660 GST_WARNING_OBJECT (dec, "out of memory, i=%d, bytes=%u", i, maxrowbytes);
665 dec->idr_width_allocated = maxrowbytes;
666 GST_LOG_OBJECT (dec, "allocated temp memory, %u bytes/row", maxrowbytes);
671 gst_jpeg_dec_decode_grayscale (GstJpegDec * dec, GstVideoFrame * frame)
674 guchar **scanarray[1] = { rows };
679 gint pstride, rstride;
681 GST_DEBUG_OBJECT (dec, "indirect decoding of grayscale");
683 width = GST_VIDEO_FRAME_WIDTH (frame);
684 height = GST_VIDEO_FRAME_HEIGHT (frame);
686 if (G_UNLIKELY (!gst_jpeg_dec_ensure_buffers (dec, GST_ROUND_UP_32 (width))))
689 base[0] = GST_VIDEO_FRAME_COMP_DATA (frame, 0);
690 pstride = GST_VIDEO_FRAME_COMP_PSTRIDE (frame, 0);
691 rstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0);
693 memcpy (rows, dec->idr_y, 16 * sizeof (gpointer));
697 lines = jpeg_read_raw_data (&dec->cinfo, scanarray, DCTSIZE);
698 if (G_LIKELY (lines > 0)) {
699 for (j = 0; (j < DCTSIZE) && (i < height); j++, i++) {
703 for (k = 0; k < width; k++) {
704 base[0][p] = rows[j][k];
710 GST_INFO_OBJECT (dec, "jpeg_read_raw_data() returned 0");
716 gst_jpeg_dec_decode_rgb (GstJpegDec * dec, GstVideoFrame * frame)
718 guchar *r_rows[16], *g_rows[16], *b_rows[16];
719 guchar **scanarray[3] = { r_rows, g_rows, b_rows };
723 guint pstride, rstride;
726 GST_DEBUG_OBJECT (dec, "indirect decoding of RGB");
728 width = GST_VIDEO_FRAME_WIDTH (frame);
729 height = GST_VIDEO_FRAME_HEIGHT (frame);
731 if (G_UNLIKELY (!gst_jpeg_dec_ensure_buffers (dec, GST_ROUND_UP_32 (width))))
734 for (i = 0; i < 3; i++)
735 base[i] = GST_VIDEO_FRAME_COMP_DATA (frame, i);
737 pstride = GST_VIDEO_FRAME_COMP_PSTRIDE (frame, 0);
738 rstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0);
740 memcpy (r_rows, dec->idr_y, 16 * sizeof (gpointer));
741 memcpy (g_rows, dec->idr_u, 16 * sizeof (gpointer));
742 memcpy (b_rows, dec->idr_v, 16 * sizeof (gpointer));
746 lines = jpeg_read_raw_data (&dec->cinfo, scanarray, DCTSIZE);
747 if (G_LIKELY (lines > 0)) {
748 for (j = 0; (j < DCTSIZE) && (i < height); j++, i++) {
752 for (k = 0; k < width; k++) {
753 base[0][p] = r_rows[j][k];
754 base[1][p] = g_rows[j][k];
755 base[2][p] = b_rows[j][k];
763 GST_INFO_OBJECT (dec, "jpeg_read_raw_data() returned 0");
769 gst_jpeg_dec_decode_indirect (GstJpegDec * dec, GstVideoFrame * frame, gint r_v,
772 guchar *y_rows[16], *u_rows[16], *v_rows[16];
773 guchar **scanarray[3] = { y_rows, u_rows, v_rows };
776 guchar *base[3], *last[3];
780 GST_DEBUG_OBJECT (dec,
781 "unadvantageous width or r_h, taking slow route involving memcpy");
783 width = GST_VIDEO_FRAME_WIDTH (frame);
784 height = GST_VIDEO_FRAME_HEIGHT (frame);
786 if (G_UNLIKELY (!gst_jpeg_dec_ensure_buffers (dec, GST_ROUND_UP_32 (width))))
789 for (i = 0; i < 3; i++) {
790 base[i] = GST_VIDEO_FRAME_COMP_DATA (frame, i);
791 stride[i] = GST_VIDEO_FRAME_COMP_STRIDE (frame, i);
792 /* make sure we don't make jpeglib write beyond our buffer,
793 * which might happen if (height % (r_v*DCTSIZE)) != 0 */
794 last[i] = base[i] + (GST_VIDEO_FRAME_COMP_STRIDE (frame, i) *
795 (GST_VIDEO_FRAME_COMP_HEIGHT (frame, i) - 1));
798 memcpy (y_rows, dec->idr_y, 16 * sizeof (gpointer));
799 memcpy (u_rows, dec->idr_u, 16 * sizeof (gpointer));
800 memcpy (v_rows, dec->idr_v, 16 * sizeof (gpointer));
802 /* fill chroma components for grayscale */
804 GST_DEBUG_OBJECT (dec, "grayscale, filling chroma");
805 for (i = 0; i < 16; i++) {
806 memset (u_rows[i], GST_ROUND_UP_32 (width), 0x80);
807 memset (v_rows[i], GST_ROUND_UP_32 (width), 0x80);
811 for (i = 0; i < height; i += r_v * DCTSIZE) {
812 lines = jpeg_read_raw_data (&dec->cinfo, scanarray, r_v * DCTSIZE);
813 if (G_LIKELY (lines > 0)) {
814 for (j = 0, k = 0; j < (r_v * DCTSIZE); j += r_v, k++) {
815 if (G_LIKELY (base[0] <= last[0])) {
816 memcpy (base[0], y_rows[j], stride[0]);
817 base[0] += stride[0];
820 if (G_LIKELY (base[0] <= last[0])) {
821 memcpy (base[0], y_rows[j + 1], stride[0]);
822 base[0] += stride[0];
825 if (G_LIKELY (base[1] <= last[1] && base[2] <= last[2])) {
827 memcpy (base[1], u_rows[k], stride[1]);
828 memcpy (base[2], v_rows[k], stride[2]);
829 } else if (r_h == 1) {
830 hresamplecpy1 (base[1], u_rows[k], stride[1]);
831 hresamplecpy1 (base[2], v_rows[k], stride[2]);
833 /* FIXME: implement (at least we avoid crashing by doing nothing) */
837 if (r_v == 2 || (k & 1) != 0) {
838 base[1] += stride[1];
839 base[2] += stride[2];
843 GST_INFO_OBJECT (dec, "jpeg_read_raw_data() returned 0");
849 gst_jpeg_dec_decode_direct (GstJpegDec * dec, GstVideoFrame * frame)
851 guchar **line[3]; /* the jpeg line buffer */
852 guchar *y[4 * DCTSIZE] = { NULL, }; /* alloc enough for the lines */
853 guchar *u[4 * DCTSIZE] = { NULL, }; /* r_v will be <4 */
854 guchar *v[4 * DCTSIZE] = { NULL, };
856 gint lines, v_samp[3];
857 guchar *base[3], *last[3];
865 v_samp[0] = dec->cinfo.comp_info[0].v_samp_factor;
866 v_samp[1] = dec->cinfo.comp_info[1].v_samp_factor;
867 v_samp[2] = dec->cinfo.comp_info[2].v_samp_factor;
869 if (G_UNLIKELY (v_samp[0] > 2 || v_samp[1] > 2 || v_samp[2] > 2))
870 goto format_not_supported;
872 height = GST_VIDEO_FRAME_HEIGHT (frame);
874 for (i = 0; i < 3; i++) {
875 base[i] = GST_VIDEO_FRAME_COMP_DATA (frame, i);
876 stride[i] = GST_VIDEO_FRAME_COMP_STRIDE (frame, i);
877 /* make sure we don't make jpeglib write beyond our buffer,
878 * which might happen if (height % (r_v*DCTSIZE)) != 0 */
879 last[i] = base[i] + (GST_VIDEO_FRAME_COMP_STRIDE (frame, i) *
880 (GST_VIDEO_FRAME_COMP_HEIGHT (frame, i) - 1));
883 /* let jpeglib decode directly into our final buffer */
884 GST_DEBUG_OBJECT (dec, "decoding directly into output buffer");
886 for (i = 0; i < height; i += v_samp[0] * DCTSIZE) {
887 for (j = 0; j < (v_samp[0] * DCTSIZE); ++j) {
889 line[0][j] = base[0] + (i + j) * stride[0];
890 if (G_UNLIKELY (line[0][j] > last[0]))
891 line[0][j] = last[0];
893 if (v_samp[1] == v_samp[0]) {
894 line[1][j] = base[1] + ((i + j) / 2) * stride[1];
895 } else if (j < (v_samp[1] * DCTSIZE)) {
896 line[1][j] = base[1] + ((i / 2) + j) * stride[1];
898 if (G_UNLIKELY (line[1][j] > last[1]))
899 line[1][j] = last[1];
901 if (v_samp[2] == v_samp[0]) {
902 line[2][j] = base[2] + ((i + j) / 2) * stride[2];
903 } else if (j < (v_samp[2] * DCTSIZE)) {
904 line[2][j] = base[2] + ((i / 2) + j) * stride[2];
906 if (G_UNLIKELY (line[2][j] > last[2]))
907 line[2][j] = last[2];
910 lines = jpeg_read_raw_data (&dec->cinfo, line, v_samp[0] * DCTSIZE);
911 if (G_UNLIKELY (!lines)) {
912 GST_INFO_OBJECT (dec, "jpeg_read_raw_data() returned 0");
917 format_not_supported:
919 gboolean ret = GST_FLOW_OK;
921 GST_VIDEO_DECODER_ERROR (dec, 1, STREAM, DECODE,
922 (_("Failed to decode JPEG image")),
923 ("Unsupported subsampling schema: v_samp factors: %u %u %u", v_samp[0],
924 v_samp[1], v_samp[2]), ret);
931 gst_jpeg_dec_negotiate (GstJpegDec * dec, gint width, gint height, gint clrspc)
933 GstVideoCodecState *outstate;
935 GstVideoFormat format;
939 format = GST_VIDEO_FORMAT_RGB;
942 format = GST_VIDEO_FORMAT_GRAY8;
945 format = GST_VIDEO_FORMAT_I420;
949 /* Compare to currently configured output state */
950 outstate = gst_video_decoder_get_output_state (GST_VIDEO_DECODER (dec));
952 info = &outstate->info;
954 if (width == GST_VIDEO_INFO_WIDTH (info) &&
955 height == GST_VIDEO_INFO_HEIGHT (info) &&
956 format == GST_VIDEO_INFO_FORMAT (info)) {
957 gst_video_codec_state_unref (outstate);
960 gst_video_codec_state_unref (outstate);
964 gst_video_decoder_set_output_state (GST_VIDEO_DECODER (dec), format,
965 width, height, dec->input_state);
972 outstate->info.colorimetry.range = GST_VIDEO_COLOR_RANGE_0_255;
973 outstate->info.colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT601;
974 outstate->info.colorimetry.transfer = GST_VIDEO_TRANSFER_UNKNOWN;
975 outstate->info.colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_UNKNOWN;
979 gst_video_codec_state_unref (outstate);
981 gst_video_decoder_negotiate (GST_VIDEO_DECODER (dec));
983 GST_DEBUG_OBJECT (dec, "max_v_samp_factor=%d", dec->cinfo.max_v_samp_factor);
984 GST_DEBUG_OBJECT (dec, "max_h_samp_factor=%d", dec->cinfo.max_h_samp_factor);
988 gst_jpeg_dec_handle_frame (GstVideoDecoder * bdec, GstVideoCodecFrame * frame)
990 GstFlowReturn ret = GST_FLOW_OK;
991 GstJpegDec *dec = (GstJpegDec *) bdec;
992 GstVideoFrame vframe;
996 gboolean need_unmap = TRUE;
997 GstVideoCodecState *state = NULL;
999 dec->current_frame = frame;
1000 gst_buffer_map (frame->input_buffer, &dec->current_frame_map, GST_MAP_READ);
1001 gst_jpeg_dec_fill_input_buffer (&dec->cinfo);
1003 if (setjmp (dec->jerr.setjmp_buffer)) {
1004 code = dec->jerr.pub.msg_code;
1006 if (code == JERR_INPUT_EOF) {
1007 GST_DEBUG ("jpeg input EOF error, we probably need more data");
1008 goto need_more_data;
1014 hdr_ok = jpeg_read_header (&dec->cinfo, TRUE);
1015 if (G_UNLIKELY (hdr_ok != JPEG_HEADER_OK)) {
1016 GST_WARNING_OBJECT (dec, "reading the header failed, %d", hdr_ok);
1019 GST_LOG_OBJECT (dec, "num_components=%d", dec->cinfo.num_components);
1020 GST_LOG_OBJECT (dec, "jpeg_color_space=%d", dec->cinfo.jpeg_color_space);
1022 if (!dec->cinfo.num_components || !dec->cinfo.comp_info)
1023 goto components_not_supported;
1025 r_h = dec->cinfo.comp_info[0].h_samp_factor;
1026 r_v = dec->cinfo.comp_info[0].v_samp_factor;
1028 GST_LOG_OBJECT (dec, "r_h = %d, r_v = %d", r_h, r_v);
1030 if (dec->cinfo.num_components > 3)
1031 goto components_not_supported;
1033 /* verify color space expectation to avoid going *boom* or bogus output */
1034 if (dec->cinfo.jpeg_color_space != JCS_YCbCr &&
1035 dec->cinfo.jpeg_color_space != JCS_GRAYSCALE &&
1036 dec->cinfo.jpeg_color_space != JCS_RGB)
1037 goto unsupported_colorspace;
1039 #ifndef GST_DISABLE_GST_DEBUG
1043 for (i = 0; i < dec->cinfo.num_components; ++i) {
1044 GST_LOG_OBJECT (dec, "[%d] h_samp_factor=%d, v_samp_factor=%d, cid=%d",
1045 i, dec->cinfo.comp_info[i].h_samp_factor,
1046 dec->cinfo.comp_info[i].v_samp_factor,
1047 dec->cinfo.comp_info[i].component_id);
1052 /* prepare for raw output */
1053 dec->cinfo.do_fancy_upsampling = FALSE;
1054 dec->cinfo.do_block_smoothing = FALSE;
1055 dec->cinfo.out_color_space = dec->cinfo.jpeg_color_space;
1056 dec->cinfo.dct_method = dec->idct_method;
1057 dec->cinfo.raw_data_out = TRUE;
1059 GST_LOG_OBJECT (dec, "starting decompress");
1060 guarantee_huff_tables (&dec->cinfo);
1061 if (!jpeg_start_decompress (&dec->cinfo)) {
1062 GST_WARNING_OBJECT (dec, "failed to start decompression cycle");
1065 /* sanity checks to get safe and reasonable output */
1066 switch (dec->cinfo.jpeg_color_space) {
1068 if (dec->cinfo.num_components != 1)
1069 goto invalid_yuvrgbgrayscale;
1072 if (dec->cinfo.num_components != 3 || dec->cinfo.max_v_samp_factor > 1 ||
1073 dec->cinfo.max_h_samp_factor > 1)
1074 goto invalid_yuvrgbgrayscale;
1077 if (dec->cinfo.num_components != 3 ||
1078 r_v > 2 || r_v < dec->cinfo.comp_info[0].v_samp_factor ||
1079 r_v < dec->cinfo.comp_info[1].v_samp_factor ||
1080 r_h < dec->cinfo.comp_info[0].h_samp_factor ||
1081 r_h < dec->cinfo.comp_info[1].h_samp_factor)
1082 goto invalid_yuvrgbgrayscale;
1085 g_assert_not_reached ();
1089 width = dec->cinfo.output_width;
1090 height = dec->cinfo.output_height;
1092 if (G_UNLIKELY (width < MIN_WIDTH || width > MAX_WIDTH ||
1093 height < MIN_HEIGHT || height > MAX_HEIGHT))
1096 gst_jpeg_dec_negotiate (dec, width, height, dec->cinfo.jpeg_color_space);
1098 state = gst_video_decoder_get_output_state (bdec);
1099 ret = gst_video_decoder_allocate_output_frame (bdec, frame);
1100 if (G_UNLIKELY (ret != GST_FLOW_OK))
1103 if (!gst_video_frame_map (&vframe, &state->info, frame->output_buffer,
1107 GST_LOG_OBJECT (dec, "width %d, height %d", width, height);
1109 if (dec->cinfo.jpeg_color_space == JCS_RGB) {
1110 gst_jpeg_dec_decode_rgb (dec, &vframe);
1111 } else if (dec->cinfo.jpeg_color_space == JCS_GRAYSCALE) {
1112 gst_jpeg_dec_decode_grayscale (dec, &vframe);
1114 GST_LOG_OBJECT (dec, "decompressing (reqired scanline buffer height = %u)",
1115 dec->cinfo.rec_outbuf_height);
1117 /* For some widths jpeglib requires more horizontal padding than I420
1118 * provides. In those cases we need to decode into separate buffers and then
1119 * copy over the data into our final picture buffer, otherwise jpeglib might
1120 * write over the end of a line into the beginning of the next line,
1121 * resulting in blocky artifacts on the left side of the picture. */
1122 if (G_UNLIKELY (width % (dec->cinfo.max_h_samp_factor * DCTSIZE) != 0
1123 || dec->cinfo.comp_info[0].h_samp_factor != 2
1124 || dec->cinfo.comp_info[1].h_samp_factor != 1
1125 || dec->cinfo.comp_info[2].h_samp_factor != 1)) {
1126 GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, dec,
1127 "indirect decoding using extra buffer copy");
1128 gst_jpeg_dec_decode_indirect (dec, &vframe, r_v, r_h,
1129 dec->cinfo.num_components);
1131 ret = gst_jpeg_dec_decode_direct (dec, &vframe);
1133 if (G_UNLIKELY (ret != GST_FLOW_OK))
1134 goto decode_direct_failed;
1138 gst_video_frame_unmap (&vframe);
1140 GST_LOG_OBJECT (dec, "decompressing finished");
1141 jpeg_finish_decompress (&dec->cinfo);
1143 gst_buffer_unmap (frame->input_buffer, &dec->current_frame_map);
1144 ret = gst_video_decoder_finish_frame (bdec, frame);
1152 gst_buffer_unmap (frame->input_buffer, &dec->current_frame_map);
1155 gst_video_codec_state_unref (state);
1162 GST_LOG_OBJECT (dec, "we need more data");
1169 GST_VIDEO_DECODER_ERROR (dec, 1, STREAM, DECODE,
1170 (_("Failed to decode JPEG image")),
1171 ("Picture is too small or too big (%ux%u)", width, height), ret);
1172 ret = GST_FLOW_ERROR;
1177 gchar err_msg[JMSG_LENGTH_MAX];
1179 dec->jerr.pub.format_message ((j_common_ptr) (&dec->cinfo), err_msg);
1181 GST_VIDEO_DECODER_ERROR (dec, 1, STREAM, DECODE,
1182 (_("Failed to decode JPEG image")), ("Decode error #%u: %s", code,
1185 gst_buffer_unmap (frame->input_buffer, &dec->current_frame_map);
1186 gst_video_decoder_drop_frame (bdec, frame);
1188 jpeg_abort_decompress (&dec->cinfo);
1190 ret = GST_FLOW_ERROR;
1193 decode_direct_failed:
1195 /* already posted an error message */
1196 jpeg_abort_decompress (&dec->cinfo);
1201 const gchar *reason;
1203 reason = gst_flow_get_name (ret);
1205 GST_DEBUG_OBJECT (dec, "failed to alloc buffer, reason %s", reason);
1206 /* Reset for next time */
1207 jpeg_abort_decompress (&dec->cinfo);
1208 if (ret != GST_FLOW_EOS && ret != GST_FLOW_FLUSHING &&
1209 ret != GST_FLOW_NOT_LINKED) {
1210 GST_VIDEO_DECODER_ERROR (dec, 1, STREAM, DECODE,
1211 (_("Failed to decode JPEG image")),
1212 ("Buffer allocation failed, reason: %s", reason), ret);
1213 jpeg_abort_decompress (&dec->cinfo);
1217 components_not_supported:
1219 GST_VIDEO_DECODER_ERROR (dec, 1, STREAM, DECODE,
1220 (_("Failed to decode JPEG image")),
1221 ("number of components not supported: %d (max 3)",
1222 dec->cinfo.num_components), ret);
1223 jpeg_abort_decompress (&dec->cinfo);
1226 unsupported_colorspace:
1228 GST_VIDEO_DECODER_ERROR (dec, 1, STREAM, DECODE,
1229 (_("Failed to decode JPEG image")),
1230 ("Picture has unknown or unsupported colourspace"), ret);
1231 jpeg_abort_decompress (&dec->cinfo);
1234 invalid_yuvrgbgrayscale:
1236 GST_VIDEO_DECODER_ERROR (dec, 1, STREAM, DECODE,
1237 (_("Failed to decode JPEG image")),
1238 ("Picture is corrupt or unhandled YUV/RGB/grayscale layout"), ret);
1239 jpeg_abort_decompress (&dec->cinfo);
1245 gst_jpeg_dec_decide_allocation (GstVideoDecoder * bdec, GstQuery * query)
1247 GstBufferPool *pool = NULL;
1248 GstStructure *config;
1250 if (!GST_VIDEO_DECODER_CLASS (parent_class)->decide_allocation (bdec, query))
1253 if (gst_query_get_n_allocation_pools (query) > 0)
1254 gst_query_parse_nth_allocation_pool (query, 0, &pool, NULL, NULL, NULL);
1259 config = gst_buffer_pool_get_config (pool);
1260 if (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL)) {
1261 gst_buffer_pool_config_add_option (config,
1262 GST_BUFFER_POOL_OPTION_VIDEO_META);
1264 gst_buffer_pool_set_config (pool, config);
1265 gst_object_unref (pool);
1271 gst_jpeg_dec_reset (GstVideoDecoder * bdec, gboolean hard)
1273 GstJpegDec *dec = (GstJpegDec *) bdec;
1275 jpeg_abort_decompress (&dec->cinfo);
1276 dec->parse_entropy_len = 0;
1277 dec->parse_resync = FALSE;
1278 dec->saw_header = FALSE;
1281 dec->parse_entropy_len = 0;
1282 dec->parse_resync = FALSE;
1284 gst_video_decoder_set_packetized (bdec, FALSE);
1291 gst_jpeg_dec_set_property (GObject * object, guint prop_id,
1292 const GValue * value, GParamSpec * pspec)
1296 dec = GST_JPEG_DEC (object);
1299 case PROP_IDCT_METHOD:
1300 dec->idct_method = g_value_get_enum (value);
1302 case PROP_MAX_ERRORS:
1303 g_atomic_int_set (&dec->max_errors, g_value_get_int (value));
1307 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1313 gst_jpeg_dec_get_property (GObject * object, guint prop_id, GValue * value,
1318 dec = GST_JPEG_DEC (object);
1321 case PROP_IDCT_METHOD:
1322 g_value_set_enum (value, dec->idct_method);
1324 case PROP_MAX_ERRORS:
1325 g_value_set_int (value, g_atomic_int_get (&dec->max_errors));
1329 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1335 gst_jpeg_dec_stop (GstVideoDecoder * bdec)
1337 GstJpegDec *dec = (GstJpegDec *) bdec;
1339 gst_jpeg_dec_free_buffers (dec);