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:gstrtpbasepayload
17 * @title: GstRTPBasePayload
18 * @short_description: Base class for RTP payloader
19 *
20 * Provides a base class for RTP payloaders
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <string.h>
28
29 #include <gst/rtp/gstrtpbuffer.h>
30
31 #include "gstrtpbasepayload.h"
32 #include "gstrtpmeta.h"
33
34 GST_DEBUG_CATEGORY_STATIC (rtpbasepayload_debug);
35 #define GST_CAT_DEFAULT (rtpbasepayload_debug)
36
37 struct _GstRTPBasePayloadPrivate
38 {
39 gboolean ts_offset_random;
40 gboolean seqnum_offset_random;
41 gboolean ssrc_random;
42 guint16 next_seqnum;
43 gboolean perfect_rtptime;
44 gint notified_first_timestamp;
45
46 gboolean pt_set;
47
48 gboolean source_info;
49 GstBuffer *input_meta_buffer;
50
51 guint64 base_offset;
52 gint64 base_rtime;
53 guint64 base_rtime_hz;
54 guint64 running_time;
55
56 gint64 prop_max_ptime;
57 gint64 caps_max_ptime;
58
59 gboolean onvif_no_rate_control;
60
61 gboolean negotiated;
62
63 gboolean delay_segment;
64 GstEvent *pending_segment;
65
66 GstCaps *subclass_srccaps;
67 GstCaps *sinkcaps;
68 };
69
70 /* RTPBasePayload signals and args */
71 enum
72 {
73 /* FILL ME */
74 LAST_SIGNAL
75 };
76
77 /* FIXME 0.11, a better default is the Ethernet MTU of
78 * 1500 - sizeof(headers) as pointed out by marcelm in IRC:
79 * So an Ethernet MTU of 1500, minus 60 for the max IP, minus 8 for UDP, gives
80 * 1432 bytes or so. And that should be adjusted downward further for other
81 * encapsulations like PPPoE, so 1400 at most.
82 */
83 #define DEFAULT_MTU 1400
84 #define DEFAULT_PT 96
85 #define DEFAULT_SSRC -1
86 #define DEFAULT_TIMESTAMP_OFFSET -1
87 #define DEFAULT_SEQNUM_OFFSET -1
88 #define DEFAULT_MAX_PTIME -1
89 #define DEFAULT_MIN_PTIME 0
90 #define DEFAULT_PERFECT_RTPTIME TRUE
91 #define DEFAULT_PTIME_MULTIPLE 0
92 #define DEFAULT_RUNNING_TIME GST_CLOCK_TIME_NONE
93 #define DEFAULT_SOURCE_INFO FALSE
94 #define DEFAULT_ONVIF_NO_RATE_CONTROL FALSE
95
96 enum
97 {
98 PROP_0,
99 PROP_MTU,
100 PROP_PT,
101 PROP_SSRC,
102 PROP_TIMESTAMP_OFFSET,
103 PROP_SEQNUM_OFFSET,
104 PROP_MAX_PTIME,
105 PROP_MIN_PTIME,
106 PROP_TIMESTAMP,
107 PROP_SEQNUM,
108 PROP_PERFECT_RTPTIME,
109 PROP_PTIME_MULTIPLE,
110 PROP_STATS,
111 PROP_SOURCE_INFO,
112 PROP_ONVIF_NO_RATE_CONTROL,
113 PROP_LAST
114 };
115
116 static void gst_rtp_base_payload_class_init (GstRTPBasePayloadClass * klass);
117 static void gst_rtp_base_payload_init (GstRTPBasePayload * rtpbasepayload,
118 gpointer g_class);
119 static void gst_rtp_base_payload_finalize (GObject * object);
120
121 static GstCaps *gst_rtp_base_payload_getcaps_default (GstRTPBasePayload *
122 rtpbasepayload, GstPad * pad, GstCaps * filter);
123
124 static gboolean gst_rtp_base_payload_sink_event_default (GstRTPBasePayload *
125 rtpbasepayload, GstEvent * event);
126 static gboolean gst_rtp_base_payload_sink_event (GstPad * pad,
127 GstObject * parent, GstEvent * event);
128 static gboolean gst_rtp_base_payload_src_event_default (GstRTPBasePayload *
129 rtpbasepayload, GstEvent * event);
130 static gboolean gst_rtp_base_payload_src_event (GstPad * pad,
131 GstObject * parent, GstEvent * event);
132 static gboolean gst_rtp_base_payload_query_default (GstRTPBasePayload *
133 rtpbasepayload, GstPad * pad, GstQuery * query);
134 static gboolean gst_rtp_base_payload_query (GstPad * pad, GstObject * parent,
135 GstQuery * query);
136 static GstFlowReturn gst_rtp_base_payload_chain (GstPad * pad,
137 GstObject * parent, GstBuffer * buffer);
138
139 static void gst_rtp_base_payload_set_property (GObject * object, guint prop_id,
140 const GValue * value, GParamSpec * pspec);
141 static void gst_rtp_base_payload_get_property (GObject * object, guint prop_id,
142 GValue * value, GParamSpec * pspec);
143
144 static GstStateChangeReturn gst_rtp_base_payload_change_state (GstElement *
145 element, GstStateChange transition);
146
147 static gboolean gst_rtp_base_payload_negotiate (GstRTPBasePayload * payload);
148
149
150 static GstElementClass *parent_class = NULL;
151 static gint private_offset = 0;
152
153 GType
gst_rtp_base_payload_get_type(void)154 gst_rtp_base_payload_get_type (void)
155 {
156 static GType rtpbasepayload_type = 0;
157
158 if (g_once_init_enter ((gsize *) & rtpbasepayload_type)) {
159 static const GTypeInfo rtpbasepayload_info = {
160 sizeof (GstRTPBasePayloadClass),
161 NULL,
162 NULL,
163 (GClassInitFunc) gst_rtp_base_payload_class_init,
164 NULL,
165 NULL,
166 sizeof (GstRTPBasePayload),
167 0,
168 (GInstanceInitFunc) gst_rtp_base_payload_init,
169 };
170 GType _type;
171
172 _type = g_type_register_static (GST_TYPE_ELEMENT, "GstRTPBasePayload",
173 &rtpbasepayload_info, G_TYPE_FLAG_ABSTRACT);
174
175 private_offset =
176 g_type_add_instance_private (_type, sizeof (GstRTPBasePayloadPrivate));
177
178 g_once_init_leave ((gsize *) & rtpbasepayload_type, _type);
179 }
180 return rtpbasepayload_type;
181 }
182
183 static inline GstRTPBasePayloadPrivate *
gst_rtp_base_payload_get_instance_private(GstRTPBasePayload * self)184 gst_rtp_base_payload_get_instance_private (GstRTPBasePayload * self)
185 {
186 return (G_STRUCT_MEMBER_P (self, private_offset));
187 }
188
189 static void
gst_rtp_base_payload_class_init(GstRTPBasePayloadClass * klass)190 gst_rtp_base_payload_class_init (GstRTPBasePayloadClass * klass)
191 {
192 GObjectClass *gobject_class;
193 GstElementClass *gstelement_class;
194
195 gobject_class = (GObjectClass *) klass;
196 gstelement_class = (GstElementClass *) klass;
197
198 if (private_offset != 0)
199 g_type_class_adjust_private_offset (klass, &private_offset);
200
201 parent_class = g_type_class_peek_parent (klass);
202
203 gobject_class->finalize = gst_rtp_base_payload_finalize;
204
205 gobject_class->set_property = gst_rtp_base_payload_set_property;
206 gobject_class->get_property = gst_rtp_base_payload_get_property;
207
208 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MTU,
209 g_param_spec_uint ("mtu", "MTU",
210 "Maximum size of one packet",
211 28, G_MAXUINT, DEFAULT_MTU,
212 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
213 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PT,
214 g_param_spec_uint ("pt", "payload type",
215 "The payload type of the packets", 0, 0x7f, DEFAULT_PT,
216 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
217 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SSRC,
218 g_param_spec_uint ("ssrc", "SSRC",
219 "The SSRC of the packets (default == random)", 0, G_MAXUINT32,
220 DEFAULT_SSRC, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
221 g_object_class_install_property (G_OBJECT_CLASS (klass),
222 PROP_TIMESTAMP_OFFSET, g_param_spec_uint ("timestamp-offset",
223 "Timestamp Offset",
224 "Offset to add to all outgoing timestamps (default = random)", 0,
225 G_MAXUINT32, DEFAULT_TIMESTAMP_OFFSET,
226 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
227 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SEQNUM_OFFSET,
228 g_param_spec_int ("seqnum-offset", "Sequence number Offset",
229 "Offset to add to all outgoing seqnum (-1 = random)", -1, G_MAXUINT16,
230 DEFAULT_SEQNUM_OFFSET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
231 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MAX_PTIME,
232 g_param_spec_int64 ("max-ptime", "Max packet time",
233 "Maximum duration of the packet data in ns (-1 = unlimited up to MTU)",
234 -1, G_MAXINT64, DEFAULT_MAX_PTIME,
235 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
236 /**
237 * GstRTPBasePayload:min-ptime:
238 *
239 * Minimum duration of the packet data in ns (can't go above MTU)
240 **/
241 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MIN_PTIME,
242 g_param_spec_int64 ("min-ptime", "Min packet time",
243 "Minimum duration of the packet data in ns (can't go above MTU)",
244 0, G_MAXINT64, DEFAULT_MIN_PTIME,
245 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
246
247 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TIMESTAMP,
248 g_param_spec_uint ("timestamp", "Timestamp",
249 "The RTP timestamp of the last processed packet",
250 0, G_MAXUINT32, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
251 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SEQNUM,
252 g_param_spec_uint ("seqnum", "Sequence number",
253 "The RTP sequence number of the last processed packet",
254 0, G_MAXUINT16, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
255
256 /**
257 * GstRTPBasePayload:perfect-rtptime:
258 *
259 * Try to use the offset fields to generate perfect RTP timestamps. When this
260 * option is disabled, RTP timestamps are generated from GST_BUFFER_PTS of
261 * each payloaded buffer. The PTSes of buffers may not necessarily increment
262 * with the amount of data in each input buffer, consider e.g. the case where
263 * the buffer arrives from a network which means that the PTS is unrelated to
264 * the amount of data. Because the RTP timestamps are generated from
265 * GST_BUFFER_PTS this can result in RTP timestamps that also don't increment
266 * with the amount of data in the payloaded packet. To circumvent this it is
267 * possible to set the perfect rtptime option enabled. When this option is
268 * enabled the payloader will increment the RTP timestamps based on
269 * GST_BUFFER_OFFSET which relates to the amount of data in each packet
270 * rather than the GST_BUFFER_PTS of each buffer and therefore the RTP
271 * timestamps will more closely correlate with the amount of data in each
272 * buffer. Currently GstRTPBasePayload is limited to handling perfect RTP
273 * timestamps for audio streams.
274 */
275 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PERFECT_RTPTIME,
276 g_param_spec_boolean ("perfect-rtptime", "Perfect RTP Time",
277 "Generate perfect RTP timestamps when possible",
278 DEFAULT_PERFECT_RTPTIME, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
279 /**
280 * GstRTPBasePayload:ptime-multiple:
281 *
282 * Force buffers to be multiples of this duration in ns (0 disables)
283 **/
284 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PTIME_MULTIPLE,
285 g_param_spec_int64 ("ptime-multiple", "Packet time multiple",
286 "Force buffers to be multiples of this duration in ns (0 disables)",
287 0, G_MAXINT64, DEFAULT_PTIME_MULTIPLE,
288 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
289
290 /**
291 * GstRTPBasePayload:stats:
292 *
293 * Various payloader statistics retrieved atomically (and are therefore
294 * synchroized with each other), these can be used e.g. to generate an
295 * RTP-Info header. This property return a GstStructure named
296 * application/x-rtp-payload-stats containing the following fields relating to
297 * the last processed buffer and current state of the stream being payloaded:
298 *
299 * * `clock-rate` :#G_TYPE_UINT, clock-rate of the stream
300 * * `running-time` :#G_TYPE_UINT64, running time
301 * * `seqnum` :#G_TYPE_UINT, sequence number, same as #GstRTPBasePayload:seqnum
302 * * `timestamp` :#G_TYPE_UINT, RTP timestamp, same as #GstRTPBasePayload:timestamp
303 * * `ssrc` :#G_TYPE_UINT, The SSRC in use
304 * * `pt` :#G_TYPE_UINT, The Payload type in use, same as #GstRTPBasePayload:pt
305 * * `seqnum-offset` :#G_TYPE_UINT, The current offset added to the seqnum
306 * * `timestamp-offset` :#G_TYPE_UINT, The current offset added to the timestamp
307 **/
308 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_STATS,
309 g_param_spec_boxed ("stats", "Statistics", "Various statistics",
310 GST_TYPE_STRUCTURE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
311
312 /**
313 * GstRTPBasePayload:source-info:
314 *
315 * Enable writing the CSRC field in allocated RTP header based on RTP source
316 * information found in the input buffer's #GstRTPSourceMeta.
317 *
318 * Since: 1.16
319 **/
320 g_object_class_install_property (gobject_class, PROP_SOURCE_INFO,
321 g_param_spec_boolean ("source-info", "RTP source information",
322 "Write CSRC based on buffer meta RTP source information",
323 DEFAULT_SOURCE_INFO, G_PARAM_READWRITE));
324
325 /**
326 * GstRTPBasePayload:onvif-no-rate-control:
327 *
328 * Make the payloader timestamp packets according to the Rate-Control=no
329 * behaviour specified in the ONVIF replay spec.
330 *
331 * Since: 1.16
332 */
333 g_object_class_install_property (G_OBJECT_CLASS (klass),
334 PROP_ONVIF_NO_RATE_CONTROL, g_param_spec_boolean ("onvif-no-rate-control",
335 "ONVIF no rate control",
336 "Enable ONVIF Rate-Control=no timestamping mode",
337 DEFAULT_ONVIF_NO_RATE_CONTROL,
338 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
339
340 gstelement_class->change_state = gst_rtp_base_payload_change_state;
341
342 klass->get_caps = gst_rtp_base_payload_getcaps_default;
343 klass->sink_event = gst_rtp_base_payload_sink_event_default;
344 klass->src_event = gst_rtp_base_payload_src_event_default;
345 klass->query = gst_rtp_base_payload_query_default;
346
347 GST_DEBUG_CATEGORY_INIT (rtpbasepayload_debug, "rtpbasepayload", 0,
348 "Base class for RTP Payloaders");
349 }
350
351 static void
gst_rtp_base_payload_init(GstRTPBasePayload * rtpbasepayload,gpointer g_class)352 gst_rtp_base_payload_init (GstRTPBasePayload * rtpbasepayload, gpointer g_class)
353 {
354 GstPadTemplate *templ;
355 GstRTPBasePayloadPrivate *priv;
356
357 rtpbasepayload->priv = priv =
358 gst_rtp_base_payload_get_instance_private (rtpbasepayload);
359
360 templ =
361 gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "src");
362 g_return_if_fail (templ != NULL);
363
364 rtpbasepayload->srcpad = gst_pad_new_from_template (templ, "src");
365 gst_pad_set_event_function (rtpbasepayload->srcpad,
366 gst_rtp_base_payload_src_event);
367 gst_element_add_pad (GST_ELEMENT (rtpbasepayload), rtpbasepayload->srcpad);
368
369 templ =
370 gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "sink");
371 g_return_if_fail (templ != NULL);
372
373 rtpbasepayload->sinkpad = gst_pad_new_from_template (templ, "sink");
374 gst_pad_set_chain_function (rtpbasepayload->sinkpad,
375 gst_rtp_base_payload_chain);
376 gst_pad_set_event_function (rtpbasepayload->sinkpad,
377 gst_rtp_base_payload_sink_event);
378 gst_pad_set_query_function (rtpbasepayload->sinkpad,
379 gst_rtp_base_payload_query);
380 gst_element_add_pad (GST_ELEMENT (rtpbasepayload), rtpbasepayload->sinkpad);
381
382 rtpbasepayload->mtu = DEFAULT_MTU;
383 rtpbasepayload->pt = DEFAULT_PT;
384 rtpbasepayload->seqnum_offset = DEFAULT_SEQNUM_OFFSET;
385 rtpbasepayload->ssrc = DEFAULT_SSRC;
386 rtpbasepayload->ts_offset = DEFAULT_TIMESTAMP_OFFSET;
387 priv->running_time = DEFAULT_RUNNING_TIME;
388 priv->seqnum_offset_random = (rtpbasepayload->seqnum_offset == -1);
389 priv->ts_offset_random = (rtpbasepayload->ts_offset == -1);
390 priv->ssrc_random = (rtpbasepayload->ssrc == -1);
391 priv->pt_set = FALSE;
392 priv->source_info = DEFAULT_SOURCE_INFO;
393
394 rtpbasepayload->max_ptime = DEFAULT_MAX_PTIME;
395 rtpbasepayload->min_ptime = DEFAULT_MIN_PTIME;
396 rtpbasepayload->priv->perfect_rtptime = DEFAULT_PERFECT_RTPTIME;
397 rtpbasepayload->ptime_multiple = DEFAULT_PTIME_MULTIPLE;
398 rtpbasepayload->priv->base_offset = GST_BUFFER_OFFSET_NONE;
399 rtpbasepayload->priv->base_rtime_hz = GST_BUFFER_OFFSET_NONE;
400 rtpbasepayload->priv->onvif_no_rate_control = DEFAULT_ONVIF_NO_RATE_CONTROL;
401
402 rtpbasepayload->media = NULL;
403 rtpbasepayload->encoding_name = NULL;
404
405 rtpbasepayload->clock_rate = 0;
406
407 rtpbasepayload->priv->caps_max_ptime = DEFAULT_MAX_PTIME;
408 rtpbasepayload->priv->prop_max_ptime = DEFAULT_MAX_PTIME;
409 }
410
411 static void
gst_rtp_base_payload_finalize(GObject * object)412 gst_rtp_base_payload_finalize (GObject * object)
413 {
414 GstRTPBasePayload *rtpbasepayload;
415
416 rtpbasepayload = GST_RTP_BASE_PAYLOAD (object);
417
418 g_free (rtpbasepayload->media);
419 rtpbasepayload->media = NULL;
420 g_free (rtpbasepayload->encoding_name);
421 rtpbasepayload->encoding_name = NULL;
422
423 gst_caps_replace (&rtpbasepayload->priv->subclass_srccaps, NULL);
424 gst_caps_replace (&rtpbasepayload->priv->sinkcaps, NULL);
425
426 G_OBJECT_CLASS (parent_class)->finalize (object);
427 }
428
429 static GstCaps *
gst_rtp_base_payload_getcaps_default(GstRTPBasePayload * rtpbasepayload,GstPad * pad,GstCaps * filter)430 gst_rtp_base_payload_getcaps_default (GstRTPBasePayload * rtpbasepayload,
431 GstPad * pad, GstCaps * filter)
432 {
433 GstCaps *caps;
434
435 caps = GST_PAD_TEMPLATE_CAPS (GST_PAD_PAD_TEMPLATE (pad));
436 GST_DEBUG_OBJECT (pad,
437 "using pad template %p with caps %p %" GST_PTR_FORMAT,
438 GST_PAD_PAD_TEMPLATE (pad), caps, caps);
439
440 if (filter)
441 caps = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
442 else
443 caps = gst_caps_ref (caps);
444
445 return caps;
446 }
447
448 static gboolean
gst_rtp_base_payload_sink_event_default(GstRTPBasePayload * rtpbasepayload,GstEvent * event)449 gst_rtp_base_payload_sink_event_default (GstRTPBasePayload * rtpbasepayload,
450 GstEvent * event)
451 {
452 GstObject *parent = GST_OBJECT_CAST (rtpbasepayload);
453 gboolean res = FALSE;
454
455 switch (GST_EVENT_TYPE (event)) {
456 case GST_EVENT_FLUSH_START:
457 res = gst_pad_event_default (rtpbasepayload->sinkpad, parent, event);
458 break;
459 case GST_EVENT_FLUSH_STOP:
460 res = gst_pad_event_default (rtpbasepayload->sinkpad, parent, event);
461 gst_segment_init (&rtpbasepayload->segment, GST_FORMAT_UNDEFINED);
462 gst_event_replace (&rtpbasepayload->priv->pending_segment, NULL);
463 break;
464 case GST_EVENT_CAPS:
465 {
466 GstRTPBasePayloadClass *rtpbasepayload_class;
467 GstCaps *caps;
468
469 gst_event_parse_caps (event, &caps);
470 GST_DEBUG_OBJECT (rtpbasepayload, "setting caps %" GST_PTR_FORMAT, caps);
471
472 gst_caps_replace (&rtpbasepayload->priv->sinkcaps, caps);
473
474 rtpbasepayload_class = GST_RTP_BASE_PAYLOAD_GET_CLASS (rtpbasepayload);
475 if (rtpbasepayload_class->set_caps)
476 res = rtpbasepayload_class->set_caps (rtpbasepayload, caps);
477 else
478 res = gst_rtp_base_payload_negotiate (rtpbasepayload);
479
480 rtpbasepayload->priv->negotiated = res;
481
482 gst_event_unref (event);
483 break;
484 }
485 case GST_EVENT_SEGMENT:
486 {
487 GstSegment *segment;
488
489 segment = &rtpbasepayload->segment;
490 gst_event_copy_segment (event, segment);
491
492 rtpbasepayload->priv->base_offset = GST_BUFFER_OFFSET_NONE;
493
494 GST_DEBUG_OBJECT (rtpbasepayload,
495 "configured SEGMENT %" GST_SEGMENT_FORMAT, segment);
496 if (rtpbasepayload->priv->delay_segment) {
497 gst_event_replace (&rtpbasepayload->priv->pending_segment, event);
498 gst_event_unref (event);
499 res = TRUE;
500 } else {
501 res = gst_pad_event_default (rtpbasepayload->sinkpad, parent, event);
502 }
503 break;
504 }
505 default:
506 res = gst_pad_event_default (rtpbasepayload->sinkpad, parent, event);
507 break;
508 }
509 return res;
510 }
511
512 static gboolean
gst_rtp_base_payload_sink_event(GstPad * pad,GstObject * parent,GstEvent * event)513 gst_rtp_base_payload_sink_event (GstPad * pad, GstObject * parent,
514 GstEvent * event)
515 {
516 GstRTPBasePayload *rtpbasepayload;
517 GstRTPBasePayloadClass *rtpbasepayload_class;
518 gboolean res = FALSE;
519
520 rtpbasepayload = GST_RTP_BASE_PAYLOAD (parent);
521 rtpbasepayload_class = GST_RTP_BASE_PAYLOAD_GET_CLASS (rtpbasepayload);
522
523 if (rtpbasepayload_class->sink_event)
524 res = rtpbasepayload_class->sink_event (rtpbasepayload, event);
525 else
526 gst_event_unref (event);
527
528 return res;
529 }
530
531 static gboolean
gst_rtp_base_payload_src_event_default(GstRTPBasePayload * rtpbasepayload,GstEvent * event)532 gst_rtp_base_payload_src_event_default (GstRTPBasePayload * rtpbasepayload,
533 GstEvent * event)
534 {
535 GstObject *parent = GST_OBJECT_CAST (rtpbasepayload);
536 gboolean res = TRUE, forward = TRUE;
537
538 switch (GST_EVENT_TYPE (event)) {
539 case GST_EVENT_CUSTOM_UPSTREAM:
540 {
541 const GstStructure *s = gst_event_get_structure (event);
542
543 if (gst_structure_has_name (s, "GstRTPCollision")) {
544 guint ssrc = 0;
545
546 if (!gst_structure_get_uint (s, "ssrc", &ssrc))
547 ssrc = -1;
548
549 GST_DEBUG_OBJECT (rtpbasepayload, "collided ssrc: %" G_GUINT32_FORMAT,
550 ssrc);
551
552 /* choose another ssrc for our stream */
553 if (ssrc == rtpbasepayload->current_ssrc) {
554 GstCaps *caps;
555 guint suggested_ssrc = 0;
556
557 if (gst_structure_get_uint (s, "suggested-ssrc", &suggested_ssrc))
558 rtpbasepayload->current_ssrc = suggested_ssrc;
559
560 while (ssrc == rtpbasepayload->current_ssrc)
561 rtpbasepayload->current_ssrc = g_random_int ();
562
563 caps = gst_pad_get_current_caps (rtpbasepayload->srcpad);
564 if (caps) {
565 caps = gst_caps_make_writable (caps);
566 gst_caps_set_simple (caps,
567 "ssrc", G_TYPE_UINT, rtpbasepayload->current_ssrc, NULL);
568 res = gst_pad_set_caps (rtpbasepayload->srcpad, caps);
569 gst_caps_unref (caps);
570 }
571
572 /* the event was for us */
573 forward = FALSE;
574 }
575 }
576 break;
577 }
578 default:
579 break;
580 }
581
582 if (forward)
583 res = gst_pad_event_default (rtpbasepayload->srcpad, parent, event);
584 else
585 gst_event_unref (event);
586
587 return res;
588 }
589
590 static gboolean
gst_rtp_base_payload_src_event(GstPad * pad,GstObject * parent,GstEvent * event)591 gst_rtp_base_payload_src_event (GstPad * pad, GstObject * parent,
592 GstEvent * event)
593 {
594 GstRTPBasePayload *rtpbasepayload;
595 GstRTPBasePayloadClass *rtpbasepayload_class;
596 gboolean res = FALSE;
597
598 rtpbasepayload = GST_RTP_BASE_PAYLOAD (parent);
599 rtpbasepayload_class = GST_RTP_BASE_PAYLOAD_GET_CLASS (rtpbasepayload);
600
601 if (rtpbasepayload_class->src_event)
602 res = rtpbasepayload_class->src_event (rtpbasepayload, event);
603 else
604 gst_event_unref (event);
605
606 return res;
607 }
608
609
610 static gboolean
gst_rtp_base_payload_query_default(GstRTPBasePayload * rtpbasepayload,GstPad * pad,GstQuery * query)611 gst_rtp_base_payload_query_default (GstRTPBasePayload * rtpbasepayload,
612 GstPad * pad, GstQuery * query)
613 {
614 gboolean res = FALSE;
615
616 switch (GST_QUERY_TYPE (query)) {
617 case GST_QUERY_CAPS:
618 {
619 GstRTPBasePayloadClass *rtpbasepayload_class;
620 GstCaps *filter, *caps;
621
622 gst_query_parse_caps (query, &filter);
623 GST_DEBUG_OBJECT (rtpbasepayload, "getting caps with filter %"
624 GST_PTR_FORMAT, filter);
625
626 rtpbasepayload_class = GST_RTP_BASE_PAYLOAD_GET_CLASS (rtpbasepayload);
627 if (rtpbasepayload_class->get_caps) {
628 caps = rtpbasepayload_class->get_caps (rtpbasepayload, pad, filter);
629 gst_query_set_caps_result (query, caps);
630 gst_caps_unref (caps);
631 res = TRUE;
632 }
633 break;
634 }
635 default:
636 res =
637 gst_pad_query_default (pad, GST_OBJECT_CAST (rtpbasepayload), query);
638 break;
639 }
640 return res;
641 }
642
643 static gboolean
gst_rtp_base_payload_query(GstPad * pad,GstObject * parent,GstQuery * query)644 gst_rtp_base_payload_query (GstPad * pad, GstObject * parent, GstQuery * query)
645 {
646 GstRTPBasePayload *rtpbasepayload;
647 GstRTPBasePayloadClass *rtpbasepayload_class;
648 gboolean res = FALSE;
649
650 rtpbasepayload = GST_RTP_BASE_PAYLOAD (parent);
651 rtpbasepayload_class = GST_RTP_BASE_PAYLOAD_GET_CLASS (rtpbasepayload);
652
653 if (rtpbasepayload_class->query)
654 res = rtpbasepayload_class->query (rtpbasepayload, pad, query);
655
656 return res;
657 }
658
659 static GstFlowReturn
gst_rtp_base_payload_chain(GstPad * pad,GstObject * parent,GstBuffer * buffer)660 gst_rtp_base_payload_chain (GstPad * pad, GstObject * parent,
661 GstBuffer * buffer)
662 {
663 GstRTPBasePayload *rtpbasepayload;
664 GstRTPBasePayloadClass *rtpbasepayload_class;
665 GstFlowReturn ret;
666
667 rtpbasepayload = GST_RTP_BASE_PAYLOAD (parent);
668 rtpbasepayload_class = GST_RTP_BASE_PAYLOAD_GET_CLASS (rtpbasepayload);
669
670 if (!rtpbasepayload_class->handle_buffer)
671 goto no_function;
672
673 if (!rtpbasepayload->priv->negotiated)
674 goto not_negotiated;
675
676 if (rtpbasepayload->priv->source_info) {
677 /* Save a copy of meta (instead of taking an extra reference before
678 * handle_buffer) to make the meta available when allocating a output
679 * buffer. */
680 rtpbasepayload->priv->input_meta_buffer = gst_buffer_new ();
681 gst_buffer_copy_into (rtpbasepayload->priv->input_meta_buffer, buffer,
682 GST_BUFFER_COPY_META, 0, -1);
683 }
684
685 if (gst_pad_check_reconfigure (GST_RTP_BASE_PAYLOAD_SRCPAD (rtpbasepayload))) {
686 if (!gst_rtp_base_payload_negotiate (rtpbasepayload)) {
687 gst_pad_mark_reconfigure (GST_RTP_BASE_PAYLOAD_SRCPAD (rtpbasepayload));
688 if (GST_PAD_IS_FLUSHING (GST_RTP_BASE_PAYLOAD_SRCPAD (rtpbasepayload))) {
689 goto flushing;
690 } else {
691 goto negotiate_failed;
692 }
693 }
694 }
695
696 ret = rtpbasepayload_class->handle_buffer (rtpbasepayload, buffer);
697
698 gst_buffer_replace (&rtpbasepayload->priv->input_meta_buffer, NULL);
699
700 return ret;
701
702 /* ERRORS */
703 no_function:
704 {
705 GST_ELEMENT_ERROR (rtpbasepayload, STREAM, NOT_IMPLEMENTED, (NULL),
706 ("subclass did not implement handle_buffer function"));
707 gst_buffer_unref (buffer);
708 return GST_FLOW_ERROR;
709 }
710 not_negotiated:
711 {
712 GST_ELEMENT_ERROR (rtpbasepayload, CORE, NEGOTIATION, (NULL),
713 ("No input format was negotiated, i.e. no caps event was received. "
714 "Perhaps you need a parser or typefind element before the payloader"));
715 gst_buffer_unref (buffer);
716 return GST_FLOW_NOT_NEGOTIATED;
717 }
718 negotiate_failed:
719 {
720 GST_DEBUG_OBJECT (rtpbasepayload, "Not negotiated");
721 gst_buffer_unref (buffer);
722 return GST_FLOW_NOT_NEGOTIATED;
723 }
724 flushing:
725 {
726 GST_DEBUG_OBJECT (rtpbasepayload, "we are flushing");
727 gst_buffer_unref (buffer);
728 return GST_FLOW_FLUSHING;
729 }
730 }
731
732 /**
733 * gst_rtp_base_payload_set_options:
734 * @payload: a #GstRTPBasePayload
735 * @media: the media type (typically "audio" or "video")
736 * @dynamic: if the payload type is dynamic
737 * @encoding_name: the encoding name
738 * @clock_rate: the clock rate of the media
739 *
740 * Set the rtp options of the payloader. These options will be set in the caps
741 * of the payloader. Subclasses must call this method before calling
742 * gst_rtp_base_payload_push() or gst_rtp_base_payload_set_outcaps().
743 */
744 void
gst_rtp_base_payload_set_options(GstRTPBasePayload * payload,const gchar * media,gboolean dynamic,const gchar * encoding_name,guint32 clock_rate)745 gst_rtp_base_payload_set_options (GstRTPBasePayload * payload,
746 const gchar * media, gboolean dynamic, const gchar * encoding_name,
747 guint32 clock_rate)
748 {
749 g_return_if_fail (payload != NULL);
750 g_return_if_fail (clock_rate != 0);
751
752 g_free (payload->media);
753 payload->media = g_strdup (media);
754 payload->dynamic = dynamic;
755 g_free (payload->encoding_name);
756 payload->encoding_name = g_strdup (encoding_name);
757 payload->clock_rate = clock_rate;
758 }
759
760 static gboolean
copy_fixed(GQuark field_id,const GValue * value,GstStructure * dest)761 copy_fixed (GQuark field_id, const GValue * value, GstStructure * dest)
762 {
763 if (gst_value_is_fixed (value)) {
764 gst_structure_id_set_value (dest, field_id, value);
765 }
766 return TRUE;
767 }
768
769 static void
update_max_ptime(GstRTPBasePayload * rtpbasepayload)770 update_max_ptime (GstRTPBasePayload * rtpbasepayload)
771 {
772 if (rtpbasepayload->priv->caps_max_ptime != -1 &&
773 rtpbasepayload->priv->prop_max_ptime != -1)
774 rtpbasepayload->max_ptime = MIN (rtpbasepayload->priv->caps_max_ptime,
775 rtpbasepayload->priv->prop_max_ptime);
776 else if (rtpbasepayload->priv->caps_max_ptime != -1)
777 rtpbasepayload->max_ptime = rtpbasepayload->priv->caps_max_ptime;
778 else if (rtpbasepayload->priv->prop_max_ptime != -1)
779 rtpbasepayload->max_ptime = rtpbasepayload->priv->prop_max_ptime;
780 else
781 rtpbasepayload->max_ptime = DEFAULT_MAX_PTIME;
782 }
783
784 /**
785 * gst_rtp_base_payload_set_outcaps:
786 * @payload: a #GstRTPBasePayload
787 * @fieldname: the first field name or %NULL
788 * @...: field values
789 *
790 * Configure the output caps with the optional parameters.
791 *
792 * Variable arguments should be in the form field name, field type
793 * (as a GType), value(s). The last variable argument should be NULL.
794 *
795 * Returns: %TRUE if the caps could be set.
796 */
797 gboolean
gst_rtp_base_payload_set_outcaps(GstRTPBasePayload * payload,const gchar * fieldname,...)798 gst_rtp_base_payload_set_outcaps (GstRTPBasePayload * payload,
799 const gchar * fieldname, ...)
800 {
801 GstCaps *srccaps;
802
803 /* fill in the defaults, their properties cannot be negotiated. */
804 srccaps = gst_caps_new_simple ("application/x-rtp",
805 "media", G_TYPE_STRING, payload->media,
806 "clock-rate", G_TYPE_INT, payload->clock_rate,
807 "encoding-name", G_TYPE_STRING, payload->encoding_name, NULL);
808
809 GST_DEBUG_OBJECT (payload, "defaults: %" GST_PTR_FORMAT, srccaps);
810
811 if (fieldname) {
812 va_list varargs;
813
814 /* override with custom properties */
815 va_start (varargs, fieldname);
816 gst_caps_set_simple_valist (srccaps, fieldname, varargs);
817 va_end (varargs);
818
819 GST_DEBUG_OBJECT (payload, "custom added: %" GST_PTR_FORMAT, srccaps);
820 }
821
822 gst_caps_replace (&payload->priv->subclass_srccaps, srccaps);
823 gst_caps_unref (srccaps);
824
825 return gst_rtp_base_payload_negotiate (payload);
826 }
827
828 static gboolean
gst_rtp_base_payload_negotiate(GstRTPBasePayload * payload)829 gst_rtp_base_payload_negotiate (GstRTPBasePayload * payload)
830 {
831 GstCaps *templ, *peercaps, *srccaps;
832 GstStructure *s, *d;
833 gboolean res;
834
835 payload->priv->caps_max_ptime = DEFAULT_MAX_PTIME;
836 payload->ptime = 0;
837
838 gst_pad_check_reconfigure (payload->srcpad);
839
840 templ = gst_pad_get_pad_template_caps (payload->srcpad);
841
842 if (payload->priv->subclass_srccaps) {
843 GstCaps *tmp = gst_caps_intersect (payload->priv->subclass_srccaps,
844 templ);
845 gst_caps_unref (templ);
846 templ = tmp;
847 }
848
849 peercaps = gst_pad_peer_query_caps (payload->srcpad, templ);
850
851 if (peercaps == NULL) {
852 /* no peer caps, just add the other properties */
853
854 srccaps = gst_caps_copy (templ);
855 gst_caps_set_simple (srccaps,
856 "payload", G_TYPE_INT, GST_RTP_BASE_PAYLOAD_PT (payload),
857 "ssrc", G_TYPE_UINT, payload->current_ssrc,
858 "timestamp-offset", G_TYPE_UINT, payload->ts_base,
859 "seqnum-offset", G_TYPE_UINT, payload->seqnum_base, NULL);
860
861 GST_DEBUG_OBJECT (payload, "no peer caps: %" GST_PTR_FORMAT, srccaps);
862 } else {
863 GstCaps *temp;
864 const GValue *value;
865 gboolean have_pt = FALSE;
866 gboolean have_ts_offset = FALSE;
867 gboolean have_seqnum_offset = FALSE;
868 guint max_ptime, ptime;
869
870 /* peer provides caps we can use to fixate. They are already intersected
871 * with our srccaps, just make them writable */
872 temp = gst_caps_make_writable (peercaps);
873 peercaps = NULL;
874
875 if (gst_caps_is_empty (temp)) {
876 gst_caps_unref (temp);
877 gst_caps_unref (templ);
878 res = FALSE;
879 goto out;
880 }
881
882 /* We prefer the pt, timestamp-offset, seqnum-offset from the
883 * property (if set), or any previously configured value over what
884 * downstream prefers. Only if downstream can't accept that, or the
885 * properties were not set, we fall back to choosing downstream's
886 * preferred value
887 *
888 * For ssrc we prefer any value downstream suggests, otherwise
889 * the property value or as a last resort a random value.
890 * This difference for ssrc is implemented for retaining backwards
891 * compatibility with changing rtpsession's internal-ssrc property.
892 *
893 * FIXME 2.0: All these properties should go away and be negotiated
894 * via caps only!
895 */
896
897 /* try to use the previously set pt, or the one from the property */
898 if (payload->priv->pt_set || gst_pad_has_current_caps (payload->srcpad)) {
899 GstCaps *probe_caps = gst_caps_copy (templ);
900 GstCaps *intersection;
901
902 gst_caps_set_simple (probe_caps, "payload", G_TYPE_INT,
903 GST_RTP_BASE_PAYLOAD_PT (payload), NULL);
904 intersection = gst_caps_intersect (probe_caps, temp);
905
906 if (!gst_caps_is_empty (intersection)) {
907 GST_LOG_OBJECT (payload, "Using selected pt %d",
908 GST_RTP_BASE_PAYLOAD_PT (payload));
909 have_pt = TRUE;
910 gst_caps_unref (temp);
911 temp = intersection;
912 } else {
913 GST_WARNING_OBJECT (payload, "Can't use selected pt %d",
914 GST_RTP_BASE_PAYLOAD_PT (payload));
915 gst_caps_unref (intersection);
916 }
917 gst_caps_unref (probe_caps);
918 }
919
920 /* If we got no pt above, select one now */
921 if (!have_pt) {
922 gint pt;
923
924 /* get first structure */
925 s = gst_caps_get_structure (temp, 0);
926
927 if (gst_structure_get_int (s, "payload", &pt)) {
928 /* use peer pt */
929 GST_RTP_BASE_PAYLOAD_PT (payload) = pt;
930 GST_LOG_OBJECT (payload, "using peer pt %d", pt);
931 } else {
932 if (gst_structure_has_field (s, "payload")) {
933 /* can only fixate if there is a field */
934 gst_structure_fixate_field_nearest_int (s, "payload",
935 GST_RTP_BASE_PAYLOAD_PT (payload));
936 gst_structure_get_int (s, "payload", &pt);
937 GST_RTP_BASE_PAYLOAD_PT (payload) = pt;
938 GST_LOG_OBJECT (payload, "using peer pt %d", pt);
939 } else {
940 /* no pt field, use the internal pt */
941 pt = GST_RTP_BASE_PAYLOAD_PT (payload);
942 gst_structure_set (s, "payload", G_TYPE_INT, pt, NULL);
943 GST_LOG_OBJECT (payload, "using internal pt %d", pt);
944 }
945 }
946 s = NULL;
947 }
948
949 /* If we got no ssrc above, select one now */
950 /* get first structure */
951 s = gst_caps_get_structure (temp, 0);
952
953 if (gst_structure_has_field_typed (s, "ssrc", G_TYPE_UINT)) {
954 value = gst_structure_get_value (s, "ssrc");
955 payload->current_ssrc = g_value_get_uint (value);
956 GST_LOG_OBJECT (payload, "using peer ssrc %08x", payload->current_ssrc);
957 } else {
958 /* FIXME, fixate_nearest_uint would be even better but we
959 * don't support uint ranges so how likely is it that anybody
960 * uses a list of possible ssrcs */
961 gst_structure_set (s, "ssrc", G_TYPE_UINT, payload->current_ssrc, NULL);
962 GST_LOG_OBJECT (payload, "using internal ssrc %08x",
963 payload->current_ssrc);
964 }
965 s = NULL;
966
967 /* try to select the previously used timestamp-offset, or the one from the property */
968 if (!payload->priv->ts_offset_random
969 || gst_pad_has_current_caps (payload->srcpad)) {
970 GstCaps *probe_caps = gst_caps_copy (templ);
971 GstCaps *intersection;
972
973 gst_caps_set_simple (probe_caps, "timestamp-offset", G_TYPE_UINT,
974 payload->ts_base, NULL);
975 intersection = gst_caps_intersect (probe_caps, temp);
976
977 if (!gst_caps_is_empty (intersection)) {
978 GST_LOG_OBJECT (payload, "Using selected timestamp-offset %u",
979 payload->ts_base);
980 gst_caps_unref (temp);
981 temp = intersection;
982 have_ts_offset = TRUE;
983 } else {
984 GST_WARNING_OBJECT (payload, "Can't use selected timestamp-offset %u",
985 payload->ts_base);
986 gst_caps_unref (intersection);
987 }
988 gst_caps_unref (probe_caps);
989 }
990
991 /* If we got no timestamp-offset above, select one now */
992 if (!have_ts_offset) {
993 /* get first structure */
994 s = gst_caps_get_structure (temp, 0);
995
996 if (gst_structure_has_field_typed (s, "timestamp-offset", G_TYPE_UINT)) {
997 value = gst_structure_get_value (s, "timestamp-offset");
998 payload->ts_base = g_value_get_uint (value);
999 GST_LOG_OBJECT (payload, "using peer timestamp-offset %u",
1000 payload->ts_base);
1001 } else {
1002 /* FIXME, fixate_nearest_uint would be even better but we
1003 * don't support uint ranges so how likely is it that anybody
1004 * uses a list of possible timestamp-offsets */
1005 gst_structure_set (s, "timestamp-offset", G_TYPE_UINT, payload->ts_base,
1006 NULL);
1007 GST_LOG_OBJECT (payload, "using internal timestamp-offset %u",
1008 payload->ts_base);
1009 }
1010 s = NULL;
1011 }
1012
1013 /* try to select the previously used seqnum-offset, or the one from the property */
1014 if (!payload->priv->seqnum_offset_random
1015 || gst_pad_has_current_caps (payload->srcpad)) {
1016 GstCaps *probe_caps = gst_caps_copy (templ);
1017 GstCaps *intersection;
1018
1019 gst_caps_set_simple (probe_caps, "seqnum-offset", G_TYPE_UINT,
1020 payload->seqnum_base, NULL);
1021 intersection = gst_caps_intersect (probe_caps, temp);
1022
1023 if (!gst_caps_is_empty (intersection)) {
1024 GST_LOG_OBJECT (payload, "Using selected seqnum-offset %u",
1025 payload->seqnum_base);
1026 gst_caps_unref (temp);
1027 temp = intersection;
1028 have_seqnum_offset = TRUE;
1029 } else {
1030 GST_WARNING_OBJECT (payload, "Can't use selected seqnum-offset %u",
1031 payload->seqnum_base);
1032 gst_caps_unref (intersection);
1033 }
1034 gst_caps_unref (probe_caps);
1035 }
1036
1037 /* If we got no seqnum-offset above, select one now */
1038 if (!have_seqnum_offset) {
1039 /* get first structure */
1040 s = gst_caps_get_structure (temp, 0);
1041
1042 if (gst_structure_has_field_typed (s, "seqnum-offset", G_TYPE_UINT)) {
1043 value = gst_structure_get_value (s, "seqnum-offset");
1044 payload->seqnum_base = g_value_get_uint (value);
1045 GST_LOG_OBJECT (payload, "using peer seqnum-offset %u",
1046 payload->seqnum_base);
1047 payload->priv->next_seqnum = payload->seqnum_base;
1048 payload->seqnum = payload->seqnum_base;
1049 payload->priv->seqnum_offset_random = FALSE;
1050 } else {
1051 /* FIXME, fixate_nearest_uint would be even better but we
1052 * don't support uint ranges so how likely is it that anybody
1053 * uses a list of possible seqnum-offsets */
1054 gst_structure_set (s, "seqnum-offset", G_TYPE_UINT,
1055 payload->seqnum_base, NULL);
1056 GST_LOG_OBJECT (payload, "using internal seqnum-offset %u",
1057 payload->seqnum_base);
1058 }
1059
1060 s = NULL;
1061 }
1062
1063 /* now fixate, start by taking the first caps */
1064 temp = gst_caps_truncate (temp);
1065
1066 /* get first structure */
1067 s = gst_caps_get_structure (temp, 0);
1068
1069 if (gst_structure_get_uint (s, "maxptime", &max_ptime))
1070 payload->priv->caps_max_ptime = max_ptime * GST_MSECOND;
1071
1072 if (gst_structure_get_uint (s, "ptime", &ptime))
1073 payload->ptime = ptime * GST_MSECOND;
1074
1075 /* make the target caps by copying over all the fixed fields, removing the
1076 * unfixed fields. */
1077 srccaps = gst_caps_new_empty_simple (gst_structure_get_name (s));
1078 d = gst_caps_get_structure (srccaps, 0);
1079
1080 gst_structure_foreach (s, (GstStructureForeachFunc) copy_fixed, d);
1081
1082 gst_caps_unref (temp);
1083
1084 GST_DEBUG_OBJECT (payload, "with peer caps: %" GST_PTR_FORMAT, srccaps);
1085 }
1086
1087 if (payload->priv->sinkcaps != NULL) {
1088 s = gst_caps_get_structure (payload->priv->sinkcaps, 0);
1089 if (g_str_has_prefix (gst_structure_get_name (s), "video")) {
1090 gboolean has_framerate;
1091 gint num, denom;
1092
1093 GST_DEBUG_OBJECT (payload, "video caps: %" GST_PTR_FORMAT,
1094 payload->priv->sinkcaps);
1095
1096 has_framerate = gst_structure_get_fraction (s, "framerate", &num, &denom);
1097 if (has_framerate && num == 0 && denom == 1) {
1098 has_framerate =
1099 gst_structure_get_fraction (s, "max-framerate", &num, &denom);
1100 }
1101
1102 if (has_framerate) {
1103 gchar str[G_ASCII_DTOSTR_BUF_SIZE];
1104 gdouble framerate;
1105
1106 gst_util_fraction_to_double (num, denom, &framerate);
1107 g_ascii_dtostr (str, G_ASCII_DTOSTR_BUF_SIZE, framerate);
1108 d = gst_caps_get_structure (srccaps, 0);
1109 gst_structure_set (d, "a-framerate", G_TYPE_STRING, str, NULL);
1110 }
1111
1112 GST_DEBUG_OBJECT (payload, "with video caps: %" GST_PTR_FORMAT, srccaps);
1113 }
1114 }
1115
1116 update_max_ptime (payload);
1117
1118 res = gst_pad_set_caps (GST_RTP_BASE_PAYLOAD_SRCPAD (payload), srccaps);
1119 gst_caps_unref (srccaps);
1120 gst_caps_unref (templ);
1121
1122 out:
1123
1124 if (!res)
1125 gst_pad_mark_reconfigure (GST_RTP_BASE_PAYLOAD_SRCPAD (payload));
1126
1127 return res;
1128 }
1129
1130 /**
1131 * gst_rtp_base_payload_is_filled:
1132 * @payload: a #GstRTPBasePayload
1133 * @size: the size of the packet
1134 * @duration: the duration of the packet
1135 *
1136 * Check if the packet with @size and @duration would exceed the configured
1137 * maximum size.
1138 *
1139 * Returns: %TRUE if the packet of @size and @duration would exceed the
1140 * configured MTU or max_ptime.
1141 */
1142 gboolean
gst_rtp_base_payload_is_filled(GstRTPBasePayload * payload,guint size,GstClockTime duration)1143 gst_rtp_base_payload_is_filled (GstRTPBasePayload * payload,
1144 guint size, GstClockTime duration)
1145 {
1146 if (size > payload->mtu)
1147 return TRUE;
1148
1149 if (payload->max_ptime != -1 && duration >= payload->max_ptime)
1150 return TRUE;
1151
1152 return FALSE;
1153 }
1154
1155 typedef struct
1156 {
1157 GstRTPBasePayload *payload;
1158 guint32 ssrc;
1159 guint16 seqnum;
1160 guint8 pt;
1161 GstClockTime dts;
1162 GstClockTime pts;
1163 guint64 offset;
1164 guint32 rtptime;
1165 } HeaderData;
1166
1167 static gboolean
find_timestamp(GstBuffer ** buffer,guint idx,gpointer user_data)1168 find_timestamp (GstBuffer ** buffer, guint idx, gpointer user_data)
1169 {
1170 HeaderData *data = user_data;
1171 data->dts = GST_BUFFER_DTS (*buffer);
1172 data->pts = GST_BUFFER_PTS (*buffer);
1173 data->offset = GST_BUFFER_OFFSET (*buffer);
1174
1175 /* stop when we find a timestamp. We take whatever offset is associated with
1176 * the timestamp (if any) to do perfect timestamps when we need to. */
1177 if (data->pts != -1)
1178 return FALSE;
1179 else
1180 return TRUE;
1181 }
1182
1183 static gboolean
set_headers(GstBuffer ** buffer,guint idx,gpointer user_data)1184 set_headers (GstBuffer ** buffer, guint idx, gpointer user_data)
1185 {
1186 HeaderData *data = user_data;
1187 GstRTPBuffer rtp = { NULL, };
1188
1189 if (!gst_rtp_buffer_map (*buffer, GST_MAP_WRITE, &rtp))
1190 goto map_failed;
1191
1192 gst_rtp_buffer_set_ssrc (&rtp, data->ssrc);
1193 gst_rtp_buffer_set_payload_type (&rtp, data->pt);
1194 gst_rtp_buffer_set_seq (&rtp, data->seqnum);
1195 gst_rtp_buffer_set_timestamp (&rtp, data->rtptime);
1196 gst_rtp_buffer_unmap (&rtp);
1197
1198 /* increment the seqnum for each buffer */
1199 data->seqnum++;
1200
1201 return TRUE;
1202 /* ERRORS */
1203 map_failed:
1204 {
1205 GST_ERROR ("failed to map buffer %p", *buffer);
1206 return FALSE;
1207 }
1208 }
1209
1210 static gboolean
foreach_metadata_drop(GstBuffer * buffer,GstMeta ** meta,gpointer user_data)1211 foreach_metadata_drop (GstBuffer * buffer, GstMeta ** meta, gpointer user_data)
1212 {
1213 GType drop_api_type = (GType) GPOINTER_TO_INT (user_data);
1214 const GstMetaInfo *info = (*meta)->info;
1215
1216 if (info->api == drop_api_type)
1217 *meta = NULL;
1218
1219 return TRUE;
1220 }
1221
1222 static gboolean
filter_meta(GstBuffer ** buffer,guint idx,gpointer user_data)1223 filter_meta (GstBuffer ** buffer, guint idx, gpointer user_data)
1224 {
1225 return gst_buffer_foreach_meta (*buffer, foreach_metadata_drop,
1226 GINT_TO_POINTER (GST_RTP_SOURCE_META_API_TYPE));
1227 }
1228
1229 /* Updates the SSRC, payload type, seqnum and timestamp of the RTP buffer
1230 * before the buffer is pushed. */
1231 static GstFlowReturn
gst_rtp_base_payload_prepare_push(GstRTPBasePayload * payload,gpointer obj,gboolean is_list)1232 gst_rtp_base_payload_prepare_push (GstRTPBasePayload * payload,
1233 gpointer obj, gboolean is_list)
1234 {
1235 GstRTPBasePayloadPrivate *priv;
1236 HeaderData data;
1237
1238 if (payload->clock_rate == 0)
1239 goto no_rate;
1240
1241 priv = payload->priv;
1242
1243 /* update first, so that the property is set to the last
1244 * seqnum pushed */
1245 payload->seqnum = priv->next_seqnum;
1246
1247 /* fill in the fields we want to set on all headers */
1248 data.payload = payload;
1249 data.seqnum = payload->seqnum;
1250 data.ssrc = payload->current_ssrc;
1251 data.pt = payload->pt;
1252
1253 /* find the first buffer with a timestamp */
1254 if (is_list) {
1255 data.dts = -1;
1256 data.pts = -1;
1257 data.offset = GST_BUFFER_OFFSET_NONE;
1258 gst_buffer_list_foreach (GST_BUFFER_LIST_CAST (obj), find_timestamp, &data);
1259 } else {
1260 data.dts = GST_BUFFER_DTS (GST_BUFFER_CAST (obj));
1261 data.pts = GST_BUFFER_PTS (GST_BUFFER_CAST (obj));
1262 data.offset = GST_BUFFER_OFFSET (GST_BUFFER_CAST (obj));
1263 }
1264
1265 /* convert to RTP time */
1266 if (priv->perfect_rtptime && data.offset != GST_BUFFER_OFFSET_NONE &&
1267 priv->base_offset != GST_BUFFER_OFFSET_NONE) {
1268 /* generate perfect RTP time by adding together the base timestamp, the
1269 * running time of the first buffer and difference between the offset of the
1270 * first buffer and the offset of the current buffer. */
1271 guint64 offset = data.offset - priv->base_offset;
1272 data.rtptime = payload->ts_base + priv->base_rtime_hz + offset;
1273
1274 GST_LOG_OBJECT (payload,
1275 "Using offset %" G_GUINT64_FORMAT " for RTP timestamp", data.offset);
1276
1277 /* store buffer's running time */
1278 GST_LOG_OBJECT (payload,
1279 "setting running-time to %" G_GUINT64_FORMAT,
1280 data.offset - priv->base_offset);
1281 priv->running_time = priv->base_rtime + data.offset - priv->base_offset;
1282 } else if (GST_CLOCK_TIME_IS_VALID (data.pts)) {
1283 guint64 rtime_ns;
1284 guint64 rtime_hz;
1285
1286 /* no offset, use the gstreamer pts */
1287 if (priv->onvif_no_rate_control)
1288 rtime_ns = data.pts;
1289 else
1290 rtime_ns =
1291 gst_segment_to_running_time (&payload->segment, GST_FORMAT_TIME,
1292 data.pts);
1293
1294 if (!GST_CLOCK_TIME_IS_VALID (rtime_ns)) {
1295 GST_LOG_OBJECT (payload, "Clipped pts, using base RTP timestamp");
1296 rtime_hz = 0;
1297 } else {
1298 GST_LOG_OBJECT (payload,
1299 "Using running_time %" GST_TIME_FORMAT " for RTP timestamp",
1300 GST_TIME_ARGS (rtime_ns));
1301 rtime_hz =
1302 gst_util_uint64_scale_int (rtime_ns, payload->clock_rate, GST_SECOND);
1303 priv->base_offset = data.offset;
1304 priv->base_rtime_hz = rtime_hz;
1305 }
1306
1307 /* add running_time in clock-rate units to the base timestamp */
1308 data.rtptime = payload->ts_base + rtime_hz;
1309
1310 /* store buffer's running time */
1311 if (priv->perfect_rtptime) {
1312 GST_LOG_OBJECT (payload,
1313 "setting running-time to %" G_GUINT64_FORMAT, rtime_hz);
1314 priv->running_time = rtime_hz;
1315 } else {
1316 GST_LOG_OBJECT (payload,
1317 "setting running-time to %" GST_TIME_FORMAT,
1318 GST_TIME_ARGS (rtime_ns));
1319 priv->running_time = rtime_ns;
1320 }
1321 } else {
1322 GST_LOG_OBJECT (payload,
1323 "Using previous RTP timestamp %" G_GUINT32_FORMAT, payload->timestamp);
1324 /* no timestamp to convert, take previous timestamp */
1325 data.rtptime = payload->timestamp;
1326 }
1327
1328 /* set ssrc, payload type, seq number, caps and rtptime */
1329 /* remove unwanted meta */
1330 if (is_list) {
1331 gst_buffer_list_foreach (GST_BUFFER_LIST_CAST (obj), set_headers, &data);
1332 gst_buffer_list_foreach (GST_BUFFER_LIST_CAST (obj), filter_meta, NULL);
1333 /* sequence number has increased more if this was a buffer list */
1334 payload->seqnum = data.seqnum - 1;
1335 } else {
1336 GstBuffer *buf = GST_BUFFER_CAST (obj);
1337 set_headers (&buf, 0, &data);
1338 filter_meta (&buf, 0, NULL);
1339 }
1340
1341 priv->next_seqnum = data.seqnum;
1342 payload->timestamp = data.rtptime;
1343
1344 GST_LOG_OBJECT (payload, "Preparing to push %s with size %"
1345 G_GSIZE_FORMAT ", seq=%d, rtptime=%u, pts %" GST_TIME_FORMAT,
1346 (is_list) ? "list" : "packet",
1347 (is_list) ? gst_buffer_list_length (GST_BUFFER_LIST_CAST (obj)) :
1348 gst_buffer_get_size (GST_BUFFER (obj)),
1349 payload->seqnum, data.rtptime, GST_TIME_ARGS (data.pts));
1350
1351 if (g_atomic_int_compare_and_exchange (&payload->priv->
1352 notified_first_timestamp, 1, 0)) {
1353 g_object_notify (G_OBJECT (payload), "timestamp");
1354 g_object_notify (G_OBJECT (payload), "seqnum");
1355 }
1356
1357 return GST_FLOW_OK;
1358
1359 /* ERRORS */
1360 no_rate:
1361 {
1362 GST_ELEMENT_ERROR (payload, STREAM, NOT_IMPLEMENTED, (NULL),
1363 ("subclass did not specify clock-rate"));
1364 return GST_FLOW_ERROR;
1365 }
1366 }
1367
1368 /**
1369 * gst_rtp_base_payload_push_list:
1370 * @payload: a #GstRTPBasePayload
1371 * @list: a #GstBufferList
1372 *
1373 * Push @list to the peer element of the payloader. The SSRC, payload type,
1374 * seqnum and timestamp of the RTP buffer will be updated first.
1375 *
1376 * This function takes ownership of @list.
1377 *
1378 * Returns: a #GstFlowReturn.
1379 */
1380 GstFlowReturn
gst_rtp_base_payload_push_list(GstRTPBasePayload * payload,GstBufferList * list)1381 gst_rtp_base_payload_push_list (GstRTPBasePayload * payload,
1382 GstBufferList * list)
1383 {
1384 GstFlowReturn res;
1385
1386 res = gst_rtp_base_payload_prepare_push (payload, list, TRUE);
1387
1388 if (G_LIKELY (res == GST_FLOW_OK)) {
1389 if (G_UNLIKELY (payload->priv->pending_segment)) {
1390 gst_pad_push_event (payload->srcpad, payload->priv->pending_segment);
1391 payload->priv->pending_segment = FALSE;
1392 payload->priv->delay_segment = FALSE;
1393 }
1394 res = gst_pad_push_list (payload->srcpad, list);
1395 } else {
1396 gst_buffer_list_unref (list);
1397 }
1398
1399 return res;
1400 }
1401
1402 /**
1403 * gst_rtp_base_payload_push:
1404 * @payload: a #GstRTPBasePayload
1405 * @buffer: a #GstBuffer
1406 *
1407 * Push @buffer to the peer element of the payloader. The SSRC, payload type,
1408 * seqnum and timestamp of the RTP buffer will be updated first.
1409 *
1410 * This function takes ownership of @buffer.
1411 *
1412 * Returns: a #GstFlowReturn.
1413 */
1414 GstFlowReturn
gst_rtp_base_payload_push(GstRTPBasePayload * payload,GstBuffer * buffer)1415 gst_rtp_base_payload_push (GstRTPBasePayload * payload, GstBuffer * buffer)
1416 {
1417 GstFlowReturn res;
1418
1419 res = gst_rtp_base_payload_prepare_push (payload, buffer, FALSE);
1420
1421 if (G_LIKELY (res == GST_FLOW_OK)) {
1422 if (G_UNLIKELY (payload->priv->pending_segment)) {
1423 gst_pad_push_event (payload->srcpad, payload->priv->pending_segment);
1424 payload->priv->pending_segment = FALSE;
1425 payload->priv->delay_segment = FALSE;
1426 }
1427 res = gst_pad_push (payload->srcpad, buffer);
1428 } else {
1429 gst_buffer_unref (buffer);
1430 }
1431
1432 return res;
1433 }
1434
1435 /**
1436 * gst_rtp_base_payload_allocate_output_buffer:
1437 * @payload: a #GstRTPBasePayload
1438 * @payload_len: the length of the payload
1439 * @pad_len: the amount of padding
1440 * @csrc_count: the minimum number of CSRC entries
1441 *
1442 * Allocate a new #GstBuffer with enough data to hold an RTP packet with
1443 * minimum @csrc_count CSRCs, a payload length of @payload_len and padding of
1444 * @pad_len. If @payload has #GstRTPBasePayload:source-info %TRUE additional
1445 * CSRCs may be allocated and filled with RTP source information.
1446 *
1447 * Returns: A newly allocated buffer that can hold an RTP packet with given
1448 * parameters.
1449 *
1450 * Since: 1.16
1451 */
1452 GstBuffer *
gst_rtp_base_payload_allocate_output_buffer(GstRTPBasePayload * payload,guint payload_len,guint8 pad_len,guint8 csrc_count)1453 gst_rtp_base_payload_allocate_output_buffer (GstRTPBasePayload * payload,
1454 guint payload_len, guint8 pad_len, guint8 csrc_count)
1455 {
1456 GstBuffer *buffer = NULL;
1457
1458 if (payload->priv->input_meta_buffer != NULL) {
1459 GstRTPSourceMeta *meta =
1460 gst_buffer_get_rtp_source_meta (payload->priv->input_meta_buffer);
1461 if (meta != NULL) {
1462 guint total_csrc_count, idx, i;
1463 GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
1464
1465 total_csrc_count = csrc_count + meta->csrc_count +
1466 (meta->ssrc_valid ? 1 : 0);
1467 total_csrc_count = MIN (total_csrc_count, 15);
1468 buffer = gst_rtp_buffer_new_allocate (payload_len, pad_len,
1469 total_csrc_count);
1470
1471 gst_rtp_buffer_map (buffer, GST_MAP_READWRITE, &rtp);
1472
1473 /* Skip CSRC fields requested by derived class and fill CSRCs from meta.
1474 * Finally append the SSRC as a new CSRC. */
1475 idx = csrc_count;
1476 for (i = 0; i < meta->csrc_count && idx < 15; i++, idx++)
1477 gst_rtp_buffer_set_csrc (&rtp, idx, meta->csrc[i]);
1478 if (meta->ssrc_valid && idx < 15)
1479 gst_rtp_buffer_set_csrc (&rtp, idx, meta->ssrc);
1480
1481 gst_rtp_buffer_unmap (&rtp);
1482 }
1483 }
1484
1485 if (buffer == NULL)
1486 buffer = gst_rtp_buffer_new_allocate (payload_len, pad_len, csrc_count);
1487
1488 return buffer;
1489 }
1490
1491 static GstStructure *
gst_rtp_base_payload_create_stats(GstRTPBasePayload * rtpbasepayload)1492 gst_rtp_base_payload_create_stats (GstRTPBasePayload * rtpbasepayload)
1493 {
1494 GstRTPBasePayloadPrivate *priv;
1495 GstStructure *s;
1496
1497 priv = rtpbasepayload->priv;
1498
1499 s = gst_structure_new ("application/x-rtp-payload-stats",
1500 "clock-rate", G_TYPE_UINT, (guint) rtpbasepayload->clock_rate,
1501 "running-time", G_TYPE_UINT64, priv->running_time,
1502 "seqnum", G_TYPE_UINT, (guint) rtpbasepayload->seqnum,
1503 "timestamp", G_TYPE_UINT, (guint) rtpbasepayload->timestamp,
1504 "ssrc", G_TYPE_UINT, rtpbasepayload->current_ssrc,
1505 "pt", G_TYPE_UINT, rtpbasepayload->pt,
1506 "seqnum-offset", G_TYPE_UINT, (guint) rtpbasepayload->seqnum_base,
1507 "timestamp-offset", G_TYPE_UINT, (guint) rtpbasepayload->ts_base, NULL);
1508
1509 return s;
1510 }
1511
1512 static void
gst_rtp_base_payload_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)1513 gst_rtp_base_payload_set_property (GObject * object, guint prop_id,
1514 const GValue * value, GParamSpec * pspec)
1515 {
1516 GstRTPBasePayload *rtpbasepayload;
1517 GstRTPBasePayloadPrivate *priv;
1518 gint64 val;
1519
1520 rtpbasepayload = GST_RTP_BASE_PAYLOAD (object);
1521 priv = rtpbasepayload->priv;
1522
1523 switch (prop_id) {
1524 case PROP_MTU:
1525 rtpbasepayload->mtu = g_value_get_uint (value);
1526 break;
1527 case PROP_PT:
1528 rtpbasepayload->pt = g_value_get_uint (value);
1529 priv->pt_set = TRUE;
1530 break;
1531 case PROP_SSRC:
1532 val = g_value_get_uint (value);
1533 rtpbasepayload->ssrc = val;
1534 priv->ssrc_random = FALSE;
1535 break;
1536 case PROP_TIMESTAMP_OFFSET:
1537 val = g_value_get_uint (value);
1538 rtpbasepayload->ts_offset = val;
1539 priv->ts_offset_random = FALSE;
1540 break;
1541 case PROP_SEQNUM_OFFSET:
1542 val = g_value_get_int (value);
1543 rtpbasepayload->seqnum_offset = val;
1544 priv->seqnum_offset_random = (val == -1);
1545 GST_DEBUG_OBJECT (rtpbasepayload, "seqnum offset 0x%04x, random %d",
1546 rtpbasepayload->seqnum_offset, priv->seqnum_offset_random);
1547 break;
1548 case PROP_MAX_PTIME:
1549 rtpbasepayload->priv->prop_max_ptime = g_value_get_int64 (value);
1550 update_max_ptime (rtpbasepayload);
1551 break;
1552 case PROP_MIN_PTIME:
1553 rtpbasepayload->min_ptime = g_value_get_int64 (value);
1554 break;
1555 case PROP_PERFECT_RTPTIME:
1556 priv->perfect_rtptime = g_value_get_boolean (value);
1557 break;
1558 case PROP_PTIME_MULTIPLE:
1559 rtpbasepayload->ptime_multiple = g_value_get_int64 (value);
1560 break;
1561 case PROP_SOURCE_INFO:
1562 gst_rtp_base_payload_set_source_info_enabled (rtpbasepayload,
1563 g_value_get_boolean (value));
1564 break;
1565 case PROP_ONVIF_NO_RATE_CONTROL:
1566 priv->onvif_no_rate_control = g_value_get_boolean (value);
1567 break;
1568 default:
1569 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1570 break;
1571 }
1572 }
1573
1574 static void
gst_rtp_base_payload_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)1575 gst_rtp_base_payload_get_property (GObject * object, guint prop_id,
1576 GValue * value, GParamSpec * pspec)
1577 {
1578 GstRTPBasePayload *rtpbasepayload;
1579 GstRTPBasePayloadPrivate *priv;
1580
1581 rtpbasepayload = GST_RTP_BASE_PAYLOAD (object);
1582 priv = rtpbasepayload->priv;
1583
1584 switch (prop_id) {
1585 case PROP_MTU:
1586 g_value_set_uint (value, rtpbasepayload->mtu);
1587 break;
1588 case PROP_PT:
1589 g_value_set_uint (value, rtpbasepayload->pt);
1590 break;
1591 case PROP_SSRC:
1592 if (priv->ssrc_random)
1593 g_value_set_uint (value, -1);
1594 else
1595 g_value_set_uint (value, rtpbasepayload->ssrc);
1596 break;
1597 case PROP_TIMESTAMP_OFFSET:
1598 if (priv->ts_offset_random)
1599 g_value_set_uint (value, -1);
1600 else
1601 g_value_set_uint (value, (guint32) rtpbasepayload->ts_offset);
1602 break;
1603 case PROP_SEQNUM_OFFSET:
1604 if (priv->seqnum_offset_random)
1605 g_value_set_int (value, -1);
1606 else
1607 g_value_set_int (value, (guint16) rtpbasepayload->seqnum_offset);
1608 break;
1609 case PROP_MAX_PTIME:
1610 g_value_set_int64 (value, rtpbasepayload->max_ptime);
1611 break;
1612 case PROP_MIN_PTIME:
1613 g_value_set_int64 (value, rtpbasepayload->min_ptime);
1614 break;
1615 case PROP_TIMESTAMP:
1616 g_value_set_uint (value, rtpbasepayload->timestamp);
1617 break;
1618 case PROP_SEQNUM:
1619 g_value_set_uint (value, rtpbasepayload->seqnum);
1620 break;
1621 case PROP_PERFECT_RTPTIME:
1622 g_value_set_boolean (value, priv->perfect_rtptime);
1623 break;
1624 case PROP_PTIME_MULTIPLE:
1625 g_value_set_int64 (value, rtpbasepayload->ptime_multiple);
1626 break;
1627 case PROP_STATS:
1628 g_value_take_boxed (value,
1629 gst_rtp_base_payload_create_stats (rtpbasepayload));
1630 break;
1631 case PROP_SOURCE_INFO:
1632 g_value_set_boolean (value,
1633 gst_rtp_base_payload_is_source_info_enabled (rtpbasepayload));
1634 break;
1635 case PROP_ONVIF_NO_RATE_CONTROL:
1636 g_value_set_boolean (value, priv->onvif_no_rate_control);
1637 break;
1638 default:
1639 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1640 break;
1641 }
1642 }
1643
1644 static GstStateChangeReturn
gst_rtp_base_payload_change_state(GstElement * element,GstStateChange transition)1645 gst_rtp_base_payload_change_state (GstElement * element,
1646 GstStateChange transition)
1647 {
1648 GstRTPBasePayload *rtpbasepayload;
1649 GstRTPBasePayloadPrivate *priv;
1650 GstStateChangeReturn ret;
1651
1652 rtpbasepayload = GST_RTP_BASE_PAYLOAD (element);
1653 priv = rtpbasepayload->priv;
1654
1655 switch (transition) {
1656 case GST_STATE_CHANGE_NULL_TO_READY:
1657 break;
1658 case GST_STATE_CHANGE_READY_TO_PAUSED:
1659 gst_segment_init (&rtpbasepayload->segment, GST_FORMAT_UNDEFINED);
1660 rtpbasepayload->priv->delay_segment = TRUE;
1661 gst_event_replace (&rtpbasepayload->priv->pending_segment, NULL);
1662
1663 if (priv->seqnum_offset_random)
1664 rtpbasepayload->seqnum_base = g_random_int_range (0, G_MAXINT16);
1665 else
1666 rtpbasepayload->seqnum_base = rtpbasepayload->seqnum_offset;
1667 priv->next_seqnum = rtpbasepayload->seqnum_base;
1668 rtpbasepayload->seqnum = rtpbasepayload->seqnum_base;
1669
1670 if (priv->ssrc_random)
1671 rtpbasepayload->current_ssrc = g_random_int ();
1672 else
1673 rtpbasepayload->current_ssrc = rtpbasepayload->ssrc;
1674
1675 if (priv->ts_offset_random)
1676 rtpbasepayload->ts_base = g_random_int ();
1677 else
1678 rtpbasepayload->ts_base = rtpbasepayload->ts_offset;
1679 rtpbasepayload->timestamp = rtpbasepayload->ts_base;
1680 priv->running_time = DEFAULT_RUNNING_TIME;
1681 g_atomic_int_set (&rtpbasepayload->priv->notified_first_timestamp, 1);
1682 priv->base_offset = GST_BUFFER_OFFSET_NONE;
1683 priv->negotiated = FALSE;
1684 gst_caps_replace (&rtpbasepayload->priv->subclass_srccaps, NULL);
1685 gst_caps_replace (&rtpbasepayload->priv->sinkcaps, NULL);
1686 break;
1687 default:
1688 break;
1689 }
1690
1691 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1692
1693 switch (transition) {
1694 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1695 g_atomic_int_set (&rtpbasepayload->priv->notified_first_timestamp, 1);
1696 break;
1697 case GST_STATE_CHANGE_PAUSED_TO_READY:
1698 gst_event_replace (&rtpbasepayload->priv->pending_segment, NULL);
1699 break;
1700 default:
1701 break;
1702 }
1703 return ret;
1704 }
1705
1706 /**
1707 * gst_rtp_base_payload_set_source_info_enabled:
1708 * @payload: a #GstRTPBasePayload
1709 * @enable: whether to add contributing sources to RTP packets
1710 *
1711 * Enable or disable adding contributing sources to RTP packets from
1712 * #GstRTPSourceMeta.
1713 *
1714 * Since: 1.16
1715 **/
1716 void
gst_rtp_base_payload_set_source_info_enabled(GstRTPBasePayload * payload,gboolean enable)1717 gst_rtp_base_payload_set_source_info_enabled (GstRTPBasePayload * payload,
1718 gboolean enable)
1719 {
1720 payload->priv->source_info = enable;
1721 }
1722
1723 /**
1724 * gst_rtp_base_payload_is_source_info_enabled:
1725 * @payload: a #GstRTPBasePayload
1726 *
1727 * Queries whether the payloader will add contributing sources (CSRCs) to the
1728 * RTP header from #GstRTPSourceMeta.
1729 *
1730 * Returns: %TRUE if source-info is enabled.
1731 *
1732 * Since: 1.16
1733 **/
1734 gboolean
gst_rtp_base_payload_is_source_info_enabled(GstRTPBasePayload * payload)1735 gst_rtp_base_payload_is_source_info_enabled (GstRTPBasePayload * payload)
1736 {
1737 return payload->priv->source_info;
1738 }
1739
1740
1741 /**
1742 * gst_rtp_base_payload_get_source_count:
1743 * @payload: a #GstRTPBasePayload
1744 * @buffer: (transfer none): a #GstBuffer, typically the buffer to payload
1745 *
1746 * Count the total number of RTP sources found in the meta of @buffer, which
1747 * will be automically added by gst_rtp_base_payload_allocate_output_buffer().
1748 * If #GstRTPBasePayload:source-info is %FALSE the count will be 0.
1749 *
1750 * Returns: The number of sources.
1751 *
1752 * Since: 1.16
1753 **/
1754 guint
gst_rtp_base_payload_get_source_count(GstRTPBasePayload * payload,GstBuffer * buffer)1755 gst_rtp_base_payload_get_source_count (GstRTPBasePayload * payload,
1756 GstBuffer * buffer)
1757 {
1758 guint count = 0;
1759
1760 g_return_val_if_fail (buffer != NULL, 0);
1761
1762 if (gst_rtp_base_payload_is_source_info_enabled (payload)) {
1763 GstRTPSourceMeta *meta = gst_buffer_get_rtp_source_meta (buffer);
1764 if (meta != NULL)
1765 count = gst_rtp_source_meta_get_source_count (meta);
1766 }
1767
1768 return count;
1769 }
1770