alpha: Some preparations for supporting more color formats

This commit is contained in:
Sebastian Dröge 2010-03-19 18:11:12 +01:00
parent b019a78ab8
commit 6b0c535e8d
2 changed files with 171 additions and 58 deletions

View file

@ -34,6 +34,43 @@
#define M_PI 3.14159265358979323846 #define M_PI 3.14159265358979323846
#endif #endif
/* Generated by -bad/ext/cog/generate_tables */
static const int cog_ycbcr_to_rgb_matrix_8bit_hdtv[] = {
298, 0, 459, -63514,
298, -55, -136, 19681,
298, 541, 0, -73988,
};
static const int cog_ycbcr_to_rgb_matrix_8bit_sdtv[] = {
298, 0, 409, -57068,
298, -100, -208, 34707,
298, 516, 0, -70870,
};
static const gint cog_rgb_to_ycbcr_matrix_8bit_hdtv[] = {
47, 157, 16, 4096,
-26, -87, 112, 32768,
112, -102, -10, 32768,
};
static const gint cog_rgb_to_ycbcr_matrix_8bit_sdtv[] = {
66, 129, 25, 4096,
-38, -74, 112, 32768,
112, -94, -18, 32768,
};
static const gint cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit[] = {
256, -30, -53, 10600,
0, 261, 29, -4367,
0, 19, 262, -3289,
};
static const gint cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit[] = {
256, 25, 49, -9536,
0, 253, -28, 3958,
0, -19, 252, 2918,
};
/* Alpha signals and args */ /* Alpha signals and args */
enum enum
{ {
@ -92,6 +129,7 @@ static GstFlowReturn gst_alpha_transform (GstBaseTransform * btrans,
GstBuffer * in, GstBuffer * out); GstBuffer * in, GstBuffer * out);
static void gst_alpha_init_params (GstAlpha * alpha); static void gst_alpha_init_params (GstAlpha * alpha);
static gboolean gst_alpha_set_process_function (GstAlpha * alpha);
static void gst_alpha_set_property (GObject * object, guint prop_id, static void gst_alpha_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec); const GValue * value, GParamSpec * pspec);
@ -235,6 +273,7 @@ gst_alpha_set_property (GObject * object, guint prop_id,
default: default:
break; break;
} }
gst_alpha_set_process_function (alpha);
gst_alpha_init_params (alpha); gst_alpha_init_params (alpha);
break; break;
case PROP_ALPHA: case PROP_ALPHA:
@ -339,30 +378,36 @@ gst_alpha_transform_caps (GstBaseTransform * btrans,
GstStructure *structure; GstStructure *structure;
gint i; gint i;
ret = gst_caps_copy (caps); ret = gst_caps_new_empty ();
/* When going from the SINK pad to the src, we just need to make sure the /* When going from the SINK pad to the src, we just need to make sure the
* format is AYUV */ * format is AYUV */
if (direction == GST_PAD_SINK) { if (direction == GST_PAD_SINK) {
for (i = 0; i < gst_caps_get_size (ret); i++) { for (i = 0; i < gst_caps_get_size (caps); i++) {
structure = gst_caps_get_structure (ret, i); structure = gst_structure_copy (gst_caps_get_structure (caps, i));
gst_structure_set (structure, "format", gst_structure_set (structure, "format",
GST_TYPE_FOURCC, GST_MAKE_FOURCC ('A', 'Y', 'U', 'V'), NULL); GST_TYPE_FOURCC, GST_MAKE_FOURCC ('A', 'Y', 'U', 'V'), NULL);
gst_structure_remove_field (structure, "chroma-site");
gst_structure_remove_field (structure, "color-matrix");
gst_caps_append_structure (ret, structure);
} }
} else { } else {
GstCaps *ayuv_caps;
/* In the other direction, prepend a copy of the caps with format AYUV, /* In the other direction, prepend a copy of the caps with format AYUV,
* and set the first to I420 */ * and set the first to I420 */
ayuv_caps = gst_caps_copy (ret);
for (i = 0; i < gst_caps_get_size (ret); i++) { for (i = 0; i < gst_caps_get_size (caps); i++) {
structure = gst_caps_get_structure (ret, i); structure = gst_structure_copy (gst_caps_get_structure (caps, i));
gst_structure_remove_field (structure, "color-matrix");
gst_structure_set (structure, "format", gst_structure_set (structure, "format",
GST_TYPE_FOURCC, GST_MAKE_FOURCC ('I', '4', '2', '0'), NULL); GST_TYPE_FOURCC, GST_MAKE_FOURCC ('I', '4', '2', '0'), NULL);
} gst_caps_append_structure (ret, gst_structure_copy (structure));
gst_caps_append (ret, ayuv_caps); gst_structure_set (structure, "format",
GST_TYPE_FOURCC, GST_MAKE_FOURCC ('A', 'Y', 'U', 'V'), NULL);
gst_structure_remove_field (structure, "chroma-site");
gst_caps_append_structure (ret, structure);
}
} }
gst_caps_do_simplify (ret); gst_caps_do_simplify (ret);
@ -375,19 +420,40 @@ gst_alpha_set_caps (GstBaseTransform * btrans,
GstCaps * incaps, GstCaps * outcaps) GstCaps * incaps, GstCaps * outcaps)
{ {
GstAlpha *alpha = GST_ALPHA (btrans); GstAlpha *alpha = GST_ALPHA (btrans);
const gchar *matrix;
if (!gst_video_format_parse_caps (incaps, &alpha->format, GST_OBJECT_LOCK (alpha);
&alpha->width, &alpha->height))
if (!gst_video_format_parse_caps (incaps, &alpha->in_format,
&alpha->width, &alpha->height) ||
!gst_video_format_parse_caps (incaps, &alpha->out_format,
&alpha->width, &alpha->height)) {
GST_OBJECT_UNLOCK (alpha);
return FALSE; return FALSE;
}
if (!gst_alpha_set_process_function (alpha)) {
GST_OBJECT_UNLOCK (alpha);
return FALSE;
}
matrix = gst_video_parse_caps_color_matrix (incaps);
alpha->in_sdtv = matrix ? g_str_equal (matrix, "sdtv") : TRUE;
matrix = gst_video_parse_caps_color_matrix (outcaps);
alpha->out_sdtv = matrix ? g_str_equal (matrix, "sdtv") : TRUE;
gst_alpha_init_params (alpha);
GST_OBJECT_UNLOCK (alpha);
return TRUE; return TRUE;
} }
static void static void
gst_alpha_set_ayuv (guint8 * src, guint8 * dest, gint width, gint height, gst_alpha_set_ayuv (const guint8 * src, guint8 * dest, gint width, gint height,
gdouble alpha) GstAlpha * alpha)
{ {
gint s_alpha = CLAMP ((gint) (alpha * 256), 0, 256); gint s_alpha = CLAMP ((gint) (alpha->alpha * 256), 0, 256);
gint y, x; gint y, x;
for (y = 0; y < height; y++) { for (y = 0; y < height; y++) {
@ -401,13 +467,13 @@ gst_alpha_set_ayuv (guint8 * src, guint8 * dest, gint width, gint height,
} }
static void static void
gst_alpha_set_i420 (guint8 * src, guint8 * dest, gint width, gint height, gst_alpha_set_i420 (const guint8 * src, guint8 * dest, gint width, gint height,
gdouble alpha) GstAlpha * alpha)
{ {
gint b_alpha = CLAMP ((gint) (alpha * 255), 0, 255); gint b_alpha = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
guint8 *srcY; const guint8 *srcY;
guint8 *srcU; const guint8 *srcU;
guint8 *srcV; const guint8 *srcV;
gint i, j; gint i, j;
gint src_wrap, src_uv_wrap; gint src_wrap, src_uv_wrap;
gint y_stride, uv_stride; gint y_stride, uv_stride;
@ -537,10 +603,10 @@ chroma_keying_yuv (gint a, gint * y, guint ny, gint * u,
} }
static void static void
gst_alpha_chroma_key_ayuv (guint8 * src, guint8 * dest, gint width, gint height, gst_alpha_chroma_key_ayuv (const guint8 * src, guint8 * dest, gint width,
GstAlpha * alpha) gint height, GstAlpha * alpha)
{ {
guint8 *src1; const guint8 *src1;
guint8 *dest1; guint8 *dest1;
gint i, j; gint i, j;
gint a, y, u, v; gint a, y, u, v;
@ -578,7 +644,8 @@ gst_alpha_chroma_key_ayuv (guint8 * src, guint8 * dest, gint width, gint height,
static inline void static inline void
gst_alpha_chromakey_row_i420 (GstAlpha * alpha, guint8 * dest1, guint8 * dest2, gst_alpha_chromakey_row_i420 (GstAlpha * alpha, guint8 * dest1, guint8 * dest2,
guint8 * srcY1, guint8 * srcY2, guint8 * srcU, guint8 * srcV, gint width) const guint8 * srcY1, const guint8 * srcY2, const guint8 * srcU,
const guint8 * srcV, gint width)
{ {
gint xpos; gint xpos;
gint a, a2, y[4], u, v; gint a, a2, y[4], u, v;
@ -624,10 +691,10 @@ gst_alpha_chromakey_row_i420 (GstAlpha * alpha, guint8 * dest1, guint8 * dest2,
} }
static void static void
gst_alpha_chroma_key_i420 (guint8 * src, guint8 * dest, gint width, gint height, gst_alpha_chroma_key_i420 (const guint8 * src, guint8 * dest, gint width,
GstAlpha * alpha) gint height, GstAlpha * alpha)
{ {
guint8 *srcY1, *srcY2, *srcU, *srcV; const guint8 *srcY1, *srcY2, *srcU, *srcV;
guint8 *dest1, *dest2; guint8 *dest1, *dest2;
gint ypos; gint ypos;
gint dest_stride, src_y_stride, src_uv_stride; gint dest_stride, src_y_stride, src_uv_stride;
@ -673,16 +740,28 @@ gst_alpha_init_params (GstAlpha * alpha)
float kgl; float kgl;
float tmp; float tmp;
float tmp1, tmp2; float tmp1, tmp2;
const gint *matrix;
matrix =
(alpha->out_sdtv) ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
cog_rgb_to_ycbcr_matrix_8bit_hdtv;
alpha->y = alpha->y =
0.257 * alpha->target_r + 0.504 * alpha->target_g + (matrix[0] * ((gint) alpha->target_r) +
0.098 * alpha->target_b; matrix[1] * ((gint) alpha->target_g) +
matrix[2] * ((gint) alpha->target_b) + matrix[3]) >> 8;
/* Cb,Cr without offset here because the chroma keying
* works with them being in range [-128,127]
*/
tmp1 = tmp1 =
-0.148 * alpha->target_r - 0.291 * alpha->target_g + (matrix[4] * ((gint) alpha->target_r) +
0.439 * alpha->target_b; matrix[5] * ((gint) alpha->target_g) +
matrix[6] * ((gint) alpha->target_b)) >> 8;
tmp2 = tmp2 =
0.439 * alpha->target_r - 0.368 * alpha->target_g - (matrix[8] * ((gint) alpha->target_r) +
0.071 * alpha->target_b; matrix[9] * ((gint) alpha->target_g) +
matrix[10] * ((gint) alpha->target_b)) >> 8;
kgl = sqrt (tmp1 * tmp1 + tmp2 * tmp2); kgl = sqrt (tmp1 * tmp1 + tmp2 * tmp2);
alpha->cb = 127 * (tmp1 / kgl); alpha->cb = 127 * (tmp1 / kgl);
alpha->cr = 127 * (tmp2 / kgl); alpha->cr = 127 * (tmp2 / kgl);
@ -705,6 +784,53 @@ gst_alpha_init_params (GstAlpha * alpha)
alpha->noise_level2 = alpha->noise_level * alpha->noise_level; alpha->noise_level2 = alpha->noise_level * alpha->noise_level;
} }
static gboolean
gst_alpha_set_process_function (GstAlpha * alpha)
{
alpha->process = NULL;
switch (alpha->method) {
case ALPHA_METHOD_SET:
switch (alpha->out_format) {
case GST_VIDEO_FORMAT_AYUV:
switch (alpha->in_format) {
case GST_VIDEO_FORMAT_AYUV:
alpha->process = gst_alpha_set_ayuv;
break;
case GST_VIDEO_FORMAT_I420:
alpha->process = gst_alpha_set_i420;
break;
default:
break;
}
default:
break;
}
break;
case ALPHA_METHOD_GREEN:
case ALPHA_METHOD_BLUE:
case ALPHA_METHOD_CUSTOM:
switch (alpha->out_format) {
case GST_VIDEO_FORMAT_AYUV:
switch (alpha->in_format) {
case GST_VIDEO_FORMAT_AYUV:
alpha->process = gst_alpha_chroma_key_ayuv;
break;
case GST_VIDEO_FORMAT_I420:
alpha->process = gst_alpha_chroma_key_i420;
break;
default:
break;
}
default:
break;
}
break;
default:
break;
}
return alpha->process != NULL;
}
static gboolean static gboolean
gst_alpha_start (GstBaseTransform * btrans) gst_alpha_start (GstBaseTransform * btrans)
{ {
@ -734,30 +860,14 @@ gst_alpha_transform (GstBaseTransform * btrans, GstBuffer * in, GstBuffer * out)
gst_object_sync_values (G_OBJECT (alpha), timestamp); gst_object_sync_values (G_OBJECT (alpha), timestamp);
GST_OBJECT_LOCK (alpha); GST_OBJECT_LOCK (alpha);
switch (alpha->method) { if (G_UNLIKELY (!alpha->process)) {
case ALPHA_METHOD_SET: GST_ERROR_OBJECT (alpha, "Not negotiated yet");
if (alpha->format == GST_VIDEO_FORMAT_AYUV) { GST_OBJECT_UNLOCK (alpha);
gst_alpha_set_ayuv (GST_BUFFER_DATA (in), return GST_FLOW_NOT_NEGOTIATED;
GST_BUFFER_DATA (out), width, height, alpha->alpha);
} else {
gst_alpha_set_i420 (GST_BUFFER_DATA (in),
GST_BUFFER_DATA (out), width, height, alpha->alpha);
}
break;
case ALPHA_METHOD_GREEN:
case ALPHA_METHOD_BLUE:
case ALPHA_METHOD_CUSTOM:
if (alpha->format == GST_VIDEO_FORMAT_AYUV) {
gst_alpha_chroma_key_ayuv (GST_BUFFER_DATA (in),
GST_BUFFER_DATA (out), width, height, alpha);
} else {
gst_alpha_chroma_key_i420 (GST_BUFFER_DATA (in),
GST_BUFFER_DATA (out), width, height, alpha);
}
break;
default:
break;
} }
alpha->process (GST_BUFFER_DATA (in),
GST_BUFFER_DATA (out), width, height, alpha);
GST_OBJECT_UNLOCK (alpha); GST_OBJECT_UNLOCK (alpha);
return GST_FLOW_OK; return GST_FLOW_OK;

View file

@ -61,8 +61,9 @@ struct _GstAlpha
GstVideoFilter parent; GstVideoFilter parent;
/* caps */ /* caps */
GstVideoFormat format; GstVideoFormat in_format, out_format;
gint width, height; gint width, height;
gboolean in_sdtv, out_sdtv;
gdouble alpha; gdouble alpha;
@ -87,6 +88,8 @@ struct _GstAlpha
guint8 accept_angle_ctg; guint8 accept_angle_ctg;
guint8 one_over_kc; guint8 one_over_kc;
guint8 kfgy_scale; guint8 kfgy_scale;
void (*process) (const guint8 *src, guint8 *dest, gint width, gint height, GstAlpha *alpha);
}; };
struct _GstAlphaClass struct _GstAlphaClass