1 /*
2 * GStreamer AVTP Plugin
3 * Copyright (C) 2019 Intel Corporation
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later
9 * version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301 USA
20 */
21
22 #include "gstavtpbasepayload.h"
23
24 GST_DEBUG_CATEGORY_STATIC (avtpbasepayload_debug);
25 #define GST_CAT_DEFAULT (avtpbasepayload_debug)
26
27 #define DEFAULT_STREAMID 0xAABBCCDDEEFF0000
28 #define DEFAULT_MTT 50000000
29 #define DEFAULT_TU 1000000
30 #define DEFAULT_PROCESSING_DEADLINE (20 * GST_MSECOND)
31
32 enum
33 {
34 PROP_0,
35 PROP_STREAMID,
36 PROP_MTT,
37 PROP_TU,
38 PROP_PROCESSING_DEADLINE,
39 };
40
41 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
42 GST_PAD_SRC,
43 GST_PAD_ALWAYS,
44 GST_STATIC_CAPS ("application/x-avtp")
45 );
46
47 static void gst_avtp_base_payload_class_init (GstAvtpBasePayloadClass * klass);
48 static void gst_avtp_base_payload_init (GstAvtpBasePayload * avtpbasepayload,
49 gpointer g_class);
50
51 static void gst_avtp_base_payload_set_property (GObject * object, guint prop_id,
52 const GValue * value, GParamSpec * pspec);
53 static void gst_avtp_base_payload_get_property (GObject * object, guint prop_id,
54 GValue * value, GParamSpec * pspec);
55
56 static gboolean gst_avtp_base_payload_sink_event (GstPad * pad,
57 GstObject * parent, GstEvent * event);
58
59 GType
gst_avtp_base_payload_get_type(void)60 gst_avtp_base_payload_get_type (void)
61 {
62 static GType avtpbasepayload_type = 0;
63
64 if (g_once_init_enter ((gsize *) & avtpbasepayload_type)) {
65 static const GTypeInfo avtpbasepayload_info = {
66 sizeof (GstAvtpBasePayloadClass),
67 NULL,
68 NULL,
69 (GClassInitFunc) gst_avtp_base_payload_class_init,
70 NULL,
71 NULL,
72 sizeof (GstAvtpBasePayload),
73 0,
74 (GInstanceInitFunc) gst_avtp_base_payload_init,
75 };
76 GType _type;
77
78 _type = g_type_register_static (GST_TYPE_ELEMENT, "GstAvtpBasePayload",
79 &avtpbasepayload_info, G_TYPE_FLAG_ABSTRACT);
80
81 g_once_init_leave ((gsize *) & avtpbasepayload_type, _type);
82 }
83 return avtpbasepayload_type;
84 }
85
86 static void
gst_avtp_base_payload_class_init(GstAvtpBasePayloadClass * klass)87 gst_avtp_base_payload_class_init (GstAvtpBasePayloadClass * klass)
88 {
89 GObjectClass *object_class = G_OBJECT_CLASS (klass);
90
91 object_class->set_property = gst_avtp_base_payload_set_property;
92 object_class->get_property = gst_avtp_base_payload_get_property;
93
94 g_object_class_install_property (object_class, PROP_STREAMID,
95 g_param_spec_uint64 ("streamid", "Stream ID",
96 "Stream ID associated with the AVTPDU", 0, G_MAXUINT64,
97 DEFAULT_STREAMID, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
98 GST_PARAM_MUTABLE_READY));
99 g_object_class_install_property (object_class, PROP_MTT,
100 g_param_spec_uint ("mtt", "Maximum Transit Time",
101 "Maximum Transit Time (MTT) in nanoseconds", 0,
102 G_MAXUINT, DEFAULT_MTT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
103 g_object_class_install_property (object_class, PROP_TU,
104 g_param_spec_uint ("tu", "Timing Uncertainty",
105 "Timing Uncertainty (TU) in nanoseconds", 0,
106 G_MAXUINT, DEFAULT_TU, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
107 g_object_class_install_property (object_class, PROP_PROCESSING_DEADLINE,
108 g_param_spec_uint64 ("processing-deadline", "Processing deadline",
109 "Maximum amount of time (in ns) the pipeline can take for processing the buffer",
110 0, G_MAXUINT64, DEFAULT_PROCESSING_DEADLINE, G_PARAM_READWRITE |
111 G_PARAM_STATIC_STRINGS));
112
113 klass->chain = NULL;
114 klass->sink_event = GST_DEBUG_FUNCPTR (gst_avtp_base_payload_sink_event);
115
116 GST_DEBUG_CATEGORY_INIT (avtpbasepayload_debug, "avtpbasepayload", 0,
117 "Base class for AVTP payloaders");
118
119 gst_type_mark_as_plugin_api (GST_TYPE_AVTP_BASE_PAYLOAD, 0);
120 }
121
122 static void
gst_avtp_base_payload_init(GstAvtpBasePayload * avtpbasepayload,gpointer g_class)123 gst_avtp_base_payload_init (GstAvtpBasePayload * avtpbasepayload,
124 gpointer g_class)
125 {
126 GstPadTemplate *templ;
127 GstElement *element = GST_ELEMENT (avtpbasepayload);
128 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
129 GstAvtpBasePayloadClass *avtpbasepayload_class =
130 GST_AVTP_BASE_PAYLOAD_CLASS (g_class);
131
132 g_assert (avtpbasepayload_class->chain != NULL);
133
134 avtpbasepayload->srcpad = gst_pad_new_from_static_template (&src_template,
135 "src");
136 gst_element_add_pad (element, avtpbasepayload->srcpad);
137
138 templ = gst_element_class_get_pad_template (element_class, "sink");
139 g_assert (templ != NULL);
140 avtpbasepayload->sinkpad = gst_pad_new_from_template (templ, "sink");
141 gst_pad_set_chain_function (avtpbasepayload->sinkpad,
142 avtpbasepayload_class->chain);
143 gst_pad_set_event_function (avtpbasepayload->sinkpad,
144 avtpbasepayload_class->sink_event);
145 gst_element_add_pad (element, avtpbasepayload->sinkpad);
146
147 avtpbasepayload->streamid = DEFAULT_STREAMID;
148 avtpbasepayload->mtt = DEFAULT_MTT;
149 avtpbasepayload->tu = DEFAULT_TU;
150 avtpbasepayload->processing_deadline = DEFAULT_PROCESSING_DEADLINE;
151
152 avtpbasepayload->latency = GST_CLOCK_TIME_NONE;
153 avtpbasepayload->seqnum = 0;
154 gst_segment_init (&avtpbasepayload->segment, GST_FORMAT_UNDEFINED);
155 }
156
157 static void
gst_avtp_base_payload_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)158 gst_avtp_base_payload_set_property (GObject * object, guint prop_id,
159 const GValue * value, GParamSpec * pspec)
160 {
161 GstAvtpBasePayload *avtpbasepayload = GST_AVTP_BASE_PAYLOAD (object);
162
163 GST_DEBUG_OBJECT (avtpbasepayload, "prop_id %u", prop_id);
164
165 switch (prop_id) {
166 case PROP_STREAMID:
167 avtpbasepayload->streamid = g_value_get_uint64 (value);
168 break;
169 case PROP_MTT:
170 avtpbasepayload->mtt = g_value_get_uint (value);
171 break;
172 case PROP_TU:
173 avtpbasepayload->tu = g_value_get_uint (value);
174 break;
175 case PROP_PROCESSING_DEADLINE:
176 avtpbasepayload->processing_deadline = g_value_get_uint64 (value);
177 break;
178 default:
179 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
180 break;
181 }
182 }
183
184 static void
gst_avtp_base_payload_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)185 gst_avtp_base_payload_get_property (GObject * object, guint prop_id,
186 GValue * value, GParamSpec * pspec)
187 {
188 GstAvtpBasePayload *avtpbasepayload = GST_AVTP_BASE_PAYLOAD (object);
189
190 GST_DEBUG_OBJECT (avtpbasepayload, "prop_id %u", prop_id);
191
192 switch (prop_id) {
193 case PROP_STREAMID:
194 g_value_set_uint64 (value, avtpbasepayload->streamid);
195 break;
196 case PROP_MTT:
197 g_value_set_uint (value, avtpbasepayload->mtt);
198 break;
199 case PROP_TU:
200 g_value_set_uint (value, avtpbasepayload->tu);
201 break;
202 case PROP_PROCESSING_DEADLINE:
203 g_value_set_uint64 (value, avtpbasepayload->processing_deadline);
204 break;
205 default:
206 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
207 break;
208 }
209 }
210
211 static gboolean
gst_avtp_base_payload_sink_event(GstPad * pad,GstObject * parent,GstEvent * event)212 gst_avtp_base_payload_sink_event (GstPad * pad, GstObject * parent,
213 GstEvent * event)
214 {
215 GstAvtpBasePayload *avtpbasepayload = GST_AVTP_BASE_PAYLOAD (parent);
216
217 GST_DEBUG_OBJECT (avtpbasepayload, "event %s", GST_EVENT_TYPE_NAME (event));
218
219 switch (GST_EVENT_TYPE (event)) {
220 case GST_EVENT_SEGMENT:
221 gst_event_copy_segment (event, &avtpbasepayload->segment);
222 /* Fall through */
223 default:
224 return gst_pad_event_default (pad, parent, event);
225 }
226 }
227
228 GstClockTime
gst_avtp_base_payload_calc_ptime(GstAvtpBasePayload * avtpbasepayload,GstBuffer * buffer)229 gst_avtp_base_payload_calc_ptime (GstAvtpBasePayload * avtpbasepayload,
230 GstBuffer * buffer)
231 {
232 GstClockTime base_time, running_time;
233
234 g_assert (GST_BUFFER_PTS (buffer) != GST_CLOCK_TIME_NONE);
235
236 if (G_UNLIKELY (avtpbasepayload->latency == GST_CLOCK_TIME_NONE)) {
237 GstQuery *query;
238
239 query = gst_query_new_latency ();
240 if (!gst_pad_peer_query (avtpbasepayload->sinkpad, query))
241 return GST_CLOCK_TIME_NONE;
242 gst_query_parse_latency (query, NULL, &avtpbasepayload->latency, NULL);
243 gst_query_unref (query);
244
245 GST_DEBUG_OBJECT (avtpbasepayload, "latency %" GST_TIME_FORMAT,
246 GST_TIME_ARGS (avtpbasepayload->latency));
247 }
248
249 base_time = gst_element_get_base_time (GST_ELEMENT (avtpbasepayload));
250
251 running_time = gst_segment_to_running_time (&avtpbasepayload->segment,
252 avtpbasepayload->segment.format, GST_BUFFER_PTS (buffer));
253
254 return base_time + running_time + avtpbasepayload->latency +
255 avtpbasepayload->processing_deadline + avtpbasepayload->mtt +
256 avtpbasepayload->tu;
257 }
258