summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Almeida <daniel.almeida@collabora.com>2021-05-21 12:24:37 -0300
committerNicolas Dufresne <nicolas.dufresne@collabora.com>2021-05-21 21:16:24 -0400
commit6760c7fd766d0be5d37ce911f73502fe5463f5e2 (patch)
treecf23445b945f3ade3c431b42e2c6ce0b6590ef9b
parent038ba1bffe4fd6751e3c5edd2797413875f38d79 (diff)
downloadgstreamer-plugins-base-6760c7fd766d0be5d37ce911f73502fe5463f5e2.tar.gz
video: add support for AV12
AV12 is an internally conceived format that is actually the combination of NV12 and an alpha plane. This format is to add to gstreamer's webM transparency support for vp8 and vp9. To this end, two I420 streams are independently decoded simultaneously for the actual content and the alpha plane respectively and these are then combined into A420. Since most hardware decoders output NV12, this patch adds NV12+A to make the same workflow possible. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/-/merge_requests/1152>
-rw-r--r--gst-libs/gst/video/video-converter.c4
-rw-r--r--gst-libs/gst/video/video-format.c96
-rw-r--r--gst-libs/gst/video/video-format.h15
-rw-r--r--gst-libs/gst/video/video-info.c10
-rw-r--r--gst-libs/gst/video/video-orc.orc35
5 files changed, 158 insertions, 2 deletions
diff --git a/gst-libs/gst/video/video-converter.c b/gst-libs/gst/video/video-converter.c
index 1980b6320..c2c9c817c 100644
--- a/gst-libs/gst/video/video-converter.c
+++ b/gst-libs/gst/video/video-converter.c
@@ -6595,6 +6595,10 @@ get_scale_format (GstVideoFormat format, gint plane)
case GST_VIDEO_FORMAT_NV24:
res = plane == 0 ? GST_VIDEO_FORMAT_GRAY8 : GST_VIDEO_FORMAT_NV12;
break;
+ case GST_VIDEO_FORMAT_AV12:
+ res = (plane == 0
+ || plane == 2) ? GST_VIDEO_FORMAT_GRAY8 : GST_VIDEO_FORMAT_NV12;
+ break;
case GST_VIDEO_FORMAT_UNKNOWN:
case GST_VIDEO_FORMAT_ENCODED:
case GST_VIDEO_FORMAT_v210:
diff --git a/gst-libs/gst/video/video-format.c b/gst-libs/gst/video/video-format.c
index e87dc622b..75030b65d 100644
--- a/gst-libs/gst/video/video-format.c
+++ b/gst-libs/gst/video/video-format.c
@@ -1753,6 +1753,98 @@ unpack_NV21 (const GstVideoFormatInfo * info, GstVideoPackFlags flags,
}
}
+#define PACK_AV12 GST_VIDEO_FORMAT_AYUV, unpack_AV12, 1, pack_AV12
+static void
+unpack_AV12 (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)
+{
+ gint uv = GET_UV_420 (y, flags);
+ const guint8 *restrict sy = GET_PLANE_LINE (0, y);
+ const guint8 *restrict suv = GET_PLANE_LINE (1, uv);
+ const guint8 *restrict sa = GET_PLANE_LINE (2, y); /* a is for 'alpha' */
+ guint8 *restrict d = dest;
+
+ sy += x;
+ sa += x;
+ suv += (x & ~1);
+
+ if (x & 1) {
+ d[0] = *sa++;
+ d[1] = *sy++;
+ d[2] = suv[0];
+ d[3] = suv[1];
+ width--;
+ d += 4;
+ suv += 2;
+ }
+
+ if (IS_ALIGNED (d, 8)) {
+ video_orc_unpack_AV12 (d, sy, suv, sa, width / 2);
+ } else {
+ gint i;
+ for (i = 0; i < width / 2; i++) {
+ d[i * 8 + 0] = sa[i * 2 + 0];
+ d[i * 8 + 1] = sy[i * 2 + 0];
+ d[i * 8 + 2] = suv[i * 2 + 0];
+ d[i * 8 + 3] = suv[i * 2 + 1];
+ d[i * 8 + 4] = sa[i * 2 + 1];
+ d[i * 8 + 5] = sy[i * 2 + 1];
+ d[i * 8 + 6] = suv[i * 2 + 0];
+ d[i * 8 + 7] = suv[i * 2 + 1];
+ }
+ }
+
+ if (width & 1) {
+ gint i = width - 1;
+
+ d[i * 4 + 0] = sa[i];
+ d[i * 4 + 1] = sy[i];
+ d[i * 4 + 2] = suv[i + 0];
+ d[i * 4 + 3] = suv[i + 1];
+ }
+}
+
+static void
+pack_AV12 (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)
+{
+ gint uv = GET_UV_420 (y, flags);
+ guint8 *restrict dy = GET_PLANE_LINE (0, y);
+ guint8 *restrict duv = GET_PLANE_LINE (1, uv);
+ guint8 *restrict da = GET_PLANE_LINE (2, y); /* a is for 'alpha' */
+ const guint8 *restrict s = src;
+
+ if (IS_CHROMA_LINE_420 (y, flags)) {
+ if (IS_ALIGNED (s, 8)) {
+ video_orc_pack_AV12 (dy, duv, da, s, width / 2);
+ } else {
+ gint i;
+ for (i = 0; i < width / 2; i++) {
+ /* AYUV_AYUV: alpha is on bytes 0 and 4 */
+ da[i * 2 + 0] = s[i * 8 + 0];
+ da[i * 2 + 1] = s[i * 8 + 4];
+ dy[i * 2 + 0] = s[i * 8 + 1];
+ dy[i * 2 + 1] = s[i * 8 + 5];
+ duv[i * 2 + 0] = s[i * 8 + 2];
+ duv[i * 2 + 1] = s[i * 8 + 3];
+ }
+ }
+ if (width & 1) {
+ gint i = width - 1;
+
+ da[i] = s[i * 4 + 0]; /* AYUV: alpha is byte 0 */
+ dy[i] = s[i * 4 + 1];
+ duv[i + 0] = s[i * 4 + 2];
+ duv[i + 1] = s[i * 4 + 3];
+ }
+ } else {
+ video_orc_pack_YA (dy, da, s, width);
+ }
+}
+
static void
pack_NV21 (const GstVideoFormatInfo * info, GstVideoPackFlags flags,
const gpointer src, gint sstride, gpointer data[GST_VIDEO_MAX_PLANES],
@@ -6374,6 +6466,7 @@ typedef struct
#define PSTR111 { 1, 1, 1, 0 }
#define PSTR1111 { 1, 1, 1, 1 }
#define PSTR122 { 1, 2, 2, 0 }
+#define PSTR1221 { 1, 2, 2, 1 }
#define PSTR2 { 2, 0, 0, 0 }
#define PSTR222 { 2, 2, 2, 0 }
#define PSTR2222 { 2, 2, 2, 2 }
@@ -6389,6 +6482,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 PLANE0112 3, { 0, 1, 1, 2 }
#define PLANE012 3, { 0, 1, 2, 0 }
#define PLANE0123 4, { 0, 1, 2, 3 }
#define PLANE021 3, { 0, 2, 1, 0 }
@@ -6708,6 +6802,8 @@ static const VideoFormat formats[] = {
PACK_RGBP),
MAKE_RGB_FORMAT (BGRP, "raw video", DPTH888, PSTR111, PLANE210, OFFS0, SUB444,
PACK_BGRP),
+ MAKE_YUV_FORMAT (AV12, "raw video", GST_MAKE_FOURCC ('A', 'V', '1', '2'),
+ DPTH8888, PSTR1221, PLANE0112, OFFS001, SUB4204, PACK_AV12),
};
static GstVideoFormat
diff --git a/gst-libs/gst/video/video-format.h b/gst-libs/gst/video/video-format.h
index cfbb17f16..1884404f9 100644
--- a/gst-libs/gst/video/video-format.h
+++ b/gst-libs/gst/video/video-format.h
@@ -133,6 +133,7 @@ G_BEGIN_DECLS
* @GST_VIDEO_FORMAT_NV12_32L32: NV12 with 32x32 tiles in linear order (Since: 1.18)
* @GST_VIDEO_FORMAT_RGBP: planar 4:4:4 RGB, 8 bits per channel (Since: 1.20)
* @GST_VIDEO_FORMAT_BGRP: planar 4:4:4 RGB, 8 bits per channel (Since: 1.20)
+ * @GST_VIDEO_FORMAT_AV12: Planar 4:2:0 YUV with interleaved UV plane with alpha as 3rd plane (Since: 1.20)
*
* Enum value describing the most common video formats.
*
@@ -271,6 +272,16 @@ typedef enum {
* Since: 1.20
*/
GST_VIDEO_FORMAT_BGRP,
+
+ /**
+ * GST_VIDEO_FORMAT_AV12:
+ *
+ * Planar 4:2:0 YUV with interleaved UV plane with alpha as
+ * 3rd plane.
+ *
+ * Since: 1.20
+ */
+ GST_VIDEO_FORMAT_AV12,
} GstVideoFormat;
#define GST_VIDEO_MAX_PLANES 4
@@ -645,7 +656,7 @@ gconstpointer gst_video_format_get_palette (GstVideoFormat format, gsi
"I422_10BE, I422_10LE, NV16_10LE32, Y210, v210, UYVP, I420_10BE, I420_10LE, " \
"P010_10BE, P010_10LE, NV12_10LE32, NV12_10LE40, Y444, GBR, RGBP, BGRP, NV24, xBGR, BGRx, " \
"xRGB, RGBx, BGR, IYU2, v308, RGB, Y42B, NV61, NV16, VYUY, UYVY, YVYU, YUY2, I420, " \
- "YV12, NV21, NV12, NV12_64Z32, NV12_4L4, NV12_32L32, Y41B, IYU1, YVU9, YUV9, RGB16, " \
+ "YV12, NV21, NV12, NV12_64Z32, NV12_4L4, NV12_32L32, AV12, Y41B, IYU1, YVU9, YUV9, RGB16, " \
"BGR16, RGB15, BGR15, RGB8P, GRAY16_BE, GRAY16_LE, GRAY10_LE32, GRAY8 }"
#elif G_BYTE_ORDER == G_LITTLE_ENDIAN
#define GST_VIDEO_FORMATS_ALL "{ AYUV64, ARGB64, GBRA_12LE, GBRA_12BE, Y412_LE, " \
@@ -657,7 +668,7 @@ gconstpointer gst_video_format_get_palette (GstVideoFormat format, gsi
"I422_10LE, I422_10BE, NV16_10LE32, Y210, v210, UYVP, I420_10LE, I420_10BE, " \
"P010_10LE, NV12_10LE32, NV12_10LE40, P010_10BE, Y444, GBR, RGBP, BGRP, NV24, xBGR, BGRx, " \
"xRGB, RGBx, BGR, IYU2, v308, RGB, Y42B, NV61, NV16, VYUY, UYVY, YVYU, YUY2, I420, " \
- "YV12, NV21, NV12, NV12_64Z32, NV12_4L4, NV12_32L32, Y41B, IYU1, YVU9, YUV9, RGB16, " \
+ "YV12, NV21, NV12, NV12_64Z32, NV12_4L4, NV12_32L32, AV12, Y41B, IYU1, YVU9, YUV9, RGB16, " \
"BGR16, RGB15, BGR15, RGB8P, GRAY16_LE, GRAY16_BE, GRAY10_LE32, GRAY8 }"
#endif
diff --git a/gst-libs/gst/video/video-info.c b/gst-libs/gst/video/video-info.c
index 3d2abcfd3..4aafb3836 100644
--- a/gst-libs/gst/video/video-info.c
+++ b/gst-libs/gst/video/video-info.c
@@ -944,6 +944,16 @@ fill_planes (GstVideoInfo * info, gsize plane_size[GST_VIDEO_MAX_PLANES])
cr_h = GST_ROUND_UP_2 (cr_h);
info->size = info->offset[1] + info->stride[0] * cr_h;
break;
+ case GST_VIDEO_FORMAT_AV12:
+ info->stride[0] = GST_ROUND_UP_4 (width);
+ info->stride[1] = info->stride[0];
+ info->stride[2] = info->stride[0];
+ info->offset[0] = 0;
+ info->offset[1] = info->stride[0] * GST_ROUND_UP_2 (height);
+ info->offset[2] =
+ info->offset[1] + (info->stride[1] * GST_ROUND_UP_2 (height) / 2);
+ info->size = info->offset[2] + info->stride[2] * GST_ROUND_UP_2 (height);
+ break;
case GST_VIDEO_FORMAT_NV16:
case GST_VIDEO_FORMAT_NV61:
info->stride[0] = GST_ROUND_UP_4 (width);
diff --git a/gst-libs/gst/video/video-orc.orc b/gst-libs/gst/video/video-orc.orc
index b09e6b471..03a302f1e 100644
--- a/gst-libs/gst/video/video-orc.orc
+++ b/gst-libs/gst/video/video-orc.orc
@@ -104,6 +104,16 @@ select0wb v, vv
select0lw ay, ayuv
select1wb y, ay
+.function video_orc_pack_YA
+.dest 1 y guint8
+.dest 1 a guint8
+.source 4 ayuv guint8
+.temp 2 ay
+
+select0lw ay, ayuv
+select1wb y, ay
+select0wb a, ay
+
.function video_orc_unpack_YUY2
.dest 8 ayuv guint8
.source 4 yuy2 guint8
@@ -446,6 +456,31 @@ x2 splitlw uvuv, ay, ayuv
x2 select1wb y, ay
select0lw uv, uvuv
+.function video_orc_unpack_AV12
+.dest 8 d guint8
+.source 2 y guint8
+.source 2 uv guint8
+.source 2 a guint8
+.temp 4 ay
+.temp 4 uvuv
+
+mergewl uvuv, uv, uv
+x2 mergebw ay, a, y
+x2 mergewl d, ay, uvuv
+
+.function video_orc_pack_AV12
+.dest 2 y guint8
+.dest 2 uv guint8
+.dest 2 a guint8
+.source 8 ayuv guint8
+.temp 4 ay
+.temp 4 uvuv
+
+x2 splitlw uvuv, ay, ayuv
+x2 select1wb y, ay
+x2 select0wb a, ay
+select0lw uv, uvuv
+
.function video_orc_unpack_NV21
.dest 8 d guint8
.source 2 y guint8