|
1 /* GStreamer |
|
2 * Copyright (C) <2005> Wim Taymans <wim@fluendo.com> |
|
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 |
|
13 */ |
|
14 |
|
15 /** |
|
16 * SECTION:gstbasertppayload |
|
17 * @short_description: Base class for RTP payloader |
|
18 * |
|
19 * <refsect2> |
|
20 * <para> |
|
21 * Provides a base class for RTP payloaders |
|
22 * </para> |
|
23 * </refsect2> |
|
24 */ |
|
25 |
|
26 #ifdef HAVE_CONFIG_H |
|
27 # include "config.h" |
|
28 #endif |
|
29 |
|
30 #include <string.h> |
|
31 |
|
32 #include <gst/rtp/gstrtpbuffer.h> |
|
33 |
|
34 #include "gstbasertppayload.h" |
|
35 |
|
36 GST_DEBUG_CATEGORY_STATIC (basertppayload_debug); |
|
37 #define GST_CAT_DEFAULT (basertppayload_debug) |
|
38 |
|
39 #define GST_BASE_RTP_PAYLOAD_GET_PRIVATE(obj) \ |
|
40 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_BASE_RTP_PAYLOAD, GstBaseRTPPayloadPrivate)) |
|
41 |
|
42 struct _GstBaseRTPPayloadPrivate |
|
43 { |
|
44 gboolean ts_offset_random; |
|
45 gboolean seqnum_offset_random; |
|
46 gboolean ssrc_random; |
|
47 guint16 next_seqnum; |
|
48 |
|
49 GstClockTime rt_base; |
|
50 }; |
|
51 |
|
52 /* BaseRTPPayload signals and args */ |
|
53 enum |
|
54 { |
|
55 /* FILL ME */ |
|
56 LAST_SIGNAL |
|
57 }; |
|
58 |
|
59 /* FIXME 0.11, a better default is the Ethernet MTU of |
|
60 * 1500 - sizeof(headers) as pointed out by marcelm in IRC: |
|
61 * So an Ethernet MTU of 1500, minus 60 for the max IP, minus 8 for UDP, gives |
|
62 * 1432 bytes or so. And that should be adjusted downward further for other |
|
63 * encapsulations like PPPoE, so 1400 at most. |
|
64 */ |
|
65 #define DEFAULT_MTU 1400 |
|
66 #define DEFAULT_PT 96 |
|
67 #define DEFAULT_SSRC -1 |
|
68 #define DEFAULT_TIMESTAMP_OFFSET -1 |
|
69 #define DEFAULT_SEQNUM_OFFSET -1 |
|
70 #define DEFAULT_MAX_PTIME -1 |
|
71 #define DEFAULT_MIN_PTIME 0 |
|
72 |
|
73 enum |
|
74 { |
|
75 PROP_0, |
|
76 PROP_MTU, |
|
77 PROP_PT, |
|
78 PROP_SSRC, |
|
79 PROP_TIMESTAMP_OFFSET, |
|
80 PROP_SEQNUM_OFFSET, |
|
81 PROP_MAX_PTIME, |
|
82 PROP_MIN_PTIME, |
|
83 PROP_TIMESTAMP, |
|
84 PROP_SEQNUM |
|
85 }; |
|
86 |
|
87 static void gst_basertppayload_class_init (GstBaseRTPPayloadClass * klass); |
|
88 static void gst_basertppayload_base_init (GstBaseRTPPayloadClass * klass); |
|
89 static void gst_basertppayload_init (GstBaseRTPPayload * basertppayload, |
|
90 gpointer g_class); |
|
91 static void gst_basertppayload_finalize (GObject * object); |
|
92 |
|
93 static gboolean gst_basertppayload_setcaps (GstPad * pad, GstCaps * caps); |
|
94 static GstCaps *gst_basertppayload_getcaps (GstPad * pad); |
|
95 static gboolean gst_basertppayload_event (GstPad * pad, GstEvent * event); |
|
96 static GstFlowReturn gst_basertppayload_chain (GstPad * pad, |
|
97 GstBuffer * buffer); |
|
98 |
|
99 static void gst_basertppayload_set_property (GObject * object, guint prop_id, |
|
100 const GValue * value, GParamSpec * pspec); |
|
101 static void gst_basertppayload_get_property (GObject * object, guint prop_id, |
|
102 GValue * value, GParamSpec * pspec); |
|
103 |
|
104 static GstStateChangeReturn gst_basertppayload_change_state (GstElement * |
|
105 element, GstStateChange transition); |
|
106 |
|
107 static GstElementClass *parent_class = NULL; |
|
108 |
|
109 /* FIXME 0.11: API should be changed to gst_base_typ_payload_xyz */ |
|
110 #ifdef __SYMBIAN32__ |
|
111 EXPORT_C |
|
112 #endif |
|
113 |
|
114 |
|
115 GType |
|
116 gst_basertppayload_get_type (void) |
|
117 { |
|
118 static GType basertppayload_type = 0; |
|
119 |
|
120 if (!basertppayload_type) { |
|
121 static const GTypeInfo basertppayload_info = { |
|
122 sizeof (GstBaseRTPPayloadClass), |
|
123 (GBaseInitFunc) gst_basertppayload_base_init, |
|
124 NULL, |
|
125 (GClassInitFunc) gst_basertppayload_class_init, |
|
126 NULL, |
|
127 NULL, |
|
128 sizeof (GstBaseRTPPayload), |
|
129 0, |
|
130 (GInstanceInitFunc) gst_basertppayload_init, |
|
131 }; |
|
132 |
|
133 basertppayload_type = |
|
134 g_type_register_static (GST_TYPE_ELEMENT, "GstBaseRTPPayload", |
|
135 &basertppayload_info, G_TYPE_FLAG_ABSTRACT); |
|
136 } |
|
137 return basertppayload_type; |
|
138 } |
|
139 |
|
140 static void |
|
141 gst_basertppayload_base_init (GstBaseRTPPayloadClass * klass) |
|
142 { |
|
143 } |
|
144 |
|
145 static void |
|
146 gst_basertppayload_class_init (GstBaseRTPPayloadClass * klass) |
|
147 { |
|
148 GObjectClass *gobject_class; |
|
149 GstElementClass *gstelement_class; |
|
150 |
|
151 gobject_class = (GObjectClass *) klass; |
|
152 gstelement_class = (GstElementClass *) klass; |
|
153 |
|
154 g_type_class_add_private (klass, sizeof (GstBaseRTPPayloadPrivate)); |
|
155 |
|
156 parent_class = g_type_class_peek_parent (klass); |
|
157 |
|
158 gobject_class->finalize = gst_basertppayload_finalize; |
|
159 |
|
160 gobject_class->set_property = gst_basertppayload_set_property; |
|
161 gobject_class->get_property = gst_basertppayload_get_property; |
|
162 |
|
163 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MTU, |
|
164 g_param_spec_uint ("mtu", "MTU", |
|
165 "Maximum size of one packet", |
|
166 28, G_MAXUINT, DEFAULT_MTU, G_PARAM_READWRITE)); |
|
167 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PT, |
|
168 g_param_spec_uint ("pt", "payload type", |
|
169 "The payload type of the packets", |
|
170 0, 0x80, DEFAULT_PT, G_PARAM_READWRITE)); |
|
171 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SSRC, |
|
172 g_param_spec_uint ("ssrc", "SSRC", |
|
173 "The SSRC of the packets (default == random)", |
|
174 0, G_MAXUINT32, DEFAULT_SSRC, G_PARAM_READWRITE)); |
|
175 g_object_class_install_property (G_OBJECT_CLASS (klass), |
|
176 PROP_TIMESTAMP_OFFSET, g_param_spec_uint ("timestamp-offset", |
|
177 "Timestamp Offset", |
|
178 "Offset to add to all outgoing timestamps (default = random)", 0, |
|
179 G_MAXUINT32, DEFAULT_TIMESTAMP_OFFSET, G_PARAM_READWRITE)); |
|
180 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SEQNUM_OFFSET, |
|
181 g_param_spec_int ("seqnum-offset", "Sequence number Offset", |
|
182 "Offset to add to all outgoing seqnum (-1 = random)", -1, G_MAXUINT16, |
|
183 DEFAULT_SEQNUM_OFFSET, G_PARAM_READWRITE)); |
|
184 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MAX_PTIME, |
|
185 g_param_spec_int64 ("max-ptime", "Max packet time", |
|
186 "Maximum duration of the packet data in ns (-1 = unlimited up to MTU)", |
|
187 -1, G_MAXINT64, DEFAULT_MAX_PTIME, G_PARAM_READWRITE)); |
|
188 /** |
|
189 * GstBaseRTPAudioPayload:min-ptime: |
|
190 * |
|
191 * Minimum duration of the packet data in ns (can't go above MTU) |
|
192 * |
|
193 * Since: 0.10.13 |
|
194 **/ |
|
195 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MIN_PTIME, |
|
196 g_param_spec_int64 ("min-ptime", "Min packet time", |
|
197 "Minimum duration of the packet data in ns (can't go above MTU)", |
|
198 0, G_MAXINT64, DEFAULT_MIN_PTIME, G_PARAM_READWRITE)); |
|
199 |
|
200 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TIMESTAMP, |
|
201 g_param_spec_uint ("timestamp", "Timestamp", |
|
202 "The RTP timestamp of the last processed packet", |
|
203 0, G_MAXUINT32, 0, G_PARAM_READABLE)); |
|
204 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SEQNUM, |
|
205 g_param_spec_uint ("seqnum", "Sequence number", |
|
206 "The RTP sequence number of the last processed packet", |
|
207 0, G_MAXUINT16, 0, G_PARAM_READABLE)); |
|
208 |
|
209 gstelement_class->change_state = gst_basertppayload_change_state; |
|
210 |
|
211 GST_DEBUG_CATEGORY_INIT (basertppayload_debug, "basertppayload", 0, |
|
212 "Base class for RTP Payloaders"); |
|
213 } |
|
214 |
|
215 static void |
|
216 gst_basertppayload_init (GstBaseRTPPayload * basertppayload, gpointer g_class) |
|
217 { |
|
218 GstPadTemplate *templ; |
|
219 GstBaseRTPPayloadPrivate *priv; |
|
220 |
|
221 basertppayload->priv = priv = |
|
222 GST_BASE_RTP_PAYLOAD_GET_PRIVATE (basertppayload); |
|
223 |
|
224 templ = |
|
225 gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "src"); |
|
226 g_return_if_fail (templ != NULL); |
|
227 |
|
228 basertppayload->srcpad = gst_pad_new_from_template (templ, "src"); |
|
229 gst_element_add_pad (GST_ELEMENT (basertppayload), basertppayload->srcpad); |
|
230 |
|
231 templ = |
|
232 gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "sink"); |
|
233 g_return_if_fail (templ != NULL); |
|
234 |
|
235 basertppayload->sinkpad = gst_pad_new_from_template (templ, "sink"); |
|
236 gst_pad_set_setcaps_function (basertppayload->sinkpad, |
|
237 gst_basertppayload_setcaps); |
|
238 gst_pad_set_getcaps_function (basertppayload->sinkpad, |
|
239 gst_basertppayload_getcaps); |
|
240 gst_pad_set_event_function (basertppayload->sinkpad, |
|
241 gst_basertppayload_event); |
|
242 gst_pad_set_chain_function (basertppayload->sinkpad, |
|
243 gst_basertppayload_chain); |
|
244 gst_element_add_pad (GST_ELEMENT (basertppayload), basertppayload->sinkpad); |
|
245 |
|
246 basertppayload->seq_rand = g_rand_new (); |
|
247 basertppayload->ssrc_rand = g_rand_new (); |
|
248 basertppayload->ts_rand = g_rand_new (); |
|
249 |
|
250 basertppayload->mtu = DEFAULT_MTU; |
|
251 basertppayload->pt = DEFAULT_PT; |
|
252 basertppayload->seqnum_offset = DEFAULT_SEQNUM_OFFSET; |
|
253 basertppayload->ssrc = DEFAULT_SSRC; |
|
254 basertppayload->ts_offset = DEFAULT_TIMESTAMP_OFFSET; |
|
255 priv->seqnum_offset_random = (basertppayload->seqnum_offset == -1); |
|
256 priv->ts_offset_random = (basertppayload->ts_offset == -1); |
|
257 priv->ssrc_random = (basertppayload->ssrc == -1); |
|
258 |
|
259 basertppayload->max_ptime = DEFAULT_MAX_PTIME; |
|
260 basertppayload->min_ptime = DEFAULT_MIN_PTIME; |
|
261 |
|
262 basertppayload->media = NULL; |
|
263 basertppayload->encoding_name = NULL; |
|
264 |
|
265 basertppayload->clock_rate = 0; |
|
266 } |
|
267 |
|
268 static void |
|
269 gst_basertppayload_finalize (GObject * object) |
|
270 { |
|
271 GstBaseRTPPayload *basertppayload; |
|
272 |
|
273 basertppayload = GST_BASE_RTP_PAYLOAD (object); |
|
274 |
|
275 g_rand_free (basertppayload->seq_rand); |
|
276 basertppayload->seq_rand = NULL; |
|
277 g_rand_free (basertppayload->ssrc_rand); |
|
278 basertppayload->ssrc_rand = NULL; |
|
279 g_rand_free (basertppayload->ts_rand); |
|
280 basertppayload->ts_rand = NULL; |
|
281 |
|
282 g_free (basertppayload->media); |
|
283 basertppayload->media = NULL; |
|
284 g_free (basertppayload->encoding_name); |
|
285 basertppayload->encoding_name = NULL; |
|
286 |
|
287 G_OBJECT_CLASS (parent_class)->finalize (object); |
|
288 } |
|
289 |
|
290 static gboolean |
|
291 gst_basertppayload_setcaps (GstPad * pad, GstCaps * caps) |
|
292 { |
|
293 GstBaseRTPPayload *basertppayload; |
|
294 GstBaseRTPPayloadClass *basertppayload_class; |
|
295 gboolean ret = TRUE; |
|
296 |
|
297 GST_DEBUG_OBJECT (pad, "setting caps %" GST_PTR_FORMAT, caps); |
|
298 basertppayload = GST_BASE_RTP_PAYLOAD (gst_pad_get_parent (pad)); |
|
299 basertppayload_class = GST_BASE_RTP_PAYLOAD_GET_CLASS (basertppayload); |
|
300 |
|
301 if (basertppayload_class->set_caps) |
|
302 ret = basertppayload_class->set_caps (basertppayload, caps); |
|
303 |
|
304 gst_object_unref (basertppayload); |
|
305 |
|
306 return ret; |
|
307 } |
|
308 |
|
309 static GstCaps * |
|
310 gst_basertppayload_getcaps (GstPad * pad) |
|
311 { |
|
312 GstBaseRTPPayload *basertppayload; |
|
313 GstBaseRTPPayloadClass *basertppayload_class; |
|
314 GstCaps *caps = NULL; |
|
315 |
|
316 GST_DEBUG_OBJECT (pad, "getting caps"); |
|
317 |
|
318 basertppayload = GST_BASE_RTP_PAYLOAD (gst_pad_get_parent (pad)); |
|
319 basertppayload_class = GST_BASE_RTP_PAYLOAD_GET_CLASS (basertppayload); |
|
320 |
|
321 if (basertppayload_class->get_caps) |
|
322 caps = basertppayload_class->get_caps (basertppayload, pad); |
|
323 |
|
324 if (!caps) { |
|
325 caps = GST_PAD_TEMPLATE_CAPS (GST_PAD_PAD_TEMPLATE (pad)); |
|
326 GST_DEBUG_OBJECT (pad, |
|
327 "using pad template %p with caps %p %" GST_PTR_FORMAT, |
|
328 GST_PAD_PAD_TEMPLATE (pad), caps, caps); |
|
329 |
|
330 caps = gst_caps_ref (caps); |
|
331 } |
|
332 |
|
333 gst_object_unref (basertppayload); |
|
334 |
|
335 return caps; |
|
336 } |
|
337 |
|
338 static gboolean |
|
339 gst_basertppayload_event (GstPad * pad, GstEvent * event) |
|
340 { |
|
341 GstBaseRTPPayload *basertppayload; |
|
342 GstBaseRTPPayloadClass *basertppayload_class; |
|
343 gboolean res; |
|
344 |
|
345 basertppayload = GST_BASE_RTP_PAYLOAD (gst_pad_get_parent (pad)); |
|
346 basertppayload_class = GST_BASE_RTP_PAYLOAD_GET_CLASS (basertppayload); |
|
347 |
|
348 if (basertppayload_class->handle_event) { |
|
349 res = basertppayload_class->handle_event (pad, event); |
|
350 if (res) |
|
351 goto done; |
|
352 } |
|
353 |
|
354 switch (GST_EVENT_TYPE (event)) { |
|
355 case GST_EVENT_FLUSH_START: |
|
356 res = gst_pad_event_default (pad, event); |
|
357 break; |
|
358 case GST_EVENT_FLUSH_STOP: |
|
359 res = gst_pad_event_default (pad, event); |
|
360 gst_segment_init (&basertppayload->segment, GST_FORMAT_UNDEFINED); |
|
361 break; |
|
362 case GST_EVENT_NEWSEGMENT: |
|
363 { |
|
364 gboolean update; |
|
365 gdouble rate; |
|
366 GstFormat fmt; |
|
367 gint64 start, stop, position; |
|
368 |
|
369 gst_event_parse_new_segment (event, &update, &rate, &fmt, &start, &stop, |
|
370 &position); |
|
371 gst_segment_set_newsegment (&basertppayload->segment, update, rate, fmt, |
|
372 start, stop, position); |
|
373 |
|
374 /* fallthrough */ |
|
375 } |
|
376 default: |
|
377 res = gst_pad_event_default (pad, event); |
|
378 break; |
|
379 } |
|
380 |
|
381 done: |
|
382 gst_object_unref (basertppayload); |
|
383 |
|
384 return res; |
|
385 } |
|
386 |
|
387 |
|
388 static GstFlowReturn |
|
389 gst_basertppayload_chain (GstPad * pad, GstBuffer * buffer) |
|
390 { |
|
391 GstBaseRTPPayload *basertppayload; |
|
392 GstBaseRTPPayloadClass *basertppayload_class; |
|
393 GstFlowReturn ret; |
|
394 |
|
395 basertppayload = GST_BASE_RTP_PAYLOAD (gst_pad_get_parent (pad)); |
|
396 basertppayload_class = GST_BASE_RTP_PAYLOAD_GET_CLASS (basertppayload); |
|
397 |
|
398 if (!basertppayload_class->handle_buffer) |
|
399 goto no_function; |
|
400 |
|
401 ret = basertppayload_class->handle_buffer (basertppayload, buffer); |
|
402 |
|
403 gst_object_unref (basertppayload); |
|
404 |
|
405 return ret; |
|
406 |
|
407 /* ERRORS */ |
|
408 no_function: |
|
409 { |
|
410 GST_ELEMENT_ERROR (basertppayload, STREAM, NOT_IMPLEMENTED, (NULL), |
|
411 ("subclass did not implement handle_buffer function")); |
|
412 gst_object_unref (basertppayload); |
|
413 gst_buffer_unref (buffer); |
|
414 return GST_FLOW_ERROR; |
|
415 } |
|
416 } |
|
417 |
|
418 /** |
|
419 * gst_basertppayload_set_options: |
|
420 * @payload: a #GstBaseRTPPayload |
|
421 * @media: the media type (typically "audio" or "video") |
|
422 * @dynamic: if the payload type is dynamic |
|
423 * @encoding_name: the encoding name |
|
424 * @clock_rate: the clock rate of the media |
|
425 * |
|
426 * Set the rtp options of the payloader. These options will be set in the caps |
|
427 * of the payloader. Subclasses must call this method before calling |
|
428 * gst_basertppayload_push() or gst_basertppayload_set_outcaps(). |
|
429 */ |
|
430 #ifdef __SYMBIAN32__ |
|
431 EXPORT_C |
|
432 #endif |
|
433 |
|
434 void |
|
435 gst_basertppayload_set_options (GstBaseRTPPayload * payload, |
|
436 gchar * media, gboolean dynamic, gchar * encoding_name, guint32 clock_rate) |
|
437 { |
|
438 g_return_if_fail (payload != NULL); |
|
439 g_return_if_fail (clock_rate != 0); |
|
440 |
|
441 g_free (payload->media); |
|
442 payload->media = g_strdup (media); |
|
443 payload->dynamic = dynamic; |
|
444 g_free (payload->encoding_name); |
|
445 payload->encoding_name = g_strdup (encoding_name); |
|
446 payload->clock_rate = clock_rate; |
|
447 } |
|
448 |
|
449 static gboolean |
|
450 copy_fixed (GQuark field_id, const GValue * value, GstStructure * dest) |
|
451 { |
|
452 if (gst_value_is_fixed (value)) { |
|
453 gst_structure_id_set_value (dest, field_id, value); |
|
454 } |
|
455 return TRUE; |
|
456 } |
|
457 |
|
458 /** |
|
459 * gst_basertppayload_set_outcaps: |
|
460 * @payload: a #GstBaseRTPPayload |
|
461 * @fieldname: the first field name or %NULL |
|
462 * @...: field values |
|
463 * |
|
464 * Configure the output caps with the optional parameters. |
|
465 * |
|
466 * Variable arguments should be in the form field name, field type |
|
467 * (as a GType), value(s). The last variable argument should be NULL. |
|
468 * |
|
469 * Returns: %TRUE if the caps could be set. |
|
470 */ |
|
471 #ifdef __SYMBIAN32__ |
|
472 EXPORT_C |
|
473 #endif |
|
474 |
|
475 gboolean |
|
476 gst_basertppayload_set_outcaps (GstBaseRTPPayload * payload, gchar * fieldname, |
|
477 ...) |
|
478 { |
|
479 GstCaps *srccaps, *peercaps; |
|
480 |
|
481 /* fill in the defaults, there properties cannot be negotiated. */ |
|
482 srccaps = gst_caps_new_simple ("application/x-rtp", |
|
483 "media", G_TYPE_STRING, payload->media, |
|
484 "clock-rate", G_TYPE_INT, payload->clock_rate, |
|
485 "encoding-name", G_TYPE_STRING, payload->encoding_name, NULL); |
|
486 |
|
487 GST_DEBUG_OBJECT (payload, "defaults: %" GST_PTR_FORMAT, srccaps); |
|
488 |
|
489 if (fieldname) { |
|
490 va_list varargs; |
|
491 |
|
492 /* override with custom properties */ |
|
493 va_start (varargs, fieldname); |
|
494 gst_caps_set_simple_valist (srccaps, fieldname, varargs); |
|
495 va_end (varargs); |
|
496 |
|
497 GST_DEBUG_OBJECT (payload, "custom added: %" GST_PTR_FORMAT, srccaps); |
|
498 } |
|
499 |
|
500 /* the peer caps can override some of the defaults */ |
|
501 peercaps = gst_pad_peer_get_caps (payload->srcpad); |
|
502 if (peercaps == NULL) { |
|
503 /* no peer caps, just add the other properties */ |
|
504 gst_caps_set_simple (srccaps, |
|
505 "payload", G_TYPE_INT, GST_BASE_RTP_PAYLOAD_PT (payload), |
|
506 "ssrc", G_TYPE_UINT, payload->current_ssrc, |
|
507 "clock-base", G_TYPE_UINT, payload->ts_base, |
|
508 "seqnum-base", G_TYPE_UINT, payload->seqnum_base, NULL); |
|
509 |
|
510 GST_DEBUG_OBJECT (payload, "no peer caps: %" GST_PTR_FORMAT, srccaps); |
|
511 } else { |
|
512 GstCaps *temp; |
|
513 GstStructure *s, *d; |
|
514 const GValue *value; |
|
515 gint pt; |
|
516 |
|
517 /* peer provides caps we can use to fixate, intersect. This always returns a |
|
518 * writable caps. */ |
|
519 temp = gst_caps_intersect (srccaps, peercaps); |
|
520 gst_caps_unref (srccaps); |
|
521 gst_caps_unref (peercaps); |
|
522 |
|
523 /* now fixate, start by taking the first caps */ |
|
524 gst_caps_truncate (temp); |
|
525 |
|
526 /* get first structure */ |
|
527 s = gst_caps_get_structure (temp, 0); |
|
528 |
|
529 if (gst_structure_get_int (s, "payload", &pt)) { |
|
530 /* use peer pt */ |
|
531 GST_BASE_RTP_PAYLOAD_PT (payload) = pt; |
|
532 GST_LOG_OBJECT (payload, "using peer pt %d", pt); |
|
533 } else { |
|
534 if (gst_structure_has_field (s, "payload")) { |
|
535 /* can only fixate if there is a field */ |
|
536 gst_structure_fixate_field_nearest_int (s, "payload", |
|
537 GST_BASE_RTP_PAYLOAD_PT (payload)); |
|
538 gst_structure_get_int (s, "payload", &pt); |
|
539 GST_LOG_OBJECT (payload, "using peer pt %d", pt); |
|
540 } else { |
|
541 /* no pt field, use the internal pt */ |
|
542 pt = GST_BASE_RTP_PAYLOAD_PT (payload); |
|
543 gst_structure_set (s, "payload", G_TYPE_INT, pt, NULL); |
|
544 GST_LOG_OBJECT (payload, "using internal pt %d", pt); |
|
545 } |
|
546 } |
|
547 |
|
548 if (gst_structure_has_field_typed (s, "ssrc", G_TYPE_UINT)) { |
|
549 value = gst_structure_get_value (s, "ssrc"); |
|
550 payload->current_ssrc = g_value_get_uint (value); |
|
551 GST_LOG_OBJECT (payload, "using peer ssrc %08x", payload->current_ssrc); |
|
552 } else { |
|
553 /* FIXME, fixate_nearest_uint would be even better */ |
|
554 gst_structure_set (s, "ssrc", G_TYPE_UINT, payload->current_ssrc, NULL); |
|
555 GST_LOG_OBJECT (payload, "using internal ssrc %08x", |
|
556 payload->current_ssrc); |
|
557 } |
|
558 |
|
559 if (gst_structure_has_field_typed (s, "clock-base", G_TYPE_UINT)) { |
|
560 value = gst_structure_get_value (s, "clock-base"); |
|
561 payload->ts_base = g_value_get_uint (value); |
|
562 GST_LOG_OBJECT (payload, "using peer clock-base %u", payload->ts_base); |
|
563 } else { |
|
564 /* FIXME, fixate_nearest_uint would be even better */ |
|
565 gst_structure_set (s, "clock-base", G_TYPE_UINT, payload->ts_base, NULL); |
|
566 GST_LOG_OBJECT (payload, "using internal clock-base %u", |
|
567 payload->ts_base); |
|
568 } |
|
569 if (gst_structure_has_field_typed (s, "seqnum-base", G_TYPE_UINT)) { |
|
570 value = gst_structure_get_value (s, "seqnum-base"); |
|
571 payload->seqnum_base = g_value_get_uint (value); |
|
572 GST_LOG_OBJECT (payload, "using peer seqnum-base %u", |
|
573 payload->seqnum_base); |
|
574 } else { |
|
575 /* FIXME, fixate_nearest_uint would be even better */ |
|
576 gst_structure_set (s, "seqnum-base", G_TYPE_UINT, payload->seqnum_base, |
|
577 NULL); |
|
578 GST_LOG_OBJECT (payload, "using internal seqnum-base %u", |
|
579 payload->seqnum_base); |
|
580 } |
|
581 |
|
582 /* make the target caps by copying over all the fixed caps, removing the |
|
583 * unfixed caps. */ |
|
584 srccaps = gst_caps_new_simple (gst_structure_get_name (s), NULL); |
|
585 d = gst_caps_get_structure (srccaps, 0); |
|
586 |
|
587 gst_structure_foreach (s, (GstStructureForeachFunc) copy_fixed, d); |
|
588 |
|
589 gst_caps_unref (temp); |
|
590 |
|
591 GST_DEBUG_OBJECT (payload, "with peer caps: %" GST_PTR_FORMAT, srccaps); |
|
592 } |
|
593 |
|
594 gst_pad_set_caps (GST_BASE_RTP_PAYLOAD_SRCPAD (payload), srccaps); |
|
595 gst_caps_unref (srccaps); |
|
596 |
|
597 return TRUE; |
|
598 } |
|
599 |
|
600 /** |
|
601 * gst_basertppayload_is_filled: |
|
602 * @payload: a #GstBaseRTPPayload |
|
603 * @size: the size of the packet |
|
604 * @duration: the duration of the packet |
|
605 * |
|
606 * Check if the packet with @size and @duration would exceed the configure |
|
607 * maximum size. |
|
608 * |
|
609 * Returns: %TRUE if the packet of @size and @duration would exceed the |
|
610 * configured MTU or max_ptime. |
|
611 */ |
|
612 #ifdef __SYMBIAN32__ |
|
613 EXPORT_C |
|
614 #endif |
|
615 |
|
616 gboolean |
|
617 gst_basertppayload_is_filled (GstBaseRTPPayload * payload, |
|
618 guint size, GstClockTime duration) |
|
619 { |
|
620 if (size > payload->mtu) |
|
621 return TRUE; |
|
622 |
|
623 if (payload->max_ptime != -1 && duration >= payload->max_ptime) |
|
624 return TRUE; |
|
625 |
|
626 return FALSE; |
|
627 } |
|
628 |
|
629 /** |
|
630 * gst_basertppayload_push: |
|
631 * @payload: a #GstBaseRTPPayload |
|
632 * @buffer: a #GstBuffer |
|
633 * |
|
634 * Push @buffer to the peer element of the payloader. The SSRC, payload type, |
|
635 * seqnum and timestamp of the RTP buffer will be updated first. |
|
636 * |
|
637 * This function takes ownership of @buffer. |
|
638 * |
|
639 * Returns: a #GstFlowReturn. |
|
640 */ |
|
641 #ifdef __SYMBIAN32__ |
|
642 EXPORT_C |
|
643 #endif |
|
644 |
|
645 GstFlowReturn |
|
646 gst_basertppayload_push (GstBaseRTPPayload * payload, GstBuffer * buffer) |
|
647 { |
|
648 GstFlowReturn res; |
|
649 GstClockTime timestamp; |
|
650 guint32 rtptime; |
|
651 GstBaseRTPPayloadPrivate *priv; |
|
652 |
|
653 if (payload->clock_rate == 0) |
|
654 goto no_rate; |
|
655 |
|
656 priv = payload->priv; |
|
657 |
|
658 gst_rtp_buffer_set_ssrc (buffer, payload->current_ssrc); |
|
659 |
|
660 gst_rtp_buffer_set_payload_type (buffer, payload->pt); |
|
661 |
|
662 /* update first, so that the property is set to the last |
|
663 * seqnum pushed */ |
|
664 payload->seqnum = priv->next_seqnum; |
|
665 gst_rtp_buffer_set_seq (buffer, payload->seqnum); |
|
666 |
|
667 /* can wrap around, which is perfectly fine */ |
|
668 priv->next_seqnum++; |
|
669 |
|
670 /* add our random offset to the timestamp */ |
|
671 rtptime = payload->ts_base; |
|
672 |
|
673 timestamp = GST_BUFFER_TIMESTAMP (buffer); |
|
674 if (GST_CLOCK_TIME_IS_VALID (timestamp)) { |
|
675 gint64 rtime; |
|
676 |
|
677 rtime = gst_segment_to_running_time (&payload->segment, GST_FORMAT_TIME, |
|
678 timestamp); |
|
679 |
|
680 /* take first timestamp as base, we want to calculate the RTP timestamp |
|
681 * starting from the ts_base */ |
|
682 if (priv->rt_base == -1) { |
|
683 priv->rt_base = rtime; |
|
684 GST_LOG_OBJECT (payload, "first timestamp %" GST_TIME_FORMAT, |
|
685 GST_TIME_ARGS (rtime)); |
|
686 } |
|
687 rtime -= priv->rt_base; |
|
688 |
|
689 rtime = gst_util_uint64_scale_int (rtime, payload->clock_rate, GST_SECOND); |
|
690 |
|
691 /* add running_time in clock-rate units to the base timestamp */ |
|
692 rtptime += rtime; |
|
693 } else { |
|
694 /* no timestamp to convert, take previous timestamp */ |
|
695 rtptime = payload->timestamp; |
|
696 } |
|
697 gst_rtp_buffer_set_timestamp (buffer, rtptime); |
|
698 |
|
699 payload->timestamp = rtptime; |
|
700 |
|
701 /* set caps */ |
|
702 gst_buffer_set_caps (buffer, GST_PAD_CAPS (payload->srcpad)); |
|
703 |
|
704 GST_LOG_OBJECT (payload, |
|
705 "Pushing packet size %d, seq=%d, rtptime=%u, timestamp %" GST_TIME_FORMAT, |
|
706 GST_BUFFER_SIZE (buffer), payload->seqnum, rtptime, |
|
707 GST_TIME_ARGS (timestamp)); |
|
708 |
|
709 res = gst_pad_push (payload->srcpad, buffer); |
|
710 |
|
711 return res; |
|
712 |
|
713 /* ERRORS */ |
|
714 no_rate: |
|
715 { |
|
716 GST_ELEMENT_ERROR (payload, STREAM, NOT_IMPLEMENTED, (NULL), |
|
717 ("subclass did not specify clock-rate")); |
|
718 gst_buffer_unref (buffer); |
|
719 return GST_FLOW_ERROR; |
|
720 } |
|
721 } |
|
722 |
|
723 static void |
|
724 gst_basertppayload_set_property (GObject * object, guint prop_id, |
|
725 const GValue * value, GParamSpec * pspec) |
|
726 { |
|
727 GstBaseRTPPayload *basertppayload; |
|
728 GstBaseRTPPayloadPrivate *priv; |
|
729 gint64 val; |
|
730 |
|
731 basertppayload = GST_BASE_RTP_PAYLOAD (object); |
|
732 priv = basertppayload->priv; |
|
733 |
|
734 switch (prop_id) { |
|
735 case PROP_MTU: |
|
736 basertppayload->mtu = g_value_get_uint (value); |
|
737 break; |
|
738 case PROP_PT: |
|
739 basertppayload->pt = g_value_get_uint (value); |
|
740 break; |
|
741 case PROP_SSRC: |
|
742 val = g_value_get_uint (value); |
|
743 basertppayload->ssrc = val; |
|
744 priv->ssrc_random = FALSE; |
|
745 break; |
|
746 case PROP_TIMESTAMP_OFFSET: |
|
747 val = g_value_get_uint (value); |
|
748 basertppayload->ts_offset = val; |
|
749 priv->ts_offset_random = FALSE; |
|
750 break; |
|
751 case PROP_SEQNUM_OFFSET: |
|
752 val = g_value_get_int (value); |
|
753 basertppayload->seqnum_offset = val; |
|
754 priv->seqnum_offset_random = (val == -1); |
|
755 GST_DEBUG_OBJECT (basertppayload, "seqnum offset 0x%04x, random %d", |
|
756 basertppayload->seqnum_offset, priv->seqnum_offset_random); |
|
757 break; |
|
758 case PROP_MAX_PTIME: |
|
759 basertppayload->max_ptime = g_value_get_int64 (value); |
|
760 break; |
|
761 case PROP_MIN_PTIME: |
|
762 basertppayload->min_ptime = g_value_get_int64 (value); |
|
763 break; |
|
764 default: |
|
765 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
|
766 break; |
|
767 } |
|
768 } |
|
769 |
|
770 static void |
|
771 gst_basertppayload_get_property (GObject * object, guint prop_id, |
|
772 GValue * value, GParamSpec * pspec) |
|
773 { |
|
774 GstBaseRTPPayload *basertppayload; |
|
775 GstBaseRTPPayloadPrivate *priv; |
|
776 |
|
777 basertppayload = GST_BASE_RTP_PAYLOAD (object); |
|
778 priv = basertppayload->priv; |
|
779 |
|
780 switch (prop_id) { |
|
781 case PROP_MTU: |
|
782 g_value_set_uint (value, basertppayload->mtu); |
|
783 break; |
|
784 case PROP_PT: |
|
785 g_value_set_uint (value, basertppayload->pt); |
|
786 break; |
|
787 case PROP_SSRC: |
|
788 if (priv->ssrc_random) |
|
789 g_value_set_uint (value, -1); |
|
790 else |
|
791 g_value_set_uint (value, basertppayload->ssrc); |
|
792 break; |
|
793 case PROP_TIMESTAMP_OFFSET: |
|
794 if (priv->ts_offset_random) |
|
795 g_value_set_uint (value, -1); |
|
796 else |
|
797 g_value_set_uint (value, (guint32) basertppayload->ts_offset); |
|
798 break; |
|
799 case PROP_SEQNUM_OFFSET: |
|
800 if (priv->seqnum_offset_random) |
|
801 g_value_set_int (value, -1); |
|
802 else |
|
803 g_value_set_int (value, (guint16) basertppayload->seqnum_offset); |
|
804 break; |
|
805 case PROP_MAX_PTIME: |
|
806 g_value_set_int64 (value, basertppayload->max_ptime); |
|
807 break; |
|
808 case PROP_MIN_PTIME: |
|
809 g_value_set_int64 (value, basertppayload->min_ptime); |
|
810 break; |
|
811 case PROP_TIMESTAMP: |
|
812 g_value_set_uint (value, basertppayload->timestamp); |
|
813 break; |
|
814 case PROP_SEQNUM: |
|
815 g_value_set_uint (value, basertppayload->seqnum); |
|
816 break; |
|
817 default: |
|
818 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
|
819 break; |
|
820 } |
|
821 } |
|
822 |
|
823 static GstStateChangeReturn |
|
824 gst_basertppayload_change_state (GstElement * element, |
|
825 GstStateChange transition) |
|
826 { |
|
827 GstBaseRTPPayload *basertppayload; |
|
828 GstBaseRTPPayloadPrivate *priv; |
|
829 GstStateChangeReturn ret; |
|
830 |
|
831 basertppayload = GST_BASE_RTP_PAYLOAD (element); |
|
832 priv = basertppayload->priv; |
|
833 |
|
834 switch (transition) { |
|
835 case GST_STATE_CHANGE_NULL_TO_READY: |
|
836 break; |
|
837 case GST_STATE_CHANGE_READY_TO_PAUSED: |
|
838 gst_segment_init (&basertppayload->segment, GST_FORMAT_UNDEFINED); |
|
839 |
|
840 if (priv->seqnum_offset_random) |
|
841 basertppayload->seqnum_base = |
|
842 g_rand_int_range (basertppayload->seq_rand, 0, G_MAXUINT16); |
|
843 else |
|
844 basertppayload->seqnum_base = basertppayload->seqnum_offset; |
|
845 priv->next_seqnum = basertppayload->seqnum_base; |
|
846 |
|
847 if (priv->ssrc_random) |
|
848 basertppayload->current_ssrc = g_rand_int (basertppayload->ssrc_rand); |
|
849 else |
|
850 basertppayload->current_ssrc = basertppayload->ssrc; |
|
851 |
|
852 if (priv->ts_offset_random) |
|
853 basertppayload->ts_base = g_rand_int (basertppayload->ts_rand); |
|
854 else |
|
855 basertppayload->ts_base = basertppayload->ts_offset; |
|
856 |
|
857 priv->rt_base = -1; |
|
858 break; |
|
859 default: |
|
860 break; |
|
861 } |
|
862 |
|
863 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); |
|
864 |
|
865 switch (transition) { |
|
866 case GST_STATE_CHANGE_READY_TO_NULL: |
|
867 break; |
|
868 default: |
|
869 break; |
|
870 } |
|
871 return ret; |
|
872 } |