Top |
Functions
Description
GstTestClock is an implementation of GstClock which has different
behaviour compared to GstSystemClock. Time for GstSystemClock advances
according to the system time, while time for GstTestClock changes only
when gst_test_clock_set_time()
or gst_test_clock_advance_time()
are
called. GstTestClock provides unit tests with the possibility to
precisely advance the time in a deterministic manner, independent of the
system time or any other external factors.
Advancing the time of a GstTestClock
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#include <gst/gst.h> #include <gst/check/gsttestclock.h> GstClock *clock; GstTestClock *test_clock; clock = gst_test_clock_new (); test_clock = GST_TEST_CLOCK (clock); GST_INFO ("Time: %" GST_TIME_FORMAT, GST_TIME_ARGS (gst_clock_get_time (clock))); gst_test_clock_advance_time ( test_clock, 1 * GST_SECOND); GST_INFO ("Time: %" GST_TIME_FORMAT, GST_TIME_ARGS (gst_clock_get_time (clock))); g_usleep (10 * G_USEC_PER_SEC); GST_INFO ("Time: %" GST_TIME_FORMAT, GST_TIME_ARGS (gst_clock_get_time (clock))); gst_test_clock_set_time (test_clock, 42 * GST_SECOND); GST_INFO ("Time: %" GST_TIME_FORMAT, GST_TIME_ARGS (gst_clock_get_time (clock))); ... |
GstClock allows for setting up single shot or periodic clock notifications
as well as waiting for these notifications synchronously (using
gst_clock_id_wait()
) or asynchronously (using gst_clock_id_wait_async()
or
gst_clock_id_wait_async()
). This is used by many GStreamer elements,
among them GstBaseSrc and GstBaseSink.
GstTestClock keeps track of these clock notifications. By calling
gst_test_clock_wait_for_next_pending_id()
or
gst_test_clock_wait_for_multiple_pending_ids()
a unit tests may wait for the
next one or several clock notifications to be requested. Additionally unit
tests may release blocked waits in a controlled fashion by calling
gst_test_clock_process_next_clock_id()
. This way a unit test can control the
inaccuracy (jitter) of clock notifications, since the test can decide to
release blocked waits when the clock time has advanced exactly to, or past,
the requested clock notification time.
There are also interfaces for determining if a notification belongs to a GstTestClock or not, as well as getting the number of requested clock notifications so far.
N.B.: When a unit test waits for a certain amount of clock notifications to
be requested in gst_test_clock_wait_for_next_pending_id()
or
gst_test_clock_wait_for_multiple_pending_ids()
then these functions may block
for a long time. If they block forever then the expected clock notifications
were never requested from GstTestClock, and so the assumptions in the code
of the unit test are wrong. The unit test case runner in gstcheck is
expected to catch these cases either by the default test case timeout or the
one set for the unit test by calling tcase_set_timeout()
.
The sample code below assumes that the element under test will delay a
buffer pushed on the source pad by some latency until it arrives on the sink
pad. Moreover it is assumed that the element will at some point call
gst_clock_id_wait()
to synchronously wait for a specific time. The first
buffer sent will arrive exactly on time only delayed by the latency. The
second buffer will arrive a little late (7ms) due to simulated jitter in the
clock notification.
Demonstration of how to work with clock notifications and GstTestClock
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
#include <gst/gst.h> #include <gst/check/gstcheck.h> #include <gst/check/gsttestclock.h> GstClockTime latency; GstElement *element; GstPad *srcpad; GstClock *clock; GstTestClock *test_clock; GstBuffer buf; GstClockID pending_id; GstClockID processed_id; latency = 42 * GST_MSECOND; element = create_element (latency, ...); srcpad = get_source_pad (element); clock = gst_test_clock_new (); test_clock = GST_TEST_CLOCK (clock); gst_element_set_clock (element, clock); GST_INFO ("Set time, create and push the first buffer\n"); gst_test_clock_set_time (test_clock, 0); buf = create_test_buffer (gst_clock_get_time (clock), ...); gst_assert_cmpint (gst_pad_push (srcpad, buf), ==, GST_FLOW_OK); GST_INFO ("Block until element is waiting for a clock notification\n"); gst_test_clock_wait_for_next_pending_id (test_clock, &pending_id); GST_INFO ("Advance to the requested time of the clock notification\n"); gst_test_clock_advance_time (test_clock, latency); GST_INFO ("Release the next blocking wait and make sure it is the one from element\n"); processed_id = gst_test_clock_process_next_clock_id (test_clock); g_assert (processed_id == pending_id); g_assert_cmpint (GST_CLOCK_ENTRY_STATUS (processed_id), ==, GST_CLOCK_OK); gst_clock_id_unref (pending_id); gst_clock_id_unref (processed_id); GST_INFO ("Validate that element produced an output buffer and check its timestamp\n"); g_assert_cmpint (get_number_of_output_buffer (...), ==, 1); buf = get_buffer_pushed_by_element (element, ...); g_assert_cmpint (GST_BUFFER_TIMESTAMP (buf), ==, latency); gst_buffer_unref (buf); GST_INFO ("Check that element does not wait for any clock notification\n"); g_assert (!gst_test_clock_peek_next_pending_id (test_clock, NULL)); GST_INFO ("Set time, create and push the second buffer\n"); gst_test_clock_advance_time (test_clock, 10 * GST_SECOND); buf = create_test_buffer (gst_clock_get_time (clock), ...); gst_assert_cmpint (gst_pad_push (srcpad, buf), ==, GST_FLOW_OK); GST_INFO ("Block until element is waiting for a new clock notification\n"); (gst_test_clock_wait_for_next_pending_id (test_clock, &pending_id); GST_INFO ("Advance past 7ms beyond the requested time of the clock notification\n"); gst_test_clock_advance_time (test_clock, latency + 7 * GST_MSECOND); GST_INFO ("Release the next blocking wait and make sure it is the one from element\n"); processed_id = gst_test_clock_process_next_clock_id (test_clock); g_assert (processed_id == pending_id); g_assert_cmpint (GST_CLOCK_ENTRY_STATUS (processed_id), ==, GST_CLOCK_OK); gst_clock_id_unref (pending_id); gst_clock_id_unref (processed_id); GST_INFO ("Validate that element produced an output buffer and check its timestamp\n"); g_assert_cmpint (get_number_of_output_buffer (...), ==, 1); buf = get_buffer_pushed_by_element (element, ...); g_assert_cmpint (GST_BUFFER_TIMESTAMP (buf), ==, 10 * GST_SECOND + latency + 7 * GST_MSECOND); gst_buffer_unref (buf); GST_INFO ("Check that element does not wait for any clock notification\n"); g_assert (!gst_test_clock_peek_next_pending_id (test_clock, NULL)); ... |
Since GstTestClock is only supposed to be used in unit tests it calls
g_assert()
, g_assert_cmpint()
or g_assert_cmpuint()
to validate all function
arguments. This will highlight any issues with the unit test code itself.
Functions
gst_test_clock_new ()
GstClock *
gst_test_clock_new (void
);
Creates a new test clock with its time set to zero.
MT safe.
Since: 1.2
gst_test_clock_new_with_start_time ()
GstClock *
gst_test_clock_new_with_start_time (GstClockTime start_time
);
Creates a new test clock with its time set to the specified time.
MT safe.
Since: 1.2
gst_test_clock_set_time ()
void gst_test_clock_set_time (GstTestClock *test_clock
,GstClockTime new_time
);
Sets the time of test_clock
to the time given by new_time
. The time of
test_clock
is monotonically increasing, therefore providing a new_time
which is earlier or equal to the time of the clock as given by
gst_clock_get_time()
is a programming error.
MT safe.
Parameters
test_clock |
a GstTestClock of which to set the time |
|
new_time |
a GstClockTime later than that returned by |
Since: 1.2
gst_test_clock_advance_time ()
void gst_test_clock_advance_time (GstTestClock *test_clock
,GstClockTimeDiff delta
);
Advances the time of the test_clock
by the amount given by delta
. The
time of test_clock
is monotonically increasing, therefore providing a
delta
which is negative or zero is a programming error.
MT safe.
Parameters
test_clock |
a GstTestClock for which to increase the time |
|
delta |
a positive GstClockTimeDiff to be added to the time of the clock |
Since: 1.2
gst_test_clock_peek_id_count ()
guint
gst_test_clock_peek_id_count (GstTestClock *test_clock
);
Determine the number of pending clock notifications that have been
requested from the test_clock
.
MT safe.
Since: 1.2
gst_test_clock_has_id ()
gboolean gst_test_clock_has_id (GstTestClock *test_clock
,GstClockID id
);
Checks whether test_clock
was requested to provide the clock notification
given by id
.
MT safe.
Parameters
test_clock |
a GstTestClock to ask if it provided the notification |
|
id |
a GstClockID clock notification. |
[transfer none] |
Since: 1.2
gst_test_clock_peek_next_pending_id ()
gboolean gst_test_clock_peek_next_pending_id (GstTestClock *test_clock
,GstClockID *pending_id
);
Determines if the pending_id
is the next clock notification scheduled to
be triggered given the current time of the test_clock
.
MT safe.
Return: TRUE
if pending_id
is the next clock notification to be
triggered, FALSE
otherwise.
Parameters
test_clock |
a GstTestClock to check the clock notifications for |
|
pending_id |
a GstClockID clock notification to look for. |
[allow-none][out][transfer full] |
Since: 1.2
gst_test_clock_wait_for_next_pending_id ()
void gst_test_clock_wait_for_next_pending_id (GstTestClock *test_clock
,GstClockID *pending_id
);
Waits until a clock notification is requested from test_clock
. There is no
timeout for this wait, see the main description of GstTestClock. A reference
to the pending clock notification is stored in pending_id
.
MT safe.
Parameters
test_clock |
GstTestClock for which to get the pending clock notification |
|
pending_id |
GstClockID with information about the pending clock notification. |
[allow-none][out][transfer full] |
Since: 1.2
gst_test_clock_wait_for_pending_id_count ()
void gst_test_clock_wait_for_pending_id_count (GstTestClock *test_clock
,guint count
);
gst_test_clock_wait_for_pending_id_count
is deprecated and should not be used in newly-written code.
use gst_test_clock_wait_for_multiple_pending_ids()
instead.
Blocks until at least count
clock notifications have been requested from
test_clock
. There is no timeout for this wait, see the main description of
GstTestClock.
Parameters
test_clock |
GstTestClock for which to await having enough pending clock |
|
count |
the number of pending clock notifications to wait for |
Since: 1.2
gst_test_clock_process_next_clock_id ()
GstClockID
gst_test_clock_process_next_clock_id (GstTestClock *test_clock
);
MT safe.
Since: 1.2
gst_test_clock_get_next_entry_time ()
GstClockTime
gst_test_clock_get_next_entry_time (GstTestClock *test_clock
);
Retrieve the requested time for the next pending clock notification.
MT safe.
Returns
a GstClockTime set to the time of the next pending clock
notification. If no clock notifications have been requested
GST_CLOCK_TIME_NONE
will be returned.
Since: 1.2
gst_test_clock_wait_for_multiple_pending_ids ()
void gst_test_clock_wait_for_multiple_pending_ids (GstTestClock *test_clock
,guint count
,GList **pending_list
);
Blocks until at least count
clock notifications have been requested from
test_clock
. There is no timeout for this wait, see the main description of
GstTestClock.
MT safe.
Parameters
test_clock |
GstTestClock for which to await having enough pending clock |
|
count |
the number of pending clock notifications to wait for |
|
pending_list |
Address
of a GList pointer variable to store the list of pending GstClockIDs
that expired, or |
[out][element-type Gst.ClockID][transfer full][allow-none] |
Since: 1.4
gst_test_clock_id_list_get_latest_time ()
GstClockTime
gst_test_clock_id_list_get_latest_time
(const GList *pending_list
);
Finds the latest time inside the list.
MT safe.
Parameters
pending_list |
List of of pending GstClockIDs. |
[element-type Gst.ClockID][transfer none][allow-none] |
Since: 1.4
gst_test_clock_process_id_list ()
guint gst_test_clock_process_id_list (GstTestClock *test_clock
,const GList *pending_list
);
Processes and releases the pending IDs in the list.
MT safe.
Parameters
test_clock |
GstTestClock for which to process the pending IDs |
|
pending_list |
List of pending GstClockIDs. |
[element-type Gst.ClockID][transfer none][allow-none] |
Since: 1.4
gst_test_clock_crank ()
gboolean
gst_test_clock_crank (GstTestClock *test_clock
);
A "crank" consists of three steps: 1: Wait for a GstClockID to be registered with the GstTestClock. 2: Advance the GstTestClock to the time the GstClockID is waiting for. 3: Release the GstClockID wait. A "crank" can be though of as the notion of manually driving the clock forward to its next logical step.
Return: TRUE
if the crank was successful, FALSE
otherwise.
MT safe.
Since: 1.8
Types and Values
struct GstTestClock
struct GstTestClock;
A GstTestClock structure which is based on a GstClock along with some private data.
Since: 1.2
struct GstTestClockClass
struct GstTestClockClass { GstClockClass parent_class; };
The class of a GstTestClock, which has no virtual methods to override.
Since: 1.2
Property Details
The “clock-type”
property
“clock-type” GstClockType
The kind of clock implementation to be reported by this clock.
Flags: Read / Write
Default value: GST_CLOCK_TYPE_MONOTONIC
The “start-time”
property
“start-time” guint64
When a GstTestClock is constructed it will have a certain start time set.
If the clock was created using gst_test_clock_new_with_start_time()
then
this property contains the value of the start_time
argument. If
gst_test_clock_new()
was called the clock started at time zero, and thus
this property contains the value 0.
Flags: Read / Write / Construct Only
Default value: 0