• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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