gstbasesink.c 164 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
 *
 * 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
Tim-Philipp Müller's avatar
Tim-Philipp Müller committed
18 19
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
 * Boston, MA 02110-1301, USA.
Wim Taymans's avatar
Wim Taymans committed
20 21
 */

22
/**
Wim Taymans's avatar
Wim Taymans committed
23
 * SECTION:gstbasesink
24
 * @title: GstBaseSink
25
 * @short_description: Base class for sink elements
Stefan Kost's avatar
Stefan Kost committed
26
 * @see_also: #GstBaseTransform, #GstBaseSrc
27
 *
28
 * #GstBaseSink is the base class for sink elements in GStreamer, such as
29
 * xvimagesink or filesink. It is a layer on top of #GstElement that provides a
30 31 32 33 34 35
 * 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
36 37
 * #GstBaseSink infrastructure should be sufficient.
 *
38
 * #GstBaseSink provides support for exactly one sink pad, which should be
39
 * named "sink". A sink implementation (subclass of #GstBaseSink) should
40
 * install a pad template in its class_init function, like so:
41
 * |[<!-- language="C" -->
42
 * static void
43
 * my_element_class_init (GstMyElementClass *klass)
44
 * {
45
 *   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
Wim Taymans's avatar
Wim Taymans committed
46
 *
47
 *   // sinktemplate should be a #GstStaticPadTemplate with direction
48
 *   // %GST_PAD_SINK and name "sink"
49
 *   gst_element_class_add_static_pad_template (gstelement_class, &amp;sinktemplate);
Wim Taymans's avatar
Wim Taymans committed
50 51 52 53 54
 *
 *   gst_element_class_set_static_metadata (gstelement_class,
 *       "Sink name",
 *       "Sink",
 *       "My Sink element",
55
 *       "The author <my.sink@my.email>");
56
 * }
Stefan Kost's avatar
Stefan Kost committed
57
 * ]|
58
 *
59
 * #GstBaseSink will handle the prerolling correctly. This means that it will
60
 * return %GST_STATE_CHANGE_ASYNC from a state change to PAUSED until the first
61
 * buffer arrives in this element. The base class will call the
Stefan Kost's avatar
Stefan Kost committed
62 63
 * #GstBaseSinkClass.preroll() vmethod with this preroll buffer and will then
 * commit the state change to the next asynchronously pending state.
64
 *
65
 * When the element is set to PLAYING, #GstBaseSink will synchronise on the
Stefan Kost's avatar
Stefan Kost committed
66
 * clock using the times returned from #GstBaseSinkClass.get_times(). If this
67
 * function returns %GST_CLOCK_TIME_NONE for the start time, no synchronisation
Stefan Kost's avatar
Stefan Kost committed
68 69
 * will be done. Synchronisation can be disabled entirely by setting the object
 * #GstBaseSink:sync property to %FALSE.
70
 *
Stefan Kost's avatar
Stefan Kost committed
71 72
 * After synchronisation the virtual method #GstBaseSinkClass.render() will be
 * called. Subclasses should minimally implement this method.
73
 *
74 75 76 77 78 79
 * 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.
 * These subclasses can use gst_base_sink_wait_preroll() to perform the
 * blocking wait.
80
 *
81 82
 * 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
83 84 85
 * #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.
86
 *
87
 * #GstBaseSink will internally use the %GST_EVENT_SEGMENT events to schedule
88
 * synchronisation and clipping of buffers. Buffers that fall completely outside
89 90
 * of the current segment are dropped. Buffers that fall partially in the
 * segment are rendered (and prerolled). Subclasses should do any subbuffer
91
 * clipping themselves when needed.
92 93
 *
 * #GstBaseSink will by default report the current playback position in
94
 * %GST_FORMAT_TIME based on the current clock time and segment information.
95
 * If no clock has been set on the element, the query will be forwarded
96
 * upstream.
97
 *
Stefan Kost's avatar
Stefan Kost committed
98 99 100 101
 * 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
102
 * will be called when resources should be allocated. Any
Stefan Kost's avatar
Stefan Kost committed
103 104 105 106 107
 * #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
108
 * received by #GstBaseSink. Normally this method should only be overridden by
Stefan Kost's avatar
Stefan Kost committed
109 110 111 112 113 114 115 116 117 118 119 120
 * 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
121 122
 * timestamp and element base_time) plus the duration is before the current
 * time of the clock.
123
 * If the frame is later than max-lateness, the sink will drop the buffer
124
 * without calling the render method.
Stefan Kost's avatar
Stefan Kost committed
125 126 127
 * 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).
128
 * Subclasses can use gst_base_sink_set_max_lateness() to configure the
129
 * max-lateness value.
130
 *
Stefan Kost's avatar
Stefan Kost committed
131 132 133
 * 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
134
 * gathered and a QOS event is sent upstream with these numbers. This
135 136
 * information can then be used by upstream elements to reduce their processing
 * rate, for example.
137
 *
138 139 140
 * 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.
141 142
 */

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

147 148
#include <gst/gst_private.h>

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

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

155 156
#define GST_FLOW_STEP GST_FLOW_CUSTOM_ERROR

157 158
typedef struct
{
159 160 161 162
  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 */
163
  guint64 position;             /* the position in the stepped data */
164 165 166
  guint64 duration;             /* the duration in time of the skipped data */
  guint64 start;                /* running_time of the start */
  gdouble rate;                 /* rate of skipping */
167
  gdouble start_rate;           /* rate before skipping */
168
  guint64 start_start;          /* start position skipping */
169
  guint64 start_stop;           /* stop position skipping */
170
  gboolean flush;               /* if this was a flushing step */
171 172
  gboolean intermediate;        /* if this is an intermediate step */
  gboolean need_preroll;        /* if we need preroll after this step */
173 174
} GstStepInfo;

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

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

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

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

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

202
  /* running averages go here these are done on running time */
203 204
  GstClockTime avg_pt, avg_in_diff;
  gdouble avg_rate;             /* average with infinite window */
205 206 207 208

  /* number of rendered and dropped frames */
  guint64 rendered;
  guint64 dropped;
209 210 211

  /* latency stuff */
  GstClockTime latency;
212

luz.paz's avatar
luz.paz committed
213 214
  /* if we already committed the state */
  gboolean committed;
215 216
  /* state change to playing ongoing */
  gboolean to_playing;
217 218 219

  /* when we received EOS */
  gboolean received_eos;
220 221 222

  /* when we are prerolled and able to report latency */
  gboolean have_latency;
223 224

  /* the last buffer we prerolled or rendered. Useful for making snapshots */
225
  gint enable_last_sample;      /* atomic */
226
  GstBuffer *last_buffer;
227
  GstCaps *last_caps;
228
  GstBufferList *last_buffer_list;
229

230 231
  /* negotiated caps */
  GstCaps *caps;
232

233
  /* blocksize for pulling */
234
  guint blocksize;
235 236

  gboolean discont;
237 238 239

  /* seqnum of the stream */
  guint32 seqnum;
240 241

  gboolean call_preroll;
242
  gboolean step_unlock;
243

244 245 246
  /* we have a pending and a current step operation */
  GstStepInfo current_step;
  GstStepInfo pending_step;
247 248 249

  /* Cached GstClockID */
  GstClockID cached_clock_id;
250

251 252
  /* for throttling and QoS */
  GstClockTime earliest_in_time;
253
  GstClockTime throttle_time;
254 255 256 257 258 259

  /* for rate control */
  guint64 max_bitrate;
  GstClockTime rc_time;
  GstClockTime rc_next;
  gsize rc_accumulated;
260 261

  gboolean drop_out_of_segment;
262 263
};

264 265
#define DO_RUNNING_AVG(avg,val,size) (((val) + ((size)-1) * (avg)) / (size))

266
/* generic running average, this has a neutral window size */
267 268
#define UPDATE_RUNNING_AVG(avg,val)   DO_RUNNING_AVG(avg,val,8)

269
/* the windows for these running averages are experimentally obtained.
270
 * positive values get averaged more while negative values use a small
271
 * window so we can react faster to badness. */
272 273
#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)
274

275
/* BaseSink properties */
Wim Taymans's avatar
Wim Taymans committed
276

277 278
#define DEFAULT_CAN_ACTIVATE_PULL FALSE /* fixme: enable me */
#define DEFAULT_CAN_ACTIVATE_PUSH TRUE
Wim Taymans's avatar
Wim Taymans committed
279

Wim Taymans's avatar
Wim Taymans committed
280 281 282 283 284 285 286
#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
287
#define DEFAULT_ENABLE_LAST_SAMPLE  TRUE
288
#define DEFAULT_THROTTLE_TIME       0
289
#define DEFAULT_MAX_BITRATE         0
290
#define DEFAULT_DROP_OUT_OF_SEGMENT TRUE
291
#define DEFAULT_PROCESSING_DEADLINE (20 * GST_MSECOND)
292

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

Wim Taymans's avatar
Wim Taymans committed
312
static GstElementClass *parent_class = NULL;
313
static gint private_offset = 0;
Wim Taymans's avatar
Wim Taymans committed
314

315 316 317
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
318 319

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

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

338
    _type = g_type_register_static (GST_TYPE_ELEMENT,
339
        "GstBaseSink", &base_sink_info, G_TYPE_FLAG_ABSTRACT);
340 341 342 343

    private_offset =
        g_type_add_instance_private (_type, sizeof (GstBaseSinkPrivate));

344
    g_once_init_leave (&base_sink_type, _type);
Wim Taymans's avatar
Wim Taymans committed
345
  }
346
  return base_sink_type;
Wim Taymans's avatar
Wim Taymans committed
347
}
Wim Taymans's avatar
Wim Taymans committed
348

349 350 351 352 353 354
static inline GstBaseSinkPrivate *
gst_base_sink_get_instance_private (GstBaseSink * self)
{
  return (G_STRUCT_MEMBER_P (self, private_offset));
}

355
static void gst_base_sink_set_property (GObject * object, guint prop_id,
Wim Taymans's avatar
Wim Taymans committed
356
    const GValue * value, GParamSpec * pspec);
357
static void gst_base_sink_get_property (GObject * object, guint prop_id,
Wim Taymans's avatar
Wim Taymans committed
358 359
    GValue * value, GParamSpec * pspec);

360 361
static gboolean gst_base_sink_send_event (GstElement * element,
    GstEvent * event);
362
static gboolean default_element_query (GstElement * element, GstQuery * query);
363

Wim Taymans's avatar
Wim Taymans committed
364 365 366 367 368 369
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);
370 371
static gboolean gst_base_sink_set_flushing (GstBaseSink * basesink,
    GstPad * pad, gboolean flushing);
372
static gboolean gst_base_sink_default_activate_pull (GstBaseSink * basesink,
373
    gboolean active);
374 375 376 377
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
378

379 380
static GstStateChangeReturn gst_base_sink_change_state (GstElement * element,
    GstStateChange transition);
Wim Taymans's avatar
Wim Taymans committed
381

382 383
static gboolean gst_base_sink_sink_query (GstPad * pad, GstObject * parent,
    GstQuery * query);
384 385 386
static GstFlowReturn gst_base_sink_chain (GstPad * pad, GstObject * parent,
    GstBuffer * buffer);
static GstFlowReturn gst_base_sink_chain_list (GstPad * pad, GstObject * parent,
387 388
    GstBufferList * list);

389
static void gst_base_sink_loop (GstPad * pad);
390
static gboolean gst_base_sink_pad_activate (GstPad * pad, GstObject * parent);
391 392
static gboolean gst_base_sink_pad_activate_mode (GstPad * pad,
    GstObject * parent, GstPadMode mode, gboolean active);
393 394
static gboolean gst_base_sink_default_event (GstBaseSink * basesink,
    GstEvent * event);
395
static GstFlowReturn gst_base_sink_default_wait_event (GstBaseSink * basesink,
396
    GstEvent * event);
397 398
static gboolean gst_base_sink_event (GstPad * pad, GstObject * parent,
    GstEvent * event);
Wim Taymans's avatar
Wim Taymans committed
399

Wim Taymans's avatar
Wim Taymans committed
400 401
static gboolean gst_base_sink_default_query (GstBaseSink * sink,
    GstQuery * query);
402

403
static gboolean gst_base_sink_negotiate_pull (GstBaseSink * basesink);
404 405 406
static GstCaps *gst_base_sink_default_fixate (GstBaseSink * bsink,
    GstCaps * caps);
static GstCaps *gst_base_sink_fixate (GstBaseSink * bsink, GstCaps * caps);
407

408 409
/* check if an object was too late */
static gboolean gst_base_sink_is_too_late (GstBaseSink * basesink,
Wim Taymans's avatar
Wim Taymans committed
410
    GstMiniObject * obj, GstClockTime rstart, GstClockTime rstop,
411
    GstClockReturn status, GstClockTimeDiff jitter, gboolean render);
412

Wim Taymans's avatar
Wim Taymans committed
413
static void
414
gst_base_sink_class_init (GstBaseSinkClass * klass)
Wim Taymans's avatar
Wim Taymans committed
415 416 417 418
{
  GObjectClass *gobject_class;
  GstElementClass *gstelement_class;

419 420
  gobject_class = G_OBJECT_CLASS (klass);
  gstelement_class = GST_ELEMENT_CLASS (klass);
Wim Taymans's avatar
Wim Taymans committed
421

422 423 424
  if (private_offset != 0)
    g_type_class_adjust_private_offset (klass, &private_offset);

425 426 427
  GST_DEBUG_CATEGORY_INIT (gst_base_sink_debug, "basesink", 0,
      "basesink element");

428
  parent_class = g_type_class_peek_parent (klass);
Wim Taymans's avatar
Wim Taymans committed
429

430 431 432
  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
433

434
  g_object_class_install_property (gobject_class, PROP_SYNC,
435
      g_param_spec_boolean ("sync", "Sync", "Sync on the clock", DEFAULT_SYNC,
436
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Wim Taymans's avatar
Wim Taymans committed
437

438
  g_object_class_install_property (gobject_class, PROP_MAX_LATENESS,
439 440 441
      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,
442
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
443

444
  g_object_class_install_property (gobject_class, PROP_QOS,
445 446
      g_param_spec_boolean ("qos", "Qos",
          "Generate Quality-of-Service events upstream", DEFAULT_QOS,
447
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
448
  /**
449
   * GstBaseSink:async:
450
   *
451 452
   * 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.
453 454 455 456 457
   * Use this option when dealing with sparse streams or when synchronisation is
   * not required.
   */
  g_object_class_install_property (gobject_class, PROP_ASYNC,
      g_param_spec_boolean ("async", "Async",
458 459
          "Go asynchronously to PAUSED", DEFAULT_ASYNC,
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
460
  /**
461
   * GstBaseSink:ts-offset:
462 463
   *
   * Controls the final synchronisation, a negative value will render the buffer
Wim Taymans's avatar
Wim Taymans committed
464
   * earlier while a positive value delays playback. This property can be
465 466 467 468 469
   * used to fix synchronisation in bad files.
   */
  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,
470
          DEFAULT_TS_OFFSET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
471 472

  /**
473
   * GstBaseSink:enable-last-sample:
474
   *
475
   * Enable the last-sample property. If %FALSE, basesink doesn't keep a
476
   * reference to the last buffer arrived and the last-sample property is always
477
   * set to %NULL. This can be useful if you need buffers to be released as soon
478 479
   * as possible, eg. if you're using a buffer pool.
   */
480 481 482
  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,
483 484
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));

485
  /**
486
   * GstBaseSink:last-sample:
487 488
   *
   * The last buffer that arrived in the sink and was used for preroll or for
489
   * rendering. This property can be used to generate thumbnails. This property
490
   * can be %NULL when the sink has not yet received a buffer.
491
   */
492 493 494
  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,
495
          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
496
  /**
497
   * GstBaseSink:blocksize:
498 499 500
   *
   * The amount of bytes to pull when operating in pull mode.
   */
501
  /* FIXME 2.0: blocksize property should be int, otherwise min>max.. */
502 503 504 505
  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));
506
  /**
507
   * GstBaseSink:render-delay:
508 509 510 511 512 513 514 515 516
   *
   * 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.
   */
  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));
517
  /**
518
   * GstBaseSink:throttle-time:
519 520 521 522 523 524 525
   *
   * 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.
   */
  g_object_class_install_property (gobject_class, PROP_THROTTLE_TIME,
      g_param_spec_uint64 ("throttle-time", "Throttle time",
526 527 528 529 530 531 532 533 534 535
          "The time to keep between rendered buffers (0 = disabled)", 0,
          G_MAXUINT64, DEFAULT_THROTTLE_TIME,
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
  /**
   * GstBaseSink:max-bitrate:
   *
   * Control the maximum amount of bits that will be rendered per second.
   * Setting this property to a value bigger than 0 will make the sink delay
   * rendering of the buffers when it would exceed to max-bitrate.
   *
536
   * Since: 1.2
537 538 539 540 541 542
   */
  g_object_class_install_property (gobject_class, PROP_MAX_BITRATE,
      g_param_spec_uint64 ("max-bitrate", "Max Bitrate",
          "The maximum bits per second to render (0 = disabled)", 0,
          G_MAXUINT64, DEFAULT_MAX_BITRATE,
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
543 544 545 546 547 548 549 550 551 552 553 554 555 556
  /**
   * GstBaseSink:processing-deadline:
   *
   * Maximum amount of time (in nanoseconds) that the pipeline can take
   * for processing the buffer. This is added to the latency of live
   * pipelines.
   *
   * Since: 1.16
   */
  g_object_class_install_property (gobject_class, PROP_PROCESSING_DEADLINE,
      g_param_spec_uint64 ("processing-deadline", "Processing deadline",
          "Maximum processing deadline in nanoseconds", 0, G_MAXUINT64,
          DEFAULT_PROCESSING_DEADLINE,
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
557

558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575

  /**
   * GstBaseSink::stats:
   *
   * Various #GstBaseSink statistics. This property returns a #GstStructure
   * with name `application/x-gst-base-sink-stats` with the following fields:
   *
   * - "average-rate"  G_TYPE_DOUBLE   average frame rate
   * - "dropped" G_TYPE_UINT64   Number of dropped frames
   * - "rendered" G_TYPE_UINT64   Number of rendered frames
   *
   * Since: 1.18
   */
  g_object_class_install_property (gobject_class, PROP_STATS,
      g_param_spec_boxed ("stats", "Statistics",
          "Sink Statistics", GST_TYPE_STRUCTURE,
          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));

Wim Taymans's avatar
Wim Taymans committed
576
  gstelement_class->change_state =
577
      GST_DEBUG_FUNCPTR (gst_base_sink_change_state);
578
  gstelement_class->send_event = GST_DEBUG_FUNCPTR (gst_base_sink_send_event);
579
  gstelement_class->query = GST_DEBUG_FUNCPTR (default_element_query);
Wim Taymans's avatar
Wim Taymans committed
580

Wim Taymans's avatar
Wim Taymans committed
581 582
  klass->get_caps = GST_DEBUG_FUNCPTR (gst_base_sink_default_get_caps);
  klass->set_caps = GST_DEBUG_FUNCPTR (gst_base_sink_default_set_caps);
583
  klass->fixate = GST_DEBUG_FUNCPTR (gst_base_sink_default_fixate);
584 585
  klass->activate_pull =
      GST_DEBUG_FUNCPTR (gst_base_sink_default_activate_pull);
Wim Taymans's avatar
Wim Taymans committed
586 587
  klass->get_times = GST_DEBUG_FUNCPTR (gst_base_sink_default_get_times);
  klass->query = GST_DEBUG_FUNCPTR (gst_base_sink_default_query);
588
  klass->event = GST_DEBUG_FUNCPTR (gst_base_sink_default_event);
Wim Taymans's avatar
Wim Taymans committed
589
  klass->wait_event = GST_DEBUG_FUNCPTR (gst_base_sink_default_wait_event);
590 591

  /* Registering debug symbols for function pointers */
592
  GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_fixate);
593
  GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_pad_activate);
594
  GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_pad_activate_mode);
595 596 597
  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);
598
  GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_sink_query);
Wim Taymans's avatar
Wim Taymans committed
599 600 601
}

static GstCaps *
602
gst_base_sink_query_caps (GstBaseSink * bsink, GstPad * pad, GstCaps * filter)
Wim Taymans's avatar
Wim Taymans committed
603 604 605
{
  GstBaseSinkClass *bclass;
  GstCaps *caps = NULL;
606
  gboolean fixed;
Wim Taymans's avatar
Wim Taymans committed
607

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
608
  bclass = GST_BASE_SINK_GET_CLASS (bsink);
609
  fixed = GST_PAD_IS_FIXED_CAPS (pad);
Wim Taymans's avatar
Wim Taymans committed
610

Wim Taymans's avatar
Wim Taymans committed
611
  if (fixed || bsink->pad_mode == GST_PAD_MODE_PULL) {
612 613
    /* if we are operating in pull mode or fixed caps, we only accept the
     * currently negotiated caps */
614
    caps = gst_pad_get_current_caps (pad);
615
  }
Wim Taymans's avatar
Wim Taymans committed
616
  if (caps == NULL) {
617
    if (bclass->get_caps)
618
      caps = bclass->get_caps (bsink, filter);
Wim Taymans's avatar
Wim Taymans committed
619

620 621 622 623 624 625 626
    if (caps == NULL) {
      GstPadTemplate *pad_template;

      pad_template =
          gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass),
          "sink");
      if (pad_template != NULL) {
627
        caps = gst_pad_template_get_caps (pad_template);
628 629 630 631 632 633 634 635 636

        if (filter) {
          GstCaps *intersection;

          intersection =
              gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
          gst_caps_unref (caps);
          caps = intersection;
        }
637
      }
Wim Taymans's avatar
Wim Taymans committed
638
    }
Wim Taymans's avatar
Wim Taymans committed
639
  }
Wim Taymans's avatar
Wim Taymans committed
640

Wim Taymans's avatar
Wim Taymans committed
641 642 643
  return caps;
}

644
static GstCaps *
645 646 647
gst_base_sink_default_fixate (GstBaseSink * bsink, GstCaps * caps)
{
  GST_DEBUG_OBJECT (bsink, "using default caps fixate function");
648
  return gst_caps_fixate (caps);
649 650
}

651
static GstCaps *
652
gst_base_sink_fixate (GstBaseSink * bsink, GstCaps * caps)
653 654 655 656 657 658
{
  GstBaseSinkClass *bclass;

  bclass = GST_BASE_SINK_GET_CLASS (bsink);

  if (bclass->fixate)
659 660 661
    caps = bclass->fixate (bsink, caps);

  return caps;
662 663
}

Wim Taymans's avatar
Wim Taymans committed
664
static void
665
gst_base_sink_init (GstBaseSink * basesink, gpointer g_class)
Wim Taymans's avatar
Wim Taymans committed
666
{
Wim Taymans's avatar
Wim Taymans committed
667
  GstPadTemplate *pad_template;
668 669
  GstBaseSinkPrivate *priv;

670
  basesink->priv = priv = gst_base_sink_get_instance_private (basesink);
Wim Taymans's avatar
Wim Taymans committed
671 672 673 674

  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
675

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

678
  gst_pad_set_activate_function (basesink->sinkpad, gst_base_sink_pad_activate);
679 680
  gst_pad_set_activatemode_function (basesink->sinkpad,
      gst_base_sink_pad_activate_mode);
681
  gst_pad_set_query_function (basesink->sinkpad, gst_base_sink_sink_query);
682 683 684
  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);
685
  gst_element_add_pad (GST_ELEMENT_CAST (basesink), basesink->sinkpad);
Wim Taymans's avatar
Wim Taymans committed
686

Wim Taymans's avatar
Wim Taymans committed
687
  basesink->pad_mode = GST_PAD_MODE_NONE;
Wim Taymans's avatar
Wim Taymans committed
688 689
  g_mutex_init (&basesink->preroll_lock);
  g_cond_init (&basesink->preroll_cond);
690
  priv->have_latency = FALSE;
691

692 693 694
  basesink->can_activate_push = DEFAULT_CAN_ACTIVATE_PUSH;
  basesink->can_activate_pull = DEFAULT_CAN_ACTIVATE_PULL;

695
  basesink->sync = DEFAULT_SYNC;
Wim Taymans's avatar
Wim Taymans committed
696
  basesink->max_lateness = DEFAULT_MAX_LATENESS;
697
  g_atomic_int_set (&priv->qos_enabled, DEFAULT_QOS);
698
  priv->async_enabled = DEFAULT_ASYNC;
699
  priv->ts_offset = DEFAULT_TS_OFFSET;
700
  priv->render_delay = DEFAULT_RENDER_DELAY;
701
  priv->processing_deadline = DEFAULT_PROCESSING_DEADLINE;
702
  priv->blocksize = DEFAULT_BLOCKSIZE;
703
  priv->cached_clock_id = NULL;
704
  g_atomic_int_set (&priv->enable_last_sample, DEFAULT_ENABLE_LAST_SAMPLE);
705
  priv->throttle_time = DEFAULT_THROTTLE_TIME;
706
  priv->max_bitrate = DEFAULT_MAX_BITRATE;
707

708 709
  priv->drop_out_of_segment = DEFAULT_DROP_OUT_OF_SEGMENT;

Wim Taymans's avatar
Wim Taymans committed
710
  GST_OBJECT_FLAG_SET (basesink, GST_ELEMENT_FLAG_SINK);
Wim Taymans's avatar
Wim Taymans committed
711 712
}

713
static void
714
gst_base_sink_finalize (GObject * object)
715 716 717
{
  GstBaseSink *basesink;

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
718
  basesink = GST_BASE_SINK (object);
719

Wim Taymans's avatar
Wim Taymans committed
720 721
  g_mutex_clear (&basesink->preroll_lock);
  g_cond_clear (&basesink->preroll_cond);
722 723 724 725

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

726 727 728 729 730 731
/**
 * gst_base_sink_set_sync:
 * @sink: the sink
 * @sync: the new sync value.
 *
 * Configures @sink to synchronize on the clock or not. When
732 733
 * @sync is %FALSE, incoming samples will be played as fast as
 * possible. If @sync is %TRUE, the timestamps of the incoming
734 735 736 737 738 739
 * buffers will be used to schedule the exact render time of its
 * contents.
 */
void
gst_base_sink_set_sync (GstBaseSink * sink, gboolean sync)
{
740 741
  g_return_if_fail (GST_IS_BASE_SINK (sink));

742 743 744 745 746 747 748 749 750 751 752 753
  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.
 *
754
 * Returns: %TRUE if the sink is configured to synchronize against the clock.
755 756 757 758 759 760
 */
gboolean
gst_base_sink_get_sync (GstBaseSink * sink)
{
  gboolean res;

761 762
  g_return_val_if_fail (GST_IS_BASE_SINK (sink), FALSE);

763 764 765 766 767 768 769
  GST_OBJECT_LOCK (sink);
  res = sink->sync;
  GST_OBJECT_UNLOCK (sink);

  return res;
}

770 771 772
/**
 * gst_base_sink_set_drop_out_of_segment:
 * @sink: the sink
773
 * @drop_out_of_segment: drop buffers outside the segment
774
 *
775
 * Configure @sink to drop buffers which are outside the current segment
776 777
 *
 * Since: 1.12
778 779 780 781 782 783 784 785
 */
void
gst_base_sink_set_drop_out_of_segment (GstBaseSink * sink,
    gboolean drop_out_of_segment)
{
  g_return_if_fail (GST_IS_BASE_SINK (sink));

  GST_OBJECT_LOCK (sink);
786
  sink->priv->drop_out_of_segment = drop_out_of_segment;
787 788 789 790 791 792 793 794 795 796 797
  GST_OBJECT_UNLOCK (sink);

}

/**
 * gst_base_sink_get_drop_out_of_segment:
 * @sink: the sink
 *
 * Checks if @sink is currently configured to drop buffers which are outside
 * the current segment
 *
798 799
 * Returns: %TRUE if the sink is configured to drop buffers outside the
 * current segment.
800 801
 *
 * Since: 1.12
802 803 804 805 806 807 808 809 810
 */
gboolean
gst_base_sink_get_drop_out_of_segment (GstBaseSink * sink)
{
  gboolean res;

  g_return_val_if_fail (GST_IS_BASE_SINK (sink), FALSE);

  GST_OBJECT_LOCK (sink);
811
  res = sink->priv->drop_out_of_segment;
812 813 814 815 816
  GST_OBJECT_UNLOCK (sink);

  return res;
}

817 818 819 820 821 822 823 824 825 826 827 828 829
/**
 * 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.
 */
void
gst_base_sink_set_max_lateness (GstBaseSink * sink, gint64 max_lateness)
{
830 831
  g_return_if_fail (GST_IS_BASE_SINK (sink));

832
  GST_OBJECT_LOCK (sink);
Wim Taymans's avatar
Wim Taymans committed
833
  sink->max_lateness = max_lateness;
834 835 836 837 838 839 840
  GST_OBJECT_UNLOCK (sink);
}

/**
 * gst_base_sink_get_max_lateness:
 * @sink: the sink
 *
841
 * Gets the max lateness value. See gst_base_sink_set_max_lateness() for
842 843 844 845 846 847 848 849 850 851 852
 * 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.
 */
gint64
gst_base_sink_get_max_lateness (GstBaseSink * sink)
{
  gint64 res;

853 854
  g_return_val_if_fail (GST_IS_BASE_SINK (sink), -1);

855
  GST_OBJECT_LOCK (sink);
Wim Taymans's avatar
Wim Taymans committed
856
  res = sink->max_lateness;
857 858 859 860 861
  GST_OBJECT_UNLOCK (sink);

  return res;
}

862 863 864
/**
 * gst_base_sink_set_qos_enabled:
 * @sink: the sink
865
 * @enabled: the new qos value.
866
 *
867
 * Configures @sink to send Quality-of-Service events upstream.
868 869 870 871
 */
void
gst_base_sink_set_qos_enabled (GstBaseSink * sink, gboolean enabled)
{
872 873
  g_return_if_fail (GST_IS_BASE_SINK (sink));

874
  g_atomic_int_set (&sink->priv->qos_enabled, enabled);
875 876 877 878 879 880
}

/**
 * gst_base_sink_is_qos_enabled:
 * @sink: the sink
 *
881
 * Checks if @sink is currently configured to send Quality-of-Service events
882 883
 * upstream.
 *
884
 * Returns: %TRUE if the sink is configured to perform Quality-of-Service.
885 886 887 888 889 890
 */
gboolean
gst_base_sink_is_qos_enabled (GstBaseSink * sink)
{
  gboolean res;

891 892
  g_return_val_if_fail (GST_IS_BASE_SINK (sink), FALSE);

893
  res = g_atomic_int_get (&sink->priv->qos_enabled);
894 895 896 897

  return res;
}

898 899 900 901 902
/**
 * gst_base_sink_set_async_enabled:
 * @sink: the sink
 * @enabled: the new async value.
 *
903
 * Configures @sink to perform all state changes asynchronously. When async is
Piotr Fusik's avatar
Piotr Fusik committed
904 905
 * 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
906 907 908 909 910 911 912
 * against the clock or when it is dealing with sparse streams.
 */
void
gst_base_sink_set_async_enabled (GstBaseSink * sink, gboolean enabled)
{
  g_return_if_fail (GST_IS_BASE_SINK (sink));

913
  GST_BASE_SINK_PREROLL_LOCK (sink);
914
  g_atomic_int_set (&sink->priv->async_enabled, enabled);
915
  GST_LOG_OBJECT (sink, "set async enabled to %d", enabled);
916
  GST_BASE_SINK_PREROLL_UNLOCK (sink);
917 918 919 920 921 922 923 924 925
}

/**
 * gst_base_sink_is_async_enabled:
 * @sink: the sink
 *
 * Checks if @sink is currently configured to perform asynchronous state
 * changes to PAUSED.
 *
926
 * Returns: %TRUE if the sink is configured to perform asynchronous state
927 928 929 930 931 932 933 934 935
 * changes.
 */
gboolean
gst_base_sink_is_async_enabled (GstBaseSink * sink)
{
  gboolean res;

  g_return_val_if_fail (GST_IS_BASE_SINK (sink), FALSE);

936
  res = g_atomic_int_get (&sink->priv->async_enabled);
937 938 939 940

  return res;
}

941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957
/**
 * 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.
 */
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;
958
  GST_LOG_OBJECT (sink, "set time offset to %" G_GINT64_FORMAT, offset);
959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983
  GST_OBJECT_UNLOCK (sink);
}

/**
 * gst_base_sink_get_ts_offset:
 * @sink: the sink
 *
 * Get the synchronisation offset of @sink.
 *
 * Returns: The synchronisation offset.
 */
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;
}

984
/**
985
 * gst_base_sink_get_last_sample:
986 987
 * @sink: the sink
 *
988
 * Get the last sample that arrived in the sink and was used for preroll or for
989 990
 * rendering. This property can be used to generate thumbnails.
 *
991
 * The #GstCaps on the sample can be used to determine the type of the buffer.
Wim Taymans's avatar
Wim Taymans committed
992
 *
993
 * Free-function: gst_sample_unref
994
 *
995 996 997
 * Returns: (transfer full) (nullable): a #GstSample. gst_sample_unref() after
 *     usage.  This function returns %NULL when no buffer has arrived in the
 *     sink yet or when the sink is not in PAUSED or PLAYING.
998
 */
999 1000
GstSample *
gst_base_sink_get_last_sample (GstBaseSink * sink)
1001
{
1002
  GstSample *res = NULL;
1003 1004 1005 1006

  g_return_val_if_fail (GST_IS_BASE_SINK (sink), NULL);

  GST_OBJECT_LOCK (sink);
1007 1008 1009 1010