gstvideobox.c 35.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/* 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.
 */
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
/**
 * SECTION:element-videobox
 * @see_also: #GstVideoCrop
 *
 * This plugin crops or enlarges the image. It takes 4 values as input, a
 * top, bottom, left and right offset. Positive values will crop that much
 * pixels from the respective border of the image, negative values will add
 * that much pixels. When pixels are added, you can specify their color. 
 * Some predefined colors are usable with an enum property.
 * 
 * The plugin is alpha channel aware and will try to negotiate with a format
 * that supports alpha channels first. When alpha channel is active two
 * other properties, alpha and border_alpha can be used to set the alpha
 * values of the inner picture and the border respectively. an alpha value of
 * 0.0 means total transparency, 1.0 is opaque.
 * 
 * The videobox plugin has many uses such as doing a mosaic of pictures, 
 * letterboxing video, cutting out pieces of video, picture in picture, etc..
 */
38 39 40 41
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gst/gst.h>
42
#include <gst/base/gstbasetransform.h>
43
#include <gst/video/video.h>
44
#include <math.h>
45
#include <liboil/liboil.h>
46 47
#include <string.h>

48
GST_DEBUG_CATEGORY_STATIC (videobox_debug);
49 50
#define GST_CAT_DEFAULT videobox_debug

51 52 53 54 55 56 57 58
#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))
Stefan Kost's avatar
Stefan Kost committed
59
#define GST_IS_VIDEO_BOX_CLASS(klass) \
60 61 62 63 64 65 66 67 68 69
  (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,
70
  VIDEO_BOX_FILL_LAST
71 72 73 74 75
}
GstVideoBoxFill;

struct _GstVideoBox
{
76
  GstBaseTransform element;
77 78

  /* caps */
79
  guint32 in_fourcc;
80
  gint in_width, in_height;
81
  guint32 out_fourcc;
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
  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;

  gdouble alpha;
  gdouble border_alpha;

  GstVideoBoxFill fill_type;
};

struct _GstVideoBoxClass
{
97
  GstBaseTransformClass parent_class;
98 99 100
};

/* elementfactory information */
101
static const GstElementDetails gst_video_box_details =
Wim Taymans's avatar
Wim Taymans committed
102
GST_ELEMENT_DETAILS ("Video box filter",
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
    "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
{
118 119 120 121 122 123 124
  PROP_0,
  PROP_LEFT,
  PROP_RIGHT,
  PROP_TOP,
  PROP_BOTTOM,
  PROP_FILL_TYPE,
  PROP_ALPHA,
125 126
  PROP_BORDER_ALPHA
      /* FILL ME */
127 128 129
};

static GstStaticPadTemplate gst_video_box_src_template =
130
    GST_STATIC_PAD_TEMPLATE ("src",
131 132
    GST_PAD_SRC,
    GST_PAD_ALWAYS,
133 134
    GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV") ";"
        GST_VIDEO_CAPS_YUV ("I420"))
135 136 137
    );

static GstStaticPadTemplate gst_video_box_sink_template =
138
    GST_STATIC_PAD_TEMPLATE ("sink",
139 140
    GST_PAD_SINK,
    GST_PAD_ALWAYS,
141 142
    GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV") ";"
        GST_VIDEO_CAPS_YUV ("I420"))
143 144 145
    );


146 147
GST_BOILERPLATE (GstVideoBox, gst_video_box, GstBaseTransform,
    GST_TYPE_BASE_TRANSFORM);
148 149 150 151 152 153

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);

154
static GstCaps *gst_video_box_transform_caps (GstBaseTransform * trans,
155
    GstPadDirection direction, GstCaps * from);
156 157
static gboolean gst_video_box_set_caps (GstBaseTransform * trans,
    GstCaps * in, GstCaps * out);
158 159
static gboolean gst_video_box_get_unit_size (GstBaseTransform * trans,
    GstCaps * caps, guint * size);
160
static GstFlowReturn gst_video_box_transform (GstBaseTransform * trans,
Wim Taymans's avatar
Wim Taymans committed
161
    GstBuffer * in, GstBuffer * out);
162 163 164 165 166 167 168


#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;
169
  static const GEnumValue video_box_fill[] = {
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
170 171 172
    {VIDEO_BOX_FILL_BLACK, "Black", "black"},
    {VIDEO_BOX_FILL_GREEN, "Colorkey green", "green"},
    {VIDEO_BOX_FILL_BLUE, "Colorkey blue", "blue"},
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
    {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));
}
196

197 198 199 200
static void
gst_video_box_class_init (GstVideoBoxClass * klass)
{
  GObjectClass *gobject_class;
201
  GstBaseTransformClass *trans_class;
202 203

  gobject_class = (GObjectClass *) klass;
204
  trans_class = (GstBaseTransformClass *) klass;
205

Wim Taymans's avatar
Wim Taymans committed
206 207 208
  gobject_class->set_property = gst_video_box_set_property;
  gobject_class->get_property = gst_video_box_get_property;

209
  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_FILL_TYPE,
210 211 212
      g_param_spec_enum ("fill", "Fill", "How to fill the borders",
          GST_TYPE_VIDEO_BOX_FILL, DEFAULT_FILL_TYPE,
          (GParamFlags) G_PARAM_READWRITE));
213
  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LEFT,
214 215 216
      g_param_spec_int ("left", "Left",
          "Pixels to box at left (<0  = add a border)", G_MININT, G_MAXINT,
          DEFAULT_LEFT, G_PARAM_READWRITE));
217
  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_RIGHT,
218 219 220
      g_param_spec_int ("right", "Right",
          "Pixels to box at right (<0 = add a border)", G_MININT, G_MAXINT,
          DEFAULT_RIGHT, G_PARAM_READWRITE));
221
  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TOP,
222 223 224
      g_param_spec_int ("top", "Top",
          "Pixels to box at top (<0 = add a border)", G_MININT, G_MAXINT,
          DEFAULT_TOP, G_PARAM_READWRITE));
225
  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BOTTOM,
226 227 228
      g_param_spec_int ("bottom", "Bottom",
          "Pixels to box at bottom (<0 = add a border)", G_MININT, G_MAXINT,
          DEFAULT_BOTTOM, G_PARAM_READWRITE));
229
  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ALPHA,
230 231
      g_param_spec_double ("alpha", "Alpha", "Alpha value picture", 0.0, 1.0,
          DEFAULT_ALPHA, G_PARAM_READWRITE));
232
  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BORDER_ALPHA,
233 234 235 236
      g_param_spec_double ("border_alpha", "Border Alpha",
          "Alpha value of the border", 0.0, 1.0, DEFAULT_BORDER_ALPHA,
          G_PARAM_READWRITE));

237
  trans_class->transform = GST_DEBUG_FUNCPTR (gst_video_box_transform);
238 239 240 241
  trans_class->transform_caps =
      GST_DEBUG_FUNCPTR (gst_video_box_transform_caps);
  trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_video_box_set_caps);
  trans_class->get_unit_size = GST_DEBUG_FUNCPTR (gst_video_box_get_unit_size);
242 243 244

  GST_DEBUG_CATEGORY_INIT (videobox_debug, "videobox", 0,
      "Resizes a video by adding borders or cropping");
245 246 247
}

static void
248
gst_video_box_init (GstVideoBox * video_box, GstVideoBoxClass * g_class)
249 250 251 252 253
{
  video_box->box_right = DEFAULT_RIGHT;
  video_box->box_left = DEFAULT_LEFT;
  video_box->box_top = DEFAULT_TOP;
  video_box->box_bottom = DEFAULT_BOTTOM;
254 255 256 257
  video_box->crop_right = 0;
  video_box->crop_left = 0;
  video_box->crop_top = 0;
  video_box->crop_bottom = 0;
258 259 260 261 262 263 264 265 266
  video_box->fill_type = DEFAULT_FILL_TYPE;
  video_box->alpha = DEFAULT_ALPHA;
  video_box->border_alpha = DEFAULT_BORDER_ALPHA;
}

static void
gst_video_box_set_property (GObject * object, guint prop_id,
    const GValue * value, GParamSpec * pspec)
{
267
  GstVideoBox *video_box = GST_VIDEO_BOX (object);
268

269
  GST_BASE_TRANSFORM_LOCK (GST_BASE_TRANSFORM_CAST (video_box));
270
  switch (prop_id) {
271
    case PROP_LEFT:
272 273 274 275 276 277 278 279 280
      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;
281
    case PROP_RIGHT:
282 283 284 285 286 287 288 289 290
      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;
291
    case PROP_TOP:
292 293 294 295 296 297 298 299 300
      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;
301
    case PROP_BOTTOM:
302 303 304 305 306 307 308 309 310
      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;
311
    case PROP_FILL_TYPE:
312 313
      video_box->fill_type = g_value_get_enum (value);
      break;
314
    case PROP_ALPHA:
315 316
      video_box->alpha = g_value_get_double (value);
      break;
317
    case PROP_BORDER_ALPHA:
318 319 320 321 322 323
      video_box->border_alpha = g_value_get_double (value);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
324
  GST_DEBUG_OBJECT (video_box, "Calling reconfigure");
325
  gst_base_transform_reconfigure (GST_BASE_TRANSFORM (video_box));
326
  GST_BASE_TRANSFORM_UNLOCK (GST_BASE_TRANSFORM_CAST (video_box));
327
}
328

329 330 331 332
static void
gst_video_box_get_property (GObject * object, guint prop_id, GValue * value,
    GParamSpec * pspec)
{
333
  GstVideoBox *video_box = GST_VIDEO_BOX (object);
334 335

  switch (prop_id) {
336
    case PROP_LEFT:
337 338
      g_value_set_int (value, video_box->box_left);
      break;
339
    case PROP_RIGHT:
340 341
      g_value_set_int (value, video_box->box_right);
      break;
342
    case PROP_TOP:
343 344
      g_value_set_int (value, video_box->box_top);
      break;
345
    case PROP_BOTTOM:
346 347
      g_value_set_int (value, video_box->box_bottom);
      break;
348
    case PROP_FILL_TYPE:
349 350
      g_value_set_enum (value, video_box->fill_type);
      break;
351
    case PROP_ALPHA:
352 353
      g_value_set_double (value, video_box->alpha);
      break;
354
    case PROP_BORDER_ALPHA:
355 356 357 358 359 360 361 362
      g_value_set_double (value, video_box->border_alpha);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}

363
static GstCaps *
364 365
gst_video_box_transform_caps (GstBaseTransform * trans,
    GstPadDirection direction, GstCaps * from)
366 367
{
  GstVideoBox *video_box;
368 369
  GstCaps *to, *ret;
  const GstCaps *templ;
370
  GstStructure *structure;
371 372
  GstPad *other;
  gint width, height;
373 374

  video_box = GST_VIDEO_BOX (trans);
375

376
  to = gst_caps_copy (from);
377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393
  structure = gst_caps_get_structure (to, 0);

  /* get rid of format */
  gst_structure_remove_field (structure, "format");

  /* calculate width and height */
  if (gst_structure_get_int (structure, "width", &width)) {
    if (direction == GST_PAD_SINK) {
      width -= video_box->box_left;
      width -= video_box->box_right;
    } else {
      width += video_box->box_left;
      width += video_box->box_right;
    }
    if (width <= 0)
      width = 1;

394
    GST_DEBUG_OBJECT (trans, "New caps width: %d", width);
395 396 397 398 399 400 401 402 403 404
    gst_structure_set (structure, "width", G_TYPE_INT, width, NULL);
  }

  if (gst_structure_get_int (structure, "height", &height)) {
    if (direction == GST_PAD_SINK) {
      height -= video_box->box_top;
      height -= video_box->box_bottom;
    } else {
      height += video_box->box_top;
      height += video_box->box_bottom;
405
    }
406 407 408 409

    if (height <= 0)
      height = 1;

410
    GST_DEBUG_OBJECT (trans, "New caps height: %d", height);
411
    gst_structure_set (structure, "height", G_TYPE_INT, height, NULL);
412 413
  }

414 415 416 417 418 419
  /* filter against set allowed caps on the pad */
  other = (direction == GST_PAD_SINK) ? trans->srcpad : trans->sinkpad;

  templ = gst_pad_get_pad_template_caps (other);
  ret = gst_caps_intersect (to, templ);
  gst_caps_unref (to);
420

421
  GST_DEBUG_OBJECT (video_box, "direction %d, transformed %" GST_PTR_FORMAT
422 423 424 425 426
      " to %" GST_PTR_FORMAT, direction, from, ret);

  return ret;
}

Wim Taymans's avatar
Wim Taymans committed
427
static gboolean
428
gst_video_box_set_caps (GstBaseTransform * trans, GstCaps * in, GstCaps * out)
429 430 431 432 433
{
  GstVideoBox *video_box;
  GstStructure *structure;
  gboolean ret;

434
  video_box = GST_VIDEO_BOX (trans);
435

436
  structure = gst_caps_get_structure (in, 0);
437 438
  ret = gst_structure_get_int (structure, "width", &video_box->in_width);
  ret &= gst_structure_get_int (structure, "height", &video_box->in_height);
439
  ret &= gst_structure_get_fourcc (structure, "format", &video_box->in_fourcc);
440

441 442 443
  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);
444
  ret &= gst_structure_get_fourcc (structure, "format", &video_box->out_fourcc);
445

446 447 448 449
  /* something wrong getting the caps */
  if (!ret)
    goto no_caps;

450 451 452 453 454 455 456 457 458 459
  GST_DEBUG_OBJECT (trans, "Input w: %d h: %d", video_box->in_width,
      video_box->in_height);
  GST_DEBUG_OBJECT (trans, "Output w: %d h: %d", video_box->out_width,
      video_box->out_height);

  /* if we have the same format in and out and we don't need to perform and
   * cropping at all, we can just operate in passthorugh mode */
  if (video_box->in_fourcc == video_box->out_fourcc &&
      video_box->box_left == 0 && video_box->box_right == 0 &&
      video_box->box_top == 0 && video_box->box_bottom == 0) {
460

461 462 463 464 465 466
    GST_LOG_OBJECT (video_box, "we are using passthrough");
    gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (video_box), TRUE);
  } else {
    GST_LOG_OBJECT (video_box, "we are not using passthrough");
    gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (video_box), FALSE);
  }
467

Wim Taymans's avatar
Wim Taymans committed
468
  return ret;
469 470 471 472 473 474 475

  /* ERRORS */
no_caps:
  {
    GST_DEBUG_OBJECT (video_box, "Could not get all caps fields");
    return FALSE;
  }
476 477
}

478
/* see gst-plugins/gst/games/gstvideoimage.c, paint_setup_I420() */
479 480 481
#define GST_VIDEO_I420_Y_ROWSTRIDE(width) (GST_ROUND_UP_4(width))
#define GST_VIDEO_I420_U_ROWSTRIDE(width) (GST_ROUND_UP_8(width)/2)
#define GST_VIDEO_I420_V_ROWSTRIDE(width) ((GST_ROUND_UP_8(GST_VIDEO_I420_Y_ROWSTRIDE(width)))/2)
482

483
#define GST_VIDEO_I420_Y_OFFSET(w,h) (0)
484 485
#define GST_VIDEO_I420_U_OFFSET(w,h) (GST_VIDEO_I420_Y_OFFSET(w,h)+(GST_VIDEO_I420_Y_ROWSTRIDE(w)*GST_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)*GST_ROUND_UP_2(h)/2))
486

487
#define GST_VIDEO_I420_SIZE(w,h)     (GST_VIDEO_I420_V_OFFSET(w,h)+(GST_VIDEO_I420_V_ROWSTRIDE(w)*GST_ROUND_UP_2(h)/2))
488

489 490 491
static gboolean
gst_video_box_get_unit_size (GstBaseTransform * trans, GstCaps * caps,
    guint * size)
Wim Taymans's avatar
Wim Taymans committed
492
{
493

Wim Taymans's avatar
Wim Taymans committed
494
  GstVideoBox *video_box;
495 496 497
  GstStructure *structure = NULL;
  guint32 fourcc;
  gint width, height;
Wim Taymans's avatar
Wim Taymans committed
498

Stefan Kost's avatar
Stefan Kost committed
499 500
  g_assert (size);

Wim Taymans's avatar
Wim Taymans committed
501 502
  video_box = GST_VIDEO_BOX (trans);

503 504 505 506 507 508 509 510 511 512 513 514 515 516 517
  structure = gst_caps_get_structure (caps, 0);
  gst_structure_get_fourcc (structure, "format", &fourcc);
  gst_structure_get_int (structure, "width", &width);
  gst_structure_get_int (structure, "height", &height);

  switch (fourcc) {
    case GST_MAKE_FOURCC ('A', 'Y', 'U', 'V'):
      *size = width * height * 4;
      break;
    case GST_MAKE_FOURCC ('I', '4', '2', '0'):
      *size = GST_VIDEO_I420_SIZE (width, height);
      break;
    default:
      return FALSE;
      break;
Wim Taymans's avatar
Wim Taymans committed
518
  }
519

520 521
  GST_LOG_OBJECT (video_box, "Returning from _unit_size %d", *size);

522
  return TRUE;
Wim Taymans's avatar
Wim Taymans committed
523 524
}

525 526 527
static const guint8 yuv_colors_Y[VIDEO_BOX_FILL_LAST] = { 16, 150, 29 };
static const guint8 yuv_colors_U[VIDEO_BOX_FILL_LAST] = { 128, 46, 255 };
static const guint8 yuv_colors_V[VIDEO_BOX_FILL_LAST] = { 128, 21, 107 };
528

529 530 531 532 533 534 535 536 537 538
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++) {
539
    oil_splat_u8_ns (dest, &fill_color, dest_width);
540 541 542 543 544
    dest += dest_stride;
  }

  /* copy and add left and right border */
  for (j = 0; j < src_crop_height; j++) {
545 546 547
    oil_splat_u8_ns (dest, &fill_color, bl);
    oil_memcpy (dest + bl, src, src_crop_width);
    oil_splat_u8_ns (dest + bl + src_crop_width, &fill_color, br);
548 549 550 551 552 553
    dest += dest_stride;
    src += src_stride;
  }

  /* bottom border */
  for (j = 0; j < bb; j++) {
554
    oil_splat_u8_ns (dest, &fill_color, dest_width);
555 556 557 558
    dest += dest_stride;
  }
}

559
static void
560
gst_video_box_apply_alpha (guint8 * dest, guint8 alpha)
561
{
562 563 564
  if (dest[0] != 0)
    dest[0] = alpha;
}
565

566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601
static void
gst_video_box_ayuv_ayuv (GstVideoBox * video_box, guint8 * src, guint8 * dest)
{
  gint dblen = video_box->out_height * video_box->out_width;
  guint32 *destb = (guint32 *) dest;
  guint32 *srcb = (guint32 *) src;
  guint8 b_alpha = (guint8) (video_box->border_alpha * 255);
  guint8 i_alpha = (guint8) (video_box->alpha * 255);
  gint br, bl, bt, bb, crop_w, crop_h;
  gint i;
  guint32 *loc = destb;
  guint32 empty_pixel;

  GST_LOG ("Processing AYUV -> AYUV data");

  crop_h = 0;
  crop_w = 0;
  empty_pixel = GUINT32_FROM_BE ((b_alpha << 24) |
      (yuv_colors_Y[video_box->fill_type] << 16) |
      (yuv_colors_U[video_box->fill_type] << 8) |
      yuv_colors_V[video_box->fill_type]);

  br = video_box->box_right;
  bl = video_box->box_left;
  bt = video_box->box_top;
  bb = video_box->box_bottom;

  if (br >= 0 && bl >= 0) {
    crop_w = video_box->in_width - (br + bl);
  } else if (br >= 0 && bl < 0) {
    crop_w = video_box->in_width - (br);
  } else if (br < 0 && bl >= 0) {
    crop_w = video_box->in_width - (bl);
  } else if (br < 0 && bl < 0) {
    crop_w = video_box->in_width;
  }
602

603 604 605 606 607 608 609 610 611
  if (bb >= 0 && bt >= 0) {
    crop_h = video_box->in_height - (bb + bt);
  } else if (bb >= 0 && bt < 0) {
    crop_h = video_box->in_height - (bb);
  } else if (bb < 0 && bt >= 0) {
    crop_h = video_box->in_height - (bt);
  } else if (bb < 0 && bt < 0) {
    crop_h = video_box->in_height;
  }
612

613 614
  GST_DEBUG ("Borders are: L:%d, R:%d, T:%d, B:%d", bl, br, bt, bb);
  GST_DEBUG ("Alpha value is: %d", i_alpha);
615

616
  if (crop_h <= 0 || crop_w <= 0) {
617

618
    oil_splat_u32_ns (destb, &empty_pixel, dblen);
619

620
  } else {
621

622
    guint32 *src_loc = srcb;
623

624 625 626 627 628 629 630
    /* Top border */
    if (bt < 0) {
      oil_splat_u32_ns (loc, &empty_pixel, (-bt) * video_box->out_width);
      loc = loc + ((-bt) * video_box->out_width);
    } else {
      src_loc = src_loc + (bt * video_box->in_width);
    }
631

632 633
    if (bl >= 0)
      src_loc += bl;
634

635 636
    for (i = 0; i < crop_h; i++) {
      gint j;
637

638 639 640 641 642
      /* Left border */
      if (bl < 0) {
        oil_splat_u32_ns (loc, &empty_pixel, -bl);
        loc += (-bl);
      }
643

644 645
      /* Cropped area */
      oil_copy_u8 ((guint8 *) loc, (guint8 *) src_loc, crop_w * 4);
646

647 648
      for (j = 0; j < crop_w; j++)
        gst_video_box_apply_alpha ((guint8 *) & loc[j], i_alpha);
649

650 651
      src_loc += video_box->in_width;
      loc += crop_w;
652

653 654 655 656 657 658
      /* Right border */
      if (br < 0) {
        oil_splat_u32_ns (loc, &empty_pixel, -br);
        loc += (-br);
      }
    }
659

660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702
    /* Bottom border */
    if (bb < 0) {
      oil_splat_u32_ns (loc, &empty_pixel, (-bb) * video_box->out_width);
    }
  }

  GST_LOG ("image created");

}

static gpointer
gst_video_box_clear (gpointer dest, gint size)
{
  guint8 nil = 255;

  oil_splat_u8_ns (dest, &nil, size);

  return dest;
}

static gint
UVfloor (gint j)
{
  return floor (((float) j) / 2);
}

static gint
UVceil (gint j)
{
  return ceil (((float) j) / 2);
}

static void
gst_video_box_ayuv_i420 (GstVideoBox * video_box, guint8 * src, guint8 * dest)
{
  gint br, bl, bt, bb, crop_w, crop_h, rest;
  gint Ysize, Usize, Vsize;
  guint8 *Ydest, *Udest, *Vdest;
  guint8 *Utemp, *Vtemp;
  guint32 empty_px_values[3];
  gint i, j;
  guint Ywidth, Uwidth, Vwidth;

703
  GST_LOG ("AYUV to I420 conversion");
704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756

  crop_h = 0;
  crop_w = 0;
  rest = 0;

  empty_px_values[0] = yuv_colors_Y[video_box->fill_type];
  empty_px_values[1] = yuv_colors_U[video_box->fill_type];
  empty_px_values[2] = yuv_colors_V[video_box->fill_type];

  Ywidth = GST_VIDEO_I420_Y_ROWSTRIDE (video_box->out_width);
  Uwidth = GST_VIDEO_I420_U_ROWSTRIDE (video_box->out_width);
  Vwidth = GST_VIDEO_I420_V_ROWSTRIDE (video_box->out_width);

  Ydest = dest + GST_VIDEO_I420_Y_OFFSET (video_box->out_width,
      video_box->out_height);
  Udest = Ydest + GST_VIDEO_I420_U_OFFSET (video_box->out_width,
      video_box->out_height);
  Vdest = Ydest + GST_VIDEO_I420_V_OFFSET (video_box->out_width,
      video_box->out_height);

  Ysize = Ywidth * video_box->out_height;
  Usize = Uwidth * UVceil (video_box->out_height);
  Vsize = Vwidth * UVceil (video_box->out_height);

  br = video_box->box_right;
  bl = video_box->box_left;
  bt = video_box->box_top;
  bb = video_box->box_bottom;

  if (br >= 0 && bl >= 0) {
    rest = Ywidth - video_box->out_width;
    crop_w = video_box->in_width - (bl + br);
  } else if (br >= 0 && bl < 0) {
    rest = Ywidth - video_box->out_width;
    crop_w = video_box->in_width - (br);
  } else if (br < 0 && bl >= 0) {
    rest = Ywidth - video_box->out_width;
    crop_w = video_box->in_width - (bl);
  } else if (br < 0 && bl < 0) {
    rest = Ywidth - video_box->out_width;
    crop_w = video_box->in_width;
  }

  if (bb >= 0 && bt >= 0) {
    crop_h = video_box->in_height - (bb + bt);
  } else if (bb >= 0 && bt < 0) {
    crop_h = video_box->in_height - (bb);
  } else if (bb < 0 && bt >= 0) {
    crop_h = video_box->in_height - (bt);
  } else if (bb < 0 && bt < 0) {
    crop_h = video_box->in_height;
  }

757 758
  Utemp = g_malloc0 (Uwidth);
  Vtemp = g_malloc0 (Vwidth);
759

760
  GST_LOG ("Borders are: L:%d, R:%d, T:%d, B:%d", bl, br, bt, bb);
761

762
  GST_LOG ("Starting conversion");
763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802

  if (crop_h <= 0 || crop_w <= 0) {

    oil_splat_u8_ns (Ydest, (guint8 *) & empty_px_values[0], Ysize);
    oil_splat_u8_ns (Udest, (guint8 *) & empty_px_values[1], Usize);
    oil_splat_u8_ns (Vdest, (guint8 *) & empty_px_values[2], Vsize);

  } else {

    gboolean sumbuff = FALSE;
    guint32 *src_loc1;
    gint a = 0;

    src_loc1 = (guint32 *) src;

    if (bt < 0) {
      oil_splat_u8_ns (Ydest, (guint8 *) & empty_px_values[0], (-bt) * Ywidth);

      oil_splat_u8_ns (Udest, (guint8 *) & empty_px_values[1],
          (UVfloor (-bt) * Uwidth) + 7);
      oil_splat_u8_ns (Vdest, (guint8 *) & empty_px_values[2],
          UVfloor (-bt) * Vwidth);

      if ((-bt) % 2 > 0) {
        oil_splat_u8_ns (Utemp, (guint8 *) & empty_px_values[1], Uwidth);
        oil_splat_u8_ns (Vtemp, (guint8 *) & empty_px_values[2], Vwidth);
        sumbuff = TRUE;
      }

      Ydest += ((-bt) * Ywidth);
      Udest += (UVfloor (-bt) * Uwidth);
      Vdest += (UVfloor (-bt) * Vwidth);

    } else {
      src_loc1 = src_loc1 + (bt * video_box->in_width);
    }

    if (bl >= 0)
      src_loc1 += bl;

803 804 805 806 807
    GST_LOG ("Cropped area");
    GST_LOG ("Ydest value: %p Ywidth: %u", Ydest, Ywidth);
    GST_LOG ("Udest value: %p Uwidth: %u", Udest, Uwidth);
    GST_LOG ("Vdest value: %p Vwidth: %u", Vdest, Vwidth);
    GST_LOG ("Rest: %d", rest);
808 809 810 811
    for (i = 0; i < crop_h; i++) {

      a = 0;
      if (sumbuff) {
812
        /* left border */
813 814 815 816 817 818 819 820 821 822 823 824
        if (bl < 0) {
          oil_splat_u8_ns (Ydest, (guint8 *) & empty_px_values[0], -bl);

          for (j = 0; j < -bl; j++) {
            Utemp[UVfloor (j)] = (Utemp[UVfloor (j)] + empty_px_values[1]) / 2;
            Vtemp[UVfloor (j)] = (Vtemp[UVfloor (j)] + empty_px_values[2]) / 2;
          }
          Ydest += -bl;
          a = -bl;
        }

        for (j = 0; j < crop_w; j++) {
825
          /* check ARCH */
826 827 828 829 830 831 832 833
          Ydest[j] = ((guint8 *) & src_loc1[j])[1];
          Utemp[UVfloor (a + j)] =
              (Utemp[UVfloor (a + j)] + ((guint8 *) & src_loc1[j])[2]) / 2;
          Vtemp[UVfloor (a + j)] =
              (Vtemp[UVfloor (a + j)] + ((guint8 *) & src_loc1[j])[3]) / 2;
        }
        Ydest += crop_w;

834
        /* right border */
835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856
        if (br < 0) {
          oil_splat_u8_ns (Ydest, (guint8 *) & empty_px_values[0], -br);
          for (j = 0; j < -br; j++) {
            Utemp[UVfloor (a + crop_w + j)] =
                (Utemp[UVfloor (a + crop_w + j)] + empty_px_values[1]) / 2;
            Vtemp[UVfloor (a + crop_w + j)] =
                (Vtemp[UVfloor (a + crop_w + j)] + empty_px_values[2]) / 2;
          }
          Ydest += -br;
        }
        oil_copy_u8 (Udest, Utemp, Uwidth);
        oil_copy_u8 (Vdest, Vtemp, Vwidth);
        Udest += Uwidth;
        Vdest += Vwidth;
        Ydest += rest;
        gst_video_box_clear (Utemp, Uwidth);
        gst_video_box_clear (Vtemp, Vwidth);
        src_loc1 += video_box->in_width;
        sumbuff = FALSE;

      } else {

857
        /* left border */
858 859 860 861 862 863 864 865 866 867 868 869 870
        a = 0;
        if (bl < 0) {
          oil_splat_u8_ns (Ydest, (guint8 *) & empty_px_values[0], -bl);
          oil_splat_u8_ns (Vtemp, (guint8 *) & empty_px_values[1],
              UVceil (-bl));
          oil_splat_u8_ns (Utemp, (guint8 *) & empty_px_values[2],
              UVceil (-bl));
          Ydest += -bl;
          a = -bl;
        }

        for (j = 0; j < crop_w; j++) {

871
          /* check ARCH */
872 873 874 875 876 877 878 879 880 881 882 883 884 885
          Ydest[j] = ((guint8 *) & src_loc1[j])[1];

          if ((a + j) % 2 > 0) {
            Utemp[UVfloor (a + j)] =
                (Utemp[UVfloor (a + j)] + ((guint8 *) & src_loc1[j])[2]) / 2;
            Vtemp[UVfloor (a + j)] =
                (Vtemp[UVfloor (a + j)] + ((guint8 *) & src_loc1[j])[3]) / 2;
          } else {
            Utemp[UVfloor (a + j)] = ((guint8 *) & src_loc1[j])[2] / 2;
            Vtemp[UVfloor (a + j)] = ((guint8 *) & src_loc1[j])[3] / 2;
          }
        }
        Ydest += crop_w;

886
        /* right border */
887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911
        if (br < 0) {
          j = 0;
          if ((a + crop_w) % 2 > 0) {
            Utemp[UVfloor (a + crop_w)] =
                (Utemp[UVfloor (a + crop_w)] + empty_px_values[1]) / 2;
            Vtemp[UVfloor (a + crop_w)] =
                (Vtemp[UVfloor (a + crop_w)] + empty_px_values[2]) / 2;
            a++;
            j = -1;
          }

          oil_splat_u8_ns (Ydest, (guint8 *) & empty_px_values[0], -br);
          oil_splat_u8_ns (&Utemp[UVfloor (a + crop_w)],
              (guint8 *) & empty_px_values[1], UVceil ((-br) + j));
          oil_splat_u8_ns (&Vtemp[UVfloor (a + crop_w)],
              (guint8 *) & empty_px_values[2], UVceil ((-br) + j));
          Ydest += -br;
        }
        Ydest += rest;
        src_loc1 += video_box->in_width;
        sumbuff = TRUE;

      }
    }

912
    /* bottom border */
913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942
    if (bb < 0) {
      oil_splat_u8_ns (Ydest, (guint8 *) & empty_px_values[0], (-bb) * Ywidth);
      if (sumbuff) {
        for (i = 0; i < Uwidth; i++) {
          Utemp[i] = (Utemp[i] + empty_px_values[1]) / 2;
        }
        for (i = 0; i < Vwidth; i++) {
          Vtemp[i] = (Vtemp[i] + empty_px_values[2]) / 2;
        }

        oil_copy_u8 (Udest, Utemp, Uwidth);
        oil_copy_u8 (Vdest, Vtemp, Vwidth);
        Udest += Uwidth;
        Vdest += Vwidth;
        sumbuff = FALSE;
      }
      oil_splat_u8_ns (Udest, (guint8 *) & empty_px_values[1],
          (UVfloor ((-bb))) * Uwidth);
      oil_splat_u8_ns (Vdest, (guint8 *) & empty_px_values[2],
          (UVfloor ((-bb))) * Vwidth);
    }
    if (sumbuff) {
      oil_copy_u8 (Udest, Utemp, Uwidth);
      oil_copy_u8 (Vdest, Vtemp, Vwidth);
    }
  }

  GST_LOG ("image created");
  g_free (Utemp);
  g_free (Vtemp);
943 944 945
}

static void
946
gst_video_box_i420_ayuv (GstVideoBox * video_box, guint8 * src, guint8 * dest)
947 948 949
{
  guint8 *srcY, *srcU, *srcV;
  gint crop_width, crop_width2, crop_height;
950
  gint out_width;
951
  gint src_stridey, src_strideu, src_stridev;
952 953 954 955 956
  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);
957 958
  guint32 *destp;
  guint32 *destb = (guint32 *) dest;
959 960 961 962 963 964 965 966 967
  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;

968 969 970
  src_stridey = GST_VIDEO_I420_Y_ROWSTRIDE (video_box->in_width);
  src_strideu = GST_VIDEO_I420_U_ROWSTRIDE (video_box->in_width);
  src_stridev = GST_VIDEO_I420_V_ROWSTRIDE (video_box->in_width);
971

972 973
  crop_width = video_box->in_width;
  crop_width -= (video_box->crop_left + video_box->crop_right);
974
  crop_width2 = crop_width / 2;
975 976
  crop_height = video_box->in_height;
  crop_height -= (video_box->crop_top + video_box->crop_bottom);
977 978 979

  srcY =
      src + GST_VIDEO_I420_Y_OFFSET (video_box->in_width, video_box->in_height);
980
  srcY += src_stridey * video_box->crop_top + video_box->crop_left;
981 982
  srcU =
      src + GST_VIDEO_I420_U_OFFSET (video_box->in_width, video_box->in_height);
983
  srcU += src_strideu * (video_box->crop_top / 2) + (video_box->crop_left / 2);
984 985
  srcV =
      src + GST_VIDEO_I420_V_OFFSET (video_box->in_width, video_box->in_height);
986
  srcV += src_stridev * (video_box->crop_top / 2) + (video_box->crop_left / 2);
987 988 989 990 991 992 993 994 995 996

  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 */
997 998 999
  if (bt) {
    size_t nb_pixels = bt * out_width;

1000 1001
    oil_splat_u32_ns (destb, &ayuv, nb_pixels);
    destb += nb_pixels;
1002 1003
  }
  for (i = 0; i < crop_height; i++) {
1004
    destp = destb;
1005
    /* left border */
1006 1007 1008
    if (bl) {
      oil_splat_u32_ns (destp, &ayuv, bl);
      destp += bl;
1009 1010 1011
    }
    dest = (guint8 *) destp;
    /* center */
1012 1013
    /* We can splat the alpha channel for the whole line */
    oil_splat_u8 (dest, 4, &i_alpha, crop_width);
1014
    for (j = 0; j < crop_width2; j++) {
1015
      dest++;
1016 1017 1018
      *dest++ = *srcY++;
      *dest++ = *srcU;
      *dest++ = *srcV;
1019
      dest++;
1020 1021 1022 1023 1024 1025 1026 1027
      *dest++ = *srcY++;
      *dest++ = *srcU++;
      *dest++ = *srcV++;
    }
    if (i % 2 == 0) {
      srcU -= crop_width2;
      srcV -= crop_width2;
    } else {
1028 1029
      srcU += src_strideu - crop_width2;
      srcV += src_stridev - crop_width2;
1030
    }
1031
    srcY += src_stridey - (crop_width2 * 2);
1032 1033 1034

    destp = (guint32 *) dest;
    /* right border */
1035 1036
    if (br) {
      oil_splat_u32_ns (destp, &ayuv, br);
1037
    }
1038
    destb += out_width;
1039 1040
  }
  /* bottom border */
1041 1042 1043
  if (bb) {
    size_t nb_pixels = bb * out_width;

1044
    oil_splat_u32_ns (destb, &ayuv, nb_pixels);
1045 1046 1047
  }
}

1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086

static void
gst_video_box_i420_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;
  gint src_width, src_height;
  gint src_stride, dest_stride;
  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;

  src_width = video_box->in_width;
  src_height = video_box->in_height;

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

  /* Y plane */
  src_stride = GST_VIDEO_I420_Y_ROWSTRIDE (src_width);
  dest_stride = GST_VIDEO_I420_Y_ROWSTRIDE (out_width);

  destY = dest + GST_VIDEO_I420_Y_OFFSET (out_width, out_height);

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

  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]);

1087 1088 1089 1090 1091 1092 1093 1094 1095
  br /= 2;
  bb /= 2;
  bl /= 2;
  bt /= 2;

  /* we need to round up to make sure we draw all the U and V lines */
  crop_width = (crop_width + 1) / 2;
  crop_height = (crop_height + 1) / 2;

1096 1097 1098 1099 1100 1101 1102 1103 1104
  /* U plane */
  src_stride = GST_VIDEO_I420_U_ROWSTRIDE (src_width);
  dest_stride = GST_VIDEO_I420_U_ROWSTRIDE (out_width);

  destU = dest + GST_VIDEO_I420_U_OFFSET (out_width, out_height);

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

1105 1106 1107
  gst_video_box_copy_plane_i420 (video_box, srcU, destU, br, bl, bt, bb,
      crop_width, crop_height, src_stride, out_width / 2, dest_stride,
      yuv_colors_U[video_box->fill_type]);
1108 1109 1110 1111 1112 1113 1114 1115 1116 1117

  /* 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);

1118 1119 1120
  gst_video_box_copy_plane_i420 (video_box, srcV, destV, br, bl, bt, bb,
      crop_width, crop_height, src_stride, out_width / 2, dest_stride,
      yuv_colors_V[video_box->fill_type]);
1121 1122
}

Wim Taymans's avatar
Wim Taymans committed
1123
static GstFlowReturn
1124
gst_video_box_transform (GstBaseTransform * trans, GstBuffer * in,
Wim Taymans's avatar
Wim Taymans committed
1125
    GstBuffer * out)
1126 1127
{
  GstVideoBox *video_box;
1128
  guint8 *indata, *outdata;
1129

1130
  video_box = GST_VIDEO_BOX (trans);
1131

1132 1133
  indata = GST_BUFFER_DATA (in);
  outdata = GST_BUFFER_DATA (out);
1134

1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162
  switch (video_box->in_fourcc) {
    case GST_MAKE_FOURCC ('A', 'Y', 'U', 'V'):
      switch (video_box->out_fourcc) {
        case GST_MAKE_FOURCC ('A', 'Y', 'U', 'V'):
          gst_video_box_ayuv_ayuv (video_box, indata, outdata);
          break;
        case GST_MAKE_FOURCC ('I', '4', '2', '0'):
          gst_video_box_ayuv_i420 (video_box, indata, outdata);
          break;
        default:
          goto invalid_format;
      }
      break;
    case GST_MAKE_FOURCC ('I', '4', '2', '0'):
      switch (video_box->out_fourcc) {
        case GST_MAKE_FOURCC ('A', 'Y', 'U', 'V'):
          gst_video_box_i420_ayuv (video_box, indata, outdata);
          break;
        case GST_MAKE_FOURCC ('I', '4', '2', '0'):
          gst_video_box_i420_i420 (video_box, indata, outdata);
          break;
        default:
          goto invalid_format;
      }
      break;
    default:
      goto invalid_format;
  }
Wim Taymans's avatar
Wim Taymans committed
1163
  return GST_FLOW_OK;
1164 1165 1166 1167 1168 1169

  /* ERRORS */
invalid_format:
  {
    return GST_FLOW_ERROR;
  }
1170 1171
}

1172
/* FIXME: 0.11 merge with videocrop plugin */
1173 1174 1175
static gboolean
plugin_init (GstPlugin * plugin)
{
1176 1177
  oil_init ();

1178 1179 1180 1181 1182 1183 1184 1185
  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",
1186
    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)