| /* 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); |
| src = src + src_y * src_stride + src_x * pixel_stride; |
| |
| for (i = 0; i < h; i++) { |
| memcpy (dest, src, row_size); |
| dest += dest_stride; |
| src += src_stride; |
| } |
| } |
| |
| static void |
| fill_yuy2 (GstVideoBoxFill fill_type, guint b_alpha, |
| GstVideoFrame * frame, gboolean sdtv) |
| { |
| guint8 y, u, v; |
| gint i, j; |
| gint stride; |
| gint width, height; |
| guint8 *dest; |
| 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); |
| stride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0); |
| |
| y = (sdtv) ? yuv_sdtv_colors_Y[fill_type] : yuv_hdtv_colors_Y[fill_type]; |
| u = (sdtv) ? yuv_sdtv_colors_U[fill_type] : yuv_hdtv_colors_U[fill_type]; |
| v = (sdtv) ? yuv_sdtv_colors_V[fill_type] : yuv_hdtv_colors_V[fill_type]; |
| |
| width = width + (width % 2); |
| |
| if (format == GST_VIDEO_FORMAT_YUY2) { |
| for (i = 0; i < height; i++) { |
| for (j = 0; j < width; j += 2) { |
| dest[j * 2 + 0] = y; |
| dest[j * 2 + 1] = u; |
| dest[j * 2 + 2] = y; |
| dest[j * 2 + 3] = v; |
| } |
| |
| dest += stride; |
| } |
| } else if (format == GST_VIDEO_FORMAT_YVYU) { |
| for (i = 0; i < height; i++) { |
| for (j = 0; j < width; j += 2) { |
| dest[j * 2 + 0] = y; |
| dest[j * 2 + 1] = v; |
| dest[j * 2 + 2] = y; |
| dest[j * 2 + 3] = u; |
| } |
| |
| dest += stride; |
| } |
| } else { |
| for (i = 0; i < height; i++) { |
| for (j = 0; j < width; j += 2) { |
| dest[j * 2 + 0] = u; |
| dest[j * 2 + 1] = y; |
| dest[j * 2 + 2] = v; |
| dest[j * 2 + 3] = y; |
| } |
| |
| dest += stride; |
| } |
| } |
| } |
| |
| static void |
| copy_yuy2_yuy2 (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; |
| guint8 *src, *dest; |
| GstVideoFormat src_format; |
| |
| src_format = GST_VIDEO_FRAME_FORMAT (src_frame); |
| |
| src_stride = GST_VIDEO_FRAME_PLANE_STRIDE (src_frame, 0); |
| dest_stride = GST_VIDEO_FRAME_PLANE_STRIDE (dest_frame, 0); |
| |
| dest_x = (dest_x & ~1); |
| src_x = (src_x & ~1); |
| |
| w = w + (w % 2); |
| |
| dest = GST_VIDEO_FRAME_PLANE_DATA (dest_frame, 0); |
| dest = dest + dest_y * dest_stride + dest_x * 2; |
| src = GST_VIDEO_FRAME_PLANE_DATA (src_frame, 0); |
| src = src + src_y * src_stride + src_x * 2; |
| |
| if (src_sdtv != dest_sdtv) { |
| gint y1, u1, v1; |
| gint y2, u2, v2; |
| 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)); |
| |
| if (src_format == GST_VIDEO_FORMAT_YUY2) { |
| for (i = 0; i < h; i++) { |
| for (j = 0; j < w; j += 2) { |
| y1 = src[j * 2 + 0]; |
| y2 = src[j * 2 + 2]; |
| u1 = u2 = src[j * 2 + 1]; |
| v1 = v2 = src[j * 2 + 3]; |
| |
| dest[j * 2 + 0] = APPLY_MATRIX (matrix, 0, y1, u1, v1); |
| dest[j * 2 + 1] = APPLY_MATRIX (matrix, 1, y1, u1, v1); |
| dest[j * 2 + 2] = APPLY_MATRIX (matrix, 0, y1, u2, v2); |
| dest[j * 2 + 3] = APPLY_MATRIX (matrix, 2, y2, u2, v2); |
| } |
| dest += dest_stride; |
| src += src_stride; |
| } |
| } else if (src_format == GST_VIDEO_FORMAT_YVYU) { |
| for (i = 0; i < h; i++) { |
| for (j = 0; j < w; j += 2) { |
| y1 = src[j * 2 + 0]; |
| y2 = src[j * 2 + 2]; |
| v1 = v2 = src[j * 2 + 1]; |
| u1 = u2 = src[j * 2 + 3]; |
| |
| dest[j * 2 + 0] = APPLY_MATRIX (matrix, 0, y1, u1, v1); |
| dest[j * 2 + 1] = APPLY_MATRIX (matrix, 2, y1, u1, v1); |
| dest[j * 2 + 2] = APPLY_MATRIX (matrix, 0, y1, u2, v2); |
| dest[j * 2 + 3] = APPLY_MATRIX (matrix, 1, y2, u2, v2); |
| } |
| dest += dest_stride; |
| src += src_stride; |
| } |
| } else { |
| for (i = 0; i < h; i++) { |
| for (j = 0; j < w; j += 2) { |
| u1 = u2 = src[j * 2 + 0]; |
| v1 = v2 = src[j * 2 + 2]; |
| y1 = src[j * 2 + 1]; |
| y2 = src[j * 2 + 3]; |
| |
| dest[j * 2 + 1] = APPLY_MATRIX (matrix, 0, y1, u1, v1); |
| dest[j * 2 + 0] = APPLY_MATRIX (matrix, 1, y1, u1, v1); |
| dest[j * 2 + 3] = APPLY_MATRIX (matrix, 0, y1, u2, v2); |
| dest[j * 2 + 2] = APPLY_MATRIX (matrix, 2, y2, u2, v2); |
| } |
| dest += dest_stride; |
| src += src_stride; |
| } |
| } |
| } else { |
| for (i = 0; i < h; i++) { |
| memcpy (dest, src, w * 2); |
| dest += dest_stride; |
| src += src_stride; |
| } |
| } |
| } |
| |
| #define DEFAULT_LEFT 0 |
| #define DEFAULT_RIGHT 0 |
| #define DEFAULT_TOP 0 |
| #define DEFAULT_BOTTOM 0 |
| #define DEFAULT_FILL_TYPE VIDEO_BOX_FILL_BLACK |
| #define DEFAULT_ALPHA 1.0 |
| #define DEFAULT_BORDER_ALPHA 1.0 |
| |
| enum |
| { |
| PROP_0, |
| PROP_LEFT, |
| PROP_RIGHT, |
| PROP_TOP, |
| PROP_BOTTOM, |
| PROP_FILL_TYPE, |
| PROP_ALPHA, |
| PROP_BORDER_ALPHA, |
| PROP_AUTOCROP |
| /* FILL ME */ |
| }; |
| |
| static GstStaticPadTemplate gst_video_box_src_template = |
| GST_STATIC_PAD_TEMPLATE ("src", |
| GST_PAD_SRC, |
| GST_PAD_ALWAYS, |
| GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ AYUV, " |
| "ARGB, BGRA, ABGR, RGBA, xRGB, BGRx, xBGR, RGBx, RGB, BGR, " |
| "Y444, Y42B, YUY2, YVYU, UYVY, I420, YV12, Y41B, " |
| "GRAY8, GRAY16_BE, GRAY16_LE } ")) |
| ); |
| |
| static GstStaticPadTemplate gst_video_box_sink_template = |
| GST_STATIC_PAD_TEMPLATE ("sink", |
| GST_PAD_SINK, |
| GST_PAD_ALWAYS, |
| GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ AYUV, " |
| "ARGB, BGRA, ABGR, RGBA, xRGB, BGRx, xBGR, RGBx, RGB, BGR, " |
| "Y444, Y42B, YUY2, YVYU, UYVY, I420, YV12, Y41B, " |
| "GRAY8, GRAY16_BE, GRAY16_LE } ")) |
| ); |
| |
| #define gst_video_box_parent_class parent_class |
| G_DEFINE_TYPE (GstVideoBox, gst_video_box, GST_TYPE_VIDEO_FILTER); |
| |
| static void gst_video_box_set_property (GObject * object, guint prop_id, |
| const GValue * value, GParamSpec * pspec); |
| static
|