gstvideobox.c 19.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/* GStreamer
 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gst/gst.h>
24
#include <gst/base/gstbasetransform.h>
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
#include <gst/video/video.h>

#include <string.h>

#define GST_TYPE_VIDEO_BOX \
  (gst_video_box_get_type())
#define GST_VIDEO_BOX(obj) \
  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VIDEO_BOX,GstVideoBox))
#define GST_VIDEO_BOX_CLASS(klass) \
  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VIDEO_BOX,GstVideoBoxClass))
#define GST_IS_VIDEO_BOX(obj) \
  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VIDEO_BOX))
#define GST_IS_VIDEO_BOX_CLASS(obj) \
  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VIDEO_BOX))

typedef struct _GstVideoBox GstVideoBox;
typedef struct _GstVideoBoxClass GstVideoBoxClass;

typedef enum
{
  VIDEO_BOX_FILL_BLACK,
  VIDEO_BOX_FILL_GREEN,
  VIDEO_BOX_FILL_BLUE,
}
GstVideoBoxFill;

struct _GstVideoBox
{
53
  GstBaseTransform element;
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72

  /* caps */
  gint in_width, in_height;
  gint out_width, out_height;

  gint box_left, box_right, box_top, box_bottom;

  gint border_left, border_right, border_top, border_bottom;
  gint crop_left, crop_right, crop_top, crop_bottom;

  gboolean use_alpha;
  gdouble alpha;
  gdouble border_alpha;

  GstVideoBoxFill fill_type;
};

struct _GstVideoBoxClass
{
73
  GstBaseTransformClass parent_class;
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
};

/* elementfactory information */
static GstElementDetails gst_video_box_details =
GST_ELEMENT_DETAILS ("video box filter",
    "Filter/Effect/Video",
    "Resizes a video by adding borders or cropping",
    "Wim Taymans <wim@fluendo.com>");


#define DEFAULT_LEFT      0
#define DEFAULT_RIGHT     0
#define DEFAULT_TOP       0
#define DEFAULT_BOTTOM    0
#define DEFAULT_FILL_TYPE VIDEO_BOX_FILL_BLACK
#define DEFAULT_ALPHA     1.0
#define DEFAULT_BORDER_ALPHA 1.0

enum
{
94 95 96 97 98 99 100 101
  PROP_0,
  PROP_LEFT,
  PROP_RIGHT,
  PROP_TOP,
  PROP_BOTTOM,
  PROP_FILL_TYPE,
  PROP_ALPHA,
  PROP_BORDER_ALPHA,
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
  /* FILL ME */
};

static GstStaticPadTemplate gst_video_box_src_template =
GST_STATIC_PAD_TEMPLATE ("src",
    GST_PAD_SRC,
    GST_PAD_ALWAYS,
    GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("{ I420, AYUV }"))
    );

static GstStaticPadTemplate gst_video_box_sink_template =
GST_STATIC_PAD_TEMPLATE ("sink",
    GST_PAD_SINK,
    GST_PAD_ALWAYS,
    GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("I420"))
    );


120 121
GST_BOILERPLATE (GstVideoBox, gst_video_box, GstBaseTransform,
    GST_TYPE_BASE_TRANSFORM);
122 123 124 125 126 127

static void gst_video_box_set_property (GObject * object, guint prop_id,
    const GValue * value, GParamSpec * pspec);
static void gst_video_box_get_property (GObject * object, guint prop_id,
    GValue * value, GParamSpec * pspec);

128 129 130 131 132 133
static GstCaps *gst_video_box_transform_caps (GstBaseTransform * trans,
    GstPad * pad, GstCaps * from);
static gboolean gst_video_box_set_caps (GstBaseTransform * trans,
    GstCaps * in, GstCaps * out);
static GstFlowReturn gst_video_box_transform (GstBaseTransform * trans,
    GstBuffer * in, GstBuffer ** out);
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167


#define GST_TYPE_VIDEO_BOX_FILL (gst_video_box_fill_get_type())
static GType
gst_video_box_fill_get_type (void)
{
  static GType video_box_fill_type = 0;
  static GEnumValue video_box_fill[] = {
    {VIDEO_BOX_FILL_BLACK, "0", "Black"},
    {VIDEO_BOX_FILL_GREEN, "1", "Colorkey green"},
    {VIDEO_BOX_FILL_BLUE, "2", "Colorkey blue"},
    {0, NULL, NULL},
  };

  if (!video_box_fill_type) {
    video_box_fill_type =
        g_enum_register_static ("GstVideoBoxFill", video_box_fill);
  }
  return video_box_fill_type;
}


static void
gst_video_box_base_init (gpointer g_class)
{
  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);

  gst_element_class_set_details (element_class, &gst_video_box_details);

  gst_element_class_add_pad_template (element_class,
      gst_static_pad_template_get (&gst_video_box_sink_template));
  gst_element_class_add_pad_template (element_class,
      gst_static_pad_template_get (&gst_video_box_src_template));
}
168

169 170 171 172
static void
gst_video_box_class_init (GstVideoBoxClass * klass)
{
  GObjectClass *gobject_class;
173
  GstBaseTransformClass *trans_class;
174 175

  gobject_class = (GObjectClass *) klass;
176
  trans_class = (GstBaseTransformClass *) klass;
177

Wim Taymans's avatar
Wim Taymans committed
178 179 180
  gobject_class->set_property = gst_video_box_set_property;
  gobject_class->get_property = gst_video_box_get_property;

181
  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_FILL_TYPE,
182 183 184
      g_param_spec_enum ("fill", "Fill", "How to fill the borders",
          GST_TYPE_VIDEO_BOX_FILL, DEFAULT_FILL_TYPE,
          (GParamFlags) G_PARAM_READWRITE));
185
  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LEFT,
186 187 188
      g_param_spec_int ("left", "Left",
          "Pixels to box at left (<0  = add a border)", G_MININT, G_MAXINT,
          DEFAULT_LEFT, G_PARAM_READWRITE));
189
  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_RIGHT,
190 191 192
      g_param_spec_int ("right", "Right",
          "Pixels to box at right (<0 = add a border)", G_MININT, G_MAXINT,
          DEFAULT_RIGHT, G_PARAM_READWRITE));
193
  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TOP,
194 195 196
      g_param_spec_int ("top", "Top",
          "Pixels to box at top (<0 = add a border)", G_MININT, G_MAXINT,
          DEFAULT_TOP, G_PARAM_READWRITE));
197
  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BOTTOM,
198 199 200
      g_param_spec_int ("bottom", "Bottom",
          "Pixels to box at bottom (<0 = add a border)", G_MININT, G_MAXINT,
          DEFAULT_BOTTOM, G_PARAM_READWRITE));
201
  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ALPHA,
202 203
      g_param_spec_double ("alpha", "Alpha", "Alpha value picture", 0.0, 1.0,
          DEFAULT_ALPHA, G_PARAM_READWRITE));
204
  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BORDER_ALPHA,
205 206 207 208
      g_param_spec_double ("border_alpha", "Border Alpha",
          "Alpha value of the border", 0.0, 1.0, DEFAULT_BORDER_ALPHA,
          G_PARAM_READWRITE));

209 210 211
  trans_class->transform_caps = gst_video_box_transform_caps;
  trans_class->set_caps = gst_video_box_set_caps;
  trans_class->transform = gst_video_box_transform;
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
}

static void
gst_video_box_init (GstVideoBox * video_box)
{
  video_box->box_right = DEFAULT_RIGHT;
  video_box->box_left = DEFAULT_LEFT;
  video_box->box_top = DEFAULT_TOP;
  video_box->box_bottom = DEFAULT_BOTTOM;
  video_box->fill_type = DEFAULT_FILL_TYPE;
  video_box->alpha = DEFAULT_ALPHA;
  video_box->border_alpha = DEFAULT_BORDER_ALPHA;
}

/* do we need this function? */
static void
gst_video_box_set_property (GObject * object, guint prop_id,
    const GValue * value, GParamSpec * pspec)
{
231
  GstVideoBox *video_box = GST_VIDEO_BOX (object);
232 233

  switch (prop_id) {
234
    case PROP_LEFT:
235 236 237 238 239 240 241 242 243
      video_box->box_left = g_value_get_int (value);
      if (video_box->box_left < 0) {
        video_box->border_left = -video_box->box_left;
        video_box->crop_left = 0;
      } else {
        video_box->border_left = 0;
        video_box->crop_left = video_box->box_left;
      }
      break;
244
    case PROP_RIGHT:
245 246 247 248 249 250 251 252 253
      video_box->box_right = g_value_get_int (value);
      if (video_box->box_right < 0) {
        video_box->border_right = -video_box->box_right;
        video_box->crop_right = 0;
      } else {
        video_box->border_right = 0;
        video_box->crop_right = video_box->box_right;
      }
      break;
254
    case PROP_TOP:
255 256 257 258 259 260 261 262 263
      video_box->box_top = g_value_get_int (value);
      if (video_box->box_top < 0) {
        video_box->border_top = -video_box->box_top;
        video_box->crop_top = 0;
      } else {
        video_box->border_top = 0;
        video_box->crop_top = video_box->box_top;
      }
      break;
264
    case PROP_BOTTOM:
265 266 267 268 269 270 271 272 273
      video_box->box_bottom = g_value_get_int (value);
      if (video_box->box_bottom < 0) {
        video_box->border_bottom = -video_box->box_bottom;
        video_box->crop_bottom = 0;
      } else {
        video_box->border_bottom = 0;
        video_box->crop_bottom = video_box->box_bottom;
      }
      break;
274
    case PROP_FILL_TYPE:
275 276
      video_box->fill_type = g_value_get_enum (value);
      break;
277
    case PROP_ALPHA:
278 279
      video_box->alpha = g_value_get_double (value);
      break;
280
    case PROP_BORDER_ALPHA:
281 282 283 284 285 286 287 288 289 290 291
      video_box->border_alpha = g_value_get_double (value);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}
static void
gst_video_box_get_property (GObject * object, guint prop_id, GValue * value,
    GParamSpec * pspec)
{
292
  GstVideoBox *video_box = GST_VIDEO_BOX (object);
293 294

  switch (prop_id) {
295
    case PROP_LEFT:
296 297
      g_value_set_int (value, video_box->box_left);
      break;
298
    case PROP_RIGHT:
299 300
      g_value_set_int (value, video_box->box_right);
      break;
301
    case PROP_TOP:
302 303
      g_value_set_int (value, video_box->box_top);
      break;
304
    case PROP_BOTTOM:
305 306
      g_value_set_int (value, video_box->box_bottom);
      break;
307
    case PROP_FILL_TYPE:
308 309
      g_value_set_enum (value, video_box->fill_type);
      break;
310
    case PROP_ALPHA:
311 312
      g_value_set_double (value, video_box->alpha);
      break;
313
    case PROP_BORDER_ALPHA:
314 315 316 317 318 319 320 321
      g_value_set_double (value, video_box->border_alpha);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}

322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
static GstCaps *
gst_video_box_transform_caps (GstBaseTransform * trans, GstPad * pad,
    GstCaps * from)
{
  GstVideoBox *video_box;
  GstCaps *to;
  GstStructure *structure;
  gint direction, i, tmp;

  video_box = GST_VIDEO_BOX (trans);
  to = gst_caps_copy (from);
  direction = (pad == trans->sinkpad) ? 1 : -1;

  for (i = 0; i < gst_caps_get_size (to); i++) {
    structure = gst_caps_get_structure (to, i);
    if (gst_structure_get_int (structure, "width", &tmp))
      gst_structure_set (structure, "width", G_TYPE_INT,
          tmp + direction * (video_box->box_left + video_box->box_right), NULL);
    if (gst_structure_get_int (structure, "height", &tmp))
      gst_structure_set (structure, "height", G_TYPE_INT,
          tmp + direction * (video_box->box_top + video_box->box_bottom), NULL);
  }

  return to;
}

Wim Taymans's avatar
Wim Taymans committed
348
static gboolean
349
gst_video_box_set_caps (GstBaseTransform * trans, GstCaps * in, GstCaps * out)
350 351 352 353 354
{
  GstVideoBox *video_box;
  GstStructure *structure;
  gboolean ret;

355
  video_box = GST_VIDEO_BOX (trans);
356

357
  structure = gst_caps_get_structure (in, 0);
358 359 360
  ret = gst_structure_get_int (structure, "width", &video_box->in_width);
  ret &= gst_structure_get_int (structure, "height", &video_box->in_height);

361 362 363 364
  structure = gst_caps_get_structure (out, 0);
  ret &= gst_structure_get_int (structure, "width", &video_box->out_width);
  ret &= gst_structure_get_int (structure, "height", &video_box->out_height);

Wim Taymans's avatar
Wim Taymans committed
365
  return ret;
366 367
}

368 369 370 371 372 373 374 375
#define ROUND_UP_2(x)  (((x)+1)&~1)
#define ROUND_UP_4(x)  (((x)+3)&~3)
#define ROUND_UP_8(x)  (((x)+7)&~7)

/* see gst-plugins/gst/games/gstvideoimage.c, paint_setup_I420() */
#define GST_VIDEO_I420_Y_ROWSTRIDE(width) (ROUND_UP_4(width))
#define GST_VIDEO_I420_U_ROWSTRIDE(width) (ROUND_UP_8(width)/2)
#define GST_VIDEO_I420_V_ROWSTRIDE(width) ((ROUND_UP_8(GST_VIDEO_I420_Y_ROWSTRIDE(width)))/2)
376

377 378 379 380 381
#define GST_VIDEO_I420_Y_OFFSET(w,h) (0)
#define GST_VIDEO_I420_U_OFFSET(w,h) (GST_VIDEO_I420_Y_OFFSET(w,h)+(GST_VIDEO_I420_Y_ROWSTRIDE(w)*ROUND_UP_2(h)))
#define GST_VIDEO_I420_V_OFFSET(w,h) (GST_VIDEO_I420_U_OFFSET(w,h)+(GST_VIDEO_I420_U_ROWSTRIDE(w)*ROUND_UP_2(h)/2))

#define GST_VIDEO_I420_SIZE(w,h)     (GST_VIDEO_I420_V_OFFSET(w,h)+(GST_VIDEO_I420_V_ROWSTRIDE(w)*ROUND_UP_2(h)/2))
382 383 384 385 386

static int yuv_colors_Y[] = { 16, 150, 29 };
static int yuv_colors_U[] = { 128, 46, 255 };
static int yuv_colors_V[] = { 128, 21, 107 };

387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416
static void
gst_video_box_copy_plane_i420 (GstVideoBox * video_box, guint8 * src,
    guint8 * dest, gint br, gint bl, gint bt, gint bb, gint src_crop_width,
    gint src_crop_height, gint src_stride, gint dest_width, gint dest_stride,
    guint8 fill_color)
{
  gint j;

  /* top border */
  for (j = 0; j < bt; j++) {
    memset (dest, fill_color, dest_width);
    dest += dest_stride;
  }

  /* copy and add left and right border */
  for (j = 0; j < src_crop_height; j++) {
    memset (dest, fill_color, bl);
    memcpy (dest + bl, src, src_crop_width);
    memset (dest + bl + src_crop_width, fill_color, br);
    dest += dest_stride;
    src += src_stride;
  }

  /* bottom border */
  for (j = 0; j < bb; j++) {
    memset (dest, fill_color, dest_width);
    dest += dest_stride;
  }
}

417 418 419 420 421 422 423
static void
gst_video_box_i420 (GstVideoBox * video_box, guint8 * src, guint8 * dest)
{
  guint8 *srcY, *srcU, *srcV;
  guint8 *destY, *destU, *destV;
  gint crop_width, crop_height;
  gint out_width, out_height;
424 425
  gint src_width, src_height;
  gint src_stride, dest_stride;
426 427 428 429 430 431 432 433 434 435
  gint br, bl, bt, bb;

  br = video_box->border_right;
  bl = video_box->border_left;
  bt = video_box->border_top;
  bb = video_box->border_bottom;

  out_width = video_box->out_width;
  out_height = video_box->out_height;

436 437
  src_width = video_box->in_width;
  src_height = video_box->in_height;
438

439 440
  crop_width = src_width - (video_box->crop_left + video_box->crop_right);
  crop_height = src_height - (video_box->crop_top + video_box->crop_bottom);
441

442 443 444
  /* Y plane */
  src_stride = GST_VIDEO_I420_Y_ROWSTRIDE (src_width);
  dest_stride = GST_VIDEO_I420_Y_ROWSTRIDE (out_width);
445

446
  destY = dest + GST_VIDEO_I420_Y_OFFSET (out_width, out_height);
447

448 449
  srcY = src + GST_VIDEO_I420_Y_OFFSET (src_width, src_height);
  srcY += src_stride * video_box->crop_top + video_box->crop_left;
450

451 452 453
  gst_video_box_copy_plane_i420 (video_box, srcY, destY, br, bl, bt, bb,
      crop_width, crop_height, src_stride, out_width, dest_stride,
      yuv_colors_Y[video_box->fill_type]);
454

455 456 457
  /* U plane */
  src_stride = GST_VIDEO_I420_U_ROWSTRIDE (src_width);
  dest_stride = GST_VIDEO_I420_U_ROWSTRIDE (out_width);
458 459 460

  destU = dest + GST_VIDEO_I420_U_OFFSET (out_width, out_height);

461
  srcU = src + GST_VIDEO_I420_U_OFFSET (src_width, src_height);
462 463
  srcU += src_stride * (video_box->crop_top / 2) + (video_box->crop_left / 2);

464 465 466
  gst_video_box_copy_plane_i420 (video_box, srcU, destU, br / 2, bl / 2, bt / 2,
      bb / 2, crop_width / 2, crop_height / 2, src_stride, out_width / 2,
      dest_stride, yuv_colors_U[video_box->fill_type]);
467

468 469 470 471 472 473 474 475 476 477 478 479
  /* V plane */
  src_stride = GST_VIDEO_I420_V_ROWSTRIDE (src_width);
  dest_stride = GST_VIDEO_I420_V_ROWSTRIDE (out_width);

  destV = dest + GST_VIDEO_I420_V_OFFSET (out_width, out_height);

  srcV = src + GST_VIDEO_I420_V_OFFSET (src_width, src_height);
  srcV += src_stride * (video_box->crop_top / 2) + (video_box->crop_left / 2);

  gst_video_box_copy_plane_i420 (video_box, srcV, destV, br / 2, bl / 2, bt / 2,
      bb / 2, crop_width / 2, crop_height / 2, src_stride, out_width / 2,
      dest_stride, yuv_colors_V[video_box->fill_type]);
480 481
}

482 483 484
/* Note the source image is always I420, we
 * are converting to AYUV on the fly here */

485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580
static void
gst_video_box_ayuv (GstVideoBox * video_box, guint8 * src, guint8 * dest)
{
  guint8 *srcY, *srcU, *srcV;
  gint crop_width, crop_width2, crop_height;
  gint out_width, out_height;
  gint src_stride, src_stride2;
  gint br, bl, bt, bb;
  gint colorY, colorU, colorV;
  gint i, j;
  guint8 b_alpha = (guint8) (video_box->border_alpha * 255);
  guint8 i_alpha = (guint8) (video_box->alpha * 255);
  guint32 *destp = (guint32 *) dest;
  guint32 ayuv;

  br = video_box->border_right;
  bl = video_box->border_left;
  bt = video_box->border_top;
  bb = video_box->border_bottom;

  out_width = video_box->out_width;
  out_height = video_box->out_height;

  src_stride = GST_VIDEO_I420_Y_ROWSTRIDE (video_box->in_width);
  src_stride2 = src_stride / 2;

  crop_width =
      video_box->in_width - (video_box->crop_left + video_box->crop_right);
  crop_width2 = crop_width / 2;
  crop_height =
      video_box->in_height - (video_box->crop_top + video_box->crop_bottom);

  srcY =
      src + GST_VIDEO_I420_Y_OFFSET (video_box->in_width, video_box->in_height);
  srcY += src_stride * video_box->crop_top + video_box->crop_left;
  srcU =
      src + GST_VIDEO_I420_U_OFFSET (video_box->in_width, video_box->in_height);
  srcU += src_stride2 * (video_box->crop_top / 2) + (video_box->crop_left / 2);
  srcV =
      src + GST_VIDEO_I420_V_OFFSET (video_box->in_width, video_box->in_height);
  srcV += src_stride2 * (video_box->crop_top / 2) + (video_box->crop_left / 2);

  colorY = yuv_colors_Y[video_box->fill_type];
  colorU = yuv_colors_U[video_box->fill_type];
  colorV = yuv_colors_V[video_box->fill_type];

  ayuv =
      GUINT32_FROM_BE ((b_alpha << 24) | (colorY << 16) | (colorU << 8) |
      colorV);

  /* top border */
  for (i = 0; i < bt; i++) {
    for (j = 0; j < out_width; j++) {
      *destp++ = ayuv;
    }
  }
  for (i = 0; i < crop_height; i++) {
    /* left border */
    for (j = 0; j < bl; j++) {
      *destp++ = ayuv;
    }
    dest = (guint8 *) destp;
    /* center */
    for (j = 0; j < crop_width2; j++) {
      *dest++ = i_alpha;
      *dest++ = *srcY++;
      *dest++ = *srcU;
      *dest++ = *srcV;
      *dest++ = i_alpha;
      *dest++ = *srcY++;
      *dest++ = *srcU++;
      *dest++ = *srcV++;
    }
    if (i % 2 == 0) {
      srcU -= crop_width2;
      srcV -= crop_width2;
    } else {
      srcU += src_stride2 - crop_width2;
      srcV += src_stride2 - crop_width2;
    }
    srcY += src_stride - crop_width;

    destp = (guint32 *) dest;
    /* right border */
    for (j = 0; j < br; j++) {
      *destp++ = ayuv;
    }
  }
  /* bottom border */
  for (i = 0; i < bb; i++) {
    for (j = 0; j < out_width; j++) {
      *destp++ = ayuv;
    }
  }
}

Wim Taymans's avatar
Wim Taymans committed
581
static GstFlowReturn
582 583
gst_video_box_transform (GstBaseTransform * trans, GstBuffer * in,
    GstBuffer ** out)
584 585
{
  GstVideoBox *video_box;
Wim Taymans's avatar
Wim Taymans committed
586
  GstFlowReturn ret;
587

588
  video_box = GST_VIDEO_BOX (trans);
589 590

  if (video_box->use_alpha) {
591 592 593 594
    ret = gst_pad_alloc_buffer (trans->srcpad,
        GST_BUFFER_OFFSET_NONE,
        video_box->out_height * video_box->out_height * 4,
        GST_PAD_CAPS (trans->srcpad), out);
Wim Taymans's avatar
Wim Taymans committed
595 596
    if (ret != GST_FLOW_OK)
      goto done;
597 598

    gst_video_box_ayuv (video_box,
599
        GST_BUFFER_DATA (in), GST_BUFFER_DATA (*out));
600
  } else {
601 602 603 604
    ret = gst_pad_alloc_buffer (trans->srcpad,
        GST_BUFFER_OFFSET_NONE,
        GST_VIDEO_I420_SIZE (video_box->out_width, video_box->out_height),
        GST_PAD_CAPS (trans->srcpad), out);
Wim Taymans's avatar
Wim Taymans committed
605 606
    if (ret != GST_FLOW_OK)
      goto done;
607 608

    gst_video_box_i420 (video_box,
609
        GST_BUFFER_DATA (in), GST_BUFFER_DATA (*out));
610 611
  }

612
  gst_buffer_stamp (*out, in);
613

Wim Taymans's avatar
Wim Taymans committed
614
done:
615
  gst_buffer_unref (in);
Wim Taymans's avatar
Wim Taymans committed
616
  return ret;
617 618 619 620 621 622 623 624 625 626 627 628 629 630
}

static gboolean
plugin_init (GstPlugin * plugin)
{
  return gst_element_register (plugin, "videobox", GST_RANK_NONE,
      GST_TYPE_VIDEO_BOX);
}

GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
    GST_VERSION_MINOR,
    "videobox",
    "resizes a video by adding borders or cropping",
    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE, GST_ORIGIN)