videoscale: Add nearest/linear scaling for NV12
authorDavid Schleef <ds@schleef.org>
Mon, 30 Jan 2012 16:21:54 +0000 (08:21 -0800)
committerDavid Schleef <ds@schleef.org>
Sat, 4 Feb 2012 21:41:47 +0000 (13:41 -0800)
gst/videoscale/gstvideoscale.c
gst/videoscale/vs_image.c
gst/videoscale/vs_image.h
gst/videoscale/vs_scanline.c
gst/videoscale/vs_scanline.h

index 6df4ba6..9f072a3 100644 (file)
@@ -1,6 +1,6 @@
 /* GStreamer
  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
- * Copyright (C) 2005 David Schleef <ds@schleef.org>
+ * Copyright (C) 2005-2012 David Schleef <ds@schleef.org>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -140,7 +140,8 @@ static GstStaticCaps gst_video_scale_format_caps[] = {
   GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("Y8  ")),
   GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("GREY")),
   GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AY64")),
-  GST_STATIC_CAPS (GST_VIDEO_CAPS_ARGB_64)
+  GST_STATIC_CAPS (GST_VIDEO_CAPS_ARGB_64),
+  GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("NV12"))
 };
 
 #define GST_TYPE_VIDEO_SCALE_METHOD (gst_video_scale_method_get_type())
@@ -1024,7 +1025,8 @@ gst_video_scale_setup_vs_image (VSImage * image, GstVideoFormat format,
   if (format == GST_VIDEO_FORMAT_I420
       || format == GST_VIDEO_FORMAT_YV12
       || format == GST_VIDEO_FORMAT_Y444
-      || format == GST_VIDEO_FORMAT_Y42B || format == GST_VIDEO_FORMAT_Y41B) {
+      || format == GST_VIDEO_FORMAT_Y42B || format == GST_VIDEO_FORMAT_Y41B
+      || format == GST_VIDEO_FORMAT_NV12) {
     image->real_pixels = data + gst_video_format_get_component_offset (format,
         component, width, height);
   } else {
@@ -1090,6 +1092,7 @@ _get_black_for_format (GstVideoFormat format)
     case GST_VIDEO_FORMAT_Y444:
     case GST_VIDEO_FORMAT_Y42B:
     case GST_VIDEO_FORMAT_Y41B:
+    case GST_VIDEO_FORMAT_NV12:
       return black[4];          /* Y, U, V, 0 */
     case GST_VIDEO_FORMAT_RGB16:
     case GST_VIDEO_FORMAT_RGB15:
@@ -1153,6 +1156,14 @@ gst_video_scale_transform (GstBaseTransform * trans, GstBuffer * in,
         videoscale->to_width, videoscale->to_height, videoscale->borders_w,
         videoscale->borders_h, GST_BUFFER_DATA (out));
   }
+  if (videoscale->format == GST_VIDEO_FORMAT_NV12) {
+    gst_video_scale_setup_vs_image (&src_u, videoscale->format, 1,
+        videoscale->from_width, videoscale->from_height, 0, 0,
+        GST_BUFFER_DATA (in));
+    gst_video_scale_setup_vs_image (&dest_u, videoscale->format, 1,
+        videoscale->to_width, videoscale->to_height, videoscale->borders_w,
+        videoscale->borders_h, GST_BUFFER_DATA (out));
+  }
 
   switch (videoscale->format) {
     case GST_VIDEO_FORMAT_RGBx:
@@ -1340,6 +1351,20 @@ gst_video_scale_transform (GstBaseTransform * trans, GstBuffer * in,
           goto unknown_mode;
       }
       break;
+    case GST_VIDEO_FORMAT_NV12:
+      switch (method) {
+        case GST_VIDEO_SCALE_NEAREST:
+          vs_image_scale_nearest_Y (&dest, &src, videoscale->tmp_buf);
+          vs_image_scale_nearest_NV12 (&dest_u, &src_u, videoscale->tmp_buf);
+          break;
+        case GST_VIDEO_SCALE_BILINEAR:
+          vs_image_scale_linear_Y (&dest, &src, videoscale->tmp_buf);
+          vs_image_scale_linear_NV12 (&dest_u, &src_u, videoscale->tmp_buf);
+          break;
+        default:
+          goto unknown_mode;
+      }
+      break;
     case GST_VIDEO_FORMAT_RGB16:
       if (add_borders)
         vs_fill_borders_RGB565 (&dest, black);
index c28b0d8..09ccf25 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Image Scaling Functions
- * Copyright (c) 2005 David A. Schleef <ds@schleef.org>
+ * Copyright (c) 2005-2012 David A. Schleef <ds@schleef.org>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -522,6 +522,136 @@ vs_image_scale_linear_UYVY (const VSImage * dest, const VSImage * src,
   }
 }
 
+/* NV12 */
+
+void
+vs_image_scale_nearest_NV12 (const VSImage * dest, const VSImage * src,
+    uint8_t * tmpbuf)
+{
+  int acc;
+  int y_increment;
+  int x_increment;
+  int i;
+  int j;
+  int xacc;
+
+  if (dest->height == 1)
+    y_increment = 0;
+  else
+    y_increment = ((src->height - 1) << 16) / (dest->height - 1);
+
+  if (dest->width == 1)
+    x_increment = 0;
+  else
+    x_increment = ((src->width - 1) << 16) / (dest->width - 1);
+
+  acc = 0;
+  for (i = 0; i < dest->height; i++) {
+    j = acc >> 16;
+
+    xacc = 0;
+    vs_scanline_resample_nearest_NV12 (dest->pixels + i * dest->stride,
+        src->pixels + j * src->stride, src->width, dest->width, &xacc,
+        x_increment);
+
+    acc += y_increment;
+  }
+}
+
+void
+vs_image_scale_linear_NV12 (const VSImage * dest, const VSImage * src,
+    uint8_t * tmpbuf)
+{
+  int acc;
+  int y_increment;
+  int x_increment;
+  uint8_t *tmp1;
+  uint8_t *tmp2;
+  int y1;
+  int y2;
+  int i;
+  int j;
+  int x;
+  int dest_size;
+  int xacc;
+
+  if (dest->height == 1)
+    y_increment = 0;
+  else
+    y_increment = ((src->height - 1) << 16) / (dest->height - 1) - 1;
+
+  if (dest->width == 1)
+    x_increment = 0;
+  else
+    x_increment = ((src->width - 1) << 16) / (dest->width - 1) - 1;
+
+  dest_size = ROUND_UP_4 (dest->width * 2);
+
+  tmp1 = tmpbuf;
+  tmp2 = tmpbuf + dest_size;
+
+  acc = 0;
+  xacc = 0;
+  y2 = -1;
+  vs_scanline_resample_linear_NV12 (tmp1, src->pixels, src->width, dest->width,
+      &xacc, x_increment);
+  y1 = 0;
+  for (i = 0; i < dest->height; i++) {
+    j = acc >> 16;
+    x = acc & 0xffff;
+
+    if (x == 0) {
+      if (j == y1) {
+        memcpy (dest->pixels + i * dest->stride, tmp1, dest_size);
+      } else if (j == y2) {
+        memcpy (dest->pixels + i * dest->stride, tmp2, dest_size);
+      } else {
+        xacc = 0;
+        vs_scanline_resample_linear_NV12 (tmp1, src->pixels + j * src->stride,
+            src->width, dest->width, &xacc, x_increment);
+        y1 = j;
+        memcpy (dest->pixels + i * dest->stride, tmp1, dest_size);
+      }
+    } else {
+      if (j == y1) {
+        if (j + 1 != y2) {
+          xacc = 0;
+          vs_scanline_resample_linear_NV12 (tmp2,
+              src->pixels + (j + 1) * src->stride, src->width, dest->width,
+              &xacc, x_increment);
+          y2 = j + 1;
+        }
+        vs_scanline_merge_linear_NV12 (dest->pixels + i * dest->stride,
+            tmp1, tmp2, dest->width, x);
+      } else if (j == y2) {
+        if (j + 1 != y1) {
+          xacc = 0;
+          vs_scanline_resample_linear_NV12 (tmp1,
+              src->pixels + (j + 1) * src->stride, src->width, dest->width,
+              &xacc, x_increment);
+          y1 = j + 1;
+        }
+        vs_scanline_merge_linear_NV12 (dest->pixels + i * dest->stride,
+            tmp2, tmp1, dest->width, x);
+      } else {
+        xacc = 0;
+        vs_scanline_resample_linear_NV12 (tmp1, src->pixels + j * src->stride,
+            src->width, dest->width, &xacc, x_increment);
+        y1 = j;
+        xacc = 0;
+        vs_scanline_resample_linear_NV12 (tmp2,
+            src->pixels + (j + 1) * src->stride, src->width, dest->width,
+            &xacc, x_increment);
+        y2 = (j + 1);
+        vs_scanline_merge_linear_NV12 (dest->pixels + i * dest->stride,
+            tmp1, tmp2, dest->width, x);
+      }
+    }
+
+    acc += y_increment;
+  }
+}
+
 /* greyscale */
 
 void
index 7b34991..d3cc31d 100644 (file)
@@ -71,6 +71,11 @@ void vs_image_scale_nearest_UYVY (const VSImage *dest, const VSImage *src,
 void vs_image_scale_linear_UYVY (const VSImage *dest, const VSImage *src,
     uint8_t *tmpbuf);
 
+void vs_image_scale_nearest_NV12 (const VSImage *dest, const VSImage *src,
+    uint8_t *tmpbuf);
+void vs_image_scale_linear_NV12 (const VSImage *dest, const VSImage *src,
+    uint8_t *tmpbuf);
+
 void vs_image_scale_nearest_Y (const VSImage *dest, const VSImage *src,
     uint8_t *tmpbuf);
 void vs_image_scale_linear_Y (const VSImage *dest, const VSImage *src,
index 822a6b6..c9459c2 100644 (file)
@@ -519,6 +519,88 @@ vs_scanline_merge_linear_UYVY (uint8_t * dest, uint8_t * src1,
 }
 
 
+/* NV12 */
+
+/* n is the number of bi-pixels */
+
+void
+vs_scanline_downsample_NV12 (uint8_t * dest, uint8_t * src, int n)
+{
+  int i;
+
+  for (i = 0; i < n; i++) {
+    dest[i * 2 + 0] = (src[i * 4 + 0] + src[i * 4 + 2]) / 2;
+    dest[i * 2 + 1] = (src[i * 4 + 1] + src[i * 4 + 3]) / 2;
+  }
+}
+
+void
+vs_scanline_resample_nearest_NV12 (uint8_t * dest, uint8_t * src, int src_width,
+    int n, int *accumulator, int increment)
+{
+  int acc = *accumulator;
+  int i;
+  int j;
+  int x;
+
+  for (i = 0; i < n; i++) {
+    j = acc >> 16;
+    x = acc & 0xffff;
+
+    dest[i * 2 + 0] = (x < 32768
+        || j + 1 >= src_width) ? src[j * 2 + 0] : src[j * 2 + 2];
+    dest[i * 2 + 1] = (x < 32768
+        || j + 1 >= src_width) ? src[j * 2 + 1] : src[j * 2 + 3];
+
+    acc += increment;
+  }
+
+  *accumulator = acc;
+}
+
+void
+vs_scanline_resample_linear_NV12 (uint8_t * dest, uint8_t * src, int src_width,
+    int n, int *accumulator, int increment)
+{
+  int acc = *accumulator;
+  int i;
+  int j;
+  int x;
+
+  for (i = 0; i < n; i++) {
+    j = acc >> 16;
+    x = acc & 0xffff;
+
+    if (j + 1 < src_width) {
+      dest[i * 2 + 0] =
+          (src[j * 2 + 0] * (65536 - x) + src[j * 2 + 2] * x) >> 16;
+      dest[i * 2 + 1] =
+          (src[j * 2 + 1] * (65536 - x) + src[j * 2 + 3] * x) >> 16;
+    } else {
+      dest[i * 4 + 0] = src[j * 2 + 0];
+      dest[i * 4 + 1] = src[j * 2 + 1];
+    }
+
+    acc += increment;
+  }
+
+  *accumulator = acc;
+}
+
+void
+vs_scanline_merge_linear_NV12 (uint8_t * dest, uint8_t * src1,
+    uint8_t * src2, int n, int x)
+{
+  uint32_t value = x >> 8;
+
+  if (value == 0) {
+    memcpy (dest, src1, n * 2);
+  } else {
+    orc_merge_linear_u8 (dest, src1, src2, value, n * 2);
+  }
+}
+
+
 /* RGB565 */
 
 /* note that src and dest are uint16_t, and thus endian dependent */
index 387fc95..92d8f6f 100644 (file)
@@ -55,6 +55,11 @@ void vs_scanline_resample_nearest_UYVY (uint8_t *dest, uint8_t *src, int src_wid
 void vs_scanline_resample_linear_UYVY (uint8_t *dest, uint8_t *src, int src_width, int n, int *accumulator, int increment);
 void vs_scanline_merge_linear_UYVY (uint8_t *dest, uint8_t *src1, uint8_t *src2, int n, int x);
 
+void vs_scanline_downsample_NV12 (uint8_t *dest, uint8_t *src, int n);
+void vs_scanline_resample_nearest_NV12 (uint8_t *dest, uint8_t *src, int src_width, int n, int *accumulator, int increment);
+void vs_scanline_resample_linear_NV12 (uint8_t *dest, uint8_t *src, int src_width, int n, int *accumulator, int increment);
+void vs_scanline_merge_linear_NV12 (uint8_t *dest, uint8_t *src1, uint8_t *src2, int n, int x);
+
 void vs_scanline_downsample_RGB565 (uint8_t *dest, uint8_t *src, int n);
 void vs_scanline_resample_nearest_RGB565 (uint8_t *dest, uint8_t *src, int src_width, int n, int *accumulator, int increment);
 void vs_scanline_resample_linear_RGB565 (uint8_t *dest, uint8_t *src, int src_width, int n, int *accumulator, int increment);