gstbasesink.c 144 KB
Newer Older
Wim Taymans's avatar
Wim Taymans committed
1
/* GStreamer
2
 * Copyright (C) 2005-2007 Wim Taymans <wim.taymans@gmail.com>
Wim Taymans's avatar
Wim Taymans committed
3
 *
4
 * gstbasesink.c: Base class for sink elements
Wim Taymans's avatar
Wim Taymans committed
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
 *
 * 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.
 */

22 23 24
/**
 * SECTION:gstbasesink
 * @short_description: Base class for sink elements
Stefan Kost's avatar
Stefan Kost committed
25
 * @see_also: #GstBaseTransform, #GstBaseSrc
26
 *
27
 * #GstBaseSink is the base class for sink elements in GStreamer, such as
28
 * xvimagesink or filesink. It is a layer on top of #GstElement that provides a
29 30 31 32 33 34
 * simplified interface to plugin writers. #GstBaseSink handles many details
 * for you, for example: preroll, clock synchronization, state changes,
 * activation in push or pull mode, and queries.
 *
 * In most cases, when writing sink elements, there is no need to implement
 * class methods from #GstElement or to set functions on pads, because the
35 36
 * #GstBaseSink infrastructure should be sufficient.
 *
37
 * #GstBaseSink provides support for exactly one sink pad, which should be
38
 * named "sink". A sink implementation (subclass of #GstBaseSink) should
39
 * install a pad template in its class_init function, like so:
Stefan Kost's avatar
Stefan Kost committed
40
 * |[
41
 * static void
42
 * my_element_class_init (GstMyElementClass *klass)
43
 * {
44
 *   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
Wim Taymans's avatar
Wim Taymans committed
45
 *
46 47 48 49 50 51 52
 *   // sinktemplate should be a #GstStaticPadTemplate with direction
 *   // #GST_PAD_SINK and name "sink"
 *   gst_element_class_add_pad_template (gstelement_class,
 *       gst_static_pad_template_get (&amp;sinktemplate));
 *   // see #GstElementDetails
 *   gst_element_class_set_details (gstelement_class, &amp;details);
 * }
Stefan Kost's avatar
Stefan Kost committed
53
 * ]|
54
 *
55
 * #GstBaseSink will handle the prerolling correctly. This means that it will
56
 * return #GST_STATE_CHANGE_ASYNC from a state change to PAUSED until the first
57
 * buffer arrives in this element. The base class will call the
Stefan Kost's avatar
Stefan Kost committed
58 59
 * #GstBaseSinkClass.preroll() vmethod with this preroll buffer and will then
 * commit the state change to the next asynchronously pending state.
60
 *
61
 * When the element is set to PLAYING, #GstBaseSink will synchronise on the
Stefan Kost's avatar
Stefan Kost committed
62 63 64 65
 * clock using the times returned from #GstBaseSinkClass.get_times(). If this
 * function returns #GST_CLOCK_TIME_NONE for the start time, no synchronisation
 * will be done. Synchronisation can be disabled entirely by setting the object
 * #GstBaseSink:sync property to %FALSE.
66
 *
Stefan Kost's avatar
Stefan Kost committed
67 68
 * After synchronisation the virtual method #GstBaseSinkClass.render() will be
 * called. Subclasses should minimally implement this method.
69
 *
Stefan Kost's avatar
Stefan Kost committed
70 71 72 73 74 75
 * Since 0.10.3 subclasses that synchronise on the clock in the
 * #GstBaseSinkClass.render() method are supported as well. These classes
 * typically receive a buffer in the render method and can then potentially
 * block on the clock while rendering. A typical example is an audiosink.
 * Since 0.10.11 these subclasses can use gst_base_sink_wait_preroll() to
 * perform the blocking wait.
76
 *
77 78
 * Upon receiving the EOS event in the PLAYING state, #GstBaseSink will wait
 * for the clock to reach the time indicated by the stop time of the last
Stefan Kost's avatar
Stefan Kost committed
79 80 81
 * #GstBaseSinkClass.get_times() call before posting an EOS message. When the
 * element receives EOS in PAUSED, preroll completes, the event is queued and an
 * EOS message is posted when going to PLAYING.
82
 *
83
 * #GstBaseSink will internally use the #GST_EVENT_NEWSEGMENT events to schedule
84
 * synchronisation and clipping of buffers. Buffers that fall completely outside
85 86
 * of the current segment are dropped. Buffers that fall partially in the
 * segment are rendered (and prerolled). Subclasses should do any subbuffer
87
 * clipping themselves when needed.
88 89
 *
 * #GstBaseSink will by default report the current playback position in
90
 * #GST_FORMAT_TIME based on the current clock time and segment information.
91
 * If no clock has been set on the element, the query will be forwarded
92
 * upstream.
93
 *
Stefan Kost's avatar
Stefan Kost committed
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
 * The #GstBaseSinkClass.set_caps() function will be called when the subclass
 * should configure itself to process a specific media type.
 *
 * The #GstBaseSinkClass.start() and #GstBaseSinkClass.stop() virtual methods
 * will be called when resources should be allocated. Any 
 * #GstBaseSinkClass.preroll(), #GstBaseSinkClass.render() and
 * #GstBaseSinkClass.set_caps() function will be called between the
 * #GstBaseSinkClass.start() and #GstBaseSinkClass.stop() calls.
 *
 * The #GstBaseSinkClass.event() virtual method will be called when an event is
 * received by #GstBaseSink. Normally this method should only be overriden by
 * very specific elements (such as file sinks) which need to handle the
 * newsegment event specially.
 *
 * The #GstBaseSinkClass.unlock() method is called when the elements should
 * unblock any blocking operations they perform in the
 * #GstBaseSinkClass.render() method. This is mostly useful when the
 * #GstBaseSinkClass.render() method performs a blocking write on a file
 * descriptor, for example.
 *
 * The #GstBaseSink:max-lateness property affects how the sink deals with
 * buffers that arrive too late in the sink. A buffer arrives too late in the
 * sink when the presentation time (as a combination of the last segment, buffer
117 118
 * timestamp and element base_time) plus the duration is before the current
 * time of the clock.
119
 * If the frame is later than max-lateness, the sink will drop the buffer
120
 * without calling the render method.
Stefan Kost's avatar
Stefan Kost committed
121 122 123
 * This feature is disabled if sync is disabled, the
 * #GstBaseSinkClass.get_times() method does not return a valid start time or
 * max-lateness is set to -1 (the default).
124
 * Subclasses can use gst_base_sink_set_max_lateness() to configure the
125
 * max-lateness value.
126
 *
Stefan Kost's avatar
Stefan Kost committed
127 128 129
 * The #GstBaseSink:qos property will enable the quality-of-service features of
 * the basesink which gather statistics about the real-time performance of the
 * clock synchronisation. For each buffer received in the sink, statistics are
130
 * gathered and a QOS event is sent upstream with these numbers. This
131 132
 * information can then be used by upstream elements to reduce their processing
 * rate, for example.
133
 *
Stefan Kost's avatar
Stefan Kost committed
134 135 136
 * Since 0.10.15 the #GstBaseSink:async property can be used to instruct the
 * sink to never perform an ASYNC state change. This feature is mostly usable
 * when dealing with non-synchronized streams or sparse streams.
137 138
 *
 * Last reviewed on 2007-08-29 (0.10.15)
139 140
 */

Wim Taymans's avatar
Wim Taymans committed
141 142 143 144
#ifdef HAVE_CONFIG_H
#  include "config.h"
#endif

145 146
#include <gst/gst_private.h>

Wim Taymans's avatar
Wim Taymans committed
147 148
#include "gstbasesink.h"
#include <gst/gstmarshal.h>
149
#include <gst/gst-i18n-lib.h>
Wim Taymans's avatar
Wim Taymans committed
150

151 152
GST_DEBUG_CATEGORY_STATIC (gst_base_sink_debug);
#define GST_CAT_DEFAULT gst_base_sink_debug
Wim Taymans's avatar
Wim Taymans committed
153

154 155 156
#define GST_BASE_SINK_GET_PRIVATE(obj)  \
   (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_BASE_SINK, GstBaseSinkPrivate))

157 158
#define GST_FLOW_STEP GST_FLOW_CUSTOM_ERROR

159 160
typedef struct
{
161 162 163 164
  gboolean valid;               /* if this info is valid */
  guint32 seqnum;               /* the seqnum of the STEP event */
  GstFormat format;             /* the format of the amount */
  guint64 amount;               /* the total amount of data to skip */
165
  guint64 position;             /* the position in the stepped data */
166 167 168
  guint64 duration;             /* the duration in time of the skipped data */
  guint64 start;                /* running_time of the start */
  gdouble rate;                 /* rate of skipping */
169
  gdouble start_rate;           /* rate before skipping */
170
  guint64 start_start;          /* start position skipping */
171
  guint64 start_stop;           /* stop position skipping */
172
  gboolean flush;               /* if this was a flushing step */
173 174
  gboolean intermediate;        /* if this is an intermediate step */
  gboolean need_preroll;        /* if we need preroll after this step */
175 176
} GstStepInfo;

177 178
struct _GstBaseSinkPrivate
{
179
  gint qos_enabled;             /* ATOMIC */
180
  gboolean async_enabled;
181
  GstClockTimeDiff ts_offset;
182
  GstClockTime render_delay;
183

184 185 186
  /* start, stop of current buffer, stream time, used to report position */
  GstClockTime current_sstart;
  GstClockTime current_sstop;
187

188 189 190
  /* start, stop and jitter of current buffer, running time */
  GstClockTime current_rstart;
  GstClockTime current_rstop;
191
  GstClockTimeDiff current_jitter;
192 193
  /* the running time of the previous buffer */
  GstClockTime prev_rstart;
194

195 196 197
  /* EOS sync time in running time */
  GstClockTime eos_rtime;

198
  /* last buffer that arrived in time, running time */
Wim Taymans's avatar
Wim Taymans committed
199
  GstClockTime last_render_time;
200
  /* when the last buffer left the sink, running time */
201 202
  GstClockTime last_left;

203
  /* running averages go here these are done on running time */
204 205 206
  GstClockTime avg_pt;
  GstClockTime avg_duration;
  gdouble avg_rate;
207
  GstClockTime avg_in_diff;
208

209
  /* these are done on system time. avg_jitter and avg_render are
210
   * compared to eachother to see if the rendering time takes a
211
   * huge amount of the processing, If so we are flooded with
212 213 214
   * buffers. */
  GstClockTime last_left_systime;
  GstClockTime avg_jitter;
215
  GstClockTime start, stop;
216
  GstClockTime avg_render;
217 218 219 220

  /* number of rendered and dropped frames */
  guint64 rendered;
  guint64 dropped;
221 222 223

  /* latency stuff */
  GstClockTime latency;
224

225
  /* if we already commited the state */
226
  gboolean commited;
227 228
  /* state change to playing ongoing */
  gboolean to_playing;
229 230 231

  /* when we received EOS */
  gboolean received_eos;
232 233 234

  /* when we are prerolled and able to report latency */
  gboolean have_latency;
235 236

  /* the last buffer we prerolled or rendered. Useful for making snapshots */
237
  gint enable_last_sample;      /* atomic */
238
  GstBuffer *last_buffer;
239
  GstCaps *last_caps;
240

241 242
  /* negotiated caps */
  GstCaps *caps;
243

244
  /* blocksize for pulling */
245
  guint blocksize;
246 247

  gboolean discont;
248 249 250

  /* seqnum of the stream */
  guint32 seqnum;
251 252

  gboolean call_preroll;
253
  gboolean step_unlock;
254

255 256 257
  /* we have a pending and a current step operation */
  GstStepInfo current_step;
  GstStepInfo pending_step;
258 259 260

  /* Cached GstClockID */
  GstClockID cached_clock_id;
261

262 263
  /* for throttling and QoS */
  GstClockTime earliest_in_time;
264
  GstClockTime throttle_time;
265 266

  gboolean reset_time;
267 268
};

269 270
#define DO_RUNNING_AVG(avg,val,size) (((val) + ((size)-1) * (avg)) / (size))

271
/* generic running average, this has a neutral window size */
272 273
#define UPDATE_RUNNING_AVG(avg,val)   DO_RUNNING_AVG(avg,val,8)

274 275 276
/* the windows for these running averages are experimentally obtained.
 * possitive values get averaged more while negative values use a small
 * window so we can react faster to badness. */
277 278
#define UPDATE_RUNNING_AVG_P(avg,val) DO_RUNNING_AVG(avg,val,16)
#define UPDATE_RUNNING_AVG_N(avg,val) DO_RUNNING_AVG(avg,val,4)
279

280
/* BaseSink properties */
Wim Taymans's avatar
Wim Taymans committed
281

282 283
#define DEFAULT_CAN_ACTIVATE_PULL FALSE /* fixme: enable me */
#define DEFAULT_CAN_ACTIVATE_PUSH TRUE
Wim Taymans's avatar
Wim Taymans committed
284

Wim Taymans's avatar
Wim Taymans committed
285 286 287 288 289 290 291
#define DEFAULT_SYNC                TRUE
#define DEFAULT_MAX_LATENESS        -1
#define DEFAULT_QOS                 FALSE
#define DEFAULT_ASYNC               TRUE
#define DEFAULT_TS_OFFSET           0
#define DEFAULT_BLOCKSIZE           4096
#define DEFAULT_RENDER_DELAY        0
292
#define DEFAULT_ENABLE_LAST_SAMPLE  TRUE
293
#define DEFAULT_THROTTLE_TIME       0
294

Wim Taymans's avatar
Wim Taymans committed
295 296 297
enum
{
  PROP_0,
298
  PROP_SYNC,
299
  PROP_MAX_LATENESS,
300
  PROP_QOS,
301
  PROP_ASYNC,
302
  PROP_TS_OFFSET,
303 304
  PROP_ENABLE_LAST_SAMPLE,
  PROP_LAST_SAMPLE,
305
  PROP_BLOCKSIZE,
306
  PROP_RENDER_DELAY,
307
  PROP_THROTTLE_TIME,
308
  PROP_LAST
Wim Taymans's avatar
Wim Taymans committed
309 310
};

Wim Taymans's avatar
Wim Taymans committed
311 312
static GstElementClass *parent_class = NULL;

313 314 315
static void gst_base_sink_class_init (GstBaseSinkClass * klass);
static void gst_base_sink_init (GstBaseSink * trans, gpointer g_class);
static void gst_base_sink_finalize (GObject * object);
Wim Taymans's avatar
Wim Taymans committed
316 317

GType
318
gst_base_sink_get_type (void)
Wim Taymans's avatar
Wim Taymans committed
319
{
320
  static volatile gsize base_sink_type = 0;
Wim Taymans's avatar
Wim Taymans committed
321

322 323
  if (g_once_init_enter (&base_sink_type)) {
    GType _type;
324
    static const GTypeInfo base_sink_info = {
Wim Taymans's avatar
Wim Taymans committed
325
      sizeof (GstBaseSinkClass),
326
      NULL,
Wim Taymans's avatar
Wim Taymans committed
327
      NULL,
328
      (GClassInitFunc) gst_base_sink_class_init,
Wim Taymans's avatar
Wim Taymans committed
329 330 331 332
      NULL,
      NULL,
      sizeof (GstBaseSink),
      0,
333
      (GInstanceInitFunc) gst_base_sink_init,
Wim Taymans's avatar
Wim Taymans committed
334
    };
Wim Taymans's avatar
Wim Taymans committed
335

336
    _type = g_type_register_static (GST_TYPE_ELEMENT,
337
        "GstBaseSink", &base_sink_info, G_TYPE_FLAG_ABSTRACT);
338
    g_once_init_leave (&base_sink_type, _type);
Wim Taymans's avatar
Wim Taymans committed
339
  }
340
  return base_sink_type;
Wim Taymans's avatar
Wim Taymans committed
341
}
Wim Taymans's avatar
Wim Taymans committed
342

343
static void gst_base_sink_set_property (GObject * object, guint prop_id,
Wim Taymans's avatar
Wim Taymans committed
344
    const GValue * value, GParamSpec * pspec);
345
static void gst_base_sink_get_property (GObject * object, guint prop_id,
Wim Taymans's avatar
Wim Taymans committed
346 347
    GValue * value, GParamSpec * pspec);

348 349
static gboolean gst_base_sink_send_event (GstElement * element,
    GstEvent * event);
350
static gboolean default_element_query (GstElement * element, GstQuery * query);
351

Wim Taymans's avatar
Wim Taymans committed
352 353 354 355 356 357
static GstCaps *gst_base_sink_default_get_caps (GstBaseSink * sink,
    GstCaps * caps);
static gboolean gst_base_sink_default_set_caps (GstBaseSink * sink,
    GstCaps * caps);
static void gst_base_sink_default_get_times (GstBaseSink * basesink,
    GstBuffer * buffer, GstClockTime * start, GstClockTime * end);
358 359
static gboolean gst_base_sink_set_flushing (GstBaseSink * basesink,
    GstPad * pad, gboolean flushing);
360
static gboolean gst_base_sink_default_activate_pull (GstBaseSink * basesink,
361
    gboolean active);
362 363 364 365
static gboolean gst_base_sink_default_do_seek (GstBaseSink * sink,
    GstSegment * segment);
static gboolean gst_base_sink_default_prepare_seek_segment (GstBaseSink * sink,
    GstEvent * event, GstSegment * segment);
Wim Taymans's avatar
Wim Taymans committed
366

367 368
static GstStateChangeReturn gst_base_sink_change_state (GstElement * element,
    GstStateChange transition);
Wim Taymans's avatar
Wim Taymans committed
369

370 371
static gboolean gst_base_sink_sink_query (GstPad * pad, GstObject * parent,
    GstQuery * query);
372 373 374
static GstFlowReturn gst_base_sink_chain (GstPad * pad, GstObject * parent,
    GstBuffer * buffer);
static GstFlowReturn gst_base_sink_chain_list (GstPad * pad, GstObject * parent,
375 376
    GstBufferList * list);

377
static void gst_base_sink_loop (GstPad * pad);
378
static gboolean gst_base_sink_pad_activate (GstPad * pad, GstObject * parent);
379 380
static gboolean gst_base_sink_pad_activate_mode (GstPad * pad,
    GstObject * parent, GstPadMode mode, gboolean active);
381 382 383 384
static gboolean gst_base_sink_default_event (GstBaseSink * basesink,
    GstEvent * event);
static GstFlowReturn gst_base_sink_default_wait_eos (GstBaseSink * basesink,
    GstEvent * event);
385 386
static gboolean gst_base_sink_event (GstPad * pad, GstObject * parent,
    GstEvent * event);
Wim Taymans's avatar
Wim Taymans committed
387

Wim Taymans's avatar
Wim Taymans committed
388 389
static gboolean gst_base_sink_default_query (GstBaseSink * sink,
    GstQuery * query);
390

391
static gboolean gst_base_sink_negotiate_pull (GstBaseSink * basesink);
392 393
static void gst_base_sink_default_fixate (GstBaseSink * bsink, GstCaps * caps);
static void gst_base_sink_fixate (GstBaseSink * bsink, GstCaps * caps);
394

395 396
/* check if an object was too late */
static gboolean gst_base_sink_is_too_late (GstBaseSink * basesink,
Wim Taymans's avatar
Wim Taymans committed
397
    GstMiniObject * obj, GstClockTime rstart, GstClockTime rstop,
398
    GstClockReturn status, GstClockTimeDiff jitter);
399

Wim Taymans's avatar
Wim Taymans committed
400
static void
401
gst_base_sink_class_init (GstBaseSinkClass * klass)
Wim Taymans's avatar
Wim Taymans committed
402 403 404 405
{
  GObjectClass *gobject_class;
  GstElementClass *gstelement_class;

406 407
  gobject_class = G_OBJECT_CLASS (klass);
  gstelement_class = GST_ELEMENT_CLASS (klass);
Wim Taymans's avatar
Wim Taymans committed
408

409 410 411
  GST_DEBUG_CATEGORY_INIT (gst_base_sink_debug, "basesink", 0,
      "basesink element");

412 413
  g_type_class_add_private (klass, sizeof (GstBaseSinkPrivate));

414
  parent_class = g_type_class_peek_parent (klass);
Wim Taymans's avatar
Wim Taymans committed
415

416 417 418
  gobject_class->finalize = gst_base_sink_finalize;
  gobject_class->set_property = gst_base_sink_set_property;
  gobject_class->get_property = gst_base_sink_get_property;
Wim Taymans's avatar
Wim Taymans committed
419

420
  g_object_class_install_property (gobject_class, PROP_SYNC,
421
      g_param_spec_boolean ("sync", "Sync", "Sync on the clock", DEFAULT_SYNC,
422
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Wim Taymans's avatar
Wim Taymans committed
423

424
  g_object_class_install_property (gobject_class, PROP_MAX_LATENESS,
425 426 427
      g_param_spec_int64 ("max-lateness", "Max Lateness",
          "Maximum number of nanoseconds that a buffer can be late before it "
          "is dropped (-1 unlimited)", -1, G_MAXINT64, DEFAULT_MAX_LATENESS,
428
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
429

430
  g_object_class_install_property (gobject_class, PROP_QOS,
431 432
      g_param_spec_boolean ("qos", "Qos",
          "Generate Quality-of-Service events upstream", DEFAULT_QOS,
433
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
434 435 436 437 438 439 440 441 442 443 444 445
  /**
   * GstBaseSink:async
   *
   * If set to #TRUE, the basesink will perform asynchronous state changes.
   * When set to #FALSE, the sink will not signal the parent when it prerolls.
   * Use this option when dealing with sparse streams or when synchronisation is
   * not required.
   *
   * Since: 0.10.15
   */
  g_object_class_install_property (gobject_class, PROP_ASYNC,
      g_param_spec_boolean ("async", "Async",
446 447
          "Go asynchronously to PAUSED", DEFAULT_ASYNC,
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
448 449 450 451
  /**
   * GstBaseSink:ts-offset
   *
   * Controls the final synchronisation, a negative value will render the buffer
Wim Taymans's avatar
Wim Taymans committed
452
   * earlier while a positive value delays playback. This property can be
453 454 455 456 457 458 459
   * used to fix synchronisation in bad files.
   *
   * Since: 0.10.15
   */
  g_object_class_install_property (gobject_class, PROP_TS_OFFSET,
      g_param_spec_int64 ("ts-offset", "TS Offset",
          "Timestamp offset in nanoseconds", G_MININT64, G_MAXINT64,
460
          DEFAULT_TS_OFFSET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
461 462

  /**
463
   * GstBaseSink:enable-last-sample
464
   *
465 466
   * Enable the last-sample property. If FALSE, basesink doesn't keep a
   * reference to the last buffer arrived and the last-sample property is always
467 468 469 470 471
   * set to NULL. This can be useful if you need buffers to be released as soon
   * as possible, eg. if you're using a buffer pool.
   *
   * Since: 0.10.30
   */
472 473 474
  g_object_class_install_property (gobject_class, PROP_ENABLE_LAST_SAMPLE,
      g_param_spec_boolean ("enable-last-sample", "Enable Last Buffer",
          "Enable the last-sample property", DEFAULT_ENABLE_LAST_SAMPLE,
475 476
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));

477
  /**
478
   * GstBaseSink:last-sample
479 480
   *
   * The last buffer that arrived in the sink and was used for preroll or for
481 482
   * rendering. This property can be used to generate thumbnails. This property
   * can be NULL when the sink has not yet received a bufer.
483 484 485
   *
   * Since: 0.10.15
   */
486 487 488
  g_object_class_install_property (gobject_class, PROP_LAST_SAMPLE,
      g_param_spec_boxed ("last-sample", "Last Sample",
          "The last sample received in the sink", GST_TYPE_SAMPLE,
489
          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
490 491 492 493 494 495 496
  /**
   * GstBaseSink:blocksize
   *
   * The amount of bytes to pull when operating in pull mode.
   *
   * Since: 0.10.22
   */
497
  /* FIXME 0.11: blocksize property should be int, otherwise min>max.. */
498 499 500 501
  g_object_class_install_property (gobject_class, PROP_BLOCKSIZE,
      g_param_spec_uint ("blocksize", "Block size",
          "Size in bytes to pull per buffer (0 = default)", 0, G_MAXUINT,
          DEFAULT_BLOCKSIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
502 503 504 505 506 507 508 509 510 511 512 513 514
  /**
   * GstBaseSink:render-delay
   *
   * The additional delay between synchronisation and actual rendering of the
   * media. This property will add additional latency to the device in order to
   * make other sinks compensate for the delay.
   *
   * Since: 0.10.22
   */
  g_object_class_install_property (gobject_class, PROP_RENDER_DELAY,
      g_param_spec_uint64 ("render-delay", "Render Delay",
          "Additional render delay of the sink in nanoseconds", 0, G_MAXUINT64,
          DEFAULT_RENDER_DELAY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
515 516 517 518 519 520 521 522 523 524 525 526 527
  /**
   * GstBaseSink:throttle-time
   *
   * The time to insert between buffers. This property can be used to control
   * the maximum amount of buffers per second to render. Setting this property
   * to a value bigger than 0 will make the sink create THROTTLE QoS events.
   *
   * Since: 0.10.33
   */
  g_object_class_install_property (gobject_class, PROP_THROTTLE_TIME,
      g_param_spec_uint64 ("throttle-time", "Throttle time",
          "The time to keep between rendered buffers (unused)", 0, G_MAXUINT64,
          DEFAULT_THROTTLE_TIME, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
528

Wim Taymans's avatar
Wim Taymans committed
529
  gstelement_class->change_state =
530
      GST_DEBUG_FUNCPTR (gst_base_sink_change_state);
531
  gstelement_class->send_event = GST_DEBUG_FUNCPTR (gst_base_sink_send_event);
532
  gstelement_class->query = GST_DEBUG_FUNCPTR (default_element_query);
Wim Taymans's avatar
Wim Taymans committed
533

Wim Taymans's avatar
Wim Taymans committed
534 535
  klass->get_caps = GST_DEBUG_FUNCPTR (gst_base_sink_default_get_caps);
  klass->set_caps = GST_DEBUG_FUNCPTR (gst_base_sink_default_set_caps);
536
  klass->fixate = GST_DEBUG_FUNCPTR (gst_base_sink_default_fixate);
537 538
  klass->activate_pull =
      GST_DEBUG_FUNCPTR (gst_base_sink_default_activate_pull);
Wim Taymans's avatar
Wim Taymans committed
539 540
  klass->get_times = GST_DEBUG_FUNCPTR (gst_base_sink_default_get_times);
  klass->query = GST_DEBUG_FUNCPTR (gst_base_sink_default_query);
541 542
  klass->event = GST_DEBUG_FUNCPTR (gst_base_sink_default_event);
  klass->wait_eos = GST_DEBUG_FUNCPTR (gst_base_sink_default_wait_eos);
543 544

  /* Registering debug symbols for function pointers */
545
  GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_fixate);
546
  GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_pad_activate);
547
  GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_pad_activate_mode);
548 549 550
  GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_event);
  GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_chain);
  GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_chain_list);
551
  GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_sink_query);
Wim Taymans's avatar
Wim Taymans committed
552 553 554
}

static GstCaps *
555
gst_base_sink_query_caps (GstBaseSink * bsink, GstPad * pad, GstCaps * filter)
Wim Taymans's avatar
Wim Taymans committed
556 557 558
{
  GstBaseSinkClass *bclass;
  GstCaps *caps = NULL;
559
  gboolean fixed;
Wim Taymans's avatar
Wim Taymans committed
560

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
561
  bclass = GST_BASE_SINK_GET_CLASS (bsink);
562
  fixed = GST_PAD_IS_FIXED_CAPS (pad);
Wim Taymans's avatar
Wim Taymans committed
563

Wim Taymans's avatar
Wim Taymans committed
564
  if (fixed || bsink->pad_mode == GST_PAD_MODE_PULL) {
565 566
    /* if we are operating in pull mode or fixed caps, we only accept the
     * currently negotiated caps */
567
    caps = gst_pad_get_current_caps (pad);
568
  }
Wim Taymans's avatar
Wim Taymans committed
569
  if (caps == NULL) {
570
    if (bclass->get_caps)
571
      caps = bclass->get_caps (bsink, filter);
Wim Taymans's avatar
Wim Taymans committed
572

573 574 575 576 577 578 579
    if (caps == NULL) {
      GstPadTemplate *pad_template;

      pad_template =
          gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass),
          "sink");
      if (pad_template != NULL) {
580
        caps = gst_pad_template_get_caps (pad_template);
581 582 583 584 585 586 587 588 589

        if (filter) {
          GstCaps *intersection;

          intersection =
              gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
          gst_caps_unref (caps);
          caps = intersection;
        }
590
      }
Wim Taymans's avatar
Wim Taymans committed
591
    }
Wim Taymans's avatar
Wim Taymans committed
592
  }
Wim Taymans's avatar
Wim Taymans committed
593

Wim Taymans's avatar
Wim Taymans committed
594 595 596
  return caps;
}

597
static void
598 599 600 601 602 603 604 605
gst_base_sink_default_fixate (GstBaseSink * bsink, GstCaps * caps)
{
  GST_DEBUG_OBJECT (bsink, "using default caps fixate function");
  gst_caps_fixate (caps);
}

static void
gst_base_sink_fixate (GstBaseSink * bsink, GstCaps * caps)
606 607 608 609 610 611 612 613 614
{
  GstBaseSinkClass *bclass;

  bclass = GST_BASE_SINK_GET_CLASS (bsink);

  if (bclass->fixate)
    bclass->fixate (bsink, caps);
}

Wim Taymans's avatar
Wim Taymans committed
615
static void
616
gst_base_sink_init (GstBaseSink * basesink, gpointer g_class)
Wim Taymans's avatar
Wim Taymans committed
617
{
Wim Taymans's avatar
Wim Taymans committed
618
  GstPadTemplate *pad_template;
619 620 621
  GstBaseSinkPrivate *priv;

  basesink->priv = priv = GST_BASE_SINK_GET_PRIVATE (basesink);
Wim Taymans's avatar
Wim Taymans committed
622 623 624 625

  pad_template =
      gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "sink");
  g_return_if_fail (pad_template != NULL);
Wim Taymans's avatar
Wim Taymans committed
626

Wim Taymans's avatar
Wim Taymans committed
627
  basesink->sinkpad = gst_pad_new_from_template (pad_template, "sink");
Wim Taymans's avatar
Wim Taymans committed
628

629
  gst_pad_set_activate_function (basesink->sinkpad, gst_base_sink_pad_activate);
630 631
  gst_pad_set_activatemode_function (basesink->sinkpad,
      gst_base_sink_pad_activate_mode);
632
  gst_pad_set_query_function (basesink->sinkpad, gst_base_sink_sink_query);
633 634 635
  gst_pad_set_event_function (basesink->sinkpad, gst_base_sink_event);
  gst_pad_set_chain_function (basesink->sinkpad, gst_base_sink_chain);
  gst_pad_set_chain_list_function (basesink->sinkpad, gst_base_sink_chain_list);
636
  gst_element_add_pad (GST_ELEMENT_CAST (basesink), basesink->sinkpad);
Wim Taymans's avatar
Wim Taymans committed
637

Wim Taymans's avatar
Wim Taymans committed
638
  basesink->pad_mode = GST_PAD_MODE_NONE;
Wim Taymans's avatar
Wim Taymans committed
639 640
  g_mutex_init (&basesink->preroll_lock);
  g_cond_init (&basesink->preroll_cond);
641
  priv->have_latency = FALSE;
642

643 644 645
  basesink->can_activate_push = DEFAULT_CAN_ACTIVATE_PUSH;
  basesink->can_activate_pull = DEFAULT_CAN_ACTIVATE_PULL;

646
  basesink->sync = DEFAULT_SYNC;
Wim Taymans's avatar
Wim Taymans committed
647
  basesink->max_lateness = DEFAULT_MAX_LATENESS;
648
  g_atomic_int_set (&priv->qos_enabled, DEFAULT_QOS);
649
  priv->async_enabled = DEFAULT_ASYNC;
650
  priv->ts_offset = DEFAULT_TS_OFFSET;
651
  priv->render_delay = DEFAULT_RENDER_DELAY;
652
  priv->blocksize = DEFAULT_BLOCKSIZE;
653
  priv->cached_clock_id = NULL;
654
  g_atomic_int_set (&priv->enable_last_sample, DEFAULT_ENABLE_LAST_SAMPLE);
655
  priv->throttle_time = DEFAULT_THROTTLE_TIME;
656

Wim Taymans's avatar
Wim Taymans committed
657
  GST_OBJECT_FLAG_SET (basesink, GST_ELEMENT_FLAG_SINK);
Wim Taymans's avatar
Wim Taymans committed
658 659
}

660
static void
661
gst_base_sink_finalize (GObject * object)
662 663 664
{
  GstBaseSink *basesink;

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
665
  basesink = GST_BASE_SINK (object);
666

Wim Taymans's avatar
Wim Taymans committed
667 668
  g_mutex_clear (&basesink->preroll_lock);
  g_cond_clear (&basesink->preroll_cond);
669 670 671 672

  G_OBJECT_CLASS (parent_class)->finalize (object);
}

673 674 675 676 677 678
/**
 * gst_base_sink_set_sync:
 * @sink: the sink
 * @sync: the new sync value.
 *
 * Configures @sink to synchronize on the clock or not. When
Piotr Fusik's avatar
Piotr Fusik committed
679
 * @sync is FALSE, incoming samples will be played as fast as
680 681 682 683 684 685 686 687 688
 * possible. If @sync is TRUE, the timestamps of the incomming
 * buffers will be used to schedule the exact render time of its
 * contents.
 *
 * Since: 0.10.4
 */
void
gst_base_sink_set_sync (GstBaseSink * sink, gboolean sync)
{
689 690
  g_return_if_fail (GST_IS_BASE_SINK (sink));

691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711
  GST_OBJECT_LOCK (sink);
  sink->sync = sync;
  GST_OBJECT_UNLOCK (sink);
}

/**
 * gst_base_sink_get_sync:
 * @sink: the sink
 *
 * Checks if @sink is currently configured to synchronize against the
 * clock.
 *
 * Returns: TRUE if the sink is configured to synchronize against the clock.
 *
 * Since: 0.10.4
 */
gboolean
gst_base_sink_get_sync (GstBaseSink * sink)
{
  gboolean res;

712 713
  g_return_val_if_fail (GST_IS_BASE_SINK (sink), FALSE);

714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735
  GST_OBJECT_LOCK (sink);
  res = sink->sync;
  GST_OBJECT_UNLOCK (sink);

  return res;
}

/**
 * gst_base_sink_set_max_lateness:
 * @sink: the sink
 * @max_lateness: the new max lateness value.
 *
 * Sets the new max lateness value to @max_lateness. This value is
 * used to decide if a buffer should be dropped or not based on the
 * buffer timestamp and the current clock time. A value of -1 means
 * an unlimited time.
 *
 * Since: 0.10.4
 */
void
gst_base_sink_set_max_lateness (GstBaseSink * sink, gint64 max_lateness)
{
736 737
  g_return_if_fail (GST_IS_BASE_SINK (sink));

738
  GST_OBJECT_LOCK (sink);
Wim Taymans's avatar
Wim Taymans committed
739
  sink->max_lateness = max_lateness;
740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760
  GST_OBJECT_UNLOCK (sink);
}

/**
 * gst_base_sink_get_max_lateness:
 * @sink: the sink
 *
 * Gets the max lateness value. See gst_base_sink_set_max_lateness for
 * more details.
 *
 * Returns: The maximum time in nanoseconds that a buffer can be late
 * before it is dropped and not rendered. A value of -1 means an
 * unlimited time.
 *
 * Since: 0.10.4
 */
gint64
gst_base_sink_get_max_lateness (GstBaseSink * sink)
{
  gint64 res;

761 762
  g_return_val_if_fail (GST_IS_BASE_SINK (sink), -1);

763
  GST_OBJECT_LOCK (sink);
Wim Taymans's avatar
Wim Taymans committed
764
  res = sink->max_lateness;
765 766 767 768 769
  GST_OBJECT_UNLOCK (sink);

  return res;
}

770 771 772
/**
 * gst_base_sink_set_qos_enabled:
 * @sink: the sink
773
 * @enabled: the new qos value.
774
 *
775
 * Configures @sink to send Quality-of-Service events upstream.
776 777 778 779 780 781
 *
 * Since: 0.10.5
 */
void
gst_base_sink_set_qos_enabled (GstBaseSink * sink, gboolean enabled)
{
782 783
  g_return_if_fail (GST_IS_BASE_SINK (sink));

784
  g_atomic_int_set (&sink->priv->qos_enabled, enabled);
785 786 787 788 789 790
}

/**
 * gst_base_sink_is_qos_enabled:
 * @sink: the sink
 *
791
 * Checks if @sink is currently configured to send Quality-of-Service events
792 793
 * upstream.
 *
794
 * Returns: TRUE if the sink is configured to perform Quality-of-Service.
795 796 797 798 799 800 801 802
 *
 * Since: 0.10.5
 */
gboolean
gst_base_sink_is_qos_enabled (GstBaseSink * sink)
{
  gboolean res;

803 804
  g_return_val_if_fail (GST_IS_BASE_SINK (sink), FALSE);

805
  res = g_atomic_int_get (&sink->priv->qos_enabled);
806 807 808 809

  return res;
}

810 811 812 813 814 815
/**
 * gst_base_sink_set_async_enabled:
 * @sink: the sink
 * @enabled: the new async value.
 *
 * Configures @sink to perform all state changes asynchronusly. When async is
Piotr Fusik's avatar
Piotr Fusik committed
816 817
 * disabled, the sink will immediately go to PAUSED instead of waiting for a
 * preroll buffer. This feature is useful if the sink does not synchronize
818 819 820 821 822 823 824 825 826
 * against the clock or when it is dealing with sparse streams.
 *
 * Since: 0.10.15
 */
void
gst_base_sink_set_async_enabled (GstBaseSink * sink, gboolean enabled)
{
  g_return_if_fail (GST_IS_BASE_SINK (sink));

827
  GST_BASE_SINK_PREROLL_LOCK (sink);
828
  g_atomic_int_set (&sink->priv->async_enabled, enabled);
829
  GST_LOG_OBJECT (sink, "set async enabled to %d", enabled);
830
  GST_BASE_SINK_PREROLL_UNLOCK (sink);
831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851
}

/**
 * gst_base_sink_is_async_enabled:
 * @sink: the sink
 *
 * Checks if @sink is currently configured to perform asynchronous state
 * changes to PAUSED.
 *
 * Returns: TRUE if the sink is configured to perform asynchronous state
 * changes.
 *
 * Since: 0.10.15
 */
gboolean
gst_base_sink_is_async_enabled (GstBaseSink * sink)
{
  gboolean res;

  g_return_val_if_fail (GST_IS_BASE_SINK (sink), FALSE);

852
  res = g_atomic_int_get (&sink->priv->async_enabled);
853 854 855 856

  return res;
}

857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875
/**
 * gst_base_sink_set_ts_offset:
 * @sink: the sink
 * @offset: the new offset
 *
 * Adjust the synchronisation of @sink with @offset. A negative value will
 * render buffers earlier than their timestamp. A positive value will delay
 * rendering. This function can be used to fix playback of badly timestamped
 * buffers.
 *
 * Since: 0.10.15
 */
void
gst_base_sink_set_ts_offset (GstBaseSink * sink, GstClockTimeDiff offset)
{
  g_return_if_fail (GST_IS_BASE_SINK (sink));

  GST_OBJECT_LOCK (sink);
  sink->priv->ts_offset = offset;
876
  GST_LOG_OBJECT (sink, "set time offset to %" G_GINT64_FORMAT, offset);
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 902 903
  GST_OBJECT_UNLOCK (sink);
}

/**
 * gst_base_sink_get_ts_offset:
 * @sink: the sink
 *
 * Get the synchronisation offset of @sink.
 *
 * Returns: The synchronisation offset.
 *
 * Since: 0.10.15
 */
GstClockTimeDiff
gst_base_sink_get_ts_offset (GstBaseSink * sink)
{
  GstClockTimeDiff res;

  g_return_val_if_fail (GST_IS_BASE_SINK (sink), 0);

  GST_OBJECT_LOCK (sink);
  res = sink->priv->ts_offset;
  GST_OBJECT_UNLOCK (sink);

  return res;
}

904
/**
905
 * gst_base_sink_get_last_sample:
906 907
 * @sink: the sink
 *
908
 * Get the last sample that arrived in the sink and was used for preroll or for
909 910
 * rendering. This property can be used to generate thumbnails.
 *
911
 * The #GstCaps on the sample can be used to determine the type of the buffer.
Wim Taymans's avatar
Wim Taymans committed
912
 *
913
 * Free-function: gst_sample_unref
914
 *
915
 * Returns: (transfer full): a #GstSample. gst_sample_unref() after usage.
916 917
 *     This function returns NULL when no buffer has arrived in the sink yet
 *     or when the sink is not in PAUSED or PLAYING.
918 919 920
 *
 * Since: 0.10.15
 */
921 922
GstSample *
gst_base_sink_get_last_sample (GstBaseSink * sink)
923
{
924
  GstSample *res = NULL;
925 926 927 928

  g_return_val_if_fail (GST_IS_BASE_SINK (sink), NULL);

  GST_OBJECT_LOCK (sink);
929 930 931 932
  if (sink->priv->last_buffer) {
    res = gst_sample_new (sink->priv->last_buffer,
        sink->priv->last_caps, &sink->segment, NULL);
  }
933 934 935 936 937
  GST_OBJECT_UNLOCK (sink);

  return res;
}

938
/* with OBJECT_LOCK */
939
static void
940
gst_base_sink_set_last_buffer_unlocked (GstBaseSink * sink, GstBuffer * buffer)
941
{
942 943 944
  GstBuffer *old;

  old = sink->priv->last_buffer;
945 946 947 948 949
  if (G_LIKELY (old != buffer)) {
    GST_DEBUG_OBJECT (sink, "setting last buffer to %p", buffer);
    if (G_LIKELY (buffer))
      gst_buffer_ref (buffer);
    sink->priv->last_buffer = buffer;
950 951 952 953 954
    if (buffer)
      /* copy over the caps */
      gst_caps_replace (&sink->priv->last_caps, sink->priv->caps);
    else
      gst_caps_replace (&sink->priv->last_caps, NULL);
955 956 957 958 959
  } else {
    old = NULL;
  }
  /* avoid unreffing with the lock because cleanup code might want to take the
   * lock too */
960 961
  if (G_LIKELY (old)) {
    GST_OBJECT_UNLOCK (sink);
Wim Taymans's avatar