jpegdec: add support for RGB and grayscale color space
Also refactor src caps negotiation and setting.
This commit is contained in:
parent
b0ac4a4560
commit
78a2b22ed5
@ -59,12 +59,17 @@ enum
|
|||||||
PROP_IDCT_METHOD
|
PROP_IDCT_METHOD
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* *INDENT-OFF* */
|
||||||
static GstStaticPadTemplate gst_jpeg_dec_src_pad_template =
|
static GstStaticPadTemplate gst_jpeg_dec_src_pad_template =
|
||||||
GST_STATIC_PAD_TEMPLATE ("src",
|
GST_STATIC_PAD_TEMPLATE ("src",
|
||||||
GST_PAD_SRC,
|
GST_PAD_SRC,
|
||||||
GST_PAD_ALWAYS,
|
GST_PAD_ALWAYS,
|
||||||
GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("I420"))
|
GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("I420") "; "
|
||||||
|
GST_VIDEO_CAPS_RGB "; " GST_VIDEO_CAPS_BGR "; "
|
||||||
|
GST_VIDEO_CAPS_RGBx "; " GST_VIDEO_CAPS_xRGB "; "
|
||||||
|
GST_VIDEO_CAPS_BGRx "; " GST_VIDEO_CAPS_xBGR)
|
||||||
);
|
);
|
||||||
|
/* *INDENT-ON* */
|
||||||
|
|
||||||
static GstStaticPadTemplate gst_jpeg_dec_sink_pad_template =
|
static GstStaticPadTemplate gst_jpeg_dec_sink_pad_template =
|
||||||
GST_STATIC_PAD_TEMPLATE ("sink",
|
GST_STATIC_PAD_TEMPLATE ("sink",
|
||||||
@ -714,9 +719,51 @@ gst_jpeg_dec_ensure_buffers (GstJpegDec * dec, guint maxrowbytes)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_jpeg_dec_decode_rgb (GstJpegDec * dec, guchar * base[3],
|
||||||
|
guint width, guint height, guint pstride, guint rstride)
|
||||||
|
{
|
||||||
|
guchar *r_rows[16], *g_rows[16], *b_rows[16];
|
||||||
|
guchar **scanarray[3] = { r_rows, g_rows, b_rows };
|
||||||
|
gint i, j, k;
|
||||||
|
gint lines;
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (dec, "indirect decoding of RGB");
|
||||||
|
|
||||||
|
if (G_UNLIKELY (!gst_jpeg_dec_ensure_buffers (dec, GST_ROUND_UP_32 (width))))
|
||||||
|
return;
|
||||||
|
|
||||||
|
memcpy (r_rows, dec->idr_y, 16 * sizeof (gpointer));
|
||||||
|
memcpy (g_rows, dec->idr_u, 16 * sizeof (gpointer));
|
||||||
|
memcpy (b_rows, dec->idr_v, 16 * sizeof (gpointer));
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while (i < height) {
|
||||||
|
lines = jpeg_read_raw_data (&dec->cinfo, scanarray, DCTSIZE);
|
||||||
|
if (G_LIKELY (lines > 0)) {
|
||||||
|
for (j = 0; (j < DCTSIZE) && (i < height); j++, i++) {
|
||||||
|
gint p;
|
||||||
|
|
||||||
|
p = 0;
|
||||||
|
for (k = 0; k < width; k++) {
|
||||||
|
base[0][p] = r_rows[j][k];
|
||||||
|
base[1][p] = g_rows[j][k];
|
||||||
|
base[2][p] = b_rows[j][k];
|
||||||
|
p += pstride;
|
||||||
|
}
|
||||||
|
base[0] += rstride;
|
||||||
|
base[1] += rstride;
|
||||||
|
base[2] += rstride;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
GST_INFO_OBJECT (dec, "jpeg_read_raw_data() returned 0");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_jpeg_dec_decode_indirect (GstJpegDec * dec, guchar * base[3],
|
gst_jpeg_dec_decode_indirect (GstJpegDec * dec, guchar * base[3],
|
||||||
guchar * last[3], guint width, guint height, gint r_v, gint r_h)
|
guchar * last[3], guint width, guint height, gint r_v, gint r_h, gint comp)
|
||||||
{
|
{
|
||||||
guchar *y_rows[16], *u_rows[16], *v_rows[16];
|
guchar *y_rows[16], *u_rows[16], *v_rows[16];
|
||||||
guchar **scanarray[3] = { y_rows, u_rows, v_rows };
|
guchar **scanarray[3] = { y_rows, u_rows, v_rows };
|
||||||
@ -733,6 +780,15 @@ gst_jpeg_dec_decode_indirect (GstJpegDec * dec, guchar * base[3],
|
|||||||
memcpy (u_rows, dec->idr_u, 16 * sizeof (gpointer));
|
memcpy (u_rows, dec->idr_u, 16 * sizeof (gpointer));
|
||||||
memcpy (v_rows, dec->idr_v, 16 * sizeof (gpointer));
|
memcpy (v_rows, dec->idr_v, 16 * sizeof (gpointer));
|
||||||
|
|
||||||
|
/* fill chroma components for grayscale */
|
||||||
|
if (comp == 1) {
|
||||||
|
GST_DEBUG_OBJECT (dec, "grayscale, filling chroma");
|
||||||
|
for (i = 0; i < 16; i++) {
|
||||||
|
memset (u_rows[i], GST_ROUND_UP_32 (width), 0x80);
|
||||||
|
memset (v_rows[i], GST_ROUND_UP_32 (width), 0x80);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < height; i += r_v * DCTSIZE) {
|
for (i = 0; i < height; i += r_v * DCTSIZE) {
|
||||||
lines = jpeg_read_raw_data (&dec->cinfo, scanarray, r_v * DCTSIZE);
|
lines = jpeg_read_raw_data (&dec->cinfo, scanarray, r_v * DCTSIZE);
|
||||||
if (G_LIKELY (lines > 0)) {
|
if (G_LIKELY (lines > 0)) {
|
||||||
@ -927,6 +983,110 @@ gst_jpeg_dec_do_qos (GstJpegDec * dec, GstClockTime timestamp)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_jpeg_dec_negotiate (GstJpegDec * dec, gint width, gint height, gint clrspc)
|
||||||
|
{
|
||||||
|
GstCaps *caps;
|
||||||
|
GstVideoFormat format;
|
||||||
|
|
||||||
|
if (G_UNLIKELY (width == dec->caps_width && height == dec->caps_height &&
|
||||||
|
dec->framerate_numerator == dec->caps_framerate_numerator &&
|
||||||
|
dec->framerate_denominator == dec->caps_framerate_denominator &&
|
||||||
|
clrspc == dec->clrspc))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* framerate == 0/1 is a still frame */
|
||||||
|
if (dec->framerate_denominator == 0) {
|
||||||
|
dec->framerate_numerator = 0;
|
||||||
|
dec->framerate_denominator = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* calculate or assume an average frame duration for QoS purposes */
|
||||||
|
GST_OBJECT_LOCK (dec);
|
||||||
|
if (dec->framerate_numerator != 0) {
|
||||||
|
dec->qos_duration = gst_util_uint64_scale (GST_SECOND,
|
||||||
|
dec->framerate_denominator, dec->framerate_numerator);
|
||||||
|
} else {
|
||||||
|
/* if not set just use 25fps */
|
||||||
|
dec->qos_duration = gst_util_uint64_scale (GST_SECOND, 1, 25);
|
||||||
|
}
|
||||||
|
GST_OBJECT_UNLOCK (dec);
|
||||||
|
|
||||||
|
if (dec->cinfo.jpeg_color_space == JCS_RGB) {
|
||||||
|
gint i;
|
||||||
|
GstCaps *allowed_caps;
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (dec, "selecting RGB format");
|
||||||
|
/* retrieve allowed caps, and find the first one that reasonably maps
|
||||||
|
* to the parameters of the colourspace */
|
||||||
|
caps = gst_pad_get_allowed_caps (dec->srcpad);
|
||||||
|
if (!caps) {
|
||||||
|
GST_DEBUG_OBJECT (dec, "... but no peer, using template caps");
|
||||||
|
/* need to copy because get_allowed_caps returns a ref,
|
||||||
|
* and get_pad_template_caps doesn't */
|
||||||
|
caps = gst_caps_copy (gst_pad_get_pad_template_caps (dec->srcpad));
|
||||||
|
}
|
||||||
|
/* avoid lists of fourcc, etc */
|
||||||
|
allowed_caps = gst_caps_normalize (caps);
|
||||||
|
gst_caps_unref (caps);
|
||||||
|
caps = NULL;
|
||||||
|
GST_LOG_OBJECT (dec, "allowed source caps %" GST_PTR_FORMAT, allowed_caps);
|
||||||
|
|
||||||
|
for (i = 0; i < gst_caps_get_size (allowed_caps); i++) {
|
||||||
|
if (caps)
|
||||||
|
gst_caps_unref (caps);
|
||||||
|
caps = gst_caps_copy_nth (allowed_caps, i);
|
||||||
|
/* sigh, ds and _parse_caps need fixed caps for parsing, fixate */
|
||||||
|
gst_pad_fixate_caps (dec->srcpad, caps);
|
||||||
|
GST_LOG_OBJECT (dec, "checking caps %" GST_PTR_FORMAT, caps);
|
||||||
|
if (!gst_video_format_parse_caps (caps, &format, NULL, NULL))
|
||||||
|
continue;
|
||||||
|
/* we'll settle for the first (preferred) downstream rgb format */
|
||||||
|
if (gst_video_format_is_rgb (format))
|
||||||
|
break;
|
||||||
|
/* default fall-back */
|
||||||
|
format = GST_VIDEO_FORMAT_RGB;
|
||||||
|
}
|
||||||
|
if (caps)
|
||||||
|
gst_caps_unref (caps);
|
||||||
|
gst_caps_unref (allowed_caps);
|
||||||
|
caps = gst_video_format_new_caps (format, width, height,
|
||||||
|
dec->framerate_numerator, dec->framerate_denominator, 1, 1);
|
||||||
|
dec->outsize = gst_video_format_get_size (format, width, height);
|
||||||
|
/* some format info */
|
||||||
|
dec->offset[0] =
|
||||||
|
gst_video_format_get_component_offset (format, 0, width, height);
|
||||||
|
dec->offset[1] =
|
||||||
|
gst_video_format_get_component_offset (format, 1, width, height);
|
||||||
|
dec->offset[2] =
|
||||||
|
gst_video_format_get_component_offset (format, 2, width, height);
|
||||||
|
/* equal for all components */
|
||||||
|
dec->stride = gst_video_format_get_row_stride (format, 0, width);
|
||||||
|
dec->inc = gst_video_format_get_pixel_stride (format, 0);
|
||||||
|
} else {
|
||||||
|
/* go for plain and simple I420 */
|
||||||
|
/* TODO other YUV cases ? */
|
||||||
|
caps = gst_caps_new_simple ("video/x-raw-yuv",
|
||||||
|
"format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('I', '4', '2', '0'),
|
||||||
|
"width", G_TYPE_INT, width, "height", G_TYPE_INT, height,
|
||||||
|
"framerate", GST_TYPE_FRACTION, dec->framerate_numerator,
|
||||||
|
dec->framerate_denominator, NULL);
|
||||||
|
dec->outsize = I420_SIZE (width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (dec, "setting caps %" GST_PTR_FORMAT, caps);
|
||||||
|
GST_DEBUG_OBJECT (dec, "max_v_samp_factor=%d", dec->cinfo.max_v_samp_factor);
|
||||||
|
GST_DEBUG_OBJECT (dec, "max_h_samp_factor=%d", dec->cinfo.max_h_samp_factor);
|
||||||
|
|
||||||
|
gst_pad_set_caps (dec->srcpad, caps);
|
||||||
|
gst_caps_unref (caps);
|
||||||
|
|
||||||
|
dec->caps_width = width;
|
||||||
|
dec->caps_height = height;
|
||||||
|
dec->caps_framerate_numerator = dec->framerate_numerator;
|
||||||
|
dec->caps_framerate_denominator = dec->framerate_denominator;
|
||||||
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_jpeg_dec_chain (GstPad * pad, GstBuffer * buf)
|
gst_jpeg_dec_chain (GstPad * pad, GstBuffer * buf)
|
||||||
{
|
{
|
||||||
@ -1035,7 +1195,9 @@ gst_jpeg_dec_chain (GstPad * pad, GstBuffer * buf)
|
|||||||
goto components_not_supported;
|
goto components_not_supported;
|
||||||
|
|
||||||
/* verify color space expectation to avoid going *boom* or bogus output */
|
/* verify color space expectation to avoid going *boom* or bogus output */
|
||||||
if (dec->cinfo.jpeg_color_space != JCS_YCbCr)
|
if (dec->cinfo.jpeg_color_space != JCS_YCbCr &&
|
||||||
|
dec->cinfo.jpeg_color_space != JCS_GRAYSCALE &&
|
||||||
|
dec->cinfo.jpeg_color_space != JCS_RGB)
|
||||||
goto unsupported_colorspace;
|
goto unsupported_colorspace;
|
||||||
|
|
||||||
#ifndef GST_DISABLE_GST_DEBUG
|
#ifndef GST_DISABLE_GST_DEBUG
|
||||||
@ -1054,7 +1216,7 @@ gst_jpeg_dec_chain (GstPad * pad, GstBuffer * buf)
|
|||||||
/* prepare for raw output */
|
/* prepare for raw output */
|
||||||
dec->cinfo.do_fancy_upsampling = FALSE;
|
dec->cinfo.do_fancy_upsampling = FALSE;
|
||||||
dec->cinfo.do_block_smoothing = FALSE;
|
dec->cinfo.do_block_smoothing = FALSE;
|
||||||
dec->cinfo.out_color_space = JCS_YCbCr;
|
dec->cinfo.out_color_space = dec->cinfo.jpeg_color_space;
|
||||||
dec->cinfo.dct_method = dec->idct_method;
|
dec->cinfo.dct_method = dec->idct_method;
|
||||||
dec->cinfo.raw_data_out = TRUE;
|
dec->cinfo.raw_data_out = TRUE;
|
||||||
|
|
||||||
@ -1064,11 +1226,27 @@ gst_jpeg_dec_chain (GstPad * pad, GstBuffer * buf)
|
|||||||
GST_WARNING_OBJECT (dec, "failed to start decompression cycle");
|
GST_WARNING_OBJECT (dec, "failed to start decompression cycle");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* YUV sanity checks to get safe and reasonable I420 output */
|
/* sanity checks to get safe and reasonable output */
|
||||||
g_assert (dec->cinfo.num_components == 3);
|
switch (dec->cinfo.jpeg_color_space) {
|
||||||
if (r_v > 2 || r_v < dec->cinfo.comp_info[0].v_samp_factor ||
|
case JCS_GRAYSCALE:
|
||||||
r_h < dec->cinfo.comp_info[0].h_samp_factor)
|
break;
|
||||||
goto invalid_yuv;
|
case JCS_RGB:
|
||||||
|
if (dec->cinfo.num_components != 3 || dec->cinfo.max_v_samp_factor > 1 ||
|
||||||
|
dec->cinfo.max_h_samp_factor > 1)
|
||||||
|
goto invalid_yuvrgb;
|
||||||
|
break;
|
||||||
|
case JCS_YCbCr:
|
||||||
|
if (dec->cinfo.num_components != 3 ||
|
||||||
|
r_v > 2 || r_v < dec->cinfo.comp_info[0].v_samp_factor ||
|
||||||
|
r_v < dec->cinfo.comp_info[1].v_samp_factor ||
|
||||||
|
r_h < dec->cinfo.comp_info[0].h_samp_factor ||
|
||||||
|
r_h < dec->cinfo.comp_info[1].h_samp_factor)
|
||||||
|
goto invalid_yuvrgb;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_assert_not_reached ();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
width = dec->cinfo.output_width;
|
width = dec->cinfo.output_width;
|
||||||
height = dec->cinfo.output_height;
|
height = dec->cinfo.output_height;
|
||||||
@ -1077,50 +1255,7 @@ gst_jpeg_dec_chain (GstPad * pad, GstBuffer * buf)
|
|||||||
height < MIN_HEIGHT || height > MAX_HEIGHT))
|
height < MIN_HEIGHT || height > MAX_HEIGHT))
|
||||||
goto wrong_size;
|
goto wrong_size;
|
||||||
|
|
||||||
if (G_UNLIKELY (width != dec->caps_width || height != dec->caps_height ||
|
gst_jpeg_dec_negotiate (dec, width, height, dec->cinfo.jpeg_color_space);
|
||||||
dec->framerate_numerator != dec->caps_framerate_numerator ||
|
|
||||||
dec->framerate_denominator != dec->caps_framerate_denominator)) {
|
|
||||||
GstCaps *caps;
|
|
||||||
|
|
||||||
/* framerate == 0/1 is a still frame */
|
|
||||||
if (dec->framerate_denominator == 0) {
|
|
||||||
dec->framerate_numerator = 0;
|
|
||||||
dec->framerate_denominator = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* calculate or assume an average frame duration for QoS purposes */
|
|
||||||
GST_OBJECT_LOCK (dec);
|
|
||||||
if (dec->framerate_numerator != 0) {
|
|
||||||
dec->qos_duration = gst_util_uint64_scale (GST_SECOND,
|
|
||||||
dec->framerate_denominator, dec->framerate_numerator);
|
|
||||||
} else {
|
|
||||||
/* if not set just use 25fps */
|
|
||||||
dec->qos_duration = gst_util_uint64_scale (GST_SECOND, 1, 25);
|
|
||||||
}
|
|
||||||
GST_OBJECT_UNLOCK (dec);
|
|
||||||
|
|
||||||
caps = gst_caps_new_simple ("video/x-raw-yuv",
|
|
||||||
"format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('I', '4', '2', '0'),
|
|
||||||
"width", G_TYPE_INT, width,
|
|
||||||
"height", G_TYPE_INT, height,
|
|
||||||
"framerate", GST_TYPE_FRACTION, dec->framerate_numerator,
|
|
||||||
dec->framerate_denominator, NULL);
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (dec, "setting caps %" GST_PTR_FORMAT, caps);
|
|
||||||
GST_DEBUG_OBJECT (dec, "max_v_samp_factor=%d",
|
|
||||||
dec->cinfo.max_v_samp_factor);
|
|
||||||
GST_DEBUG_OBJECT (dec, "max_h_samp_factor=%d",
|
|
||||||
dec->cinfo.max_h_samp_factor);
|
|
||||||
|
|
||||||
gst_pad_set_caps (dec->srcpad, caps);
|
|
||||||
gst_caps_unref (caps);
|
|
||||||
|
|
||||||
dec->caps_width = width;
|
|
||||||
dec->caps_height = height;
|
|
||||||
dec->caps_framerate_numerator = dec->framerate_numerator;
|
|
||||||
dec->caps_framerate_denominator = dec->framerate_denominator;
|
|
||||||
dec->outsize = I420_SIZE (width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = gst_pad_alloc_buffer_and_set_caps (dec->srcpad, GST_BUFFER_OFFSET_NONE,
|
ret = gst_pad_alloc_buffer_and_set_caps (dec->srcpad, GST_BUFFER_OFFSET_NONE,
|
||||||
dec->outsize, GST_PAD_CAPS (dec->srcpad), &outbuf);
|
dec->outsize, GST_PAD_CAPS (dec->srcpad), &outbuf);
|
||||||
@ -1153,43 +1288,51 @@ gst_jpeg_dec_chain (GstPad * pad, GstBuffer * buf)
|
|||||||
}
|
}
|
||||||
GST_BUFFER_DURATION (outbuf) = duration;
|
GST_BUFFER_DURATION (outbuf) = duration;
|
||||||
|
|
||||||
/* mind the swap, jpeglib outputs blue chroma first
|
if (dec->cinfo.jpeg_color_space == JCS_RGB) {
|
||||||
* ensonic: I see no swap?
|
base[0] = outdata + dec->offset[0];
|
||||||
*/
|
base[1] = outdata + dec->offset[1];
|
||||||
base[0] = outdata + I420_Y_OFFSET (width, height);
|
base[2] = outdata + dec->offset[2];
|
||||||
base[1] = outdata + I420_U_OFFSET (width, height);
|
gst_jpeg_dec_decode_rgb (dec, base, width, height, dec->inc, dec->stride);
|
||||||
base[2] = outdata + I420_V_OFFSET (width, height);
|
|
||||||
|
|
||||||
/* make sure we don't make jpeglib write beyond our buffer,
|
|
||||||
* which might happen if (height % (r_v*DCTSIZE)) != 0 */
|
|
||||||
last[0] = base[0] + (I420_Y_ROWSTRIDE (width) * (height - 1));
|
|
||||||
last[1] =
|
|
||||||
base[1] + (I420_U_ROWSTRIDE (width) * ((GST_ROUND_UP_2 (height) / 2) -
|
|
||||||
1));
|
|
||||||
last[2] =
|
|
||||||
base[2] + (I420_V_ROWSTRIDE (width) * ((GST_ROUND_UP_2 (height) / 2) -
|
|
||||||
1));
|
|
||||||
|
|
||||||
GST_LOG_OBJECT (dec, "decompressing (reqired scanline buffer height = %u)",
|
|
||||||
dec->cinfo.rec_outbuf_height);
|
|
||||||
|
|
||||||
/* For some widths jpeglib requires more horizontal padding than I420
|
|
||||||
* provides. In those cases we need to decode into separate buffers and then
|
|
||||||
* copy over the data into our final picture buffer, otherwise jpeglib might
|
|
||||||
* write over the end of a line into the beginning of the next line,
|
|
||||||
* resulting in blocky artifacts on the left side of the picture. */
|
|
||||||
if (G_UNLIKELY (width % (dec->cinfo.max_h_samp_factor * DCTSIZE) != 0
|
|
||||||
|| dec->cinfo.comp_info[0].h_samp_factor != 2
|
|
||||||
|| dec->cinfo.comp_info[1].h_samp_factor != 1
|
|
||||||
|| dec->cinfo.comp_info[2].h_samp_factor != 1)) {
|
|
||||||
GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, dec,
|
|
||||||
"indirect decoding using extra buffer copy");
|
|
||||||
gst_jpeg_dec_decode_indirect (dec, base, last, width, height, r_v, r_h);
|
|
||||||
} else {
|
} else {
|
||||||
ret = gst_jpeg_dec_decode_direct (dec, base, last, width, height);
|
/* mind the swap, jpeglib outputs blue chroma first
|
||||||
|
* ensonic: I see no swap?
|
||||||
|
*/
|
||||||
|
base[0] = outdata + I420_Y_OFFSET (width, height);
|
||||||
|
base[1] = outdata + I420_U_OFFSET (width, height);
|
||||||
|
base[2] = outdata + I420_V_OFFSET (width, height);
|
||||||
|
|
||||||
if (G_UNLIKELY (ret != GST_FLOW_OK))
|
/* make sure we don't make jpeglib write beyond our buffer,
|
||||||
goto decode_direct_failed;
|
* which might happen if (height % (r_v*DCTSIZE)) != 0 */
|
||||||
|
last[0] = base[0] + (I420_Y_ROWSTRIDE (width) * (height - 1));
|
||||||
|
last[1] =
|
||||||
|
base[1] + (I420_U_ROWSTRIDE (width) * ((GST_ROUND_UP_2 (height) / 2) -
|
||||||
|
1));
|
||||||
|
last[2] =
|
||||||
|
base[2] + (I420_V_ROWSTRIDE (width) * ((GST_ROUND_UP_2 (height) / 2) -
|
||||||
|
1));
|
||||||
|
|
||||||
|
GST_LOG_OBJECT (dec, "decompressing (reqired scanline buffer height = %u)",
|
||||||
|
dec->cinfo.rec_outbuf_height);
|
||||||
|
|
||||||
|
/* For some widths jpeglib requires more horizontal padding than I420
|
||||||
|
* provides. In those cases we need to decode into separate buffers and then
|
||||||
|
* copy over the data into our final picture buffer, otherwise jpeglib might
|
||||||
|
* write over the end of a line into the beginning of the next line,
|
||||||
|
* resulting in blocky artifacts on the left side of the picture. */
|
||||||
|
if (G_UNLIKELY (width % (dec->cinfo.max_h_samp_factor * DCTSIZE) != 0
|
||||||
|
|| dec->cinfo.comp_info[0].h_samp_factor != 2
|
||||||
|
|| dec->cinfo.comp_info[1].h_samp_factor != 1
|
||||||
|
|| dec->cinfo.comp_info[2].h_samp_factor != 1)) {
|
||||||
|
GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, dec,
|
||||||
|
"indirect decoding using extra buffer copy");
|
||||||
|
gst_jpeg_dec_decode_indirect (dec, base, last, width, height, r_v, r_h,
|
||||||
|
dec->cinfo.num_components);
|
||||||
|
} else {
|
||||||
|
ret = gst_jpeg_dec_decode_direct (dec, base, last, width, height);
|
||||||
|
|
||||||
|
if (G_UNLIKELY (ret != GST_FLOW_OK))
|
||||||
|
goto decode_direct_failed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_LOG_OBJECT (dec, "decompressing finished");
|
GST_LOG_OBJECT (dec, "decompressing finished");
|
||||||
@ -1323,10 +1466,10 @@ unsupported_colorspace:
|
|||||||
ret = GST_FLOW_ERROR;
|
ret = GST_FLOW_ERROR;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
invalid_yuv:
|
invalid_yuvrgb:
|
||||||
{
|
{
|
||||||
GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL),
|
GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL),
|
||||||
("Picture is corrupt or unhandled YUV layout"));
|
("Picture is corrupt or unhandled YUV/RGB layout"));
|
||||||
ret = GST_FLOW_ERROR;
|
ret = GST_FLOW_ERROR;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
@ -1456,6 +1599,7 @@ gst_jpeg_dec_change_state (GstElement * element, GstStateChange transition)
|
|||||||
dec->caps_framerate_numerator = dec->caps_framerate_denominator = 0;
|
dec->caps_framerate_numerator = dec->caps_framerate_denominator = 0;
|
||||||
dec->caps_width = -1;
|
dec->caps_width = -1;
|
||||||
dec->caps_height = -1;
|
dec->caps_height = -1;
|
||||||
|
dec->clrspc = -1;
|
||||||
dec->packetized = FALSE;
|
dec->packetized = FALSE;
|
||||||
dec->next_ts = 0;
|
dec->next_ts = 0;
|
||||||
dec->discont = TRUE;
|
dec->discont = TRUE;
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include <setjmp.h>
|
#include <setjmp.h>
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
|
#include <gst/video/video.h>
|
||||||
|
|
||||||
/* this is a hack hack hack to get around jpeglib header bugs... */
|
/* this is a hack hack hack to get around jpeglib header bugs... */
|
||||||
#ifdef HAVE_STDLIB_H
|
#ifdef HAVE_STDLIB_H
|
||||||
@ -96,6 +97,11 @@ struct _GstJpegDec {
|
|||||||
gint caps_width;
|
gint caps_width;
|
||||||
gint caps_height;
|
gint caps_height;
|
||||||
gint outsize;
|
gint outsize;
|
||||||
|
gint clrspc;
|
||||||
|
|
||||||
|
gint offset[3];
|
||||||
|
gint stride;
|
||||||
|
gint inc;
|
||||||
|
|
||||||
/* properties */
|
/* properties */
|
||||||
gint idct_method;
|
gint idct_method;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user