gstvideobox.c 34.5 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
#include <gst/video/video.h>
26
#include <math.h>
27
#include <liboil/liboil.h>
28
29
#include <string.h>

30
GST_DEBUG_CATEGORY_STATIC (videobox_debug);
31
32
#define GST_CAT_DEFAULT videobox_debug

33
34
35
36
37
38
39
40
#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
41
#define GST_IS_VIDEO_BOX_CLASS(klass) \
42
43
44
45
46
47
48
49
50
51
  (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,
52
  VIDEO_BOX_FILL_LAST
53
54
55
56
57
}
GstVideoBoxFill;

struct _GstVideoBox
{
58
  GstBaseTransform element;
59
60

  /* caps */
61
  guint32 in_fourcc;
62
  gint in_width, in_height;
63
  guint32 out_fourcc;
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
  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
{
79
  GstBaseTransformClass parent_class;
80
81
82
};

/* elementfactory information */
83
static const GstElementDetails gst_video_box_details =
Wim Taymans's avatar
Wim Taymans committed
84
GST_ELEMENT_DETAILS ("Video box filter",
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
    "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
{
100
101
102
103
104
105
106
  PROP_0,
  PROP_LEFT,
  PROP_RIGHT,
  PROP_TOP,
  PROP_BOTTOM,
  PROP_FILL_TYPE,
  PROP_ALPHA,
107
108
  PROP_BORDER_ALPHA
      /* FILL ME */
109
110
111
};

static GstStaticPadTemplate gst_video_box_src_template =
112
    GST_STATIC_PAD_TEMPLATE ("src",
113
114
    GST_PAD_SRC,
    GST_PAD_ALWAYS,
115
116
    GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV") ";"
        GST_VIDEO_CAPS_YUV ("I420"))
117
118
119
    );

static GstStaticPadTemplate gst_video_box_sink_template =
120
    GST_STATIC_PAD_TEMPLATE ("sink",
121
122
    GST_PAD_SINK,
    GST_PAD_ALWAYS,
123
124
    GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV") ";"
        GST_VIDEO_CAPS_YUV ("I420"))
125
126
127
    );


128
129
GST_BOILERPLATE (GstVideoBox, gst_video_box, GstBaseTransform,
    GST_TYPE_BASE_TRANSFORM);
130
131
132
133
134
135

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

136
static gboolean video_box_recalc_transform (GstVideoBox * video_box);
137
static GstCaps *gst_video_box_transform_caps (GstBaseTransform * trans,
138
    GstPadDirection direction, GstCaps * from);
139
140
static gboolean gst_video_box_set_caps (GstBaseTransform * trans,
    GstCaps * in, GstCaps * out);
141
142
static gboolean gst_video_box_get_unit_size (GstBaseTransform * trans,
    GstCaps * caps, guint * size);
143
static GstFlowReturn gst_video_box_transform (GstBaseTransform * trans,
Wim Taymans's avatar
Wim Taymans committed
144
    GstBuffer * in, GstBuffer * out);
145
146
147
148
149
150
151


#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;
152
  static const GEnumValue video_box_fill[] = {
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
153
154
155
    {VIDEO_BOX_FILL_BLACK, "Black", "black"},
    {VIDEO_BOX_FILL_GREEN, "Colorkey green", "green"},
    {VIDEO_BOX_FILL_BLUE, "Colorkey blue", "blue"},
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
    {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));
}
179

180
181
182
183
static void
gst_video_box_class_init (GstVideoBoxClass * klass)
{
  GObjectClass *gobject_class;
184
  GstBaseTransformClass *trans_class;
185
186

  gobject_class = (GObjectClass *) klass;
187
  trans_class = (GstBaseTransformClass *) klass;
188

Wim Taymans's avatar
Wim Taymans committed
189
190
191
  gobject_class->set_property = gst_video_box_set_property;
  gobject_class->get_property = gst_video_box_get_property;

192
  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_FILL_TYPE,
193
194
195
      g_param_spec_enum ("fill", "Fill", "How to fill the borders",
          GST_TYPE_VIDEO_BOX_FILL, DEFAULT_FILL_TYPE,
          (GParamFlags) G_PARAM_READWRITE));
196
  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LEFT,
197
198
199
      g_param_spec_int ("left", "Left",
          "Pixels to box at left (<0  = add a border)", G_MININT, G_MAXINT,
          DEFAULT_LEFT, G_PARAM_READWRITE));
200
  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_RIGHT,
201
202
203
      g_param_spec_int ("right", "Right",
          "Pixels to box at right (<0 = add a border)", G_MININT, G_MAXINT,
          DEFAULT_RIGHT, G_PARAM_READWRITE));
204
  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TOP,
205
206
207
      g_param_spec_int ("top", "Top",
          "Pixels to box at top (<0 = add a border)", G_MININT, G_MAXINT,
          DEFAULT_TOP, G_PARAM_READWRITE));
208
  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BOTTOM,
209
210
211
      g_param_spec_int ("bottom", "Bottom",
          "Pixels to box at bottom (<0 = add a border)", G_MININT, G_MAXINT,
          DEFAULT_BOTTOM, G_PARAM_READWRITE));
212
  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ALPHA,
213
214
      g_param_spec_double ("alpha", "Alpha", "Alpha value picture", 0.0, 1.0,
          DEFAULT_ALPHA, G_PARAM_READWRITE));
215
  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BORDER_ALPHA,
216
217
218
219
      g_param_spec_double ("border_alpha", "Border Alpha",
          "Alpha value of the border", 0.0, 1.0, DEFAULT_BORDER_ALPHA,
          G_PARAM_READWRITE));

220
  trans_class->transform = GST_DEBUG_FUNCPTR (gst_video_box_transform);
221
222
223
224
  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);
225
226
227

  GST_DEBUG_CATEGORY_INIT (videobox_debug, "videobox", 0,
      "Resizes a video by adding borders or cropping");
228
229
230
}

static void
231
gst_video_box_init (GstVideoBox * video_box, GstVideoBoxClass * g_class)
232
233
234
235
236
{
  video_box->box_right = DEFAULT_RIGHT;
  video_box->box_left = DEFAULT_LEFT;
  video_box->box_top = DEFAULT_TOP;
  video_box->box_bottom = DEFAULT_BOTTOM;
237
238
239
240
  video_box->crop_right = 0;
  video_box->crop_left = 0;
  video_box->crop_top = 0;
  video_box->crop_bottom = 0;
241
242
243
244
245
246
247
248
249
  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)
{
250
  GstVideoBox *video_box = GST_VIDEO_BOX (object);
251

252
  GST_BASE_TRANSFORM_LOCK (GST_BASE_TRANSFORM_CAST (video_box));
253
  switch (prop_id) {
254
    case PROP_LEFT:
255
256
257
258
259
260
261
262
263
      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;
264
    case PROP_RIGHT:
265
266
267
268
269
270
271
272
273
      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;
274
    case PROP_TOP:
275
276
277
278
279
280
281
282
283
      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;
284
    case PROP_BOTTOM:
285
286
287
288
289
290
291
292
293
      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;
294
    case PROP_FILL_TYPE:
295
296
      video_box->fill_type = g_value_get_enum (value);
      break;
297
    case PROP_ALPHA:
298
299
      video_box->alpha = g_value_get_double (value);
      break;
300
    case PROP_BORDER_ALPHA:
301
302
303
304
305
306
      video_box->border_alpha = g_value_get_double (value);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
307
308
  video_box_recalc_transform (video_box);
  GST_BASE_TRANSFORM_UNLOCK (GST_BASE_TRANSFORM_CAST (video_box));
309
}
310

311
312
313
314
static void
gst_video_box_get_property (GObject * object, guint prop_id, GValue * value,
    GParamSpec * pspec)
{
315
  GstVideoBox *video_box = GST_VIDEO_BOX (object);
316
317

  switch (prop_id) {
318
    case PROP_LEFT:
319
320
      g_value_set_int (value, video_box->box_left);
      break;
321
    case PROP_RIGHT:
322
323
      g_value_set_int (value, video_box->box_right);
      break;
324
    case PROP_TOP:
325
326
      g_value_set_int (value, video_box->box_top);
      break;
327
    case PROP_BOTTOM:
328
329
      g_value_set_int (value, video_box->box_bottom);
      break;
330
    case PROP_FILL_TYPE:
331
332
      g_value_set_enum (value, video_box->fill_type);
      break;
333
    case PROP_ALPHA:
334
335
      g_value_set_double (value, video_box->alpha);
      break;
336
    case PROP_BORDER_ALPHA:
337
338
339
340
341
342
343
344
      g_value_set_double (value, video_box->border_alpha);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}

345
static GstCaps *
346
347
gst_video_box_transform_caps (GstBaseTransform * trans,
    GstPadDirection direction, GstCaps * from)
348
349
{
  GstVideoBox *video_box;
350
351
  GstCaps *to, *ret;
  const GstCaps *templ;
352
  GstStructure *structure;
353
354
  GstPad *other;
  gint width, height;
355
356

  video_box = GST_VIDEO_BOX (trans);
357

358
  to = gst_caps_copy (from);
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
  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;

    GST_DEBUG ("New caps width: %d", width);
    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;
387
    }
388
389
390
391
392
393

    if (height <= 0)
      height = 1;

    GST_DEBUG ("New caps height: %d", height);
    gst_structure_set (structure, "height", G_TYPE_INT, height, NULL);
394
395
  }

396
397
398
399
400
401
  /* 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);
402

403
  GST_DEBUG_OBJECT (video_box, "direction %d, transformed %" GST_PTR_FORMAT
404
405
406
407
408
409
410
411
412
      " to %" GST_PTR_FORMAT, direction, from, ret);

  return ret;
}

static gboolean
video_box_recalc_transform (GstVideoBox * video_box)
{
  gboolean res = TRUE;
413

414
415
416
417
418
419
420
421
422
423
424
425
426
  /* 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) {

    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);
  }
  return res;
427
428
}

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

436
  video_box = GST_VIDEO_BOX (trans);
437

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

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

448
449
450
451
452
453
454
455
456
  /* something wrong getting the caps */
  if (!ret)
    goto no_caps;

  GST_DEBUG ("Input w: %d h: %d", video_box->in_width, video_box->in_height);
  GST_DEBUG ("Output w: %d h: %d", video_box->out_width, video_box->out_height);

  /* recalc the transformation strategy */
  ret = video_box_recalc_transform (video_box);
457

Wim Taymans's avatar
Wim Taymans committed
458
  return ret;
459
460
461
462
463
464
465

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

468
/* see gst-plugins/gst/games/gstvideoimage.c, paint_setup_I420() */
469
470
471
#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)
472

473
#define GST_VIDEO_I420_Y_OFFSET(w,h) (0)
474
475
#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))
476

477
#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))
478

479
480
481
static gboolean
gst_video_box_get_unit_size (GstBaseTransform * trans, GstCaps * caps,
    guint * size)
Wim Taymans's avatar
Wim Taymans committed
482
{
483

Wim Taymans's avatar
Wim Taymans committed
484
  GstVideoBox *video_box;
485
486
487
  GstStructure *structure = NULL;
  guint32 fourcc;
  gint width, height;
Wim Taymans's avatar
Wim Taymans committed
488

Stefan Kost's avatar
Stefan Kost committed
489
490
  g_assert (size);

Wim Taymans's avatar
Wim Taymans committed
491
492
  video_box = GST_VIDEO_BOX (trans);

493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
  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
508
  }
509

510
511
  GST_LOG_OBJECT (video_box, "Returning from _unit_size %d", *size);

512
  return TRUE;
Wim Taymans's avatar
Wim Taymans committed
513
514
}

515
516
517
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 };
518

519
520
521
522
523
524
525
526
527
528
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++) {
529
    oil_splat_u8_ns (dest, &fill_color, dest_width);
530
531
532
533
534
    dest += dest_stride;
  }

  /* copy and add left and right border */
  for (j = 0; j < src_crop_height; j++) {
535
536
537
    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);
538
539
540
541
542
543
    dest += dest_stride;
    src += src_stride;
  }

  /* bottom border */
  for (j = 0; j < bb; j++) {
544
    oil_splat_u8_ns (dest, &fill_color, dest_width);
545
546
547
548
    dest += dest_stride;
  }
}

549
static void
550
gst_video_box_apply_alpha (guint8 * dest, guint8 alpha)
551
{
552
553
554
  if (dest[0] != 0)
    dest[0] = alpha;
}
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
581
582
583
584
585
586
587
588
589
590
591
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;
  }
592

593
594
595
596
597
598
599
600
601
  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;
  }
602

603
604
  GST_DEBUG ("Borders are: L:%d, R:%d, T:%d, B:%d", bl, br, bt, bb);
  GST_DEBUG ("Alpha value is: %d", i_alpha);
605

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

608
    oil_splat_u32_ns (destb, &empty_pixel, dblen);
609

610
  } else {
611

612
    guint32 *src_loc = srcb;
613

614
615
616
617
618
619
620
    /* 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);
    }
621

622
623
    if (bl >= 0)
      src_loc += bl;
624

625
626
    for (i = 0; i < crop_h; i++) {
      gint j;
627

628
629
630
631
632
      /* Left border */
      if (bl < 0) {
        oil_splat_u32_ns (loc, &empty_pixel, -bl);
        loc += (-bl);
      }
633

634
635
      /* Cropped area */
      oil_copy_u8 ((guint8 *) loc, (guint8 *) src_loc, crop_w * 4);
636

637
638
      for (j = 0; j < crop_w; j++)
        gst_video_box_apply_alpha ((guint8 *) & loc[j], i_alpha);
639

640
641
      src_loc += video_box->in_width;
      loc += crop_w;
642

643
644
645
646
647
648
      /* Right border */
      if (br < 0) {
        oil_splat_u32_ns (loc, &empty_pixel, -br);
        loc += (-br);
      }
    }
649

650
651
652
653
654
655
656
657
658
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
    /* 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;

693
  GST_LOG ("AYUV to I420 conversion");
694
695
696
697
698
699
700
701
702
703
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

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

747
748
  Utemp = g_malloc0 (Uwidth);
  Vtemp = g_malloc0 (Vwidth);
749

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

752
  GST_LOG ("Starting conversion");
753
754
755
756
757
758
759
760
761
762
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

  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;

793
794
795
796
797
    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);
798
799
800
801
    for (i = 0; i < crop_h; i++) {

      a = 0;
      if (sumbuff) {
802
        /* left border */
803
804
805
806
807
808
809
810
811
812
813
814
        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++) {
815
          /* check ARCH */
816
817
818
819
820
821
822
823
          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;

824
        /* right border */
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
        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 {

847
        /* left border */
848
849
850
851
852
853
854
855
856
857
858
859
860
        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++) {

861
          /* check ARCH */
862
863
864
865
866
867
868
869
870
871
872
873
874
875
          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;

876
        /* right border */
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
        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;

      }
    }

902
    /* bottom border */
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
    if (bb < 0) {
      a = 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;
        a = -1;
      }
      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);
935
936
937
}

static void
938
gst_video_box_i420_ayuv (GstVideoBox * video_box, guint8 * src, guint8 * dest)
939
940
941
942
{
  guint8 *srcY, *srcU, *srcV;
  gint crop_width, crop_width2, crop_height;
  gint out_width, out_height;
943
  gint src_stridey, src_strideu, src_stridev;
944
945
946
947
948
  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);
949
950
  guint32 *destp;
  guint32 *destb = (guint32 *) dest;
951
952
953
954
955
956
957
958
959
960
  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;

961
962
963
  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);
964

965
966
  crop_width = video_box->in_width;
  crop_width -= (video_box->crop_left + video_box->crop_right);
967
  crop_width2 = crop_width / 2;
968
969
  crop_height = video_box->in_height;
  crop_height -= (video_box->crop_top + video_box->crop_bottom);
970
971
972

  srcY =
      src + GST_VIDEO_I420_Y_OFFSET (video_box->in_width, video_box->in_height);
973
  srcY += src_stridey * video_box->crop_top + video_box->crop_left;
974
975
  srcU =
      src + GST_VIDEO_I420_U_OFFSET (video_box->in_width, video_box->in_height);
976
  srcU += src_strideu * (video_box->crop_top / 2) + (video_box->crop_left / 2);
977
978
  srcV =
      src + GST_VIDEO_I420_V_OFFSET (video_box->in_width, video_box->in_height);
979
  srcV += src_stridev * (video_box->crop_top / 2) + (video_box->crop_left / 2);
980
981
982
983
984
985
986
987
988
989

  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 */
990
991
992
  if (bt) {
    size_t nb_pixels = bt * out_width;

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

    destp = (guint32 *) dest;
    /* right border */
1028
1029
1030
    if (br) {
      oil_splat_u32_ns (destp, &ayuv, br);
      destp += br;
1031
    }
1032
    destb += out_width;
1033
1034
  }
  /* bottom border */
1035
1036
1037
  if (bb) {
    size_t nb_pixels = bb * out_width;

1038
1039
    oil_splat_u32_ns (destb, &ayuv, nb_pixels);
    destb += nb_pixels;
1040
1041
1042
  }
}

1043
1044
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
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108

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

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

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

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

Wim Taymans's avatar
Wim Taymans committed
1109
static GstFlowReturn
1110
gst_video_box_transform (GstBaseTransform * trans, GstBuffer * in,
Wim Taymans's avatar
Wim Taymans committed
1111
    GstBuffer * out)
1112
1113
{
  GstVideoBox *video_box;
1114
  guint8 *indata, *outdata;
1115

1116
  video_box = GST_VIDEO_BOX (trans);
1117

1118
1119
  indata = GST_BUFFER_DATA (in);
  outdata = GST_BUFFER_DATA (out);
1120

1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
  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
1149
  return GST_FLOW_OK;
1150
1151
1152
1153
1154
1155

  /* ERRORS */
invalid_format:
  {
    return GST_FLOW_ERROR;
  }
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
}

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",
1169
    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)