blob: f8f984c5a8b768b3d20b0d9140627ab1c13c35c5 [file] [log] [blame]
/* GStreamer
* Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu>
* Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
* Copyright (C) 2010 Sebastian Dröge <sebastian.droege@collabora.co.uk>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**
* SECTION:element-videobox
* @see_also: #GstVideoCrop
*
* This plugin crops or enlarges the image. It takes 4 values as input, a
* top, bottom, left and right offset. Positive values will crop that much
* pixels from the respective border of the image, negative values will add
* that much pixels. When pixels are added, you can specify their color.
* Some predefined colors are usable with an enum property.
*
* The plugin is alpha channel aware and will try to negotiate with a format
* that supports alpha channels first. When alpha channel is active two
* other properties, alpha and border_alpha can be used to set the alpha
* values of the inner picture and the border respectively. an alpha value of
* 0.0 means total transparency, 1.0 is opaque.
*
* The videobox plugin has many uses such as doing a mosaic of pictures,
* letterboxing video, cutting out pieces of video, picture in picture, etc..
*
* Setting autocrop to true changes the behavior of the plugin so that
* caps determine crop properties rather than the other way around: given
* input and output dimensions, the crop values are selected so that the
* smaller frame is effectively centered in the larger frame. This
* involves either cropping or padding.
*
* If you use autocrop there is little point in setting the other
* properties manually because they will be overriden if the caps change,
* but nothing stops you from doing so.
*
* Sample pipeline:
* |[
* gst-launch-1.0 videotestsrc ! videobox autocrop=true ! \
* "video/x-raw, width=600, height=400" ! videoconvert ! ximagesink
* ]|
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstvideobox.h"
#include "gstvideoboxorc.h"
#include <math.h>
#include <string.h>
GST_DEBUG_CATEGORY_STATIC (videobox_debug);
#define GST_CAT_DEFAULT videobox_debug
/* From videotestsrc.c */
static const guint8 yuv_sdtv_colors_Y[VIDEO_BOX_FILL_LAST] =
{ 16, 145, 41, 81, 210, 235 };
static const guint8 yuv_sdtv_colors_U[VIDEO_BOX_FILL_LAST] =
{ 128, 54, 240, 90, 16, 128 };
static const guint8 yuv_sdtv_colors_V[VIDEO_BOX_FILL_LAST] =
{ 128, 34, 110, 240, 146, 128 };
static const guint8 yuv_hdtv_colors_Y[VIDEO_BOX_FILL_LAST] =
{ 16, 173, 32, 63, 219, 235 };
static const guint8 yuv_hdtv_colors_U[VIDEO_BOX_FILL_LAST] =
{ 128, 42, 240, 102, 16, 128 };
static const guint8 yuv_hdtv_colors_V[VIDEO_BOX_FILL_LAST] =
{ 128, 26, 118, 240, 138, 128 };
static const guint8 rgb_colors_R[VIDEO_BOX_FILL_LAST] =
{ 0, 0, 0, 255, 255, 255 };
static const guint8 rgb_colors_G[VIDEO_BOX_FILL_LAST] =
{ 0, 255, 0, 0, 255, 255 };
static const guint8 rgb_colors_B[VIDEO_BOX_FILL_LAST] =
{ 0, 0, 255, 0, 0, 255 };
/* 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,
};
static const gint cog_identity_matrix_8bit[] = {
256, 0, 0, 0,
0, 256, 0, 0,
0, 0, 256, 0,
};
#define APPLY_MATRIX(m,o,v1,v2,v3) ((m[o*4] * v1 + m[o*4+1] * v2 + m[o*4+2] * v3 + m[o*4+3]) >> 8)
static void
fill_ayuv (GstVideoBoxFill fill_type, guint b_alpha,
GstVideoFrame * frame, gboolean sdtv)
{
guint32 empty_pixel;
guint8 *dest;
gint width, height;
gint stride;
width = GST_VIDEO_FRAME_WIDTH (frame);
height = GST_VIDEO_FRAME_HEIGHT (frame);
b_alpha = CLAMP (b_alpha, 0, 255);
if (sdtv)
empty_pixel = GUINT32_FROM_BE ((b_alpha << 24) |
(yuv_sdtv_colors_Y[fill_type] << 16) |
(yuv_sdtv_colors_U[fill_type] << 8) | yuv_sdtv_colors_V[fill_type]);
else
empty_pixel = GUINT32_FROM_BE ((b_alpha << 24) |
(yuv_hdtv_colors_Y[fill_type] << 16) |
(yuv_hdtv_colors_U[fill_type] << 8) | yuv_hdtv_colors_V[fill_type]);
dest = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
stride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0);
if (G_LIKELY (stride == 4 * width))
video_box_orc_splat_u32 ((guint32 *) dest, empty_pixel, width * height);
else if (height) {
for (; height; --height) {
video_box_orc_splat_u32 ((guint32 *) dest, empty_pixel, width);
dest += stride;
}
}
}
static void
copy_ayuv_ayuv (guint i_alpha, GstVideoFrame * dest_frame,
gboolean dest_sdtv, gint dest_x, gint dest_y, GstVideoFrame * src_frame,
gboolean src_sdtv, gint src_x, gint src_y, gint w, gint h)
{
gint i, j;
gint src_stride;
gint dest_stride;
guint8 *dest, *src;
src_stride = GST_VIDEO_FRAME_PLANE_STRIDE (src_frame, 0);
dest_stride = GST_VIDEO_FRAME_PLANE_STRIDE (dest_frame, 0);
src = GST_VIDEO_FRAME_PLANE_DATA (src_frame, 0);
dest = GST_VIDEO_FRAME_PLANE_DATA (dest_frame, 0);
dest = dest + dest_y * dest_stride + dest_x * 4;
src = src + src_y * src_stride + src_x * 4;
w *= 4;
if (dest_sdtv != src_sdtv) {
gint matrix[12];
gint y, u, v;
memcpy (matrix,
dest_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit, 12 * sizeof (gint));
for (i = 0; i < h; i++) {
for (j = 0; j < w; j += 4) {
/* ORC FIXME */
dest[j] = (src[j] * i_alpha) >> 8;
y = src[j + 1];
u = src[j + 2];
v = src[j + 3];
dest[j + 1] = APPLY_MATRIX (matrix, 0, y, u, v);
dest[j + 2] = APPLY_MATRIX (matrix, 1, y, u, v);
dest[j + 3] = APPLY_MATRIX (matrix, 2, y, u, v);
}
dest += dest_stride;
src += src_stride;
}
} else {
for (i = 0; i < h; i++) {
for (j = 0; j < w; j += 4) {
/* ORC FIXME */
dest[j] = (src[j] * i_alpha) >> 8;
dest[j + 1] = src[j + 1];
dest[j + 2] = src[j + 2];
dest[j + 3] = src[j + 3];
}
dest += dest_stride;
src += src_stride;
}
}
}
static void
copy_ayuv_i420 (guint i_alpha, GstVideoFrame * dest_frame,
gboolean dest_sdtv, gint dest_x, gint dest_y, GstVideoFrame * src_frame,
gboolean src_sdtv, gint src_x, gint src_y, gint w, gint h)
{
gint i, j;
guint8 *destY, *destY2, *destU, *destV;
gint dest_strideY, dest_strideU, dest_strideV;
const guint8 *src2;
gint src_stride;
gint y_idx, uv_idx;
gint y1, y2, y3, y4;
gint u1, u2, u3, u4;
gint v1, v2, v3, v4;
gint matrix[12];
guint8 *src;
gint dest_height, src_height, dest_width;
dest_height = GST_VIDEO_FRAME_HEIGHT (dest_frame);
dest_width = GST_VIDEO_FRAME_WIDTH (dest_frame);
src_height = GST_VIDEO_FRAME_HEIGHT (src_frame);
dest_strideY = GST_VIDEO_FRAME_COMP_STRIDE (dest_frame, 0);
dest_strideU = GST_VIDEO_FRAME_COMP_STRIDE (dest_frame, 1);
dest_strideV = GST_VIDEO_FRAME_COMP_STRIDE (dest_frame, 2);
src_stride = GST_VIDEO_FRAME_PLANE_STRIDE (src_frame, 0);
destY = GST_VIDEO_FRAME_COMP_DATA (dest_frame, 0);
destU = GST_VIDEO_FRAME_COMP_DATA (dest_frame, 1);
destV = GST_VIDEO_FRAME_COMP_DATA (dest_frame, 2);
destY = destY + dest_y * dest_strideY + dest_x;
destY2 = (dest_y < dest_height) ? destY + dest_strideY : destY;
destU = destU + (dest_y / 2) * dest_strideU + dest_x / 2;
destV = destV + (dest_y / 2) * dest_strideV + dest_x / 2;
src = GST_VIDEO_FRAME_PLANE_DATA (src_frame, 0);
src = src + src_y * src_stride + src_x * 4;
src2 = (src_y < src_height) ? src + src_stride : src;
h = dest_y + h;
w = dest_x + w;
if (src_sdtv != dest_sdtv)
memcpy (matrix,
dest_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit, 12 * sizeof (gint));
else
memcpy (matrix, cog_identity_matrix_8bit, 12 * sizeof (gint));
/* 1. Handle the first destination scanline specially if it
* doesn't start at the macro pixel boundary, i.e. blend
* with the background! */
if (dest_y % 2 == 1) {
/* 1.1. Handle the first destination pixel if it doesn't
* start at the macro pixel boundary, i.e. blend with
* the background! */
if (dest_x % 2 == 1) {
y1 = src[4 * 0 + 1];
u1 = src[4 * 0 + 2];
v1 = src[4 * 0 + 3];
destY[0] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
destU[0] =
CLAMP ((3 * destU[0] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 4, 0,
255);
destV[0] =
CLAMP ((3 * destV[0] + APPLY_MATRIX (matrix, 2, y1, u1, v1)) / 4, 0,
255);
j = dest_x + 1;
y_idx = uv_idx = 1;
} else {
j = dest_x;
y_idx = uv_idx = 0;
}
/* 1.2. Copy all macro pixels from the source to the destination
* but blend with the background because we're only filling
* the lower part of the macro pixels. */
for (; j < w - 1; j += 2) {
y1 = src[4 * y_idx + 1];
y2 = src[4 * y_idx + 4 + 1];
u1 = src[4 * y_idx + 2];
u2 = src[4 * y_idx + 4 + 2];
v1 = src[4 * y_idx + 3];
v2 = src[4 * y_idx + 4 + 3];
destY[y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
destY[y_idx + 1] = CLAMP (APPLY_MATRIX (matrix, 0, y2, u2, v2), 0, 255);
destU[uv_idx] = CLAMP (
(2 * destU[uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
v1) + APPLY_MATRIX (matrix, 1, y2, u2, v2)) / 4, 0, 255);
destV[uv_idx] = CLAMP (
(2 * destV[uv_idx] + APPLY_MATRIX (matrix, 2, y1, u1,
v1) + APPLY_MATRIX (matrix, 2, y2, u2, v2)) / 4, 0, 255);
y_idx += 2;
uv_idx++;
}
/* 1.3. Now copy the last pixel if one exists and blend it
* with the background because we only fill part of
* the macro pixel. In case this is the last pixel of
* the destination we will a larger part. */
if (j == w - 1 && j == dest_width - 1) {
y1 = src[4 * y_idx + 1];
u1 = src[4 * y_idx + 2];
v1 = src[4 * y_idx + 3];
destY[y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
destU[uv_idx] = CLAMP (
(destU[uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 2, 0, 255);
destV[uv_idx] = CLAMP (
(destV[uv_idx] + APPLY_MATRIX (matrix, 2, y1, u1, v1)) / 2, 0, 255);
} else if (j == w - 1) {
y1 = src[4 * y_idx + 1];
u1 = src[4 * y_idx + 2];
v1 = src[4 * y_idx + 3];
destY[y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
destU[uv_idx] = CLAMP (
(3 * destU[uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 4, 0,
255);
destV[uv_idx] =
CLAMP ((3 * destV[uv_idx] + APPLY_MATRIX (matrix, 2, y1, u1, v1)) / 4,
0, 255);
}
destY += dest_strideY;
destY2 += dest_strideY;
destU += dest_strideU;
destV += dest_strideV;
src += src_stride;
src2 += src_stride;
i = dest_y + 1;
} else {
i = dest_y;
}
/* 2. Copy all macro pixel scanlines, the destination scanline
* now starts at macro pixel boundary. */
for (; i < h - 1; i += 2) {
/* 2.1. Handle the first destination pixel if it doesn't
* start at the macro pixel boundary, i.e. blend with
* the background! */
if (dest_x % 2 == 1) {
y1 = src[4 * 0 + 1];
y2 = src2[4 * 0 + 1];
u1 = src[4 * 0 + 2];
u2 = src2[4 * 0 + 2];
v1 = src[4 * 0 + 3];
v2 = src2[4 * 0 + 3];
destY[0] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
destY2[0] = CLAMP (APPLY_MATRIX (matrix, 0, y2, u2, v2), 0, 255);
destU[0] = CLAMP (
(2 * destU[0] + APPLY_MATRIX (matrix, 1, y1, u1,
v1) + APPLY_MATRIX (matrix, 1, y2, u2, v2)) / 4, 0, 255);
destV[0] = CLAMP (
(2 * destV[0] + APPLY_MATRIX (matrix, 2, y1, u1,
v1) + APPLY_MATRIX (matrix, 2, y2, u2, v2)) / 4, 0, 255);
j = dest_x + 1;
y_idx = uv_idx = 1;
} else {
j = dest_x;
y_idx = uv_idx = 0;
}
/* 2.2. Copy all macro pixels from the source to the destination.
* All pixels now start at macro pixel boundary, i.e. no
* blending with the background is necessary. */
for (; j < w - 1; j += 2) {
y1 = src[4 * y_idx + 1];
y2 = src[4 * y_idx + 4 + 1];
y3 = src2[4 * y_idx + 1];
y4 = src2[4 * y_idx + 4 + 1];
u1 = src[4 * y_idx + 2];
u2 = src[4 * y_idx + 4 + 2];
u3 = src2[4 * y_idx + 2];
u4 = src2[4 * y_idx + 4 + 2];
v1 = src[4 * y_idx + 3];
v2 = src[4 * y_idx + 4 + 3];
v3 = src2[4 * y_idx + 3];
v4 = src2[4 * y_idx + 4 + 3];
destY[y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
destY[y_idx + 1] = CLAMP (APPLY_MATRIX (matrix, 0, y2, u2, v2), 0, 255);
destY2[y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y3, u3, v3), 0, 255);
destY2[y_idx + 1] = CLAMP (APPLY_MATRIX (matrix, 0, y4, u4, v4), 0, 255);
destU[uv_idx] = CLAMP (
(APPLY_MATRIX (matrix, 1, y1, u1, v1) + APPLY_MATRIX (matrix, 1, y2,
u2, v2) + APPLY_MATRIX (matrix, 1, y3, u3,
v3) + APPLY_MATRIX (matrix, 1, y4, u4, v4)) / 4, 0, 255);
destV[uv_idx] = CLAMP (
(APPLY_MATRIX (matrix, 2, y1, u1, v1) + APPLY_MATRIX (matrix, 2, y2,
u2, v2) + APPLY_MATRIX (matrix, 2, y3, u3,
v3) + APPLY_MATRIX (matrix, 2, y4, u4, v4)) / 4, 0, 255);
y_idx += 2;
uv_idx++;
}
/* 2.3. Now copy the last pixel if one exists and blend it
* with the background because we only fill part of
* the macro pixel. In case this is the last pixel of
* the destination we will a larger part. */
if (j == w - 1 && j == dest_width - 1) {
y1 = src[4 * y_idx + 1];
y2 = src2[4 * y_idx + 1];
u1 = src[4 * y_idx + 2];
u2 = src2[4 * y_idx + 2];
v1 = src[4 * y_idx + 3];
v2 = src2[4 * y_idx + 3];
destY[y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
destY2[y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y2, u2, v2), 0, 255);
destU[uv_idx] = CLAMP (
(APPLY_MATRIX (matrix, 1, y1, u1, v1) + APPLY_MATRIX (matrix, 2, y2,
u2, v2)) / 2, 0, 255);
destV[uv_idx] = CLAMP (
(APPLY_MATRIX (matrix, 1, y1, u1, v1) + APPLY_MATRIX (matrix, 2, y2,
u2, v2)) / 2, 0, 255);
} else if (j == w - 1) {
y1 = src[4 * y_idx + 1];
y2 = src2[4 * y_idx + 1];
u1 = src[4 * y_idx + 2];
u2 = src2[4 * y_idx + 2];
v1 = src[4 * y_idx + 3];
v2 = src2[4 * y_idx + 3];
destY[y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
destY2[y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y2, u2, v2), 0, 255);
destU[uv_idx] = CLAMP (
(2 * destU[uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
v1) + APPLY_MATRIX (matrix, 2, y2, u2, v2)) / 4, 0, 255);
destV[uv_idx] = CLAMP (
(2 * destV[uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
v1) + APPLY_MATRIX (matrix, 2, y2, u2, v2)) / 4, 0, 255);
}
destY += 2 * dest_strideY;
destY2 += 2 * dest_strideY;
destU += dest_strideU;
destV += dest_strideV;
src += 2 * src_stride;
src2 += 2 * src_stride;
}
/* 3. Handle the last scanline if one exists. This again
* doesn't start at macro pixel boundary but should
* only fill the upper part of the macro pixels. */
if (i == h - 1 && i == dest_height - 1) {
/* 3.1. Handle the first destination pixel if it doesn't
* start at the macro pixel boundary, i.e. blend with
* the background! */
if (dest_x % 2 == 1) {
y1 = src[4 * 0 + 1];
u1 = src[4 * 0 + 2];
v1 = src[4 * 0 + 3];
destY[0] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
destU[0] =
CLAMP ((destU[0] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 2, 0, 255);
destV[0] =
CLAMP ((destV[0] + APPLY_MATRIX (matrix, 2, y1, u1, v1)) / 2, 0, 255);
j = dest_x + 1;
y_idx = uv_idx = 1;
} else {
j = dest_x;
y_idx = uv_idx = 0;
}
/* 3.2. Copy all macro pixels from the source to the destination
* but blend with the background because we're only filling
* the upper part of the macro pixels. */
for (; j < w - 1; j += 2) {
y1 = src[4 * y_idx + 1];
y2 = src[4 * y_idx + 4 + 1];
u1 = src[4 * y_idx + 2];
u2 = src[4 * y_idx + 4 + 2];
v1 = src[4 * y_idx + 3];
v2 = src[4 * y_idx + 4 + 3];
destY[y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
destY[y_idx + 1] = CLAMP (APPLY_MATRIX (matrix, 0, y2, u2, v2), 0, 255);
destU[uv_idx] = CLAMP (
(2 * destU[uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
v1) + APPLY_MATRIX (matrix, 1, y2, u2, v2)) / 4, 0, 255);
destV[uv_idx] = CLAMP (
(2 * destV[uv_idx] + APPLY_MATRIX (matrix, 2, y1, u1,
v1) + APPLY_MATRIX (matrix, 2, y2, u2, v2)) / 4, 0, 255);
y_idx += 2;
uv_idx++;
}
/* 3.3. Now copy the last pixel if one exists and blend it
* with the background because we only fill part of
* the macro pixel. In case this is the last pixel of
* the destination we will a larger part. */
if (j == w - 1 && j == dest_width - 1) {
y1 = src[4 * y_idx + 1];
u1 = src[4 * y_idx + 2];
v1 = src[4 * y_idx + 3];
destY[y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
destU[uv_idx] = CLAMP (
(destU[uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 2, 0, 255);
destV[uv_idx] = CLAMP (
(destV[uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 2, 0, 255);
} else if (j == w - 1) {
y1 = src[4 * y_idx + 1];
u1 = src[4 * y_idx + 2];
v1 = src[4 * y_idx + 3];
destY[y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
destU[uv_idx] = CLAMP (
(3 * destU[uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 4, 0,
255);
destV[uv_idx] =
CLAMP ((3 * destV[uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 4,
0, 255);
}
} else if (i == h - 1) {
/* 3.1. Handle the first destination pixel if it doesn't
* start at the macro pixel boundary, i.e. blend with
* the background! */
if (dest_x % 2 == 1) {
y1 = src[4 * 0 + 1];
u1 = src[4 * 0 + 2];
v1 = src[4 * 0 + 3];
destY[0] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
destU[0] =
CLAMP ((3 * destU[0] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 4, 0,
255);
destV[0] =
CLAMP ((3 * destV[0] + APPLY_MATRIX (matrix, 2, y1, u1, v1)) / 4, 0,
255);
j = dest_x + 1;
y_idx = uv_idx = 1;
} else {
j = dest_x;
y_idx = uv_idx = 0;
}
/* 3.2. Copy all macro pixels from the source to the destination
* but blend with the background because we're only filling
* the upper part of the macro pixels. */
for (; j < w - 1; j += 2) {
y1 = src[4 * y_idx + 1];
y2 = src[4 * y_idx + 4 + 1];
u1 = src[4 * y_idx + 2];
u2 = src[4 * y_idx + 4 + 2];
v1 = src[4 * y_idx + 3];
v2 = src[4 * y_idx + 4 + 3];
destY[y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
destY[y_idx + 1] = CLAMP (APPLY_MATRIX (matrix, 0, y2, u2, v2), 0, 255);
destU[uv_idx] = CLAMP (
(2 * destU[uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
v1) + APPLY_MATRIX (matrix, 1, y2, u2, v2)) / 4, 0, 255);
destV[uv_idx] = CLAMP (
(2 * destV[uv_idx] + APPLY_MATRIX (matrix, 2, y1, u1,
v1) + APPLY_MATRIX (matrix, 2, y2, u2, v2)) / 4, 0, 255);
y_idx += 2;
uv_idx++;
}
/* 3.3. Now copy the last pixel if one exists and blend it
* with the background because we only fill part of
* the macro pixel. In case this is the last pixel of
* the destination we will a larger part. */
if (j == w - 1 && j == dest_width - 1) {
y1 = src[4 * y_idx + 1];
u1 = src[4 * y_idx + 2];
v1 = src[4 * y_idx + 3];
destY[y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
destU[uv_idx] = CLAMP (
(destU[uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 2, 0, 255);
destV[uv_idx] = CLAMP (
(destV[uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 2, 0, 255);
} else if (j == w - 1) {
y1 = src[4 * y_idx + 1];
u1 = src[4 * y_idx + 2];
v1 = src[4 * y_idx + 3];
destY[y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
destU[uv_idx] = CLAMP (
(3 * destU[uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 4, 0,
255);
destV[uv_idx] =
CLAMP ((3 * destV[uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 4,
0, 255);
}
}
}
static void
fill_planar_yuv (GstVideoBoxFill fill_type, guint b_alpha,
GstVideoFrame * frame, gboolean sdtv)
{
guint8 empty_pixel[3];
guint8 *destY, *destU, *destV;
gint strideY, strideU, strideV;
gint heightY, heightU, heightV;
gint widthY, widthU, widthV;
if (sdtv) {
empty_pixel[0] = yuv_sdtv_colors_Y[fill_type];
empty_pixel[1] = yuv_sdtv_colors_U[fill_type];
empty_pixel[2] = yuv_sdtv_colors_V[fill_type];
} else {
empty_pixel[0] = yuv_hdtv_colors_Y[fill_type];
empty_pixel[1] = yuv_hdtv_colors_U[fill_type];
empty_pixel[2] = yuv_hdtv_colors_V[fill_type];
}
strideY = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0);
strideU = GST_VIDEO_FRAME_COMP_STRIDE (frame, 1);
strideV = GST_VIDEO_FRAME_COMP_STRIDE (frame, 2);
destY = GST_VIDEO_FRAME_COMP_DATA (frame, 0);
destU = GST_VIDEO_FRAME_COMP_DATA (frame, 1);
destV = GST_VIDEO_FRAME_COMP_DATA (frame, 2);
widthY = GST_VIDEO_FRAME_COMP_WIDTH (frame, 0);
widthU = GST_VIDEO_FRAME_COMP_WIDTH (frame, 1);
widthV = GST_VIDEO_FRAME_COMP_WIDTH (frame, 2);
heightY = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 0);
heightU = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 1);
heightV = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 2);
if (strideY == widthY) {
memset (destY, empty_pixel[0], strideY * heightY);
} else if (heightY) {
for (; heightY; --heightY) {
memset (destY, empty_pixel[0], widthY);
destY += strideY;
}
}
if (strideU == widthU) {
memset (destU, empty_pixel[1], strideU * heightU);
} else if (heightU) {
for (; heightU; --heightU) {
memset (destU, empty_pixel[1], widthU);
destU += strideU;
}
}
if (strideV == widthV) {
memset (destV, empty_pixel[2], strideV * heightV);
} else if (heightV) {
for (; heightV; --heightV) {
memset (destV, empty_pixel[2], widthV);
destV += strideV;
}
}
}
static void
copy_y444_y444 (guint i_alpha, GstVideoFrame * dest,
gboolean dest_sdtv, gint dest_x, gint dest_y, GstVideoFrame * src,
gboolean src_sdtv, gint src_x, gint src_y, gint w, gint h)
{
gint i, j;
guint8 *destY, *destU, *destV;
const guint8 *srcY, *srcU, *srcV;
gint dest_strideY, dest_strideU, dest_strideV;
gint src_strideY, src_strideU, src_strideV;
dest_strideY = GST_VIDEO_FRAME_COMP_STRIDE (dest, 0);
dest_strideU = GST_VIDEO_FRAME_COMP_STRIDE (dest, 1);
dest_strideV = GST_VIDEO_FRAME_COMP_STRIDE (dest, 2);
src_strideY = GST_VIDEO_FRAME_COMP_STRIDE (src, 0);
src_strideU = GST_VIDEO_FRAME_COMP_STRIDE (src, 1);
src_strideV = GST_VIDEO_FRAME_COMP_STRIDE (src, 2);
destY = GST_VIDEO_FRAME_COMP_DATA (dest, 0);
destU = GST_VIDEO_FRAME_COMP_DATA (dest, 1);
destV = GST_VIDEO_FRAME_COMP_DATA (dest, 2);
srcY = GST_VIDEO_FRAME_COMP_DATA (src, 0);
srcU = GST_VIDEO_FRAME_COMP_DATA (src, 1);
srcV = GST_VIDEO_FRAME_COMP_DATA (src, 2);
destY = destY + dest_y * dest_strideY + dest_x;
destU = destU + dest_y * dest_strideU + dest_x;
destV = destV + dest_y * dest_strideV + dest_x;
srcY = srcY + src_y * src_strideY + src_x;
srcU = srcU + src_y * src_strideU + src_x;
srcV = srcV + src_y * src_strideV + src_x;
if (src_sdtv != dest_sdtv) {
gint matrix[12];
gint y, u, v;
memcpy (matrix,
dest_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit, 12 * sizeof (gint));
for (i = 0; i < h; i++) {
for (j = 0; j < w; j++) {
y = APPLY_MATRIX (matrix, 0, srcY[j], srcU[j], srcV[j]);
u = APPLY_MATRIX (matrix, 1, srcY[j], srcU[j], srcV[j]);
v = APPLY_MATRIX (matrix, 2, srcY[j], srcU[j], srcV[j]);
destY[j] = y;
destU[j] = u;
destV[j] = v;
}
destY += dest_strideY;
destU += dest_strideU;
destV += dest_strideV;
srcY += src_strideY;
srcU += src_strideU;
srcV += src_strideV;
}
} else {
for (i = 0; i < h; i++) {
memcpy (destY, srcY, w);
memcpy (destU, srcU, w);
memcpy (destV, srcV, w);
destY += dest_strideY;
destU += dest_strideU;
destV += dest_strideV;
srcY += src_strideY;
srcU += src_strideU;
srcV += src_strideV;
}
}
}
static void
copy_y42b_y42b (guint i_alpha, GstVideoFrame * dest,
gboolean dest_sdtv, gint dest_x, gint dest_y, GstVideoFrame * src,
gboolean src_sdtv, gint src_x, gint src_y, gint w, gint h)
{
gint i, j;
guint8 *destY, *destU, *destV;
const guint8 *srcY, *srcU, *srcV;
gint dest_strideY, dest_strideU, dest_strideV;
gint src_strideY, src_strideU, src_strideV;
gint src_y_idx, src_uv_idx;
gint dest_y_idx, dest_uv_idx;
gint matrix[12];
gint y1, y2;
gint u1, u2;
gint v1, v2;
gint dest_width;
dest_width = GST_VIDEO_FRAME_WIDTH (dest);
dest_strideY = GST_VIDEO_FRAME_COMP_STRIDE (dest, 0);
dest_strideU = GST_VIDEO_FRAME_COMP_STRIDE (dest, 1);
dest_strideV = GST_VIDEO_FRAME_COMP_STRIDE (dest, 2);
src_strideY = GST_VIDEO_FRAME_COMP_STRIDE (src, 0);
src_strideU = GST_VIDEO_FRAME_COMP_STRIDE (src, 1);
src_strideV = GST_VIDEO_FRAME_COMP_STRIDE (src, 2);
destY = GST_VIDEO_FRAME_COMP_DATA (dest, 0);
destU = GST_VIDEO_FRAME_COMP_DATA (dest, 1);
destV = GST_VIDEO_FRAME_COMP_DATA (dest, 2);
srcY = GST_VIDEO_FRAME_COMP_DATA (src, 0);
srcU = GST_VIDEO_FRAME_COMP_DATA (src, 1);
srcV = GST_VIDEO_FRAME_COMP_DATA (src, 2);
destY = destY + dest_y * dest_strideY + dest_x;
destU = destU + dest_y * dest_strideU + dest_x / 2;
destV = destV + dest_y * dest_strideV + dest_x / 2;
srcY = srcY + src_y * src_strideY + src_x;
srcU = srcU + src_y * src_strideU + src_x / 2;
srcV = srcV + src_y * src_strideV + src_x / 2;
h = dest_y + h;
w = dest_x + w;
if (src_sdtv != dest_sdtv)
memcpy (matrix,
dest_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit, 12 * sizeof (gint));
else
memcpy (matrix, cog_identity_matrix_8bit, 12 * sizeof (gint));
/* 1. Copy all macro pixel scanlines, the destination scanline
* now starts at macro pixel boundary. */
for (i = dest_y; i < h; i++) {
/* 1.1. Handle the first destination pixel if it doesn't
* start at the macro pixel boundary, i.e. blend with
* the background! */
if (dest_x % 2 == 1) {
y1 = srcY[0];
u1 = srcU[0];
v1 = srcV[0];
destY[0] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
destU[0] = CLAMP (
(destU[0] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 2, 0, 255);
destV[0] = CLAMP (
(destV[0] + APPLY_MATRIX (matrix, 2, y1, u1, v1)) / 2, 0, 255);
j = dest_x + 1;
src_y_idx = dest_y_idx = dest_uv_idx = 1;
src_uv_idx = (src_x % 2) + 1;
} else {
j = dest_x;
src_y_idx = dest_y_idx = dest_uv_idx = 0;
src_uv_idx = (src_x % 2);
}
/* 1.2. Copy all macro pixels from the source to the destination.
* All pixels now start at macro pixel boundary, i.e. no
* blending with the background is necessary. */
for (; j < w - 1; j += 2) {
y1 = srcY[src_y_idx];
y2 = srcY[src_y_idx + 1];
u1 = srcU[src_uv_idx / 2];
v1 = srcV[src_uv_idx / 2];
src_uv_idx++;
u2 = srcU[src_uv_idx / 2];
v2 = srcV[src_uv_idx / 2];
src_uv_idx++;
destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
destY[dest_y_idx + 1] =
CLAMP (APPLY_MATRIX (matrix, 0, y2, u2, v2), 0, 255);
destU[dest_uv_idx] = CLAMP (
(APPLY_MATRIX (matrix, 1, y1, u1, v1) + APPLY_MATRIX (matrix, 1, y2,
u2, v2)) / 2, 0, 255);
destV[dest_uv_idx] = CLAMP (
(APPLY_MATRIX (matrix, 2, y1, u1, v1) + APPLY_MATRIX (matrix, 2, y2,
u2, v2)) / 2, 0, 255);
dest_y_idx += 2;
src_y_idx += 2;
dest_uv_idx++;
}
/* 1.3. Now copy the last pixel if one exists and blend it
* with the background because we only fill part of
* the macro pixel. In case this is the last pixel of
* the destination we will a larger part. */
if (j == w - 1 && j == dest_width - 1) {
y1 = srcY[src_y_idx];
u1 = srcU[src_uv_idx / 2];
v1 = srcV[src_uv_idx / 2];
destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
destU[dest_uv_idx] = CLAMP (APPLY_MATRIX (matrix, 1, y1, u1, v1), 0, 255);
destV[dest_uv_idx] = CLAMP (APPLY_MATRIX (matrix, 1, y1, u1, v1), 0, 255);
} else if (j == w - 1) {
y1 = srcY[src_y_idx];
u1 = srcU[src_uv_idx / 2];
v1 = srcV[src_uv_idx / 2];
destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
destU[dest_uv_idx] = CLAMP (
(destU[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
v1)) / 2, 0, 255);
destV[dest_uv_idx] = CLAMP (
(destV[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
v1)) / 2, 0, 255);
}
destY += dest_strideY;
destU += dest_strideU;
destV += dest_strideV;
srcY += src_strideY;
srcU += src_strideU;
srcV += src_strideV;
}
}
static void
copy_y41b_y41b (guint i_alpha, GstVideoFrame * dest,
gboolean dest_sdtv, gint dest_x, gint dest_y, GstVideoFrame * src,
gboolean src_sdtv, gint src_x, gint src_y, gint w, gint h)
{
gint i, j;
guint8 *destY, *destU, *destV;
const guint8 *srcY, *srcU, *srcV;
gint dest_strideY, dest_strideU, dest_strideV;
gint src_strideY, src_strideU, src_strideV;
gint src_y_idx, src_uv_idx;
gint dest_y_idx, dest_uv_idx;
gint matrix[12];
gint y1, y2, y3, y4;
gint u1, u2, u3, u4;
gint v1, v2, v3, v4;
gint dest_width;
dest_width = GST_VIDEO_FRAME_WIDTH (dest);
dest_strideY = GST_VIDEO_FRAME_COMP_STRIDE (dest, 0);
dest_strideU = GST_VIDEO_FRAME_COMP_STRIDE (dest, 1);
dest_strideV = GST_VIDEO_FRAME_COMP_STRIDE (dest, 2);
src_strideY = GST_VIDEO_FRAME_COMP_STRIDE (src, 0);
src_strideU = GST_VIDEO_FRAME_COMP_STRIDE (src, 1);
src_strideV = GST_VIDEO_FRAME_COMP_STRIDE (src, 2);
destY = GST_VIDEO_FRAME_COMP_DATA (dest, 0);
destU = GST_VIDEO_FRAME_COMP_DATA (dest, 1);
destV = GST_VIDEO_FRAME_COMP_DATA (dest, 2);
srcY = GST_VIDEO_FRAME_COMP_DATA (src, 0);
srcU = GST_VIDEO_FRAME_COMP_DATA (src, 1);
srcV = GST_VIDEO_FRAME_COMP_DATA (src, 2);
destY = destY + dest_y * dest_strideY + dest_x;
destU = destU + dest_y * dest_strideU + dest_x / 4;
destV = destV + dest_y * dest_strideV + dest_x / 4;
srcY = srcY + src_y * src_strideY + src_x;
srcU = srcU + src_y * src_strideU + src_x / 4;
srcV = srcV + src_y * src_strideV + src_x / 4;
h = dest_y + h;
w = dest_x + w;
if (src_sdtv != dest_sdtv)
memcpy (matrix,
dest_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit, 12 * sizeof (gint));
else
memcpy (matrix, cog_identity_matrix_8bit, 12 * sizeof (gint));
/* 1. Copy all macro pixel scanlines, the destination scanline
* now starts at macro pixel boundary. */
for (i = dest_y; i < h; i++) {
/* 1.1. Handle the first destination pixel if it doesn't
* start at the macro pixel boundary, i.e. blend with
* the background! */
if (dest_x % 4 == 1) {
y1 = srcY[0];
y2 = srcY[1];
y3 = srcY[2];
u1 = srcU[0];
v1 = srcV[0];
destY[0] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
destY[1] = CLAMP (APPLY_MATRIX (matrix, 0, y2, u1, v1), 0, 255);
destY[2] = CLAMP (APPLY_MATRIX (matrix, 0, y3, u1, v1), 0, 255);
destU[0] = CLAMP (
(destU[0] + APPLY_MATRIX (matrix, 1, y1, u1,
v1) + APPLY_MATRIX (matrix, 1, y2, u1,
v1) + APPLY_MATRIX (matrix, 1, y3, u1, v1)) / 4, 0, 255);
destV[0] =
CLAMP ((destV[0] + APPLY_MATRIX (matrix, 2, y1, u1,
v1) + APPLY_MATRIX (matrix, 2, y2, u1,
v1) + APPLY_MATRIX (matrix, 2, y3, u1, v1)) / 4, 0, 255);
j = dest_x + 3;
src_y_idx = dest_y_idx = 3;
dest_uv_idx = 1;
src_uv_idx = (src_x % 4) + 3;
} else if (dest_x % 4 == 2) {
y1 = srcY[0];
y2 = srcY[1];
u1 = srcU[0];
v1 = srcV[0];
destY[0] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
destY[1] = CLAMP (APPLY_MATRIX (matrix, 0, y2, u1, v1), 0, 255);
destU[0] = CLAMP (
(2 * destU[0] + APPLY_MATRIX (matrix, 1, y1, u1,
v1) + APPLY_MATRIX (matrix, 1, y2, u1, v1)) / 4, 0, 255);
destV[0] =
CLAMP ((2 * destV[0] + APPLY_MATRIX (matrix, 2, y1, u1,
v1) + APPLY_MATRIX (matrix, 2, y2, u1, v1)) / 4, 0, 255);
j = dest_x + 2;
src_y_idx = dest_y_idx = 2;
dest_uv_idx = 1;
src_uv_idx = (src_x % 4) + 2;
} else if (dest_x % 4 == 3) {
y1 = srcY[0];
u1 = srcU[0];
v1 = srcV[0];
destY[0] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
destU[0] = CLAMP (
(3 * destU[0] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 4, 0, 255);
destV[0] = CLAMP (
(3 * destV[0] + APPLY_MATRIX (matrix, 2, y1, u1, v1)) / 4, 0, 255);
j = dest_x + 1;
src_y_idx = dest_y_idx = 1;
dest_uv_idx = 1;
src_uv_idx = (src_x % 4) + 1;
} else {
j = dest_x;
src_y_idx = dest_y_idx = dest_uv_idx = 0;
src_uv_idx = (src_x % 4);
}
/* 1.2. Copy all macro pixels from the source to the destination.
* All pixels now start at macro pixel boundary, i.e. no
* blending with the background is necessary. */
for (; j < w - 3; j += 4) {
y1 = srcY[src_y_idx];
y2 = srcY[src_y_idx + 1];
y3 = srcY[src_y_idx + 2];
y4 = srcY[src_y_idx + 3];
u1 = srcU[src_uv_idx / 4];
v1 = srcV[src_uv_idx / 4];
src_uv_idx++;
u2 = srcU[src_uv_idx / 4];
v2 = srcV[src_uv_idx / 4];
src_uv_idx++;
u3 = srcU[src_uv_idx / 4];
v3 = srcV[src_uv_idx / 4];
src_uv_idx++;
u4 = srcU[src_uv_idx / 4];
v4 = srcV[src_uv_idx / 4];
src_uv_idx++;
destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
destY[dest_y_idx + 1] =
CLAMP (APPLY_MATRIX (matrix, 0, y2, u2, v2), 0, 255);
destY[dest_y_idx + 2] =
CLAMP (APPLY_MATRIX (matrix, 0, y3, u3, v3), 0, 255);
destY[dest_y_idx + 3] =
CLAMP (APPLY_MATRIX (matrix, 0, y4, u4, v4), 0, 255);
destU[dest_uv_idx] = CLAMP (
(APPLY_MATRIX (matrix, 1, y1, u1, v1) + APPLY_MATRIX (matrix, 1, y2,
u2, v2) + APPLY_MATRIX (matrix, 1, y3, u3,
v3) + APPLY_MATRIX (matrix, 1, y4, u4, v4)) / 4, 0, 255);
destV[dest_uv_idx] =
CLAMP ((APPLY_MATRIX (matrix, 2, y1, u1, v1) + APPLY_MATRIX (matrix,
2, y2, u2, v2) + APPLY_MATRIX (matrix, 2, y3, u3,
v3) + APPLY_MATRIX (matrix, 2, y4, u4, v4)) / 4, 0, 255);
dest_y_idx += 4;
src_y_idx += 4;
dest_uv_idx++;
}
/* 1.3. Now copy the last pixel if one exists and blend it
* with the background because we only fill part of
* the macro pixel. In case this is the last pixel of
* the destination we will a larger part. */
if (j == w - 1 && j == dest_width - 1) {
y1 = srcY[src_y_idx];
u1 = srcU[src_uv_idx / 4];
v1 = srcV[src_uv_idx / 4];
destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
destU[dest_uv_idx] = CLAMP (APPLY_MATRIX (matrix, 1, y1, u1, v1), 0, 255);
destV[dest_uv_idx] = CLAMP (APPLY_MATRIX (matrix, 1, y1, u1, v1), 0, 255);
} else if (j == w - 1) {
y1 = srcY[src_y_idx];
u1 = srcU[src_uv_idx / 4];
v1 = srcV[src_uv_idx / 4];
destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
destU[dest_uv_idx] = CLAMP (
(destU[dest_uv_idx] + 3 * APPLY_MATRIX (matrix, 1, y1, u1,
v1)) / 4, 0, 255);
destV[dest_uv_idx] = CLAMP (
(destV[dest_uv_idx] + 3 * APPLY_MATRIX (matrix, 1, y1, u1,
v1)) / 4, 0, 255);
} else if (j == w - 2 && j == dest_width - 2) {
y1 = srcY[src_y_idx];
y2 = srcY[src_y_idx + 1];
u1 = srcU[src_uv_idx / 4];
v1 = srcV[src_uv_idx / 4];
destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
destY[dest_y_idx + 1] =
CLAMP (APPLY_MATRIX (matrix, 0, y2, u1, v1), 0, 255);
destU[dest_uv_idx] = CLAMP (APPLY_MATRIX (matrix, 1, y1, u1, v1), 0, 255);
destV[dest_uv_idx] = CLAMP (APPLY_MATRIX (matrix, 1, y1, u1, v1), 0, 255);
} else if (j == w - 2) {
y1 = srcY[src_y_idx];
y2 = srcY[src_y_idx + 1];
u1 = srcU[src_uv_idx / 4];
v1 = srcV[src_uv_idx / 4];
destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
destY[dest_y_idx + 1] =
CLAMP (APPLY_MATRIX (matrix, 0, y2, u1, v1), 0, 255);
destU[dest_uv_idx] =
CLAMP ((destU[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
v1)) / 2, 0, 255);
destV[dest_uv_idx] =
CLAMP ((destV[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
v1)) / 2, 0, 255);
} else if (j == w - 3 && j == dest_width - 3) {
y1 = srcY[src_y_idx];
y2 = srcY[src_y_idx + 1];
y3 = srcY[src_y_idx + 2];
u1 = srcU[src_uv_idx / 4];
v1 = srcV[src_uv_idx / 4];
destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
destY[dest_y_idx + 1] =
CLAMP (APPLY_MATRIX (matrix, 0, y2, u1, v1), 0, 255);
destY[dest_y_idx + 2] =
CLAMP (APPLY_MATRIX (matrix, 0, y3, u1, v1), 0, 255);
destU[dest_uv_idx] = CLAMP (APPLY_MATRIX (matrix, 1, y1, u1, v1), 0, 255);
destV[dest_uv_idx] = CLAMP (APPLY_MATRIX (matrix, 1, y1, u1, v1), 0, 255);
} else if (j == w - 3) {
y1 = srcY[src_y_idx];
y2 = srcY[src_y_idx + 1];
y3 = srcY[src_y_idx + 2];
u1 = srcU[src_uv_idx / 4];
v1 = srcV[src_uv_idx / 4];
destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
destY[dest_y_idx + 1] =
CLAMP (APPLY_MATRIX (matrix, 0, y2, u1, v1), 0, 255);
destY[dest_y_idx + 2] =
CLAMP (APPLY_MATRIX (matrix, 0, y3, u1, v1), 0, 255);
destU[dest_uv_idx] =
CLAMP ((3 * destU[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
v1)) / 4, 0, 255);
destV[dest_uv_idx] =
CLAMP ((3 * destV[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
v1)) / 4, 0, 255);
}
destY += dest_strideY;
destU += dest_strideU;
destV += dest_strideV;
srcY += src_strideY;
srcU += src_strideU;
srcV += src_strideV;
}
}
static void
copy_i420_i420 (guint i_alpha, GstVideoFrame * dest,
gboolean dest_sdtv, gint dest_x, gint dest_y, GstVideoFrame * src,
gboolean src_sdtv, gint src_x, gint src_y, gint w, gint h)
{
gint i, j;
guint8 *destY, *destU, *destV;
const guint8 *srcY, *srcU, *srcV;
guint8 *destY2;
const guint8 *srcY2, *srcU2, *srcV2;
gint dest_strideY, dest_strideU, dest_strideV;
gint src_strideY, src_strideU, src_strideV;
gint src_y_idx, src_uv_idx;
gint dest_y_idx, dest_uv_idx;
gint matrix[12];
gint y1, y2, y3, y4;
gint u1, u2, u3, u4;
gint v1, v2, v3, v4;
gint dest_width, dest_height;
dest_width = GST_VIDEO_FRAME_WIDTH (dest);
dest_height = GST_VIDEO_FRAME_HEIGHT (dest);
dest_strideY = GST_VIDEO_FRAME_COMP_STRIDE (dest, 0);
dest_strideU = GST_VIDEO_FRAME_COMP_STRIDE (dest, 1);
dest_strideV = GST_VIDEO_FRAME_COMP_STRIDE (dest, 2);
src_strideY = GST_VIDEO_FRAME_COMP_STRIDE (src, 0);
src_strideU = GST_VIDEO_FRAME_COMP_STRIDE (src, 1);
src_strideV = GST_VIDEO_FRAME_COMP_STRIDE (src, 2);
destY = GST_VIDEO_FRAME_COMP_DATA (dest, 0);
destU = GST_VIDEO_FRAME_COMP_DATA (dest, 1);
destV = GST_VIDEO_FRAME_COMP_DATA (dest, 2);
srcY = GST_VIDEO_FRAME_COMP_DATA (src, 0);
srcU = GST_VIDEO_FRAME_COMP_DATA (src, 1);
srcV = GST_VIDEO_FRAME_COMP_DATA (src, 2);
destY = destY + dest_y * dest_strideY + dest_x;
destU = destU + (dest_y / 2) * dest_strideU + dest_x / 2;
destV = destV + (dest_y / 2) * dest_strideV + dest_x / 2;
srcY = srcY + src_y * src_strideY + src_x;
srcU = srcU + (src_y / 2) * src_strideU + src_x / 2;
srcV = srcV + (src_y / 2) * src_strideV + src_x / 2;
destY2 = destY + dest_strideY;
srcY2 = srcY + src_strideY;
h = dest_y + h;
w = dest_x + w;
if (src_sdtv != dest_sdtv)
memcpy (matrix,
dest_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit, 12 * sizeof (gint));
else
memcpy (matrix, cog_identity_matrix_8bit, 12 * sizeof (gint));
/* 1. Handle the first destination scanline specially if it
* doesn't start at the macro pixel boundary, i.e. blend
* with the background! */
if (dest_y % 2 == 1) {
/* 1.1. Handle the first destination pixel if it doesn't
* start at the macro pixel boundary, i.e. blend with
* the background! */
if (dest_x % 2 == 1) {
y1 = srcY[0];
u1 = srcU[0];
v1 = srcV[0];
destY[0] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
destU[0] =
CLAMP ((3 * destU[0] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 4, 0,
255);
destV[0] =
CLAMP ((3 * destV[0] + APPLY_MATRIX (matrix, 2, y1, u1, v1)) / 4, 0,
255);
j = dest_x + 1;
src_y_idx = dest_y_idx = dest_uv_idx = 1;
src_uv_idx = (src_x % 2) + 1;
} else {
j = dest_x;
src_y_idx = dest_y_idx = dest_uv_idx = 0;
src_uv_idx = (src_x % 2);
}
/* 1.2. Copy all macro pixels from the source to the destination
* but blend with the background because we're only filling
* the lower part of the macro pixels. */
for (; j < w - 1; j += 2) {
y1 = srcY[src_y_idx];
y2 = srcY[src_y_idx + 1];
u1 = srcU[src_uv_idx / 2];
v1 = srcV[src_uv_idx / 2];
src_uv_idx++;
u2 = srcU[src_uv_idx / 2];
v2 = srcV[src_uv_idx / 2];
src_uv_idx++;
destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
destY[dest_y_idx + 1] =
CLAMP (APPLY_MATRIX (matrix, 0, y2, u2, v2), 0, 255);
destU[dest_uv_idx] =
CLAMP ((2 * destU[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
v1) + APPLY_MATRIX (matrix, 1, y2, u2, v2)) / 4, 0, 255);
destV[dest_uv_idx] =
CLAMP ((2 * destV[dest_uv_idx] + APPLY_MATRIX (matrix, 2, y1, u1,
v1) + APPLY_MATRIX (matrix, 2, y2, u2, v2)) / 4, 0, 255);
dest_y_idx += 2;
src_y_idx += 2;
dest_uv_idx++;
}
/* 1.3. Now copy the last pixel if one exists and blend it
* with the background because we only fill part of
* the macro pixel. In case this is the last pixel of
* the destination we will a larger part. */
if (j == w - 1 && j == dest_width - 1) {
y1 = srcY[src_y_idx];
u1 = srcU[src_uv_idx / 2];
v1 = srcV[src_uv_idx / 2];
destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
destU[dest_uv_idx] = CLAMP (
(destU[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 2, 0,
255);
destV[dest_uv_idx] =
CLAMP ((destV[dest_uv_idx] + APPLY_MATRIX (matrix, 2, y1, u1,
v1)) / 2, 0, 255);
} else if (j == w - 1) {
y1 = srcY[src_y_idx];
u1 = srcU[src_uv_idx / 2];
v1 = srcV[src_uv_idx / 2];
destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
destU[dest_uv_idx] = CLAMP (
(3 * destU[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 4,
0, 255);
destV[dest_uv_idx] =
CLAMP ((3 * destV[dest_uv_idx] + APPLY_MATRIX (matrix, 2, y1, u1,
v1)) / 4, 0, 255);
}
destY += dest_strideY;
destY2 += dest_strideY;
destU += dest_strideU;
destV += dest_strideV;
srcY += src_strideY;
srcY2 += src_strideY;
src_y++;
if (src_y % 2 == 0) {
srcU += src_strideU;
srcV += src_strideV;
}
i = dest_y + 1;
} else {
i = dest_y;
}
/* 2. Copy all macro pixel scanlines, the destination scanline
* now starts at macro pixel boundary. */
for (; i < h - 1; i += 2) {
/* 2.1. Handle the first destination pixel if it doesn't
* start at the macro pixel boundary, i.e. blend with
* the background! */
srcU2 = srcU;
srcV2 = srcV;
if (src_y % 2 == 1) {
srcU2 += src_strideU;
srcV2 += src_strideV;
}
if (dest_x % 2 == 1) {
y1 = srcY[0];
y2 = srcY2[0];
u1 = srcU[0];
v1 = srcV[0];
u2 = srcU2[0];
v2 = srcV2[0];
destY[0] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
destY2[0] = CLAMP (APPLY_MATRIX (matrix, 0, y2, u2, v2), 0, 255);
destU[0] = CLAMP (
(2 * destU[0] + APPLY_MATRIX (matrix, 1, y1, u1,
v1) + APPLY_MATRIX (matrix, 1, y2, u2, v2)) / 4, 0, 255);
destV[0] = CLAMP (
(2 * destV[0] + APPLY_MATRIX (matrix, 2, y1, u1,
v1) + APPLY_MATRIX (matrix, 2, y2, u2, v2)) / 4, 0, 255);
j = dest_x + 1;
src_y_idx = dest_y_idx = dest_uv_idx = 1;
src_uv_idx = (src_x % 2) + 1;
} else {
j = dest_x;
src_y_idx = dest_y_idx = dest_uv_idx = 0;
src_uv_idx = (src_x % 2);
}
/* 2.2. Copy all macro pixels from the source to the destination.
* All pixels now start at macro pixel boundary, i.e. no
* blending with the background is necessary. */
for (; j < w - 1; j += 2) {
y1 = srcY[src_y_idx];
y2 = srcY[src_y_idx + 1];
y3 = srcY2[src_y_idx];
y4 = srcY2[src_y_idx + 1];
u1 = srcU[src_uv_idx / 2];
u3 = srcU2[src_uv_idx / 2];
v1 = srcV[src_uv_idx / 2];
v3 = srcV2[src_uv_idx / 2];
src_uv_idx++;
u2 = srcU[src_uv_idx / 2];
u4 = srcU2[src_uv_idx / 2];
v2 = srcV[src_uv_idx / 2];
v4 = srcV2[src_uv_idx / 2];
src_uv_idx++;
destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
destY[dest_y_idx + 1] =
CLAMP (APPLY_MATRIX (matrix, 0, y2, u2, v2), 0, 255);
destY2[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y3, u3, v3), 0, 255);
destY2[dest_y_idx + 1] =
CLAMP (APPLY_MATRIX (matrix, 0, y4, u4, v4), 0, 255);
destU[dest_uv_idx] = CLAMP (
(APPLY_MATRIX (matrix, 1, y1, u1, v1) + APPLY_MATRIX (matrix, 1, y2,
u2, v2) + APPLY_MATRIX (matrix, 1, y3, u3,
v3) + APPLY_MATRIX (matrix, 1, y4, u4, v4)) / 4, 0, 255);
destV[dest_uv_idx] = CLAMP (
(APPLY_MATRIX (matrix, 2, y1, u1, v1) + APPLY_MATRIX (matrix, 2, y2,
u2, v2) + APPLY_MATRIX (matrix, 2, y3, u3,
v3) + APPLY_MATRIX (matrix, 2, y4, u4, v4)) / 4, 0, 255);
dest_y_idx += 2;
src_y_idx += 2;
dest_uv_idx++;
}
/* 2.3. Now copy the last pixel if one exists and blend it
* with the background because we only fill part of
* the macro pixel. In case this is the last pixel of
* the destination we will a larger part. */
if (j == w - 1 && j == dest_width - 1) {
y1 = srcY[src_y_idx];
y2 = srcY2[src_y_idx];
u1 = srcU[src_uv_idx / 2];
u2 = srcU2[src_uv_idx / 2];
v1 = srcV[src_uv_idx / 2];
v2 = srcV2[src_uv_idx / 2];
destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
destY2[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y2, u2, v2), 0, 255);
destU[dest_uv_idx] = CLAMP (
(APPLY_MATRIX (matrix, 1, y1, u1, v1) + APPLY_MATRIX (matrix, 2, y2,
u2, v2)) / 2, 0, 255);
destV[dest_uv_idx] = CLAMP (
(APPLY_MATRIX (matrix, 1, y1, u1, v1) + APPLY_MATRIX (matrix, 2, y2,
u2, v2)) / 2, 0, 255);
} else if (j == w - 1) {
y1 = srcY[src_y_idx];
y2 = srcY2[src_y_idx];
u1 = srcU[src_uv_idx / 2];
u2 = srcU2[src_uv_idx / 2];
v1 = srcV[src_uv_idx / 2];
v2 = srcV2[src_uv_idx / 2];
destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
destY2[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y2, u2, v2), 0, 255);
destU[dest_uv_idx] = CLAMP (
(2 * destU[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
v1) + APPLY_MATRIX (matrix, 2, y2, u2, v2)) / 4, 0, 255);
destV[dest_uv_idx] = CLAMP (
(2 * destV[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
v1) + APPLY_MATRIX (matrix, 2, y2, u2, v2)) / 4, 0, 255);
}
destY += 2 * dest_strideY;
destY2 += 2 * dest_strideY;
destU += dest_strideU;
destV += dest_strideV;
srcY += 2 * src_strideY;
srcY2 += 2 * src_strideY;
src_y += 2;
srcU += src_strideU;
srcV += src_strideV;
}
/* 3. Handle the last scanline if one exists. This again
* doesn't start at macro pixel boundary but should
* only fill the upper part of the macro pixels. */
if (i == h - 1 && i == dest_height - 1) {
/* 3.1. Handle the first destination pixel if it doesn't
* start at the macro pixel boundary, i.e. blend with
* the background! */
if (dest_x % 2 == 1) {
y1 = srcY[0];
u1 = srcU[0];
v1 = srcV[0];
destY[0] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
destU[0] =
CLAMP ((destU[0] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 2, 0, 255);
destV[0] =
CLAMP ((destV[0] + APPLY_MATRIX (matrix, 2, y1, u1, v1)) / 2, 0, 255);
j = dest_x + 1;
src_y_idx = dest_y_idx = dest_uv_idx = 1;
src_uv_idx = (src_x % 2) + 1;
} else {
j = dest_x;
src_y_idx = dest_y_idx = dest_uv_idx = 0;
src_uv_idx = (src_x % 2);
}
/* 3.2. Copy all macro pixels from the source to the destination
* but blend with the background because we're only filling
* the upper part of the macro pixels. */
for (; j < w - 1; j += 2) {
y1 = srcY[src_y_idx];
y2 = srcY[src_y_idx + 1];
u1 = srcU[src_uv_idx / 2];
v1 = srcV[src_uv_idx / 2];
src_uv_idx++;
u2 = srcU[src_uv_idx / 2];
v2 = srcV[src_uv_idx / 2];
src_uv_idx++;
destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
destY[dest_y_idx + 1] =
CLAMP (APPLY_MATRIX (matrix, 0, y2, u2, v2), 0, 255);
destU[dest_uv_idx] = CLAMP (
(2 * destU[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
v1) + APPLY_MATRIX (matrix, 1, y2, u2, v2)) / 4, 0, 255);
destV[dest_uv_idx] = CLAMP (
(2 * destV[dest_uv_idx] + APPLY_MATRIX (matrix, 2, y1, u1,
v1) + APPLY_MATRIX (matrix, 2, y2, u2, v2)) / 4, 0, 255);
dest_y_idx += 2;
src_y_idx += 2;
dest_uv_idx++;
}
/* 3.3. Now copy the last pixel if one exists and blend it
* with the background because we only fill part of
* the macro pixel. In case this is the last pixel of
* the destination we will a larger part. */
if (j == w - 1 && j == dest_width - 1) {
y1 = srcY[src_y_idx];
u1 = srcU[src_uv_idx / 2];
v1 = srcV[src_uv_idx / 2];
destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
destU[dest_uv_idx] = CLAMP (
(destU[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 2, 0,
255);
destV[dest_uv_idx] =
CLAMP ((destV[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
v1)) / 2, 0, 255);
} else if (j == w - 1) {
y1 = srcY[src_y_idx];
u1 = srcU[src_uv_idx / 2];
v1 = srcV[src_uv_idx / 2];
destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
destU[dest_uv_idx] = CLAMP (
(3 * destU[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 4,
0, 255);
destV[dest_uv_idx] =
CLAMP ((3 * destV[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
v1)) / 4, 0, 255);
}
} else if (i == h - 1) {
/* 3.1. Handle the first destination pixel if it doesn't
* start at the macro pixel boundary, i.e. blend with
* the background! */
if (dest_x % 2 == 1) {
y1 = srcY[0];
u1 = srcU[0];
v1 = srcV[0];
destY[0] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
destU[0] =
CLAMP ((3 * destU[0] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 4, 0,
255);
destV[0] =
CLAMP ((3 * destV[0] + APPLY_MATRIX (matrix, 2, y1, u1, v1)) / 4, 0,
255);
j = dest_x + 1;
src_y_idx = dest_y_idx = dest_uv_idx = 1;
src_uv_idx = (src_x % 2) + 1;
} else {
j = dest_x;
src_y_idx = dest_y_idx = dest_uv_idx = 0;
src_uv_idx = (src_x % 2);
}
/* 3.2. Copy all macro pixels from the source to the destination
* but blend with the background because we're only filling
* the upper part of the macro pixels. */
for (; j < w - 1; j += 2) {
y1 = srcY[src_y_idx];
y2 = srcY[src_y_idx + 1];
u1 = srcU[src_uv_idx / 2];
v1 = srcV[src_uv_idx / 2];
src_uv_idx++;
u2 = srcU[src_uv_idx / 2];
v2 = srcV[src_uv_idx / 2];
src_uv_idx++;
destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
destY[dest_y_idx + 1] =
CLAMP (APPLY_MATRIX (matrix, 0, y2, u2, v2), 0, 255);
destU[dest_uv_idx] = CLAMP (
(2 * destU[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
v1) + APPLY_MATRIX (matrix, 1, y2, u2, v2)) / 4, 0, 255);
destV[dest_uv_idx] = CLAMP (
(2 * destV[dest_uv_idx] + APPLY_MATRIX (matrix, 2, y1, u1,
v1) + APPLY_MATRIX (matrix, 2, y2, u2, v2)) / 4, 0, 255);
dest_y_idx += 2;
src_y_idx += 2;
dest_uv_idx++;
}
/* 3.3. Now copy the last pixel if one exists and blend it
* with the background because we only fill part of
* the macro pixel. In case this is the last pixel of
* the destination we will a larger part. */
if (j == w - 1 && j == dest_width - 1) {
y1 = srcY[src_y_idx];
u1 = srcU[src_uv_idx / 2];
v1 = srcV[src_uv_idx / 2];
destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
destU[dest_uv_idx] = CLAMP (
(destU[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 2, 0,
255);
destV[dest_uv_idx] =
CLAMP ((destV[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
v1)) / 2, 0, 255);
} else if (j == w - 1) {
y1 = srcY[src_y_idx];
u1 = srcU[src_uv_idx / 2];
v1 = srcV[src_uv_idx / 2];
destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
destU[dest_uv_idx] = CLAMP (
(3 * destU[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 4,
0, 255);
destV[dest_uv_idx] =
CLAMP ((3 * destV[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
v1)) / 4, 0, 255);
}
}
}
static void
copy_i420_ayuv (guint i_alpha, GstVideoFrame * dest_frame,
gboolean dest_sdtv, gint dest_x, gint dest_y, GstVideoFrame * src_frame,
gboolean src_sdtv, gint src_x, gint src_y, gint w, gint h)
{
const guint8 *srcY, *srcU, *srcV;
gint src_strideY, src_strideU, src_strideV;
gint dest_stride;
guint8 *dest;
src_strideY = GST_VIDEO_FRAME_COMP_STRIDE (src_frame, 0);
src_strideU = GST_VIDEO_FRAME_COMP_STRIDE (src_frame, 1);
src_strideV = GST_VIDEO_FRAME_COMP_STRIDE (src_frame, 2);
srcY = GST_VIDEO_FRAME_COMP_DATA (src_frame, 0);
srcU = GST_VIDEO_FRAME_COMP_DATA (src_frame, 1);
srcV = GST_VIDEO_FRAME_COMP_DATA (src_frame, 2);
dest_stride = GST_VIDEO_FRAME_PLANE_STRIDE (dest_frame, 0);
dest = GST_VIDEO_FRAME_PLANE_DATA (dest_frame, 0);
dest = dest + dest_y * dest_stride + dest_x * 4;
srcY = srcY + src_y * src_strideY + src_x;
srcU = srcU + (src_y / 2) * src_strideU + src_x / 2;
srcV = srcV + (src_y / 2) * src_strideV + src_x / 2;
i_alpha = CLAMP (i_alpha, 0, 255);
if (src_sdtv != dest_sdtv) {
gint i, j, uv_idx;
gint y, u, v;
gint y1, u1, v1;
gint matrix[12];
memcpy (matrix,
dest_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit, 12 * sizeof (gint));
for (i = 0; i < h; i++) {
for (j = 0, uv_idx = src_x % 2; j < w; j++, uv_idx++) {
y = srcY[j];
u = srcU[uv_idx / 2];
v = srcV[uv_idx / 2];
y1 = APPLY_MATRIX (matrix, 0, y, u, v);
u1 = APPLY_MATRIX (matrix, 1, y, u, v);
v1 = APPLY_MATRIX (matrix, 2, y, u, v);
dest[4 * j + 0] = i_alpha;
dest[4 * j + 1] = y1;
dest[4 * j + 2] = u1;
dest[4 * j + 3] = v1;
}
dest += dest_stride;
src_y++;
srcY += src_strideY;
if (src_y % 2 == 0) {
srcU += src_strideU;
srcV += src_strideV;
}
}
} else {
gint i, j, uv_idx;
gint y, u, v;
for (i = 0; i < h; i++) {
for (j = 0, uv_idx = src_x % 2; j < w; j++, uv_idx++) {
y = srcY[j];
u = srcU[uv_idx / 2];
v = srcV[uv_idx / 2];
dest[4 * j + 0] = i_alpha;
dest[4 * j + 1] = y;
dest[4 * j + 2] = u;
dest[4 * j + 3] = v;
}
dest += dest_stride;
src_y++;
srcY += src_strideY;
if (src_y % 2 == 0) {
srcU += src_strideU;
srcV += src_strideV;
}
}
}
}
static void
fill_rgb32 (GstVideoBoxFill fill_type, guint b_alpha,
GstVideoFrame * frame, gboolean sdtv)
{
guint32 empty_pixel;
gint p[4];
guint8 *dest;
guint stride;
gint width, height;
width = GST_VIDEO_FRAME_WIDTH (frame);
height = GST_VIDEO_FRAME_HEIGHT (frame);
dest = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
stride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0);
p[0] = GST_VIDEO_FRAME_COMP_OFFSET (frame, 3);
p[1] = GST_VIDEO_FRAME_COMP_OFFSET (frame, 0);
p[2] = GST_VIDEO_FRAME_COMP_OFFSET (frame, 1);
p[3] = GST_VIDEO_FRAME_COMP_OFFSET (frame, 2);
b_alpha = CLAMP (b_alpha, 0, 255);
if (GST_VIDEO_FRAME_N_COMPONENTS (frame) == 4) {
empty_pixel = GUINT32_FROM_LE ((b_alpha << (p[0] * 8)) |
(rgb_colors_R[fill_type] << (p[1] * 8)) |
(rgb_colors_G[fill_type] << (p[2] * 8)) |
(rgb_colors_B[fill_type] << (p[3] * 8)));
} else {
empty_pixel = GUINT32_FROM_LE (
(rgb_colors_R[fill_type] << (p[1] * 8)) |
(rgb_colors_G[fill_type] << (p[2] * 8)) |
(rgb_colors_B[fill_type] << (p[3] * 8)));
}
if (stride == width * 4) {
video_box_orc_splat_u32 ((guint32 *) dest, empty_pixel, width * height);
} else if (height) {
for (; height; --height) {
video_box_orc_splat_u32 ((guint32 *) dest, empty_pixel, width);
dest += stride;
}
}
}
static void
fill_rgb24 (GstVideoBoxFill fill_type, guint b_alpha,
GstVideoFrame * frame, gboolean sdtv)
{
gint dest_stride;
gint p[4];
gint i, j;
guint8 *dest;
gint width, height;
width = GST_VIDEO_FRAME_WIDTH (frame);
height = GST_VIDEO_FRAME_HEIGHT (frame);
dest = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
dest_stride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0);
p[1] = GST_VIDEO_FRAME_COMP_OFFSET (frame, 0);
p[2] = GST_VIDEO_FRAME_COMP_OFFSET (frame, 1);
p[3] = GST_VIDEO_FRAME_COMP_OFFSET (frame, 2);
for (i = 0; i < height; i++) {
for (j = 0; j < width; j++) {
dest[3 * j + p[1]] = rgb_colors_R[fill_type];
dest[3 * j + p[2]] = rgb_colors_G[fill_type];
dest[3 * j + p[3]] = rgb_colors_B[fill_type];
}
dest += dest_stride;
}
}
static void
copy_rgb32 (guint i_alpha, GstVideoFrame * dest_frame,
gboolean dest_sdtv, gint dest_x, gint dest_y, GstVideoFrame * src_frame,
gboolean src_sdtv, gint src_x, gint src_y, gint w, gint h)
{
gint i, j;
gint src_stride, dest_stride;
gboolean in_alpha, out_alpha;
gint in_bpp, out_bpp;
gint p_out[4];
gint p_in[4];
gboolean packed_out;
gboolean packed_in;
guint8 *src, *dest;
src_stride = GST_VIDEO_FRAME_PLANE_STRIDE (src_frame, 0);
dest_stride = GST_VIDEO_FRAME_PLANE_STRIDE (dest_frame, 0);
in_bpp = GST_VIDEO_FRAME_COMP_PSTRIDE (src_frame, 0);
out_bpp = GST_VIDEO_FRAME_COMP_PSTRIDE (dest_frame, 0);
packed_in = (in_bpp < 4);
packed_out = (out_bpp < 4);
out_alpha = GST_VIDEO_INFO_HAS_ALPHA (&dest_frame->info);
p_out[0] = GST_VIDEO_FRAME_COMP_OFFSET (dest_frame, 3);
p_out[1] = GST_VIDEO_FRAME_COMP_OFFSET (dest_frame, 0);
p_out[2] = GST_VIDEO_FRAME_COMP_OFFSET (dest_frame, 1);
p_out[3] = GST_VIDEO_FRAME_COMP_OFFSET (dest_frame, 2);
in_alpha = GST_VIDEO_INFO_HAS_ALPHA (&src_frame->info);
p_in[0] = GST_VIDEO_FRAME_COMP_OFFSET (src_frame, 3);
p_in[1] = GST_VIDEO_FRAME_COMP_OFFSET (src_frame, 0);
p_in[2] = GST_VIDEO_FRAME_COMP_OFFSET (src_frame, 1);
p_in[3] = GST_VIDEO_FRAME_COMP_OFFSET (src_frame, 2);
dest = GST_VIDEO_FRAME_PLANE_DATA (dest_frame, 0);
dest = dest + dest_y * dest_stride + dest_x * out_bpp;
src = GST_VIDEO_FRAME_PLANE_DATA (src_frame, 0);
src = src + src_y * src_stride + src_x * in_bpp;
if (in_alpha && out_alpha) {
w *= 4;
for (i = 0; i < h; i++) {
for (j = 0; j < w; j += 4) {
dest[j + p_out[0]] = (src[j + p_in[0]] * i_alpha) >> 8;
dest[j + p_out[1]] = src[j + p_in[1]];
dest[j + p_out[2]] = src[j + p_in[2]];
dest[j + p_out[3]] = src[j + p_in[3]];
}
dest += dest_stride;
src += src_stride;
}
} else if (out_alpha && !packed_in) {
w *= 4;
i_alpha = CLAMP (i_alpha, 0, 255);
for (i = 0; i < h; i++) {
for (j = 0; j < w; j += 4) {
dest[j + p_out[0]] = i_alpha;
dest[j + p_out[1]] = src[j + p_in[1]];
dest[j + p_out[2]] = src[j + p_in[2]];
dest[j + p_out[3]] = src[j + p_in[3]];
}
dest += dest_stride;
src += src_stride;
}
} else if (out_alpha && packed_in) {
i_alpha = CLAMP (i_alpha, 0, 255);
for (i = 0; i < h; i++) {
for (j = 0; j < w; j++) {
dest[4 * j + p_out[0]] = i_alpha;
dest[4 * j + p_out[1]] = src[in_bpp * j + p_in[1]];
dest[4 * j + p_out[2]] = src[in_bpp * j + p_in[2]];
dest[4 * j + p_out[3]] = src[in_bpp * j + p_in[3]];
}
dest += dest_stride;
src += src_stride;
}
} else if (!packed_out && !packed_in) {
w *= 4;
for (i = 0; i < h; i++) {
for (j = 0; j < w; j += 4) {
dest[j + p_out[1]] = src[j + p_in[1]];
dest[j + p_out[2]] = src[j + p_in[2]];
dest[j + p_out[3]] = src[j + p_in[3]];
}
dest += dest_stride;
src += src_stride;
}
} else {
for (i = 0; i < h; i++) {
for (j = 0; j < w; j++) {
dest[out_bpp * j + p_out[1]] = src[in_bpp * j + p_in[1]];
dest[out_bpp * j + p_out[2]] = src[in_bpp * j + p_in[2]];
dest[out_bpp * j + p_out[3]] = src[in_bpp * j + p_in[3]];
}
dest += dest_stride;
src += src_stride;
}
}
}
static void
copy_rgb32_ayuv (guint i_alpha, GstVideoFrame * dest_frame,
gboolean dest_sdtv, gint dest_x, gint dest_y, GstVideoFrame * src_frame,
gboolean src_sdtv, gint src_x, gint src_y, gint w, gint h)
{
gint i, j;
gint src_stride, dest_stride;
gboolean in_alpha;
gint in_bpp;
gint p_in[4];
gboolean packed_in;
gint matrix[12];
gint a;
gint y, u, v;
gint r, g, b;
guint8 *dest, *src;
dest_stride = GST_VIDEO_FRAME_PLANE_STRIDE (dest_frame, 0);
src_stride = GST_VIDEO_FRAME_PLANE_STRIDE (src_frame, 0);
in_bpp = GST_VIDEO_FRAME_COMP_PSTRIDE (src_frame, 0);
packed_in = (in_bpp < 4);
in_alpha = GST_VIDEO_INFO_HAS_ALPHA (&src_frame->info);
p_in[0] = GST_VIDEO_FRAME_COMP_OFFSET (src_frame, 3);
p_in[1] = GST_VIDEO_FRAME_COMP_OFFSET (src_frame, 0);
p_in[2] = GST_VIDEO_FRAME_COMP_OFFSET (src_frame, 1);
p_in[3] = GST_VIDEO_FRAME_COMP_OFFSET (src_frame, 2);
memcpy (matrix,
(dest_sdtv) ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
cog_rgb_to_ycbcr_matrix_8bit_hdtv, 12 * sizeof (gint));
dest = GST_VIDEO_FRAME_PLANE_DATA (dest_frame, 0);
dest = dest + dest_y * dest_stride + dest_x * 4;
src = GST_VIDEO_FRAME_PLANE_DATA (src_frame, 0);
src = src + src_y * src_stride + src_x * in_bpp;
if (in_alpha) {
w *= 4;
for (i = 0; i < h; i++) {
for (j = 0; j < w; j += 4) {
a = (src[j + p_in[0]] * i_alpha) >> 8;
r = src[j + p_in[1]];
g = src[j + p_in[2]];
b = src[j + p_in[3]];
y = APPLY_MATRIX (matrix, 0, r, g, b);
u = APPLY_MATRIX (matrix, 1, r, g, b);
v = APPLY_MATRIX (matrix, 2, r, g, b);
dest[j + 0] = a;
dest[j + 1] = CLAMP (y, 0, 255);
dest[j + 2] = CLAMP (u, 0, 255);
dest[j + 3] = CLAMP (v, 0, 255);
}
dest += dest_stride;
src += src_stride;
}
} else if (!packed_in) {
w *= 4;
i_alpha = CLAMP (i_alpha, 0, 255);
for (i = 0; i < h; i++) {
for (j = 0; j < w; j += 4) {
a = i_alpha;
r = src[j + p_in[1]];
g = src[j + p_in[2]];
b = src[j + p_in[3]];
y = APPLY_MATRIX (matrix, 0, r, g, b);
u = APPLY_MATRIX (matrix, 1, r, g, b);
v = APPLY_MATRIX (matrix, 2, r, g, b);
dest[j + 0] = a;
dest[j + 1] = CLAMP (y, 0, 255);
dest[j + 2] = CLAMP (u, 0, 255);
dest[j + 3] = CLAMP (v, 0, 255);
}
dest += dest_stride;
src += src_stride;
}
} else {
i_alpha = CLAMP (i_alpha, 0, 255);
for (i = 0; i < h; i++) {
for (j = 0; j < w; j++) {
a = i_alpha;
r = src[in_bpp * j + p_in[1]];
g = src[in_bpp * j + p_in[2]];
b = src[in_bpp * j + p_in[3]];
y = APPLY_MATRIX (matrix, 0, r, g, b);
u = APPLY_MATRIX (matrix, 1, r, g, b);
v = APPLY_MATRIX (matrix, 2, r, g, b);
dest[4 * j + 0] = a;
dest[4 * j + 1] = CLAMP (y, 0, 255);
dest[4 * j + 2] = CLAMP (u, 0, 255);
dest[4 * j + 3] = CLAMP (v, 0, 255);
}
dest += dest_stride;
src += src_stride;
}
}
}
static void
copy_ayuv_rgb32 (guint i_alpha, GstVideoFrame * dest_frame,
gboolean dest_sdtv, gint dest_x, gint dest_y, GstVideoFrame * src_frame,
gboolean src_sdtv, gint src_x, gint src_y, gint w, gint h)
{
gint i, j;
gint src_stride, dest_stride;
gboolean out_alpha;
gint out_bpp;
gint p_out[4];
gboolean packed_out;
gint matrix[12];
gint a;
gint y, u, v;
gint r, g, b;
guint8 *src, *dest;
src_stride = GST_VIDEO_FRAME_PLANE_STRIDE (src_frame, 0);
dest_stride = GST_VIDEO_FRAME_PLANE_STRIDE (dest_frame, 0);
out_bpp = GST_VIDEO_FRAME_COMP_PSTRIDE (dest_frame, 0);
packed_out = (out_bpp < 4);
out_alpha = GST_VIDEO_INFO_HAS_ALPHA (&dest_frame->info);
p_out[0] = GST_VIDEO_FRAME_COMP_OFFSET (dest_frame, 3);
p_out[1] = GST_VIDEO_FRAME_COMP_OFFSET (dest_frame, 0);
p_out[2] = GST_VIDEO_FRAME_COMP_OFFSET (dest_frame, 1);
p_out[3] = GST_VIDEO_FRAME_COMP_OFFSET (dest_frame, 2);
memcpy (matrix,
(src_sdtv) ? cog_ycbcr_to_rgb_matrix_8bit_sdtv :
cog_ycbcr_to_rgb_matrix_8bit_hdtv, 12 * sizeof (gint));
dest = GST_VIDEO_FRAME_PLANE_DATA (dest_frame, 0);
dest = dest + dest_y * dest_stride + dest_x * out_bpp;
src = GST_VIDEO_FRAME_PLANE_DATA (src_frame, 0);
src = src + src_y * src_stride + src_x * 4;
if (out_alpha) {
w *= 4;
for (i = 0; i < h; i++) {
for (j = 0; j < w; j += 4) {
a = (src[j + 0] * i_alpha) >> 8;
y = src[j + 1];
u = src[j + 2];
v = src[j + 3];
r = APPLY_MATRIX (matrix, 0, y, u, v);
g = APPLY_MATRIX (matrix, 1, y, u, v);
b = APPLY_MATRIX (matrix, 2, y, u, v);
dest[j + p_out[0]] = a;
dest[j + p_out[1]] = CLAMP (r, 0, 255);
dest[j + p_out[2]] = CLAMP (g, 0, 255);
dest[j + p_out[3]] = CLAMP (b, 0, 255);
}
dest += dest_stride;
src += src_stride;
}
} else if (!packed_out) {
w *= 4;
for (i = 0; i < h; i++) {
for (j = 0; j < w; j += 4) {
y = src[j + 1];
u = src[j + 2];
v = src[j + 3];
r = APPLY_MATRIX (matrix, 0, y, u, v);
g = APPLY_MATRIX (matrix, 1, y, u, v);
b = APPLY_MATRIX (matrix, 2, y, u, v);
dest[j + p_out[1]] = CLAMP (r, 0, 255);
dest[j + p_out[2]] = CLAMP (g, 0, 255);
dest[j + p_out[3]] = CLAMP (b, 0, 255);
}
dest += dest_stride;
src += src_stride;
}
} else {
for (i = 0; i < h; i++) {
for (j = 0; j < w; j++) {
y = src[4 * j + 1];
u = src[4 * j + 2];
v = src[4 * j + 3];
r = APPLY_MATRIX (matrix, 0, y, u, v);
g = APPLY_MATRIX (matrix, 1, y, u, v);
b = APPLY_MATRIX (matrix, 2, y, u, v);
dest[out_bpp * j + p_out[1]] = CLAMP (r, 0, 255);
dest[out_bpp * j + p_out[2]] = CLAMP (g, 0, 255);
dest[out_bpp * j + p_out[3]] = CLAMP (b, 0, 255);
}
dest += dest_stride;
src += src_stride;
}
}
}
static void
fill_gray (GstVideoBoxFill fill_type, guint b_alpha,
GstVideoFrame * frame, gboolean sdtv)
{
gint i, j;
gint dest_stride;
guint8 *dest;
gint width, height;
GstVideoFormat format;
format = GST_VIDEO_FRAME_FORMAT (frame);
width = GST_VIDEO_FRAME_WIDTH (frame);
height = GST_VIDEO_FRAME_HEIGHT (frame);
dest = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
dest_stride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0);
if (format == GST_VIDEO_FORMAT_GRAY8) {
guint8 val = yuv_sdtv_colors_Y[fill_type];
for (i = 0; i < height; i++) {
memset (dest, val, width);
dest += dest_stride;
}
} else {
guint16 val = yuv_sdtv_colors_Y[fill_type] << 8;
if (format == GST_VIDEO_FORMAT_GRAY16_BE) {
for (i = 0; i < height; i++) {
for (j = 0; j < width; j++) {
GST_WRITE_UINT16_BE (dest + 2 * j, val);
}
dest += dest_stride;
}
} else {
for (i = 0; i < height; i++) {
for (j = 0; j < width; j++) {
GST_WRITE_UINT16_LE (dest + 2 * j, val);
}
dest += dest_stride;
}
}
}
}
static void
copy_packed_simple (guint i_alpha, GstVideoFrame * dest_frame,
gboolean dest_sdtv, gint dest_x, gint dest_y, GstVideoFrame * src_frame,
gboolean src_sdtv, gint src_x, gint src_y, gint w, gint h)
{
gint i;
gint src_stride, dest_stride;
gint pixel_stride, row_size;
guint8 *src, *dest;
src_stride = GST_VIDEO_FRAME_PLANE_STRIDE (src_frame, 0);
dest_stride = GST_VIDEO_FRAME_PLANE_STRIDE (dest_frame, 0);
pixel_stride = GST_VIDEO_FRAME_COMP_PSTRIDE (dest_frame, 0);
row_size = w * pixel_stride;
dest = GST_VIDEO_FRAME_PLANE_DATA (dest_frame, 0);
dest = dest + dest_y * dest_stride + dest_x * pixel_stride;
src = GST_VIDEO_FRAME_PLANE_DATA (src_frame, 0);
s