1 /* GStreamer
2 * Copyright (C) 2019 Intel Corporation
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
17 * Boston, MA 02110-1335, USA.
18 */
19 /**
20 * SECTION:element-clockselect
21 *
22 * The clockselect element is a pipeline that enables one to choose its
23 * clock. By default, pipelines chose a clock depending on its elements,
24 * however the clockselect pipeline has some properties to force an
25 * arbitrary clock on it.
26 *
27 * <refsect2>
28 * <title>Example launch line</title>
29 * |[
30 * gst-launch-1.0 -v clockselect. \( clock-id=ptp domain=1 fakesrc ! fakesink \)
31 * ]|
32 * This example will create a pipeline and use the PTP clock with domain 1 on it.
33 * </refsect2>
34 */
35
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
39
40 #include <gst/gst.h>
41 #include <gst/net/net.h>
42 #include "gstdebugutilsbadelements.h"
43 #include "gstclockselect.h"
44
45 GST_DEBUG_CATEGORY_STATIC (gst_clock_select_debug_category);
46 #define GST_CAT_DEFAULT gst_clock_select_debug_category
47
48 #define GST_TYPE_CLOCK_SELECT_CLOCK_ID (gst_clock_select_clock_id_get_type())
49 static GType
gst_clock_select_clock_id_get_type(void)50 gst_clock_select_clock_id_get_type (void)
51 {
52 static GType clock_id_type = 0;
53
54 if (g_once_init_enter (&clock_id_type)) {
55 GType type;
56 static const GEnumValue clock_id_types[] = {
57 {GST_CLOCK_SELECT_CLOCK_ID_DEFAULT,
58 "Default (elected from elements) pipeline clock", "default"},
59 {GST_CLOCK_SELECT_CLOCK_ID_MONOTONIC, "System monotonic clock",
60 "monotonic"},
61 {GST_CLOCK_SELECT_CLOCK_ID_REALTIME, "System realtime clock", "realtime"},
62 {GST_CLOCK_SELECT_CLOCK_ID_PTP, "PTP clock", "ptp"},
63 {GST_CLOCK_SELECT_CLOCK_ID_TAI, "System TAI clock", "tai"},
64 {0, NULL, NULL},
65 };
66
67 type = g_enum_register_static ("GstClockSelectClockId", clock_id_types);
68 g_once_init_leave (&clock_id_type, type);
69 }
70
71 return clock_id_type;
72 }
73
74 /* prototypes */
75 static void gst_clock_select_set_property (GObject * object,
76 guint property_id, const GValue * value, GParamSpec * pspec);
77 static void gst_clock_select_get_property (GObject * object,
78 guint property_id, GValue * value, GParamSpec * pspec);
79
80 static GstClock *gst_clock_select_provide_clock (GstElement * element);
81
82 enum
83 {
84 PROP_0,
85 PROP_CLOCK_ID,
86 PROP_PTP_DOMAIN
87 };
88
89 #define DEFAULT_CLOCK_ID GST_CLOCK_SELECT_CLOCK_ID_DEFAULT
90 #define DEFAULT_PTP_DOMAIN 0
91
92 /* class initialization */
93
94 #define gst_clock_select_parent_class parent_class
95 G_DEFINE_TYPE_WITH_CODE (GstClockSelect, gst_clock_select, GST_TYPE_PIPELINE,
96 GST_DEBUG_CATEGORY_INIT (gst_clock_select_debug_category, "clockselect", 0,
97 "debug category for clockselect element"));
98 GST_ELEMENT_REGISTER_DEFINE (clockselect, "clockselect",
99 GST_RANK_NONE, gst_clock_select_get_type ());
100
101 static void
gst_clock_select_class_init(GstClockSelectClass * klass)102 gst_clock_select_class_init (GstClockSelectClass * klass)
103 {
104 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
105 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
106
107 gobject_class->set_property = gst_clock_select_set_property;
108 gobject_class->get_property = gst_clock_select_get_property;
109
110 g_object_class_install_property (gobject_class, PROP_CLOCK_ID,
111 g_param_spec_enum ("clock-id", "Clock ID", "ID of pipeline clock",
112 GST_TYPE_CLOCK_SELECT_CLOCK_ID, DEFAULT_CLOCK_ID,
113 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
114
115 g_object_class_install_property (gobject_class, PROP_PTP_DOMAIN,
116 g_param_spec_uint ("ptp-domain", "PTP domain",
117 "PTP clock domain (meaningful only when Clock ID is PTP)",
118 0, G_MAXUINT8, DEFAULT_PTP_DOMAIN,
119 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
120
121 gst_element_class_set_static_metadata (GST_ELEMENT_CLASS (klass),
122 "Clock select", "Generic/Bin", "Pipeline that enables different clocks",
123 "Ederson de Souza <ederson.desouza@intel.com>");
124
125 gstelement_class->provide_clock =
126 GST_DEBUG_FUNCPTR (gst_clock_select_provide_clock);
127
128 gst_type_mark_as_plugin_api (GST_TYPE_CLOCK_SELECT_CLOCK_ID, 0);
129 }
130
131 static void
gst_clock_select_init(GstClockSelect * clock_select)132 gst_clock_select_init (GstClockSelect * clock_select)
133 {
134 clock_select->clock_id = DEFAULT_CLOCK_ID;
135 clock_select->ptp_domain = DEFAULT_PTP_DOMAIN;
136 }
137
138 static void
gst_clock_select_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)139 gst_clock_select_set_property (GObject * object, guint property_id,
140 const GValue * value, GParamSpec * pspec)
141 {
142 GstClockSelect *clock_select = GST_CLOCK_SELECT (object);
143
144 GST_DEBUG_OBJECT (clock_select, "set_property");
145
146 switch (property_id) {
147 case PROP_CLOCK_ID:
148 clock_select->clock_id = g_value_get_enum (value);
149 break;
150 case PROP_PTP_DOMAIN:
151 clock_select->ptp_domain = g_value_get_uint (value);
152 break;
153 default:
154 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
155 break;
156 }
157 }
158
159 static void
gst_clock_select_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)160 gst_clock_select_get_property (GObject * object, guint property_id,
161 GValue * value, GParamSpec * pspec)
162 {
163 GstClockSelect *clock_select = GST_CLOCK_SELECT (object);
164
165 GST_DEBUG_OBJECT (clock_select, "get_property");
166
167 switch (property_id) {
168 case PROP_CLOCK_ID:
169 g_value_set_enum (value, clock_select->clock_id);
170 break;
171 case PROP_PTP_DOMAIN:
172 g_value_set_uint (value, clock_select->ptp_domain);
173 break;
174 default:
175 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
176 break;
177 }
178 }
179
180 static GstClock *
gst_clock_select_provide_clock(GstElement * element)181 gst_clock_select_provide_clock (GstElement * element)
182 {
183 GstClock *clock;
184 GstClockSelect *clock_select = GST_CLOCK_SELECT (element);
185
186 switch (clock_select->clock_id) {
187 case GST_CLOCK_SELECT_CLOCK_ID_MONOTONIC:
188 clock =
189 g_object_new (GST_TYPE_SYSTEM_CLOCK, "name", "DebugGstSystemClock",
190 NULL);
191 gst_object_ref_sink (clock);
192 gst_util_set_object_arg (G_OBJECT (clock), "clock-type", "monotonic");
193 break;
194 case GST_CLOCK_SELECT_CLOCK_ID_REALTIME:
195 clock =
196 g_object_new (GST_TYPE_SYSTEM_CLOCK, "name", "DebugGstSystemClock",
197 NULL);
198 gst_object_ref_sink (clock);
199 gst_util_set_object_arg (G_OBJECT (clock), "clock-type", "realtime");
200 break;
201 case GST_CLOCK_SELECT_CLOCK_ID_PTP:
202 clock = gst_ptp_clock_new ("ptp-clock", clock_select->ptp_domain);
203 if (!clock) {
204 GST_WARNING_OBJECT (clock_select,
205 "Failed to get PTP clock, falling back to pipeline default clock");
206 }
207 break;
208 case GST_CLOCK_SELECT_CLOCK_ID_TAI:
209 clock =
210 g_object_new (GST_TYPE_SYSTEM_CLOCK, "name", "DebugGstSystemClock",
211 NULL);
212 gst_object_ref_sink (clock);
213 gst_util_set_object_arg (G_OBJECT (clock), "clock-type", "tai");
214 break;
215 case GST_CLOCK_SELECT_CLOCK_ID_DEFAULT:
216 default:
217 clock = NULL;
218 }
219
220 if (clock) {
221 GST_INFO_OBJECT (clock_select, "Waiting clock sync...");
222 gst_clock_wait_for_sync (clock, GST_CLOCK_TIME_NONE);
223 gst_pipeline_use_clock (GST_PIPELINE (clock_select), clock);
224 /* gst_pipeline_use_clock above ref's clock, as well as parent call
225 * below, so we don't need our reference anymore */
226 gst_object_unref (clock);
227 }
228
229 clock = GST_ELEMENT_CLASS (parent_class)->provide_clock (element);
230
231 return clock;
232 }
233