videoflip: Add support for 10/12bit planar formats
authorPiotr Brzeziński <piotr@centricular.com>
Tue, 9 Aug 2022 07:42:23 +0000 (09:42 +0200)
committerGStreamer Marge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Wed, 10 Aug 2022 10:52:27 +0000 (10:52 +0000)
Implements support for I420, I422 and Y444 in 10/12 bit LE/BE variants.
I422 is handled separately from the rest, as it needs to consider
the endianness of the current format during most transforms.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2788>

subprojects/gst-plugins-good/docs/gst_plugins_cache.json
subprojects/gst-plugins-good/gst/videofilter/gstvideoflip.c

index a230a1e..cead12b 100644 (file)
                 "long-name": "Video flipper",
                 "pad-templates": {
                     "sink": {
-                        "caps": "video/x-raw:\n         format: { AYUV, ARGB, BGRA, ABGR, RGBA, Y444, xRGB, RGBx, xBGR, BGRx, RGB, BGR, I420, YV12, IYUV, YUY2, UYVY, YVYU, NV12, NV21, GRAY8, GRAY16_BE, GRAY16_LE }\n          width: [ 1, 2147483647 ]\n         height: [ 1, 2147483647 ]\n      framerate: [ 0/1, 2147483647/1 ]\n",
+                        "caps": "video/x-raw:\n         format: { AYUV, ARGB, BGRA, ABGR, RGBA, Y444, xRGB, RGBx, xBGR, BGRx, RGB, BGR, I420, YV12, IYUV, YUY2, UYVY, YVYU, NV12, NV21, GRAY8, GRAY16_BE, GRAY16_LE, I420_10LE, I420_10BE, I420_12LE, I420_12BE, I422_10LE, I422_10BE, I422_12LE, I422_12BE, Y444_10LE, Y444_10BE, Y444_12LE, Y444_12BE }\n          width: [ 1, 2147483647 ]\n         height: [ 1, 2147483647 ]\n      framerate: [ 0/1, 2147483647/1 ]\n",
                         "direction": "sink",
                         "presence": "always"
                     },
                     "src": {
-                        "caps": "video/x-raw:\n         format: { AYUV, ARGB, BGRA, ABGR, RGBA, Y444, xRGB, RGBx, xBGR, BGRx, RGB, BGR, I420, YV12, IYUV, YUY2, UYVY, YVYU, NV12, NV21, GRAY8, GRAY16_BE, GRAY16_LE }\n          width: [ 1, 2147483647 ]\n         height: [ 1, 2147483647 ]\n      framerate: [ 0/1, 2147483647/1 ]\n",
+                        "caps": "video/x-raw:\n         format: { AYUV, ARGB, BGRA, ABGR, RGBA, Y444, xRGB, RGBx, xBGR, BGRx, RGB, BGR, I420, YV12, IYUV, YUY2, UYVY, YVYU, NV12, NV21, GRAY8, GRAY16_BE, GRAY16_LE, I420_10LE, I420_10BE, I420_12LE, I420_12BE, I422_10LE, I422_10BE, I422_12LE, I422_12BE, Y444_10LE, Y444_10BE, Y444_12LE, Y444_12BE }\n          width: [ 1, 2147483647 ]\n         height: [ 1, 2147483647 ]\n      framerate: [ 0/1, 2147483647/1 ]\n",
                         "direction": "src",
                         "presence": "always"
                     }
index 2403f2a..69d9a5e 100644 (file)
@@ -22,7 +22,7 @@
 
 /*
  * This file was (probably) generated from gstvideoflip.c,
- * gstvideoflip.c,v 1.7 2003/11/08 02:48:59 dschleef Exp 
+ * gstvideoflip.c,v 1.7 2003/11/08 02:48:59 dschleef Exp
  */
 /**
  * SECTION:element-videoflip
@@ -68,8 +68,9 @@ GST_STATIC_PAD_TEMPLATE ("src",
     GST_PAD_ALWAYS,
     GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ AYUV, "
             "ARGB, BGRA, ABGR, RGBA, Y444, xRGB, RGBx, xBGR, BGRx, "
-            "RGB, BGR, I420, YV12, IYUV, YUY2, UYVY, YVYU, NV12, NV21, "
-            "GRAY8, GRAY16_BE, GRAY16_LE }"))
+            "RGB, BGR, I420, YV12, IYUV, YUY2, UYVY, YVYU, NV12, NV21,"
+            "GRAY8, GRAY16_BE, GRAY16_LE, I420_10LE, I420_10BE, I420_12LE, I420_12BE, "
+            "I422_10LE, I422_10BE, I422_12LE, I422_12BE, Y444_10LE, Y444_10BE, Y444_12LE, Y444_12BE }"))
     );
 
 static GstStaticPadTemplate gst_video_flip_sink_template =
@@ -78,8 +79,9 @@ GST_STATIC_PAD_TEMPLATE ("sink",
     GST_PAD_ALWAYS,
     GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ AYUV, "
             "ARGB, BGRA, ABGR, RGBA, Y444, xRGB, RGBx, xBGR, BGRx, "
-            "RGB, BGR, I420, YV12, IYUV, YUY2, UYVY, YVYU, NV12, NV21, "
-            "GRAY8, GRAY16_BE, GRAY16_LE }"))
+            "RGB, BGR, I420, YV12, IYUV, YUY2, UYVY, YVYU, NV12, NV21,"
+            "GRAY8, GRAY16_BE, GRAY16_LE, I420_10LE, I420_10BE, I420_12LE, I420_12BE, "
+            "I422_10LE, I422_10BE, I422_12LE, I422_12BE, Y444_10LE, Y444_10BE, Y444_12LE, Y444_12BE }"))
     );
 
 #define GST_TYPE_VIDEO_FLIP_METHOD (gst_video_flip_method_get_type())
@@ -422,8 +424,257 @@ gst_video_flip_planar_yuv (GstVideoFlip * videoflip, GstVideoFrame * dest,
       /* Flip V */
       s = GST_VIDEO_FRAME_PLANE_DATA (src, 2);
       d = GST_VIDEO_FRAME_PLANE_DATA (dest, 2);
+      for (y = 0; y < dest_v_height; y++) {
+        for (x = 0; x < dest_v_width; x++) {
+          d[y * dest_v_stride + x] = s[x * src_v_stride + y];
+        }
+      }
+      break;
+    case GST_VIDEO_ORIENTATION_UR_LL:
+      /* Flip Y */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
+      for (y = 0; y < dest_y_height; y++) {
+        for (x = 0; x < dest_y_width; x++) {
+          d[y * dest_y_stride + x] =
+              s[(src_y_height - 1 - x) * src_y_stride + (src_y_width - 1 - y)];
+        }
+      }
+      /* Flip U */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 1);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 1);
+      for (y = 0; y < dest_u_height; y++) {
+        for (x = 0; x < dest_u_width; x++) {
+          d[y * dest_u_stride + x] =
+              s[(src_u_height - 1 - x) * src_u_stride + (src_u_width - 1 - y)];
+        }
+      }
+      /* Flip V */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 2);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 2);
+      for (y = 0; y < dest_v_height; y++) {
+        for (x = 0; x < dest_v_width; x++) {
+          d[y * dest_v_stride + x] =
+              s[(src_v_height - 1 - x) * src_v_stride + (src_v_width - 1 - y)];
+        }
+      }
+      break;
+    case GST_VIDEO_ORIENTATION_IDENTITY:
+      gst_video_frame_copy (dest, src);
+      break;
+    default:
+      g_assert_not_reached ();
+      break;
+  }
+}
+
+static void
+gst_video_flip_planar_yuv_16bit (GstVideoFlip * videoflip, GstVideoFrame * dest,
+    const GstVideoFrame * src)
+{
+  gint x, y;
+  guint16 const *s;
+  guint16 *d;
+  gint src_y_stride, src_u_stride, src_v_stride;
+  gint src_y_height, src_u_height, src_v_height;
+  gint src_y_width, src_u_width, src_v_width;
+  gint dest_y_stride, dest_u_stride, dest_v_stride;
+  gint dest_y_height, dest_u_height, dest_v_height;
+  gint dest_y_width, dest_u_width, dest_v_width;
+
+  /* Divide strides by 2 because we're operating on guint16's */
+  src_y_stride = GST_VIDEO_FRAME_PLANE_STRIDE (src, 0) / 2;
+  src_u_stride = GST_VIDEO_FRAME_PLANE_STRIDE (src, 1) / 2;
+  src_v_stride = GST_VIDEO_FRAME_PLANE_STRIDE (src, 2) / 2;
+
+  dest_y_stride = GST_VIDEO_FRAME_PLANE_STRIDE (dest, 0) / 2;
+  dest_u_stride = GST_VIDEO_FRAME_PLANE_STRIDE (dest, 1) / 2;
+  dest_v_stride = GST_VIDEO_FRAME_PLANE_STRIDE (dest, 2) / 2;
+
+  src_y_width = GST_VIDEO_FRAME_COMP_WIDTH (src, 0);
+  src_u_width = GST_VIDEO_FRAME_COMP_WIDTH (src, 1);
+  src_v_width = GST_VIDEO_FRAME_COMP_WIDTH (src, 2);
+
+  dest_y_width = GST_VIDEO_FRAME_COMP_WIDTH (dest, 0);
+  dest_u_width = GST_VIDEO_FRAME_COMP_WIDTH (dest, 1);
+  dest_v_width = GST_VIDEO_FRAME_COMP_WIDTH (dest, 2);
+
+  src_y_height = GST_VIDEO_FRAME_COMP_HEIGHT (src, 0);
+  src_u_height = GST_VIDEO_FRAME_COMP_HEIGHT (src, 1);
+  src_v_height = GST_VIDEO_FRAME_COMP_HEIGHT (src, 2);
+
+  dest_y_height = GST_VIDEO_FRAME_COMP_HEIGHT (dest, 0);
+  dest_u_height = GST_VIDEO_FRAME_COMP_HEIGHT (dest, 1);
+  dest_v_height = GST_VIDEO_FRAME_COMP_HEIGHT (dest, 2);
+
+  switch (videoflip->active_method) {
+    case GST_VIDEO_ORIENTATION_90R:
+      /* Flip Y */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
+      for (y = 0; y < dest_y_height; y++) {
+        for (x = 0; x < dest_y_width; x++) {
+          d[y * dest_y_stride + x] =
+              s[(src_y_height - 1 - x) * src_y_stride + y];
+        }
+      }
+      /* Flip U */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 1);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 1);
+      for (y = 0; y < dest_u_height; y++) {
+        for (x = 0; x < dest_u_width; x++) {
+          d[y * dest_u_stride + x] =
+              s[(src_u_height - 1 - x) * src_u_stride + y];
+        }
+      }
+      /* Flip V */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 2);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 2);
+      for (y = 0; y < dest_v_height; y++) {
+        for (x = 0; x < dest_v_width; x++) {
+          d[y * dest_v_stride + x] =
+              s[(src_v_height - 1 - x) * src_v_stride + y];
+        }
+      }
+      break;
+    case GST_VIDEO_ORIENTATION_90L:
+      /* Flip Y */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
+      for (y = 0; y < dest_y_height; y++) {
+        for (x = 0; x < dest_y_width; x++) {
+          d[y * dest_y_stride + x] =
+              s[x * src_y_stride + (src_y_width - 1 - y)];
+        }
+      }
+      /* Flip U */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 1);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 1);
+      for (y = 0; y < dest_u_height; y++) {
+        for (x = 0; x < dest_u_width; x++) {
+          d[y * dest_u_stride + x] =
+              s[x * src_u_stride + (src_u_width - 1 - y)];
+        }
+      }
+      /* Flip V */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 2);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 2);
+      for (y = 0; y < dest_v_height; y++) {
+        for (x = 0; x < dest_v_width; x++) {
+          d[y * dest_v_stride + x] =
+              s[x * src_v_stride + (src_v_width - 1 - y)];
+        }
+      }
+      break;
+    case GST_VIDEO_ORIENTATION_180:
+      /* Flip Y */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
+      for (y = 0; y < dest_y_height; y++) {
+        for (x = 0; x < dest_y_width; x++) {
+          d[y * dest_y_stride + x] =
+              s[(src_y_height - 1 - y) * src_y_stride + (src_y_width - 1 - x)];
+        }
+      }
+      /* Flip U */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 1);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 1);
+      for (y = 0; y < dest_u_height; y++) {
+        for (x = 0; x < dest_u_width; x++) {
+          d[y * dest_u_stride + x] =
+              s[(src_u_height - 1 - y) * src_u_stride + (src_u_width - 1 - x)];
+        }
+      }
+      /* Flip V */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 2);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 2);
+      for (y = 0; y < dest_v_height; y++) {
+        for (x = 0; x < dest_v_width; x++) {
+          d[y * dest_v_stride + x] =
+              s[(src_v_height - 1 - y) * src_v_stride + (src_v_width - 1 - x)];
+        }
+      }
+      break;
+    case GST_VIDEO_ORIENTATION_HORIZ:
+      /* Flip Y */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
+      for (y = 0; y < dest_y_height; y++) {
+        for (x = 0; x < dest_y_width; x++) {
+          d[y * dest_y_stride + x] =
+              s[y * src_y_stride + (src_y_width - 1 - x)];
+        }
+      }
+      /* Flip U */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 1);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 1);
+      for (y = 0; y < dest_u_height; y++) {
+        for (x = 0; x < dest_u_width; x++) {
+          d[y * dest_u_stride + x] =
+              s[y * src_u_stride + (src_u_width - 1 - x)];
+        }
+      }
+      /* Flip V */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 2);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 2);
+      for (y = 0; y < dest_v_height; y++) {
+        for (x = 0; x < dest_v_width; x++) {
+          d[y * dest_v_stride + x] =
+              s[y * src_v_stride + (src_v_width - 1 - x)];
+        }
+      }
+      break;
+    case GST_VIDEO_ORIENTATION_VERT:
+      /* Flip Y */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
+      for (y = 0; y < dest_y_height; y++) {
+        for (x = 0; x < dest_y_width; x++) {
+          d[y * dest_y_stride + x] =
+              s[(src_y_height - 1 - y) * src_y_stride + x];
+        }
+      }
+      /* Flip U */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 1);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 1);
+      for (y = 0; y < dest_u_height; y++) {
+        for (x = 0; x < dest_u_width; x++) {
+          d[y * dest_u_stride + x] =
+              s[(src_u_height - 1 - y) * src_u_stride + x];
+        }
+      }
+      /* Flip V */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 2);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 2);
+      for (y = 0; y < dest_v_height; y++) {
+        for (x = 0; x < dest_v_width; x++) {
+          d[y * dest_v_stride + x] =
+              s[(src_v_height - 1 - y) * src_v_stride + x];
+        }
+      }
+      break;
+    case GST_VIDEO_ORIENTATION_UL_LR:
+      /* Flip Y */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
+      for (y = 0; y < dest_y_height; y++) {
+        for (x = 0; x < dest_y_width; x++) {
+          d[y * dest_y_stride + x] = s[x * src_y_stride + y];
+        }
+      }
+      /* Flip U */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 1);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 1);
       for (y = 0; y < dest_u_height; y++) {
         for (x = 0; x < dest_u_width; x++) {
+          d[y * dest_u_stride + x] = s[x * src_u_stride + y];
+        }
+      }
+      /* Flip V */
+      s = GST_VIDEO_FRAME_PLANE_DATA (src, 2);
+      d = GST_VIDEO_FRAME_PLANE_DATA (dest, 2);
+      for (y = 0; y < dest_v_height; y++) {
+        for (x = 0; x < dest_v_width; x++) {
           d[y * dest_v_stride + x] = s[x * src_v_stride + y];
         }
       }
@@ -466,6 +717,228 @@ gst_video_flip_planar_yuv (GstVideoFlip * videoflip, GstVideoFrame * dest,
   }
 }
 
+static inline void
+rotate_yuv422_plane (GstVideoFrame * dest, const GstVideoFrame * src,
+    gint plane_index, GstVideoOrientationMethod method,
+    gboolean is_chroma, gboolean is_le)
+{
+  gint src_stride, src_height, src_width;
+  gint dest_stride, dest_height, dest_width;
+  gint x, y;
+  guint scale;
+  guint16 const *s, *addr;
+  guint16 *d;
+  guint16 val, val2;
+
+  s = GST_VIDEO_FRAME_PLANE_DATA (src, plane_index);
+  d = GST_VIDEO_FRAME_PLANE_DATA (dest, plane_index);
+
+  /* Divide strides by 2 because we're operating on guint16's */
+  src_stride = GST_VIDEO_FRAME_PLANE_STRIDE (src, plane_index) / 2;
+  src_height = GST_VIDEO_FRAME_COMP_HEIGHT (src, plane_index);
+  src_width = GST_VIDEO_FRAME_COMP_WIDTH (src, plane_index);
+
+  dest_stride = GST_VIDEO_FRAME_PLANE_STRIDE (dest, plane_index) / 2;
+  dest_height = GST_VIDEO_FRAME_COMP_HEIGHT (dest, plane_index);
+  dest_width = GST_VIDEO_FRAME_COMP_WIDTH (dest, plane_index);
+
+  scale = is_chroma ? 2 : 1;
+
+  switch (method) {
+    case GST_VIDEO_ORIENTATION_90R:
+      if (is_le) {
+        for (y = 0; y < dest_height; y++) {
+          for (x = 0; x < dest_width; x++) {
+            addr = s + (src_height - 1 - x * scale) * src_stride + y / scale;
+            val = GST_READ_UINT16_LE (addr);
+
+            if (is_chroma && x * 2 + 1 < src_height) {
+              addr = s + (src_height - 1 - (x * 2 + 1)) * src_stride + y / 2;
+              val2 = GST_READ_UINT16_LE (addr);
+              val = (val + val2) / 2;
+            }
+
+            GST_WRITE_UINT16_LE (d + y * dest_stride + x, val);
+          }
+        }
+      } else {
+        for (y = 0; y < dest_height; y++) {
+          for (x = 0; x < dest_width; x++) {
+            addr = s + (src_height - 1 - x * scale) * src_stride + y / scale;
+            val = GST_READ_UINT16_BE (addr);
+
+            if (is_chroma && x * 2 + 1 < src_height) {
+              addr = s + (src_height - 1 - (x * 2 + 1)) * src_stride + y / 2;
+              val2 = GST_READ_UINT16_BE (addr);
+              val = (val + val2) / 2;
+            }
+
+            GST_WRITE_UINT16_BE (d + y * dest_stride + x, val);
+          }
+        }
+      }
+      break;
+    case GST_VIDEO_ORIENTATION_90L:
+      if (is_le) {
+        for (y = 0; y < dest_height; y++) {
+          for (x = 0; x < dest_width; x++) {
+            addr = s + x * scale * src_stride + (src_width - 1 - y / scale);
+            val = GST_READ_UINT16_LE (addr);
+
+            if (is_chroma && x * 2 + 1 < src_width) {
+              addr = s + (x * 2 + 1) * src_stride + (src_width - 1 - y / 2);
+              val2 = GST_READ_UINT16_LE (addr);
+              val = (val + val2) / 2;
+            }
+
+            GST_WRITE_UINT16_LE (d + y * dest_stride + x, val);
+          }
+        }
+      } else {
+        for (y = 0; y < dest_height; y++) {
+          for (x = 0; x < dest_width; x++) {
+            addr = s + x * scale * src_stride + (src_width - 1 - y / scale);
+            val = GST_READ_UINT16_BE (addr);
+
+            if (is_chroma && x * 2 + 1 < src_width) {
+              addr = s + (x * 2 + 1) * src_stride + (src_width - 1 - y / 2);
+              val2 = GST_READ_UINT16_BE (addr);
+              val = (val + val2) / 2;
+            }
+
+            GST_WRITE_UINT16_BE (d + y * dest_stride + x, val);
+          }
+        }
+      }
+      break;
+    case GST_VIDEO_ORIENTATION_180:
+      for (y = 0; y < dest_height; y++) {
+        for (x = 0; x < dest_width; x++) {
+          d[y * dest_stride + x] =
+              s[(src_height - 1 - y) * src_stride + (src_width - 1 - x)];
+        }
+      }
+      break;
+    case GST_VIDEO_ORIENTATION_HORIZ:
+      for (y = 0; y < dest_height; y++) {
+        for (x = 0; x < dest_width; x++) {
+          d[y * dest_stride + x] = s[y * src_stride + (src_width - 1 - x)];
+        }
+      }
+      break;
+    case GST_VIDEO_ORIENTATION_VERT:
+      for (y = 0; y < dest_height; y++) {
+        for (x = 0; x < dest_width; x++) {
+          d[y * dest_stride + x] = s[(src_height - 1 - y) * src_stride + x];
+        }
+      }
+      break;
+    case GST_VIDEO_ORIENTATION_UL_LR:
+      if (is_le) {
+        for (y = 0; y < dest_height; y++) {
+          for (x = 0; x < dest_width; x++) {
+            addr = s + x * scale * src_stride + y / scale;
+            val = GST_READ_UINT16_LE (addr);
+
+            if (is_chroma && x * 2 + 1 < src_width) {
+              addr = s + (x * 2 + 1) * src_stride + y / 2;
+              val2 = GST_READ_UINT16_LE (addr);
+              val = (val + val2) / 2;
+            }
+
+            GST_WRITE_UINT16_LE (d + y * dest_stride + x, val);
+          }
+        }
+      } else {
+        for (y = 0; y < dest_height; y++) {
+          for (x = 0; x < dest_width; x++) {
+            addr = s + x * scale * src_stride + y / scale;
+            val = GST_READ_UINT16_BE (addr);
+
+            if (is_chroma && x * 2 + 1 < src_width) {
+              addr = s + (x * 2 + 1) * src_stride + y / 2;
+              val2 = GST_READ_UINT16_BE (addr);
+              val = (val + val2) / 2;
+            }
+
+            GST_WRITE_UINT16_BE (d + y * dest_stride + x, val);
+          }
+        }
+      }
+      break;
+    case GST_VIDEO_ORIENTATION_UR_LL:
+      if (is_le) {
+        for (y = 0; y < dest_height; y++) {
+          for (x = 0; x < dest_width; x++) {
+            addr = s
+                + (src_height - 1 - x * scale) * src_stride
+                + (src_width - 1 - y / scale);
+            val = GST_READ_UINT16_LE (addr);
+
+            if (is_chroma && x * 2 + 1 < src_width) {
+              addr = s
+                  + (src_height - 1 - (x * 2 + 1)) * src_stride
+                  + (src_width - 1 - y / 2);
+              val2 = GST_READ_UINT16_LE (addr);
+              val = (val + val2) / 2;
+            }
+
+            GST_WRITE_UINT16_LE (d + y * dest_stride + x, val);
+          }
+        }
+      } else {
+        for (y = 0; y < dest_height; y++) {
+          for (x = 0; x < dest_width; x++) {
+            addr = s
+                + (src_height - 1 - x * scale) * src_stride
+                + (src_width - 1 - y / scale);
+            val = GST_READ_UINT16_BE (addr);
+
+            if (is_chroma && x * 2 + 1 < src_width) {
+              addr = s
+                  + (src_height - 1 - (x * 2 + 1)) * src_stride
+                  + (src_width - 1 - y / 2);
+              val2 = GST_READ_UINT16_BE (addr);
+              val = (val + val2) / 2;
+            }
+
+            GST_WRITE_UINT16_BE (d + y * dest_stride + x, val);
+          }
+        }
+      }
+      break;
+    case GST_VIDEO_ORIENTATION_IDENTITY:
+      gst_video_frame_copy (dest, src);
+      break;
+    default:
+      g_assert_not_reached ();
+      break;
+  }
+}
+
+static void
+gst_video_flip_planar_yuv_422_16bit (GstVideoFlip * videoflip,
+    GstVideoFrame * dest, const GstVideoFrame * src)
+{
+  gboolean format_is_le;
+
+  /* We need to consider the endianness during transforms
+   * which need average chrominance values between two pixels */
+  format_is_le = GST_VIDEO_FORMAT_INFO_IS_LE (dest->info.finfo);
+
+  /* Attempt to get the compiler to inline specialized variants of this function 
+   * to avoid too much branching due to endianness checks */
+  if (format_is_le) {
+    rotate_yuv422_plane (dest, src, 0, videoflip->active_method, FALSE, TRUE);
+    rotate_yuv422_plane (dest, src, 1, videoflip->active_method, TRUE, TRUE);
+    rotate_yuv422_plane (dest, src, 2, videoflip->active_method, TRUE, TRUE);
+  } else {
+    rotate_yuv422_plane (dest, src, 0, videoflip->active_method, FALSE, FALSE);
+    rotate_yuv422_plane (dest, src, 1, videoflip->active_method, TRUE, FALSE);
+    rotate_yuv422_plane (dest, src, 2, videoflip->active_method, TRUE, FALSE);
+  }
+}
+
 static void
 gst_video_flip_semi_planar_yuv (GstVideoFlip * videoflip, GstVideoFrame * dest,
     const GstVideoFrame * src)
@@ -766,7 +1239,6 @@ gst_video_flip_packed_simple (GstVideoFlip * videoflip, GstVideoFrame * dest,
   }
 }
 
-
 static void
 gst_video_flip_y422 (GstVideoFlip * videoflip, GstVideoFrame * dest,
     const GstVideoFrame * src)
@@ -991,6 +1463,22 @@ gst_video_flip_configure_process (GstVideoFlip * vf)
     case GST_VIDEO_FORMAT_Y444:
       vf->process = gst_video_flip_planar_yuv;
       break;
+    case GST_VIDEO_FORMAT_I420_10LE:
+    case GST_VIDEO_FORMAT_I420_10BE:
+    case GST_VIDEO_FORMAT_I420_12LE:
+    case GST_VIDEO_FORMAT_I420_12BE:
+    case GST_VIDEO_FORMAT_Y444_10LE:
+    case GST_VIDEO_FORMAT_Y444_10BE:
+    case GST_VIDEO_FORMAT_Y444_12LE:
+    case GST_VIDEO_FORMAT_Y444_12BE:
+      vf->process = gst_video_flip_planar_yuv_16bit;
+      break;
+    case GST_VIDEO_FORMAT_I422_10LE:
+    case GST_VIDEO_FORMAT_I422_10BE:
+    case GST_VIDEO_FORMAT_I422_12LE:
+    case GST_VIDEO_FORMAT_I422_12BE:
+      vf->process = gst_video_flip_planar_yuv_422_16bit;
+      break;
     case GST_VIDEO_FORMAT_YUY2:
     case GST_VIDEO_FORMAT_UYVY:
     case GST_VIDEO_FORMAT_YVYU: