~ubuntu-branches/ubuntu/quantal/gst-plugins-bad-multiverse0.10/quantal

« back to all changes in this revision

Viewing changes to gst/frei0r/gstfrei0rmixer.c

  • Committer: Bazaar Package Importer
  • Author(s): Onkar Shinde
  • Date: 2009-12-07 08:54:28 UTC
  • mfrom: (1.1.15 upstream)
  • Revision ID: james.westby@ubuntu.com-20091207085428-ml6aaukf0p2ph34d
Tags: 0.10.17-0ubuntu1
* New upstream release.
* Add myself to maintainer.
* Fix misc lintian warnings.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* GStreamer
 
2
 * Copyright (C) 2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
 
3
 *
 
4
 * This library is free software; you can redistribute it and/or
 
5
 * modify it under the terms of the GNU Library General Public
 
6
 * License as published by the Free Software Foundation; either
 
7
 * version 2 of the License, or (at your option) any later version.
 
8
 *
 
9
 * This library is distributed in the hope that it will be useful,
 
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
12
 * Library General Public License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU Library General Public
 
15
 * License along with this library; if not, write to the
 
16
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 
17
 * Boston, MA 02111-1307, USA.
 
18
 */
 
19
 
 
20
#ifdef HAVE_CONFIG_H
 
21
#include "config.h"
 
22
#endif
 
23
 
 
24
#include <string.h>
 
25
 
 
26
#include "gstfrei0r.h"
 
27
#include "gstfrei0rmixer.h"
 
28
 
 
29
GST_DEBUG_CATEGORY_EXTERN (frei0r_debug);
 
30
#define GST_CAT_DEFAULT frei0r_debug
 
31
 
 
32
typedef struct
 
33
{
 
34
  f0r_plugin_info_t info;
 
35
  GstFrei0rFuncTable ftable;
 
36
} GstFrei0rMixerClassData;
 
37
 
 
38
static void
 
39
gst_frei0r_mixer_reset (GstFrei0rMixer * self)
 
40
{
 
41
  GstFrei0rMixerClass *klass = GST_FREI0R_MIXER_GET_CLASS (self);
 
42
 
 
43
  if (self->f0r_instance) {
 
44
    klass->ftable->destruct (self->f0r_instance);
 
45
    self->f0r_instance = NULL;
 
46
  }
 
47
 
 
48
  if (self->property_cache)
 
49
    gst_frei0r_property_cache_free (klass->properties, self->property_cache,
 
50
        klass->n_properties);
 
51
  self->property_cache = NULL;
 
52
 
 
53
  gst_caps_replace (&self->caps, NULL);
 
54
  gst_event_replace (&self->newseg_event, NULL);
 
55
 
 
56
  self->fmt = GST_VIDEO_FORMAT_UNKNOWN;
 
57
  self->width = self->height = 0;
 
58
}
 
59
 
 
60
static void
 
61
gst_frei0r_mixer_finalize (GObject * object)
 
62
{
 
63
  GstFrei0rMixer *self = GST_FREI0R_MIXER (object);
 
64
  GstFrei0rMixerClass *klass = GST_FREI0R_MIXER_GET_CLASS (object);
 
65
 
 
66
  if (self->property_cache)
 
67
    gst_frei0r_property_cache_free (klass->properties, self->property_cache,
 
68
        klass->n_properties);
 
69
  self->property_cache = NULL;
 
70
 
 
71
  if (self->collect)
 
72
    gst_object_unref (self->collect);
 
73
  self->collect = NULL;
 
74
 
 
75
  G_OBJECT_CLASS (g_type_class_peek_parent (klass))->finalize (object);
 
76
}
 
77
 
 
78
static void
 
79
gst_frei0r_mixer_get_property (GObject * object, guint prop_id, GValue * value,
 
80
    GParamSpec * pspec)
 
81
{
 
82
  GstFrei0rMixer *self = GST_FREI0R_MIXER (object);
 
83
  GstFrei0rMixerClass *klass = GST_FREI0R_MIXER_GET_CLASS (object);
 
84
 
 
85
  if (!gst_frei0r_get_property (self->f0r_instance, klass->ftable,
 
86
          klass->properties, klass->n_properties, self->property_cache, prop_id,
 
87
          value))
 
88
    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
89
}
 
90
 
 
91
static void
 
92
gst_frei0r_mixer_set_property (GObject * object, guint prop_id,
 
93
    const GValue * value, GParamSpec * pspec)
 
94
{
 
95
  GstFrei0rMixer *self = GST_FREI0R_MIXER (object);
 
96
  GstFrei0rMixerClass *klass = GST_FREI0R_MIXER_GET_CLASS (object);
 
97
 
 
98
  if (!gst_frei0r_set_property (self->f0r_instance, klass->ftable,
 
99
          klass->properties, klass->n_properties, self->property_cache, prop_id,
 
100
          value))
 
101
    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
102
}
 
103
 
 
104
static GstStateChangeReturn
 
105
gst_frei0r_mixer_change_state (GstElement * element, GstStateChange transition)
 
106
{
 
107
  GstFrei0rMixer *self = GST_FREI0R_MIXER (element);
 
108
  GstFrei0rMixerClass *klass = GST_FREI0R_MIXER_GET_CLASS (self);
 
109
  GstStateChangeReturn ret;
 
110
 
 
111
  switch (transition) {
 
112
    case GST_STATE_CHANGE_NULL_TO_READY:
 
113
      break;
 
114
    case GST_STATE_CHANGE_READY_TO_PAUSED:
 
115
      gst_collect_pads_start (self->collect);
 
116
      break;
 
117
    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
 
118
      break;
 
119
    default:
 
120
      break;
 
121
  }
 
122
 
 
123
  /* Stop before calling the parent's state change function as
 
124
   * GstCollectPads might take locks and we would deadlock in that
 
125
   * case
 
126
   */
 
127
  if (transition == GST_STATE_CHANGE_PAUSED_TO_READY)
 
128
    gst_collect_pads_stop (self->collect);
 
129
 
 
130
  ret =
 
131
      GST_ELEMENT_CLASS (g_type_class_peek_parent (klass))->change_state
 
132
      (element, transition);
 
133
 
 
134
  switch (transition) {
 
135
    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
 
136
      break;
 
137
    case GST_STATE_CHANGE_PAUSED_TO_READY:
 
138
      gst_frei0r_mixer_reset (self);
 
139
      break;
 
140
    case GST_STATE_CHANGE_READY_TO_NULL:
 
141
      break;
 
142
    default:
 
143
      break;
 
144
  }
 
145
 
 
146
  return ret;
 
147
}
 
148
 
 
149
static GstCaps *
 
150
gst_frei0r_mixer_get_caps (GstPad * pad)
 
151
{
 
152
  GstFrei0rMixer *self = GST_FREI0R_MIXER (gst_pad_get_parent (pad));
 
153
  GstCaps *caps = NULL;
 
154
 
 
155
  if (self->caps) {
 
156
    caps = gst_caps_ref (self->caps);
 
157
  } else {
 
158
    GstCaps *tmp, *tmp1;
 
159
 
 
160
    tmp = gst_caps_copy (gst_pad_get_pad_template_caps (self->src));
 
161
    tmp1 = gst_pad_peer_get_caps (pad);
 
162
    if (tmp1) {
 
163
      caps = gst_caps_intersect (tmp, tmp1);
 
164
      gst_caps_unref (tmp1);
 
165
      gst_caps_unref (tmp);
 
166
    } else {
 
167
      caps = tmp;
 
168
    }
 
169
 
 
170
    tmp = caps;
 
171
    tmp1 = gst_pad_peer_get_caps (self->sink0);
 
172
    if (tmp1) {
 
173
      caps = gst_caps_intersect (tmp, tmp1);
 
174
      gst_caps_unref (tmp);
 
175
      gst_caps_unref (tmp1);
 
176
    }
 
177
 
 
178
    tmp = caps;
 
179
    tmp1 = gst_pad_peer_get_caps (self->sink1);
 
180
    if (tmp1) {
 
181
      caps = gst_caps_intersect (tmp, tmp1);
 
182
      gst_caps_unref (tmp);
 
183
      gst_caps_unref (tmp1);
 
184
    }
 
185
 
 
186
    if (self->sink2) {
 
187
      tmp = caps;
 
188
      tmp1 = gst_pad_peer_get_caps (self->sink2);
 
189
      if (tmp1) {
 
190
        caps = gst_caps_intersect (tmp, tmp1);
 
191
        gst_caps_unref (tmp);
 
192
        gst_caps_unref (tmp1);
 
193
      }
 
194
    }
 
195
  }
 
196
 
 
197
  gst_object_unref (self);
 
198
 
 
199
  return caps;
 
200
}
 
201
 
 
202
static gboolean
 
203
gst_frei0r_mixer_set_caps (GstPad * pad, GstCaps * caps)
 
204
{
 
205
  GstFrei0rMixer *self = GST_FREI0R_MIXER (gst_pad_get_parent (pad));
 
206
  gboolean ret = TRUE;
 
207
 
 
208
  gst_caps_replace (&self->caps, caps);
 
209
 
 
210
  if (pad != self->src)
 
211
    ret &= gst_pad_set_caps (self->src, caps);
 
212
  if (pad != self->sink0)
 
213
    ret &= gst_pad_set_caps (self->sink0, caps);
 
214
  if (pad != self->sink1)
 
215
    ret &= gst_pad_set_caps (self->sink1, caps);
 
216
  if (pad != self->sink2 && self->sink2)
 
217
    ret &= gst_pad_set_caps (self->sink2, caps);
 
218
 
 
219
  if (ret) {
 
220
    if (!gst_video_format_parse_caps (caps, &self->fmt, &self->width,
 
221
            &self->height)) {
 
222
      ret = FALSE;
 
223
      goto out;
 
224
    }
 
225
  }
 
226
out:
 
227
 
 
228
  gst_object_unref (self);
 
229
 
 
230
  return ret;
 
231
}
 
232
 
 
233
static gboolean
 
234
gst_frei0r_mixer_src_query_duration (GstFrei0rMixer * self, GstQuery * query)
 
235
{
 
236
  gint64 min;
 
237
  gboolean res;
 
238
  GstFormat format;
 
239
  GstIterator *it;
 
240
  gboolean done;
 
241
 
 
242
  /* parse format */
 
243
  gst_query_parse_duration (query, &format, NULL);
 
244
 
 
245
  min = -1;
 
246
  res = TRUE;
 
247
  done = FALSE;
 
248
 
 
249
  /* Take minimum of all durations */
 
250
  it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (self));
 
251
  while (!done) {
 
252
    GstIteratorResult ires;
 
253
    gpointer item;
 
254
 
 
255
    ires = gst_iterator_next (it, &item);
 
256
    switch (ires) {
 
257
      case GST_ITERATOR_DONE:
 
258
        done = TRUE;
 
259
        break;
 
260
      case GST_ITERATOR_OK:
 
261
      {
 
262
        GstPad *pad = GST_PAD_CAST (item);
 
263
        gint64 duration;
 
264
 
 
265
        /* ask sink peer for duration */
 
266
        res &= gst_pad_query_peer_duration (pad, &format, &duration);
 
267
        /* take min from all valid return values */
 
268
        if (res) {
 
269
          /* valid unknown length, stop searching */
 
270
          if (duration == -1) {
 
271
            min = duration;
 
272
            done = TRUE;
 
273
          }
 
274
          /* else see if smaller than current min */
 
275
          else if (duration < min)
 
276
            min = duration;
 
277
        }
 
278
        gst_object_unref (pad);
 
279
        break;
 
280
      }
 
281
      case GST_ITERATOR_RESYNC:
 
282
        min = -1;
 
283
        res = TRUE;
 
284
        gst_iterator_resync (it);
 
285
        break;
 
286
      default:
 
287
        res = FALSE;
 
288
        done = TRUE;
 
289
        break;
 
290
    }
 
291
  }
 
292
  gst_iterator_free (it);
 
293
 
 
294
  if (res) {
 
295
    /* and store the min */
 
296
    GST_DEBUG_OBJECT (self, "Total duration in format %s: %"
 
297
        GST_TIME_FORMAT, gst_format_get_name (format), GST_TIME_ARGS (min));
 
298
    gst_query_set_duration (query, format, min);
 
299
  }
 
300
 
 
301
  return res;
 
302
}
 
303
 
 
304
static gboolean
 
305
gst_frei0r_mixer_src_query_latency (GstFrei0rMixer * self, GstQuery * query)
 
306
{
 
307
  GstClockTime min, max;
 
308
  gboolean live;
 
309
  gboolean res;
 
310
  GstIterator *it;
 
311
  gboolean done;
 
312
 
 
313
  res = TRUE;
 
314
  done = FALSE;
 
315
 
 
316
  live = FALSE;
 
317
  min = 0;
 
318
  max = GST_CLOCK_TIME_NONE;
 
319
 
 
320
  /* Take maximum of all latency values */
 
321
  it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (self));
 
322
  while (!done) {
 
323
    GstIteratorResult ires;
 
324
    gpointer item;
 
325
 
 
326
    ires = gst_iterator_next (it, &item);
 
327
    switch (ires) {
 
328
      case GST_ITERATOR_DONE:
 
329
        done = TRUE;
 
330
        break;
 
331
      case GST_ITERATOR_OK:
 
332
      {
 
333
        GstPad *pad = GST_PAD_CAST (item);
 
334
        GstQuery *peerquery;
 
335
        GstClockTime min_cur, max_cur;
 
336
        gboolean live_cur;
 
337
 
 
338
        peerquery = gst_query_new_latency ();
 
339
 
 
340
        /* Ask peer for latency */
 
341
        res &= gst_pad_peer_query (pad, peerquery);
 
342
 
 
343
        /* take max from all valid return values */
 
344
        if (res) {
 
345
          gst_query_parse_latency (peerquery, &live_cur, &min_cur, &max_cur);
 
346
 
 
347
          if (min_cur > min)
 
348
            min = min_cur;
 
349
 
 
350
          if (max_cur != GST_CLOCK_TIME_NONE &&
 
351
              ((max != GST_CLOCK_TIME_NONE && max_cur > max) ||
 
352
                  (max == GST_CLOCK_TIME_NONE)))
 
353
            max = max_cur;
 
354
 
 
355
          live = live || live_cur;
 
356
        }
 
357
 
 
358
        gst_query_unref (peerquery);
 
359
        gst_object_unref (pad);
 
360
        break;
 
361
      }
 
362
      case GST_ITERATOR_RESYNC:
 
363
        live = FALSE;
 
364
        min = 0;
 
365
        max = GST_CLOCK_TIME_NONE;
 
366
        res = TRUE;
 
367
        gst_iterator_resync (it);
 
368
        break;
 
369
      default:
 
370
        res = FALSE;
 
371
        done = TRUE;
 
372
        break;
 
373
    }
 
374
  }
 
375
  gst_iterator_free (it);
 
376
 
 
377
  if (res) {
 
378
    /* store the results */
 
379
    GST_DEBUG_OBJECT (self, "Calculated total latency: live %s, min %"
 
380
        GST_TIME_FORMAT ", max %" GST_TIME_FORMAT,
 
381
        (live ? "yes" : "no"), GST_TIME_ARGS (min), GST_TIME_ARGS (max));
 
382
    gst_query_set_latency (query, live, min, max);
 
383
  }
 
384
 
 
385
  return res;
 
386
}
 
387
 
 
388
static gboolean
 
389
gst_frei0r_mixer_src_query (GstPad * pad, GstQuery * query)
 
390
{
 
391
  GstFrei0rMixer *self = GST_FREI0R_MIXER (gst_pad_get_parent (pad));
 
392
  gboolean ret = FALSE;
 
393
 
 
394
  switch (GST_QUERY_TYPE (query)) {
 
395
    case GST_QUERY_POSITION:
 
396
      ret = gst_pad_query (self->sink0, query);
 
397
      break;
 
398
    case GST_QUERY_DURATION:
 
399
      ret = gst_frei0r_mixer_src_query_duration (self, query);
 
400
      break;
 
401
    case GST_QUERY_LATENCY:
 
402
      ret = gst_frei0r_mixer_src_query_latency (self, query);
 
403
      break;
 
404
    default:
 
405
      ret = gst_pad_query_default (pad, query);
 
406
      break;
 
407
  }
 
408
 
 
409
  gst_object_unref (self);
 
410
 
 
411
  return ret;
 
412
}
 
413
 
 
414
static gboolean
 
415
gst_frei0r_mixer_sink_query (GstPad * pad, GstQuery * query)
 
416
{
 
417
  GstFrei0rMixer *self = GST_FREI0R_MIXER (gst_pad_get_parent (pad));
 
418
  gboolean ret = gst_pad_query (self->src, query);
 
419
 
 
420
  gst_object_unref (self);
 
421
 
 
422
  return ret;
 
423
}
 
424
 
 
425
static gboolean
 
426
forward_event_func (GstPad * pad, GValue * ret, GstEvent * event)
 
427
{
 
428
  gst_event_ref (event);
 
429
  GST_LOG_OBJECT (pad, "About to send event %s", GST_EVENT_TYPE_NAME (event));
 
430
  if (!gst_pad_push_event (pad, event)) {
 
431
    g_value_set_boolean (ret, FALSE);
 
432
    GST_WARNING_OBJECT (pad, "Sending event  %p (%s) failed.",
 
433
        event, GST_EVENT_TYPE_NAME (event));
 
434
  } else {
 
435
    GST_LOG_OBJECT (pad, "Sent event  %p (%s).",
 
436
        event, GST_EVENT_TYPE_NAME (event));
 
437
  }
 
438
  gst_object_unref (pad);
 
439
  return TRUE;
 
440
}
 
441
 
 
442
static gboolean
 
443
forward_event (GstFrei0rMixer * self, GstEvent * event)
 
444
{
 
445
  GstIterator *it;
 
446
  GValue vret = { 0 };
 
447
 
 
448
  GST_LOG_OBJECT (self, "Forwarding event %p (%s)", event,
 
449
      GST_EVENT_TYPE_NAME (event));
 
450
 
 
451
  g_value_init (&vret, G_TYPE_BOOLEAN);
 
452
  g_value_set_boolean (&vret, TRUE);
 
453
  it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (self));
 
454
  gst_iterator_fold (it, (GstIteratorFoldFunction) forward_event_func, &vret,
 
455
      event);
 
456
  gst_iterator_free (it);
 
457
  gst_event_unref (event);
 
458
 
 
459
  return g_value_get_boolean (&vret);
 
460
}
 
461
 
 
462
static gboolean
 
463
gst_frei0r_mixer_src_event (GstPad * pad, GstEvent * event)
 
464
{
 
465
  GstFrei0rMixer *self = GST_FREI0R_MIXER (gst_pad_get_parent (pad));
 
466
  gboolean ret = FALSE;
 
467
 
 
468
  switch (GST_EVENT_TYPE (event)) {
 
469
    case GST_EVENT_QOS:
 
470
      /* QoS might be tricky */
 
471
      ret = FALSE;
 
472
      break;
 
473
    case GST_EVENT_SEEK:
 
474
    {
 
475
      GstSeekFlags flags;
 
476
 
 
477
      /* parse the seek parameters */
 
478
      gst_event_parse_seek (event, NULL, NULL, &flags, NULL, NULL, NULL, NULL);
 
479
 
 
480
      /* check if we are flushing */
 
481
      if (flags & GST_SEEK_FLAG_FLUSH) {
 
482
        /* make sure we accept nothing anymore and return WRONG_STATE */
 
483
        gst_collect_pads_set_flushing (self->collect, TRUE);
 
484
 
 
485
        /* flushing seek, start flush downstream, the flush will be done
 
486
         * when all pads received a FLUSH_STOP. */
 
487
        gst_pad_push_event (self->src, gst_event_new_flush_start ());
 
488
      }
 
489
 
 
490
      ret = forward_event (self, event);
 
491
      break;
 
492
    }
 
493
    case GST_EVENT_NAVIGATION:
 
494
      /* navigation is rather pointless. */
 
495
      ret = FALSE;
 
496
      break;
 
497
    default:
 
498
      /* just forward the rest for now */
 
499
      ret = forward_event (self, event);
 
500
      break;
 
501
  }
 
502
 
 
503
  gst_object_unref (self);
 
504
 
 
505
  return ret;
 
506
}
 
507
 
 
508
static gboolean
 
509
gst_frei0r_mixer_sink0_event (GstPad * pad, GstEvent * event)
 
510
{
 
511
  GstFrei0rMixer *self = GST_FREI0R_MIXER (gst_pad_get_parent (pad));
 
512
  gboolean ret = FALSE;
 
513
 
 
514
  GST_DEBUG ("Got %s event on pad %s:%s", GST_EVENT_TYPE_NAME (event),
 
515
      GST_DEBUG_PAD_NAME (pad));
 
516
 
 
517
  switch (GST_EVENT_TYPE (event)) {
 
518
    case GST_EVENT_NEWSEGMENT:
 
519
      gst_event_replace (&self->newseg_event, event);
 
520
      break;
 
521
    default:
 
522
      break;
 
523
  }
 
524
 
 
525
  /* now GstCollectPads can take care of the rest, e.g. EOS */
 
526
  ret = self->collect_event (pad, event);
 
527
 
 
528
  gst_object_unref (self);
 
529
 
 
530
  return ret;
 
531
}
 
532
 
 
533
static GstFlowReturn
 
534
gst_frei0r_mixer_collected (GstCollectPads * pads, GstFrei0rMixer * self)
 
535
{
 
536
  GstBuffer *inbuf0 = NULL, *inbuf1 = NULL, *inbuf2 = NULL;
 
537
  GstBuffer *outbuf = NULL;
 
538
  GstFlowReturn ret = GST_FLOW_OK;
 
539
  GSList *l;
 
540
  GstFrei0rMixerClass *klass = GST_FREI0R_MIXER_GET_CLASS (self);
 
541
  gdouble time;
 
542
 
 
543
  if (G_UNLIKELY (self->width <= 0 || self->height <= 0))
 
544
    return GST_FLOW_NOT_NEGOTIATED;
 
545
 
 
546
  if (G_UNLIKELY (!self->f0r_instance)) {
 
547
    self->f0r_instance =
 
548
        gst_frei0r_instance_construct (klass->ftable, klass->properties,
 
549
        klass->n_properties, self->property_cache, self->width, self->height);
 
550
    if (G_UNLIKELY (!self->f0r_instance))
 
551
      return GST_FLOW_ERROR;
 
552
  }
 
553
 
 
554
  if (self->newseg_event) {
 
555
    gst_pad_push_event (self->src, self->newseg_event);
 
556
    self->newseg_event = NULL;
 
557
  }
 
558
 
 
559
  if ((ret =
 
560
          gst_pad_alloc_buffer_and_set_caps (self->src, GST_BUFFER_OFFSET_NONE,
 
561
              gst_video_format_get_size (self->fmt, self->width, self->height),
 
562
              GST_PAD_CAPS (self->src), &outbuf)) != GST_FLOW_OK)
 
563
    return ret;
 
564
 
 
565
  for (l = pads->data; l; l = l->next) {
 
566
    GstCollectData *cdata = l->data;
 
567
 
 
568
    if (cdata->pad == self->sink0)
 
569
      inbuf0 = gst_collect_pads_pop (pads, cdata);
 
570
    else if (cdata->pad == self->sink1)
 
571
      inbuf1 = gst_collect_pads_pop (pads, cdata);
 
572
    else if (cdata->pad == self->sink2)
 
573
      inbuf2 = gst_collect_pads_pop (pads, cdata);
 
574
  }
 
575
 
 
576
  if (!inbuf0 || !inbuf1 || (!inbuf2 && self->sink2))
 
577
    goto eos;
 
578
 
 
579
  gst_buffer_copy_metadata (outbuf, inbuf0,
 
580
      GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS);
 
581
  time = ((gdouble) GST_BUFFER_TIMESTAMP (outbuf)) / GST_SECOND;
 
582
 
 
583
  klass->ftable->update2 (self->f0r_instance, time,
 
584
      (const guint32 *) GST_BUFFER_DATA (inbuf0),
 
585
      (const guint32 *) GST_BUFFER_DATA (inbuf1),
 
586
      (inbuf2) ? (const guint32 *) GST_BUFFER_DATA (inbuf2) : NULL,
 
587
      (guint32 *) GST_BUFFER_DATA (outbuf));
 
588
 
 
589
  gst_buffer_unref (inbuf0);
 
590
  gst_buffer_unref (inbuf1);
 
591
  if (inbuf2)
 
592
    gst_buffer_unref (inbuf2);
 
593
 
 
594
  ret = gst_pad_push (self->src, outbuf);
 
595
 
 
596
  return ret;
 
597
 
 
598
eos:
 
599
  {
 
600
    GST_DEBUG_OBJECT (self, "no data available, must be EOS");
 
601
    gst_buffer_unref (outbuf);
 
602
 
 
603
    if (inbuf0)
 
604
      gst_buffer_unref (inbuf0);
 
605
    if (inbuf1)
 
606
      gst_buffer_unref (inbuf1);
 
607
    if (inbuf2)
 
608
      gst_buffer_unref (inbuf2);
 
609
 
 
610
    gst_pad_push_event (self->src, gst_event_new_eos ());
 
611
    return GST_FLOW_UNEXPECTED;
 
612
  }
 
613
}
 
614
 
 
615
static void
 
616
gst_frei0r_mixer_class_init (GstFrei0rMixerClass * klass,
 
617
    GstFrei0rMixerClassData * class_data)
 
618
{
 
619
  GObjectClass *gobject_class = (GObjectClass *) klass;
 
620
  GstElementClass *gstelement_class = (GstElementClass *) klass;
 
621
  GstPadTemplate *templ;
 
622
  GstCaps *caps;
 
623
  gchar *author;
 
624
 
 
625
  klass->ftable = &class_data->ftable;
 
626
  klass->info = &class_data->info;
 
627
 
 
628
  gobject_class->finalize = gst_frei0r_mixer_finalize;
 
629
  gobject_class->set_property = gst_frei0r_mixer_set_property;
 
630
  gobject_class->get_property = gst_frei0r_mixer_get_property;
 
631
 
 
632
  klass->n_properties = klass->info->num_params;
 
633
  klass->properties = g_new0 (GstFrei0rProperty, klass->n_properties);
 
634
 
 
635
  gst_frei0r_klass_install_properties (gobject_class, klass->ftable,
 
636
      klass->properties, klass->n_properties);
 
637
 
 
638
  author =
 
639
      g_strdup_printf
 
640
      ("Sebastian Dröge <sebastian.droege@collabora.co.uk>, %s",
 
641
      class_data->info.author);
 
642
  gst_element_class_set_details_simple (gstelement_class, class_data->info.name,
 
643
      "Filter/Editor/Video", class_data->info.explanation, author);
 
644
  g_free (author);
 
645
 
 
646
  caps = gst_frei0r_caps_from_color_model (class_data->info.color_model);
 
647
 
 
648
  templ =
 
649
      gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
 
650
      gst_caps_ref (caps));
 
651
  gst_element_class_add_pad_template (gstelement_class, templ);
 
652
 
 
653
  templ =
 
654
      gst_pad_template_new ("sink_0", GST_PAD_SINK, GST_PAD_ALWAYS,
 
655
      gst_caps_ref (caps));
 
656
  gst_element_class_add_pad_template (gstelement_class, templ);
 
657
 
 
658
  templ =
 
659
      gst_pad_template_new ("sink_1", GST_PAD_SINK, GST_PAD_ALWAYS,
 
660
      gst_caps_ref (caps));
 
661
  gst_element_class_add_pad_template (gstelement_class, templ);
 
662
 
 
663
  if (klass->info->plugin_type == F0R_PLUGIN_TYPE_MIXER3) {
 
664
    templ =
 
665
        gst_pad_template_new ("sink_2", GST_PAD_SINK, GST_PAD_ALWAYS,
 
666
        gst_caps_ref (caps));
 
667
    gst_element_class_add_pad_template (gstelement_class, templ);
 
668
  }
 
669
  gst_caps_unref (caps);
 
670
 
 
671
  gstelement_class->change_state =
 
672
      GST_DEBUG_FUNCPTR (gst_frei0r_mixer_change_state);
 
673
}
 
674
 
 
675
static void
 
676
gst_frei0r_mixer_init (GstFrei0rMixer * self, GstFrei0rMixerClass * klass)
 
677
{
 
678
  self->property_cache =
 
679
      gst_frei0r_property_cache_init (klass->properties, klass->n_properties);
 
680
 
 
681
  self->collect = gst_collect_pads_new ();
 
682
  gst_collect_pads_set_function (self->collect,
 
683
      (GstCollectPadsFunction) gst_frei0r_mixer_collected, self);
 
684
 
 
685
  self->src =
 
686
      gst_pad_new_from_template (gst_element_class_get_pad_template
 
687
      (GST_ELEMENT_CLASS (klass), "src"), "src");
 
688
  gst_pad_set_getcaps_function (self->src,
 
689
      GST_DEBUG_FUNCPTR (gst_frei0r_mixer_get_caps));
 
690
  gst_pad_set_setcaps_function (self->src,
 
691
      GST_DEBUG_FUNCPTR (gst_frei0r_mixer_set_caps));
 
692
  gst_pad_set_query_function (self->src,
 
693
      GST_DEBUG_FUNCPTR (gst_frei0r_mixer_src_query));
 
694
  gst_pad_set_event_function (self->src,
 
695
      GST_DEBUG_FUNCPTR (gst_frei0r_mixer_src_event));
 
696
  gst_element_add_pad (GST_ELEMENT_CAST (self), self->src);
 
697
 
 
698
  self->sink0 =
 
699
      gst_pad_new_from_template (gst_element_class_get_pad_template
 
700
      (GST_ELEMENT_CLASS (klass), "sink_0"), "sink_0");
 
701
  gst_pad_set_getcaps_function (self->sink0,
 
702
      GST_DEBUG_FUNCPTR (gst_frei0r_mixer_get_caps));
 
703
  gst_pad_set_setcaps_function (self->sink0,
 
704
      GST_DEBUG_FUNCPTR (gst_frei0r_mixer_set_caps));
 
705
  gst_pad_set_query_function (self->sink0,
 
706
      GST_DEBUG_FUNCPTR (gst_frei0r_mixer_sink_query));
 
707
  gst_collect_pads_add_pad (self->collect, self->sink0,
 
708
      sizeof (GstCollectData));
 
709
  self->collect_event = (GstPadEventFunction) GST_PAD_EVENTFUNC (self->sink0);
 
710
  gst_pad_set_event_function (self->sink0,
 
711
      GST_DEBUG_FUNCPTR (gst_frei0r_mixer_sink0_event));
 
712
  gst_element_add_pad (GST_ELEMENT_CAST (self), self->sink0);
 
713
 
 
714
  self->sink1 =
 
715
      gst_pad_new_from_template (gst_element_class_get_pad_template
 
716
      (GST_ELEMENT_CLASS (klass), "sink_1"), "sink_1");
 
717
  gst_pad_set_getcaps_function (self->sink1,
 
718
      GST_DEBUG_FUNCPTR (gst_frei0r_mixer_get_caps));
 
719
  gst_pad_set_setcaps_function (self->sink1,
 
720
      GST_DEBUG_FUNCPTR (gst_frei0r_mixer_set_caps));
 
721
  gst_pad_set_query_function (self->sink0,
 
722
      GST_DEBUG_FUNCPTR (gst_frei0r_mixer_sink_query));
 
723
  gst_collect_pads_add_pad (self->collect, self->sink1,
 
724
      sizeof (GstCollectData));
 
725
  gst_element_add_pad (GST_ELEMENT_CAST (self), self->sink1);
 
726
 
 
727
  if (klass->info->plugin_type == F0R_PLUGIN_TYPE_MIXER3) {
 
728
    self->sink2 =
 
729
        gst_pad_new_from_template (gst_element_class_get_pad_template
 
730
        (GST_ELEMENT_CLASS (klass), "sink_2"), "sink_2");
 
731
    gst_pad_set_getcaps_function (self->sink2,
 
732
        GST_DEBUG_FUNCPTR (gst_frei0r_mixer_get_caps));
 
733
    gst_pad_set_setcaps_function (self->sink2,
 
734
        GST_DEBUG_FUNCPTR (gst_frei0r_mixer_set_caps));
 
735
    gst_pad_set_query_function (self->sink0,
 
736
        GST_DEBUG_FUNCPTR (gst_frei0r_mixer_sink_query));
 
737
    gst_collect_pads_add_pad (self->collect, self->sink2,
 
738
        sizeof (GstCollectData));
 
739
    gst_element_add_pad (GST_ELEMENT_CAST (self), self->sink2);
 
740
  }
 
741
 
 
742
}
 
743
 
 
744
gboolean
 
745
gst_frei0r_mixer_register (GstPlugin * plugin, const f0r_plugin_info_t * info,
 
746
    const GstFrei0rFuncTable * ftable)
 
747
{
 
748
  GTypeInfo typeinfo = {
 
749
    sizeof (GstFrei0rMixerClass),
 
750
    NULL,
 
751
    NULL,
 
752
    (GClassInitFunc) gst_frei0r_mixer_class_init,
 
753
    NULL,
 
754
    NULL,
 
755
    sizeof (GstFrei0rMixer),
 
756
    0,
 
757
    (GInstanceInitFunc) gst_frei0r_mixer_init
 
758
  };
 
759
  GType type;
 
760
  gchar *type_name, *tmp;
 
761
  GstFrei0rMixerClassData *class_data;
 
762
  gboolean ret = FALSE;
 
763
 
 
764
  if (ftable->update2 == NULL)
 
765
    return FALSE;
 
766
 
 
767
  tmp = g_strdup_printf ("frei0r-mixer-%s", info->name);
 
768
  type_name = g_ascii_strdown (tmp, -1);
 
769
  g_free (tmp);
 
770
  g_strcanon (type_name, G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "-+", '-');
 
771
 
 
772
  if (g_type_from_name (type_name)) {
 
773
    GST_WARNING ("Type '%s' already exists", type_name);
 
774
    return FALSE;
 
775
  }
 
776
 
 
777
  class_data = g_new0 (GstFrei0rMixerClassData, 1);
 
778
  memcpy (&class_data->info, info, sizeof (f0r_plugin_info_t));
 
779
  memcpy (&class_data->ftable, ftable, sizeof (GstFrei0rFuncTable));
 
780
  typeinfo.class_data = class_data;
 
781
 
 
782
  type = g_type_register_static (GST_TYPE_ELEMENT, type_name, &typeinfo, 0);
 
783
  ret = gst_element_register (plugin, type_name, GST_RANK_NONE, type);
 
784
 
 
785
  g_free (type_name);
 
786
  return ret;
 
787
}