ext/jpeg/gstjpegdec.c: Fix decoding of pictures with certain uneven or unaligned widths where jpeglib needs more hori...

Original commit message from CVS:
* ext/jpeg/gstjpegdec.c: (gst_jpeg_dec_decode_indirect),
(gst_jpeg_dec_decode_direct), (gst_jpeg_dec_chain):
Fix decoding of pictures with certain uneven or unaligned
widths where jpeglib needs more horizontal padding than our
I420 buffers provide, resulting in blocky artifacts at the
left side of the picture (#164176).
Also make use of our shiny new GST_ROUND_N() macros.
This commit is contained in:
Tim-Philipp Müller 2005-08-12 19:33:31 +00:00
parent 2c39e57114
commit d39143f4bb
2 changed files with 115 additions and 43 deletions

View file

@ -1,3 +1,13 @@
2005-08-12 Tim-Philipp Müller <tim at centricular dot net>
* ext/jpeg/gstjpegdec.c: (gst_jpeg_dec_decode_indirect),
(gst_jpeg_dec_decode_direct), (gst_jpeg_dec_chain):
Fix decoding of pictures with certain uneven or unaligned
widths where jpeglib needs more horizontal padding than our
I420 buffers provide, resulting in blocky artifacts at the
left side of the picture (#164176).
Also make use of our shiny new GST_ROUND_N() macros.
2005-08-11 Tim-Philipp Müller <tim at centricular dot net>
* ext/jpeg/gstjpegdec.c: (gst_jpeg_dec_init), (gst_jpeg_dec_chain),

View file

@ -62,20 +62,15 @@ GST_DEBUG_CATEGORY (jpeg_dec_debug);
/* These macros are adapted from videotestsrc.c
* and/or gst-plugins/gst/games/gstvideoimage.c */
#define ROUND_UP_2(x) (((x)+1)&~1)
#define ROUND_UP_4(x) (((x)+3)&~3)
#define ROUND_UP_8(x) (((x)+7)&~7)
/* I420 */
#define I420_Y_ROWSTRIDE(width) (ROUND_UP_4(width))
#define I420_U_ROWSTRIDE(width) (ROUND_UP_8(width)/2)
#define I420_V_ROWSTRIDE(width) ((ROUND_UP_8(I420_Y_ROWSTRIDE(width)))/2)
#define I420_Y_ROWSTRIDE(width) (GST_ROUND_UP_4(width))
#define I420_U_ROWSTRIDE(width) (GST_ROUND_UP_8(width)/2)
#define I420_V_ROWSTRIDE(width) ((GST_ROUND_UP_8(I420_Y_ROWSTRIDE(width)))/2)
#define I420_Y_OFFSET(w,h) (0)
#define I420_U_OFFSET(w,h) (I420_Y_OFFSET(w,h)+(I420_Y_ROWSTRIDE(w)*ROUND_UP_2(h)))
#define I420_V_OFFSET(w,h) (I420_U_OFFSET(w,h)+(I420_U_ROWSTRIDE(w)*ROUND_UP_2(h)/2))
#define I420_U_OFFSET(w,h) (I420_Y_OFFSET(w,h)+(I420_Y_ROWSTRIDE(w)*GST_ROUND_UP_2(h)))
#define I420_V_OFFSET(w,h) (I420_U_OFFSET(w,h)+(I420_U_ROWSTRIDE(w)*GST_ROUND_UP_2(h)/2))
#define I420_SIZE(w,h) (I420_V_OFFSET(w,h)+(I420_V_ROWSTRIDE(w)*ROUND_UP_2(h)/2))
#define I420_SIZE(w,h) (I420_V_OFFSET(w,h)+(I420_V_ROWSTRIDE(w)*GST_ROUND_UP_2(h)/2))
static GstElementClass *parent_class; /* NULL */
@ -613,6 +608,87 @@ gst_jpeg_dec_setcaps (GstPad * pad, GstCaps * caps)
return TRUE;
}
static void
gst_jpeg_dec_decode_indirect (GstJpegDec * dec, guchar * base[3],
guchar * last[3], guint width, guint height, gint r_v)
{
guchar y[16][MAX_WIDTH];
guchar u[8][MAX_WIDTH / 2];
guchar v[8][MAX_WIDTH / 2];
guchar *y_rows[16] = { y[0], y[1], y[2], y[3], y[4], y[5], y[6], y[7],
y[8], y[9], y[10], y[11], y[12], y[13], y[14], y[15]
};
guchar *u_rows[8] = { u[0], u[1], u[2], u[3], u[4], u[5], u[6], u[7] };
guchar *v_rows[8] = { v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7] };
guchar **scanarray[3] = { y_rows, u_rows, v_rows };
gint i, j, k;
GST_DEBUG_OBJECT (dec,
"unadvantageous width, taking slow route involving memcpy");
for (i = 0; i < height; i += r_v * DCTSIZE) {
jpeg_read_raw_data (&dec->cinfo, scanarray, r_v * DCTSIZE);
for (j = 0, k = 0; j < (r_v * DCTSIZE); j += r_v, k++) {
memcpy (base[0], y_rows[j], I420_Y_ROWSTRIDE (width));
if (base[0] < last[0])
base[0] += I420_Y_ROWSTRIDE (width);
if (r_v == 2) {
memcpy (base[0], y_rows[j + 1], I420_Y_ROWSTRIDE (width));
if (base[0] < last[0])
base[0] += I420_Y_ROWSTRIDE (width);
}
memcpy (base[1], u_rows[k], I420_U_ROWSTRIDE (width));
memcpy (base[2], v_rows[k], I420_V_ROWSTRIDE (width));
if (r_v == 2 || (k & 1) != 0) {
if (base[1] < last[1] && base[2] < last[2]) {
base[1] += I420_U_ROWSTRIDE (width);
base[2] += I420_V_ROWSTRIDE (width);
}
}
}
}
}
static void
gst_jpeg_dec_decode_direct (GstJpegDec * dec, guchar * base[3],
guchar * last[3], guint width, guint height, gint r_v)
{
guchar **line[3]; /* the jpeg line buffer */
gint i, j, k;
line[0] = g_alloca ((r_v * DCTSIZE) * sizeof (guchar *));
line[1] = g_alloca ((r_v * DCTSIZE) * sizeof (guchar *));
line[2] = g_alloca ((r_v * DCTSIZE) * sizeof (guchar *));
memset (line[0], 0, (r_v * DCTSIZE) * sizeof (guchar *));
memset (line[1], 0, (r_v * DCTSIZE) * sizeof (guchar *));
memset (line[2], 0, (r_v * DCTSIZE) * sizeof (guchar *));
/* let jpeglib decode directly into our final buffer */
GST_DEBUG_OBJECT (dec, "decoding directly into output buffer");
for (i = 0; i < height; i += r_v * DCTSIZE) {
for (j = 0, k = 0; j < (r_v * DCTSIZE); j += r_v, k++) {
line[0][j] = base[0];
if (base[0] < last[0])
base[0] += I420_Y_ROWSTRIDE (width);
if (r_v == 2) {
line[0][j + 1] = base[0];
if (base[0] < last[0])
base[0] += I420_Y_ROWSTRIDE (width);
}
line[1][k] = base[1];
line[2][k] = base[2];
if (r_v == 2 || (k & 1) != 0) {
if (base[1] < last[1] && base[2] < last[2]) {
base[1] += I420_U_ROWSTRIDE (width);
base[2] += I420_V_ROWSTRIDE (width);
}
}
}
jpeg_read_raw_data (&dec->cinfo, line, r_v * DCTSIZE);
}
}
static GstFlowReturn
gst_jpeg_dec_chain (GstPad * pad, GstBuffer * buf)
{
@ -623,11 +699,10 @@ gst_jpeg_dec_chain (GstPad * pad, GstBuffer * buf)
gulong size;
guchar *data, *outdata;
guchar *base[3], *last[3];
guchar **line[3]; /* the jpeg line buffer */
guint img_len;
gint width, height;
gint r_h, r_v;
gint i, j, k;
gint i;
dec = GST_JPEG_DEC (GST_OBJECT_PARENT (pad));
@ -762,39 +837,26 @@ gst_jpeg_dec_chain (GstPad * pad, GstBuffer * buf)
/* 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) - 1));
last[1] = base[1] + (I420_U_ROWSTRIDE (width) * ((height / 2) - 1));
last[2] = base[2] + (I420_V_ROWSTRIDE (width) * ((height / 2) - 1));
line[0] = g_alloca ((r_v * DCTSIZE) * sizeof (guchar *));
line[1] = g_alloca ((r_v * DCTSIZE) * sizeof (guchar *));
line[2] = g_alloca ((r_v * DCTSIZE) * sizeof (guchar *));
memset (line[0], 0, (r_v * DCTSIZE) * sizeof (guchar *));
memset (line[1], 0, (r_v * DCTSIZE) * sizeof (guchar *));
memset (line[2], 0, (r_v * DCTSIZE) * sizeof (guchar *));
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 %u", dec->cinfo.rec_outbuf_height);
GST_LOG_OBJECT (dec, "max_h_samp_factor=%u", dec->cinfo.max_h_samp_factor);
for (i = 0; i < height; i += r_v * DCTSIZE) {
for (j = 0, k = 0; j < (r_v * DCTSIZE); j += r_v, k++) {
line[0][j] = base[0];
if (base[0] < last[0])
base[0] += I420_Y_ROWSTRIDE (width);
if (r_v == 2) {
line[0][j + 1] = base[0];
if (base[0] < last[0])
base[0] += I420_Y_ROWSTRIDE (width);
}
line[1][k] = base[1];
line[2][k] = base[2];
if (r_v == 2 || (k & 1) != 0) {
if (base[1] < last[1] && base[2] < last[2]) {
base[1] += I420_U_ROWSTRIDE (width);
base[2] += I420_V_ROWSTRIDE (width);
}
}
}
jpeg_read_raw_data (&dec->cinfo, line, r_v * DCTSIZE);
/* 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 ((I420_Y_ROWSTRIDE (width) % (dec->cinfo.max_h_samp_factor * DCTSIZE)) > 0) {
gst_jpeg_dec_decode_indirect (dec, base, last, width, height, r_v);
} else {
gst_jpeg_dec_decode_direct (dec, base, last, width, height, r_v);
}
GST_LOG_OBJECT (dec, "decompressing finished");