summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTim-Philipp Müller <tim@centricular.net>2005-08-12 19:33:31 +0000
committerTim-Philipp Müller <tim@centricular.net>2005-08-12 19:33:31 +0000
commitd39143f4bb05330aff16c8580d0199ac82f1beef (patch)
tree28d11d1095f064d02efa566ccb13865bbc262553
parent2c39e571142cae79fc910c359e2d6ff479299cd2 (diff)
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.
-rw-r--r--ChangeLog10
-rw-r--r--ext/jpeg/gstjpegdec.c150
2 files changed, 116 insertions, 44 deletions
diff --git a/ChangeLog b/ChangeLog
index 8bfe48f4..f5275913 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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),
diff --git a/ext/jpeg/gstjpegdec.c b/ext/jpeg/gstjpegdec.c
index c1a87cac..aaf2af3f 100644
--- a/ext/jpeg/gstjpegdec.c
+++ b/ext/jpeg/gstjpegdec.c
@@ -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);
-
- 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);
+ GST_LOG_OBJECT (dec, "max_h_samp_factor=%u", dec->cinfo.max_h_samp_factor);
+
+ /* 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");