~ubuntu-branches/ubuntu/saucy/gnash/saucy-proposed

« back to all changes in this revision

Viewing changes to libmedia/gst/gstappsink.c

  • Committer: Bazaar Package Importer
  • Author(s): Alexander Sack
  • Date: 2008-10-13 14:29:49 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: james.westby@ubuntu.com-20081013142949-f6qdvnu4mn05ltdc
Tags: 0.8.4~~bzr9980-0ubuntu1
* new upstream release 0.8.4 (LP: #240325)
* ship new lib usr/lib/gnash/libmozsdk.so.* in mozilla-plugin-gnash
  - update debian/mozilla-plugin-gnash.install
* ship new lib usr/lib/gnash/libgnashnet.so.* in gnash-common
  - update debian/gnash-common.install
* add basic debian/build_head script to build latest CVS head packages.
  - add debian/build_head
* new sound architecture requires build depend on libsdl1.2-dev
  - update debian/control
* head build script now has been completely migrated to bzr (upstream +
  ubuntu)
  - update debian/build_head
* disable kde gui until klash/qt4 has been fixed; keep kde packages as empty
  packages for now.
  - update debian/rules
  - debian/klash.install
  - debian/klash.links
  - debian/klash.manpages
  - debian/konqueror-plugin-gnash.install
* drop libkonq5-dev build dependency accordingly
  - update debian/control
* don't install headers manually anymore. gnash doesnt provide a -dev
  package after all
  - update debian/rules
* update libs installed in gnash-common; libgnashserver-*.so is not available
  anymore (removed); in turn we add the new libgnashcore-*.so
  - update debian/gnash-common.install
* use -Os for optimization and properly pass CXXFLAGS=$(CFLAGS) to configure
  - update debian/rules
* touch firefox .autoreg in postinst of mozilla plugin
  - update debian/mozilla-plugin-gnash.postinst
* link gnash in ubufox plugins directory for the plugin alternative switcher
  - add debian/mozilla-plugin-gnash.links
* suggest ubufox accordingly
  - update debian/control
* add new required build-depends on libgif-dev
  - update debian/control
* add Xb-Npp-Description and Xb-Npp-File as new plugin database meta data
  - update debian/control

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* GStreamer
2
 
 * Copyright (C) 2007 David Schleef <ds@schleef.org>
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
 
/* $Id: gstappsink.c,v 1.6 2008/01/29 05:18:33 bjacques Exp $ */
21
 
 
22
 
#ifdef HAVE_CONFIG_H
23
 
#include "gnashconfig.h"
24
 
#endif
25
 
 
26
 
#include <gst/gst.h>
27
 
#include <gst/base/gstbasesink.h>
28
 
#include <gst/gstbuffer.h>
29
 
 
30
 
#include <string.h>
31
 
 
32
 
#include "gstappsink.h"
33
 
 
34
 
 
35
 
GST_DEBUG_CATEGORY (app_sink_debug);
36
 
#define GST_CAT_DEFAULT app_sink_debug
37
 
 
38
 
static const GstElementDetails app_sink_details =
39
 
GST_ELEMENT_DETAILS ("AppSink",
40
 
    "Generic/Sink",
41
 
    "Allow the application to get access to raw buffer",
42
 
    "David Schleef <ds@schleef.org>, Wim Taymans <wim.taymans@gmail.com");
43
 
 
44
 
enum
45
 
{
46
 
  /* signals */
47
 
  SIGNAL_EOS,
48
 
  SIGNAL_NEW_PREROLL,
49
 
  SIGNAL_NEW_BUFFER,
50
 
 
51
 
  /* acions */
52
 
  SIGNAL_PULL_PREROLL,
53
 
  SIGNAL_PULL_BUFFER,
54
 
 
55
 
  LAST_SIGNAL
56
 
};
57
 
 
58
 
enum
59
 
{
60
 
  PROP_0,
61
 
  PROP_CAPS,
62
 
  PROP_EOS
63
 
};
64
 
 
65
 
static GstStaticPadTemplate gst_app_sink_template =
66
 
GST_STATIC_PAD_TEMPLATE ("sink",
67
 
    GST_PAD_SINK,
68
 
    GST_PAD_ALWAYS,
69
 
    GST_STATIC_CAPS_ANY);
70
 
 
71
 
static void gst_app_sink_dispose (GObject * object);
72
 
static void gst_app_sink_finalize (GObject * object);
73
 
 
74
 
static void gst_app_sink_set_property (GObject * object, guint prop_id,
75
 
    const GValue * value, GParamSpec * pspec);
76
 
static void gst_app_sink_get_property (GObject * object, guint prop_id,
77
 
    GValue * value, GParamSpec * pspec);
78
 
 
79
 
static gboolean gst_app_sink_start (GstBaseSink * psink);
80
 
static gboolean gst_app_sink_stop (GstBaseSink * psink);
81
 
static gboolean gst_app_sink_event (GstBaseSink * sink, GstEvent * event);
82
 
static GstFlowReturn gst_app_sink_preroll (GstBaseSink * psink,
83
 
    GstBuffer * buffer);
84
 
static GstFlowReturn gst_app_sink_render (GstBaseSink * psink,
85
 
    GstBuffer * buffer);
86
 
static GstCaps *gst_app_sink_getcaps (GstBaseSink * psink);
87
 
 
88
 
static guint gst_app_sink_signals[LAST_SIGNAL] = { 0 };
89
 
 
90
 
GST_BOILERPLATE (GstAppSink, gst_app_sink, GstBaseSink, GST_TYPE_BASE_SINK);
91
 
 
92
 
void
93
 
gst_app_marshal_OBJECT__VOID (GClosure * closure,
94
 
    GValue * return_value,
95
 
    guint n_param_values,
96
 
    const GValue * param_values,
97
 
    gpointer invocation_hint, gpointer marshal_data)
98
 
{
99
 
  typedef GstBuffer *(*GMarshalFunc_OBJECT__VOID) (gpointer data1,
100
 
      gpointer data2);
101
 
  register GMarshalFunc_OBJECT__VOID callback;
102
 
  register GCClosure *cc = (GCClosure *) closure;
103
 
  register gpointer data1, data2;
104
 
  GstBuffer *v_return;
105
 
 
106
 
  g_return_if_fail (return_value != NULL);
107
 
  g_return_if_fail (n_param_values == 1);
108
 
 
109
 
  if (G_CCLOSURE_SWAP_DATA (closure)) {
110
 
    data1 = closure->data;
111
 
    data2 = g_value_peek_pointer (param_values + 0);
112
 
  } else {
113
 
    data1 = g_value_peek_pointer (param_values + 0);
114
 
    data2 = closure->data;
115
 
  }
116
 
  callback =
117
 
      (GMarshalFunc_OBJECT__VOID) (marshal_data ? marshal_data : cc->callback);
118
 
 
119
 
  v_return = callback (data1, data2);
120
 
 
121
 
  gst_value_take_buffer (return_value, v_return);
122
 
}
123
 
 
124
 
static void
125
 
gst_app_sink_base_init (gpointer g_class)
126
 
{
127
 
  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
128
 
 
129
 
  GST_DEBUG_CATEGORY_INIT (app_sink_debug, "appsink", 0, "appsink element");
130
 
 
131
 
  gst_element_class_set_details (element_class, &app_sink_details);
132
 
 
133
 
  gst_element_class_add_pad_template (element_class,
134
 
      gst_static_pad_template_get (&gst_app_sink_template));
135
 
}
136
 
 
137
 
static void
138
 
gst_app_sink_class_init (GstAppSinkClass * klass)
139
 
{
140
 
  GObjectClass *gobject_class = (GObjectClass *) klass;
141
 
  GstBaseSinkClass *basesink_class = (GstBaseSinkClass *) klass;
142
 
 
143
 
  gobject_class->dispose = gst_app_sink_dispose;
144
 
  gobject_class->finalize = gst_app_sink_finalize;
145
 
 
146
 
  gobject_class->set_property = gst_app_sink_set_property;
147
 
  gobject_class->get_property = gst_app_sink_get_property;
148
 
 
149
 
  g_object_class_install_property (gobject_class, PROP_CAPS,
150
 
      g_param_spec_boxed ("caps", "Caps",
151
 
          "The caps of the sink pad", GST_TYPE_CAPS, G_PARAM_READWRITE));
152
 
 
153
 
  g_object_class_install_property (gobject_class, PROP_EOS,
154
 
      g_param_spec_boolean ("eos", "EOS",
155
 
          "Check if the sink is EOS", TRUE, G_PARAM_READABLE));
156
 
 
157
 
  /**
158
 
   * GstAppSink::eos:
159
 
   * @appsink: the appsink element that emited the signal
160
 
   *
161
 
   * Signal that the end-of-stream has been reached. 
162
 
   */
163
 
  gst_app_sink_signals[SIGNAL_EOS] =
164
 
      g_signal_new ("eos", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
165
 
      G_STRUCT_OFFSET (GstAppSinkClass, eos),
166
 
      NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
167
 
  /**
168
 
   * GstAppSink::new-preroll:
169
 
   * @appsink: the appsink element that emited the signal
170
 
   * @buffer: the buffer that caused the preroll
171
 
   *
172
 
   * Signal that a new preroll buffer is available.
173
 
   */
174
 
  gst_app_sink_signals[SIGNAL_NEW_PREROLL] =
175
 
      g_signal_new ("new-preroll", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
176
 
      G_STRUCT_OFFSET (GstAppSinkClass, new_preroll),
177
 
      NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 0,
178
 
      GST_TYPE_BUFFER);
179
 
  /**
180
 
   * GstAppSink::new-buffer:
181
 
   * @appsink: the appsink element that emited the signal
182
 
   * @buffer: the buffer that is available
183
 
   *
184
 
   * Signal that a new buffer is available.
185
 
   */
186
 
  gst_app_sink_signals[SIGNAL_NEW_BUFFER] =
187
 
      g_signal_new ("new-buffer", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
188
 
      G_STRUCT_OFFSET (GstAppSinkClass, new_buffer),
189
 
      NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 0,
190
 
      GST_TYPE_BUFFER);
191
 
 
192
 
  /**
193
 
   * GstAppSink::pull-preroll:
194
 
   * @appsink: the appsink element to emit this signal on
195
 
   *
196
 
   * Get the last preroll buffer on @appsink.
197
 
   */
198
 
  gst_app_sink_signals[SIGNAL_PULL_PREROLL] =
199
 
      g_signal_new ("pull-preroll", G_TYPE_FROM_CLASS (klass),
200
 
      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstAppSinkClass, pull_preroll), NULL,
201
 
      NULL, gst_app_marshal_OBJECT__VOID, GST_TYPE_BUFFER, 0, G_TYPE_NONE);
202
 
  /**
203
 
   * GstAppSink::pull-buffer:
204
 
   * @appsink: the appsink element to emit this signal on
205
 
   *
206
 
   * Get the next buffer buffer on @appsink.
207
 
   */
208
 
  gst_app_sink_signals[SIGNAL_PULL_PREROLL] =
209
 
      g_signal_new ("pull-buffer", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
210
 
      G_STRUCT_OFFSET (GstAppSinkClass, pull_buffer),
211
 
      NULL, NULL, gst_app_marshal_OBJECT__VOID, GST_TYPE_BUFFER, 0,
212
 
      G_TYPE_NONE);
213
 
 
214
 
  basesink_class->start = gst_app_sink_start;
215
 
  basesink_class->stop = gst_app_sink_stop;
216
 
  basesink_class->event = gst_app_sink_event;
217
 
  basesink_class->preroll = gst_app_sink_preroll;
218
 
  basesink_class->render = gst_app_sink_render;
219
 
  basesink_class->get_caps = gst_app_sink_getcaps;
220
 
 
221
 
  klass->pull_preroll = gst_app_sink_pull_preroll;
222
 
  klass->pull_buffer = gst_app_sink_pull_buffer;
223
 
}
224
 
 
225
 
static void
226
 
gst_app_sink_init (GstAppSink * appsink, GstAppSinkClass * klass)
227
 
{
228
 
  appsink->mutex = g_mutex_new ();
229
 
  appsink->cond = g_cond_new ();
230
 
  appsink->queue = g_queue_new ();
231
 
}
232
 
 
233
 
static void
234
 
gst_app_sink_dispose (GObject * obj)
235
 
{
236
 
  GstAppSink *appsink = GST_APP_SINK (obj);
237
 
 
238
 
  if (appsink->caps) {
239
 
    gst_caps_unref (appsink->caps);
240
 
    appsink->caps = NULL;
241
 
  }
242
 
  if (appsink->preroll) {
243
 
    gst_buffer_unref (appsink->preroll);
244
 
    appsink->preroll = NULL;
245
 
  }
246
 
  g_queue_foreach (appsink->queue, (GFunc) gst_mini_object_unref, NULL);
247
 
 
248
 
  G_OBJECT_CLASS (parent_class)->dispose (obj);
249
 
}
250
 
 
251
 
static void
252
 
gst_app_sink_finalize (GObject * obj)
253
 
{
254
 
  GstAppSink *appsink = GST_APP_SINK (obj);
255
 
 
256
 
  g_mutex_free (appsink->mutex);
257
 
  g_cond_free (appsink->cond);
258
 
  g_queue_free (appsink->queue);
259
 
 
260
 
  G_OBJECT_CLASS (parent_class)->finalize (obj);
261
 
}
262
 
 
263
 
static void
264
 
gst_app_sink_set_property (GObject * object, guint prop_id,
265
 
    const GValue * value, GParamSpec * pspec)
266
 
{
267
 
  GstAppSink *appsink = GST_APP_SINK (object);
268
 
 
269
 
  switch (prop_id) {
270
 
    case PROP_CAPS:
271
 
      gst_app_sink_set_caps (appsink, gst_value_get_caps (value));
272
 
      break;
273
 
    default:
274
 
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
275
 
      break;
276
 
  }
277
 
}
278
 
 
279
 
static void
280
 
gst_app_sink_get_property (GObject * object, guint prop_id, GValue * value,
281
 
    GParamSpec * pspec)
282
 
{
283
 
  GstAppSink *appsink = GST_APP_SINK (object);
284
 
 
285
 
  switch (prop_id) {
286
 
    case PROP_CAPS:
287
 
    {
288
 
      GstCaps *caps;
289
 
 
290
 
      caps = gst_app_sink_get_caps (appsink);
291
 
      gst_value_set_caps (value, caps);
292
 
      if (caps)
293
 
        gst_caps_unref (caps);
294
 
      break;
295
 
    }
296
 
    case PROP_EOS:
297
 
      g_value_set_boolean (value, gst_app_sink_is_eos (appsink));
298
 
      break;
299
 
    default:
300
 
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
301
 
      break;
302
 
  }
303
 
}
304
 
 
305
 
static void
306
 
gst_app_sink_flush_unlocked (GstAppSink * appsink)
307
 
{
308
 
  GstBuffer *buffer;
309
 
 
310
 
  GST_DEBUG_OBJECT (appsink, "flushing appsink");
311
 
  appsink->is_eos = FALSE;
312
 
  gst_buffer_replace (&appsink->preroll, NULL);
313
 
  while ((buffer = g_queue_pop_head (appsink->queue)))
314
 
    gst_buffer_unref (buffer);
315
 
  g_cond_signal (appsink->cond);
316
 
}
317
 
 
318
 
static gboolean
319
 
gst_app_sink_start (GstBaseSink * psink)
320
 
{
321
 
  GstAppSink *appsink = GST_APP_SINK (psink);
322
 
 
323
 
  g_mutex_lock (appsink->mutex);
324
 
  appsink->is_eos = FALSE;
325
 
  appsink->started = TRUE;
326
 
  GST_DEBUG_OBJECT (appsink, "starting");
327
 
  g_mutex_unlock (appsink->mutex);
328
 
 
329
 
  return TRUE;
330
 
}
331
 
 
332
 
static gboolean
333
 
gst_app_sink_stop (GstBaseSink * psink)
334
 
{
335
 
  GstAppSink *appsink = GST_APP_SINK (psink);
336
 
 
337
 
  g_mutex_lock (appsink->mutex);
338
 
  GST_DEBUG_OBJECT (appsink, "stopping");
339
 
  appsink->started = FALSE;
340
 
  gst_app_sink_flush_unlocked (appsink);
341
 
  g_mutex_unlock (appsink->mutex);
342
 
 
343
 
  return TRUE;
344
 
}
345
 
 
346
 
static gboolean
347
 
gst_app_sink_event (GstBaseSink * sink, GstEvent * event)
348
 
{
349
 
  GstAppSink *appsink = GST_APP_SINK (sink);
350
 
 
351
 
  switch (event->type) {
352
 
    case GST_EVENT_EOS:
353
 
      g_mutex_lock (appsink->mutex);
354
 
      GST_DEBUG_OBJECT (appsink, "receiving EOS");
355
 
      appsink->is_eos = TRUE;
356
 
      g_cond_signal (appsink->cond);
357
 
      g_mutex_unlock (appsink->mutex);
358
 
      break;
359
 
    case GST_EVENT_FLUSH_START:
360
 
      break;
361
 
    case GST_EVENT_FLUSH_STOP:
362
 
      g_mutex_lock (appsink->mutex);
363
 
      GST_DEBUG_OBJECT (appsink, "received FLUSH_STOP");
364
 
      gst_app_sink_flush_unlocked (appsink);
365
 
      g_mutex_unlock (appsink->mutex);
366
 
      break;
367
 
    default:
368
 
      break;
369
 
  }
370
 
  return TRUE;
371
 
}
372
 
 
373
 
static GstFlowReturn
374
 
gst_app_sink_preroll (GstBaseSink * psink, GstBuffer * buffer)
375
 
{
376
 
  GstAppSink *appsink = GST_APP_SINK (psink);
377
 
 
378
 
  g_mutex_lock (appsink->mutex);
379
 
  GST_DEBUG_OBJECT (appsink, "setting preroll buffer %p", buffer);
380
 
  gst_buffer_replace (&appsink->preroll, buffer);
381
 
  g_cond_signal (appsink->cond);
382
 
  g_mutex_unlock (appsink->mutex);
383
 
 
384
 
  return GST_FLOW_OK;
385
 
}
386
 
 
387
 
static GstFlowReturn
388
 
gst_app_sink_render (GstBaseSink * psink, GstBuffer * buffer)
389
 
{
390
 
  GstAppSink *appsink = GST_APP_SINK (psink);
391
 
 
392
 
  g_mutex_lock (appsink->mutex);
393
 
  GST_DEBUG_OBJECT (appsink, "pushing render buffer %p on queue", buffer);
394
 
  g_queue_push_tail (appsink->queue, gst_buffer_ref (buffer));
395
 
  g_cond_signal (appsink->cond);
396
 
  g_mutex_unlock (appsink->mutex);
397
 
 
398
 
  return GST_FLOW_OK;
399
 
}
400
 
 
401
 
static GstCaps *
402
 
gst_app_sink_getcaps (GstBaseSink * psink)
403
 
{
404
 
  GstCaps *caps;
405
 
 
406
 
  GstAppSink *appsink = GST_APP_SINK (psink);
407
 
 
408
 
  GST_OBJECT_LOCK (appsink);
409
 
  if ((caps = appsink->caps))
410
 
    gst_caps_ref (caps);
411
 
  GST_DEBUG_OBJECT (appsink, "got caps %" GST_PTR_FORMAT, caps);
412
 
  GST_OBJECT_UNLOCK (appsink);
413
 
 
414
 
  return caps;
415
 
}
416
 
 
417
 
 
418
 
static gboolean
419
 
plugin_init (GstPlugin * plugin)
420
 
{
421
 
  GST_DEBUG_CATEGORY_INIT (app_sink_debug, "appsink", 0, "Application sink");
422
 
 
423
 
  if (!gst_element_register (plugin, "appsink", GST_RANK_PRIMARY,
424
 
          gst_app_sink_get_type ()))
425
 
    return FALSE;
426
 
 
427
 
  return TRUE;
428
 
}
429
 
 
430
 
GST_PLUGIN_DEFINE_STATIC (GST_VERSION_MAJOR, GST_VERSION_MINOR,
431
 
    "appsink", "Element application sink",
432
 
    plugin_init, VERSION, "LGPL", "Gnash's internal copy of gstappsink", "Gnash")
433
 
 
434
 
 
435
 
 
436
 
 
437
 
/* external API */
438
 
 
439
 
/**
440
 
 * gst_app_sink_set_caps:
441
 
 * @appsink: a #GstAppSink
442
 
 * @caps: caps to set
443
 
 *
444
 
 * Set the capabilities on the appsink element.  This function takes
445
 
 * a copy of the caps structure. After calling this method, the sink will only
446
 
 * accept caps that match @caps. If @caps is non-fixed, you must check the caps
447
 
 * on the buffers to get the actual used caps. 
448
 
 */
449
 
void
450
 
gst_app_sink_set_caps (GstAppSink * appsink, const GstCaps * caps)
451
 
{
452
 
  GstCaps *old;
453
 
 
454
 
  g_return_if_fail (appsink != NULL);
455
 
  g_return_if_fail (GST_IS_APP_SINK (appsink));
456
 
 
457
 
  GST_OBJECT_LOCK (appsink);
458
 
  GST_DEBUG_OBJECT (appsink, "setting caps to %" GST_PTR_FORMAT, caps);
459
 
  old = appsink->caps;
460
 
  if (caps)
461
 
    appsink->caps = gst_caps_copy (caps);
462
 
  else
463
 
    appsink->caps = NULL;
464
 
  if (old)
465
 
    gst_caps_unref (old);
466
 
  GST_OBJECT_UNLOCK (appsink);
467
 
}
468
 
 
469
 
/**
470
 
 * gst_app_sink_get_caps:
471
 
 * @appsink: a #GstAppSink
472
 
 *
473
 
 * Get the configured caps on @appsink.
474
 
 *
475
 
 * Returns: the #GstCaps accepted by the sink. gst_caps_unref() after usage.
476
 
 */
477
 
GstCaps *
478
 
gst_app_sink_get_caps (GstAppSink * appsink)
479
 
{
480
 
  GstCaps *caps;
481
 
 
482
 
  g_return_val_if_fail (appsink != NULL, NULL);
483
 
  g_return_val_if_fail (GST_IS_APP_SINK (appsink), NULL);
484
 
 
485
 
  GST_OBJECT_LOCK (appsink);
486
 
  if ((caps = appsink->caps))
487
 
    gst_caps_ref (caps);
488
 
  GST_DEBUG_OBJECT (appsink, "getting caps of %" GST_PTR_FORMAT, caps);
489
 
  GST_OBJECT_UNLOCK (appsink);
490
 
 
491
 
  return caps;
492
 
}
493
 
 
494
 
/**
495
 
 * gst_app_sink_is_eos:
496
 
 * @appsink: a #GstAppSink
497
 
 *
498
 
 * Check if @appsink is EOS, which is when no more buffers can be pulled because
499
 
 * an EOS event was received.
500
 
 *
501
 
 * This function also returns %TRUE when the appsink is not in the PAUSED or
502
 
 * PLAYING state.
503
 
 *
504
 
 * Returns: %TRUE if no more buffers can be pulled and the appsink is EOS.
505
 
 */
506
 
gboolean
507
 
gst_app_sink_is_eos (GstAppSink * appsink)
508
 
{
509
 
  gboolean ret;
510
 
 
511
 
  g_return_val_if_fail (appsink != NULL, FALSE);
512
 
  g_return_val_if_fail (GST_IS_APP_SINK (appsink), FALSE);
513
 
 
514
 
  g_mutex_lock (appsink->mutex);
515
 
  if (!appsink->started)
516
 
    goto not_started;
517
 
 
518
 
  if (appsink->is_eos && g_queue_is_empty (appsink->queue)) {
519
 
    GST_DEBUG_OBJECT (appsink, "we are EOS and the queue is empty");
520
 
    ret = TRUE;
521
 
  } else {
522
 
    GST_DEBUG_OBJECT (appsink, "we are not yet EOS");
523
 
    ret = FALSE;
524
 
  }
525
 
  g_mutex_unlock (appsink->mutex);
526
 
 
527
 
  return ret;
528
 
 
529
 
not_started:
530
 
  {
531
 
    GST_DEBUG_OBJECT (appsink, "we are stopped, return TRUE");
532
 
    g_mutex_unlock (appsink->mutex);
533
 
    return TRUE;
534
 
  }
535
 
}
536
 
 
537
 
/**
538
 
 * gst_app_sink_pull_preroll:
539
 
 * @appsink: a #GstAppSink
540
 
 *
541
 
 * Get the last preroll buffer in @appsink. This was the buffer that caused the
542
 
 * appsink to preroll in the PAUSED state. This buffer can be pulled many times
543
 
 * and remains available to the application even after EOS.
544
 
 *
545
 
 * This function is typically used when dealing with a pipeline in the PAUSED
546
 
 * state. Calling this function after doing a seek will give the buffer right
547
 
 * after the seek position.
548
 
 *
549
 
 * Note that the preroll buffer will also be returned as the first buffer
550
 
 * when calling gst_app_sink_pull_buffer().
551
 
 *
552
 
 * If an EOS event was received before any buffers, this function returns
553
 
 * %NULL. Use gst_app_sink_is_eos () to check for the EOS condition. 
554
 
 *
555
 
 * This function blocks until a preroll buffer or EOS is received or the appsink
556
 
 * element is set to the READY/NULL state. 
557
 
 *
558
 
 * Returns: a #GstBuffer or NULL when the appsink is stopped or EOS.
559
 
 */
560
 
GstBuffer *
561
 
gst_app_sink_pull_preroll (GstAppSink * appsink)
562
 
{
563
 
  GstBuffer *buf = NULL;
564
 
 
565
 
  g_return_val_if_fail (appsink != NULL, NULL);
566
 
  g_return_val_if_fail (GST_IS_APP_SINK (appsink), NULL);
567
 
 
568
 
  g_mutex_lock (appsink->mutex);
569
 
 
570
 
  while (TRUE) {
571
 
    GST_DEBUG_OBJECT (appsink, "trying to grab a buffer");
572
 
    if (!appsink->started)
573
 
      goto not_started;
574
 
 
575
 
    if (appsink->preroll != NULL)
576
 
      break;
577
 
 
578
 
    if (appsink->is_eos)
579
 
      goto eos;
580
 
 
581
 
    /* nothing to return, wait */
582
 
    GST_DEBUG_OBJECT (appsink, "waiting for the preroll buffer");
583
 
    g_cond_wait (appsink->cond, appsink->mutex);
584
 
  }
585
 
  buf = gst_buffer_ref (appsink->preroll);
586
 
  GST_DEBUG_OBJECT (appsink, "we have the preroll buffer %p", buf);
587
 
  g_mutex_unlock (appsink->mutex);
588
 
 
589
 
  return buf;
590
 
 
591
 
  /* special conditions */
592
 
eos:
593
 
  {
594
 
    GST_DEBUG_OBJECT (appsink, "we are EOS, return NULL");
595
 
    g_mutex_unlock (appsink->mutex);
596
 
    return NULL;
597
 
  }
598
 
not_started:
599
 
  {
600
 
    GST_DEBUG_OBJECT (appsink, "we are stopped, return NULL");
601
 
    g_mutex_unlock (appsink->mutex);
602
 
    return NULL;
603
 
  }
604
 
}
605
 
 
606
 
/**
607
 
 * gst_app_sink_pull_buffer:
608
 
 * @appsink: a #GstAppSink
609
 
 *
610
 
 * This function blocks until a buffer or EOS becomes available or the appsink
611
 
 * element is set to the READY/NULL state. 
612
 
 *
613
 
 * This function will only return buffers when the appsink is in the PLAYING
614
 
 * state. All rendered buffers will be put in a queue so that the application
615
 
 * can pull buffers at its own rate. Note that when the application does not
616
 
 * pull buffers fast enough, the queued buffers could consume a lot of memory,
617
 
 * especially when dealing with raw video frames.
618
 
 *
619
 
 * If an EOS event was received before any buffers, this function returns
620
 
 * %NULL. Use gst_app_sink_is_eos () to check for the EOS condition. 
621
 
 *
622
 
 * Returns: a #GstBuffer or NULL when the appsink is stopped or EOS.
623
 
 */
624
 
GstBuffer *
625
 
gst_app_sink_pull_buffer (GstAppSink * appsink)
626
 
{
627
 
  GstBuffer *buf = NULL;
628
 
 
629
 
  g_return_val_if_fail (appsink != NULL, NULL);
630
 
  g_return_val_if_fail (GST_IS_APP_SINK (appsink), NULL);
631
 
 
632
 
  g_mutex_lock (appsink->mutex);
633
 
 
634
 
  while (TRUE) {
635
 
    GST_DEBUG_OBJECT (appsink, "trying to grab a buffer");
636
 
    if (!appsink->started)
637
 
      goto not_started;
638
 
 
639
 
    if (!g_queue_is_empty (appsink->queue))
640
 
      break;
641
 
 
642
 
    if (appsink->is_eos)
643
 
      goto eos;
644
 
 
645
 
    /* nothing to return, wait */
646
 
    GST_DEBUG_OBJECT (appsink, "waiting for a buffer");
647
 
    g_cond_wait (appsink->cond, appsink->mutex);    
648
 
  }
649
 
  buf = g_queue_pop_head (appsink->queue);
650
 
  GST_DEBUG_OBJECT (appsink, "we have a buffer %p", buf);
651
 
  g_mutex_unlock (appsink->mutex);
652
 
 
653
 
  return buf;
654
 
 
655
 
  /* special conditions */
656
 
eos:
657
 
  {
658
 
    GST_DEBUG_OBJECT (appsink, "we are EOS, return NULL");
659
 
    g_mutex_unlock (appsink->mutex);
660
 
    return NULL;
661
 
  }
662
 
not_started:
663
 
  {
664
 
    GST_DEBUG_OBJECT (appsink, "we are stopped, return NULL");
665
 
    g_mutex_unlock (appsink->mutex);
666
 
    return NULL;
667
 
  }
668
 
}
669
 
 
670
 
 
671
 
/**
672
 
 * gst_app_sink_pull_buffer_timed:
673
 
 * @appsink: a #GstAppSink
674
 
 *
675
 
 * This function blocks until a buffer or EOS becomes available or the appsink
676
 
 * element is set to the READY/NULL state, or if one second elapses. 
677
 
 *
678
 
 * This function will only return buffers when the appsink is in the PLAYING
679
 
 * state. All rendered buffers will be put in a queue so that the application
680
 
 * can pull buffers at its own rate.
681
 
 *
682
 
 * If an EOS event was received before any buffers, or if one second passes and
683
 
 * no data arrives, this function returns * %NULL. Use gst_app_sink_is_eos ()
684
 
 * to check for the EOS condition. 
685
 
 *
686
 
 * Returns: a #GstBuffer or NULL when the appsink is stopped or EOS, or one
687
 
 *   second elapses.
688
 
 */
689
 
GstBuffer *
690
 
gst_app_sink_pull_buffer_timed (GstAppSink * appsink)
691
 
{
692
 
  GstBuffer *buf = NULL;
693
 
 
694
 
  g_return_val_if_fail (appsink != NULL, NULL);
695
 
  g_return_val_if_fail (GST_IS_APP_SINK (appsink), NULL);
696
 
 
697
 
  g_mutex_lock (appsink->mutex);
698
 
 
699
 
  while (TRUE) {
700
 
    GST_DEBUG_OBJECT (appsink, "trying to grab a buffer");
701
 
    if (!appsink->started)
702
 
      goto not_started;
703
 
 
704
 
    if (!g_queue_is_empty (appsink->queue))
705
 
      break;
706
 
 
707
 
    if (appsink->is_eos)
708
 
      goto eos;
709
 
 
710
 
    /* nothing to return, wait */
711
 
    GST_DEBUG_OBJECT (appsink, "waiting for a buffer");    
712
 
    
713
 
    GTimeVal cur_time;
714
 
    g_get_current_time(&cur_time);
715
 
    cur_time.tv_sec++; // Add one second
716
 
 
717
 
    if (!g_cond_timed_wait(appsink->cond, appsink->mutex, &cur_time))
718
 
      goto timeout;
719
 
    
720
 
  }
721
 
  buf = g_queue_pop_head (appsink->queue);
722
 
  GST_DEBUG_OBJECT (appsink, "we have a buffer %p", buf);
723
 
  g_mutex_unlock (appsink->mutex);
724
 
 
725
 
  return buf;
726
 
 
727
 
  /* special conditions */
728
 
timeout:
729
 
  {
730
 
    GST_DEBUG_OBJECT (appsink, "we timed out, return NULL");
731
 
    g_mutex_unlock (appsink->mutex);
732
 
    return NULL;
733
 
  }
734
 
eos:
735
 
  {
736
 
    GST_DEBUG_OBJECT (appsink, "we are EOS, return NULL");
737
 
    g_mutex_unlock (appsink->mutex);
738
 
    return NULL;
739
 
  }
740
 
not_started:
741
 
  {
742
 
    GST_DEBUG_OBJECT (appsink, "we are stopped, return NULL");
743
 
    g_mutex_unlock (appsink->mutex);
744
 
    return NULL;
745
 
  }
746
 
}
747
 
 
748
 
 
749
 
 
750
 
/**
751
 
 * gst_app_sink_peek_buffer:
752
 
 * @appsink: a #GstAppSink
753
 
 *
754
 
 * This function peeks the queue to see if at least one buffer is in the queue.
755
 
 *
756
 
 * Returns: TRUE if there is a buffer in the queue.
757
 
 */
758
 
gboolean
759
 
gst_app_sink_peek_buffer (GstAppSink * appsink)
760
 
{
761
 
  g_return_val_if_fail (appsink != NULL, NULL);
762
 
  g_return_val_if_fail (GST_IS_APP_SINK (appsink), NULL);
763
 
 
764
 
  g_mutex_lock (appsink->mutex);
765
 
 
766
 
  gboolean got_data = !g_queue_is_empty(appsink->queue);
767
 
 
768
 
  g_mutex_unlock (appsink->mutex);
769
 
 
770
 
  return got_data;
771
 
}