26 * @short_description: Abstract class for global clocks |
26 * @short_description: Abstract class for global clocks |
27 * @see_also: #GstSystemClock, #GstPipeline |
27 * @see_also: #GstSystemClock, #GstPipeline |
28 * |
28 * |
29 * GStreamer uses a global clock to synchronize the plugins in a pipeline. |
29 * GStreamer uses a global clock to synchronize the plugins in a pipeline. |
30 * Different clock implementations are possible by implementing this abstract |
30 * Different clock implementations are possible by implementing this abstract |
31 * base class. |
31 * base class or, more conveniently, by subclassing #GstSystemClock. |
32 * |
32 * |
33 * The #GstClock returns a monotonically increasing time with the method |
33 * The #GstClock returns a monotonically increasing time with the method |
34 * gst_clock_get_time(). Its accuracy and base time depend on the specific |
34 * gst_clock_get_time(). Its accuracy and base time depend on the specific |
35 * clock implementation but time is always expressed in nanoseconds. Since the |
35 * clock implementation but time is always expressed in nanoseconds. Since the |
36 * baseline of the clock is undefined, the clock time returned is not |
36 * baseline of the clock is undefined, the clock time returned is not |
37 * meaningful in itself, what matters are the deltas between two clock times. |
37 * meaningful in itself, what matters are the deltas between two clock times. |
38 * The time returned by a clock is called the absolute time. |
38 * The time returned by a clock is called the absolute time. |
39 * |
39 * |
40 * The pipeline uses the clock to calculate the stream time. Usually all |
40 * The pipeline uses the clock to calculate the running time. Usually all |
41 * renderers synchronize to the global clock using the buffer timestamps, the |
41 * renderers synchronize to the global clock using the buffer timestamps, the |
42 * newsegment events and the element's base time, see #GstPipeline. |
42 * newsegment events and the element's base time, see #GstPipeline. |
43 * |
43 * |
44 * A clock implementation can support periodic and single shot clock |
44 * A clock implementation can support periodic and single shot clock |
45 * notifications both synchronous and asynchronous. |
45 * notifications both synchronous and asynchronous. |
50 * |
50 * |
51 * To perform a blocking wait for the specific time of the #GstClockID use the |
51 * To perform a blocking wait for the specific time of the #GstClockID use the |
52 * gst_clock_id_wait(). To receive a callback when the specific time is reached |
52 * gst_clock_id_wait(). To receive a callback when the specific time is reached |
53 * in the clock use gst_clock_id_wait_async(). Both these calls can be |
53 * in the clock use gst_clock_id_wait_async(). Both these calls can be |
54 * interrupted with the gst_clock_id_unschedule() call. If the blocking wait is |
54 * interrupted with the gst_clock_id_unschedule() call. If the blocking wait is |
55 * unscheduled a return value of GST_CLOCK_UNSCHEDULED is returned. |
55 * unscheduled a return value of #GST_CLOCK_UNSCHEDULED is returned. |
56 * |
56 * |
57 * Periodic callbacks scheduled async will be repeadedly called automatically |
57 * Periodic callbacks scheduled async will be repeatedly called automatically |
58 * until it is unscheduled. To schedule a sync periodic callback, |
58 * until it is unscheduled. To schedule a sync periodic callback, |
59 * gst_clock_id_wait() should be called repeadedly. |
59 * gst_clock_id_wait() should be called repeatedly. |
60 * |
60 * |
61 * The async callbacks can happen from any thread, either provided by the core |
61 * The async callbacks can happen from any thread, either provided by the core |
62 * or from a streaming thread. The application should be prepared for this. |
62 * or from a streaming thread. The application should be prepared for this. |
63 * |
63 * |
64 * A #GstClockID that has been unscheduled cannot be used again for any wait |
64 * A #GstClockID that has been unscheduled cannot be used again for any wait |
65 * operation, a new #GstClockID should be created and the old unscheduled one |
65 * operation, a new #GstClockID should be created and the old unscheduled one |
66 * should be destroyed wirth gst_clock_id_unref(). |
66 * should be destroyed with gst_clock_id_unref(). |
67 * |
67 * |
68 * It is possible to perform a blocking wait on the same #GstClockID from |
68 * It is possible to perform a blocking wait on the same #GstClockID from |
69 * multiple threads. However, registering the same #GstClockID for multiple |
69 * multiple threads. However, registering the same #GstClockID for multiple |
70 * async notifications is not possible, the callback will only be called for |
70 * async notifications is not possible, the callback will only be called for |
71 * the thread registering the entry last. |
71 * the thread registering the entry last. |
75 * notifications. The reason being that the owner of the #GstClockID has to |
75 * notifications. The reason being that the owner of the #GstClockID has to |
76 * keep a handle to the #GstClockID to unblock the wait on FLUSHING events or |
76 * keep a handle to the #GstClockID to unblock the wait on FLUSHING events or |
77 * state changes and if the entry would be unreffed automatically, the handle |
77 * state changes and if the entry would be unreffed automatically, the handle |
78 * might become invalid without any notification. |
78 * might become invalid without any notification. |
79 * |
79 * |
80 * These clock operations do not operate on the stream time, so the callbacks |
80 * These clock operations do not operate on the running time, so the callbacks |
81 * will also occur when not in PLAYING state as if the clock just keeps on |
81 * will also occur when not in PLAYING state as if the clock just keeps on |
82 * running. Some clocks however do not progress when the element that provided |
82 * running. Some clocks however do not progress when the element that provided |
83 * the clock is not PLAYING. |
83 * the clock is not PLAYING. |
84 * |
84 * |
85 * When a clock has the GST_CLOCK_FLAG_CAN_SET_MASTER flag set, it can be |
85 * When a clock has the #GST_CLOCK_FLAG_CAN_SET_MASTER flag set, it can be |
86 * slaved to another #GstClock with the gst_clock_set_master(). The clock will |
86 * slaved to another #GstClock with the gst_clock_set_master(). The clock will |
87 * then automatically be synchronized to this master clock by repeadedly |
87 * then automatically be synchronized to this master clock by repeatedly |
88 * sampling the master clock and the slave clock and recalibrating the slave |
88 * sampling the master clock and the slave clock and recalibrating the slave |
89 * clock with gst_clock_set_calibration(). This feature is mostly useful for |
89 * clock with gst_clock_set_calibration(). This feature is mostly useful for |
90 * plugins that have an internal clock but must operate with another clock |
90 * plugins that have an internal clock but must operate with another clock |
91 * selected by the #GstPipeline. They can track the offset and rate difference |
91 * selected by the #GstPipeline. They can track the offset and rate difference |
92 * of their internal clock relative to the master clock by using the |
92 * of their internal clock relative to the master clock by using the |
93 * gst_clock_get_calibration() function. |
93 * gst_clock_get_calibration() function. |
94 * |
94 * |
95 * The master/slave synchronisation can be tuned with the "timeout", "window-size" |
95 * The master/slave synchronisation can be tuned with the #GstClock:timeout, |
96 * and "window-threshold" properties. The "timeout" property defines the interval |
96 * #GstClock:window-size and #GstClock:window-threshold properties. |
97 * to sample the master clock and run the calibration functions. |
97 * The #GstClock:timeout property defines the interval to sample the master |
98 * "window-size" defines the number of samples to use when calibrating and |
98 * clock and run the calibration functions. #GstClock:window-size defines the |
99 * "window-threshold" defines the minimum number of samples before the |
99 * number of samples to use when calibrating and #GstClock:window-threshold |
100 * calibration is performed. |
100 * defines the minimum number of samples before the calibration is performed. |
101 * |
101 * |
102 * Last reviewed on 2006-08-11 (0.10.10) |
102 * Last reviewed on 2009-05-21 (0.10.24) |
103 */ |
103 */ |
104 |
104 |
105 |
105 |
106 #include "gst_private.h" |
106 #include "gst_private.h" |
107 #include <time.h> |
107 #include <time.h> |
142 PROP_WINDOW_SIZE, |
133 PROP_WINDOW_SIZE, |
143 PROP_WINDOW_THRESHOLD, |
134 PROP_WINDOW_THRESHOLD, |
144 PROP_TIMEOUT |
135 PROP_TIMEOUT |
145 }; |
136 }; |
146 |
137 |
|
138 struct _GstClockPrivate |
|
139 { |
|
140 gint pre_count; |
|
141 gint post_count; |
|
142 }; |
|
143 |
|
144 /* seqlocks */ |
|
145 #define read_seqbegin(clock) \ |
|
146 g_atomic_int_get (&clock->ABI.priv->post_count); |
|
147 |
|
148 static inline gboolean |
|
149 read_seqretry (GstClock * clock, gint seq) |
|
150 { |
|
151 /* no retry if the seqnum did not change */ |
|
152 if (G_LIKELY (seq == g_atomic_int_get (&clock->ABI.priv->pre_count))) |
|
153 return FALSE; |
|
154 |
|
155 /* wait for the writer to finish and retry */ |
|
156 GST_OBJECT_LOCK (clock); |
|
157 GST_OBJECT_UNLOCK (clock); |
|
158 return TRUE; |
|
159 } |
|
160 |
|
161 #define write_seqlock(clock) \ |
|
162 G_STMT_START { \ |
|
163 GST_OBJECT_LOCK (clock); \ |
|
164 g_atomic_int_inc (&clock->ABI.priv->pre_count); \ |
|
165 } G_STMT_END; |
|
166 |
|
167 #define write_sequnlock(clock) \ |
|
168 G_STMT_START { \ |
|
169 g_atomic_int_inc (&clock->ABI.priv->post_count); \ |
|
170 GST_OBJECT_UNLOCK (clock); \ |
|
171 } G_STMT_END; |
|
172 |
147 static void gst_clock_class_init (GstClockClass * klass); |
173 static void gst_clock_class_init (GstClockClass * klass); |
148 static void gst_clock_init (GstClock * clock); |
174 static void gst_clock_init (GstClock * clock); |
149 static void gst_clock_dispose (GObject * object); |
175 static void gst_clock_dispose (GObject * object); |
150 static void gst_clock_finalize (GObject * object); |
176 static void gst_clock_finalize (GObject * object); |
151 |
177 |
164 gst_clock_entry_new (GstClock * clock, GstClockTime time, |
190 gst_clock_entry_new (GstClock * clock, GstClockTime time, |
165 GstClockTime interval, GstClockEntryType type) |
191 GstClockTime interval, GstClockEntryType type) |
166 { |
192 { |
167 GstClockEntry *entry; |
193 GstClockEntry *entry; |
168 |
194 |
169 entry = ALLOC_ENTRY (); |
195 entry = g_slice_new (GstClockEntry); |
170 #ifndef GST_DISABLE_TRACE |
196 #ifndef GST_DISABLE_TRACE |
171 gst_alloc_trace_new (_gst_clock_entry_trace, entry); |
197 gst_alloc_trace_new (_gst_clock_entry_trace, entry); |
172 #endif |
198 #endif |
173 GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, |
199 GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, |
174 "created entry %p, time %" GST_TIME_FORMAT, entry, GST_TIME_ARGS (time)); |
200 "created entry %p, time %" GST_TIME_FORMAT, entry, GST_TIME_ARGS (time)); |
175 |
201 |
176 gst_atomic_int_set (&entry->refcount, 1); |
202 entry->refcount = 1; |
177 entry->clock = clock; |
203 entry->clock = clock; |
178 entry->type = type; |
204 entry->type = type; |
179 entry->time = time; |
205 entry->time = time; |
180 entry->interval = interval; |
206 entry->interval = interval; |
181 entry->status = GST_CLOCK_BUSY; |
207 entry->status = GST_CLOCK_OK; |
182 entry->func = NULL; |
208 entry->func = NULL; |
183 entry->user_data = NULL; |
209 entry->user_data = NULL; |
184 |
210 |
185 return (GstClockID) entry; |
211 return (GstClockID) entry; |
186 } |
212 } |
363 } |
389 } |
364 |
390 |
365 /** |
391 /** |
366 * gst_clock_id_wait |
392 * gst_clock_id_wait |
367 * @id: The #GstClockID to wait on |
393 * @id: The #GstClockID to wait on |
368 * @jitter: A pointer that will contain the jitter, can be NULL. |
394 * @jitter: A pointer that will contain the jitter, can be %NULL. |
369 * |
395 * |
370 * Perform a blocking wait on @id. |
396 * Perform a blocking wait on @id. |
371 * @id should have been created with gst_clock_new_single_shot_id() |
397 * @id should have been created with gst_clock_new_single_shot_id() |
372 * or gst_clock_new_periodic_id() and should not have been unscheduled |
398 * or gst_clock_new_periodic_id() and should not have been unscheduled |
373 * with a call to gst_clock_id_unschedule(). |
399 * with a call to gst_clock_id_unschedule(). |
374 * |
400 * |
375 * If the @jitter argument is not NULL and this function returns #GST_CLOCK_OK |
401 * If the @jitter argument is not %NULL and this function returns #GST_CLOCK_OK |
376 * or #GST_CLOCK_EARLY, it will contain the difference |
402 * or #GST_CLOCK_EARLY, it will contain the difference |
377 * against the clock and the time of @id when this method was |
403 * against the clock and the time of @id when this method was |
378 * called. |
404 * called. |
379 * Positive values indicate how late @id was relative to the clock |
405 * Positive values indicate how late @id was relative to the clock |
380 * (in which case this function will return #GST_CLOCK_EARLY). |
406 * (in which case this function will return #GST_CLOCK_EARLY). |
458 { |
480 { |
459 GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, |
481 GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, |
460 "invalid time requested, returning _BADTIME"); |
482 "invalid time requested, returning _BADTIME"); |
461 return GST_CLOCK_BADTIME; |
483 return GST_CLOCK_BADTIME; |
462 } |
484 } |
463 unscheduled: |
|
464 { |
|
465 GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, |
|
466 "entry was unscheduled return _UNSCHEDULED"); |
|
467 return GST_CLOCK_UNSCHEDULED; |
|
468 } |
|
469 not_supported: |
485 not_supported: |
470 { |
486 { |
471 GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "clock wait is not supported"); |
487 GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "clock wait is not supported"); |
472 return GST_CLOCK_UNSUPPORTED; |
488 return GST_CLOCK_UNSUPPORTED; |
473 } |
489 } |
475 |
491 |
476 /** |
492 /** |
477 * gst_clock_id_wait_async: |
493 * gst_clock_id_wait_async: |
478 * @id: a #GstClockID to wait on |
494 * @id: a #GstClockID to wait on |
479 * @func: The callback function |
495 * @func: The callback function |
480 * @user_data: User data passed in the calback |
496 * @user_data: User data passed in the callback |
481 * |
497 * |
482 * Register a callback on the given #GstClockID @id with the given |
498 * Register a callback on the given #GstClockID @id with the given |
483 * function and user_data. When passing a #GstClockID with an invalid |
499 * function and user_data. When passing a #GstClockID with an invalid |
484 * time to this function, the callback will be called immediatly |
500 * time to this function, the callback will be called immediately |
485 * with a time set to GST_CLOCK_TIME_NONE. The callback will |
501 * with a time set to GST_CLOCK_TIME_NONE. The callback will |
486 * be called when the time of @id has been reached. |
502 * be called when the time of @id has been reached. |
|
503 * |
|
504 * The callback @func can be invoked from any thread, either provided by the |
|
505 * core or from a streaming thread. The application should be prepared for this. |
487 * |
506 * |
488 * Returns: the result of the non blocking wait. |
507 * Returns: the result of the non blocking wait. |
489 * |
508 * |
490 * MT safe. |
509 * MT safe. |
491 */ |
510 */ |
536 (func) (clock, GST_CLOCK_TIME_NONE, id, user_data); |
551 (func) (clock, GST_CLOCK_TIME_NONE, id, user_data); |
537 GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, |
552 GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, |
538 "invalid time requested, returning _BADTIME"); |
553 "invalid time requested, returning _BADTIME"); |
539 return GST_CLOCK_BADTIME; |
554 return GST_CLOCK_BADTIME; |
540 } |
555 } |
541 unscheduled: |
|
542 { |
|
543 GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, |
|
544 "entry was unscheduled return _UNSCHEDULED"); |
|
545 return GST_CLOCK_UNSCHEDULED; |
|
546 } |
|
547 not_supported: |
556 not_supported: |
548 { |
557 { |
549 GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "clock wait is not supported"); |
558 GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "clock wait is not supported"); |
550 return GST_CLOCK_UNSUPPORTED; |
559 return GST_CLOCK_UNSUPPORTED; |
551 } |
560 } |
583 if (G_LIKELY (cclass->unschedule)) |
592 if (G_LIKELY (cclass->unschedule)) |
584 cclass->unschedule (clock, entry); |
593 cclass->unschedule (clock, entry); |
585 } |
594 } |
586 |
595 |
587 |
596 |
588 /** |
597 /* |
589 * GstClock abstract base class implementation |
598 * GstClock abstract base class implementation |
590 */ |
599 */ |
591 #ifdef __SYMBIAN32__ |
600 G_DEFINE_TYPE (GstClock, gst_clock, GST_TYPE_OBJECT); |
592 EXPORT_C |
|
593 #endif |
|
594 |
|
595 GType |
|
596 gst_clock_get_type (void) |
|
597 { |
|
598 static GType clock_type = 0; |
|
599 |
|
600 if (G_UNLIKELY (clock_type == 0)) { |
|
601 static const GTypeInfo clock_info = { |
|
602 sizeof (GstClockClass), |
|
603 NULL, |
|
604 NULL, |
|
605 (GClassInitFunc) gst_clock_class_init, |
|
606 NULL, |
|
607 NULL, |
|
608 sizeof (GstClock), |
|
609 0, |
|
610 (GInstanceInitFunc) gst_clock_init, |
|
611 NULL |
|
612 }; |
|
613 |
|
614 clock_type = g_type_register_static (GST_TYPE_OBJECT, "GstClock", |
|
615 &clock_info, G_TYPE_FLAG_ABSTRACT); |
|
616 } |
|
617 return clock_type; |
|
618 } |
|
619 |
601 |
620 static void |
602 static void |
621 gst_clock_class_init (GstClockClass * klass) |
603 gst_clock_class_init (GstClockClass * klass) |
622 { |
604 { |
623 GObjectClass *gobject_class; |
605 GObjectClass *gobject_class = G_OBJECT_CLASS (klass); |
624 GstObjectClass *gstobject_class; |
|
625 |
|
626 gobject_class = G_OBJECT_CLASS (klass); |
|
627 gstobject_class = GST_OBJECT_CLASS (klass); |
|
628 |
606 |
629 parent_class = g_type_class_peek_parent (klass); |
607 parent_class = g_type_class_peek_parent (klass); |
630 |
|
631 if (!g_thread_supported ()) |
|
632 g_thread_init (NULL); |
|
633 |
608 |
634 #ifndef GST_DISABLE_TRACE |
609 #ifndef GST_DISABLE_TRACE |
635 _gst_clock_entry_trace = |
610 _gst_clock_entry_trace = |
636 gst_alloc_trace_register (GST_CLOCK_ENTRY_TRACE_NAME); |
611 gst_alloc_trace_register (GST_CLOCK_ENTRY_TRACE_NAME); |
637 #endif |
612 #endif |
642 gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_clock_get_property); |
617 gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_clock_get_property); |
643 |
618 |
644 g_object_class_install_property (gobject_class, PROP_STATS, |
619 g_object_class_install_property (gobject_class, PROP_STATS, |
645 g_param_spec_boolean ("stats", "Stats", |
620 g_param_spec_boolean ("stats", "Stats", |
646 "Enable clock stats (unimplemented)", DEFAULT_STATS, |
621 "Enable clock stats (unimplemented)", DEFAULT_STATS, |
647 G_PARAM_READWRITE)); |
622 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
648 g_object_class_install_property (gobject_class, PROP_WINDOW_SIZE, |
623 g_object_class_install_property (gobject_class, PROP_WINDOW_SIZE, |
649 g_param_spec_int ("window-size", "Window size", |
624 g_param_spec_int ("window-size", "Window size", |
650 "The size of the window used to calculate rate and offset", 2, 1024, |
625 "The size of the window used to calculate rate and offset", 2, 1024, |
651 DEFAULT_WINDOW_SIZE, G_PARAM_READWRITE)); |
626 DEFAULT_WINDOW_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
652 g_object_class_install_property (gobject_class, PROP_WINDOW_THRESHOLD, |
627 g_object_class_install_property (gobject_class, PROP_WINDOW_THRESHOLD, |
653 g_param_spec_int ("window-threshold", "Window threshold", |
628 g_param_spec_int ("window-threshold", "Window threshold", |
654 "The threshold to start calculating rate and offset", 2, 1024, |
629 "The threshold to start calculating rate and offset", 2, 1024, |
655 DEFAULT_WINDOW_THRESHOLD, G_PARAM_READWRITE)); |
630 DEFAULT_WINDOW_THRESHOLD, |
|
631 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
656 g_object_class_install_property (gobject_class, PROP_TIMEOUT, |
632 g_object_class_install_property (gobject_class, PROP_TIMEOUT, |
657 g_param_spec_uint64 ("timeout", "Timeout", |
633 g_param_spec_uint64 ("timeout", "Timeout", |
658 "The amount of time, in nanoseconds, to sample master and slave clocks", |
634 "The amount of time, in nanoseconds, to sample master and slave clocks", |
659 0, G_MAXUINT64, DEFAULT_TIMEOUT, G_PARAM_READWRITE)); |
635 0, G_MAXUINT64, DEFAULT_TIMEOUT, |
|
636 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
|
637 |
|
638 g_type_class_add_private (klass, sizeof (GstClockPrivate)); |
660 } |
639 } |
661 |
640 |
662 static void |
641 static void |
663 gst_clock_init (GstClock * clock) |
642 gst_clock_init (GstClock * clock) |
664 { |
643 { |
665 clock->last_time = 0; |
644 clock->last_time = 0; |
666 clock->entries = NULL; |
645 clock->entries = NULL; |
667 clock->entries_changed = g_cond_new (); |
646 clock->entries_changed = g_cond_new (); |
668 clock->stats = FALSE; |
647 clock->stats = FALSE; |
|
648 |
|
649 clock->ABI.priv = |
|
650 G_TYPE_INSTANCE_GET_PRIVATE (clock, GST_TYPE_CLOCK, GstClockPrivate); |
669 |
651 |
670 clock->internal_calibration = 0; |
652 clock->internal_calibration = 0; |
671 clock->external_calibration = 0; |
653 clock->external_calibration = 0; |
672 clock->rate_numerator = 1; |
654 clock->rate_numerator = 1; |
673 clock->rate_denominator = 1; |
655 clock->rate_denominator = 1; |
808 cexternal = clock->external_calibration; |
790 cexternal = clock->external_calibration; |
809 cnum = clock->rate_numerator; |
791 cnum = clock->rate_numerator; |
810 cdenom = clock->rate_denominator; |
792 cdenom = clock->rate_denominator; |
811 |
793 |
812 /* avoid divide by 0 */ |
794 /* avoid divide by 0 */ |
813 if (cdenom == 0) |
795 if (G_UNLIKELY (cdenom == 0)) |
814 cnum = cdenom = 1; |
796 cnum = cdenom = 1; |
815 |
797 |
816 /* The formula is (internal - cinternal) * cnum / cdenom + cexternal |
798 /* The formula is (internal - cinternal) * cnum / cdenom + cexternal |
817 * |
799 * |
818 * Since we do math on unsigned 64-bit ints we have to special case for |
800 * Since we do math on unsigned 64-bit ints we have to special case for |
819 * interal < cinternal to get the sign right. this case is not very common, |
801 * internal < cinternal to get the sign right. this case is not very common, |
820 * though. |
802 * though. |
821 */ |
803 */ |
822 if (G_LIKELY (internal >= cinternal)) { |
804 if (G_LIKELY (internal >= cinternal)) { |
823 ret = gst_util_uint64_scale (internal - cinternal, cnum, cdenom); |
805 ret = internal - cinternal; |
|
806 ret = gst_util_uint64_scale (ret, cnum, cdenom); |
824 ret += cexternal; |
807 ret += cexternal; |
825 } else { |
808 } else { |
826 ret = gst_util_uint64_scale (cinternal - internal, cnum, cdenom); |
809 ret = cinternal - internal; |
|
810 ret = gst_util_uint64_scale (ret, cnum, cdenom); |
827 /* clamp to 0 */ |
811 /* clamp to 0 */ |
828 if (cexternal > ret) |
812 if (G_LIKELY (cexternal > ret)) |
829 ret = cexternal - ret; |
813 ret = cexternal - ret; |
830 else |
814 else |
831 ret = 0; |
815 ret = 0; |
832 } |
816 } |
833 |
817 |
867 cexternal = clock->external_calibration; |
851 cexternal = clock->external_calibration; |
868 cnum = clock->rate_numerator; |
852 cnum = clock->rate_numerator; |
869 cdenom = clock->rate_denominator; |
853 cdenom = clock->rate_denominator; |
870 |
854 |
871 /* avoid divide by 0 */ |
855 /* avoid divide by 0 */ |
872 if (cnum == 0) |
856 if (G_UNLIKELY (cnum == 0)) |
873 cnum = cdenom = 1; |
857 cnum = cdenom = 1; |
874 |
858 |
875 /* The formula is (external - cexternal) * cdenom / cnum + cinternal */ |
859 /* The formula is (external - cexternal) * cdenom / cnum + cinternal */ |
876 if (external >= cexternal) { |
860 if (G_LIKELY (external >= cexternal)) { |
877 ret = gst_util_uint64_scale (external - cexternal, cdenom, cnum); |
861 ret = external - cexternal; |
|
862 ret = gst_util_uint64_scale (ret, cdenom, cnum); |
878 ret += cinternal; |
863 ret += cinternal; |
879 } else { |
864 } else { |
880 ret = gst_util_uint64_scale (cexternal - external, cdenom, cnum); |
865 ret = cexternal - external; |
881 if (cinternal > ret) |
866 ret = gst_util_uint64_scale (ret, cdenom, cnum); |
|
867 if (G_LIKELY (cinternal > ret)) |
882 ret = cinternal - ret; |
868 ret = cinternal - ret; |
883 else |
869 else |
884 ret = 0; |
870 ret = 0; |
885 } |
871 } |
886 return ret; |
872 return ret; |
950 |
936 |
951 GstClockTime |
937 GstClockTime |
952 gst_clock_get_time (GstClock * clock) |
938 gst_clock_get_time (GstClock * clock) |
953 { |
939 { |
954 GstClockTime ret; |
940 GstClockTime ret; |
|
941 gint seq; |
955 |
942 |
956 g_return_val_if_fail (GST_IS_CLOCK (clock), GST_CLOCK_TIME_NONE); |
943 g_return_val_if_fail (GST_IS_CLOCK (clock), GST_CLOCK_TIME_NONE); |
957 |
944 |
958 ret = gst_clock_get_internal_time (clock); |
945 do { |
959 |
946 /* reget the internal time when we retry to get the most current |
960 GST_OBJECT_LOCK (clock); |
947 * timevalue */ |
961 /* this will scale for rate and offset */ |
948 ret = gst_clock_get_internal_time (clock); |
962 ret = gst_clock_adjust_unlocked (clock, ret); |
949 |
963 GST_OBJECT_UNLOCK (clock); |
950 seq = read_seqbegin (clock); |
|
951 /* this will scale for rate and offset */ |
|
952 ret = gst_clock_adjust_unlocked (clock, ret); |
|
953 } while (read_seqretry (clock, seq)); |
964 |
954 |
965 GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "adjusted time %" GST_TIME_FORMAT, |
955 GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "adjusted time %" GST_TIME_FORMAT, |
966 GST_TIME_ARGS (ret)); |
956 GST_TIME_ARGS (ret)); |
967 |
957 |
968 return ret; |
958 return ret; |
1008 void |
998 void |
1009 gst_clock_set_calibration (GstClock * clock, GstClockTime internal, GstClockTime |
999 gst_clock_set_calibration (GstClock * clock, GstClockTime internal, GstClockTime |
1010 external, GstClockTime rate_num, GstClockTime rate_denom) |
1000 external, GstClockTime rate_num, GstClockTime rate_denom) |
1011 { |
1001 { |
1012 g_return_if_fail (GST_IS_CLOCK (clock)); |
1002 g_return_if_fail (GST_IS_CLOCK (clock)); |
1013 g_return_if_fail (rate_num >= 0); |
1003 g_return_if_fail (rate_num != GST_CLOCK_TIME_NONE); |
1014 g_return_if_fail (rate_denom > 0); |
1004 g_return_if_fail (rate_denom > 0 && rate_denom != GST_CLOCK_TIME_NONE); |
1015 g_return_if_fail (internal <= gst_clock_get_internal_time (clock)); |
1005 |
1016 |
1006 write_seqlock (clock); |
1017 GST_OBJECT_LOCK (clock); |
|
1018 GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, |
1007 GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, |
1019 "internal %" GST_TIME_FORMAT " external %" GST_TIME_FORMAT " %" |
1008 "internal %" GST_TIME_FORMAT " external %" GST_TIME_FORMAT " %" |
1020 G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT " = %f", GST_TIME_ARGS (internal), |
1009 G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT " = %f", GST_TIME_ARGS (internal), |
1021 GST_TIME_ARGS (external), rate_num, rate_denom, |
1010 GST_TIME_ARGS (external), rate_num, rate_denom, |
1022 gst_guint64_to_gdouble (rate_num / rate_denom)); |
1011 gst_guint64_to_gdouble (rate_num) / gst_guint64_to_gdouble (rate_denom)); |
1023 |
1012 |
1024 clock->internal_calibration = internal; |
1013 clock->internal_calibration = internal; |
1025 clock->external_calibration = external; |
1014 clock->external_calibration = external; |
1026 clock->rate_numerator = rate_num; |
1015 clock->rate_numerator = rate_num; |
1027 clock->rate_denominator = rate_denom; |
1016 clock->rate_denominator = rate_denom; |
1028 GST_OBJECT_UNLOCK (clock); |
1017 write_sequnlock (clock); |
1029 } |
1018 } |
1030 |
1019 |
1031 /** |
1020 /** |
1032 * gst_clock_get_calibration |
1021 * gst_clock_get_calibration |
1033 * @clock: a #GstClock |
1022 * @clock: a #GstClock |
1050 |
1039 |
1051 void |
1040 void |
1052 gst_clock_get_calibration (GstClock * clock, GstClockTime * internal, |
1041 gst_clock_get_calibration (GstClock * clock, GstClockTime * internal, |
1053 GstClockTime * external, GstClockTime * rate_num, GstClockTime * rate_denom) |
1042 GstClockTime * external, GstClockTime * rate_num, GstClockTime * rate_denom) |
1054 { |
1043 { |
|
1044 gint seq; |
|
1045 |
1055 g_return_if_fail (GST_IS_CLOCK (clock)); |
1046 g_return_if_fail (GST_IS_CLOCK (clock)); |
1056 |
1047 |
1057 GST_OBJECT_LOCK (clock); |
1048 do { |
1058 if (rate_num) |
1049 seq = read_seqbegin (clock); |
1059 *rate_num = clock->rate_numerator; |
1050 if (rate_num) |
1060 if (rate_denom) |
1051 *rate_num = clock->rate_numerator; |
1061 *rate_denom = clock->rate_denominator; |
1052 if (rate_denom) |
1062 if (external) |
1053 *rate_denom = clock->rate_denominator; |
1063 *external = clock->external_calibration; |
1054 if (external) |
1064 if (internal) |
1055 *external = clock->external_calibration; |
1065 *internal = clock->internal_calibration; |
1056 if (internal) |
1066 GST_OBJECT_UNLOCK (clock); |
1057 *internal = clock->internal_calibration; |
1067 } |
1058 } while (read_seqretry (clock, seq)); |
1068 |
1059 } |
1069 /* will be called repeadedly to sample the master and slave clock |
1060 |
|
1061 /* will be called repeatedly to sample the master and slave clock |
1070 * to recalibrate the clock */ |
1062 * to recalibrate the clock */ |
1071 static gboolean |
1063 static gboolean |
1072 gst_clock_slave_callback (GstClock * master, GstClockTime time, |
1064 gst_clock_slave_callback (GstClock * master, GstClockTime time, |
1073 GstClockID id, GstClock * clock) |
1065 GstClockID id, GstClock * clock) |
1074 { |
1066 { |
1100 * master clock. |
1092 * master clock. |
1101 * |
1093 * |
1102 * A clock provider that slaves its clock to a master can get the current |
1094 * A clock provider that slaves its clock to a master can get the current |
1103 * calibration values with gst_clock_get_calibration(). |
1095 * calibration values with gst_clock_get_calibration(). |
1104 * |
1096 * |
1105 * @master can be NULL in which case @clock will not be slaved anymore. It will |
1097 * @master can be %NULL in which case @clock will not be slaved anymore. It will |
1106 * however keep reporting its time adjusted with the last configured rate |
1098 * however keep reporting its time adjusted with the last configured rate |
1107 * and time offsets. |
1099 * and time offsets. |
1108 * |
1100 * |
1109 * Returns: TRUE if the clock is capable of being slaved to a master clock. |
1101 * Returns: %TRUE if the clock is capable of being slaved to a master clock. |
1110 * Trying to set a master on a clock without the |
1102 * Trying to set a master on a clock without the |
1111 * GST_CLOCK_FLAG_CAN_SET_MASTER flag will make this function return FALSE. |
1103 * #GST_CLOCK_FLAG_CAN_SET_MASTER flag will make this function return %FALSE. |
1112 * |
1104 * |
1113 * MT safe. |
1105 * MT safe. |
1114 */ |
1106 */ |
1115 #ifdef __SYMBIAN32__ |
1107 #ifdef __SYMBIAN32__ |
1116 EXPORT_C |
1108 EXPORT_C |
1330 * clock are added to the list of observations. If enough observations |
1322 * clock are added to the list of observations. If enough observations |
1331 * are available, a linear regression algorithm is run on the |
1323 * are available, a linear regression algorithm is run on the |
1332 * observations and @clock is recalibrated. |
1324 * observations and @clock is recalibrated. |
1333 * |
1325 * |
1334 * If this functions returns %TRUE, @r_squared will contain the |
1326 * If this functions returns %TRUE, @r_squared will contain the |
1335 * correlation coefficient of the interpollation. A value of 1.0 |
1327 * correlation coefficient of the interpolation. A value of 1.0 |
1336 * means a perfect regression was performed. This value can |
1328 * means a perfect regression was performed. This value can |
1337 * be used to control the sampling frequency of the master and slave |
1329 * be used to control the sampling frequency of the master and slave |
1338 * clocks. |
1330 * clocks. |
1339 * |
1331 * |
1340 * Returns: TRUE if enough observations were added to run the |
1332 * Returns: %TRUE if enough observations were added to run the |
1341 * regression algorithm. |
1333 * regression algorithm. |
1342 * |
1334 * |
1343 * MT safe. |
1335 * MT safe. |
1344 */ |
1336 */ |
1345 #ifdef __SYMBIAN32__ |
1337 #ifdef __SYMBIAN32__ |
1354 |
1346 |
1355 g_return_val_if_fail (GST_IS_CLOCK (clock), FALSE); |
1347 g_return_val_if_fail (GST_IS_CLOCK (clock), FALSE); |
1356 g_return_val_if_fail (r_squared != NULL, FALSE); |
1348 g_return_val_if_fail (r_squared != NULL, FALSE); |
1357 |
1349 |
1358 GST_CLOCK_SLAVE_LOCK (clock); |
1350 GST_CLOCK_SLAVE_LOCK (clock); |
|
1351 |
|
1352 GST_CAT_LOG_OBJECT (GST_CAT_CLOCK, clock, |
|
1353 "adding observation slave %" GST_TIME_FORMAT ", master %" GST_TIME_FORMAT, |
|
1354 GST_TIME_ARGS (slave), GST_TIME_ARGS (master)); |
1359 |
1355 |
1360 clock->times[(4 * clock->time_index)] = slave; |
1356 clock->times[(4 * clock->time_index)] = slave; |
1361 clock->times[(4 * clock->time_index) + 2] = master; |
1357 clock->times[(4 * clock->time_index) + 2] = master; |
1362 |
1358 |
1363 clock->time_index++; |
1359 clock->time_index++; |