video: add NV12T support
authorWim Taymans <wtaymans@redhat.com>
Fri, 20 Dec 2013 20:27:46 +0000 (21:27 +0100)
committerNicolas Dufresne <nicolas.dufresne@collabora.com>
Mon, 13 Jan 2014 15:45:26 +0000 (10:45 -0500)
https://bugzilla.gnome.org/show_bug.cgi?id=707361

docs/design/part-mediatype-video-raw.txt
gst-libs/gst/video/video-format.c
gst-libs/gst/video/video-format.h
gst-libs/gst/video/video-info.c

index 5e74dec..c66a075 100644 (file)
@@ -1188,3 +1188,46 @@ Formats
           default size: size (component0) + 
                         size (component1) +
                         size (component2)
+
+ "Y444_10BE" planar 4:4:4 YUV, 10 bits per channel
+ "Y444_10LE" planar 4:4:4 YUV, 10 bits per channel
+
+ "GBR" planar 4:4:4 RGB, 8 bits per channel
+ "GBR_10BE" planar 4:4:4 RGB, 10 bits per channel
+ "GBR_10LE" planar 4:4:4 RGB, 10 bits per channel
+
+ "NV16" planar 4:2:2 YUV with interleaved UV plane
+ "NV24" planar 4:4:4 YUV with interleaved UV plane
+
+
+ "NV12T" planar 4:2:0 YUV with interleaved UV plane in 64x32 tiles zigzag
+
+        Component 0: Y
+          depth:           8
+          pstride:         1
+          default offset:  0
+          default rstride: RU128 (width)
+          default size:    rstride (component0) * RU32 (height)
+
+        Component 1: U
+          depth            8
+          pstride:         2
+          default offset:  size (component0)
+          default rstride: RU128 (width)
+
+        Component 2: V
+          depth:           8
+          pstride:         2
+          default offset:  offset (component1) + 1
+          default rstride: RU128 (width)
+
+        Component 3: T
+          pstride          TileMode zigzag
+          w_sub            6
+          h_sub            5
+          default offset:  0
+          default rstride: y_tiles
+
+        Image
+          default size: RU128 (width) * RU32 (height) * 3 / 2
+
index 2b3f4b0..85977a2 100644 (file)
@@ -2082,6 +2082,238 @@ pack_I422_10BE (const GstVideoFormatInfo * info, GstVideoPackFlags flags,
   }
 }
 
+/**
+ * GstVideoTileMode:
+ * @GST_VIDEO_TILE_MODE_UNKNOWN: Unknown or unset video format id
+ * @GST_VIDEO_TILE_MODE_ZFLIPZ_2X2: Every four adjacent buffers - two
+ *    horizontally and two vertically are grouped together and are located
+ *    in memory in Z or flipped Z order.
+ *
+ * Enum value describing the most common video formats.
+ */
+typedef enum
+{
+  GST_VIDEO_TILE_MODE_NONE,
+  GST_VIDEO_TILE_MODE_ZFLIPZ_2X2,
+} GstVideoTileMode;
+
+/**
+ * gst_video_tile_get_index:
+ * @mode: a #GstVideoTileMode
+ * @x: x coordinate
+ * @y: y coordinate
+ * @x_tiles: number of horizintal tiles
+ * @y_tiles: number of vertical tiles
+ *
+ * Get the tile index of the tile at coordinates @x and @y.
+ *
+ * Returns: the index of the tile at @x and @y in the tiled image of
+ *   @x_tiles by @y_tiles.
+ */
+static gsize
+gst_video_tile_get_index (GstVideoTileMode mode, gint x, gint y,
+    gint x_tiles, gint y_tiles)
+{
+  gsize offset;
+
+  switch (mode) {
+    case GST_VIDEO_TILE_MODE_ZFLIPZ_2X2:
+      /* Due to the zigzag pattern we know that tiles are numbered like:
+       * (see http://linuxtv.org/downloads/v4l-dvb-apis/re31.html)
+       *
+       *         |             Column (x)
+       *         |   0    1    2    3    4    5    6    7
+       *  -------|---------------------------------------
+       *       0 |   0    1    6    7    8    9   14   15
+       *    R  1 |   2    3    4    5   10   11   12   13
+       *    o  2 |  16   17   22   23   24   25   30   31
+       *    w  3 |  18   19   20   21   26   27   28   29
+       *       4 |  32   33   38   39   40   41   46   47
+       *   (y) 5 |  34   35   36   37   42   43   44   45
+       *       6 |  48   49   50   51   52   53   54   55
+       *
+       * From this we can see that:
+       *
+       * For even rows:
+       * - The first block in a row is always mapped to memory block 'y * width'.
+       * - For all even rows, except for the last one when 'y' is odd, from the first
+       *   block number an offset is then added to obtain the block number for
+       *   the other blocks in the row. The offset is 'x' plus the corresponding
+       *   number in the series [0, 0, 4, 4, 4, 4, 8, 8, 8, 8, 12, ...], which can be
+       *   expressed as 'GST_ROUND_DOWN_4 (x + 2)'.
+       *       f(x,y,width,height) = y * width + x + GST_ROUND_DOWN_4 (x + 2)
+       *
+       * - For the last row when 'y' is odd the offset is simply 'x'.
+       *       f(x,y,width,height) = y * width + x
+       * - Note that 'y' is even, so 'GST_ROUNDOWN_2 (y) == y' in this case
+       *
+       *  For odd rows:
+       * - The first block in the row is always mapped to memory block
+       *   'GST_ROUND_DOWN_2(y) * width + 2'.
+       * - From the first block number an offset is then added to obtain the block
+       *   number for the other blocks in the row. The offset is 'x' plus the
+       *   corresponding number in the series [0, 0, 0, 0, 4, 4, 4, 4, 8, 8, 8, 8, 12, ...],
+       *   which can be  expressed as GST_ROUND_DOWN_4 (x).
+       *       f(x,y,width,height) = GST_ROUND_DOWN_2 (y) * width + bx 2 + GST_ROUND_DOWN_4 (x)
+       */
+      /* Common to all cases */
+      offset = GST_ROUND_DOWN_2 (y) * x_tiles + x;
+
+      if (y & 1) {
+        /* For odd row */
+        offset += 2 + GST_ROUND_DOWN_4 (x);
+      } else if ((y_tiles & 1) == 0 || y != (y_tiles - 1)) {
+        /* For even row except for the last row when odd height */
+        offset += GST_ROUND_DOWN_4 (x + 2);
+      }
+      break;
+    default:
+      offset = 0;
+      break;
+  }
+  return offset;
+}
+
+static void
+get_tile_NV12 (gint tile_width, gint tile_height, gint tile_size, gint tx,
+    gint ty, gint x_tiles, gint y_tiles,
+    const gpointer data[GST_VIDEO_MAX_PLANES],
+    const gint stride[GST_VIDEO_MAX_PLANES],
+    gpointer tile_data[GST_VIDEO_MAX_PLANES],
+    gint tile_stride[GST_VIDEO_MAX_PLANES])
+{
+  gsize offset;
+
+  /* index of Y tile */
+  offset = gst_video_tile_get_index (GST_VIDEO_TILE_MODE_ZFLIPZ_2X2,
+      tx, ty, x_tiles, y_tiles);
+  offset *= tile_size;
+  tile_data[0] = ((guint8 *) data[0]) + offset;
+  tile_stride[0] = tile_width;
+
+  /* index of UV tile */
+  offset = gst_video_tile_get_index (GST_VIDEO_TILE_MODE_ZFLIPZ_2X2,
+      tx, ty >> 1, x_tiles, (y_tiles + 1) >> 1);
+  offset *= tile_size;
+  /* On odd rows we return the second part of the UV tile */
+  if (ty & 1)
+    offset += tile_width * (tile_height >> 1);
+  tile_data[1] = ((guint8 *) data[1]) + offset;
+  tile_stride[1] = tile_width;
+}
+
+#define PACK_NV12T GST_VIDEO_FORMAT_AYUV, unpack_NV12T, 1, pack_NV12T
+static void
+unpack_NV12T (const GstVideoFormatInfo * info, GstVideoPackFlags flags,
+    gpointer dest, const gpointer data[GST_VIDEO_MAX_PLANES],
+    const gint stride[GST_VIDEO_MAX_PLANES], gint x, gint y, gint width)
+{
+  const GstVideoFormatInfo *unpack_info, *finfo;
+  guint8 *line = dest;
+  gint x_tiles, y_tiles;
+  gint tile_width, tile_height, tile_size;
+  gint ntx, tx, ty;
+  gint unpack_pstride;
+
+  tile_width = 1 << info->w_sub[3];
+  tile_height = 1 << info->h_sub[3];
+  tile_size = tile_width * tile_height;
+
+  x_tiles = stride[0] / 64;
+  y_tiles = stride[2];
+
+  /* we reuse these unpack functions */
+  finfo = gst_video_format_get_info (GST_VIDEO_FORMAT_NV12);
+
+  /* get pstride of unpacked format */
+  unpack_info = gst_video_format_get_info (info->unpack_format);
+  unpack_pstride = GST_VIDEO_FORMAT_INFO_PSTRIDE (unpack_info, 0);
+
+  /* first x tile to convert */
+  tx = x / tile_width;
+  /* Last tile to convert */
+  ntx = (x + width) / tile_width;
+  /* The row we are going to convert */
+  ty = y / tile_height;
+
+  /* y position in a tile */
+  y = y & (tile_height - 1);
+  /* x position in a tile */
+  x = x & (tile_width - 1);
+
+  for (; tx <= ntx; tx++) {
+    gpointer tdata[GST_VIDEO_MAX_PLANES];
+    gint tstride[GST_VIDEO_MAX_PLANES];
+    gint unpack_width;
+
+    get_tile_NV12 (tile_width, tile_height, tile_size, tx, ty, x_tiles, y_tiles,
+        data, stride, tdata, tstride);
+
+    /* the number of bytes left to unpack */
+    unpack_width = MIN (width - x, tile_width - x);
+
+    finfo->unpack_func (finfo, flags, line, tdata, tstride, x, y, unpack_width);
+
+    x = 0;
+    width -= unpack_width;
+    line += unpack_width * unpack_pstride;
+  }
+}
+
+static void
+pack_NV12T (const GstVideoFormatInfo * info, GstVideoPackFlags flags,
+    const gpointer src, gint sstride, gpointer data[GST_VIDEO_MAX_PLANES],
+    const gint stride[GST_VIDEO_MAX_PLANES], GstVideoChromaSite chroma_site,
+    gint y, gint width)
+{
+  const GstVideoFormatInfo *pack_info, *finfo;
+  guint8 *line = src;
+  gint x_tiles, y_tiles;
+  gint tile_width, tile_height, tile_size;
+  gint ntx, tx, ty;
+  gint pack_pstride;
+
+  tile_width = 1 << info->w_sub[3];
+  tile_height = 1 << info->h_sub[3];
+  tile_size = tile_width * tile_height;
+
+  x_tiles = stride[0] / 64;
+  y_tiles = stride[2];
+
+  /* we reuse these pack functions */
+  finfo = gst_video_format_get_info (GST_VIDEO_FORMAT_NV12);
+
+  /* get pstride of packed format */
+  pack_info = gst_video_format_get_info (info->unpack_format);
+  pack_pstride = GST_VIDEO_FORMAT_INFO_PSTRIDE (pack_info, 0);
+
+  /* Last tile to convert */
+  ntx = width / tile_width;
+  /* The row we are going to convert */
+  ty = y / tile_height;
+
+  /* y position in a tile */
+  y = y & (tile_height - 1);
+
+  for (tx = 0; tx < ntx; tx++) {
+    gpointer tdata[GST_VIDEO_MAX_PLANES];
+    gint tstride[GST_VIDEO_MAX_PLANES];
+    gint pack_width;
+
+    get_tile_NV12 (tile_width, tile_height, tile_size, tx, ty, x_tiles, y_tiles,
+        data, stride, tdata, tstride);
+
+    /* the number of bytes left to pack */
+    pack_width = MIN (width, tile_width);
+
+    finfo->pack_func (finfo, flags, line, sstride, tdata, tstride,
+        chroma_site, y, pack_width);
+
+    width -= pack_width;
+    line += pack_width * pack_pstride;
+  }
+}
+
 typedef struct
 {
   guint32 fourcc;
@@ -2094,6 +2326,7 @@ typedef struct
 #define DPTH8_32         8, 2, { 0, 0, 0, 0 }, { 8, 32, 0, 0 }
 #define DPTH888          8, 3, { 0, 0, 0, 0 }, { 8, 8, 8, 0 }
 #define DPTH8888         8, 4, { 0, 0, 0, 0 }, { 8, 8, 8, 8 }
+#define DPTH8880         8, 4, { 0, 0, 0, 0 }, { 8, 8, 8, 0 }
 #define DPTH10_10_10     10, 3, { 0, 0, 0, 0 }, { 10, 10, 10, 0 }
 #define DPTH16           16, 1, { 0, 0, 0, 0 }, { 16, 0, 0, 0 }
 #define DPTH16_16_16     16, 3, { 0, 0, 0, 0 }, { 16, 16, 16, 0 }
@@ -2108,6 +2341,7 @@ typedef struct
 #define PSTR111           { 1, 1, 1, 0 }
 #define PSTR1111          { 1, 1, 1, 1 }
 #define PSTR122           { 1, 2, 2, 0 }
+#define PSTR122T(mode)    { 1, 2, 2, GST_VIDEO_TILE_MODE_ ##mode }
 #define PSTR2             { 2, 0, 0, 0 }
 #define PSTR222           { 2, 2, 2, 0 }
 #define PSTR244           { 2, 4, 4, 0 }
@@ -2122,6 +2356,7 @@ typedef struct
 #define PLANE0            1, { 0, 0, 0, 0 }
 #define PLANE01           2, { 0, 1, 0, 0 }
 #define PLANE011          2, { 0, 1, 1, 0 }
+#define PLANE0110         3, { 0, 1, 1, 0 }
 #define PLANE012          3, { 0, 1, 2, 0 }
 #define PLANE0123         4, { 0, 1, 2, 3 }
 #define PLANE021          3, { 0, 2, 1, 0 }
@@ -2150,6 +2385,7 @@ typedef struct
 #define SUB410            { 0, 2, 2, 0 }, { 0, 2, 2, 0 }
 #define SUB411            { 0, 2, 2, 0 }, { 0, 0, 0, 0 }
 #define SUB420            { 0, 1, 1, 0 }, { 0, 1, 1, 0 }
+#define SUB420T64x32      { 0, 1, 1, 6 }, { 0, 1, 1, 5 }
 #define SUB422            { 0, 1, 1, 0 }, { 0, 0, 0, 0 }
 #define SUB4              { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
 #define SUB44             { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
@@ -2169,6 +2405,8 @@ typedef struct
  { fourcc, {GST_VIDEO_FORMAT_ ##name, G_STRINGIFY(name), desc, GST_VIDEO_FORMAT_FLAG_YUV | GST_VIDEO_FORMAT_FLAG_ALPHA | GST_VIDEO_FORMAT_FLAG_UNPACK | GST_VIDEO_FORMAT_FLAG_LE, depth, pstride, plane, offs, sub, pack } }
 #define MAKE_YUV_C_FORMAT(name, desc, fourcc, depth, pstride, plane, offs, sub, pack) \
  { fourcc, {GST_VIDEO_FORMAT_ ##name, G_STRINGIFY(name), desc, GST_VIDEO_FORMAT_FLAG_YUV | GST_VIDEO_FORMAT_FLAG_COMPLEX, depth, pstride, plane, offs, sub, pack } }
+#define MAKE_YUV_T_FORMAT(name, desc, fourcc, depth, pstride, plane, offs, sub, pack) \
+ { fourcc, {GST_VIDEO_FORMAT_ ##name, G_STRINGIFY(name), desc, GST_VIDEO_FORMAT_FLAG_YUV | GST_VIDEO_FORMAT_FLAG_COMPLEX | GST_VIDEO_FORMAT_FLAG_TILED, depth, pstride, plane, offs, sub, pack } }
 
 #define MAKE_RGB_FORMAT(name, desc, depth, pstride, plane, offs, sub, pack) \
  { 0x00000000, {GST_VIDEO_FORMAT_ ##name, G_STRINGIFY(name), desc, GST_VIDEO_FORMAT_FLAG_RGB, depth, pstride, plane, offs, sub, pack } }
@@ -2322,6 +2560,9 @@ static VideoFormat formats[] = {
       DPTH888, PSTR111, PLANE011, OFFS001, SUB422, PACK_NV16),
   MAKE_YUV_FORMAT (NV24, "raw video", GST_MAKE_FOURCC ('N', 'V', '2', '4'),
       DPTH888, PSTR111, PLANE011, OFFS001, SUB444, PACK_NV24),
+  MAKE_YUV_T_FORMAT (NV12T, "raw video",
+      GST_MAKE_FOURCC ('T', 'M', '1', '2'), DPTH8880, PSTR122T (ZFLIPZ_2X2),
+      PLANE0110, OFFS001, SUB420T64x32, PACK_NV12T),
 };
 
 static GstVideoFormat
index f75e2be..3060c4c 100644 (file)
@@ -84,6 +84,7 @@ G_BEGIN_DECLS
  * @GST_VIDEO_FORMAT_GBR_10LE: planar 4:4:4 RGB, 10 bits per channel
  * @GST_VIDEO_FORMAT_NV16: planar 4:2:2 YUV with interleaved UV plane
  * @GST_VIDEO_FORMAT_NV24: planar 4:4:4 YUV with interleaved UV plane
+ * @GST_VIDEO_FORMAT_NV12T: NV12 with tiling
  *
  * Enum value describing the most common video formats.
  */
@@ -141,6 +142,7 @@ typedef enum {
   GST_VIDEO_FORMAT_GBR_10LE,
   GST_VIDEO_FORMAT_NV16,
   GST_VIDEO_FORMAT_NV24,
+  GST_VIDEO_FORMAT_NV12T,
 } GstVideoFormat;
 
 #define GST_VIDEO_MAX_PLANES 4
@@ -444,7 +446,7 @@ gconstpointer  gst_video_format_get_palette          (GstVideoFormat format, gsi
     "YVYU, Y444, v210, v216, NV12, NV21, NV16, NV24, GRAY8, GRAY16_BE, GRAY16_LE, " \
     "v308, RGB16, BGR16, RGB15, BGR15, UYVP, A420, RGB8P, YUV9, YVU9, " \
     "IYU1, ARGB64, AYUV64, r210, I420_10LE, I420_10BE, I422_10LE, I422_10BE, " \
-    " Y444_10LE, Y444_10BE, GBR, GBR_10LE, GBR_10BE }"
+    " Y444_10LE, Y444_10BE, GBR, GBR_10LE, GBR_10BE, NV12T }"
 
 /**
  * GST_VIDEO_CAPS_MAKE:
index 5e07b91..6234b37 100644 (file)
@@ -573,6 +573,16 @@ fill_planes (GstVideoInfo * info)
       info->offset[2] = info->offset[1] * 2;
       info->size = info->stride[0] * height * 3;
       break;
+    case GST_VIDEO_FORMAT_NV12T:
+      info->stride[0] = GST_ROUND_UP_128 (width);
+      info->stride[1] = info->stride[0];
+      info->stride[2] = GST_ROUND_UP_32 (height) / 32;
+      info->offset[0] = 0;
+      info->offset[1] = info->stride[0] * GST_ROUND_UP_32 (height);
+      info->offset[2] = 0;
+      info->size =
+          info->offset[1] + info->stride[0] * GST_ROUND_UP_64 (height) / 2;
+      break;
     case GST_VIDEO_FORMAT_ENCODED:
       break;
     case GST_VIDEO_FORMAT_UNKNOWN: