gstclock.c 16.5 KB
Newer Older
1 2 3
/* GStreamer
 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
 *                    2000 Wim Taymans <wtay@chello.be>
4
 *                    2004 Wim Taymans <wim@fluendo.com>
5 6
 *
 * gstclock.c: Clock subsystem for maintaining time sync
Wim Taymans's avatar
Wim Taymans committed
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
 *
 * 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.
 */
23 24 25 26 27 28 29 30 31 32 33 34 35 36
/**
 * SECTION:gstclock
 * @short_description: Abstract class for global clocks
 * @see_also: #GstSystemClock
 *
 * GStreamer uses a global clock to synchronise the plugins in a pipeline.
 * Different clock implementations are possible by implementing this abstract
 * base class.
 *
 * The clock time is always measured in nanoseconds and always increases. The
 * pipeline uses the clock to calculate the stream time.
 * Usually all renderers sync to the global clock so that the clock is always 
 * a good measure of the current playback time in the pipeline.
 */
37
#include <time.h>
38 39

#include "gst_private.h"
40

41
#include "gstclock.h"
42
#include "gstinfo.h"
43
#include "gstmemchunk.h"
44
#include "gstutils.h"
Wim Taymans's avatar
Wim Taymans committed
45

Wim Taymans's avatar
Wim Taymans committed
46
#ifndef GST_DISABLE_TRACE
Wim Taymans's avatar
Wim Taymans committed
47
/* #define GST_WITH_ALLOC_TRACE */
Wim Taymans's avatar
Wim Taymans committed
48 49 50
#include "gsttrace.h"
static GstAllocTrace *_gst_clock_entry_trace;
#endif
Wim Taymans's avatar
Wim Taymans committed
51

52
#define DEFAULT_EVENT_DIFF	(GST_SECOND)
53 54
#define DEFAULT_MAX_DIFF	(2 * GST_SECOND)

55 56
enum
{
57 58
  ARG_0,
  ARG_STATS,
59 60
  ARG_MAX_DIFF,
  ARG_EVENT_DIFF
61 62
};

63 64 65 66
static GstMemChunk *_gst_clock_entries_chunk;

static void gst_clock_class_init (GstClockClass * klass);
static void gst_clock_init (GstClock * clock);
Wim Taymans's avatar
Wim Taymans committed
67
static void gst_clock_finalize (GObject * object);
Wim Taymans's avatar
Wim Taymans committed
68

69 70 71 72 73
static void gst_clock_set_property (GObject * object, guint prop_id,
    const GValue * value, GParamSpec * pspec);
static void gst_clock_get_property (GObject * object, guint prop_id,
    GValue * value, GParamSpec * pspec);
static void gst_clock_update_stats (GstClock * clock);
74

75

76
static GstObjectClass *parent_class = NULL;
77

78 79
/* static guint gst_clock_signals[LAST_SIGNAL] = { 0 }; */

Wim Taymans's avatar
Wim Taymans committed
80
static GstClockID
81 82
gst_clock_entry_new (GstClock * clock, GstClockTime time,
    GstClockTime interval, GstClockEntryType type)
83 84
{
  GstClockEntry *entry;
85

86
  entry = gst_mem_chunk_alloc (_gst_clock_entries_chunk);
Wim Taymans's avatar
Wim Taymans committed
87
#ifndef GST_DISABLE_TRACE
Wim Taymans's avatar
Wim Taymans committed
88
  gst_alloc_trace_new (_gst_clock_entry_trace, entry);
Wim Taymans's avatar
Wim Taymans committed
89
#endif
90 91
  GST_CAT_DEBUG (GST_CAT_CLOCK, "created entry %p, time %" GST_TIME_FORMAT,
      entry, GST_TIME_ARGS (time));
92

93
  gst_atomic_int_set (&entry->refcount, 1);
94 95
  entry->clock = clock;
  entry->time = time;
96
  entry->interval = interval;
97
  entry->type = type;
98
  entry->status = GST_CLOCK_BUSY;
99

100 101
  return (GstClockID) entry;
}
102

103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
/**
 * gst_clock_id_ref:
 * @id: The clockid to ref
 *
 * Increase the refcount of the given clockid.
 *
 * Returns: The same #GstClockID with increased refcount.
 *
 * MT safe.
 */
GstClockID
gst_clock_id_ref (GstClockID id)
{
  g_return_val_if_fail (id != NULL, NULL);

118
  g_atomic_int_inc (&((GstClockEntry *) id)->refcount);
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151

  return id;
}

static void
_gst_clock_id_free (GstClockID id)
{
  g_return_if_fail (id != NULL);

  GST_CAT_DEBUG (GST_CAT_CLOCK, "freed entry %p", id);

#ifndef GST_DISABLE_TRACE
  gst_alloc_trace_free (_gst_clock_entry_trace, id);
#endif
  gst_mem_chunk_free (_gst_clock_entries_chunk, id);
}

/**
 * gst_clock_id_unref:
 * @id: The clockid to unref
 *
 * Unref the given clockid. When the refcount reaches 0 the
 * #GstClockID will be freed.
 *
 * MT safe.
 */
void
gst_clock_id_unref (GstClockID id)
{
  gint zero;

  g_return_if_fail (id != NULL);

152
  zero = g_atomic_int_dec_and_test (&((GstClockEntry *) id)->refcount);
153 154 155 156 157 158
  /* if we ended up with the refcount at zero, free the id */
  if (zero) {
    _gst_clock_id_free (id);
  }
}

159 160 161 162 163
/**
 * gst_clock_new_single_shot_id
 * @clock: The clockid to get a single shot notification from
 * @time: the requested time
 *
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
164
 * Get an ID from the given clock to trigger a single shot
165 166
 * notification at the requested time. The single shot id should be
 * unreffed after usage.
167 168
 *
 * Returns: An id that can be used to request the time notification.
169 170
 *
 * MT safe.
171 172
 */
GstClockID
173
gst_clock_new_single_shot_id (GstClock * clock, GstClockTime time)
174
{
175 176
  g_return_val_if_fail (GST_IS_CLOCK (clock), NULL);

177 178
  return gst_clock_entry_new (clock,
      time, GST_CLOCK_TIME_NONE, GST_CLOCK_ENTRY_SINGLE);
179 180 181
}

/**
Wim Taymans's avatar
Wim Taymans committed
182
 * gst_clock_new_periodic_id
183 184 185 186 187 188
 * @clock: The clockid to get a periodic notification id from
 * @start_time: the requested start time
 * @interval: the requested interval
 *
 * Get an ID from the given clock to trigger a periodic notification.
 * The periodeic notifications will be start at time start_time and
189 190
 * will then be fired with the given interval. The id should be unreffed
 * after usage.
191 192
 *
 * Returns: An id that can be used to request the time notification.
193 194
 *
 * MT safe.
195 196
 */
GstClockID
197 198
gst_clock_new_periodic_id (GstClock * clock, GstClockTime start_time,
    GstClockTime interval)
199
{
200
  g_return_val_if_fail (GST_IS_CLOCK (clock), NULL);
201
  g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (start_time), NULL);
202 203
  g_return_val_if_fail (interval != 0, NULL);

204 205
  return gst_clock_entry_new (clock,
      start_time, interval, GST_CLOCK_ENTRY_PERIODIC);
206 207
}

208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
/**
 * gst_clock_id_compare_func
 * @id1: A clockid
 * @id2: A clockid to compare with
 *
 * Compares the two GstClockID instances. This function can be used
 * as a GCompareFunc when sorting ids.
 *
 * Returns: negative value if a < b; zero if a = b; positive value if a > b
 *
 * MT safe.
 */
gint
gst_clock_id_compare_func (gconstpointer id1, gconstpointer id2)
{
  GstClockEntry *entry1, *entry2;

  entry1 = (GstClockEntry *) id1;
  entry2 = (GstClockEntry *) id2;

  if (GST_CLOCK_ENTRY_TIME (entry1) > GST_CLOCK_ENTRY_TIME (entry2)) {
    return 1;
  }
  if (GST_CLOCK_ENTRY_TIME (entry1) < GST_CLOCK_ENTRY_TIME (entry2)) {
    return -1;
  }

  return entry1 - entry2;
}

238 239 240 241 242 243
/**
 * gst_clock_id_get_time
 * @id: The clockid to query
 *
 * Get the time of the clock ID
 *
244 245 246
 * Returns: the time of the given clock id.
 *
 * MT safe.
247 248 249 250 251 252
 */
GstClockTime
gst_clock_id_get_time (GstClockID id)
{
  g_return_val_if_fail (id != NULL, GST_CLOCK_TIME_NONE);

253
  return GST_CLOCK_ENTRY_TIME ((GstClockEntry *) id);
254 255 256 257 258 259 260 261 262
}


/**
 * gst_clock_id_wait
 * @id: The clockid to wait on
 * @jitter: A pointer that will contain the jitter
 *
 * Perform a blocking wait on the given ID. The jitter arg can be
263
 * NULL.
264 265
 *
 * Returns: the result of the blocking wait.
266 267
 *
 * MT safe.
268 269
 */
GstClockReturn
270
gst_clock_id_wait (GstClockID id, GstClockTimeDiff * jitter)
271 272
{
  GstClockEntry *entry;
273
  GstClock *clock;
274
  GstClockReturn res;
275
  GstClockTime requested;
Wim Taymans's avatar
Wim Taymans committed
276
  GstClockClass *cclass;
277

278
  g_return_val_if_fail (id != NULL, GST_CLOCK_ERROR);
279

280 281
  entry = (GstClockEntry *) id;
  requested = GST_CLOCK_ENTRY_TIME (entry);
282

283 284 285 286 287
  if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (requested)))
    goto invalid_time;

  if (G_UNLIKELY (entry->status == GST_CLOCK_UNSCHEDULED))
    goto unscheduled;
288

289
  clock = GST_CLOCK_ENTRY_CLOCK (entry);
Wim Taymans's avatar
Wim Taymans committed
290
  cclass = GST_CLOCK_GET_CLASS (clock);
291

292
  if (G_LIKELY (cclass->wait)) {
293

294 295 296
    GST_CAT_DEBUG (GST_CAT_CLOCK, "waiting on clock entry %p", id);
    res = cclass->wait (clock, entry);
    GST_CAT_DEBUG (GST_CAT_CLOCK, "done waiting entry %p", id);
297

298
    if (jitter) {
299 300
      GstClockTime now = gst_clock_get_time (clock);

301 302
      *jitter = now - requested;
    }
303 304 305
    if (entry->type == GST_CLOCK_ENTRY_PERIODIC) {
      entry->time += entry->interval;
    }
306 307 308 309

    if (clock->stats) {
      gst_clock_update_stats (clock);
    }
310 311
  } else {
    res = GST_CLOCK_UNSUPPORTED;
312 313
  }
  return res;
314 315 316 317 318 319 320 321 322 323 324 325

  /* ERRORS */
invalid_time:
  {
    GST_CAT_DEBUG (GST_CAT_CLOCK, "invalid time requested, returning _BADTIME");
    return GST_CLOCK_BADTIME;
  }
unscheduled:
  {
    GST_CAT_DEBUG (GST_CAT_CLOCK, "entry was unscheduled return _UNSCHEDULED");
    return GST_CLOCK_UNSCHEDULED;
  }
326 327 328
}

/**
Wim Taymans's avatar
Wim Taymans committed
329 330
 * gst_clock_id_wait_async:
 * @id: a #GstClockID to wait on
331 332 333
 * @func: The callback function 
 * @user_data: User data passed in the calback
 *
Wim Taymans's avatar
Wim Taymans committed
334
 * Register a callback on the given clockid with the given
335 336 337 338
 * function and user_data. When passing an id with an invalid
 * time to this function, the callback will be called immediatly
 * with  a time set to GST_CLOCK_TIME_NONE. The callback will
 * be called when the time of the id has been reached.
339
 *
340
 * Returns: the result of the non blocking wait.
341 342
 *
 * MT safe.
343 344 345
 */
GstClockReturn
gst_clock_id_wait_async (GstClockID id,
346
    GstClockCallback func, gpointer user_data)
347 348 349
{
  GstClockEntry *entry;
  GstClock *clock;
350
  GstClockReturn res;
Wim Taymans's avatar
Wim Taymans committed
351
  GstClockClass *cclass;
352
  GstClockTime requested;
353

354
  g_return_val_if_fail (id != NULL, GST_CLOCK_ERROR);
355
  g_return_val_if_fail (func != NULL, GST_CLOCK_ERROR);
356 357

  entry = (GstClockEntry *) id;
358 359
  requested = GST_CLOCK_ENTRY_TIME (entry);
  clock = GST_CLOCK_ENTRY_CLOCK (entry);
360

361 362 363 364 365
  if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (requested)))
    goto invalid_time;

  if (G_UNLIKELY (entry->status == GST_CLOCK_UNSCHEDULED))
    goto unscheduled;
366

Wim Taymans's avatar
Wim Taymans committed
367 368 369 370 371 372 373
  cclass = GST_CLOCK_GET_CLASS (clock);

  if (cclass->wait_async) {
    entry->func = func;
    entry->user_data = user_data;

    res = cclass->wait_async (clock, entry);
374 375
  } else {
    res = GST_CLOCK_UNSUPPORTED;
376 377 378
  }
  return res;

379 380 381 382 383 384 385 386 387 388 389 390
  /* ERRORS */
invalid_time:
  {
    (func) (clock, GST_CLOCK_TIME_NONE, id, user_data);
    GST_CAT_DEBUG (GST_CAT_CLOCK, "invalid time requested, returning _BADTIME");
    return GST_CLOCK_BADTIME;
  }
unscheduled:
  {
    GST_CAT_DEBUG (GST_CAT_CLOCK, "entry was unscheduled return _UNSCHEDULED");
    return GST_CLOCK_UNSCHEDULED;
  }
391 392
}

393
/**
Wim Taymans's avatar
Wim Taymans committed
394 395
 * gst_clock_id_unschedule:
 * @id: The id to unschedule
396
 *
397 398 399 400 401 402
 * Cancel an outstanding request with the given ID. This can either
 * be an outstanding async notification or a pending sync notification.
 * After this call, the @id cannot be used anymore to receive sync or
 * async notifications, you need to create a new GstClockID.
 *
 * MT safe.
403 404 405 406 407 408
 */
void
gst_clock_id_unschedule (GstClockID id)
{
  GstClockEntry *entry;
  GstClock *clock;
Wim Taymans's avatar
Wim Taymans committed
409
  GstClockClass *cclass;
410

411 412 413 414
  g_return_if_fail (id != NULL);

  entry = (GstClockEntry *) id;
  clock = entry->clock;
415

Wim Taymans's avatar
Wim Taymans committed
416 417 418 419
  cclass = GST_CLOCK_GET_CLASS (clock);

  if (cclass->unschedule)
    cclass->unschedule (clock, entry);
420 421
}

422 423 424 425

/**
 * GstClock abstract base class implementation
 */
426 427
GType
gst_clock_get_type (void)
Wim Taymans's avatar
Wim Taymans committed
428
{
429 430 431 432
  static GType clock_type = 0;

  if (!clock_type) {
    static const GTypeInfo clock_info = {
433
      sizeof (GstClockClass),
434 435 436 437 438
      NULL,
      NULL,
      (GClassInitFunc) gst_clock_class_init,
      NULL,
      NULL,
439
      sizeof (GstClock),
440
      0,
441 442 443
      (GInstanceInitFunc) gst_clock_init,
      NULL
    };
444

445
    clock_type = g_type_register_static (GST_TYPE_OBJECT, "GstClock",
446
        &clock_info, G_TYPE_FLAG_ABSTRACT);
447 448 449
  }
  return clock_type;
}
450

451
static void
452
gst_clock_class_init (GstClockClass * klass)
453 454 455
{
  GObjectClass *gobject_class;
  GstObjectClass *gstobject_class;
456

457 458
  gobject_class = (GObjectClass *) klass;
  gstobject_class = (GstObjectClass *) klass;
459

460
  parent_class = g_type_class_ref (GST_TYPE_OBJECT);
461

Wim Taymans's avatar
Wim Taymans committed
462 463 464
  if (!g_thread_supported ())
    g_thread_init (NULL);

465
  _gst_clock_entries_chunk = gst_mem_chunk_new ("GstClockEntries",
466
      sizeof (GstClockEntry), sizeof (GstClockEntry) * 32, G_ALLOC_AND_FREE);
467

Wim Taymans's avatar
Wim Taymans committed
468
#ifndef GST_DISABLE_TRACE
469 470
  _gst_clock_entry_trace =
      gst_alloc_trace_register (GST_CLOCK_ENTRY_TRACE_NAME);
Wim Taymans's avatar
Wim Taymans committed
471
#endif
472

Wim Taymans's avatar
Wim Taymans committed
473
  gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_clock_finalize);
474 475 476 477
  gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_clock_set_property);
  gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_clock_get_property);

  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_STATS,
478
      g_param_spec_boolean ("stats", "Stats", "Enable clock stats",
479
          FALSE, G_PARAM_READWRITE));
Wim Taymans's avatar
Wim Taymans committed
480 481
}

482
static void
483
gst_clock_init (GstClock * clock)
Wim Taymans's avatar
Wim Taymans committed
484
{
485
  clock->adjust = 0;
486 487
  clock->last_time = 0;
  clock->entries = NULL;
488
  clock->entries_changed = g_cond_new ();
489 490
  clock->flags = 0;
  clock->stats = FALSE;
Wim Taymans's avatar
Wim Taymans committed
491 492
}

Wim Taymans's avatar
Wim Taymans committed
493
static void
Wim Taymans's avatar
Wim Taymans committed
494
gst_clock_finalize (GObject * object)
Wim Taymans's avatar
Wim Taymans committed
495 496 497
{
  GstClock *clock = GST_CLOCK (object);

498
  g_cond_free (clock->entries_changed);
Wim Taymans's avatar
Wim Taymans committed
499

Wim Taymans's avatar
Wim Taymans committed
500
  G_OBJECT_CLASS (parent_class)->finalize (object);
Wim Taymans's avatar
Wim Taymans committed
501 502
}

Wim Taymans's avatar
Wim Taymans committed
503
/**
504 505 506
 * gst_clock_set_resolution
 * @clock: The clock set the resolution on
 * @resolution: The resolution to set
Wim Taymans's avatar
Wim Taymans committed
507
 *
508 509 510
 * Set the accuracy of the clock.
 *
 * Returns: the new resolution of the clock.
Wim Taymans's avatar
Wim Taymans committed
511
 */
512
guint64
513
gst_clock_set_resolution (GstClock * clock, guint64 resolution)
Wim Taymans's avatar
Wim Taymans committed
514
{
Wim Taymans's avatar
Wim Taymans committed
515 516
  GstClockClass *cclass;

Wim Taymans's avatar
Wim Taymans committed
517 518
  g_return_val_if_fail (GST_IS_CLOCK (clock), G_GINT64_CONSTANT (0));
  g_return_val_if_fail (resolution != 0, G_GINT64_CONSTANT (0));
519

Wim Taymans's avatar
Wim Taymans committed
520 521 522
  cclass = GST_CLOCK_GET_CLASS (clock);

  if (cclass->change_resolution)
523
    clock->resolution =
524
        cclass->change_resolution (clock, clock->resolution, resolution);
525

526 527
  return clock->resolution;
}
528

529 530 531 532 533 534 535
/**
 * gst_clock_get_resolution
 * @clock: The clock get the resolution of
 *
 * Get the accuracy of the clock.
 *
 * Returns: the resolution of the clock in microseconds.
536 537
 *
 * MT safe.
538 539
 */
guint64
540
gst_clock_get_resolution (GstClock * clock)
541
{
Wim Taymans's avatar
Wim Taymans committed
542 543
  GstClockClass *cclass;

Wim Taymans's avatar
Wim Taymans committed
544
  g_return_val_if_fail (GST_IS_CLOCK (clock), G_GINT64_CONSTANT (0));
545

Wim Taymans's avatar
Wim Taymans committed
546 547 548 549
  cclass = GST_CLOCK_GET_CLASS (clock);

  if (cclass->get_resolution)
    return cclass->get_resolution (clock);
550

Wim Taymans's avatar
Wim Taymans committed
551
  return G_GINT64_CONSTANT (1);
Wim Taymans's avatar
Wim Taymans committed
552 553
}

Wim Taymans's avatar
Wim Taymans committed
554
/**
555 556 557
 * gst_clock_adjust_unlocked
 * @clock: a #GstClock to use
 * @internal: a clock time
Wim Taymans's avatar
Wim Taymans committed
558
 *
559 560 561
 * Converts the given @internal clock time to the real time, adjusting
 * and making sure that the returned time is increasing.
 * This function should be called with the clock lock held.
Wim Taymans's avatar
Wim Taymans committed
562
 *
563
 * Returns: the converted time of the clock.
564
 *
565
 * MT safe.
566
 */
567 568
GstClockTime
gst_clock_adjust_unlocked (GstClock * clock, GstClockTime internal)
569
{
570
  GstClockTime ret;
571

572 573 574 575 576 577
  ret = internal + clock->adjust;
  /* make sure the time is increasing, else return last_time */
  if ((gint64) ret < (gint64) clock->last_time) {
    ret = clock->last_time;
  } else {
    clock->last_time = ret;
578
  }
579
  return ret;
580 581
}

Wim Taymans's avatar
Wim Taymans committed
582 583
/**
 * gst_clock_get_time
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
584
 * @clock: a #GstClock to query
Wim Taymans's avatar
Wim Taymans committed
585
 *
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
586
 * Gets the current time of the given clock. The time is always
Wim Taymans's avatar
Wim Taymans committed
587
 * monotonically increasing.
588
 *
589 590 591 592
 * Returns: the time of the clock. Or GST_CLOCK_TIME_NONE when
 * giving wrong input.
 *
 * MT safe.
Wim Taymans's avatar
Wim Taymans committed
593
 */
594
GstClockTime
595
gst_clock_get_time (GstClock * clock)
596
{
597
  GstClockTime ret;
598
  GstClockClass *cclass;
599

600
  g_return_val_if_fail (GST_IS_CLOCK (clock), GST_CLOCK_TIME_NONE);
601

602
  cclass = GST_CLOCK_GET_CLASS (clock);
Wim Taymans's avatar
Wim Taymans committed
603

604
  if (cclass->get_internal_time) {
605
    ret = cclass->get_internal_time (clock);
606
  } else {
607
    ret = G_GINT64_CONSTANT (0);
608
  }
609 610
  GST_CAT_DEBUG (GST_CAT_CLOCK, "internal time %" GST_TIME_FORMAT,
      GST_TIME_ARGS (ret));
611

612 613 614
  GST_LOCK (clock);
  ret = gst_clock_adjust_unlocked (clock, ret);
  GST_UNLOCK (clock);
615

616 617
  GST_CAT_DEBUG (GST_CAT_CLOCK, "adjusted time %" GST_TIME_FORMAT,
      GST_TIME_ARGS (ret));
618

619
  return ret;
620 621
}

Wim Taymans's avatar
Wim Taymans committed
622
/**
623 624 625
 * gst_clock_set_time_adjust
 * @clock: a #GstClock to adjust
 * @adjust: the adjust value
Wim Taymans's avatar
Wim Taymans committed
626
 *
627 628 629 630 631
 * Adjusts the current time of the clock with the adjust value.
 * A positive value moves the clock forwards and a backwards value
 * moves it backwards. Note that _get_time() always returns 
 * increasing values so when you move the clock backwards, _get_time()
 * will report the previous value until the clock catches up.
Wim Taymans's avatar
Wim Taymans committed
632
 *
633
 * MT safe.
Wim Taymans's avatar
Wim Taymans committed
634
 */
635 636
void
gst_clock_set_time_adjust (GstClock * clock, GstClockTime adjust)
637
{
638
  g_return_if_fail (GST_IS_CLOCK (clock));
639

640
  GST_LOCK (clock);
641
  clock->adjust = adjust;
642 643 644 645
  GST_UNLOCK (clock);
}

static void
646
gst_clock_update_stats (GstClock * clock)
647
{
648 649
}

650
static void
651 652
gst_clock_set_property (GObject * object, guint prop_id,
    const GValue * value, GParamSpec * pspec)
653
{
654
  GstClock *clock;
655

656 657 658 659 660
  clock = GST_CLOCK (object);

  switch (prop_id) {
    case ARG_STATS:
      clock->stats = g_value_get_boolean (value);
661
      g_object_notify (object, "stats");
662 663 664 665
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
666
  }
Wim Taymans's avatar
Wim Taymans committed
667
}
668

669
static void
670 671
gst_clock_get_property (GObject * object, guint prop_id,
    GValue * value, GParamSpec * pspec)
672
{
673
  GstClock *clock;
674

675 676 677 678 679 680 681 682 683
  clock = GST_CLOCK (object);

  switch (prop_id) {
    case ARG_STATS:
      g_value_set_boolean (value, clock->stats);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
684
  }
685
}