2 * Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
4 * Copyright (C) 2010 Sebastian Dröge <sebastian.droege@collabora.co.uk>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
22 * SECTION:element-videobox
23 * @see_also: #GstVideoCrop
25 * This plugin crops or enlarges the image. It takes 4 values as input, a
26 * top, bottom, left and right offset. Positive values will crop that much
27 * pixels from the respective border of the image, negative values will add
28 * that much pixels. When pixels are added, you can specify their color.
29 * Some predefined colors are usable with an enum property.
31 * The plugin is alpha channel aware and will try to negotiate with a format
32 * that supports alpha channels first. When alpha channel is active two
33 * other properties, alpha and border_alpha can be used to set the alpha
34 * values of the inner picture and the border respectively. an alpha value of
35 * 0.0 means total transparency, 1.0 is opaque.
37 * The videobox plugin has many uses such as doing a mosaic of pictures,
38 * letterboxing video, cutting out pieces of video, picture in picture, etc..
40 * Setting autocrop to true changes the behavior of the plugin so that
41 * caps determine crop properties rather than the other way around: given
42 * input and output dimensions, the crop values are selected so that the
43 * smaller frame is effectively centered in the larger frame. This
44 * involves either cropping or padding.
46 * If you use autocrop there is little point in setting the other
47 * properties manually because they will be overriden if the caps change,
48 * but nothing stops you from doing so.
52 * gst-launch videotestsrc ! videobox autocrop=true ! \
53 * "video/x-raw-yuv, width=600, height=400" ! ffmpegcolorspace ! ximagesink
61 #include "gstvideobox.h"
62 #include "gstvideoboxorc.h"
67 #include <gst/controller/gstcontroller.h>
69 GST_DEBUG_CATEGORY_STATIC (videobox_debug);
70 #define GST_CAT_DEFAULT videobox_debug
72 /* From videotestsrc.c */
73 static const guint8 yuv_sdtv_colors_Y[VIDEO_BOX_FILL_LAST] =
74 { 16, 145, 41, 81, 210, 235 };
75 static const guint8 yuv_sdtv_colors_U[VIDEO_BOX_FILL_LAST] =
76 { 128, 54, 240, 90, 16, 128 };
77 static const guint8 yuv_sdtv_colors_V[VIDEO_BOX_FILL_LAST] =
78 { 128, 34, 110, 240, 146, 128 };
80 static const guint8 yuv_hdtv_colors_Y[VIDEO_BOX_FILL_LAST] =
81 { 16, 173, 32, 63, 219, 235 };
82 static const guint8 yuv_hdtv_colors_U[VIDEO_BOX_FILL_LAST] =
83 { 128, 42, 240, 102, 16, 128 };
84 static const guint8 yuv_hdtv_colors_V[VIDEO_BOX_FILL_LAST] =
85 { 128, 26, 118, 240, 138, 128 };
87 static const guint8 rgb_colors_R[VIDEO_BOX_FILL_LAST] =
88 { 0, 0, 0, 255, 255, 255 };
89 static const guint8 rgb_colors_G[VIDEO_BOX_FILL_LAST] =
90 { 0, 255, 0, 0, 255, 255 };
91 static const guint8 rgb_colors_B[VIDEO_BOX_FILL_LAST] =
92 { 0, 0, 255, 0, 0, 255 };
94 /* Generated by -bad/ext/cog/generate_tables */
95 static const int cog_ycbcr_to_rgb_matrix_8bit_hdtv[] = {
97 298, -55, -136, 19681,
101 static const int cog_ycbcr_to_rgb_matrix_8bit_sdtv[] = {
103 298, -100, -208, 34707,
107 static const gint cog_rgb_to_ycbcr_matrix_8bit_hdtv[] = {
109 -26, -87, 112, 32768,
110 112, -102, -10, 32768,
113 static const gint cog_rgb_to_ycbcr_matrix_8bit_sdtv[] = {
115 -38, -74, 112, 32768,
116 112, -94, -18, 32768,
119 static const gint cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit[] = {
120 256, -30, -53, 10600,
125 static const gint cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit[] = {
131 static const gint cog_identity_matrix_8bit[] = {
137 #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)
140 fill_ayuv (GstVideoBoxFill fill_type, guint b_alpha, GstVideoFormat format,
141 guint8 * dest, gboolean sdtv, gint width, gint height)
145 b_alpha = CLAMP (b_alpha, 0, 255);
148 empty_pixel = GUINT32_FROM_BE ((b_alpha << 24) |
149 (yuv_sdtv_colors_Y[fill_type] << 16) |
150 (yuv_sdtv_colors_U[fill_type] << 8) | yuv_sdtv_colors_V[fill_type]);
152 empty_pixel = GUINT32_FROM_BE ((b_alpha << 24) |
153 (yuv_hdtv_colors_Y[fill_type] << 16) |
154 (yuv_hdtv_colors_U[fill_type] << 8) | yuv_hdtv_colors_V[fill_type]);
156 orc_splat_u32 ((guint32 *) dest, empty_pixel, width * height);
160 copy_ayuv_ayuv (guint i_alpha, GstVideoFormat dest_format, guint8 * dest,
161 gboolean dest_sdtv, gint dest_width, gint dest_height, gint dest_x,
162 gint dest_y, GstVideoFormat src_format, const guint8 * src,
163 gboolean src_sdtv, gint src_width, gint src_height, gint src_x, gint src_y,
167 gint src_stride = 4 * src_width;
168 gint dest_stride = 4 * dest_width;
170 dest = dest + dest_y * dest_width * 4 + dest_x * 4;
171 src = src + src_y * src_width * 4 + src_x * 4;
175 if (dest_sdtv != src_sdtv) {
180 dest_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
181 cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit, 12 * sizeof (gint));
183 for (i = 0; i < h; i++) {
184 for (j = 0; j < w; j += 4) {
186 dest[j] = (src[j] * i_alpha) >> 8;
190 dest[j + 1] = APPLY_MATRIX (matrix, 0, y, u, v);
191 dest[j + 2] = APPLY_MATRIX (matrix, 1, y, u, v);
192 dest[j + 3] = APPLY_MATRIX (matrix, 2, y, u, v);
198 for (i = 0; i < h; i++) {
199 for (j = 0; j < w; j += 4) {
201 dest[j] = (src[j] * i_alpha) >> 8;
202 dest[j + 1] = src[j + 1];
203 dest[j + 2] = src[j + 2];
204 dest[j + 3] = src[j + 3];
213 copy_ayuv_i420 (guint i_alpha, GstVideoFormat dest_format, guint8 * dest,
214 gboolean dest_sdtv, gint dest_width, gint dest_height, gint dest_x,
215 gint dest_y, GstVideoFormat src_format, const guint8 * src,
216 gboolean src_sdtv, gint src_width, gint src_height, gint src_x, gint src_y,
220 guint8 *destY, *destY2, *destU, *destV;
221 gint dest_strideY, dest_strideUV;
230 dest_strideY = gst_video_format_get_row_stride (dest_format, 0, dest_width);
231 dest_strideUV = gst_video_format_get_row_stride (dest_format, 1, dest_width);
233 src_stride = 4 * src_width;
236 dest + gst_video_format_get_component_offset (dest_format, 0,
237 dest_width, dest_height);
239 dest + gst_video_format_get_component_offset (dest_format, 1,
240 dest_width, dest_height);
242 dest + gst_video_format_get_component_offset (dest_format, 2,
243 dest_width, dest_height);
245 destY = destY + dest_y * dest_strideY + dest_x;
246 destY2 = (dest_y < dest_height) ? destY + dest_strideY : destY;
247 destU = destU + (dest_y / 2) * dest_strideUV + dest_x / 2;
248 destV = destV + (dest_y / 2) * dest_strideUV + dest_x / 2;
250 src = src + src_y * src_stride + src_x * 4;
251 src2 = (src_y < src_height) ? src + src_stride : src;
256 if (src_sdtv != dest_sdtv)
258 dest_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
259 cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit, 12 * sizeof (gint));
261 memcpy (matrix, cog_identity_matrix_8bit, 12 * sizeof (gint));
263 /* 1. Handle the first destination scanline specially if it
264 * doesn't start at the macro pixel boundary, i.e. blend
265 * with the background! */
266 if (dest_y % 2 == 1) {
267 /* 1.1. Handle the first destination pixel if it doesn't
268 * start at the macro pixel boundary, i.e. blend with
270 if (dest_x % 2 == 1) {
275 destY[0] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
277 CLAMP ((3 * destU[0] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 4, 0,
280 CLAMP ((3 * destV[0] + APPLY_MATRIX (matrix, 2, y1, u1, v1)) / 4, 0,
290 /* 1.2. Copy all macro pixels from the source to the destination
291 * but blend with the background because we're only filling
292 * the lower part of the macro pixels. */
293 for (; j < w - 1; j += 2) {
294 y1 = src[4 * y_idx + 1];
295 y2 = src[4 * y_idx + 4 + 1];
297 u1 = src[4 * y_idx + 2];
298 u2 = src[4 * y_idx + 4 + 2];
300 v1 = src[4 * y_idx + 3];
301 v2 = src[4 * y_idx + 4 + 3];
303 destY[y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
304 destY[y_idx + 1] = CLAMP (APPLY_MATRIX (matrix, 0, y2, u2, v2), 0, 255);
305 destU[uv_idx] = CLAMP (
306 (2 * destU[uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
307 v1) + APPLY_MATRIX (matrix, 1, y2, u2, v2)) / 4, 0, 255);
308 destV[uv_idx] = CLAMP (
309 (2 * destV[uv_idx] + APPLY_MATRIX (matrix, 2, y1, u1,
310 v1) + APPLY_MATRIX (matrix, 2, y2, u2, v2)) / 4, 0, 255);
316 /* 1.3. Now copy the last pixel if one exists and blend it
317 * with the background because we only fill part of
318 * the macro pixel. In case this is the last pixel of
319 * the destination we will a larger part. */
320 if (j == w - 1 && j == dest_width - 1) {
321 y1 = src[4 * y_idx + 1];
322 u1 = src[4 * y_idx + 2];
323 v1 = src[4 * y_idx + 3];
325 destY[y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
326 destU[uv_idx] = CLAMP (
327 (destU[uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 2, 0, 255);
328 destV[uv_idx] = CLAMP (
329 (destV[uv_idx] + APPLY_MATRIX (matrix, 2, y1, u1, v1)) / 2, 0, 255);
330 } else if (j == w - 1) {
331 y1 = src[4 * y_idx + 1];
332 u1 = src[4 * y_idx + 2];
333 v1 = src[4 * y_idx + 3];
335 destY[y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
336 destU[uv_idx] = CLAMP (
337 (3 * destU[uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 4, 0,
340 CLAMP ((3 * destV[uv_idx] + APPLY_MATRIX (matrix, 2, y1, u1, v1)) / 4,
344 destY += dest_strideY;
345 destY2 += dest_strideY;
346 destU += dest_strideUV;
347 destV += dest_strideUV;
355 /* 2. Copy all macro pixel scanlines, the destination scanline
356 * now starts at macro pixel boundary. */
357 for (; i < h - 1; i += 2) {
358 /* 2.1. Handle the first destination pixel if it doesn't
359 * start at the macro pixel boundary, i.e. blend with
361 if (dest_x % 2 == 1) {
363 y2 = src2[4 * 0 + 1];
365 u2 = src2[4 * 0 + 2];
367 v2 = src2[4 * 0 + 3];
369 destY[0] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
370 destY2[0] = CLAMP (APPLY_MATRIX (matrix, 0, y2, u2, v2), 0, 255);
372 (2 * destU[0] + APPLY_MATRIX (matrix, 1, y1, u1,
373 v1) + APPLY_MATRIX (matrix, 1, y2, u2, v2)) / 4, 0, 255);
375 (2 * destV[0] + APPLY_MATRIX (matrix, 2, y1, u1,
376 v1) + APPLY_MATRIX (matrix, 2, y2, u2, v2)) / 4, 0, 255);
384 /* 2.2. Copy all macro pixels from the source to the destination.
385 * All pixels now start at macro pixel boundary, i.e. no
386 * blending with the background is necessary. */
387 for (; j < w - 1; j += 2) {
388 y1 = src[4 * y_idx + 1];
389 y2 = src[4 * y_idx + 4 + 1];
390 y3 = src2[4 * y_idx + 1];
391 y4 = src2[4 * y_idx + 4 + 1];
393 u1 = src[4 * y_idx + 2];
394 u2 = src[4 * y_idx + 4 + 2];
395 u3 = src2[4 * y_idx + 2];
396 u4 = src2[4 * y_idx + 4 + 2];
398 v1 = src[4 * y_idx + 3];
399 v2 = src[4 * y_idx + 4 + 3];
400 v3 = src2[4 * y_idx + 3];
401 v4 = src2[4 * y_idx + 4 + 3];
403 destY[y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
404 destY[y_idx + 1] = CLAMP (APPLY_MATRIX (matrix, 0, y2, u2, v2), 0, 255);
405 destY2[y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y3, u3, v3), 0, 255);
406 destY2[y_idx + 1] = CLAMP (APPLY_MATRIX (matrix, 0, y4, u4, v4), 0, 255);
408 destU[uv_idx] = CLAMP (
409 (APPLY_MATRIX (matrix, 1, y1, u1, v1) + APPLY_MATRIX (matrix, 1, y2,
410 u2, v2) + APPLY_MATRIX (matrix, 1, y3, u3,
411 v3) + APPLY_MATRIX (matrix, 1, y4, u4, v4)) / 4, 0, 255);
412 destV[uv_idx] = CLAMP (
413 (APPLY_MATRIX (matrix, 2, y1, u1, v1) + APPLY_MATRIX (matrix, 2, y2,
414 u2, v2) + APPLY_MATRIX (matrix, 2, y3, u3,
415 v3) + APPLY_MATRIX (matrix, 2, y4, u4, v4)) / 4, 0, 255);
421 /* 2.3. Now copy the last pixel if one exists and blend it
422 * with the background because we only fill part of
423 * the macro pixel. In case this is the last pixel of
424 * the destination we will a larger part. */
425 if (j == w - 1 && j == dest_width - 1) {
426 y1 = src[4 * y_idx + 1];
427 y2 = src2[4 * y_idx + 1];
429 u1 = src[4 * y_idx + 2];
430 u2 = src2[4 * y_idx + 2];
432 v1 = src[4 * y_idx + 3];
433 v2 = src2[4 * y_idx + 3];
435 destY[y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
436 destY2[y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y2, u2, v2), 0, 255);
437 destU[uv_idx] = CLAMP (
438 (APPLY_MATRIX (matrix, 1, y1, u1, v1) + APPLY_MATRIX (matrix, 2, y2,
439 u2, v2)) / 2, 0, 255);
440 destV[uv_idx] = CLAMP (
441 (APPLY_MATRIX (matrix, 1, y1, u1, v1) + APPLY_MATRIX (matrix, 2, y2,
442 u2, v2)) / 2, 0, 255);
443 } else if (j == w - 1) {
444 y1 = src[4 * y_idx + 1];
445 y2 = src2[4 * y_idx + 1];
447 u1 = src[4 * y_idx + 2];
448 u2 = src2[4 * y_idx + 2];
450 v1 = src[4 * y_idx + 3];
451 v2 = src2[4 * y_idx + 3];
453 destY[y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
454 destY2[y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y2, u2, v2), 0, 255);
455 destU[uv_idx] = CLAMP (
456 (2 * destU[uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
457 v1) + APPLY_MATRIX (matrix, 2, y2, u2, v2)) / 4, 0, 255);
458 destV[uv_idx] = CLAMP (
459 (2 * destV[uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
460 v1) + APPLY_MATRIX (matrix, 2, y2, u2, v2)) / 4, 0, 255);
463 destY += 2 * dest_strideY;
464 destY2 += 2 * dest_strideY;
465 destU += dest_strideUV;
466 destV += dest_strideUV;
467 src += 2 * src_stride;
468 src2 += 2 * src_stride;
471 /* 3. Handle the last scanline if one exists. This again
472 * doesn't start at macro pixel boundary but should
473 * only fill the upper part of the macro pixels. */
474 if (i == h - 1 && i == dest_height - 1) {
475 /* 3.1. Handle the first destination pixel if it doesn't
476 * start at the macro pixel boundary, i.e. blend with
478 if (dest_x % 2 == 1) {
483 destY[0] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
485 CLAMP ((destU[0] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 2, 0, 255);
487 CLAMP ((destV[0] + APPLY_MATRIX (matrix, 2, y1, u1, v1)) / 2, 0, 255);
496 /* 3.2. Copy all macro pixels from the source to the destination
497 * but blend with the background because we're only filling
498 * the upper part of the macro pixels. */
499 for (; j < w - 1; j += 2) {
500 y1 = src[4 * y_idx + 1];
501 y2 = src[4 * y_idx + 4 + 1];
503 u1 = src[4 * y_idx + 2];
504 u2 = src[4 * y_idx + 4 + 2];
506 v1 = src[4 * y_idx + 3];
507 v2 = src[4 * y_idx + 4 + 3];
509 destY[y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
510 destY[y_idx + 1] = CLAMP (APPLY_MATRIX (matrix, 0, y2, u2, v2), 0, 255);
512 destU[uv_idx] = CLAMP (
513 (2 * destU[uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
514 v1) + APPLY_MATRIX (matrix, 1, y2, u2, v2)) / 4, 0, 255);
515 destV[uv_idx] = CLAMP (
516 (2 * destV[uv_idx] + APPLY_MATRIX (matrix, 2, y1, u1,
517 v1) + APPLY_MATRIX (matrix, 2, y2, u2, v2)) / 4, 0, 255);
523 /* 3.3. Now copy the last pixel if one exists and blend it
524 * with the background because we only fill part of
525 * the macro pixel. In case this is the last pixel of
526 * the destination we will a larger part. */
527 if (j == w - 1 && j == dest_width - 1) {
528 y1 = src[4 * y_idx + 1];
529 u1 = src[4 * y_idx + 2];
530 v1 = src[4 * y_idx + 3];
532 destY[y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
533 destU[uv_idx] = CLAMP (
534 (destU[uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 2, 0, 255);
535 destV[uv_idx] = CLAMP (
536 (destV[uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 2, 0, 255);
537 } else if (j == w - 1) {
538 y1 = src[4 * y_idx + 1];
539 u1 = src[4 * y_idx + 2];
540 v1 = src[4 * y_idx + 3];
542 destY[y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
543 destU[uv_idx] = CLAMP (
544 (3 * destU[uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 4, 0,
547 CLAMP ((3 * destV[uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 4,
550 } else if (i == h - 1) {
551 /* 3.1. Handle the first destination pixel if it doesn't
552 * start at the macro pixel boundary, i.e. blend with
554 if (dest_x % 2 == 1) {
559 destY[0] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
561 CLAMP ((3 * destU[0] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 4, 0,
564 CLAMP ((3 * destV[0] + APPLY_MATRIX (matrix, 2, y1, u1, v1)) / 4, 0,
574 /* 3.2. Copy all macro pixels from the source to the destination
575 * but blend with the background because we're only filling
576 * the upper part of the macro pixels. */
577 for (; j < w - 1; j += 2) {
578 y1 = src[4 * y_idx + 1];
579 y2 = src[4 * y_idx + 4 + 1];
581 u1 = src[4 * y_idx + 2];
582 u2 = src[4 * y_idx + 4 + 2];
584 v1 = src[4 * y_idx + 3];
585 v2 = src[4 * y_idx + 4 + 3];
587 destY[y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
588 destY[y_idx + 1] = CLAMP (APPLY_MATRIX (matrix, 0, y2, u2, v2), 0, 255);
590 destU[uv_idx] = CLAMP (
591 (2 * destU[uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
592 v1) + APPLY_MATRIX (matrix, 1, y2, u2, v2)) / 4, 0, 255);
593 destV[uv_idx] = CLAMP (
594 (2 * destV[uv_idx] + APPLY_MATRIX (matrix, 2, y1, u1,
595 v1) + APPLY_MATRIX (matrix, 2, y2, u2, v2)) / 4, 0, 255);
601 /* 3.3. Now copy the last pixel if one exists and blend it
602 * with the background because we only fill part of
603 * the macro pixel. In case this is the last pixel of
604 * the destination we will a larger part. */
605 if (j == w - 1 && j == dest_width - 1) {
606 y1 = src[4 * y_idx + 1];
607 u1 = src[4 * y_idx + 2];
608 v1 = src[4 * y_idx + 3];
610 destY[y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
611 destU[uv_idx] = CLAMP (
612 (destU[uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 2, 0, 255);
613 destV[uv_idx] = CLAMP (
614 (destV[uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 2, 0, 255);
615 } else if (j == w - 1) {
616 y1 = src[4 * y_idx + 1];
617 u1 = src[4 * y_idx + 2];
618 v1 = src[4 * y_idx + 3];
620 destY[y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
621 destU[uv_idx] = CLAMP (
622 (3 * destU[uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 4, 0,
625 CLAMP ((3 * destV[uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 4,
632 fill_planar_yuv (GstVideoBoxFill fill_type, guint b_alpha,
633 GstVideoFormat format, guint8 * dest, gboolean sdtv, gint width,
636 guint8 empty_pixel[3];
637 guint8 *destY, *destU, *destV;
638 gint strideY, strideUV;
639 gint heightY, heightUV;
642 empty_pixel[0] = yuv_sdtv_colors_Y[fill_type];
643 empty_pixel[1] = yuv_sdtv_colors_U[fill_type];
644 empty_pixel[2] = yuv_sdtv_colors_V[fill_type];
646 empty_pixel[0] = yuv_hdtv_colors_Y[fill_type];
647 empty_pixel[1] = yuv_hdtv_colors_U[fill_type];
648 empty_pixel[2] = yuv_hdtv_colors_V[fill_type];
651 strideY = gst_video_format_get_row_stride (format, 0, width);
652 strideUV = gst_video_format_get_row_stride (format, 1, width);
655 dest + gst_video_format_get_component_offset (format, 0, width, height);
657 dest + gst_video_format_get_component_offset (format, 1, width, height);
659 dest + gst_video_format_get_component_offset (format, 2, width, height);
661 heightY = gst_video_format_get_component_height (format, 0, height);
662 heightUV = gst_video_format_get_component_height (format, 1, height);
664 memset (destY, empty_pixel[0], strideY * heightY);
665 memset (destU, empty_pixel[1], strideUV * heightUV);
666 memset (destV, empty_pixel[2], strideUV * heightUV);
670 copy_y444_y444 (guint i_alpha, GstVideoFormat dest_format, guint8 * dest,
671 gboolean dest_sdtv, gint dest_width, gint dest_height, gint dest_x,
672 gint dest_y, GstVideoFormat src_format, const guint8 * src,
673 gboolean src_sdtv, gint src_width, gint src_height, gint src_x, gint src_y,
677 guint8 *destY, *destU, *destV;
678 const guint8 *srcY, *srcU, *srcV;
682 dest_stride = gst_video_format_get_row_stride (dest_format, 0, dest_width);
683 src_stride = gst_video_format_get_row_stride (src_format, 0, src_width);
686 dest + gst_video_format_get_component_offset (dest_format, 0,
687 dest_width, dest_height);
689 dest + gst_video_format_get_component_offset (dest_format, 1,
690 dest_width, dest_height);
692 dest + gst_video_format_get_component_offset (dest_format, 2,
693 dest_width, dest_height);
696 src + gst_video_format_get_component_offset (src_format, 0,
697 src_width, src_height);
699 src + gst_video_format_get_component_offset (src_format, 1,
700 src_width, src_height);
702 src + gst_video_format_get_component_offset (src_format, 2,
703 src_width, src_height);
705 destY = destY + dest_y * dest_stride + dest_x;
706 destU = destU + dest_y * dest_stride + dest_x;
707 destV = destV + dest_y * dest_stride + dest_x;
709 srcY = srcY + src_y * src_stride + src_x;
710 srcU = srcU + src_y * src_stride + src_x;
711 srcV = srcV + src_y * src_stride + src_x;
713 if (src_sdtv != dest_sdtv) {
718 dest_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
719 cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit, 12 * sizeof (gint));
721 for (i = 0; i < h; i++) {
722 for (j = 0; j < w; j++) {
723 y = APPLY_MATRIX (matrix, 0, srcY[j], srcU[j], srcV[j]);
724 u = APPLY_MATRIX (matrix, 1, srcY[j], srcU[j], srcV[j]);
725 v = APPLY_MATRIX (matrix, 2, srcY[j], srcU[j], srcV[j]);
731 destY += dest_stride;
732 destU += dest_stride;
733 destV += dest_stride;
740 for (i = 0; i < h; i++) {
741 memcpy (destY, srcY, w);
742 memcpy (destU, srcU, w);
743 memcpy (destV, srcV, w);
745 destY += dest_stride;
746 destU += dest_stride;
747 destV += dest_stride;
757 copy_y42b_y42b (guint i_alpha, GstVideoFormat dest_format, guint8 * dest,
758 gboolean dest_sdtv, gint dest_width, gint dest_height, gint dest_x,
759 gint dest_y, GstVideoFormat src_format, const guint8 * src,
760 gboolean src_sdtv, gint src_width, gint src_height, gint src_x, gint src_y,
764 guint8 *destY, *destU, *destV;
765 const guint8 *srcY, *srcU, *srcV;
766 gint dest_strideY, dest_strideUV;
767 gint src_strideY, src_strideUV;
768 gint src_y_idx, src_uv_idx;
769 gint dest_y_idx, dest_uv_idx;
775 dest_strideY = gst_video_format_get_row_stride (dest_format, 0, dest_width);
776 dest_strideUV = gst_video_format_get_row_stride (dest_format, 1, dest_width);
777 src_strideY = gst_video_format_get_row_stride (src_format, 0, src_width);
778 src_strideUV = gst_video_format_get_row_stride (src_format, 1, src_width);
781 dest + gst_video_format_get_component_offset (dest_format, 0,
782 dest_width, dest_height);
784 dest + gst_video_format_get_component_offset (dest_format, 1,
785 dest_width, dest_height);
787 dest + gst_video_format_get_component_offset (dest_format, 2,
788 dest_width, dest_height);
791 src + gst_video_format_get_component_offset (src_format, 0,
792 src_width, src_height);
794 src + gst_video_format_get_component_offset (src_format, 1,
795 src_width, src_height);
797 src + gst_video_format_get_component_offset (src_format, 2,
798 src_width, src_height);
801 destY = destY + dest_y * dest_strideY + dest_x;
802 destU = destU + dest_y * dest_strideUV + dest_x / 2;
803 destV = destV + dest_y * dest_strideUV + dest_x / 2;
805 srcY = srcY + src_y * src_strideY + src_x;
806 srcU = srcU + src_y * src_strideUV + src_x / 2;
807 srcV = srcV + src_y * src_strideUV + src_x / 2;
812 if (src_sdtv != dest_sdtv)
814 dest_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
815 cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit, 12 * sizeof (gint));
817 memcpy (matrix, cog_identity_matrix_8bit, 12 * sizeof (gint));
819 /* 1. Copy all macro pixel scanlines, the destination scanline
820 * now starts at macro pixel boundary. */
821 for (i = dest_y; i < h; i++) {
822 /* 1.1. Handle the first destination pixel if it doesn't
823 * start at the macro pixel boundary, i.e. blend with
825 if (dest_x % 2 == 1) {
830 destY[0] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
832 (destU[0] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 2, 0, 255);
834 (destV[0] + APPLY_MATRIX (matrix, 2, y1, u1, v1)) / 2, 0, 255);
836 src_y_idx = dest_y_idx = dest_uv_idx = 1;
837 src_uv_idx = (src_x % 2) + 1;
840 src_y_idx = dest_y_idx = dest_uv_idx = 0;
841 src_uv_idx = (src_x % 2);
844 /* 1.2. Copy all macro pixels from the source to the destination.
845 * All pixels now start at macro pixel boundary, i.e. no
846 * blending with the background is necessary. */
847 for (; j < w - 1; j += 2) {
848 y1 = srcY[src_y_idx];
849 y2 = srcY[src_y_idx + 1];
851 u1 = srcU[src_uv_idx / 2];
852 v1 = srcV[src_uv_idx / 2];
854 u2 = srcU[src_uv_idx / 2];
855 v2 = srcV[src_uv_idx / 2];
858 destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
859 destY[dest_y_idx + 1] =
860 CLAMP (APPLY_MATRIX (matrix, 0, y2, u2, v2), 0, 255);
862 destU[dest_uv_idx] = CLAMP (
863 (APPLY_MATRIX (matrix, 1, y1, u1, v1) + APPLY_MATRIX (matrix, 1, y2,
864 u2, v2)) / 2, 0, 255);
865 destV[dest_uv_idx] = CLAMP (
866 (APPLY_MATRIX (matrix, 2, y1, u1, v1) + APPLY_MATRIX (matrix, 2, y2,
867 u2, v2)) / 2, 0, 255);
874 /* 1.3. Now copy the last pixel if one exists and blend it
875 * with the background because we only fill part of
876 * the macro pixel. In case this is the last pixel of
877 * the destination we will a larger part. */
878 if (j == w - 1 && j == dest_width - 1) {
879 y1 = srcY[src_y_idx];
880 u1 = srcU[src_uv_idx / 2];
881 v1 = srcV[src_uv_idx / 2];
883 destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
884 destU[dest_uv_idx] = CLAMP (APPLY_MATRIX (matrix, 1, y1, u1, v1), 0, 255);
885 destV[dest_uv_idx] = CLAMP (APPLY_MATRIX (matrix, 1, y1, u1, v1), 0, 255);
886 } else if (j == w - 1) {
887 y1 = srcY[src_y_idx];
888 u1 = srcU[src_uv_idx / 2];
889 v1 = srcV[src_uv_idx / 2];
891 destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
892 destU[dest_uv_idx] = CLAMP (
893 (destU[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
895 destV[dest_uv_idx] = CLAMP (
896 (destV[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
900 destY += dest_strideY;
901 destU += dest_strideUV;
902 destV += dest_strideUV;
905 srcU += src_strideUV;
906 srcV += src_strideUV;
911 copy_y41b_y41b (guint i_alpha, GstVideoFormat dest_format, guint8 * dest,
912 gboolean dest_sdtv, gint dest_width, gint dest_height, gint dest_x,
913 gint dest_y, GstVideoFormat src_format, const guint8 * src,
914 gboolean src_sdtv, gint src_width, gint src_height, gint src_x, gint src_y,
918 guint8 *destY, *destU, *destV;
919 const guint8 *srcY, *srcU, *srcV;
920 gint dest_strideY, dest_strideUV;
921 gint src_strideY, src_strideUV;
922 gint src_y_idx, src_uv_idx;
923 gint dest_y_idx, dest_uv_idx;
929 dest_strideY = gst_video_format_get_row_stride (dest_format, 0, dest_width);
930 dest_strideUV = gst_video_format_get_row_stride (dest_format, 1, dest_width);
931 src_strideY = gst_video_format_get_row_stride (src_format, 0, src_width);
932 src_strideUV = gst_video_format_get_row_stride (src_format, 1, src_width);
935 dest + gst_video_format_get_component_offset (dest_format, 0,
936 dest_width, dest_height);
938 dest + gst_video_format_get_component_offset (dest_format, 1,
939 dest_width, dest_height);
941 dest + gst_video_format_get_component_offset (dest_format, 2,
942 dest_width, dest_height);
945 src + gst_video_format_get_component_offset (src_format, 0,
946 src_width, src_height);
948 src + gst_video_format_get_component_offset (src_format, 1,
949 src_width, src_height);
951 src + gst_video_format_get_component_offset (src_format, 2,
952 src_width, src_height);
955 destY = destY + dest_y * dest_strideY + dest_x;
956 destU = destU + dest_y * dest_strideUV + dest_x / 4;
957 destV = destV + dest_y * dest_strideUV + dest_x / 4;
959 srcY = srcY + src_y * src_strideY + src_x;
960 srcU = srcU + src_y * src_strideUV + src_x / 4;
961 srcV = srcV + src_y * src_strideUV + src_x / 4;
966 if (src_sdtv != dest_sdtv)
968 dest_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
969 cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit, 12 * sizeof (gint));
971 memcpy (matrix, cog_identity_matrix_8bit, 12 * sizeof (gint));
973 /* 1. Copy all macro pixel scanlines, the destination scanline
974 * now starts at macro pixel boundary. */
975 for (i = dest_y; i < h; i++) {
976 /* 1.1. Handle the first destination pixel if it doesn't
977 * start at the macro pixel boundary, i.e. blend with
979 if (dest_x % 4 == 1) {
986 destY[0] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
987 destY[1] = CLAMP (APPLY_MATRIX (matrix, 0, y2, u1, v1), 0, 255);
988 destY[2] = CLAMP (APPLY_MATRIX (matrix, 0, y3, u1, v1), 0, 255);
991 (destU[0] + APPLY_MATRIX (matrix, 1, y1, u1,
992 v1) + APPLY_MATRIX (matrix, 1, y2, u1,
993 v1) + APPLY_MATRIX (matrix, 1, y3, u1, v1)) / 4, 0, 255);
995 CLAMP ((destV[0] + APPLY_MATRIX (matrix, 2, y1, u1,
996 v1) + APPLY_MATRIX (matrix, 2, y2, u1,
997 v1) + APPLY_MATRIX (matrix, 2, y3, u1, v1)) / 4, 0, 255);
1000 src_y_idx = dest_y_idx = 3;
1002 src_uv_idx = (src_x % 4) + 3;
1003 } else if (dest_x % 4 == 2) {
1009 destY[0] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
1010 destY[1] = CLAMP (APPLY_MATRIX (matrix, 0, y2, u1, v1), 0, 255);
1013 (2 * destU[0] + APPLY_MATRIX (matrix, 1, y1, u1,
1014 v1) + APPLY_MATRIX (matrix, 1, y2, u1, v1)) / 4, 0, 255);
1016 CLAMP ((2 * destV[0] + APPLY_MATRIX (matrix, 2, y1, u1,
1017 v1) + APPLY_MATRIX (matrix, 2, y2, u1, v1)) / 4, 0, 255);
1020 src_y_idx = dest_y_idx = 2;
1022 src_uv_idx = (src_x % 4) + 2;
1023 } else if (dest_x % 4 == 3) {
1028 destY[0] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
1031 (3 * destU[0] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 4, 0, 255);
1033 (3 * destV[0] + APPLY_MATRIX (matrix, 2, y1, u1, v1)) / 4, 0, 255);
1036 src_y_idx = dest_y_idx = 1;
1038 src_uv_idx = (src_x % 4) + 1;
1041 src_y_idx = dest_y_idx = dest_uv_idx = 0;
1042 src_uv_idx = (src_x % 4);
1045 /* 1.2. Copy all macro pixels from the source to the destination.
1046 * All pixels now start at macro pixel boundary, i.e. no
1047 * blending with the background is necessary. */
1048 for (; j < w - 3; j += 4) {
1049 y1 = srcY[src_y_idx];
1050 y2 = srcY[src_y_idx + 1];
1051 y3 = srcY[src_y_idx + 2];
1052 y4 = srcY[src_y_idx + 3];
1054 u1 = srcU[src_uv_idx / 4];
1055 v1 = srcV[src_uv_idx / 4];
1057 u2 = srcU[src_uv_idx / 4];
1058 v2 = srcV[src_uv_idx / 4];
1060 u3 = srcU[src_uv_idx / 4];
1061 v3 = srcV[src_uv_idx / 4];
1063 u4 = srcU[src_uv_idx / 4];
1064 v4 = srcV[src_uv_idx / 4];
1067 destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
1068 destY[dest_y_idx + 1] =
1069 CLAMP (APPLY_MATRIX (matrix, 0, y2, u2, v2), 0, 255);
1070 destY[dest_y_idx + 2] =
1071 CLAMP (APPLY_MATRIX (matrix, 0, y3, u3, v3), 0, 255);
1072 destY[dest_y_idx + 3] =
1073 CLAMP (APPLY_MATRIX (matrix, 0, y4, u4, v4), 0, 255);
1075 destU[dest_uv_idx] = CLAMP (
1076 (APPLY_MATRIX (matrix, 1, y1, u1, v1) + APPLY_MATRIX (matrix, 1, y2,
1077 u2, v2) + APPLY_MATRIX (matrix, 1, y3, u3,
1078 v3) + APPLY_MATRIX (matrix, 1, y4, u4, v4)) / 4, 0, 255);
1079 destV[dest_uv_idx] =
1080 CLAMP ((APPLY_MATRIX (matrix, 2, y1, u1, v1) + APPLY_MATRIX (matrix,
1081 2, y2, u2, v2) + APPLY_MATRIX (matrix, 2, y3, u3,
1082 v3) + APPLY_MATRIX (matrix, 2, y4, u4, v4)) / 4, 0, 255);
1089 /* 1.3. Now copy the last pixel if one exists and blend it
1090 * with the background because we only fill part of
1091 * the macro pixel. In case this is the last pixel of
1092 * the destination we will a larger part. */
1093 if (j == w - 1 && j == dest_width - 1) {
1094 y1 = srcY[src_y_idx];
1095 u1 = srcU[src_uv_idx / 4];
1096 v1 = srcV[src_uv_idx / 4];
1098 destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
1099 destU[dest_uv_idx] = CLAMP (APPLY_MATRIX (matrix, 1, y1, u1, v1), 0, 255);
1100 destV[dest_uv_idx] = CLAMP (APPLY_MATRIX (matrix, 1, y1, u1, v1), 0, 255);
1101 } else if (j == w - 1) {
1102 y1 = srcY[src_y_idx];
1103 u1 = srcU[src_uv_idx / 4];
1104 v1 = srcV[src_uv_idx / 4];
1106 destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
1107 destU[dest_uv_idx] = CLAMP (
1108 (destU[dest_uv_idx] + 3 * APPLY_MATRIX (matrix, 1, y1, u1,
1110 destV[dest_uv_idx] = CLAMP (
1111 (destV[dest_uv_idx] + 3 * APPLY_MATRIX (matrix, 1, y1, u1,
1113 } else if (j == w - 2 && j == dest_width - 2) {
1114 y1 = srcY[src_y_idx];
1115 y2 = srcY[src_y_idx + 1];
1116 u1 = srcU[src_uv_idx / 4];
1117 v1 = srcV[src_uv_idx / 4];
1119 destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
1120 destY[dest_y_idx + 1] =
1121 CLAMP (APPLY_MATRIX (matrix, 0, y2, u1, v1), 0, 255);
1122 destU[dest_uv_idx] = CLAMP (APPLY_MATRIX (matrix, 1, y1, u1, v1), 0, 255);
1123 destV[dest_uv_idx] = CLAMP (APPLY_MATRIX (matrix, 1, y1, u1, v1), 0, 255);
1124 } else if (j == w - 2) {
1125 y1 = srcY[src_y_idx];
1126 y2 = srcY[src_y_idx + 1];
1127 u1 = srcU[src_uv_idx / 4];
1128 v1 = srcV[src_uv_idx / 4];
1130 destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
1131 destY[dest_y_idx + 1] =
1132 CLAMP (APPLY_MATRIX (matrix, 0, y2, u1, v1), 0, 255);
1133 destU[dest_uv_idx] =
1134 CLAMP ((destU[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
1136 destV[dest_uv_idx] =
1137 CLAMP ((destV[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
1139 } else if (j == w - 3 && j == dest_width - 3) {
1140 y1 = srcY[src_y_idx];
1141 y2 = srcY[src_y_idx + 1];
1142 y3 = srcY[src_y_idx + 2];
1143 u1 = srcU[src_uv_idx / 4];
1144 v1 = srcV[src_uv_idx / 4];
1146 destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
1147 destY[dest_y_idx + 1] =
1148 CLAMP (APPLY_MATRIX (matrix, 0, y2, u1, v1), 0, 255);
1149 destY[dest_y_idx + 2] =
1150 CLAMP (APPLY_MATRIX (matrix, 0, y3, u1, v1), 0, 255);
1151 destU[dest_uv_idx] = CLAMP (APPLY_MATRIX (matrix, 1, y1, u1, v1), 0, 255);
1152 destV[dest_uv_idx] = CLAMP (APPLY_MATRIX (matrix, 1, y1, u1, v1), 0, 255);
1153 } else if (j == w - 3) {
1154 y1 = srcY[src_y_idx];
1155 y2 = srcY[src_y_idx + 1];
1156 y3 = srcY[src_y_idx + 2];
1157 u1 = srcU[src_uv_idx / 4];
1158 v1 = srcV[src_uv_idx / 4];
1160 destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
1161 destY[dest_y_idx + 1] =
1162 CLAMP (APPLY_MATRIX (matrix, 0, y2, u1, v1), 0, 255);
1163 destY[dest_y_idx + 2] =
1164 CLAMP (APPLY_MATRIX (matrix, 0, y3, u1, v1), 0, 255);
1165 destU[dest_uv_idx] =
1166 CLAMP ((3 * destU[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
1168 destV[dest_uv_idx] =
1169 CLAMP ((3 * destV[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
1173 destY += dest_strideY;
1174 destU += dest_strideUV;
1175 destV += dest_strideUV;
1176 srcY += src_strideY;
1177 srcU += src_strideUV;
1178 srcV += src_strideUV;
1183 copy_i420_i420 (guint i_alpha, GstVideoFormat dest_format, guint8 * dest,
1184 gboolean dest_sdtv, gint dest_width, gint dest_height, gint dest_x,
1185 gint dest_y, GstVideoFormat src_format, const guint8 * src,
1186 gboolean src_sdtv, gint src_width, gint src_height, gint src_x, gint src_y,
1190 guint8 *destY, *destU, *destV;
1191 const guint8 *srcY, *srcU, *srcV;
1193 const guint8 *srcY2, *srcU2, *srcV2;
1194 gint dest_strideY, dest_strideUV;
1195 gint src_strideY, src_strideUV;
1196 gint src_y_idx, src_uv_idx;
1197 gint dest_y_idx, dest_uv_idx;
1199 gint y1, y2, y3, y4;
1200 gint u1, u2, u3, u4;
1201 gint v1, v2, v3, v4;
1204 gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 0, dest_width);
1206 gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 1, dest_width);
1208 gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 0, src_width);
1210 gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 1, src_width);
1213 dest + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 0,
1214 dest_width, dest_height);
1216 dest + gst_video_format_get_component_offset (dest_format, 1,
1217 dest_width, dest_height);
1219 dest + gst_video_format_get_component_offset (dest_format, 2,
1220 dest_width, dest_height);
1223 src + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 0,
1224 src_width, src_height);
1226 src + gst_video_format_get_component_offset (src_format, 1,
1227 src_width, src_height);
1229 src + gst_video_format_get_component_offset (src_format, 2,
1230 src_width, src_height);
1233 destY = destY + dest_y * dest_strideY + dest_x;
1234 destU = destU + (dest_y / 2) * dest_strideUV + dest_x / 2;
1235 destV = destV + (dest_y / 2) * dest_strideUV + dest_x / 2;
1237 srcY = srcY + src_y * src_strideY + src_x;
1238 srcU = srcU + (src_y / 2) * src_strideUV + src_x / 2;
1239 srcV = srcV + (src_y / 2) * src_strideUV + src_x / 2;
1241 destY2 = destY + dest_strideY;
1242 srcY2 = srcY + src_strideY;
1247 if (src_sdtv != dest_sdtv)
1249 dest_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
1250 cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit, 12 * sizeof (gint));
1252 memcpy (matrix, cog_identity_matrix_8bit, 12 * sizeof (gint));
1254 /* 1. Handle the first destination scanline specially if it
1255 * doesn't start at the macro pixel boundary, i.e. blend
1256 * with the background! */
1257 if (dest_y % 2 == 1) {
1258 /* 1.1. Handle the first destination pixel if it doesn't
1259 * start at the macro pixel boundary, i.e. blend with
1260 * the background! */
1261 if (dest_x % 2 == 1) {
1266 destY[0] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
1268 CLAMP ((3 * destU[0] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 4, 0,
1271 CLAMP ((3 * destV[0] + APPLY_MATRIX (matrix, 2, y1, u1, v1)) / 4, 0,
1275 src_y_idx = dest_y_idx = dest_uv_idx = 1;
1276 src_uv_idx = (src_x % 2) + 1;
1279 src_y_idx = dest_y_idx = dest_uv_idx = 0;
1280 src_uv_idx = (src_x % 2);
1283 /* 1.2. Copy all macro pixels from the source to the destination
1284 * but blend with the background because we're only filling
1285 * the lower part of the macro pixels. */
1286 for (; j < w - 1; j += 2) {
1287 y1 = srcY[src_y_idx];
1288 y2 = srcY[src_y_idx + 1];
1290 u1 = srcU[src_uv_idx / 2];
1291 v1 = srcV[src_uv_idx / 2];
1293 u2 = srcU[src_uv_idx / 2];
1294 v2 = srcV[src_uv_idx / 2];
1297 destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
1298 destY[dest_y_idx + 1] =
1299 CLAMP (APPLY_MATRIX (matrix, 0, y2, u2, v2), 0, 255);
1300 destU[dest_uv_idx] =
1301 CLAMP ((2 * destU[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
1302 v1) + APPLY_MATRIX (matrix, 1, y2, u2, v2)) / 4, 0, 255);
1303 destV[dest_uv_idx] =
1304 CLAMP ((2 * destV[dest_uv_idx] + APPLY_MATRIX (matrix, 2, y1, u1,
1305 v1) + APPLY_MATRIX (matrix, 2, y2, u2, v2)) / 4, 0, 255);
1312 /* 1.3. Now copy the last pixel if one exists and blend it
1313 * with the background because we only fill part of
1314 * the macro pixel. In case this is the last pixel of
1315 * the destination we will a larger part. */
1316 if (j == w - 1 && j == dest_width - 1) {
1317 y1 = srcY[src_y_idx];
1318 u1 = srcU[src_uv_idx / 2];
1319 v1 = srcV[src_uv_idx / 2];
1321 destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
1322 destU[dest_uv_idx] = CLAMP (
1323 (destU[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 2, 0,
1325 destV[dest_uv_idx] =
1326 CLAMP ((destV[dest_uv_idx] + APPLY_MATRIX (matrix, 2, y1, u1,
1328 } else if (j == w - 1) {
1329 y1 = srcY[src_y_idx];
1330 u1 = srcU[src_uv_idx / 2];
1331 v1 = srcV[src_uv_idx / 2];
1333 destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
1334 destU[dest_uv_idx] = CLAMP (
1335 (3 * destU[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 4,
1337 destV[dest_uv_idx] =
1338 CLAMP ((3 * destV[dest_uv_idx] + APPLY_MATRIX (matrix, 2, y1, u1,
1342 destY += dest_strideY;
1343 destY2 += dest_strideY;
1344 destU += dest_strideUV;
1345 destV += dest_strideUV;
1346 srcY += src_strideY;
1347 srcY2 += src_strideY;
1349 if (src_y % 2 == 0) {
1350 srcU += src_strideUV;
1351 srcV += src_strideUV;
1358 /* 2. Copy all macro pixel scanlines, the destination scanline
1359 * now starts at macro pixel boundary. */
1360 for (; i < h - 1; i += 2) {
1361 /* 2.1. Handle the first destination pixel if it doesn't
1362 * start at the macro pixel boundary, i.e. blend with
1363 * the background! */
1367 if (src_y % 2 == 1) {
1368 srcU2 += src_strideUV;
1369 srcV2 += src_strideUV;
1372 if (dest_x % 2 == 1) {
1380 destY[0] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
1381 destY2[0] = CLAMP (APPLY_MATRIX (matrix, 0, y2, u2, v2), 0, 255);
1383 (2 * destU[0] + APPLY_MATRIX (matrix, 1, y1, u1,
1384 v1) + APPLY_MATRIX (matrix, 1, y2, u2, v2)) / 4, 0, 255);
1386 (2 * destV[0] + APPLY_MATRIX (matrix, 2, y1, u1,
1387 v1) + APPLY_MATRIX (matrix, 2, y2, u2, v2)) / 4, 0, 255);
1389 src_y_idx = dest_y_idx = dest_uv_idx = 1;
1390 src_uv_idx = (src_x % 2) + 1;
1393 src_y_idx = dest_y_idx = dest_uv_idx = 0;
1394 src_uv_idx = (src_x % 2);
1397 /* 2.2. Copy all macro pixels from the source to the destination.
1398 * All pixels now start at macro pixel boundary, i.e. no
1399 * blending with the background is necessary. */
1400 for (; j < w - 1; j += 2) {
1401 y1 = srcY[src_y_idx];
1402 y2 = srcY[src_y_idx + 1];
1403 y3 = srcY2[src_y_idx];
1404 y4 = srcY2[src_y_idx + 1];
1406 u1 = srcU[src_uv_idx / 2];
1407 u3 = srcU2[src_uv_idx / 2];
1408 v1 = srcV[src_uv_idx / 2];
1409 v3 = srcV2[src_uv_idx / 2];
1411 u2 = srcU[src_uv_idx / 2];
1412 u4 = srcU2[src_uv_idx / 2];
1413 v2 = srcV[src_uv_idx / 2];
1414 v4 = srcV2[src_uv_idx / 2];
1417 destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
1418 destY[dest_y_idx + 1] =
1419 CLAMP (APPLY_MATRIX (matrix, 0, y2, u2, v2), 0, 255);
1420 destY2[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y3, u3, v3), 0, 255);
1421 destY2[dest_y_idx + 1] =
1422 CLAMP (APPLY_MATRIX (matrix, 0, y4, u4, v4), 0, 255);
1424 destU[dest_uv_idx] = CLAMP (
1425 (APPLY_MATRIX (matrix, 1, y1, u1, v1) + APPLY_MATRIX (matrix, 1, y2,
1426 u2, v2) + APPLY_MATRIX (matrix, 1, y3, u3,
1427 v3) + APPLY_MATRIX (matrix, 1, y4, u4, v4)) / 4, 0, 255);
1428 destV[dest_uv_idx] = CLAMP (
1429 (APPLY_MATRIX (matrix, 2, y1, u1, v1) + APPLY_MATRIX (matrix, 2, y2,
1430 u2, v2) + APPLY_MATRIX (matrix, 2, y3, u3,
1431 v3) + APPLY_MATRIX (matrix, 2, y4, u4, v4)) / 4, 0, 255);
1438 /* 2.3. Now copy the last pixel if one exists and blend it
1439 * with the background because we only fill part of
1440 * the macro pixel. In case this is the last pixel of
1441 * the destination we will a larger part. */
1442 if (j == w - 1 && j == dest_width - 1) {
1443 y1 = srcY[src_y_idx];
1444 y2 = srcY2[src_y_idx];
1446 u1 = srcU[src_uv_idx / 2];
1447 u2 = srcU2[src_uv_idx / 2];
1449 v1 = srcV[src_uv_idx / 2];
1450 v2 = srcV2[src_uv_idx / 2];
1452 destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
1453 destY2[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y2, u2, v2), 0, 255);
1454 destU[dest_uv_idx] = CLAMP (
1455 (APPLY_MATRIX (matrix, 1, y1, u1, v1) + APPLY_MATRIX (matrix, 2, y2,
1456 u2, v2)) / 2, 0, 255);
1457 destV[dest_uv_idx] = CLAMP (
1458 (APPLY_MATRIX (matrix, 1, y1, u1, v1) + APPLY_MATRIX (matrix, 2, y2,
1459 u2, v2)) / 2, 0, 255);
1460 } else if (j == w - 1) {
1461 y1 = srcY[src_y_idx];
1462 y2 = srcY2[src_y_idx];
1464 u1 = srcU[src_uv_idx / 2];
1465 u2 = srcU2[src_uv_idx / 2];
1467 v1 = srcV[src_uv_idx / 2];
1468 v2 = srcV2[src_uv_idx / 2];
1470 destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
1471 destY2[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y2, u2, v2), 0, 255);
1472 destU[dest_uv_idx] = CLAMP (
1473 (2 * destU[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
1474 v1) + APPLY_MATRIX (matrix, 2, y2, u2, v2)) / 4, 0, 255);
1475 destV[dest_uv_idx] = CLAMP (
1476 (2 * destV[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
1477 v1) + APPLY_MATRIX (matrix, 2, y2, u2, v2)) / 4, 0, 255);
1480 destY += 2 * dest_strideY;
1481 destY2 += 2 * dest_strideY;
1482 destU += dest_strideUV;
1483 destV += dest_strideUV;
1484 srcY += 2 * src_strideY;
1485 srcY2 += 2 * src_strideY;
1488 srcU += src_strideUV;
1489 srcV += src_strideUV;
1492 /* 3. Handle the last scanline if one exists. This again
1493 * doesn't start at macro pixel boundary but should
1494 * only fill the upper part of the macro pixels. */
1495 if (i == h - 1 && i == dest_height - 1) {
1496 /* 3.1. Handle the first destination pixel if it doesn't
1497 * start at the macro pixel boundary, i.e. blend with
1498 * the background! */
1499 if (dest_x % 2 == 1) {
1504 destY[0] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
1506 CLAMP ((destU[0] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 2, 0, 255);
1508 CLAMP ((destV[0] + APPLY_MATRIX (matrix, 2, y1, u1, v1)) / 2, 0, 255);
1511 src_y_idx = dest_y_idx = dest_uv_idx = 1;
1512 src_uv_idx = (src_x % 2) + 1;
1515 src_y_idx = dest_y_idx = dest_uv_idx = 0;
1516 src_uv_idx = (src_x % 2);
1519 /* 3.2. Copy all macro pixels from the source to the destination
1520 * but blend with the background because we're only filling
1521 * the upper part of the macro pixels. */
1522 for (; j < w - 1; j += 2) {
1523 y1 = srcY[src_y_idx];
1524 y2 = srcY[src_y_idx + 1];
1526 u1 = srcU[src_uv_idx / 2];
1527 v1 = srcV[src_uv_idx / 2];
1529 u2 = srcU[src_uv_idx / 2];
1530 v2 = srcV[src_uv_idx / 2];
1533 destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
1534 destY[dest_y_idx + 1] =
1535 CLAMP (APPLY_MATRIX (matrix, 0, y2, u2, v2), 0, 255);
1537 destU[dest_uv_idx] = CLAMP (
1538 (2 * destU[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
1539 v1) + APPLY_MATRIX (matrix, 1, y2, u2, v2)) / 4, 0, 255);
1540 destV[dest_uv_idx] = CLAMP (
1541 (2 * destV[dest_uv_idx] + APPLY_MATRIX (matrix, 2, y1, u1,
1542 v1) + APPLY_MATRIX (matrix, 2, y2, u2, v2)) / 4, 0, 255);
1549 /* 3.3. Now copy the last pixel if one exists and blend it
1550 * with the background because we only fill part of
1551 * the macro pixel. In case this is the last pixel of
1552 * the destination we will a larger part. */
1553 if (j == w - 1 && j == dest_width - 1) {
1554 y1 = srcY[src_y_idx];
1555 u1 = srcU[src_uv_idx / 2];
1556 v1 = srcV[src_uv_idx / 2];
1558 destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
1559 destU[dest_uv_idx] = CLAMP (
1560 (destU[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 2, 0,
1562 destV[dest_uv_idx] =
1563 CLAMP ((destV[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
1565 } else if (j == w - 1) {
1566 y1 = srcY[src_y_idx];
1567 u1 = srcU[src_uv_idx / 2];
1568 v1 = srcV[src_uv_idx / 2];
1570 destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
1571 destU[dest_uv_idx] = CLAMP (
1572 (3 * destU[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 4,
1574 destV[dest_uv_idx] =
1575 CLAMP ((3 * destV[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
1578 } else if (i == h - 1) {
1579 /* 3.1. Handle the first destination pixel if it doesn't
1580 * start at the macro pixel boundary, i.e. blend with
1581 * the background! */
1582 if (dest_x % 2 == 1) {
1587 destY[0] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
1589 CLAMP ((3 * destU[0] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 4, 0,
1592 CLAMP ((3 * destV[0] + APPLY_MATRIX (matrix, 2, y1, u1, v1)) / 4, 0,
1596 src_y_idx = dest_y_idx = dest_uv_idx = 1;
1597 src_uv_idx = (src_x % 2) + 1;
1600 src_y_idx = dest_y_idx = dest_uv_idx = 0;
1601 src_uv_idx = (src_x % 2);
1604 /* 3.2. Copy all macro pixels from the source to the destination
1605 * but blend with the background because we're only filling
1606 * the upper part of the macro pixels. */
1607 for (; j < w - 1; j += 2) {
1608 y1 = srcY[src_y_idx];
1609 y2 = srcY[src_y_idx + 1];
1611 u1 = srcU[src_uv_idx / 2];
1612 v1 = srcV[src_uv_idx / 2];
1614 u2 = srcU[src_uv_idx / 2];
1615 v2 = srcV[src_uv_idx / 2];
1618 destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
1619 destY[dest_y_idx + 1] =
1620 CLAMP (APPLY_MATRIX (matrix, 0, y2, u2, v2), 0, 255);
1622 destU[dest_uv_idx] = CLAMP (
1623 (2 * destU[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
1624 v1) + APPLY_MATRIX (matrix, 1, y2, u2, v2)) / 4, 0, 255);
1625 destV[dest_uv_idx] = CLAMP (
1626 (2 * destV[dest_uv_idx] + APPLY_MATRIX (matrix, 2, y1, u1,
1627 v1) + APPLY_MATRIX (matrix, 2, y2, u2, v2)) / 4, 0, 255);
1634 /* 3.3. Now copy the last pixel if one exists and blend it
1635 * with the background because we only fill part of
1636 * the macro pixel. In case this is the last pixel of
1637 * the destination we will a larger part. */
1638 if (j == w - 1 && j == dest_width - 1) {
1639 y1 = srcY[src_y_idx];
1640 u1 = srcU[src_uv_idx / 2];
1641 v1 = srcV[src_uv_idx / 2];
1643 destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
1644 destU[dest_uv_idx] = CLAMP (
1645 (destU[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 2, 0,
1647 destV[dest_uv_idx] =
1648 CLAMP ((destV[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
1650 } else if (j == w - 1) {
1651 y1 = srcY[src_y_idx];
1652 u1 = srcU[src_uv_idx / 2];
1653 v1 = srcV[src_uv_idx / 2];
1655 destY[dest_y_idx] = CLAMP (APPLY_MATRIX (matrix, 0, y1, u1, v1), 0, 255);
1656 destU[dest_uv_idx] = CLAMP (
1657 (3 * destU[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1, v1)) / 4,
1659 destV[dest_uv_idx] =
1660 CLAMP ((3 * destV[dest_uv_idx] + APPLY_MATRIX (matrix, 1, y1, u1,
1667 copy_i420_ayuv (guint i_alpha, GstVideoFormat dest_format, guint8 * dest,
1668 gboolean dest_sdtv, gint dest_width, gint dest_height, gint dest_x,
1669 gint dest_y, GstVideoFormat src_format, const guint8 * src,
1670 gboolean src_sdtv, gint src_width, gint src_height, gint src_x, gint src_y,
1673 const guint8 *srcY, *srcU, *srcV;
1674 gint src_strideY, src_strideUV;
1678 gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 0, src_width);
1680 gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 1, src_width);
1683 src + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 0,
1684 src_width, src_height);
1686 src + gst_video_format_get_component_offset (src_format, 1,
1687 src_width, src_height);
1689 src + gst_video_format_get_component_offset (src_format, 2,
1690 src_width, src_height);
1692 dest_stride = dest_width * 4;
1694 dest = dest + dest_y * dest_stride + dest_x * 4;
1696 srcY = srcY + src_y * src_strideY + src_x;
1697 srcU = srcU + (src_y / 2) * src_strideUV + src_x / 2;
1698 srcV = srcV + (src_y / 2) * src_strideUV + src_x / 2;
1700 i_alpha = CLAMP (i_alpha, 0, 255);
1702 if (src_sdtv != dest_sdtv) {
1709 dest_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
1710 cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit, 12 * sizeof (gint));
1712 for (i = 0; i < h; i++) {
1713 for (j = 0, uv_idx = src_x % 2; j < w; j++, uv_idx++) {
1715 u = srcU[uv_idx / 2];
1716 v = srcV[uv_idx / 2];
1718 y1 = APPLY_MATRIX (matrix, 0, y, u, v);
1719 u1 = APPLY_MATRIX (matrix, 1, y, u, v);
1720 v1 = APPLY_MATRIX (matrix, 2, y, u, v);
1722 dest[4 * j + 0] = i_alpha;
1723 dest[4 * j + 1] = y1;
1724 dest[4 * j + 2] = u1;
1725 dest[4 * j + 3] = v1;
1727 dest += dest_stride;
1730 srcY += src_strideY;
1731 if (src_y % 2 == 0) {
1732 srcU += src_strideUV;
1733 srcV += src_strideUV;
1740 for (i = 0; i < h; i++) {
1741 for (j = 0, uv_idx = src_x % 2; j < w; j++, uv_idx++) {
1743 u = srcU[uv_idx / 2];
1744 v = srcV[uv_idx / 2];
1746 dest[4 * j + 0] = i_alpha;
1747 dest[4 * j + 1] = y;
1748 dest[4 * j + 2] = u;
1749 dest[4 * j + 3] = v;
1751 dest += dest_stride;
1754 srcY += src_strideY;
1755 if (src_y % 2 == 0) {
1756 srcU += src_strideUV;
1757 srcV += src_strideUV;
1764 fill_rgb32 (GstVideoBoxFill fill_type, guint b_alpha, GstVideoFormat format,
1765 guint8 * dest, gboolean sdtv, gint width, gint height)
1767 guint32 empty_pixel;
1770 p[0] = gst_video_format_get_component_offset (format, 3, width, height);
1771 p[1] = gst_video_format_get_component_offset (format, 0, width, height);
1772 p[2] = gst_video_format_get_component_offset (format, 1, width, height);
1773 p[3] = gst_video_format_get_component_offset (format, 2, width, height);
1775 b_alpha = CLAMP (b_alpha, 0, 255);
1777 empty_pixel = GUINT32_FROM_LE ((b_alpha << (p[0] * 8)) |
1778 (rgb_colors_R[fill_type] << (p[1] * 8)) |
1779 (rgb_colors_G[fill_type] << (p[2] * 8)) |
1780 (rgb_colors_B[fill_type] << (p[3] * 8)));
1782 orc_splat_u32 ((guint32 *) dest, empty_pixel, width * height);
1786 fill_rgb24 (GstVideoBoxFill fill_type, guint b_alpha, GstVideoFormat format,
1787 guint8 * dest, gboolean sdtv, gint width, gint height)
1789 gint dest_stride = GST_ROUND_UP_4 (width * 3);
1793 p[0] = gst_video_format_get_component_offset (format, 3, width, height);
1794 p[1] = gst_video_format_get_component_offset (format, 0, width, height);
1795 p[2] = gst_video_format_get_component_offset (format, 1, width, height);
1796 p[3] = gst_video_format_get_component_offset (format, 2, width, height);
1798 for (i = 0; i < height; i++) {
1799 for (j = 0; j < width; j++) {
1800 dest[3 * j + p[1]] = rgb_colors_R[fill_type];
1801 dest[3 * j + p[2]] = rgb_colors_G[fill_type];
1802 dest[3 * j + p[3]] = rgb_colors_B[fill_type];
1804 dest += dest_stride;
1809 copy_rgb32 (guint i_alpha, GstVideoFormat dest_format, guint8 * dest,
1810 gboolean dest_sdtv, gint dest_width, gint dest_height, gint dest_x,
1811 gint dest_y, GstVideoFormat src_format, const guint8 * src,
1812 gboolean src_sdtv, gint src_width, gint src_height, gint src_x, gint src_y,
1816 gint src_stride, dest_stride;
1817 gboolean in_alpha, out_alpha;
1818 gint in_bpp, out_bpp;
1821 gboolean packed_out = (dest_format == GST_VIDEO_FORMAT_RGB
1822 || dest_format == GST_VIDEO_FORMAT_BGR);
1823 gboolean packed_in = (src_format == GST_VIDEO_FORMAT_RGB
1824 || src_format == GST_VIDEO_FORMAT_BGR);
1826 src_stride = (packed_in) ? GST_ROUND_UP_4 (3 * src_width) : 4 * src_width;
1827 dest_stride = (packed_out) ? GST_ROUND_UP_4 (3 * dest_width) : 4 * dest_width;
1828 in_bpp = (packed_in) ? 3 : 4;
1829 out_bpp = (packed_out) ? 3 : 4;
1831 out_alpha = gst_video_format_has_alpha (dest_format);
1833 gst_video_format_get_component_offset (dest_format, 3, dest_width,
1836 gst_video_format_get_component_offset (dest_format, 0, dest_width,
1839 gst_video_format_get_component_offset (dest_format, 1, dest_width,
1842 gst_video_format_get_component_offset (dest_format, 2, dest_width,
1845 in_alpha = gst_video_format_has_alpha (src_format);
1847 gst_video_format_get_component_offset (src_format, 3, src_width,
1850 gst_video_format_get_component_offset (src_format, 0, src_width,
1853 gst_video_format_get_component_offset (src_format, 1, src_width,
1856 gst_video_format_get_component_offset (src_format, 2, src_width,
1859 dest = dest + dest_y * dest_stride + dest_x * out_bpp;
1860 src = src + src_y * src_stride + src_x * in_bpp;
1862 if (in_alpha && out_alpha) {
1864 for (i = 0; i < h; i++) {
1865 for (j = 0; j < w; j += 4) {
1866 dest[j + p_out[0]] = (src[j + p_in[0]] * i_alpha) >> 8;
1867 dest[j + p_out[1]] = src[j + p_in[1]];
1868 dest[j + p_out[2]] = src[j + p_in[2]];
1869 dest[j + p_out[3]] = src[j + p_in[3]];
1871 dest += dest_stride;
1874 } else if (out_alpha && !packed_in) {
1876 i_alpha = CLAMP (i_alpha, 0, 255);
1878 for (i = 0; i < h; i++) {
1879 for (j = 0; j < w; j += 4) {
1880 dest[j + p_out[0]] = i_alpha;
1881 dest[j + p_out[1]] = src[j + p_in[1]];
1882 dest[j + p_out[2]] = src[j + p_in[2]];
1883 dest[j + p_out[3]] = src[j + p_in[3]];
1885 dest += dest_stride;
1888 } else if (out_alpha && packed_in) {
1889 i_alpha = CLAMP (i_alpha, 0, 255);
1891 for (i = 0; i < h; i++) {
1892 for (j = 0; j < w; j++) {
1893 dest[4 * j + p_out[0]] = i_alpha;
1894 dest[4 * j + p_out[1]] = src[in_bpp * j + p_in[1]];
1895 dest[4 * j + p_out[2]] = src[in_bpp * j + p_in[2]];
1896 dest[4 * j + p_out[3]] = src[in_bpp * j + p_in[3]];
1898 dest += dest_stride;
1901 } else if (!packed_out && !packed_in) {
1903 for (i = 0; i < h; i++) {
1904 for (j = 0; j < w; j += 4) {
1905 dest[j + p_out[1]] = src[j + p_in[1]];
1906 dest[j + p_out[2]] = src[j + p_in[2]];
1907 dest[j + p_out[3]] = src[j + p_in[3]];
1909 dest += dest_stride;
1913 for (i = 0; i < h; i++) {
1914 for (j = 0; j < w; j++) {
1915 dest[out_bpp * j + p_out[1]] = src[in_bpp * j + p_in[1]];
1916 dest[out_bpp * j + p_out[2]] = src[in_bpp * j + p_in[2]];
1917 dest[out_bpp * j + p_out[3]] = src[in_bpp * j + p_in[3]];
1919 dest += dest_stride;
1926 copy_rgb32_ayuv (guint i_alpha, GstVideoFormat dest_format, guint8 * dest,
1927 gboolean dest_sdtv, gint dest_width, gint dest_height, gint dest_x,
1928 gint dest_y, GstVideoFormat src_format, const guint8 * src,
1929 gboolean src_sdtv, gint src_width, gint src_height, gint src_x, gint src_y,
1933 gint src_stride, dest_stride;
1937 gboolean packed_in = (src_format == GST_VIDEO_FORMAT_RGB
1938 || src_format == GST_VIDEO_FORMAT_BGR);
1944 src_stride = (packed_in) ? GST_ROUND_UP_4 (3 * src_width) : 4 * src_width;
1945 dest_stride = 4 * dest_width;
1946 in_bpp = (packed_in) ? 3 : 4;
1948 in_alpha = gst_video_format_has_alpha (src_format);
1950 gst_video_format_get_component_offset (src_format, 3, src_width,
1953 gst_video_format_get_component_offset (src_format, 0, src_width,
1956 gst_video_format_get_component_offset (src_format, 1, src_width,
1959 gst_video_format_get_component_offset (src_format, 2, src_width,
1963 (dest_sdtv) ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
1964 cog_rgb_to_ycbcr_matrix_8bit_hdtv, 12 * sizeof (gint));
1966 dest = dest + dest_y * dest_stride + dest_x * 4;
1967 src = src + src_y * src_stride + src_x * in_bpp;
1971 for (i = 0; i < h; i++) {
1972 for (j = 0; j < w; j += 4) {
1973 a = (src[j + p_in[0]] * i_alpha) >> 8;
1974 r = src[j + p_in[1]];
1975 g = src[j + p_in[2]];
1976 b = src[j + p_in[3]];
1978 y = APPLY_MATRIX (matrix, 0, r, g, b);
1979 u = APPLY_MATRIX (matrix, 1, r, g, b);
1980 v = APPLY_MATRIX (matrix, 2, r, g, b);
1983 dest[j + 1] = CLAMP (y, 0, 255);
1984 dest[j + 2] = CLAMP (u, 0, 255);
1985 dest[j + 3] = CLAMP (v, 0, 255);
1987 dest += dest_stride;
1990 } else if (!packed_in) {
1992 i_alpha = CLAMP (i_alpha, 0, 255);
1994 for (i = 0; i < h; i++) {
1995 for (j = 0; j < w; j += 4) {
1997 r = src[j + p_in[1]];
1998 g = src[j + p_in[2]];
1999 b = src[j + p_in[3]];
2001 y = APPLY_MATRIX (matrix, 0, r, g, b);
2002 u = APPLY_MATRIX (matrix, 1, r, g, b);
2003 v = APPLY_MATRIX (matrix, 2, r, g, b);
2006 dest[j + 1] = CLAMP (y, 0, 255);
2007 dest[j + 2] = CLAMP (u, 0, 255);
2008 dest[j + 3] = CLAMP (v, 0, 255);
2010 dest += dest_stride;
2014 i_alpha = CLAMP (i_alpha, 0, 255);
2016 for (i = 0; i < h; i++) {
2017 for (j = 0; j < w; j++) {
2019 r = src[in_bpp * j + p_in[1]];
2020 g = src[in_bpp * j + p_in[2]];
2021 b = src[in_bpp * j + p_in[3]];
2023 y = APPLY_MATRIX (matrix, 0, r, g, b);
2024 u = APPLY_MATRIX (matrix, 1, r, g, b);
2025 v = APPLY_MATRIX (matrix, 2, r, g, b);
2027 dest[4 * j + 0] = a;
2028 dest[4 * j + 1] = CLAMP (y, 0, 255);
2029 dest[4 * j + 2] = CLAMP (u, 0, 255);
2030 dest[4 * j + 3] = CLAMP (v, 0, 255);
2032 dest += dest_stride;
2039 copy_ayuv_rgb32 (guint i_alpha, GstVideoFormat dest_format, guint8 * dest,
2040 gboolean dest_sdtv, gint dest_width, gint dest_height, gint dest_x,
2041 gint dest_y, GstVideoFormat src_format, const guint8 * src,
2042 gboolean src_sdtv, gint src_width, gint src_height, gint src_x, gint src_y,
2046 gint src_stride, dest_stride;
2050 gboolean packed_out = (dest_format == GST_VIDEO_FORMAT_RGB
2051 || dest_format == GST_VIDEO_FORMAT_BGR);
2057 dest_stride = (packed_out) ? GST_ROUND_UP_4 (3 * dest_width) : 4 * dest_width;
2058 src_stride = 4 * src_width;
2059 out_bpp = (packed_out) ? 3 : 4;
2061 out_alpha = gst_video_format_has_alpha (dest_format);
2063 gst_video_format_get_component_offset (dest_format, 3, dest_width,
2066 gst_video_format_get_component_offset (dest_format, 0, dest_width,
2069 gst_video_format_get_component_offset (dest_format, 1, dest_width,
2072 gst_video_format_get_component_offset (dest_format, 2, dest_width,
2076 (src_sdtv) ? cog_ycbcr_to_rgb_matrix_8bit_sdtv :
2077 cog_ycbcr_to_rgb_matrix_8bit_hdtv, 12 * sizeof (gint));
2079 dest = dest + dest_y * dest_stride + dest_x * out_bpp;
2080 src = src + src_y * src_stride + src_x * 4;
2084 for (i = 0; i < h; i++) {
2085 for (j = 0; j < w; j += 4) {
2086 a = (src[j + 0] * i_alpha) >> 8;
2091 r = APPLY_MATRIX (matrix, 0, y, u, v);
2092 g = APPLY_MATRIX (matrix, 1, y, u, v);
2093 b = APPLY_MATRIX (matrix, 2, y, u, v);
2095 dest[j + p_out[0]] = a;
2096 dest[j + p_out[1]] = CLAMP (r, 0, 255);
2097 dest[j + p_out[2]] = CLAMP (g, 0, 255);
2098 dest[j + p_out[3]] = CLAMP (b, 0, 255);
2100 dest += dest_stride;
2103 } else if (!packed_out) {
2105 for (i = 0; i < h; i++) {
2106 for (j = 0; j < w; j += 4) {
2111 r = APPLY_MATRIX (matrix, 0, y, u, v);
2112 g = APPLY_MATRIX (matrix, 1, y, u, v);
2113 b = APPLY_MATRIX (matrix, 2, y, u, v);
2115 dest[j + p_out[1]] = CLAMP (r, 0, 255);
2116 dest[j + p_out[2]] = CLAMP (g, 0, 255);
2117 dest[j + p_out[3]] = CLAMP (b, 0, 255);
2119 dest += dest_stride;
2123 for (i = 0; i < h; i++) {
2124 for (j = 0; j < w; j++) {
2129 r = APPLY_MATRIX (matrix, 0, y, u, v);
2130 g = APPLY_MATRIX (matrix, 1, y, u, v);
2131 b = APPLY_MATRIX (matrix, 2, y, u, v);
2133 dest[out_bpp * j + p_out[1]] = CLAMP (r, 0, 255);
2134 dest[out_bpp * j + p_out[2]] = CLAMP (g, 0, 255);
2135 dest[out_bpp * j + p_out[3]] = CLAMP (b, 0, 255);
2137 dest += dest_stride;
2144 fill_gray (GstVideoBoxFill fill_type, guint b_alpha, GstVideoFormat format,
2145 guint8 * dest, gboolean sdtv, gint width, gint height)
2150 if (format == GST_VIDEO_FORMAT_GRAY8) {
2151 guint8 val = yuv_sdtv_colors_Y[fill_type];
2153 dest_stride = GST_ROUND_UP_4 (width);
2154 for (i = 0; i < height; i++) {
2155 memset (dest, val, width);
2156 dest += dest_stride;
2159 guint16 val = yuv_sdtv_colors_Y[fill_type] << 8;
2161 dest_stride = GST_ROUND_UP_4 (width * 2);
2162 if (format == GST_VIDEO_FORMAT_GRAY16_BE) {
2163 for (i = 0; i < height; i++) {
2164 for (j = 0; j < width; j++) {
2165 GST_WRITE_UINT16_BE (dest + 2 * j, val);
2167 dest += dest_stride;
2170 for (i = 0; i < height; i++) {
2171 for (j = 0; j < width; j++) {
2172 GST_WRITE_UINT16_LE (dest + 2 * j, val);
2174 dest += dest_stride;
2181 copy_packed_simple (guint i_alpha, GstVideoFormat dest_format, guint8 * dest,
2182 gboolean dest_sdtv, gint dest_width, gint dest_height, gint dest_x,
2183 gint dest_y, GstVideoFormat src_format, const guint8 * src,
2184 gboolean src_sdtv, gint src_width, gint src_height, gint src_x, gint src_y,
2188 gint src_stride, dest_stride;
2189 gint pixel_stride, row_size;
2191 src_stride = gst_video_format_get_row_stride (src_format, 0, src_width);
2192 dest_stride = gst_video_format_get_row_stride (dest_format, 0, dest_width);
2193 pixel_stride = gst_video_format_get_pixel_stride (dest_format, 0);
2194 row_size = w * pixel_stride;
2196 dest = dest + dest_y * dest_stride + dest_x * pixel_stride;
2197 src = src + src_y * src_stride + src_x * pixel_stride;
2199 for (i = 0; i < h; i++) {
2200 memcpy (dest, src, row_size);
2201 dest += dest_stride;
2207 fill_yuy2 (GstVideoBoxFill fill_type, guint b_alpha, GstVideoFormat format,
2208 guint8 * dest, gboolean sdtv, gint width, gint height)
2212 gint stride = gst_video_format_get_row_stride (format, 0, width);
2214 y = (sdtv) ? yuv_sdtv_colors_Y[fill_type] : yuv_hdtv_colors_Y[fill_type];
2215 u = (sdtv) ? yuv_sdtv_colors_U[fill_type] : yuv_hdtv_colors_U[fill_type];
2216 v = (sdtv) ? yuv_sdtv_colors_V[fill_type] : yuv_hdtv_colors_V[fill_type];
2218 width = width + (width % 2);
2220 if (format == GST_VIDEO_FORMAT_YUY2) {
2221 for (i = 0; i < height; i++) {
2222 for (j = 0; j < width; j += 2) {
2223 dest[j * 2 + 0] = y;
2224 dest[j * 2 + 1] = u;
2225 dest[j * 2 + 2] = y;
2226 dest[j * 2 + 3] = v;
2231 } else if (format == GST_VIDEO_FORMAT_YVYU) {
2232 for (i = 0; i < height; i++) {
2233 for (j = 0; j < width; j += 2) {
2234 dest[j * 2 + 0] = y;
2235 dest[j * 2 + 1] = v;
2236 dest[j * 2 + 2] = y;
2237 dest[j * 2 + 3] = u;
2243 for (i = 0; i < height; i++) {
2244 for (j = 0; j < width; j += 2) {
2245 dest[j * 2 + 0] = u;
2246 dest[j * 2 + 1] = y;
2247 dest[j * 2 + 2] = v;
2248 dest[j * 2 + 3] = y;
2257 copy_yuy2_yuy2 (guint i_alpha, GstVideoFormat dest_format, guint8 * dest,
2258 gboolean dest_sdtv, gint dest_width, gint dest_height, gint dest_x,
2259 gint dest_y, GstVideoFormat src_format, const guint8 * src,
2260 gboolean src_sdtv, gint src_width, gint src_height, gint src_x, gint src_y,
2264 gint src_stride, dest_stride;
2266 src_stride = gst_video_format_get_row_stride (src_format, 0, src_width);
2267 dest_stride = gst_video_format_get_row_stride (dest_format, 0, dest_width);
2269 dest_x = (dest_x & ~1);
2270 src_x = (src_x & ~1);
2274 dest = dest + dest_y * dest_stride + dest_x * 2;
2275 src = src + src_y * src_stride + src_x * 2;
2277 if (src_sdtv != dest_sdtv) {
2283 dest_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
2284 cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit, 12 * sizeof (gint));
2286 if (src_format == GST_VIDEO_FORMAT_YUY2) {
2287 for (i = 0; i < h; i++) {
2288 for (j = 0; j < w; j += 2) {
2289 y1 = src[j * 2 + 0];
2290 y2 = src[j * 2 + 2];
2291 u1 = u2 = src[j * 2 + 1];
2292 v1 = v2 = src[j * 2 + 3];
2294 dest[j * 2 + 0] = APPLY_MATRIX (matrix, 0, y1, u1, v1);
2295 dest[j * 2 + 1] = APPLY_MATRIX (matrix, 1, y1, u1, v1);
2296 dest[j * 2 + 2] = APPLY_MATRIX (matrix, 0, y1, u2, v2);
2297 dest[j * 2 + 3] = APPLY_MATRIX (matrix, 2, y2, u2, v2);
2299 dest += dest_stride;
2302 } else if (src_format == GST_VIDEO_FORMAT_YVYU) {
2303 for (i = 0; i < h; i++) {
2304 for (j = 0; j < w; j += 2) {
2305 y1 = src[j * 2 + 0];
2306 y2 = src[j * 2 + 2];
2307 v1 = v2 = src[j * 2 + 1];
2308 u1 = u2 = src[j * 2 + 3];
2310 dest[j * 2 + 0] = APPLY_MATRIX (matrix, 0, y1, u1, v1);
2311 dest[j * 2 + 1] = APPLY_MATRIX (matrix, 2, y1, u1, v1);
2312 dest[j * 2 + 2] = APPLY_MATRIX (matrix, 0, y1, u2, v2);
2313 dest[j * 2 + 3] = APPLY_MATRIX (matrix, 1, y2, u2, v2);
2315 dest += dest_stride;
2319 for (i = 0; i < h; i++) {
2320 for (j = 0; j < w; j += 2) {
2321 u1 = u2 = src[j * 2 + 0];
2322 v1 = v2 = src[j * 2 + 2];
2323 y1 = src[j * 2 + 1];
2324 y2 = src[j * 2 + 3];
2326 dest[j * 2 + 1] = APPLY_MATRIX (matrix, 0, y1, u1, v1);
2327 dest[j * 2 + 0] = APPLY_MATRIX (matrix, 1, y1, u1, v1);
2328 dest[j * 2 + 3] = APPLY_MATRIX (matrix, 0, y1, u2, v2);
2329 dest[j * 2 + 2] = APPLY_MATRIX (matrix, 2, y2, u2, v2);
2331 dest += dest_stride;
2336 for (i = 0; i < h; i++) {
2337 memcpy (dest, src, w * 2);
2338 dest += dest_stride;
2344 #define DEFAULT_LEFT 0
2345 #define DEFAULT_RIGHT 0
2346 #define DEFAULT_TOP 0
2347 #define DEFAULT_BOTTOM 0
2348 #define DEFAULT_FILL_TYPE VIDEO_BOX_FILL_BLACK
2349 #define DEFAULT_ALPHA 1.0
2350 #define DEFAULT_BORDER_ALPHA 1.0
2366 static GstStaticPadTemplate gst_video_box_src_template =
2367 GST_STATIC_PAD_TEMPLATE ("src",
2370 GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV") ";"
2371 GST_VIDEO_CAPS_ARGB ";" GST_VIDEO_CAPS_BGRA ";"
2372 GST_VIDEO_CAPS_ABGR ";" GST_VIDEO_CAPS_RGBA ";"
2373 GST_VIDEO_CAPS_xRGB ";" GST_VIDEO_CAPS_BGRx ";"
2374 GST_VIDEO_CAPS_xBGR ";" GST_VIDEO_CAPS_RGBx ";"
2375 GST_VIDEO_CAPS_RGB ";" GST_VIDEO_CAPS_BGR ";"
2376 GST_VIDEO_CAPS_YUV ("Y444") ";"
2377 GST_VIDEO_CAPS_YUV ("Y42B") ";"
2378 GST_VIDEO_CAPS_YUV ("YUY2") ";"
2379 GST_VIDEO_CAPS_YUV ("YVYU") ";"
2380 GST_VIDEO_CAPS_YUV ("UYVY") ";"
2381 GST_VIDEO_CAPS_YUV ("I420") ";"
2382 GST_VIDEO_CAPS_YUV ("YV12") ";"
2383 GST_VIDEO_CAPS_YUV ("Y41B") ";"
2384 GST_VIDEO_CAPS_GRAY8 ";"
2385 GST_VIDEO_CAPS_GRAY16 ("BIG_ENDIAN") ";"
2386 GST_VIDEO_CAPS_GRAY16 ("LITTLE_ENDIAN"))
2389 static GstStaticPadTemplate gst_video_box_sink_template =
2390 GST_STATIC_PAD_TEMPLATE ("sink",
2393 GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV") ";"
2394 GST_VIDEO_CAPS_ARGB ";" GST_VIDEO_CAPS_BGRA ";"
2395 GST_VIDEO_CAPS_ABGR ";" GST_VIDEO_CAPS_RGBA ";"
2396 GST_VIDEO_CAPS_xRGB ";" GST_VIDEO_CAPS_BGRx ";"
2397 GST_VIDEO_CAPS_xBGR ";" GST_VIDEO_CAPS_RGBx ";"
2398 GST_VIDEO_CAPS_RGB ";" GST_VIDEO_CAPS_BGR ";"
2399 GST_VIDEO_CAPS_YUV ("Y444") ";"
2400 GST_VIDEO_CAPS_YUV ("Y42B") ";"
2401 GST_VIDEO_CAPS_YUV ("YUY2") ";"
2402 GST_VIDEO_CAPS_YUV ("YVYU") ";"
2403 GST_VIDEO_CAPS_YUV ("UYVY") ";"
2404 GST_VIDEO_CAPS_YUV ("I420") ";"
2405 GST_VIDEO_CAPS_YUV ("YV12") ";"
2406 GST_VIDEO_CAPS_YUV ("Y41B") ";"
2407 GST_VIDEO_CAPS_GRAY8 ";"
2408 GST_VIDEO_CAPS_GRAY16 ("BIG_ENDIAN") ";"
2409 GST_VIDEO_CAPS_GRAY16 ("LITTLE_ENDIAN"))
2412 GST_BOILERPLATE (GstVideoBox, gst_video_box, GstBaseTransform,
2413 GST_TYPE_BASE_TRANSFORM);
2415 static void gst_video_box_set_property (GObject * object, guint prop_id,
2416 const GValue * value, GParamSpec * pspec);
2417 static void gst_video_box_get_property (GObject * object, guint prop_id,
2418 GValue * value, GParamSpec * pspec);
2420 static gboolean gst_video_box_recalc_transform (GstVideoBox * video_box);
2421 static GstCaps *gst_video_box_transform_caps (GstBaseTransform * trans,
2422 GstPadDirection direction, GstCaps * from);
2423 static gboolean gst_video_box_set_caps (GstBaseTransform * trans,
2424 GstCaps * in, GstCaps * out);
2425 static gboolean gst_video_box_get_unit_size (GstBaseTransform * trans,
2426 GstCaps * caps, guint * size);
2427 static GstFlowReturn gst_video_box_transform (GstBaseTransform * trans,
2428 GstBuffer * in, GstBuffer * out);
2429 static void gst_video_box_before_transform (GstBaseTransform * trans,
2431 static void gst_video_box_fixate_caps (GstBaseTransform * trans,
2432 GstPadDirection direction, GstCaps * caps, GstCaps * othercaps);
2433 static gboolean gst_video_box_src_event (GstBaseTransform * trans,
2436 #define GST_TYPE_VIDEO_BOX_FILL (gst_video_box_fill_get_type())
2438 gst_video_box_fill_get_type (void)
2440 static GType video_box_fill_type = 0;
2441 static const GEnumValue video_box_fill[] = {
2442 {VIDEO_BOX_FILL_BLACK, "Black", "black"},
2443 {VIDEO_BOX_FILL_GREEN, "Green", "green"},
2444 {VIDEO_BOX_FILL_BLUE, "Blue", "blue"},
2445 {VIDEO_BOX_FILL_RED, "Red", "red"},
2446 {VIDEO_BOX_FILL_YELLOW, "Yellow", "yellow"},
2447 {VIDEO_BOX_FILL_WHITE, "White", "white"},
2451 if (!video_box_fill_type) {
2452 video_box_fill_type =
2453 g_enum_register_static ("GstVideoBoxFill", video_box_fill);
2455 return video_box_fill_type;
2460 gst_video_box_base_init (gpointer g_class)
2462 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
2464 gst_element_class_set_details_simple (element_class, "Video box filter",
2465 "Filter/Effect/Video",
2466 "Resizes a video by adding borders or cropping",
2467 "Wim Taymans <wim@fluendo.com>");
2469 gst_element_class_add_pad_template (element_class,
2470 gst_static_pad_template_get (&gst_video_box_sink_template));
2471 gst_element_class_add_pad_template (element_class,
2472 gst_static_pad_template_get (&gst_video_box_src_template));
2476 gst_video_box_finalize (GObject * object)
2478 GstVideoBox *video_box = GST_VIDEO_BOX (object);
2480 if (video_box->mutex) {
2481 g_mutex_free (video_box->mutex);
2482 video_box->mutex = NULL;
2485 G_OBJECT_CLASS (parent_class)->finalize (object);
2489 gst_video_box_class_init (GstVideoBoxClass * klass)
2491 GObjectClass *gobject_class = (GObjectClass *) klass;
2492 GstBaseTransformClass *trans_class = (GstBaseTransformClass *) klass;
2494 gobject_class->set_property = gst_video_box_set_property;
2495 gobject_class->get_property = gst_video_box_get_property;
2496 gobject_class->finalize = gst_video_box_finalize;
2498 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_FILL_TYPE,
2499 g_param_spec_enum ("fill", "Fill", "How to fill the borders",
2500 GST_TYPE_VIDEO_BOX_FILL, DEFAULT_FILL_TYPE,
2501 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
2502 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LEFT,
2503 g_param_spec_int ("left", "Left",
2504 "Pixels to box at left (<0 = add a border)", G_MININT, G_MAXINT,
2506 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
2507 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_RIGHT,
2508 g_param_spec_int ("right", "Right",
2509 "Pixels to box at right (<0 = add a border)", G_MININT, G_MAXINT,
2511 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
2512 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TOP,
2513 g_param_spec_int ("top", "Top",
2514 "Pixels to box at top (<0 = add a border)", G_MININT, G_MAXINT,
2516 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
2517 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BOTTOM,
2518 g_param_spec_int ("bottom", "Bottom",
2519 "Pixels to box at bottom (<0 = add a border)", G_MININT, G_MAXINT,
2521 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
2522 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ALPHA,
2523 g_param_spec_double ("alpha", "Alpha", "Alpha value picture", 0.0, 1.0,
2525 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
2526 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BORDER_ALPHA,
2527 g_param_spec_double ("border-alpha", "Border Alpha",
2528 "Alpha value of the border", 0.0, 1.0, DEFAULT_BORDER_ALPHA,
2529 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
2531 * GstVideoBox:autocrop
2533 * If set to %TRUE videobox will automatically crop/pad the input
2534 * video to be centered in the output.
2538 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_AUTOCROP,
2539 g_param_spec_boolean ("autocrop", "Auto crop",
2540 "Auto crop", FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
2542 trans_class->transform = GST_DEBUG_FUNCPTR (gst_video_box_transform);
2543 trans_class->before_transform =
2544 GST_DEBUG_FUNCPTR (gst_video_box_before_transform);
2545 trans_class->transform_caps =
2546 GST_DEBUG_FUNCPTR (gst_video_box_transform_caps);
2547 trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_video_box_set_caps);
2548 trans_class->get_unit_size = GST_DEBUG_FUNCPTR (gst_video_box_get_unit_size);
2549 trans_class->fixate_caps = GST_DEBUG_FUNCPTR (gst_video_box_fixate_caps);
2550 trans_class->src_event = GST_DEBUG_FUNCPTR (gst_video_box_src_event);
2554 gst_video_box_init (GstVideoBox * video_box, GstVideoBoxClass * g_class)
2556 video_box->box_right = DEFAULT_RIGHT;
2557 video_box->box_left = DEFAULT_LEFT;
2558 video_box->box_top = DEFAULT_TOP;
2559 video_box->box_bottom = DEFAULT_BOTTOM;
2560 video_box->crop_right = 0;
2561 video_box->crop_left = 0;
2562 video_box->crop_top = 0;
2563 video_box->crop_bottom = 0;
2564 video_box->fill_type = DEFAULT_FILL_TYPE;
2565 video_box->alpha = DEFAULT_ALPHA;
2566 video_box->border_alpha = DEFAULT_BORDER_ALPHA;
2567 video_box->autocrop = FALSE;
2569 video_box->mutex = g_mutex_new ();
2573 gst_video_box_set_property (GObject * object, guint prop_id,
2574 const GValue * value, GParamSpec * pspec)
2576 GstVideoBox *video_box = GST_VIDEO_BOX (object);
2578 g_mutex_lock (video_box->mutex);
2581 video_box->box_left = g_value_get_int (value);
2582 if (video_box->box_left < 0) {
2583 video_box->border_left = -video_box->box_left;
2584 video_box->crop_left = 0;
2586 video_box->border_left = 0;
2587 video_box->crop_left = video_box->box_left;
2591 video_box->box_right = g_value_get_int (value);
2592 if (video_box->box_right < 0) {
2593 video_box->border_right = -video_box->box_right;
2594 video_box->crop_right = 0;
2596 video_box->border_right = 0;
2597 video_box->crop_right = video_box->box_right;
2601 video_box->box_top = g_value_get_int (value);
2602 if (video_box->box_top < 0) {
2603 video_box->border_top = -video_box->box_top;
2604 video_box->crop_top = 0;
2606 video_box->border_top = 0;
2607 video_box->crop_top = video_box->box_top;
2611 video_box->box_bottom = g_value_get_int (value);
2612 if (video_box->box_bottom < 0) {
2613 video_box->border_bottom = -video_box->box_bottom;
2614 video_box->crop_bottom = 0;
2616 video_box->border_bottom = 0;
2617 video_box->crop_bottom = video_box->box_bottom;
2620 case PROP_FILL_TYPE:
2621 video_box->fill_type = g_value_get_enum (value);
2624 video_box->alpha = g_value_get_double (value);
2626 case PROP_BORDER_ALPHA:
2627 video_box->border_alpha = g_value_get_double (value);
2630 video_box->autocrop = g_value_get_boolean (value);
2633 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2636 gst_video_box_recalc_transform (video_box);
2638 GST_DEBUG_OBJECT (video_box, "Calling reconfigure");
2639 gst_base_transform_reconfigure (GST_BASE_TRANSFORM_CAST (video_box));
2641 g_mutex_unlock (video_box->mutex);
2645 gst_video_box_autocrop (GstVideoBox * video_box)
2647 gint crop_w = video_box->in_width - video_box->out_width;
2648 gint crop_h = video_box->in_height - video_box->out_height;
2650 video_box->box_left = crop_w / 2;
2651 if (video_box->box_left < 0) {
2652 video_box->border_left = -video_box->box_left;
2653 video_box->crop_left = 0;
2655 video_box->border_left = 0;
2656 video_box->crop_left = video_box->box_left;
2659 /* Round down/up for odd width differences */
2665 video_box->box_right = crop_w / 2;
2666 if (video_box->box_right < 0) {
2667 video_box->border_right = -video_box->box_right;
2668 video_box->crop_right = 0;
2670 video_box->border_right = 0;
2671 video_box->crop_right = video_box->box_right;
2674 video_box->box_top = crop_h / 2;
2675 if (video_box->box_top < 0) {
2676 video_box->border_top = -video_box->box_top;
2677 video_box->crop_top = 0;
2679 video_box->border_top = 0;
2680 video_box->crop_top = video_box->box_top;
2683 /* Round down/up for odd height differences */
2688 video_box->box_bottom = crop_h / 2;
2690 if (video_box->box_bottom < 0) {
2691 video_box->border_bottom = -video_box->box_bottom;
2692 video_box->crop_bottom = 0;
2694 video_box->border_bottom = 0;
2695 video_box->crop_bottom = video_box->box_bottom;
2700 gst_video_box_get_property (GObject * object, guint prop_id, GValue * value,
2703 GstVideoBox *video_box = GST_VIDEO_BOX (object);
2707 g_value_set_int (value, video_box->box_left);
2710 g_value_set_int (value, video_box->box_right);
2713 g_value_set_int (value, video_box->box_top);
2716 g_value_set_int (value, video_box->box_bottom);
2718 case PROP_FILL_TYPE:
2719 g_value_set_enum (value, video_box->fill_type);
2722 g_value_set_double (value, video_box->alpha);
2724 case PROP_BORDER_ALPHA:
2725 g_value_set_double (value, video_box->border_alpha);
2728 g_value_set_boolean (value, video_box->autocrop);
2731 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2737 gst_video_box_transform_dimension (gint val, gint delta)
2739 gint64 new_val = (gint64) val + (gint64) delta;
2741 new_val = CLAMP (new_val, 1, G_MAXINT);
2743 return (gint) new_val;
2747 gst_video_box_transform_dimension_value (const GValue * src_val,
2748 gint delta, GValue * dest_val)
2750 gboolean ret = TRUE;
2752 g_value_init (dest_val, G_VALUE_TYPE (src_val));
2754 if (G_VALUE_HOLDS_INT (src_val)) {
2755 gint ival = g_value_get_int (src_val);
2757 ival = gst_video_box_transform_dimension (ival, delta);
2758 g_value_set_int (dest_val, ival);
2759 } else if (GST_VALUE_HOLDS_INT_RANGE (src_val)) {
2760 gint min = gst_value_get_int_range_min (src_val);
2761 gint max = gst_value_get_int_range_max (src_val);
2763 min = gst_video_box_transform_dimension (min, delta);
2764 max = gst_video_box_transform_dimension (max, delta);
2767 g_value_unset (dest_val);
2769 gst_value_set_int_range (dest_val, min, max);
2771 } else if (GST_VALUE_HOLDS_LIST (src_val)) {
2774 for (i = 0; i < gst_value_list_get_size (src_val); ++i) {
2775 const GValue *list_val;
2776 GValue newval = { 0, };
2778 list_val = gst_value_list_get_value (src_val, i);
2779 if (gst_video_box_transform_dimension_value (list_val, delta, &newval))
2780 gst_value_list_append_value (dest_val, &newval);
2781 g_value_unset (&newval);
2784 if (gst_value_list_get_size (dest_val) == 0) {
2785 g_value_unset (dest_val);
2789 g_value_unset (dest_val);
2797 gst_video_box_transform_caps (GstBaseTransform * trans,
2798 GstPadDirection direction, GstCaps * from)
2800 GstVideoBox *video_box = GST_VIDEO_BOX (trans);
2802 const GstCaps *templ;
2804 GstStructure *structure;
2807 to = gst_caps_copy (from);
2808 /* Just to be sure... */
2809 gst_caps_truncate (to);
2810 structure = gst_caps_get_structure (to, 0);
2812 /* Transform width/height */
2813 if (video_box->autocrop) {
2814 gst_structure_remove_field (structure, "width");
2815 gst_structure_remove_field (structure, "height");
2817 gint dw = 0, dh = 0;
2819 GValue w_val = { 0, };
2820 GValue h_val = { 0, };
2822 /* calculate width and height */
2823 if (direction == GST_PAD_SINK) {
2824 dw -= video_box->box_left;
2825 dw -= video_box->box_right;
2827 dw += video_box->box_left;
2828 dw += video_box->box_right;
2831 if (direction == GST_PAD_SINK) {
2832 dh -= video_box->box_top;
2833 dh -= video_box->box_bottom;
2835 dh += video_box->box_top;
2836 dh += video_box->box_bottom;
2839 v = gst_structure_get_value (structure, "width");
2840 if (!gst_video_box_transform_dimension_value (v, dw, &w_val)) {
2841 GST_WARNING_OBJECT (video_box, "could not tranform width value with dw=%d"
2842 ", caps structure=%" GST_PTR_FORMAT, dw, structure);
2843 gst_caps_unref (to);
2844 to = gst_caps_new_empty ();
2847 gst_structure_set_value (structure, "width", &w_val);
2849 v = gst_structure_get_value (structure, "height");
2850 if (!gst_video_box_transform_dimension_value (v, dh, &h_val)) {
2851 g_value_unset (&w_val);
2852 GST_WARNING_OBJECT (video_box,
2853 "could not tranform height value with dh=%d" ", caps structure=%"
2854 GST_PTR_FORMAT, dh, structure);
2855 gst_caps_unref (to);
2856 to = gst_caps_new_empty ();
2859 gst_structure_set_value (structure, "height", &h_val);
2860 g_value_unset (&w_val);
2861 g_value_unset (&h_val);
2864 /* Supported conversions:
2871 * AYUV->xRGB (24bpp, 32bpp, incl. alpha)
2872 * xRGB->xRGB (24bpp, 32bpp, from/to all variants, incl. alpha)
2873 * xRGB->AYUV (24bpp, 32bpp, incl. alpha)
2875 * Passthrough only for everything else.
2877 name = gst_structure_get_name (structure);
2878 if (g_str_equal (name, "video/x-raw-yuv")) {
2881 if (gst_structure_get_fourcc (structure, "format", &fourcc) &&
2882 (fourcc == GST_STR_FOURCC ("AYUV") ||
2883 fourcc == GST_STR_FOURCC ("I420") ||
2884 fourcc == GST_STR_FOURCC ("YV12"))) {
2885 GValue list = { 0, };
2886 GValue val = { 0, };
2889 /* get rid of format */
2890 gst_structure_remove_field (structure, "format");
2891 gst_structure_remove_field (structure, "color-matrix");
2892 gst_structure_remove_field (structure, "chroma-site");
2894 s2 = gst_structure_copy (structure);
2896 g_value_init (&list, GST_TYPE_LIST);
2897 g_value_init (&val, GST_TYPE_FOURCC);
2898 gst_value_set_fourcc (&val, GST_STR_FOURCC ("AYUV"));
2899 gst_value_list_append_value (&list, &val);
2900 g_value_reset (&val);
2901 gst_value_set_fourcc (&val, GST_STR_FOURCC ("I420"));
2902 gst_value_list_append_value (&list, &val);
2903 g_value_reset (&val);
2904 gst_value_set_fourcc (&val, GST_STR_FOURCC ("YV12"));
2905 gst_value_list_append_value (&list, &val);
2906 g_value_unset (&val);
2907 gst_structure_set_value (structure, "format", &list);
2908 g_value_unset (&list);
2910 /* We can only convert to RGB if input is AYUV */
2911 if (fourcc == GST_STR_FOURCC ("AYUV")) {
2912 gst_structure_set_name (s2, "video/x-raw-rgb");
2913 g_value_init (&list, GST_TYPE_LIST);
2914 g_value_init (&val, G_TYPE_INT);
2915 g_value_set_int (&val, 32);
2916 gst_value_list_append_value (&list, &val);
2917 g_value_reset (&val);
2918 g_value_set_int (&val, 24);
2919 gst_value_list_append_value (&list, &val);
2920 g_value_unset (&val);
2921 gst_structure_set_value (s2, "depth", &list);
2922 gst_structure_set_value (s2, "bpp", &list);
2923 g_value_unset (&list);
2924 gst_caps_append_structure (to, s2);
2926 gst_structure_free (s2);
2929 } else if (g_str_equal (name, "video/x-raw-rgb")) {
2932 if (gst_structure_get_int (structure, "bpp", &bpp) &&
2933 (bpp == 32 || bpp == 24)) {
2934 GValue list = { 0, };
2935 GValue val = { 0, };
2938 /* get rid of format */
2939 gst_structure_remove_field (structure, "depth");
2940 gst_structure_remove_field (structure, "bpp");
2941 gst_structure_remove_field (structure, "red_mask");
2942 gst_structure_remove_field (structure, "green_mask");
2943 gst_structure_remove_field (structure, "blue_mask");
2944 gst_structure_remove_field (structure, "alpha_mask");
2946 s2 = gst_structure_copy (structure);
2948 g_value_init (&list, GST_TYPE_LIST);
2949 g_value_init (&val, G_TYPE_INT);
2950 g_value_set_int (&val, 32);
2951 gst_value_list_append_value (&list, &val);
2952 g_value_reset (&val);
2953 g_value_set_int (&val, 24);
2954 gst_value_list_append_value (&list, &val);
2955 g_value_unset (&val);
2956 gst_structure_set_value (structure, "depth", &list);
2957 gst_structure_set_value (structure, "bpp", &list);
2958 g_value_unset (&list);
2960 gst_structure_set_name (s2, "video/x-raw-yuv");
2961 gst_structure_set (s2, "format", GST_TYPE_FOURCC, GST_STR_FOURCC ("AYUV"),
2963 gst_caps_append_structure (to, s2);
2967 /* filter against set allowed caps on the pad */
2968 other = (direction == GST_PAD_SINK) ? trans->srcpad : trans->sinkpad;
2970 templ = gst_pad_get_pad_template_caps (other);
2971 ret = gst_caps_intersect (to, templ);
2972 gst_caps_unref (to);
2974 GST_DEBUG_OBJECT (video_box, "direction %d, transformed %" GST_PTR_FORMAT
2975 " to %" GST_PTR_FORMAT, direction, from, ret);
2981 gst_video_box_recalc_transform (GstVideoBox * video_box)
2983 gboolean res = TRUE;
2985 /* if we have the same format in and out and we don't need to perform any
2986 * cropping at all, we can just operate in passthrough mode */
2987 if (video_box->in_format == video_box->out_format &&
2988 video_box->box_left == 0 && video_box->box_right == 0 &&
2989 video_box->box_top == 0 && video_box->box_bottom == 0 &&
2990 video_box->in_sdtv == video_box->out_sdtv) {
2992 GST_LOG_OBJECT (video_box, "we are using passthrough");
2993 gst_base_transform_set_passthrough (GST_BASE_TRANSFORM_CAST (video_box),
2996 GST_LOG_OBJECT (video_box, "we are not using passthrough");
2997 gst_base_transform_set_passthrough (GST_BASE_TRANSFORM_CAST (video_box),
3004 gst_video_box_select_processing_functions (GstVideoBox * video_box)
3006 switch (video_box->out_format) {
3007 case GST_VIDEO_FORMAT_AYUV:
3008 video_box->fill = fill_ayuv;
3009 switch (video_box->in_format) {
3010 case GST_VIDEO_FORMAT_AYUV:
3011 video_box->copy = copy_ayuv_ayuv;
3013 case GST_VIDEO_FORMAT_I420:
3014 case GST_VIDEO_FORMAT_YV12:
3015 video_box->copy = copy_i420_ayuv;
3017 case GST_VIDEO_FORMAT_ARGB:
3018 case GST_VIDEO_FORMAT_ABGR:
3019 case GST_VIDEO_FORMAT_RGBA:
3020 case GST_VIDEO_FORMAT_BGRA:
3021 case GST_VIDEO_FORMAT_xRGB:
3022 case GST_VIDEO_FORMAT_xBGR:
3023 case GST_VIDEO_FORMAT_RGBx:
3024 case GST_VIDEO_FORMAT_BGRx:
3025 case GST_VIDEO_FORMAT_RGB:
3026 case GST_VIDEO_FORMAT_BGR:
3027 video_box->copy = copy_rgb32_ayuv;
3033 case GST_VIDEO_FORMAT_I420:
3034 case GST_VIDEO_FORMAT_YV12:
3035 video_box->fill = fill_planar_yuv;
3036 switch (video_box->in_format) {
3037 case GST_VIDEO_FORMAT_AYUV:
3038 video_box->copy = copy_ayuv_i420;
3040 case GST_VIDEO_FORMAT_I420:
3041 case GST_VIDEO_FORMAT_YV12:
3042 video_box->copy = copy_i420_i420;
3048 case GST_VIDEO_FORMAT_ARGB:
3049 case GST_VIDEO_FORMAT_ABGR:
3050 case GST_VIDEO_FORMAT_RGBA:
3051 case GST_VIDEO_FORMAT_BGRA:
3052 case GST_VIDEO_FORMAT_xRGB:
3053 case GST_VIDEO_FORMAT_xBGR:
3054 case GST_VIDEO_FORMAT_RGBx:
3055 case GST_VIDEO_FORMAT_BGRx:
3056 case GST_VIDEO_FORMAT_RGB:
3057 case GST_VIDEO_FORMAT_BGR:
3058 video_box->fill = (video_box->out_format == GST_VIDEO_FORMAT_BGR
3059 || video_box->out_format ==
3060 GST_VIDEO_FORMAT_RGB) ? fill_rgb24 : fill_rgb32;
3061 switch (video_box->in_format) {
3062 case GST_VIDEO_FORMAT_ARGB:
3063 case GST_VIDEO_FORMAT_ABGR:
3064 case GST_VIDEO_FORMAT_RGBA:
3065 case GST_VIDEO_FORMAT_BGRA:
3066 case GST_VIDEO_FORMAT_xRGB:
3067 case GST_VIDEO_FORMAT_xBGR:
3068 case GST_VIDEO_FORMAT_RGBx:
3069 case GST_VIDEO_FORMAT_BGRx:
3070 case GST_VIDEO_FORMAT_RGB:
3071 case GST_VIDEO_FORMAT_BGR:
3072 video_box->copy = copy_rgb32;
3074 case GST_VIDEO_FORMAT_AYUV:
3075 video_box->copy = copy_ayuv_rgb32;
3080 case GST_VIDEO_FORMAT_GRAY8:
3081 case GST_VIDEO_FORMAT_GRAY16_BE:
3082 case GST_VIDEO_FORMAT_GRAY16_LE:
3083 video_box->fill = fill_gray;
3084 switch (video_box->in_format) {
3085 case GST_VIDEO_FORMAT_GRAY8:
3086 case GST_VIDEO_FORMAT_GRAY16_BE:
3087 case GST_VIDEO_FORMAT_GRAY16_LE:
3088 video_box->copy = copy_packed_simple;
3094 case GST_VIDEO_FORMAT_YUY2:
3095 case GST_VIDEO_FORMAT_YVYU:
3096 case GST_VIDEO_FORMAT_UYVY:
3097 video_box->fill = fill_yuy2;
3098 switch (video_box->in_format) {
3099 case GST_VIDEO_FORMAT_YUY2:
3100 case GST_VIDEO_FORMAT_YVYU:
3101 case GST_VIDEO_FORMAT_UYVY:
3102 video_box->copy = copy_yuy2_yuy2;
3108 case GST_VIDEO_FORMAT_Y444:
3109 case GST_VIDEO_FORMAT_Y42B:
3110 case GST_VIDEO_FORMAT_Y41B:
3111 video_box->fill = fill_planar_yuv;
3112 switch (video_box->in_format) {
3113 case GST_VIDEO_FORMAT_Y444:
3114 video_box->copy = copy_y444_y444;
3116 case GST_VIDEO_FORMAT_Y42B:
3117 video_box->copy = copy_y42b_y42b;
3119 case GST_VIDEO_FORMAT_Y41B:
3120 video_box->copy = copy_y41b_y41b;
3130 return video_box->fill != NULL && video_box->copy != NULL;
3134 gst_video_box_set_caps (GstBaseTransform * trans, GstCaps * in, GstCaps * out)
3136 GstVideoBox *video_box = GST_VIDEO_BOX (trans);
3138 const gchar *matrix;
3140 g_mutex_lock (video_box->mutex);
3143 gst_video_format_parse_caps (in, &video_box->in_format,
3144 &video_box->in_width, &video_box->in_height);
3146 gst_video_format_parse_caps (out, &video_box->out_format,
3147 &video_box->out_width, &video_box->out_height);
3149 matrix = gst_video_parse_caps_color_matrix (in);
3150 video_box->in_sdtv = matrix ? g_str_equal (matrix, "sdtv") : TRUE;
3151 matrix = gst_video_parse_caps_color_matrix (out);
3152 video_box->out_sdtv = matrix ? g_str_equal (matrix, "sdtv") : TRUE;
3154 /* something wrong getting the caps */
3158 GST_DEBUG_OBJECT (trans, "Input w: %d h: %d", video_box->in_width,
3159 video_box->in_height);
3160 GST_DEBUG_OBJECT (trans, "Output w: %d h: %d", video_box->out_width,
3161 video_box->out_height);
3163 if (video_box->autocrop)
3164 gst_video_box_autocrop (video_box);
3166 /* recalc the transformation strategy */
3167 ret = gst_video_box_recalc_transform (video_box);
3170 ret = gst_video_box_select_processing_functions (video_box);
3171 g_mutex_unlock (video_box->mutex);
3178 GST_DEBUG_OBJECT (video_box,
3179 "Invalid caps: %" GST_PTR_FORMAT " -> %" GST_PTR_FORMAT, in, out);
3180 g_mutex_unlock (video_box->mutex);
3186 gst_video_box_get_unit_size (GstBaseTransform * trans, GstCaps * caps,
3189 GstVideoFormat format;
3195 ret = gst_video_format_parse_caps (caps, &format, &width, &height);
3197 GST_ERROR_OBJECT (trans, "Invalid caps: %" GST_PTR_FORMAT, caps);
3201 *size = gst_video_format_get_size (format, width, height);
3203 GST_LOG_OBJECT (trans, "Returning from _unit_size %d", *size);
3209 gst_video_box_fixate_caps (GstBaseTransform * trans,
3210 GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
3216 ret = gst_video_format_parse_caps (caps, NULL, &width, &height);
3220 s = gst_caps_get_structure (othercaps, 0);
3221 gst_structure_fixate_field_nearest_int (s, "width", width);
3222 gst_structure_fixate_field_nearest_int (s, "height", height);
3226 gst_video_box_src_event (GstBaseTransform * trans, GstEvent * event)
3228 GstVideoBox *video_box = GST_VIDEO_BOX (trans);
3229 GstStructure *new_structure;
3230 const GstStructure *structure;
3231 const gchar *event_name;
3235 GST_OBJECT_LOCK (video_box);
3236 if (GST_EVENT_TYPE (event) == GST_EVENT_NAVIGATION &&
3237 (video_box->box_left != 0 || video_box->box_top != 0)) {
3238 structure = gst_event_get_structure (event);
3239 event_name = gst_structure_get_string (structure, "event");
3242 (strcmp (event_name, "mouse-move") == 0 ||
3243 strcmp (event_name, "mouse-button-press") == 0 ||
3244 strcmp (event_name, "mouse-button-release") == 0)) {
3245 if (gst_structure_get_double (structure, "pointer_x", &pointer_x) &&
3246 gst_structure_get_double (structure, "pointer_y", &pointer_y)) {
3247 gdouble new_pointer_x, new_pointer_y;
3248 GstEvent *new_event;
3250 new_pointer_x = pointer_x + video_box->box_left;
3251 new_pointer_y = pointer_y + video_box->box_top;
3253 new_structure = gst_structure_copy (structure);
3254 gst_structure_set (new_structure,
3255 "pointer_x", G_TYPE_DOUBLE, (gdouble) (new_pointer_x),
3256 "pointer_y", G_TYPE_DOUBLE, (gdouble) (new_pointer_y), NULL);
3258 new_event = gst_event_new_navigation (new_structure);
3259 gst_event_unref (event);
3262 GST_WARNING_OBJECT (video_box, "Failed to read navigation event");
3266 GST_OBJECT_UNLOCK (video_box);
3268 return GST_BASE_TRANSFORM_CLASS (parent_class)->src_event (trans, event);
3272 gst_video_box_process (GstVideoBox * video_box, const guint8 * src,
3275 guint b_alpha = CLAMP (video_box->border_alpha * 256, 0, 256);
3276 guint i_alpha = CLAMP (video_box->alpha * 256, 0, 256);
3277 GstVideoBoxFill fill_type = video_box->fill_type;
3278 gint br, bl, bt, bb, crop_w, crop_h;
3283 br = video_box->box_right;
3284 bl = video_box->box_left;
3285 bt = video_box->box_top;
3286 bb = video_box->box_bottom;
3288 if (br >= 0 && bl >= 0) {
3289 crop_w = video_box->in_width - (br + bl);
3290 } else if (br >= 0 && bl < 0) {
3291 crop_w = video_box->in_width - (br);
3292 } else if (br < 0 && bl >= 0) {
3293 crop_w = video_box->in_width - (bl);
3294 } else if (br < 0 && bl < 0) {
3295 crop_w = video_box->in_width;
3298 if (bb >= 0 && bt >= 0) {
3299 crop_h = video_box->in_height - (bb + bt);
3300 } else if (bb >= 0 && bt < 0) {
3301 crop_h = video_box->in_height - (bb);
3302 } else if (bb < 0 && bt >= 0) {
3303 crop_h = video_box->in_height - (bt);
3304 } else if (bb < 0 && bt < 0) {
3305 crop_h = video_box->in_height;
3308 GST_DEBUG_OBJECT (video_box, "Borders are: L:%d, R:%d, T:%d, B:%d", bl, br,
3310 GST_DEBUG_OBJECT (video_box, "Alpha value is: %u (frame) %u (border)",
3313 if (crop_h < 0 || crop_w < 0) {
3314 video_box->fill (fill_type, b_alpha, video_box->out_format, dest,
3315 video_box->out_sdtv, video_box->out_width, video_box->out_height);
3316 } else if (bb == 0 && bt == 0 && br == 0 && bl == 0) {
3317 video_box->copy (i_alpha, video_box->out_format, dest, video_box->out_sdtv,
3318 video_box->out_width, video_box->out_height, 0, 0, video_box->in_format,
3319 src, video_box->in_sdtv, video_box->in_width, video_box->in_height, 0,
3322 gint src_x = 0, src_y = 0;
3323 gint dest_x = 0, dest_y = 0;
3325 /* Fill everything if a border should be added somewhere */
3326 if (bt < 0 || bb < 0 || br < 0 || bl < 0)
3327 video_box->fill (fill_type, b_alpha, video_box->out_format, dest,
3328 video_box->out_sdtv, video_box->out_width, video_box->out_height);
3345 video_box->copy (i_alpha, video_box->out_format, dest, video_box->out_sdtv,
3346 video_box->out_width, video_box->out_height, dest_x, dest_y,
3347 video_box->in_format, src, video_box->in_sdtv, video_box->in_width,
3348 video_box->in_height, src_x, src_y, crop_w, crop_h);
3351 GST_LOG_OBJECT (video_box, "image created");
3355 gst_video_box_before_transform (GstBaseTransform * trans, GstBuffer * in)
3357 GstVideoBox *video_box = GST_VIDEO_BOX (trans);
3358 GstClockTime timestamp, stream_time;
3360 timestamp = GST_BUFFER_TIMESTAMP (in);
3362 gst_segment_to_stream_time (&trans->segment, GST_FORMAT_TIME, timestamp);
3364 GST_DEBUG_OBJECT (video_box, "sync to %" GST_TIME_FORMAT,
3365 GST_TIME_ARGS (timestamp));
3367 if (GST_CLOCK_TIME_IS_VALID (stream_time))
3368 gst_object_sync_values (G_OBJECT (video_box), stream_time);
3371 static GstFlowReturn
3372 gst_video_box_transform (GstBaseTransform * trans, GstBuffer * in,
3375 GstVideoBox *video_box = GST_VIDEO_BOX (trans);
3376 const guint8 *indata;
3379 indata = GST_BUFFER_DATA (in);
3380 outdata = GST_BUFFER_DATA (out);
3382 g_mutex_lock (video_box->mutex);
3383 gst_video_box_process (video_box, indata, outdata);
3384 g_mutex_unlock (video_box->mutex);
3388 /* FIXME: 0.11 merge with videocrop plugin */
3390 plugin_init (GstPlugin * plugin)
3392 gst_controller_init (NULL, NULL);
3394 GST_DEBUG_CATEGORY_INIT (videobox_debug, "videobox", 0,
3395 "Resizes a video by adding borders or cropping");
3397 return gst_element_register (plugin, "videobox", GST_RANK_NONE,
3398 GST_TYPE_VIDEO_BOX);
3401 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
3404 "resizes a video by adding borders or cropping",
3405 plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)