mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-30 05:31:15 +00:00
videomixer2: Adding nv12 and nv21 support
Fixes https://bugzilla.gnome.org/show_bug.cgi?id=683841
This commit is contained in:
parent
4f015c594c
commit
c3d619be67
3 changed files with 233 additions and 1 deletions
|
@ -442,6 +442,206 @@ PLANAR_YUV_BLEND (y41b, GST_VIDEO_FORMAT_Y41B, GST_ROUND_UP_4,
|
|||
PLANAR_YUV_FILL_CHECKER (y41b, GST_VIDEO_FORMAT_Y41B, memset);
|
||||
PLANAR_YUV_FILL_COLOR (y41b, GST_VIDEO_FORMAT_Y41B, memset);
|
||||
|
||||
/* NV12, NV21 */
|
||||
#define NV_YUV_BLEND(format_name,first_component,MEMCPY,BLENDLOOP) \
|
||||
inline static void \
|
||||
_blend_##format_name (const guint8 * src, guint8 * dest, \
|
||||
gint src_stride, gint dest_stride, gint src_width, gint src_height, \
|
||||
gdouble src_alpha) \
|
||||
{ \
|
||||
gint i; \
|
||||
gint b_alpha; \
|
||||
\
|
||||
/* If it's completely transparent... we just return */ \
|
||||
if (G_UNLIKELY (src_alpha == 0.0)) { \
|
||||
GST_INFO ("Fast copy (alpha == 0.0)"); \
|
||||
return; \
|
||||
} \
|
||||
\
|
||||
/* If it's completely opaque, we do a fast copy */ \
|
||||
if (G_UNLIKELY (src_alpha == 1.0)) { \
|
||||
GST_INFO ("Fast copy (alpha == 1.0)"); \
|
||||
for (i = 0; i < src_height; i++) { \
|
||||
MEMCPY (dest, src, src_width); \
|
||||
src += src_stride; \
|
||||
dest += dest_stride; \
|
||||
} \
|
||||
return; \
|
||||
} \
|
||||
\
|
||||
b_alpha = CLAMP ((gint) (src_alpha * 256), 0, 256); \
|
||||
\
|
||||
BLENDLOOP(dest, dest_stride, src, src_stride, b_alpha, src_width, src_height); \
|
||||
} \
|
||||
\
|
||||
static void \
|
||||
blend_##format_name (GstVideoFrame * srcframe, gint xpos, gint ypos, \
|
||||
gdouble src_alpha, GstVideoFrame * destframe) \
|
||||
{ \
|
||||
const guint8 *b_src; \
|
||||
guint8 *b_dest; \
|
||||
gint b_src_width; \
|
||||
gint b_src_height; \
|
||||
gint xoffset = 0; \
|
||||
gint yoffset = 0; \
|
||||
gint src_comp_rowstride, dest_comp_rowstride; \
|
||||
gint src_comp_height; \
|
||||
gint src_comp_width; \
|
||||
gint comp_ypos, comp_xpos; \
|
||||
gint comp_yoffset, comp_xoffset; \
|
||||
gint dest_width, dest_height; \
|
||||
const GstVideoFormatInfo *info; \
|
||||
gint src_width, src_height; \
|
||||
\
|
||||
src_width = GST_VIDEO_FRAME_WIDTH (srcframe); \
|
||||
src_height = GST_VIDEO_FRAME_HEIGHT (srcframe); \
|
||||
\
|
||||
info = srcframe->info.finfo; \
|
||||
dest_width = GST_VIDEO_FRAME_WIDTH (destframe); \
|
||||
dest_height = GST_VIDEO_FRAME_WIDTH (destframe); \
|
||||
\
|
||||
xpos = GST_ROUND_UP_2 (xpos); \
|
||||
ypos = GST_ROUND_UP_2 (ypos); \
|
||||
\
|
||||
b_src_width = src_width; \
|
||||
b_src_height = src_height; \
|
||||
\
|
||||
/* adjust src pointers for negative sizes */ \
|
||||
if (xpos < 0) { \
|
||||
xoffset = -xpos; \
|
||||
b_src_width -= -xpos; \
|
||||
xpos = 0; \
|
||||
} \
|
||||
if (ypos < 0) { \
|
||||
yoffset += -ypos; \
|
||||
b_src_height -= -ypos; \
|
||||
ypos = 0; \
|
||||
} \
|
||||
/* If x or y offset are larger then the source it's outside of the picture */ \
|
||||
if (xoffset > src_width || yoffset > src_width) { \
|
||||
return; \
|
||||
} \
|
||||
\
|
||||
/* adjust width/height if the src is bigger than dest */ \
|
||||
if (xpos + src_width > dest_width) { \
|
||||
b_src_width = dest_width - xpos; \
|
||||
} \
|
||||
if (ypos + src_height > dest_height) { \
|
||||
b_src_height = dest_height - ypos; \
|
||||
} \
|
||||
if (b_src_width < 0 || b_src_height < 0) { \
|
||||
return; \
|
||||
} \
|
||||
\
|
||||
/* First mix Y, then UV */ \
|
||||
b_src = GST_VIDEO_FRAME_COMP_DATA (srcframe, 0); \
|
||||
b_dest = GST_VIDEO_FRAME_COMP_DATA (destframe, 0); \
|
||||
src_comp_rowstride = GST_VIDEO_FRAME_COMP_STRIDE (srcframe, 0); \
|
||||
dest_comp_rowstride = GST_VIDEO_FRAME_COMP_STRIDE (destframe, 0); \
|
||||
src_comp_width = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH(info, 0, b_src_width); \
|
||||
src_comp_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info, 0, b_src_height); \
|
||||
comp_xpos = (xpos == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (info, 0, xpos); \
|
||||
comp_ypos = (ypos == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info, 0, ypos); \
|
||||
comp_xoffset = (xoffset == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (info, 0, xoffset); \
|
||||
comp_yoffset = (yoffset == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info, 0, yoffset); \
|
||||
_blend_##format_name (b_src + comp_xoffset + comp_yoffset * src_comp_rowstride, \
|
||||
b_dest + comp_xpos + comp_ypos * dest_comp_rowstride, \
|
||||
src_comp_rowstride, \
|
||||
dest_comp_rowstride, src_comp_width, src_comp_height, \
|
||||
src_alpha); \
|
||||
\
|
||||
b_src = GST_VIDEO_FRAME_COMP_DATA (srcframe, first_component); \
|
||||
b_dest = GST_VIDEO_FRAME_COMP_DATA (destframe, first_component); \
|
||||
src_comp_rowstride = GST_VIDEO_FRAME_COMP_STRIDE (srcframe, 1); \
|
||||
dest_comp_rowstride = GST_VIDEO_FRAME_COMP_STRIDE (destframe, 1); \
|
||||
src_comp_width = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH(info, 1, b_src_width); \
|
||||
src_comp_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info, 1, b_src_height); \
|
||||
comp_xpos = (xpos == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (info, 1, xpos); \
|
||||
comp_ypos = (ypos == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info, 1, ypos); \
|
||||
comp_xoffset = (xoffset == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (info, 1, xoffset); \
|
||||
comp_yoffset = (yoffset == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info, 1, yoffset); \
|
||||
_blend_##format_name (b_src + comp_xoffset * 2 + comp_yoffset * src_comp_rowstride, \
|
||||
b_dest + comp_xpos * 2 + comp_ypos * dest_comp_rowstride, \
|
||||
src_comp_rowstride, \
|
||||
dest_comp_rowstride, 2 * src_comp_width, src_comp_height, \
|
||||
src_alpha); \
|
||||
}
|
||||
|
||||
#define NV_YUV_FILL_CHECKER(format_name, first_component, MEMSET) \
|
||||
static void \
|
||||
fill_checker_##format_name (GstVideoFrame * frame) \
|
||||
{ \
|
||||
gint i, j; \
|
||||
static const int tab[] = { 80, 160, 80, 160 }; \
|
||||
guint8 *p; \
|
||||
gint comp_width, comp_height; \
|
||||
gint rowstride; \
|
||||
\
|
||||
p = GST_VIDEO_FRAME_COMP_DATA (frame, 0); \
|
||||
comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 0); \
|
||||
comp_height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 0); \
|
||||
rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0); \
|
||||
\
|
||||
for (i = 0; i < comp_height; i++) { \
|
||||
for (j = 0; j < comp_width; j++) { \
|
||||
*p++ = tab[((i & 0x8) >> 3) + ((j & 0x8) >> 3)]; \
|
||||
} \
|
||||
p += rowstride - comp_width; \
|
||||
} \
|
||||
\
|
||||
p = GST_VIDEO_FRAME_COMP_DATA (frame, first_component); \
|
||||
comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 1); \
|
||||
comp_height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 1); \
|
||||
rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 1); \
|
||||
\
|
||||
for (i = 0; i < comp_height; i++) { \
|
||||
MEMSET (p, 0x80, comp_width * 2); \
|
||||
p += rowstride; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define NV_YUV_FILL_COLOR(format_name,MEMSET) \
|
||||
static void \
|
||||
fill_color_##format_name (GstVideoFrame * frame, \
|
||||
gint colY, gint colU, gint colV) \
|
||||
{ \
|
||||
guint8 *y, *u, *v; \
|
||||
gint comp_width, comp_height; \
|
||||
gint rowstride; \
|
||||
gint i, j; \
|
||||
\
|
||||
y = GST_VIDEO_FRAME_COMP_DATA (frame, 0); \
|
||||
comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 0); \
|
||||
comp_height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 0); \
|
||||
rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0); \
|
||||
\
|
||||
for (i = 0; i < comp_height; i++) { \
|
||||
MEMSET (y, colY, comp_width); \
|
||||
y += rowstride; \
|
||||
} \
|
||||
\
|
||||
u = GST_VIDEO_FRAME_COMP_DATA (frame, 1); \
|
||||
v = GST_VIDEO_FRAME_COMP_DATA (frame, 2); \
|
||||
comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 1); \
|
||||
comp_height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 1); \
|
||||
rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 1); \
|
||||
\
|
||||
for (i = 0; i < comp_height; i++) { \
|
||||
for (j = 0; j < comp_width; j++) { \
|
||||
u[j*2] = colU; \
|
||||
v[j*2] = colV; \
|
||||
} \
|
||||
u += rowstride; \
|
||||
v += rowstride; \
|
||||
} \
|
||||
}
|
||||
|
||||
NV_YUV_BLEND (nv12, 1, memcpy, video_mixer_orc_blend_u8);
|
||||
NV_YUV_FILL_CHECKER (nv12, 1, memset);
|
||||
NV_YUV_FILL_COLOR (nv12, memset);
|
||||
NV_YUV_BLEND (nv21, 2, memcpy, video_mixer_orc_blend_u8);
|
||||
NV_YUV_FILL_CHECKER (nv21, 2, memset);
|
||||
|
||||
/* RGB, BGR, xRGB, xBGR, RGBx, BGRx */
|
||||
|
||||
#define RGB_BLEND(name, bpp, MEMCPY, BLENDLOOP) \
|
||||
|
@ -751,6 +951,8 @@ BlendFunction gst_video_mixer_blend_y444;
|
|||
BlendFunction gst_video_mixer_blend_y42b;
|
||||
BlendFunction gst_video_mixer_blend_i420;
|
||||
/* I420 is equal to YV12 */
|
||||
BlendFunction gst_video_mixer_blend_nv12;
|
||||
BlendFunction gst_video_mixer_blend_nv21;
|
||||
BlendFunction gst_video_mixer_blend_y41b;
|
||||
BlendFunction gst_video_mixer_blend_rgb;
|
||||
/* BGR is equal to RGB */
|
||||
|
@ -767,6 +969,8 @@ FillCheckerFunction gst_video_mixer_fill_checker_y444;
|
|||
FillCheckerFunction gst_video_mixer_fill_checker_y42b;
|
||||
FillCheckerFunction gst_video_mixer_fill_checker_i420;
|
||||
/* I420 is equal to YV12 */
|
||||
FillCheckerFunction gst_video_mixer_fill_checker_nv12;
|
||||
FillCheckerFunction gst_video_mixer_fill_checker_nv21;
|
||||
FillCheckerFunction gst_video_mixer_fill_checker_y41b;
|
||||
FillCheckerFunction gst_video_mixer_fill_checker_rgb;
|
||||
/* BGR is equal to RGB */
|
||||
|
@ -785,6 +989,8 @@ FillColorFunction gst_video_mixer_fill_color_y444;
|
|||
FillColorFunction gst_video_mixer_fill_color_y42b;
|
||||
FillColorFunction gst_video_mixer_fill_color_i420;
|
||||
FillColorFunction gst_video_mixer_fill_color_yv12;
|
||||
FillColorFunction gst_video_mixer_fill_color_nv12;
|
||||
/* NV21 is equal to NV12 */
|
||||
FillColorFunction gst_video_mixer_fill_color_y41b;
|
||||
FillColorFunction gst_video_mixer_fill_color_rgb;
|
||||
FillColorFunction gst_video_mixer_fill_color_bgr;
|
||||
|
@ -807,6 +1013,8 @@ gst_video_mixer_init_blend (void)
|
|||
gst_video_mixer_overlay_argb = overlay_argb;
|
||||
gst_video_mixer_overlay_bgra = overlay_bgra;
|
||||
gst_video_mixer_blend_i420 = blend_i420;
|
||||
gst_video_mixer_blend_nv12 = blend_nv12;
|
||||
gst_video_mixer_blend_nv21 = blend_nv21;
|
||||
gst_video_mixer_blend_y444 = blend_y444;
|
||||
gst_video_mixer_blend_y42b = blend_y42b;
|
||||
gst_video_mixer_blend_y41b = blend_y41b;
|
||||
|
@ -818,6 +1026,8 @@ gst_video_mixer_init_blend (void)
|
|||
gst_video_mixer_fill_checker_bgra = fill_checker_bgra_c;
|
||||
gst_video_mixer_fill_checker_ayuv = fill_checker_ayuv_c;
|
||||
gst_video_mixer_fill_checker_i420 = fill_checker_i420;
|
||||
gst_video_mixer_fill_checker_nv12 = fill_checker_nv12;
|
||||
gst_video_mixer_fill_checker_nv21 = fill_checker_nv21;
|
||||
gst_video_mixer_fill_checker_y444 = fill_checker_y444;
|
||||
gst_video_mixer_fill_checker_y42b = fill_checker_y42b;
|
||||
gst_video_mixer_fill_checker_y41b = fill_checker_y41b;
|
||||
|
@ -833,6 +1043,7 @@ gst_video_mixer_init_blend (void)
|
|||
gst_video_mixer_fill_color_ayuv = fill_color_ayuv;
|
||||
gst_video_mixer_fill_color_i420 = fill_color_i420;
|
||||
gst_video_mixer_fill_color_yv12 = fill_color_yv12;
|
||||
gst_video_mixer_fill_color_nv12 = fill_color_nv12;
|
||||
gst_video_mixer_fill_color_y444 = fill_color_y444;
|
||||
gst_video_mixer_fill_color_y42b = fill_color_y42b;
|
||||
gst_video_mixer_fill_color_y41b = fill_color_y41b;
|
||||
|
|
|
@ -39,6 +39,8 @@ extern BlendFunction gst_video_mixer_overlay_bgra;
|
|||
#define gst_video_mixer_overlay_rgba gst_video_mixer_overlay_bgra
|
||||
extern BlendFunction gst_video_mixer_blend_i420;
|
||||
#define gst_video_mixer_blend_yv12 gst_video_mixer_blend_i420
|
||||
extern BlendFunction gst_video_mixer_blend_nv12;
|
||||
extern BlendFunction gst_video_mixer_blend_nv21;
|
||||
extern BlendFunction gst_video_mixer_blend_y41b;
|
||||
extern BlendFunction gst_video_mixer_blend_y42b;
|
||||
extern BlendFunction gst_video_mixer_blend_y444;
|
||||
|
@ -59,6 +61,8 @@ extern FillCheckerFunction gst_video_mixer_fill_checker_bgra;
|
|||
extern FillCheckerFunction gst_video_mixer_fill_checker_ayuv;
|
||||
extern FillCheckerFunction gst_video_mixer_fill_checker_i420;
|
||||
#define gst_video_mixer_fill_checker_yv12 gst_video_mixer_fill_checker_i420
|
||||
extern FillCheckerFunction gst_video_mixer_fill_checker_nv12;
|
||||
extern FillCheckerFunction gst_video_mixer_fill_checker_nv21;
|
||||
extern FillCheckerFunction gst_video_mixer_fill_checker_y41b;
|
||||
extern FillCheckerFunction gst_video_mixer_fill_checker_y42b;
|
||||
extern FillCheckerFunction gst_video_mixer_fill_checker_y444;
|
||||
|
@ -79,6 +83,8 @@ extern FillColorFunction gst_video_mixer_fill_color_rgba;
|
|||
extern FillColorFunction gst_video_mixer_fill_color_ayuv;
|
||||
extern FillColorFunction gst_video_mixer_fill_color_i420;
|
||||
extern FillColorFunction gst_video_mixer_fill_color_yv12;
|
||||
extern FillColorFunction gst_video_mixer_fill_color_nv12;
|
||||
#define gst_video_mixer_fill_color_nv21 gst_video_mixer_fill_color_nv12;
|
||||
extern FillColorFunction gst_video_mixer_fill_color_y41b;
|
||||
extern FillColorFunction gst_video_mixer_fill_color_y42b;
|
||||
extern FillColorFunction gst_video_mixer_fill_color_y444;
|
||||
|
|
|
@ -104,7 +104,8 @@ GST_DEBUG_CATEGORY_STATIC (gst_videomixer2_debug);
|
|||
(g_mutex_unlock(GST_VIDEO_MIXER2_GET_LOCK (mix)))
|
||||
|
||||
#define FORMATS " { AYUV, BGRA, ARGB, RGBA, ABGR, Y444, Y42B, YUY2, UYVY, "\
|
||||
" YVYU, I420, YV12, Y41B, RGB, BGR, xRGB, xBGR, RGBx, BGRx } "
|
||||
" YVYU, I420, YV12, NV12, NV21, Y41B, RGB, BGR, xRGB, xBGR, "\
|
||||
" RGBx, BGRx } "
|
||||
|
||||
static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
|
||||
GST_PAD_SRC,
|
||||
|
@ -1507,6 +1508,20 @@ gst_videomixer2_src_setcaps (GstPad * pad, GstVideoMixer2 * mix, GstCaps * caps)
|
|||
mix->fill_color = gst_video_mixer_fill_color_yv12;
|
||||
ret = TRUE;
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_NV12:
|
||||
mix->blend = gst_video_mixer_blend_nv12;
|
||||
mix->overlay = mix->blend;
|
||||
mix->fill_checker = gst_video_mixer_fill_checker_nv12;
|
||||
mix->fill_color = gst_video_mixer_fill_color_nv12;
|
||||
ret = TRUE;
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_NV21:
|
||||
mix->blend = gst_video_mixer_blend_nv21;
|
||||
mix->overlay = mix->blend;
|
||||
mix->fill_checker = gst_video_mixer_fill_checker_nv21;
|
||||
mix->fill_color = gst_video_mixer_fill_color_nv21;
|
||||
ret = TRUE;
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_Y41B:
|
||||
mix->blend = gst_video_mixer_blend_y41b;
|
||||
mix->overlay = mix->blend;
|
||||
|
|
Loading…
Reference in a new issue