assrender: refactor blitting, avoid writing past end of buffer
authorDavid Schleef <ds@schleef.org>
Fri, 15 Apr 2011 03:46:52 +0000 (20:46 -0700)
committerTim-Philipp Müller <tim.muller@collabora.co.uk>
Sat, 16 Apr 2011 11:10:14 +0000 (12:10 +0100)
Previous blitting code could potentially write past the
end of the buffer if the x or y position was odd, and for
the same underlying reason, didn't get the chroma registration
correct in the odd position case.

https://bugzilla.gnome.org/show_bug.cgi?id=647830

ext/assrender/gstassrender.c

index 244e4d8..c5a8e1b 100644 (file)
@@ -618,101 +618,130 @@ blit_i420 (GstAssRender * render, ASS_Image * ass_image, GstBuffer * buffer)
         buffer->data + y_offset + ass_image->dst_y * y_stride +
         ass_image->dst_x;
     dst_u =
-        buffer->data + u_offset + ((ass_image->dst_y + 1) / 2) * u_stride +
-        (ass_image->dst_x + 1) / 2;
+        buffer->data + u_offset + (ass_image->dst_y / 2) * u_stride +
+        ass_image->dst_x / 2;
     dst_v =
-        buffer->data + v_offset + ((ass_image->dst_y + 1) / 2) * v_stride +
-        (ass_image->dst_x + 1) / 2;
-
-    for (y = 0; y < h - 1; y += 2) {
-      for (x = 0; x < w - 1; x += 2) {
-        k = src[0] * alpha / 255;
-        k2 = k;
-        dst_y[0] = (k * Y + (255 - k) * dst_y[0]) / 255;
-
-        k = src[1] * alpha / 255;
-        k2 += k;
-        dst_y[1] = (k * Y + (255 - k) * dst_y[1]) / 255;
-
-        src += src_stride;
-        dst_y += y_stride;
-
-        k = src[0] * alpha / 255;
-        k2 += k;
-        dst_y[0] = (k * Y + (255 - k) * dst_y[0]) / 255;
-
-        k = src[1] * alpha / 255;
-        k2 += k;
-        dst_y[1] = (k * Y + (255 - k) * dst_y[1]) / 255;
+        buffer->data + v_offset + (ass_image->dst_y / 2) * v_stride +
+        ass_image->dst_x / 2;
+
+    for (y = 0; y < h; y++) {
+      dst_y = buffer->data + y_offset + (ass_image->dst_y + y) * y_stride +
+          ass_image->dst_x;
+      for (x = 0; x < w; x++) {
+        k = src[y * ass_image->w + x] * alpha / 255;
+        dst_y[x] = (k * Y + (255 - k) * dst_y[x]) / 255;
+      }
+    }
 
-        k2 /= 4;
+    y = 0;
+    if (ass_image->dst_y & 1) {
+      dst_u =
+          buffer->data + u_offset + (ass_image->dst_y / 2) * u_stride +
+          ass_image->dst_x / 2;
+      dst_v =
+          buffer->data + v_offset + (ass_image->dst_y / 2) * v_stride +
+          ass_image->dst_x / 2;
+      x = 0;
+      if (ass_image->dst_x & 1) {
+        k2 = src[y * ass_image->w + x] * alpha / 255;
+        k2 = (k2 + 2) >> 2;
+        dst_u[0] = (k2 * U + (255 - k2) * dst_u[0]) / 255;
+        dst_v[0] = (k2 * V + (255 - k2) * dst_v[0]) / 255;
+        x++;
+        dst_u++;
+        dst_v++;
+      }
+      for (; x < w - 1; x += 2) {
+        k2 = src[y * ass_image->w + x] * alpha / 255;
+        k2 += src[y * ass_image->w + x + 1] * alpha / 255;
+        k2 = (k2 + 2) >> 2;
         dst_u[0] = (k2 * U + (255 - k2) * dst_u[0]) / 255;
         dst_v[0] = (k2 * V + (255 - k2) * dst_v[0]) / 255;
         dst_u++;
         dst_v++;
-
-        src += -src_stride + 2;
-        dst_y += -y_stride + 2;
       }
-
       if (x < w) {
-        k = src[0] * alpha / 255;
-        k2 = k;
-        dst_y[0] = (k * Y + (255 - k) * dst_y[0]) / 255;
-
-        src += src_stride;
-        dst_y += y_stride;
-
-        k = src[0] * alpha / 255;
-        k2 += k;
-        dst_y[0] = (k * Y + (255 - k) * dst_y[0]) / 255;
+        k2 = src[y * ass_image->w + x] * alpha / 255;
+        k2 = (k2 + 2) >> 2;
+        dst_u[0] = (k2 * U + (255 - k2) * dst_u[0]) / 255;
+        dst_v[0] = (k2 * V + (255 - k2) * dst_v[0]) / 255;
+      }
+    }
 
-        k2 /= 2;
+    for (; y < h - 1; y += 2) {
+      dst_u =
+          buffer->data + u_offset + ((ass_image->dst_y + y) / 2) * u_stride +
+          ass_image->dst_x / 2;
+      dst_v =
+          buffer->data + v_offset + ((ass_image->dst_y + y) / 2) * v_stride +
+          ass_image->dst_x / 2;
+      x = 0;
+      if (ass_image->dst_x & 1) {
+        k2 = src[y * ass_image->w + x] * alpha / 255;
+        k2 += src[(y + 1) * ass_image->w + x] * alpha / 255;
+        k2 = (k2 + 2) >> 2;
         dst_u[0] = (k2 * U + (255 - k2) * dst_u[0]) / 255;
         dst_v[0] = (k2 * V + (255 - k2) * dst_v[0]) / 255;
+        x++;
         dst_u++;
         dst_v++;
-
-        src += -src_stride + 1;
-        dst_y += -y_stride + 1;
       }
-
-      src += src_stride + (src_stride - w);
-      dst_y += y_stride + (y_stride - w);
-      dst_u += u_stride - w2;
-      dst_v += v_stride - w2;
+      for (; x < w - 1; x += 2) {
+        k2 = src[y * ass_image->w + x] * alpha / 255;
+        k2 += src[y * ass_image->w + x + 1] * alpha / 255;
+        k2 += src[(y + 1) * ass_image->w + x] * alpha / 255;
+        k2 += src[(y + 1) * ass_image->w + x + 1] * alpha / 255;
+        k2 = (k2 + 2) >> 2;
+        dst_u[0] = (k2 * U + (255 - k2) * dst_u[0]) / 255;
+        dst_v[0] = (k2 * V + (255 - k2) * dst_v[0]) / 255;
+        dst_u++;
+        dst_v++;
+      }
+      if (x < w) {
+        k2 = src[y * ass_image->w + x] * alpha / 255;
+        k2 += src[(y + 1) * ass_image->w + x] * alpha / 255;
+        k2 = (k2 + 2) >> 2;
+        dst_u[0] = (k2 * U + (255 - k2) * dst_u[0]) / 255;
+        dst_v[0] = (k2 * V + (255 - k2) * dst_v[0]) / 255;
+      }
     }
 
     if (y < h) {
-      for (x = 0; x < w - 1; x += 2) {
-        k = src[0] * alpha / 255;
-        k2 = k;
-        dst_y[0] = (k * Y + (255 - k) * dst_y[0]) / 255;
-
-        k = src[1] * alpha / 255;
-        k2 += k;
-        dst_y[1] = (k * Y + (255 - k) * dst_y[1]) / 255;
-
-        k2 /= 2;
+      dst_u =
+          buffer->data + u_offset + (ass_image->dst_y / 2) * u_stride +
+          ass_image->dst_x / 2;
+      dst_v =
+          buffer->data + v_offset + (ass_image->dst_y / 2) * v_stride +
+          ass_image->dst_x / 2;
+      x = 0;
+      if (ass_image->dst_x & 1) {
+        k2 = src[y * ass_image->w + x] * alpha / 255;
+        k2 = (k2 + 2) >> 2;
+        dst_u[0] = (k2 * U + (255 - k2) * dst_u[0]) / 255;
+        dst_v[0] = (k2 * V + (255 - k2) * dst_v[0]) / 255;
+        x++;
+        dst_u++;
+        dst_v++;
+      }
+      for (; x < w - 1; x += 2) {
+        k2 = src[y * ass_image->w + x] * alpha / 255;
+        k2 += src[y * ass_image->w + x + 1] * alpha / 255;
+        k2 = (k2 + 2) >> 2;
         dst_u[0] = (k2 * U + (255 - k2) * dst_u[0]) / 255;
         dst_v[0] = (k2 * V + (255 - k2) * dst_v[0]) / 255;
         dst_u++;
         dst_v++;
-
-        src += 2;
-        dst_y += 2;
       }
-
       if (x < w) {
-        k = src[0] * alpha / 255;
-        k2 = k;
-        dst_y[0] = (k * Y + (255 - k) * dst_y[0]) / 255;
-
+        k2 = src[y * ass_image->w + x] * alpha / 255;
+        k2 = (k2 + 2) >> 2;
         dst_u[0] = (k2 * U + (255 - k2) * dst_u[0]) / 255;
         dst_v[0] = (k2 * V + (255 - k2) * dst_v[0]) / 255;
       }
     }
 
+
+
   next:
     counter++;
     ass_image = ass_image->next;