videoscale: Add support for interlaced content
authorSebastian Dröge <sebastian.droege@collabora.co.uk>
Tue, 28 Jul 2009 11:55:30 +0000 (13:55 +0200)
committerSebastian Dröge <sebastian.droege@collabora.co.uk>
Thu, 6 Aug 2009 04:43:31 +0000 (06:43 +0200)
videoscale is not mixing content of two seperate fields anymore
and does scaling on every field separately.

Fixes bug #588761.

gst/videoscale/gstvideoscale.c
gst/videoscale/gstvideoscale.h

index 252d8ae..10136a7 100644 (file)
@@ -494,7 +494,8 @@ unknown_format:
 }
 
 static gboolean
-parse_caps (GstCaps * caps, gint * format, gint * width, gint * height)
+parse_caps (GstCaps * caps, gint * format, gint * width, gint * height,
+    gboolean * interlaced)
 {
   gboolean ret;
   GstStructure *structure;
@@ -506,6 +507,11 @@ parse_caps (GstCaps * caps, gint * format, gint * width, gint * height)
   if (format)
     *format = gst_video_scale_get_format (caps);
 
+  if (interlaced) {
+    *interlaced = FALSE;
+    gst_structure_get_boolean (structure, "interlaced", interlaced);
+  }
+
   return ret;
 }
 
@@ -518,8 +524,10 @@ gst_video_scale_set_caps (GstBaseTransform * trans, GstCaps * in, GstCaps * out)
   videoscale = GST_VIDEO_SCALE (trans);
 
   ret = parse_caps (in, &videoscale->format, &videoscale->from_width,
-      &videoscale->from_height);
-  ret &= parse_caps (out, NULL, &videoscale->to_width, &videoscale->to_height);
+      &videoscale->from_height, &videoscale->interlaced);
+  ret &=
+      parse_caps (out, NULL, &videoscale->to_width, &videoscale->to_height,
+      NULL);
   if (!ret)
     goto done;
 
@@ -561,7 +569,7 @@ gst_video_scale_get_unit_size (GstBaseTransform * trans, GstCaps * caps,
 
   videoscale = GST_VIDEO_SCALE (trans);
 
-  if (!parse_caps (caps, &format, &width, &height))
+  if (!parse_caps (caps, &format, &width, &height, NULL))
     return FALSE;
 
   if (!gst_video_scale_prepare_size (videoscale, format, &img, width, height,
@@ -696,7 +704,8 @@ gst_video_scale_fixate_caps (GstBaseTransform * base, GstPadDirection direction,
 
 static gboolean
 gst_video_scale_prepare_image (gint format, GstBuffer * buf,
-    VSImage * img, VSImage * img_u, VSImage * img_v)
+    VSImage * img, VSImage * img_u, VSImage * img_v, gint step,
+    gboolean interlaced)
 {
   gboolean res = TRUE;
 
@@ -707,10 +716,19 @@ gst_video_scale_prepare_image (gint format, GstBuffer * buf,
     case GST_VIDEO_SCALE_YV12:
       img_u->pixels = img->pixels + GST_ROUND_UP_2 (img->height) * img->stride;
       img_u->height = GST_ROUND_UP_2 (img->height) / 2;
+      if (interlaced) {
+        img_u->height = (img_u->height / 2) + ((step == 0
+                && img_u->height % 2 == 1) ? 1 : 0);
+        img_u->stride *= 2;
+      }
       img_u->width = GST_ROUND_UP_2 (img->width) / 2;
       img_u->stride = GST_ROUND_UP_4 (img_u->width);
       memcpy (img_v, img_u, sizeof (*img_v));
       img_v->pixels = img_u->pixels + img_u->height * img_u->stride;
+      if (interlaced && step == 1) {
+        img_v->pixels += (img_v->stride / 2);
+        img_u->pixels += (img_u->stride / 2);
+      }
       break;
     default:
       break;
@@ -722,182 +740,205 @@ static GstFlowReturn
 gst_video_scale_transform (GstBaseTransform * trans, GstBuffer * in,
     GstBuffer * out)
 {
-  GstVideoScale *videoscale;
+  GstVideoScale *videoscale = GST_VIDEO_SCALE (trans);
   GstFlowReturn ret = GST_FLOW_OK;
-  VSImage *dest;
-  VSImage *src;
-  VSImage dest_u;
-  VSImage dest_v;
-  VSImage src_u;
-  VSImage src_v;
+  VSImage dest = videoscale->dest;
+  VSImage src = videoscale->src;
+  VSImage dest_u = { NULL, };
+  VSImage dest_v = { NULL, };
+  VSImage src_u = { NULL, };
+  VSImage src_v = { NULL, };
   gint method;
-
-  videoscale = GST_VIDEO_SCALE (trans);
+  gint step;
+  gboolean interlaced = videoscale->interlaced;
 
   GST_OBJECT_LOCK (videoscale);
   method = videoscale->method;
   GST_OBJECT_UNLOCK (videoscale);
 
-  src = &videoscale->src;
-  dest = &videoscale->dest;
+  if (src.height < 4 && method == GST_VIDEO_SCALE_4TAP)
+    method = GST_VIDEO_SCALE_BILINEAR;
 
-  gst_video_scale_prepare_image (videoscale->format, in, src, &src_u, &src_v);
-  gst_video_scale_prepare_image (videoscale->format, out, dest, &dest_u,
-      &dest_v);
+  /* For interlaced content we have to run two times with half height
+   * and doubled stride */
+  if (videoscale->interlaced) {
+    dest.height /= 2;
+    src.height /= 2;
+    dest.stride *= 2;
+    src.stride *= 2;
+  }
 
-  if (src->height < 4 && method == GST_VIDEO_SCALE_4TAP)
-    method = GST_VIDEO_SCALE_BILINEAR;
+  for (step = 0; step < (interlaced ? 2 : 1); step++) {
+    gst_video_scale_prepare_image (videoscale->format, in, &src, &src_u, &src_v,
+        step, interlaced);
+    gst_video_scale_prepare_image (videoscale->format, out, &dest, &dest_u,
+        &dest_v, step, interlaced);
 
-  switch (method) {
-    case GST_VIDEO_SCALE_NEAREST:
-      GST_LOG_OBJECT (videoscale, "doing nearest scaling");
-      switch (videoscale->format) {
-        case GST_VIDEO_SCALE_RGBx:
-        case GST_VIDEO_SCALE_xRGB:
-        case GST_VIDEO_SCALE_BGRx:
-        case GST_VIDEO_SCALE_xBGR:
-        case GST_VIDEO_SCALE_RGBA:
-        case GST_VIDEO_SCALE_ARGB:
-        case GST_VIDEO_SCALE_BGRA:
-        case GST_VIDEO_SCALE_ABGR:
-        case GST_VIDEO_SCALE_AYUV:
-          vs_image_scale_nearest_RGBA (dest, src, videoscale->tmp_buf);
-          break;
-        case GST_VIDEO_SCALE_RGB:
-        case GST_VIDEO_SCALE_BGR:
-        case GST_VIDEO_SCALE_v308:
-          vs_image_scale_nearest_RGB (dest, src, videoscale->tmp_buf);
-          break;
-        case GST_VIDEO_SCALE_YUY2:
-        case GST_VIDEO_SCALE_YVYU:
-          vs_image_scale_nearest_YUYV (dest, src, videoscale->tmp_buf);
-          break;
-        case GST_VIDEO_SCALE_UYVY:
-          vs_image_scale_nearest_UYVY (dest, src, videoscale->tmp_buf);
-          break;
-        case GST_VIDEO_SCALE_Y:
-        case GST_VIDEO_SCALE_GRAY8:
-          vs_image_scale_nearest_Y (dest, src, videoscale->tmp_buf);
-          break;
-        case GST_VIDEO_SCALE_GRAY16:
-          vs_image_scale_nearest_Y16 (dest, src, videoscale->tmp_buf);
-          break;
-        case GST_VIDEO_SCALE_I420:
-        case GST_VIDEO_SCALE_YV12:
-          vs_image_scale_nearest_Y (dest, src, videoscale->tmp_buf);
-          vs_image_scale_nearest_Y (&dest_u, &src_u, videoscale->tmp_buf);
-          vs_image_scale_nearest_Y (&dest_v, &src_v, videoscale->tmp_buf);
-          break;
-        case GST_VIDEO_SCALE_RGB565:
-          vs_image_scale_nearest_RGB565 (dest, src, videoscale->tmp_buf);
-          break;
-        case GST_VIDEO_SCALE_RGB555:
-          vs_image_scale_nearest_RGB555 (dest, src, videoscale->tmp_buf);
-          break;
-        default:
-          goto unsupported;
+    if (step == 0 && interlaced) {
+      if (videoscale->from_height % 2 == 1) {
+        src.height += 1;
       }
-      break;
-    case GST_VIDEO_SCALE_BILINEAR:
-      GST_LOG_OBJECT (videoscale, "doing bilinear scaling");
-      switch (videoscale->format) {
-        case GST_VIDEO_SCALE_RGBx:
-        case GST_VIDEO_SCALE_xRGB:
-        case GST_VIDEO_SCALE_BGRx:
-        case GST_VIDEO_SCALE_xBGR:
-        case GST_VIDEO_SCALE_RGBA:
-        case GST_VIDEO_SCALE_ARGB:
-        case GST_VIDEO_SCALE_BGRA:
-        case GST_VIDEO_SCALE_ABGR:
-        case GST_VIDEO_SCALE_AYUV:
-          vs_image_scale_linear_RGBA (dest, src, videoscale->tmp_buf);
-          break;
-        case GST_VIDEO_SCALE_RGB:
-        case GST_VIDEO_SCALE_BGR:
-        case GST_VIDEO_SCALE_v308:
-          vs_image_scale_linear_RGB (dest, src, videoscale->tmp_buf);
-          break;
-        case GST_VIDEO_SCALE_YUY2:
-        case GST_VIDEO_SCALE_YVYU:
-          vs_image_scale_linear_YUYV (dest, src, videoscale->tmp_buf);
-          break;
-        case GST_VIDEO_SCALE_UYVY:
-          vs_image_scale_linear_UYVY (dest, src, videoscale->tmp_buf);
-          break;
-        case GST_VIDEO_SCALE_Y:
-        case GST_VIDEO_SCALE_GRAY8:
-          vs_image_scale_linear_Y (dest, src, videoscale->tmp_buf);
-          break;
-        case GST_VIDEO_SCALE_GRAY16:
-          vs_image_scale_linear_Y16 (dest, src, videoscale->tmp_buf);
-          break;
-        case GST_VIDEO_SCALE_I420:
-        case GST_VIDEO_SCALE_YV12:
-          vs_image_scale_linear_Y (dest, src, videoscale->tmp_buf);
-          vs_image_scale_linear_Y (&dest_u, &src_u, videoscale->tmp_buf);
-          vs_image_scale_linear_Y (&dest_v, &src_v, videoscale->tmp_buf);
-          break;
-        case GST_VIDEO_SCALE_RGB565:
-          vs_image_scale_linear_RGB565 (dest, src, videoscale->tmp_buf);
-          break;
-        case GST_VIDEO_SCALE_RGB555:
-          vs_image_scale_linear_RGB555 (dest, src, videoscale->tmp_buf);
-          break;
-        default:
-          goto unsupported;
-      }
-      break;
-    case GST_VIDEO_SCALE_4TAP:
-      GST_LOG_OBJECT (videoscale, "doing 4tap scaling");
-      switch (videoscale->format) {
-        case GST_VIDEO_SCALE_RGBx:
-        case GST_VIDEO_SCALE_xRGB:
-        case GST_VIDEO_SCALE_BGRx:
-        case GST_VIDEO_SCALE_xBGR:
-        case GST_VIDEO_SCALE_RGBA:
-        case GST_VIDEO_SCALE_ARGB:
-        case GST_VIDEO_SCALE_BGRA:
-        case GST_VIDEO_SCALE_ABGR:
-        case GST_VIDEO_SCALE_AYUV:
-          vs_image_scale_4tap_RGBA (dest, src, videoscale->tmp_buf);
-          break;
-        case GST_VIDEO_SCALE_RGB:
-        case GST_VIDEO_SCALE_BGR:
-        case GST_VIDEO_SCALE_v308:
-          vs_image_scale_4tap_RGB (dest, src, videoscale->tmp_buf);
-          break;
-        case GST_VIDEO_SCALE_YUY2:
-        case GST_VIDEO_SCALE_YVYU:
-          vs_image_scale_4tap_YUYV (dest, src, videoscale->tmp_buf);
-          break;
-        case GST_VIDEO_SCALE_UYVY:
-          vs_image_scale_4tap_UYVY (dest, src, videoscale->tmp_buf);
-          break;
-        case GST_VIDEO_SCALE_Y:
-        case GST_VIDEO_SCALE_GRAY8:
-          vs_image_scale_4tap_Y (dest, src, videoscale->tmp_buf);
-          break;
-        case GST_VIDEO_SCALE_GRAY16:
-          vs_image_scale_4tap_Y16 (dest, src, videoscale->tmp_buf);
-          break;
-        case GST_VIDEO_SCALE_I420:
-        case GST_VIDEO_SCALE_YV12:
-          vs_image_scale_4tap_Y (dest, src, videoscale->tmp_buf);
-          vs_image_scale_4tap_Y (&dest_u, &src_u, videoscale->tmp_buf);
-          vs_image_scale_4tap_Y (&dest_v, &src_v, videoscale->tmp_buf);
-          break;
-        case GST_VIDEO_SCALE_RGB565:
-          vs_image_scale_4tap_RGB565 (dest, src, videoscale->tmp_buf);
-          break;
-        case GST_VIDEO_SCALE_RGB555:
-          vs_image_scale_4tap_RGB555 (dest, src, videoscale->tmp_buf);
-          break;
-        default:
-          goto unsupported;
+
+      if (videoscale->to_height % 2 == 1) {
+        dest.height += 1;
       }
-      break;
-    default:
-      goto unknown_mode;
+    } else if (step == 1 && interlaced) {
+      src.pixels += (src.stride / 2);
+      dest.pixels += (dest.stride / 2);
+    }
+
+    switch (method) {
+      case GST_VIDEO_SCALE_NEAREST:
+        GST_LOG_OBJECT (videoscale, "doing nearest scaling");
+        switch (videoscale->format) {
+          case GST_VIDEO_SCALE_RGBx:
+          case GST_VIDEO_SCALE_xRGB:
+          case GST_VIDEO_SCALE_BGRx:
+          case GST_VIDEO_SCALE_xBGR:
+          case GST_VIDEO_SCALE_RGBA:
+          case GST_VIDEO_SCALE_ARGB:
+          case GST_VIDEO_SCALE_BGRA:
+          case GST_VIDEO_SCALE_ABGR:
+          case GST_VIDEO_SCALE_AYUV:
+            vs_image_scale_nearest_RGBA (&dest, &src, videoscale->tmp_buf);
+            break;
+          case GST_VIDEO_SCALE_RGB:
+          case GST_VIDEO_SCALE_BGR:
+          case GST_VIDEO_SCALE_v308:
+            vs_image_scale_nearest_RGB (&dest, &src, videoscale->tmp_buf);
+            break;
+          case GST_VIDEO_SCALE_YUY2:
+          case GST_VIDEO_SCALE_YVYU:
+            vs_image_scale_nearest_YUYV (&dest, &src, videoscale->tmp_buf);
+            break;
+          case GST_VIDEO_SCALE_UYVY:
+            vs_image_scale_nearest_UYVY (&dest, &src, videoscale->tmp_buf);
+            break;
+          case GST_VIDEO_SCALE_Y:
+          case GST_VIDEO_SCALE_GRAY8:
+            vs_image_scale_nearest_Y (&dest, &src, videoscale->tmp_buf);
+            break;
+          case GST_VIDEO_SCALE_GRAY16:
+            vs_image_scale_nearest_Y16 (&dest, &src, videoscale->tmp_buf);
+            break;
+          case GST_VIDEO_SCALE_I420:
+          case GST_VIDEO_SCALE_YV12:
+            vs_image_scale_nearest_Y (&dest, &src, videoscale->tmp_buf);
+            vs_image_scale_nearest_Y (&dest_u, &src_u, videoscale->tmp_buf);
+            vs_image_scale_nearest_Y (&dest_v, &src_v, videoscale->tmp_buf);
+            break;
+          case GST_VIDEO_SCALE_RGB565:
+            vs_image_scale_nearest_RGB565 (&dest, &src, videoscale->tmp_buf);
+            break;
+          case GST_VIDEO_SCALE_RGB555:
+            vs_image_scale_nearest_RGB555 (&dest, &src, videoscale->tmp_buf);
+            break;
+          default:
+            goto unsupported;
+        }
+        break;
+      case GST_VIDEO_SCALE_BILINEAR:
+        GST_LOG_OBJECT (videoscale, "doing bilinear scaling");
+        switch (videoscale->format) {
+          case GST_VIDEO_SCALE_RGBx:
+          case GST_VIDEO_SCALE_xRGB:
+          case GST_VIDEO_SCALE_BGRx:
+          case GST_VIDEO_SCALE_xBGR:
+          case GST_VIDEO_SCALE_RGBA:
+          case GST_VIDEO_SCALE_ARGB:
+          case GST_VIDEO_SCALE_BGRA:
+          case GST_VIDEO_SCALE_ABGR:
+          case GST_VIDEO_SCALE_AYUV:
+            vs_image_scale_linear_RGBA (&dest, &src, videoscale->tmp_buf);
+            break;
+          case GST_VIDEO_SCALE_RGB:
+          case GST_VIDEO_SCALE_BGR:
+          case GST_VIDEO_SCALE_v308:
+            vs_image_scale_linear_RGB (&dest, &src, videoscale->tmp_buf);
+            break;
+          case GST_VIDEO_SCALE_YUY2:
+          case GST_VIDEO_SCALE_YVYU:
+            vs_image_scale_linear_YUYV (&dest, &src, videoscale->tmp_buf);
+            break;
+          case GST_VIDEO_SCALE_UYVY:
+            vs_image_scale_linear_UYVY (&dest, &src, videoscale->tmp_buf);
+            break;
+          case GST_VIDEO_SCALE_Y:
+          case GST_VIDEO_SCALE_GRAY8:
+            vs_image_scale_linear_Y (&dest, &src, videoscale->tmp_buf);
+            break;
+          case GST_VIDEO_SCALE_GRAY16:
+            vs_image_scale_linear_Y16 (&dest, &src, videoscale->tmp_buf);
+            break;
+          case GST_VIDEO_SCALE_I420:
+          case GST_VIDEO_SCALE_YV12:
+            vs_image_scale_linear_Y (&dest, &src, videoscale->tmp_buf);
+            vs_image_scale_linear_Y (&dest_u, &src_u, videoscale->tmp_buf);
+            vs_image_scale_linear_Y (&dest_v, &src_v, videoscale->tmp_buf);
+            break;
+          case GST_VIDEO_SCALE_RGB565:
+            vs_image_scale_linear_RGB565 (&dest, &src, videoscale->tmp_buf);
+            break;
+          case GST_VIDEO_SCALE_RGB555:
+            vs_image_scale_linear_RGB555 (&dest, &src, videoscale->tmp_buf);
+            break;
+          default:
+            goto unsupported;
+        }
+        break;
+      case GST_VIDEO_SCALE_4TAP:
+        GST_LOG_OBJECT (videoscale, "doing 4tap scaling");
+        switch (videoscale->format) {
+          case GST_VIDEO_SCALE_RGBx:
+          case GST_VIDEO_SCALE_xRGB:
+          case GST_VIDEO_SCALE_BGRx:
+          case GST_VIDEO_SCALE_xBGR:
+          case GST_VIDEO_SCALE_RGBA:
+          case GST_VIDEO_SCALE_ARGB:
+          case GST_VIDEO_SCALE_BGRA:
+          case GST_VIDEO_SCALE_ABGR:
+          case GST_VIDEO_SCALE_AYUV:
+            vs_image_scale_4tap_RGBA (&dest, &src, videoscale->tmp_buf);
+            break;
+          case GST_VIDEO_SCALE_RGB:
+          case GST_VIDEO_SCALE_BGR:
+          case GST_VIDEO_SCALE_v308:
+            vs_image_scale_4tap_RGB (&dest, &src, videoscale->tmp_buf);
+            break;
+          case GST_VIDEO_SCALE_YUY2:
+          case GST_VIDEO_SCALE_YVYU:
+            vs_image_scale_4tap_YUYV (&dest, &src, videoscale->tmp_buf);
+            break;
+          case GST_VIDEO_SCALE_UYVY:
+            vs_image_scale_4tap_UYVY (&dest, &src, videoscale->tmp_buf);
+            break;
+          case GST_VIDEO_SCALE_Y:
+          case GST_VIDEO_SCALE_GRAY8:
+            vs_image_scale_4tap_Y (&dest, &src, videoscale->tmp_buf);
+            break;
+          case GST_VIDEO_SCALE_GRAY16:
+            vs_image_scale_4tap_Y16 (&dest, &src, videoscale->tmp_buf);
+            break;
+          case GST_VIDEO_SCALE_I420:
+          case GST_VIDEO_SCALE_YV12:
+            vs_image_scale_4tap_Y (&dest, &src, videoscale->tmp_buf);
+            vs_image_scale_4tap_Y (&dest_u, &src_u, videoscale->tmp_buf);
+            vs_image_scale_4tap_Y (&dest_v, &src_v, videoscale->tmp_buf);
+            break;
+          case GST_VIDEO_SCALE_RGB565:
+            vs_image_scale_4tap_RGB565 (&dest, &src, videoscale->tmp_buf);
+            break;
+          case GST_VIDEO_SCALE_RGB555:
+            vs_image_scale_4tap_RGB555 (&dest, &src, videoscale->tmp_buf);
+            break;
+          default:
+            goto unsupported;
+        }
+        break;
+      default:
+        goto unknown_mode;
+    }
+
   }
 
   GST_LOG_OBJECT (videoscale, "pushing buffer of %d bytes",
index 2024270..9ccb575 100644 (file)
@@ -78,6 +78,7 @@ struct _GstVideoScale {
   gint to_height;
   gint from_width;
   gint from_height;
+  gboolean interlaced;
   
   /*< private >*/
   guint8 *tmp_buf;