gstsmpte.c 17.7 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* 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.
 */

20
21
22
23
24
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
/**
 * SECTION:element-smpte
 * @short_description: Takes to video frames and applies an SMPTE transition 
 * effect on them.
 *
 * <refsect2>
 * <para>
 * smpte can accept I420 video streams with the same width, height and
 * framerate. The two incomming buffers are blended together using an effect
 * specific alpha mask. 
 * </para>
 * <para>
 * The depth property defines the presision in bits of the mask. A higher
 * presision will create a mask with smoother gradients in order to avoid
 * banding.
 * </para>
 * <title>Sample pipelines</title>
 * <para>
 * Here is a pipeline to demonstrate the smpte transition :
 * <programlisting>
 * gst-launch -v videotestsrc pattern=1 ! smpte name=s border=20000 type=234
 * duration=2000000000 ! ffmpegcolorspace ! ximagesink videotestsrc ! s.
 * </programlisting>
 * This shows a pinwheel transition a from a snow videotestsrc to an smpte
 * pattern videotestsrc. The transition will take 2 seconds to complete. The
 * edges of the transition are smoothed with a 20000 big border.
 * </para>
 * </refsect2>
 */

50
51
52
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
53
#include <string.h>
54
#include "gstsmpte.h"
55
#include <gst/video/video.h>
56
57
#include "paint.h"

58
59
60
GST_DEBUG_CATEGORY_STATIC (gst_smpte_debug);
#define GST_CAT_DEFAULT gst_smpte_debug

61
/* elementfactory information */
62
static const GstElementDetails smpte_details =
Wim Taymans's avatar
Wim Taymans committed
63
64
65
66
GST_ELEMENT_DETAILS ("SMPTE transitions",
    "Filter/Editor/Video",
    "Apply the standard SMPTE transitions on video images",
    "Wim Taymans <wim.taymans@chello.be>");
67

David Schleef's avatar
David Schleef committed
68
static GstStaticPadTemplate gst_smpte_src_template =
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
69
70
71
72
73
74
GST_STATIC_PAD_TEMPLATE ("src",
    GST_PAD_SRC,
    GST_PAD_ALWAYS,
    GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("I420")
    )
    );
75

David Schleef's avatar
David Schleef committed
76
static GstStaticPadTemplate gst_smpte_sink1_template =
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
77
78
79
80
81
82
GST_STATIC_PAD_TEMPLATE ("sink1",
    GST_PAD_SINK,
    GST_PAD_ALWAYS,
    GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("I420")
    )
    );
83

David Schleef's avatar
David Schleef committed
84
static GstStaticPadTemplate gst_smpte_sink2_template =
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
85
86
87
88
89
90
GST_STATIC_PAD_TEMPLATE ("sink2",
    GST_PAD_SINK,
    GST_PAD_ALWAYS,
    GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("I420")
    )
    );
91
92
93


/* SMPTE signals and args */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
94
95
enum
{
96
97
98
99
  /* FILL ME */
  LAST_SIGNAL
};

100
101
102
103
104
105
#define DEFAULT_PROP_TYPE	1
#define DEFAULT_PROP_BORDER	0
#define DEFAULT_PROP_DEPTH	16
#define DEFAULT_PROP_FPS	0.
#define DEFAULT_PROP_DURATION	GST_SECOND

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
106
107
enum
{
108
109
110
111
112
113
114
  PROP_0,
  PROP_TYPE,
  PROP_BORDER,
  PROP_DEPTH,
  PROP_FPS,
  PROP_DURATION,
  PROP_LAST,
115
116
};

117
118
119
120
121
122
123
124
125
126
127
#define I420_Y_ROWSTRIDE(width) (GST_ROUND_UP_4(width))
#define I420_U_ROWSTRIDE(width) (GST_ROUND_UP_8(width)/2)
#define I420_V_ROWSTRIDE(width) ((GST_ROUND_UP_8(I420_Y_ROWSTRIDE(width)))/2)

#define I420_Y_OFFSET(w,h) (0)
#define I420_U_OFFSET(w,h) (I420_Y_OFFSET(w,h)+(I420_Y_ROWSTRIDE(w)*GST_ROUND_UP_2(h)))
#define I420_V_OFFSET(w,h) (I420_U_OFFSET(w,h)+(I420_U_ROWSTRIDE(w)*GST_ROUND_UP_2(h)/2))

#define I420_SIZE(w,h)     (I420_V_OFFSET(w,h)+(I420_V_ROWSTRIDE(w)*GST_ROUND_UP_2(h)/2))


128
129
#define GST_TYPE_SMPTE_TRANSITION_TYPE (gst_smpte_transition_type_get_type())
static GType
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
130
gst_smpte_transition_type_get_type (void)
131
132
133
134
135
136
{
  static GType smpte_transition_type = 0;
  GEnumValue *smpte_transitions;

  if (!smpte_transition_type) {
    const GList *definitions;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
137
    gint i = 0;
138
139

    definitions = gst_mask_get_definitions ();
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
140
    smpte_transitions =
141
        g_new0 (GEnumValue, g_list_length ((GList *) definitions) + 1);
142
143
144

    while (definitions) {
      GstMaskDefinition *definition = (GstMaskDefinition *) definitions->data;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
145

146
147
148
      definitions = g_list_next (definitions);

      smpte_transitions[i].value = definition->type;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
149
150
      smpte_transitions[i].value_nick = definition->short_name;
      smpte_transitions[i].value_name = definition->long_name;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
151

152
153
154
      i++;
    }

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
155
    smpte_transition_type =
156
        g_enum_register_static ("GstSMPTETransitionType", smpte_transitions);
157
158
  }
  return smpte_transition_type;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
159
}
160
161


Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
162
163
164
static void gst_smpte_class_init (GstSMPTEClass * klass);
static void gst_smpte_base_init (GstSMPTEClass * klass);
static void gst_smpte_init (GstSMPTE * smpte);
165

166
167
static GstFlowReturn gst_smpte_collected (GstCollectPads * pads,
    GstSMPTE * smpte);
168

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
169
170
171
172
static void gst_smpte_set_property (GObject * object, guint prop_id,
    const GValue * value, GParamSpec * pspec);
static void gst_smpte_get_property (GObject * object, guint prop_id,
    GValue * value, GParamSpec * pspec);
173

174
175
176
static GstStateChangeReturn gst_smpte_change_state (GstElement * element,
    GstStateChange transition);

177
static GstElementClass *parent_class = NULL;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
178

179
180
181
182
183
184
185
186
187
/*static guint gst_smpte_signals[LAST_SIGNAL] = { 0 }; */

static GType
gst_smpte_get_type (void)
{
  static GType smpte_type = 0;

  if (!smpte_type) {
    static const GTypeInfo smpte_info = {
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
188
189
      sizeof (GstSMPTEClass),
      (GBaseInitFunc) gst_smpte_base_init,
190
      NULL,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
191
      (GClassInitFunc) gst_smpte_class_init,
192
193
      NULL,
      NULL,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
194
      sizeof (GstSMPTE),
195
      0,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
196
      (GInstanceInitFunc) gst_smpte_init,
197
    };
198

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
199
    smpte_type =
200
        g_type_register_static (GST_TYPE_ELEMENT, "GstSMPTE", &smpte_info, 0);
201
202
203
204
  }
  return smpte_type;
}

Ronald S. Bultje's avatar
Ronald S. Bultje committed
205
static void
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
206
gst_smpte_base_init (GstSMPTEClass * klass)
Ronald S. Bultje's avatar
Ronald S. Bultje committed
207
208
209
{
  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
210
211
212
213
214
215
  gst_element_class_add_pad_template (element_class,
      gst_static_pad_template_get (&gst_smpte_sink1_template));
  gst_element_class_add_pad_template (element_class,
      gst_static_pad_template_get (&gst_smpte_sink2_template));
  gst_element_class_add_pad_template (element_class,
      gst_static_pad_template_get (&gst_smpte_src_template));
Ronald S. Bultje's avatar
Ronald S. Bultje committed
216
217
218
  gst_element_class_set_details (element_class, &smpte_details);
}

219
static void
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
220
gst_smpte_class_init (GstSMPTEClass * klass)
221
222
223
224
{
  GObjectClass *gobject_class;
  GstElementClass *gstelement_class;

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
225
226
  gobject_class = (GObjectClass *) klass;
  gstelement_class = (GstElementClass *) klass;
227

228
  parent_class = g_type_class_peek_parent (klass);
229
230
231
232
233
234

  gobject_class->set_property = gst_smpte_set_property;
  gobject_class->get_property = gst_smpte_get_property;

  _gst_mask_init ();

235
  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TYPE,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
236
      g_param_spec_enum ("type", "Type", "The type of transition to use",
237
          GST_TYPE_SMPTE_TRANSITION_TYPE, DEFAULT_PROP_TYPE,
238
          G_PARAM_READWRITE));
239
240
241
242
243
  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_FPS,
      g_param_spec_float ("fps", "FPS",
          "Frames per second if no input files are given (deprecated)", 0.,
          G_MAXFLOAT, DEFAULT_PROP_FPS, G_PARAM_READWRITE));
  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BORDER,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
244
      g_param_spec_int ("border", "Border",
245
246
247
          "The border width of the transition", 0, G_MAXINT,
          DEFAULT_PROP_BORDER, G_PARAM_READWRITE));
  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DEPTH,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
248
      g_param_spec_int ("depth", "Depth", "Depth of the mask in bits", 1, 24,
249
250
251
252
253
254
255
          DEFAULT_PROP_DEPTH, G_PARAM_READWRITE));
  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DURATION,
      g_param_spec_uint64 ("duration", "Duration",
          "Duration of the transition effect in nanoseconds", 0, G_MAXUINT64,
          DEFAULT_PROP_DURATION, G_PARAM_READWRITE));

  gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_smpte_change_state);
256
257
258
}

/*                        wht  yel  cya  grn  mag  red  blu  blk   -I    Q */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
259
260
261
static int y_colors[] = { 255, 226, 179, 150, 105, 76, 29, 16, 16, 0 };
static int u_colors[] = { 128, 0, 170, 46, 212, 85, 255, 128, 0, 128 };
static int v_colors[] = { 128, 155, 0, 21, 235, 255, 107, 128, 128, 255 };
262
263

static void
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
264
fill_i420 (guint8 * data, gint width, gint height, gint color)
265
{
266
267
  gint size = I420_Y_ROWSTRIDE (width) * GST_ROUND_UP_2 (height);
  gint size4 = size >> 2;
268
  guint8 *yp = data;
269
270
  guint8 *up = data + I420_U_OFFSET (width, height);
  guint8 *vp = data + I420_V_OFFSET (width, height);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
271

272
273
274
275
276
277
  memset (yp, y_colors[color], size);
  memset (up, u_colors[color], size4);
  memset (vp, v_colors[color], size4);
}

static gboolean
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
278
279
gst_smpte_update_mask (GstSMPTE * smpte, gint type, gint depth, gint width,
    gint height)
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
{
  GstMask *newmask;

  newmask = gst_mask_factory_new (type, depth, width, height);
  if (newmask) {
    if (smpte->mask) {
      gst_mask_destroy (smpte->mask);
    }
    smpte->mask = newmask;
    smpte->type = type;
    smpte->depth = depth;
    smpte->width = width;
    smpte->height = height;

    return TRUE;
  }
  return FALSE;
297
298
299
}

static gboolean
300
gst_smpte_setcaps (GstPad * pad, GstCaps * caps)
301
302
{
  GstSMPTE *smpte;
David Schleef's avatar
David Schleef committed
303
304
  GstStructure *structure;
  gboolean ret;
305

306
  smpte = GST_SMPTE (GST_PAD_PARENT (pad));
307

David Schleef's avatar
David Schleef committed
308
  structure = gst_caps_get_structure (caps, 0);
309

David Schleef's avatar
David Schleef committed
310
311
  ret = gst_structure_get_int (structure, "width", &smpte->width);
  ret &= gst_structure_get_int (structure, "height", &smpte->height);
312
313
  ret &= gst_structure_get_fraction (structure, "framerate",
      &smpte->fps_num, &smpte->fps_denom);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
314
  if (!ret)
315
    return FALSE;
316

317
318
319
320
321
322
323
324
325
326
  /* for backward compat, we store these here */
  smpte->fps = ((gdouble) smpte->fps_num) / smpte->fps_denom;

  /* figure out the duration in frames */
  smpte->end_position = gst_util_uint64_scale (smpte->duration,
      smpte->fps_num, GST_SECOND * smpte->fps_denom);

  GST_DEBUG_OBJECT (smpte, "duration: %d frames", smpte->end_position);

  ret = gst_smpte_update_mask (smpte, smpte->type, smpte->depth, smpte->width,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
327
      smpte->height);
328

329
  return ret;
330
331
}

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
332
333
static void
gst_smpte_init (GstSMPTE * smpte)
334
{
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
335
  smpte->sinkpad1 =
336
      gst_pad_new_from_static_template (&gst_smpte_sink1_template, "sink1");
337
338
339
340
  gst_pad_set_setcaps_function (smpte->sinkpad1,
      GST_DEBUG_FUNCPTR (gst_smpte_setcaps));
  gst_pad_set_getcaps_function (smpte->sinkpad1,
      GST_DEBUG_FUNCPTR (gst_pad_proxy_getcaps));
341
342
  gst_element_add_pad (GST_ELEMENT (smpte), smpte->sinkpad1);

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
343
  smpte->sinkpad2 =
344
      gst_pad_new_from_static_template (&gst_smpte_sink2_template, "sink2");
345
346
347
348
  gst_pad_set_setcaps_function (smpte->sinkpad2,
      GST_DEBUG_FUNCPTR (gst_smpte_setcaps));
  gst_pad_set_getcaps_function (smpte->sinkpad2,
      GST_DEBUG_FUNCPTR (gst_pad_proxy_getcaps));
349
350
  gst_element_add_pad (GST_ELEMENT (smpte), smpte->sinkpad2);

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
351
  smpte->srcpad =
352
      gst_pad_new_from_static_template (&gst_smpte_src_template, "src");
353
354
  gst_element_add_pad (GST_ELEMENT (smpte), smpte->srcpad);

355
356
  smpte->collect = gst_collect_pads_new ();
  gst_collect_pads_set_function (smpte->collect,
357
      (GstCollectPadsFunction) GST_DEBUG_FUNCPTR (gst_smpte_collected), smpte);
358
  gst_collect_pads_start (smpte->collect);
359

360
  gst_collect_pads_add_pad (smpte->collect, smpte->sinkpad1,
361
      sizeof (GstCollectData));
362
  gst_collect_pads_add_pad (smpte->collect, smpte->sinkpad2,
363
      sizeof (GstCollectData));
364

365
366
367
368
369
370
371
372
373
374
375
376
377
378
  smpte->fps = DEFAULT_PROP_FPS;
  smpte->type = DEFAULT_PROP_TYPE;
  smpte->border = DEFAULT_PROP_BORDER;
  smpte->depth = DEFAULT_PROP_DEPTH;
  smpte->duration = DEFAULT_PROP_DURATION;
  smpte->fps_num = 0;
  smpte->fps_denom = 1;
}

static void
gst_smpte_reset (GstSMPTE * smpte)
{
  smpte->width = -1;
  smpte->height = -1;
379
  smpte->position = 0;
380
  smpte->end_position = 0;
381
382
383
}

static void
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
384
385
gst_smpte_blend_i420 (guint8 * in1, guint8 * in2, guint8 * out, GstMask * mask,
    gint width, gint height, gint border, gint pos)
386
{
387
388
  guint32 *maskp;
  gint value;
389
  gint i, j;
390
  gint min, max;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
391
  guint8 *in1u, *in1v, *in2u, *in2v, *outu, *outv;
392
393
394
  gint lumsize = width * height;
  gint chromsize = lumsize >> 2;

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
395
396
  if (border == 0)
    border++;
397

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
398
  min = pos - border;
399
400
  max = pos;

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
401
402
403
404
405
406
407
  in1u = in1 + lumsize;
  in1v = in1u + chromsize;
  in2u = in2 + lumsize;
  in2v = in2u + chromsize;
  outu = out + lumsize;
  outv = outu + chromsize;

408
409
  maskp = mask->data;

410
411
412
413
  for (i = 0; i < height; i++) {
    for (j = 0; j < width; j++) {
      value = *maskp++;
      value = ((CLAMP (value, min, max) - min) << 8) / border;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
414

415
416
      *out++ = ((*in1++ * value) + (*in2++ * (256 - value))) >> 8;
      if (!(i & 1) && !(j & 1)) {
417
418
        *outu++ = ((*in1u++ * value) + (*in2u++ * (256 - value))) >> 8;
        *outv++ = ((*in1v++ * value) + (*in2v++ * (256 - value))) >> 8;
419
      }
420
421
422
423
    }
  }
}

424
425
static GstFlowReturn
gst_smpte_collected (GstCollectPads * pads, GstSMPTE * smpte)
426
427
428
429
{
  GstBuffer *outbuf;
  GstClockTime ts;
  GstBuffer *in1 = NULL, *in2 = NULL;
430
  GSList *collected;
431

432
433
434
435
436
  if (smpte->fps_num == 0)
    goto not_negotiated;

  ts = gst_util_uint64_scale_int (smpte->position * GST_SECOND,
      smpte->fps_denom, smpte->fps_num);
437

438
439
440
441
442
443
  for (collected = pads->data; collected; collected = g_slist_next (collected)) {
    GstCollectData *data;

    data = (GstCollectData *) collected->data;

    if (data->pad == smpte->sinkpad1)
444
      in1 = gst_collect_pads_pop (pads, data);
445
    else if (data->pad == smpte->sinkpad2)
446
      in2 = gst_collect_pads_pop (pads, data);
447
  }
Wim Taymans's avatar
Wim Taymans committed
448
449

  if (in1 == NULL) {
450
    /* if no input, make picture black */
451
    in1 = gst_buffer_new_and_alloc (I420_SIZE (smpte->width, smpte->height));
452
453
    fill_i420 (GST_BUFFER_DATA (in1), smpte->width, smpte->height, 7);
  }
Wim Taymans's avatar
Wim Taymans committed
454
  if (in2 == NULL) {
455
    /* if no input, make picture white */
456
    in2 = gst_buffer_new_and_alloc (I420_SIZE (smpte->width, smpte->height));
457
458
459
    fill_i420 (GST_BUFFER_DATA (in2), smpte->width, smpte->height, 0);
  }

460
  if (smpte->position < smpte->end_position) {
461
    outbuf = gst_buffer_new_and_alloc (I420_SIZE (smpte->width, smpte->height));
462

463
    /* set caps if not done yet */
464
    if (!GST_PAD_CAPS (smpte->srcpad)) {
David Schleef's avatar
David Schleef committed
465
      GstCaps *caps;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
466
467

      caps =
468
469
          gst_caps_copy (gst_static_caps_get (&gst_smpte_src_template.
              static_caps));
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
470
      gst_caps_set_simple (caps, "width", G_TYPE_INT, smpte->width, "height",
471
472
          G_TYPE_INT, smpte->height, "framerate", GST_TYPE_FRACTION,
          smpte->fps_num, smpte->fps_denom, NULL);
David Schleef's avatar
David Schleef committed
473

474
      gst_pad_set_caps (smpte->srcpad, caps);
475
476
477
478
479

      gst_pad_push_event (smpte->srcpad,
          gst_event_new_new_segment_full (FALSE,
              1.0, 1.0, GST_FORMAT_TIME, 0, -1, 0));

480
    }
481
    gst_buffer_set_caps (outbuf, GST_PAD_CAPS (smpte->srcpad));
482

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
483
    gst_smpte_blend_i420 (GST_BUFFER_DATA (in1),
484
485
486
487
488
        GST_BUFFER_DATA (in2),
        GST_BUFFER_DATA (outbuf),
        smpte->mask, smpte->width, smpte->height,
        smpte->border,
        ((1 << smpte->depth) + smpte->border) *
489
        smpte->position / smpte->end_position);
490

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
491
  } else {
492
493
494
495
496
497
498
499
500
501
502
503
    outbuf = in2;
    gst_buffer_ref (in2);
  }

  smpte->position++;

  if (in1)
    gst_buffer_unref (in1);
  if (in2)
    gst_buffer_unref (in2);

  GST_BUFFER_TIMESTAMP (outbuf) = ts;
504
505

  return gst_pad_push (smpte->srcpad, outbuf);
506
507
508
509
510
511
512
513

  /* ERRORS */
not_negotiated:
  {
    GST_ELEMENT_ERROR (smpte, CORE, NEGOTIATION, (NULL),
        ("No input format negotiated"));
    return GST_FLOW_NOT_NEGOTIATED;
  }
514
515
516
}

static void
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
517
518
gst_smpte_set_property (GObject * object, guint prop_id,
    const GValue * value, GParamSpec * pspec)
519
520
521
{
  GstSMPTE *smpte;

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
522
  smpte = GST_SMPTE (object);
523
524

  switch (prop_id) {
525
526
    case PROP_TYPE:
      smpte->type = g_value_get_enum (value);
527
      break;
528
    case PROP_BORDER:
529
530
      smpte->border = g_value_get_int (value);
      break;
531
    case PROP_FPS:
532
533
      smpte->fps = g_value_get_float (value);
      break;
534
535
536
537
538
    case PROP_DEPTH:
      smpte->depth = g_value_get_int (value);
      break;
    case PROP_DURATION:
      smpte->duration = g_value_get_uint64 (value);
539
540
541
542
543
544
545
546
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}

static void
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
547
548
gst_smpte_get_property (GObject * object, guint prop_id,
    GValue * value, GParamSpec * pspec)
549
550
551
{
  GstSMPTE *smpte;

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
552
  smpte = GST_SMPTE (object);
553
554

  switch (prop_id) {
555
556
    case PROP_TYPE:
      g_value_set_enum (value, smpte->type);
557
      break;
558
    case PROP_FPS:
559
      g_value_set_float (value, smpte->fps);
560
      break;
561
    case PROP_BORDER:
562
563
      g_value_set_int (value, smpte->border);
      break;
564
    case PROP_DEPTH:
565
566
      g_value_set_int (value, smpte->depth);
      break;
567
568
569
    case PROP_DURATION:
      g_value_set_uint64 (value, smpte->duration);
      break;
570
571
572
573
574
575
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}

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
602
603
604
605
606
607
608
static GstStateChangeReturn
gst_smpte_change_state (GstElement * element, GstStateChange transition)
{
  GstStateChangeReturn ret;
  GstSMPTE *smpte;

  smpte = GST_SMPTE (element);

  switch (transition) {
    case GST_STATE_CHANGE_READY_TO_PAUSED:
      gst_smpte_reset (smpte);
      GST_LOG_OBJECT (smpte, "starting collectpads");
      gst_collect_pads_start (smpte->collect);
      break;
    case GST_STATE_CHANGE_PAUSED_TO_READY:
      GST_LOG_OBJECT (smpte, "stopping collectpads");
      gst_collect_pads_stop (smpte->collect);
      break;
    default:
      break;
  }

  ret = parent_class->change_state (element, transition);

  switch (transition) {
    case GST_STATE_CHANGE_PAUSED_TO_READY:
      gst_smpte_reset (smpte);
      break;
    default:
      break;
  }
  return ret;
}
609
610

static gboolean
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
611
plugin_init (GstPlugin * plugin)
612
{
613
614
615
  GST_DEBUG_CATEGORY_INIT (gst_smpte_debug, "smpte", 0,
      "SMPTE transition effect");

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
616
  return gst_element_register (plugin, "smpte", GST_RANK_NONE, GST_TYPE_SMPTE);
617
618
}

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
619
620
621
622
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
    GST_VERSION_MINOR,
    "smpte",
    "Apply the standard SMPTE transitions on video images",
623
    plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)