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
27 * Decodes jpeg images.
29 * ## Example launch line
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.
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>
50 /* Disable libjpeg-turbo support for now, due to unresolved cornercases */
54 #define MAX_WIDTH 65535
56 #define MAX_HEIGHT 65535
58 #define CINFO_GET_JPEGDEC(cinfo_ptr) \
59 (((struct GstJpegDecSourceMgr*)((cinfo_ptr)->src))->dec)
61 #define JPEG_DEFAULT_IDCT_METHOD JDCT_FASTEST
62 #define JPEG_DEFAULT_MAX_ERRORS 0
72 static GstStaticPadTemplate gst_jpeg_dec_src_pad_template =
73 GST_STATIC_PAD_TEMPLATE ("src",
76 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE
77 ("{ I420, RGB, BGR, RGBx, xRGB, BGRx, xBGR, GRAY8 }"))
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",
88 GST_STATIC_CAPS ("image/jpeg")
91 GST_DEBUG_CATEGORY_STATIC (jpeg_dec_debug);
92 #define GST_CAT_DEFAULT jpeg_dec_debug
93 GST_DEBUG_CATEGORY_STATIC (GST_CAT_PERFORMANCE);
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);
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,
111 static gboolean gst_jpeg_dec_sink_event (GstVideoDecoder * bdec,
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,
120 gst_jpeg_dec_finalize (GObject * object)
122 GstJpegDec *dec = GST_JPEG_DEC (object);
124 jpeg_destroy_decompress (&dec->cinfo);
125 if (dec->input_state)
126 gst_video_codec_state_unref (dec->input_state);
128 G_OBJECT_CLASS (parent_class)->finalize (object);
132 gst_jpeg_dec_class_init (GstJpegDecClass * klass)
134 GObjectClass *gobject_class;
135 GstElementClass *element_class;
136 GstVideoDecoderClass *vdec_class;
138 gobject_class = (GObjectClass *) klass;
139 element_class = (GstElementClass *) klass;
140 vdec_class = (GstVideoDecoderClass *) klass;
142 parent_class = g_type_class_peek_parent (klass);
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;
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));
155 * GstJpegDec:max-errors:
157 * Error out after receiving N consecutive decoding errors
158 * (-1 = never error out, 0 = automatic, 1 = fail on first error, etc.)
160 * Deprecated: 1.3.1: Property wasn't used internally
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));
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>");
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;
188 GST_DEBUG_CATEGORY_INIT (jpeg_dec_debug, "jpegdec", 0, "JPEG decoder");
189 GST_DEBUG_CATEGORY_GET (GST_CAT_PERFORMANCE, "GST_PERFORMANCE");
191 gst_type_mark_as_plugin_api (GST_TYPE_IDCT_METHOD, 0);
195 gst_jpeg_dec_fill_input_buffer (j_decompress_ptr cinfo)
197 /* We pass in full frame initially, if this get called, the frame is most likely
203 gst_jpeg_dec_init_source (j_decompress_ptr cinfo)
205 GST_LOG_OBJECT (CINFO_GET_JPEGDEC (cinfo), "init_source");
210 gst_jpeg_dec_skip_input_data (j_decompress_ptr cinfo, glong num_bytes)
212 GstJpegDec *dec = CINFO_GET_JPEGDEC (cinfo);
214 GST_DEBUG_OBJECT (dec, "skip %ld bytes", num_bytes);
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;
223 gst_jpeg_dec_resync_to_restart (j_decompress_ptr cinfo, gint desired)
225 GST_LOG_OBJECT (CINFO_GET_JPEGDEC (cinfo), "resync_to_start");
230 gst_jpeg_dec_term_source (j_decompress_ptr cinfo)
232 GST_LOG_OBJECT (CINFO_GET_JPEGDEC (cinfo), "term_source");
237 gst_jpeg_dec_my_output_message (j_common_ptr cinfo)
239 return; /* do nothing */
243 gst_jpeg_dec_my_emit_message (j_common_ptr cinfo, int msg_level)
245 /* GST_LOG_OBJECT (CINFO_GET_JPEGDEC (&cinfo), "msg_level=%d", msg_level); */
250 gst_jpeg_dec_my_error_exit (j_common_ptr cinfo)
252 struct GstJpegDecErrorMgr *err_mgr = (struct GstJpegDecErrorMgr *) cinfo->err;
254 (*cinfo->err->output_message) (cinfo);
255 longjmp (err_mgr->setjmp_buffer, 1);
259 gst_jpeg_dec_init (GstJpegDec * dec)
261 GST_DEBUG ("initializing");
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;
271 jpeg_create_decompress (&dec->cinfo);
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;
281 /* init properties */
282 dec->idct_method = JPEG_DEFAULT_IDCT_METHOD;
283 dec->max_errors = JPEG_DEFAULT_MAX_ERRORS;
285 gst_video_decoder_set_use_default_pad_acceptcaps (GST_VIDEO_DECODER_CAST
287 GST_PAD_SET_ACCEPT_TEMPLATE (GST_VIDEO_DECODER_SINK_PAD (dec));
290 static inline gboolean
291 gst_jpeg_dec_parse_tag_has_entropy_segment (guint8 tag)
293 if (tag == 0xda || (tag >= 0xd0 && tag <= 0xd7))
299 gst_jpeg_dec_parse (GstVideoDecoder * bdec, GstVideoCodecFrame * frame,
300 GstAdapter * adapter, gboolean at_eos)
305 gint offset = 0, noffset;
306 GstJpegDec *dec = (GstJpegDec *) bdec;
308 GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
310 /* FIXME : The overhead of using scan_uint32 is massive */
312 size = gst_adapter_available (adapter);
313 GST_DEBUG ("Parsing jpeg image data (%u bytes)", size);
316 GST_DEBUG ("Flushing all data out");
319 /* If we have leftover data, throw it away */
320 if (!dec->saw_header)
322 goto have_full_frame;
328 if (!dec->saw_header) {
330 /* we expect at least 4 bytes, first of which start marker */
332 gst_adapter_masked_scan_uint32 (adapter, 0xffff0000, 0xffd80000, 0,
335 GST_DEBUG ("ret:%d", ret);
340 gst_adapter_flush (adapter, ret);
343 dec->saw_header = TRUE;
350 GST_DEBUG ("offset:%d, size:%d", offset, size);
353 gst_adapter_masked_scan_uint32_peek (adapter, 0x0000ff00, 0x0000ff00,
354 offset, size - offset, &value);
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);
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)) {
366 gst_adapter_masked_scan_uint32_peek (adapter, 0x0000ff00, 0x0000ff00,
367 noffset, size - noffset, &value);
369 /* enough bytes left for marker? (we need 0xNN after the 0xff) */
371 GST_DEBUG ("at end of input and no EOI marker found, need more data");
375 /* now lock on the marker we found */
377 value = value & 0xff;
379 GST_DEBUG ("0x%08x: EOI marker", offset + 2);
380 /* clear parse state */
381 dec->saw_header = FALSE;
382 dec->parse_resync = FALSE;
384 goto have_full_frame;
387 GST_DEBUG ("0x%08x: SOI marker before EOI marker", offset + 2);
389 /* clear parse state */
390 dec->saw_header = FALSE;
391 dec->parse_resync = FALSE;
393 goto have_full_frame;
397 if (value >= 0xd0 && value <= 0xd7)
400 /* peek tag and subsequent length */
401 if (offset + 2 + 4 > size)
404 gst_adapter_masked_scan_uint32_peek (adapter, 0x0, 0x0, offset + 2, 4,
406 frame_len = frame_len & 0xffff;
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) {
415 if (gst_jpeg_dec_parse_tag_has_entropy_segment (value)) {
416 guint eseglen = dec->parse_entropy_len;
418 GST_DEBUG ("0x%08x: finding entropy segment length (eseglen:%d)",
419 offset + 2, eseglen);
420 if (size < offset + 2 + frame_len + eseglen)
422 noffset = offset + 2 + frame_len + dec->parse_entropy_len;
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);
430 dec->parse_entropy_len = size - offset - 4 - frame_len - 2;
433 if ((value & 0xff) != 0x00) {
434 eseglen = noffset - offset - frame_len - 2;
439 dec->parse_entropy_len = 0;
440 frame_len += eseglen;
441 GST_DEBUG ("entropy segment length=%u => frame_len=%u", eseglen,
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,
451 /* ignore and continue resyncing until we hit the end
452 * of our data or find a sync point that looks okay */
456 GST_DEBUG ("found sync at 0x%x", offset + 2);
459 /* Add current data to output buffer */
460 toadd += frame_len + 2;
461 offset += frame_len + 2;
466 gst_video_decoder_add_to_frame (bdec, toadd);
467 return GST_VIDEO_DECODER_FLOW_NEED_DATA;
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);
476 gst_adapter_flush (adapter, size);
481 /* shamelessly ripped from jpegutils.c in mjpegtools */
483 add_huff_table (j_decompress_ptr dinfo,
484 JHUFF_TBL ** htblptr, const UINT8 * bits, const UINT8 * val)
485 /* Define a Huffman table */
489 if (*htblptr == NULL)
490 *htblptr = jpeg_alloc_huff_table ((j_common_ptr) dinfo);
494 /* Copy the number-of-symbols-of-each-code-length counts */
495 memcpy ((*htblptr)->bits, bits, sizeof ((*htblptr)->bits));
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.
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. ");
507 memcpy ((*htblptr)->huffval, val, nsymbols * sizeof (UINT8));
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! */
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 };
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 };
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,
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,
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);
592 guarantee_huff_tables (j_decompress_ptr dinfo)
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);
604 gst_jpeg_dec_set_format (GstVideoDecoder * dec, GstVideoCodecState * state)
606 GstJpegDec *jpeg = GST_JPEG_DEC (dec);
607 GstStructure *structure;
608 gboolean parsed = FALSE;
610 if (jpeg->input_state)
611 gst_video_codec_state_unref (jpeg->input_state);
612 jpeg->input_state = gst_video_codec_state_ref (state);
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);
624 hresamplecpy1 (guint8 * dest, const guint8 * src, guint len)
628 for (i = 0; i < len; ++i) {
629 /* equivalent to: dest[i] = src[i << 1] */
638 gst_jpeg_dec_free_buffers (GstJpegDec * dec)
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;
651 dec->idr_width_allocated = 0;
654 static inline gboolean
655 gst_jpeg_dec_ensure_buffers (GstJpegDec * dec, guint maxrowbytes)
659 if (G_LIKELY (dec->idr_width_allocated == maxrowbytes))
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);
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);
674 dec->idr_width_allocated = maxrowbytes;
675 GST_LOG_OBJECT (dec, "allocated temp memory, %u bytes/row", maxrowbytes);
680 gst_jpeg_dec_decode_grayscale (GstJpegDec * dec, GstVideoFrame * frame,
681 guint field, guint num_fields)
684 guchar **scanarray[1] = { rows };
689 gint pstride, rstride;
691 GST_DEBUG_OBJECT (dec, "indirect decoding of grayscale");
693 width = GST_VIDEO_FRAME_WIDTH (frame);
694 height = GST_VIDEO_FRAME_HEIGHT (frame) / num_fields;
696 if (G_UNLIKELY (!gst_jpeg_dec_ensure_buffers (dec, GST_ROUND_UP_32 (width))))
699 base[0] = GST_VIDEO_FRAME_COMP_DATA (frame, 0);
701 base[0] += GST_VIDEO_FRAME_COMP_STRIDE (frame, 0);
704 pstride = GST_VIDEO_FRAME_COMP_PSTRIDE (frame, 0);
705 rstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0) * num_fields;
707 memcpy (rows, dec->idr_y, 16 * sizeof (gpointer));
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++) {
717 for (k = 0; k < width; k++) {
718 base[0][p] = rows[j][k];
724 GST_INFO_OBJECT (dec, "jpeg_read_raw_data() returned 0");
730 gst_jpeg_dec_decode_rgb (GstJpegDec * dec, GstVideoFrame * frame,
731 guint field, guint num_fields)
733 guchar *r_rows[16], *g_rows[16], *b_rows[16];
734 guchar **scanarray[3] = { r_rows, g_rows, b_rows };
738 guint pstride, rstride;
741 GST_DEBUG_OBJECT (dec, "indirect decoding of RGB");
743 width = GST_VIDEO_FRAME_WIDTH (frame);
744 height = GST_VIDEO_FRAME_HEIGHT (frame) / num_fields;
746 if (G_UNLIKELY (!gst_jpeg_dec_ensure_buffers (dec, GST_ROUND_UP_32 (width))))
749 for (i = 0; i < 3; i++) {
750 base[i] = GST_VIDEO_FRAME_COMP_DATA (frame, i);
752 base[i] += GST_VIDEO_FRAME_COMP_STRIDE (frame, i);
755 pstride = GST_VIDEO_FRAME_COMP_PSTRIDE (frame, 0);
756 rstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0) * num_fields;
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));
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++) {
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];
781 GST_INFO_OBJECT (dec, "jpeg_read_raw_data() returned 0");
787 gst_jpeg_dec_decode_indirect (GstJpegDec * dec, GstVideoFrame * frame, gint r_v,
788 gint r_h, gint comp, guint field, guint num_fields)
790 guchar *y_rows[16], *u_rows[16], *v_rows[16];
791 guchar **scanarray[3] = { y_rows, u_rows, v_rows };
794 guchar *base[3], *last[3];
795 gint rowsize[3], stride[3];
798 GST_DEBUG_OBJECT (dec,
799 "unadvantageous width or r_h, taking slow route involving memcpy");
801 width = GST_VIDEO_FRAME_WIDTH (frame);
802 height = GST_VIDEO_FRAME_HEIGHT (frame);
804 if (G_UNLIKELY (!gst_jpeg_dec_ensure_buffers (dec, GST_ROUND_UP_32 (width))))
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));
817 base[i] += GST_VIDEO_FRAME_COMP_STRIDE (frame, i);
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));
825 /* fill chroma components for grayscale */
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);
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];
843 if (G_LIKELY (base[0] <= last[0])) {
844 memcpy (base[0], y_rows[j + 1], rowsize[0]);
845 base[0] += stride[0];
848 if (G_LIKELY (base[1] <= last[1] && base[2] <= last[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]);
856 /* FIXME: implement (at least we avoid crashing by doing nothing) */
860 if (r_v == 2 || (k & 1) != 0) {
861 base[1] += stride[1];
862 base[2] += stride[2];
866 GST_INFO_OBJECT (dec, "jpeg_read_raw_data() returned 0");
872 gst_jpeg_dec_decode_direct (GstJpegDec * dec, GstVideoFrame * frame,
873 guint field, guint num_fields)
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, };
880 gint lines, v_samp[3];
881 guchar *base[3], *last[3];
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;
893 if (G_UNLIKELY (v_samp[0] > 2 || v_samp[1] > 2 || v_samp[2] > 2))
894 goto format_not_supported;
896 field_height = GST_VIDEO_FRAME_HEIGHT (frame);
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 */
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));
912 base[i] += GST_VIDEO_FRAME_COMP_STRIDE (frame, i);
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];
922 /* let jpeglib decode directly into our final buffer */
923 GST_DEBUG_OBJECT (dec, "decoding directly into output buffer");
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);
930 if (num_fields == 2) {
935 bufbase += GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0);
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;
946 for (i = 0; i < field_height; i += v_samp[0] * DCTSIZE) {
947 for (j = 0; j < (v_samp[0] * DCTSIZE); ++j) {
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;
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];
958 if (G_UNLIKELY (line[1][j] > last[1]))
959 line[1][j] = dec->scratch;
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];
966 if (G_UNLIKELY (line[2][j] > last[2]))
967 line[2][j] = dec->scratch;
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");
978 format_not_supported:
980 gboolean ret = GST_FLOW_OK;
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);
991 #ifdef JCS_EXTENSIONS
993 gst_fmt_to_jpeg_turbo_ext_fmt (GstVideoFormat gstfmt)
996 case GST_VIDEO_FORMAT_RGB:
998 case GST_VIDEO_FORMAT_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:
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;
1022 gst_jpeg_turbo_parse_ext_fmt_convert (GstJpegDec * dec, gint * clrspc)
1024 GstCaps *peer_caps, *dec_caps;
1026 dec_caps = gst_static_caps_get (&gst_jpeg_dec_src_pad_template.static_caps);
1028 gst_pad_peer_query_caps (GST_VIDEO_DECODER_SRC_PAD (dec), dec_caps);
1029 gst_caps_unref (dec_caps);
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;
1038 if (!gst_caps_is_fixed (peer_caps))
1039 peer_caps = gst_caps_fixate (peer_caps);
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);
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:
1058 dec->format = peerfmt;
1059 dec->format_convert = TRUE;
1060 dec->libjpeg_ext_format = gst_fmt_to_jpeg_turbo_ext_fmt (peerfmt);
1066 gst_caps_unref (peer_caps);
1067 GST_DEBUG_OBJECT (dec, "format_convert=%d", dec->format_convert);
1072 gst_jpeg_dec_negotiate (GstJpegDec * dec, gint width, gint height, gint clrspc,
1073 gboolean interlaced)
1075 GstVideoCodecState *outstate;
1077 GstVideoFormat format;
1079 #ifdef JCS_EXTENSIONS
1080 if (dec->format_convert) {
1081 format = dec->format;
1087 format = GST_VIDEO_FORMAT_RGB;
1090 format = GST_VIDEO_FORMAT_GRAY8;
1093 format = GST_VIDEO_FORMAT_I420;
1098 /* Compare to currently configured output state */
1099 outstate = gst_video_decoder_get_output_state (GST_VIDEO_DECODER (dec));
1101 info = &outstate->info;
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);
1109 gst_video_codec_state_unref (outstate);
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
1115 gst_jpeg_turbo_parse_ext_fmt_convert (dec, &clrspc);
1119 gst_video_decoder_set_output_state (GST_VIDEO_DECODER (dec), format,
1120 width, height, dec->input_state);
1127 /* aka JPEG chroma siting */
1128 outstate->info.chroma_site = GST_VIDEO_CHROMA_SITE_NONE;
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;
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;
1143 gst_video_codec_state_unref (outstate);
1145 gst_video_decoder_negotiate (GST_VIDEO_DECODER (dec));
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);
1151 static GstFlowReturn
1152 gst_jpeg_dec_prepare_decode (GstJpegDec * dec)
1154 G_GNUC_UNUSED GstFlowReturn ret;
1155 guint r_h, r_v, hdr_ok;
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);
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);
1166 if (!dec->cinfo.num_components || !dec->cinfo.comp_info)
1167 goto components_not_supported;
1169 r_h = dec->cinfo.comp_info[0].h_samp_factor;
1170 r_v = dec->cinfo.comp_info[0].v_samp_factor;
1172 GST_LOG_OBJECT (dec, "r_h = %d, r_v = %d", r_h, r_v);
1174 if (dec->cinfo.num_components > 3)
1175 goto components_not_supported;
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;
1183 #ifndef GST_DISABLE_GST_DEBUG
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);
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;
1208 dec->cinfo.out_color_space = dec->cinfo.jpeg_color_space;
1209 dec->cinfo.raw_data_out = TRUE;
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");
1218 /* sanity checks to get safe and reasonable output */
1219 switch (dec->cinfo.jpeg_color_space) {
1221 if (dec->cinfo.num_components != 1)
1222 goto invalid_yuvrgbgrayscale;
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;
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;
1238 g_assert_not_reached ();
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))
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;
1260 components_not_supported:
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;
1270 unsupported_colorspace:
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;
1279 invalid_yuvrgbgrayscale:
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;
1290 static GstFlowReturn
1291 gst_jpeg_dec_decode (GstJpegDec * dec, GstVideoFrame * vframe, guint width,
1292 guint height, guint field, guint num_fields)
1294 GstFlowReturn ret = GST_FLOW_OK;
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);
1301 GST_LOG_OBJECT (dec, "decompressing (required scanline buffer height = %u)",
1302 dec->cinfo.rec_outbuf_height);
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,
1320 ret = gst_jpeg_dec_decode_direct (dec, vframe, field, num_fields);
1324 GST_LOG_OBJECT (dec, "decompressing finished: %s", gst_flow_get_name (ret));
1326 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
1327 jpeg_abort_decompress (&dec->cinfo);
1329 jpeg_finish_decompress (&dec->cinfo);
1335 static GstFlowReturn
1336 gst_jpeg_dec_handle_frame (GstVideoDecoder * bdec, GstVideoCodecFrame * frame)
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) */
1346 gboolean need_unmap = TRUE;
1347 GstVideoCodecState *state = NULL;
1348 gboolean release_frame = TRUE;
1353 if (!gst_buffer_map (frame->input_buffer, &dec->current_frame_map,
1357 data = dec->current_frame_map.data;
1358 nbytes = dec->current_frame_map.size;
1360 goto need_more_data;
1361 has_eoi = ((data[nbytes - 2] == 0xff) && (data[nbytes - 1] == 0xd9));
1363 /* some cameras fail to send an end-of-image marker (EOI),
1364 * add it if that is the case. */
1367 GstBuffer *eoibuf = gst_buffer_new_and_alloc (2);
1369 /* unmap, will add EOI and remap at the end */
1370 gst_buffer_unmap (frame->input_buffer, &dec->current_frame_map);
1372 gst_buffer_map (eoibuf, &map, GST_MAP_WRITE);
1375 gst_buffer_unmap (eoibuf, &map);
1377 /* append to input buffer, and remap */
1378 frame->input_buffer = gst_buffer_append (frame->input_buffer, eoibuf);
1380 gst_buffer_map (frame->input_buffer, &dec->current_frame_map, GST_MAP_READ);
1381 GST_DEBUG ("fixup EOI marker added");
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;
1388 if (setjmp (dec->jerr.setjmp_buffer)) {
1389 code = dec->jerr.pub.msg_code;
1391 if (code == JERR_INPUT_EOF) {
1392 GST_DEBUG ("jpeg input EOF error, we probably need more data");
1393 goto need_more_data;
1398 /* read header and check values */
1399 ret = gst_jpeg_dec_prepare_decode (dec);
1400 if (G_UNLIKELY (ret == GST_FLOW_ERROR))
1403 width = dec->cinfo.output_width;
1404 height = dec->cinfo.output_height;
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,
1418 output_height = dec->input_state->info.height;
1419 height = dec->input_state->info.height / 2;
1421 GST_LOG_OBJECT (dec, "field height=%d", height);
1423 output_height = height;
1427 gst_jpeg_dec_negotiate (dec, width, output_height,
1428 dec->cinfo.jpeg_color_space, num_fields == 2);
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))
1435 if (!gst_video_frame_map (&vframe, &state->info, frame->output_buffer,
1439 if (setjmp (dec->jerr.setjmp_buffer)) {
1440 code = dec->jerr.pub.msg_code;
1441 gst_video_frame_unmap (&vframe);
1445 GST_LOG_OBJECT (dec, "width %d, height %d, fields %d", width, output_height,
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);
1454 if (setjmp (dec->jerr.setjmp_buffer)) {
1455 code = dec->jerr.pub.msg_code;
1456 gst_video_frame_unmap (&vframe);
1460 /* decode second field if there is one */
1461 if (num_fields == 2) {
1462 GstVideoFormat field2_format;
1464 /* Checked above before setting num_fields to 2 */
1465 g_assert (dec->input_state != NULL);
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;
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);
1482 /* check if format has changed for the second field */
1483 #ifdef JCS_EXTENSIONS
1484 if (dec->format_convert) {
1485 field2_format = dec->format;
1489 switch (dec->cinfo.jpeg_color_space) {
1491 field2_format = GST_VIDEO_FORMAT_RGB;
1494 field2_format = GST_VIDEO_FORMAT_GRAY8;
1497 field2_format = GST_VIDEO_FORMAT_I420;
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);
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);
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);
1523 gst_video_frame_unmap (&vframe);
1525 gst_buffer_unmap (frame->input_buffer, &dec->current_frame_map);
1526 ret = gst_video_decoder_finish_frame (bdec, frame);
1527 release_frame = FALSE;
1535 gst_buffer_unmap (frame->input_buffer, &dec->current_frame_map);
1538 gst_video_decoder_release_frame (bdec, frame);
1541 gst_video_codec_state_unref (state);
1548 GST_LOG_OBJECT (dec, "we need more data");
1555 GST_ELEMENT_ERROR (dec, RESOURCE, READ, (_("Failed to read memory")),
1556 ("gst_buffer_map() failed for READ access"));
1557 ret = GST_FLOW_ERROR;
1562 gchar err_msg[JMSG_LENGTH_MAX];
1564 dec->jerr.pub.format_message ((j_common_ptr) (&dec->cinfo), err_msg);
1566 GST_VIDEO_DECODER_ERROR (dec, 1, STREAM, DECODE,
1567 (_("Failed to decode JPEG image")), ("Decode error #%u: %s", code,
1570 gst_buffer_unmap (frame->input_buffer, &dec->current_frame_map);
1571 gst_video_decoder_drop_frame (bdec, frame);
1572 release_frame = FALSE;
1574 jpeg_abort_decompress (&dec->cinfo);
1580 /* already posted an error message */
1585 const gchar *reason;
1587 reason = gst_flow_get_name (ret);
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);
1604 gst_jpeg_dec_decide_allocation (GstVideoDecoder * bdec, GstQuery * query)
1606 GstBufferPool *pool = NULL;
1607 GstStructure *config;
1609 if (!GST_VIDEO_DECODER_CLASS (parent_class)->decide_allocation (bdec, query))
1612 if (gst_query_get_n_allocation_pools (query) > 0)
1613 gst_query_parse_nth_allocation_pool (query, 0, &pool, NULL, NULL, NULL);
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);
1623 gst_buffer_pool_set_config (pool, config);
1624 gst_object_unref (pool);
1630 gst_jpeg_dec_sink_event (GstVideoDecoder * bdec, GstEvent * event)
1632 const GstSegment *segment;
1634 if (GST_EVENT_TYPE (event) != GST_EVENT_SEGMENT)
1637 gst_event_parse_segment (event, &segment);
1639 if (segment->format == GST_FORMAT_TIME)
1640 gst_video_decoder_set_packetized (bdec, TRUE);
1642 gst_video_decoder_set_packetized (bdec, FALSE);
1645 return GST_VIDEO_DECODER_CLASS (parent_class)->sink_event (bdec, event);
1649 gst_jpeg_dec_start (GstVideoDecoder * bdec)
1651 GstJpegDec *dec = (GstJpegDec *) bdec;
1653 #ifdef JCS_EXTENSIONS
1654 dec->format_convert = FALSE;
1656 dec->saw_header = FALSE;
1657 dec->parse_entropy_len = 0;
1658 dec->parse_resync = FALSE;
1660 gst_video_decoder_set_packetized (bdec, FALSE);
1666 gst_jpeg_dec_flush (GstVideoDecoder * bdec)
1668 GstJpegDec *dec = (GstJpegDec *) bdec;
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;
1682 gst_jpeg_dec_set_property (GObject * object, guint prop_id,
1683 const GValue * value, GParamSpec * pspec)
1687 dec = GST_JPEG_DEC (object);
1690 case PROP_IDCT_METHOD:
1691 dec->idct_method = g_value_get_enum (value);
1693 #ifndef GST_REMOVE_DEPRECATED
1694 case PROP_MAX_ERRORS:
1695 g_atomic_int_set (&dec->max_errors, g_value_get_int (value));
1699 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1705 gst_jpeg_dec_get_property (GObject * object, guint prop_id, GValue * value,
1710 dec = GST_JPEG_DEC (object);
1713 case PROP_IDCT_METHOD:
1714 g_value_set_enum (value, dec->idct_method);
1716 #ifndef GST_REMOVE_DEPRECATED
1717 case PROP_MAX_ERRORS:
1718 g_value_set_int (value, g_atomic_int_get (&dec->max_errors));
1722 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1728 gst_jpeg_dec_stop (GstVideoDecoder * bdec)
1730 GstJpegDec *dec = (GstJpegDec *) bdec;
1732 gst_jpeg_dec_free_buffers (dec);
1734 g_free (dec->scratch);
1735 dec->scratch = NULL;
1736 dec->scratch_size = 0;