2 * Copyright (C) 2008 Wim Taymans <wim.taymans at gmail.com>
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.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
21 * @short_description: The media pipeline
22 * @see_also: #GstRTSPMediaFactory, #GstRTSPStream, #GstRTSPSession,
23 * #GstRTSPSessionMedia
25 * a #GstRTSPMedia contains the complete GStreamer pipeline to manage the
26 * streaming to the clients. The actual data transfer is done by the
27 * #GstRTSPStream objects that are created and exposed by the #GstRTSPMedia.
29 * The #GstRTSPMedia is usually created from a #GstRTSPMediaFactory when the
30 * client does a DESCRIBE or SETUP of a resource.
32 * A media is created with gst_rtsp_media_new() that takes the element that will
33 * provide the streaming elements. For each of the streams, a new #GstRTSPStream
34 * object needs to be made with the gst_rtsp_media_create_stream() which takes
35 * the payloader element and the source pad that produces the RTP stream.
37 * The pipeline of the media is set to PAUSED with gst_rtsp_media_prepare(). The
38 * prepare method will add rtpbin and sinks and sources to send and receive RTP
39 * and RTCP packets from the clients. Each stream srcpad is connected to an
40 * input into the internal rtpbin.
42 * It is also possible to dynamically create #GstRTSPStream objects during the
43 * prepare phase. With gst_rtsp_media_get_status() you can check the status of
46 * After the media is prepared, it is ready for streaming. It will usually be
47 * managed in a session with gst_rtsp_session_manage_media(). See
48 * #GstRTSPSession and #GstRTSPSessionMedia.
50 * The state of the media can be controlled with gst_rtsp_media_set_state ().
51 * Seeking can be done with gst_rtsp_media_seek().
53 * With gst_rtsp_media_unprepare() the pipeline is stopped and shut down. When
54 * gst_rtsp_media_set_eos_shutdown() an EOS will be sent to the pipeline to
57 * With gst_rtsp_media_set_shared(), the media can be shared between multiple
58 * clients. With gst_rtsp_media_set_reusable() you can control if the pipeline
59 * can be prepared again after an unprepare.
61 * Last reviewed on 2013-07-11 (1.0.0)
71 #include <gst/app/gstappsrc.h>
72 #include <gst/app/gstappsink.h>
74 #include "rtsp-media-ext.h"
76 #define GST_RTSP_MEDIA_EXT_GET_PRIVATE(obj) \
77 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_MEDIA_EXT, GstRTSPMediaExtPrivate))
79 #define RTP_RETRANS_PORT 19120
81 typedef struct _GstRTSPMediaExtRTPResender GstRTSPMediaExtRTPResender;
83 struct _GstRTSPMediaExtRTPResender
85 /* sinks used for sending and receiving RTP and RTCP over ipv4, they share
87 GstElement *udpsrc_v4;
89 /* for TCP transport */
93 GstElement *resend_sink;
96 struct _GstRTSPMediaExtPrivate
99 GstRTSPMediaExtMode mode;
101 GstRTSPMediaExtRTPResender rtp_resender;
105 /* pads on the rtpbin */
108 guint retransmit_port;
111 GstRTSPMediaExtLatency latency_mode;
113 GstElement *identity;
117 GST_DEBUG_CATEGORY_STATIC (rtsp_media_ext_debug);
118 #define GST_CAT_DEFAULT rtsp_media_ext_debug
120 static void gst_rtsp_media_ext_get_property (GObject * object, guint propid,
121 GValue * value, GParamSpec * pspec);
122 static void gst_rtsp_media_ext_set_property (GObject * object, guint propid,
123 const GValue * value, GParamSpec * pspec);
124 static void gst_rtsp_media_ext_finalize (GObject * obj);
126 static void ext_preparing (GstRTSPMedia * media, GstRTSPStream * stream,
128 static void ext_unpreparing (GstRTSPMedia * media, GstRTSPStream * stream,
131 G_DEFINE_TYPE (GstRTSPMediaExt, gst_rtsp_media_ext, GST_TYPE_RTSP_MEDIA);
134 gst_rtsp_media_ext_class_init (GstRTSPMediaExtClass * klass)
136 GObjectClass *gobject_class;
137 GstRTSPMediaClass *rtsp_media_class;
139 g_type_class_add_private (klass, sizeof (GstRTSPMediaExtPrivate));
141 gobject_class = G_OBJECT_CLASS (klass);
142 rtsp_media_class = GST_RTSP_MEDIA_CLASS (klass);
144 gobject_class->get_property = gst_rtsp_media_ext_get_property;
145 gobject_class->set_property = gst_rtsp_media_ext_set_property;
146 gobject_class->finalize = gst_rtsp_media_ext_finalize;
148 GST_DEBUG_CATEGORY_INIT (rtsp_media_ext_debug, "rtspmediaext", 0,
151 rtsp_media_class->preparing = ext_preparing;
152 rtsp_media_class->unpreparing = ext_unpreparing;
156 gst_rtsp_media_ext_init (GstRTSPMediaExt * media)
158 GstRTSPMediaExtPrivate *priv = GST_RTSP_MEDIA_EXT_GET_PRIVATE (media);
161 priv->is_joined = FALSE;
162 priv->mode = MEDIA_EXT_MODE_RESEND;
163 priv->retransmit_port = RTP_RETRANS_PORT;
164 priv->max_size_k = 10;
165 priv->max_size_p = 10;
166 priv->latency_mode = MEDIA_EXT_LATENCY_LOW;
167 memset (&priv->rtp_resender, 0x00, sizeof (GstRTSPMediaExtRTPResender));
168 g_mutex_init (&priv->lock);
172 gst_rtsp_media_ext_finalize (GObject * obj)
174 GstRTSPMediaExtPrivate *priv;
175 GstRTSPMediaExt *media;
177 media = GST_RTSP_MEDIA_EXT (obj);
179 g_mutex_clear (&priv->lock);
181 G_OBJECT_CLASS (gst_rtsp_media_ext_parent_class)->finalize (obj);
185 gst_rtsp_media_ext_get_property (GObject * object, guint propid, GValue * value,
191 gst_rtsp_media_ext_set_property (GObject * object, guint propid,
192 const GValue * value, GParamSpec * pspec)
197 gst_rtsp_media_ext_new (GstElement * element)
199 GstRTSPMediaExt *result;
201 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
203 result = g_object_new (GST_TYPE_RTSP_MEDIA_EXT, "element", element, NULL);
208 static gint in_idle_probe = FALSE;
211 alloc_ports (GstRTSPMediaExt * media)
213 GstStateChangeReturn ret;
217 gint tmp_feedback_rtcp;
218 gint feedback_rtcpport;
220 GInetAddress *inetaddr = NULL;
221 GSocketAddress *feedback_rtcp_sockaddr = NULL;
222 GSocket *feedback_rtp_socket;
223 GSocketFamily family = G_SOCKET_FAMILY_IPV4;
224 const gchar *sink_socket = "socket";
225 gchar *resend_uri = NULL;
227 GstRTSPMediaExtPrivate *priv;
230 g_return_val_if_fail (priv != NULL, GST_PAD_PROBE_REMOVE);
235 /* Start with random port */
236 tmp_feedback_rtcp = priv->retransmit_port + 1;
238 feedback_rtp_socket =
239 g_socket_new (family, G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP,
242 if (!feedback_rtp_socket)
243 goto no_udp_protocol;
245 inetaddr = g_inet_address_new_any (family);
247 feedback_rtcp_sockaddr =
248 g_inet_socket_address_new (inetaddr, tmp_feedback_rtcp);
250 g_object_unref (inetaddr);
253 if (!g_socket_bind (feedback_rtp_socket, feedback_rtcp_sockaddr, FALSE, NULL)) {
254 g_object_unref (feedback_rtcp_sockaddr);
257 g_object_unref (feedback_rtcp_sockaddr);
259 udpsrc = gst_element_factory_make ("udpsrc", NULL);
262 goto no_udp_protocol;
264 g_object_set (G_OBJECT (udpsrc), "socket", feedback_rtp_socket, NULL);
266 ret = gst_element_set_state (udpsrc, GST_STATE_READY);
267 if (ret == GST_STATE_CHANGE_FAILURE)
270 /* all fine, do port check */
271 g_object_get (G_OBJECT (udpsrc), "port", &feedback_rtcpport, NULL);
273 /* this should not happen... */
274 if (feedback_rtcpport != tmp_feedback_rtcp)
277 resend_uri = g_strdup_printf ("udp://localhost:%d", priv->retransmit_port);
279 udpsink = gst_element_make_from_uri (GST_URI_SINK, resend_uri, NULL, NULL);
284 goto no_udp_protocol;
286 g_object_set (G_OBJECT (udpsink), "close-socket", FALSE, NULL);
287 g_object_set (G_OBJECT (udpsink), sink_socket, feedback_rtp_socket, NULL);
288 g_object_set (G_OBJECT (udpsink), "sync", FALSE, NULL);
289 g_object_set (G_OBJECT (udpsink), "async", FALSE, NULL);
290 g_object_set (G_OBJECT (udpsink), "send-duplicates", FALSE, NULL);
291 g_object_set (G_OBJECT (udpsink), "auto-multicast", FALSE, NULL);
292 g_object_set (G_OBJECT (udpsink), "loop", FALSE, NULL);
294 priv->rtp_resender.resend_sink = udpsink;
295 priv->rtp_resender.udpsrc_v4 = udpsrc;
315 gst_element_set_state (udpsrc, GST_STATE_NULL);
316 gst_object_unref (udpsrc);
319 gst_element_set_state (udpsink, GST_STATE_NULL);
320 gst_object_unref (udpsink);
323 g_object_unref (inetaddr);
328 static GstPadProbeReturn
329 pad_probe_cb (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
331 GstPad *sinkpad, *resend_pad, *fecpad;
332 GstRTSPMediaExt *media = NULL;
333 GstRTSPMediaExtPrivate *priv;
335 if (!g_atomic_int_compare_and_exchange (&in_idle_probe, FALSE, TRUE))
336 return GST_PAD_PROBE_OK;
338 media = (GstRTSPMediaExt *) user_data;
342 g_return_val_if_fail (priv != NULL, GST_PAD_PROBE_REMOVE);
344 sinkpad = gst_pad_get_peer (priv->send_src);
345 gst_pad_unlink (priv->send_src, sinkpad);
347 if (priv->mode & MEDIA_EXT_MODE_RESEND) {
348 GST_INFO_OBJECT (media, "joining resender");
350 gst_element_get_static_pad (priv->rtp_resender.resender, "rtp_sink");
351 gst_pad_link (priv->send_src, resend_pad);
352 gst_object_unref (resend_pad);
356 GstPad *identity_src, *identity_sink;
357 identity_src = gst_element_get_static_pad (priv->identity, "src");
358 identity_sink = gst_element_get_static_pad (priv->identity, "sink");
360 gst_element_get_static_pad (priv->rtp_resender.resender, "send_src");
361 gst_pad_link (resend_pad, identity_sink);
362 gst_pad_link (identity_src, sinkpad);
363 gst_object_unref (identity_sink);
364 gst_object_unref (identity_src);
368 gst_element_get_static_pad (priv->rtp_resender.resender, "send_src");
369 gst_pad_link (resend_pad, sinkpad);
371 gst_object_unref (resend_pad);
372 } else if (priv->mode & MEDIA_EXT_MODE_FEC) {
373 GST_INFO_OBJECT (media, "joining fec encoder");
374 fecpad = gst_element_get_static_pad (priv->fecenc, "sink");
375 gst_pad_link (priv->send_src, fecpad);
376 gst_object_unref (fecpad);
380 GstPad *identity_src, *identity_sink;
381 identity_src = gst_element_get_static_pad (priv->identity, "src");
382 identity_sink = gst_element_get_static_pad (priv->identity, "sink");
384 fecpad = gst_element_get_static_pad (priv->fecenc, "src");
386 gst_pad_link (fecpad, identity_sink);
387 gst_pad_link (identity_src, sinkpad);
388 gst_object_unref (identity_sink);
389 gst_object_unref (identity_src);
392 fecpad = gst_element_get_static_pad (priv->fecenc, "src");
393 gst_pad_link (fecpad, sinkpad);
395 gst_object_unref (fecpad);
398 gst_object_unref (sinkpad);
400 return GST_PAD_PROBE_REMOVE;
404 gst_rtsp_media_ext_join_extended_plugin (GstRTSPMediaExt * media, GstBin * bin,
405 GstElement * rtpbin, GstState state, guint idx)
407 GstRTSPMediaExtPrivate *priv;
409 GstPad *pad, *sinkpad, *selpad;
412 g_return_val_if_fail (GST_IS_BIN (bin), FALSE);
413 g_return_val_if_fail (GST_IS_ELEMENT (rtpbin), FALSE);
416 g_return_val_if_fail (priv != NULL, FALSE);
418 g_mutex_lock (&priv->lock);
422 GST_INFO ("media %p joining rtp resender %u", media, idx);
424 /* get pads from the RTP session element for sending and receiving
426 name = g_strdup_printf ("send_rtp_src_%u", idx);
427 priv->send_src = gst_element_get_static_pad (rtpbin, name);
430 /* make resender for RTP and link to stream */
431 priv->rtp_resender.resender = gst_element_factory_make ("rtpresender", NULL);
432 gst_bin_add (bin, priv->rtp_resender.resender);
434 gst_element_sync_state_with_parent (priv->rtp_resender.resender);
436 if (!alloc_ports (media))
439 /* For the sender we create this bit of pipeline for both
440 * RTP and RTCP. Sync and preroll are enabled on udpsink so
441 * we need to add a queue before appsink to make the pipeline
442 * not block. For the TCP case, we want to pump data to the
443 * client as fast as possible anyway.
445 * .--------. .-----. .---------.
446 * | rtpbin | | tee | | udpsink |
447 * | send->sink src->sink |
448 * '--------' | | '---------'
449 * | | .---------. .---------.
450 * | | | queue | | appsink |
451 * | src->sink src->sink |
452 * '-----' '---------' '---------'
454 * When only UDP is allowed, we skip the tee, queue and appsink and link the
455 * udpsink directly to the session.
458 gst_bin_add (bin, priv->rtp_resender.resend_sink);
459 sinkpad = gst_element_get_static_pad (priv->rtp_resender.resend_sink, "sink");
461 gst_element_get_static_pad (priv->rtp_resender.resender, "resend_src");
463 gst_pad_link (resenderpad, sinkpad);
464 gst_object_unref (resenderpad);
465 gst_object_unref (sinkpad);
467 /* For the receiver we create this bit of pipeline for both
468 * RTP and RTCP. We receive RTP/RTCP on appsrc and udpsrc
469 * and it is all funneled into the rtpbin receive pad.
471 * .--------. .--------. .--------.
472 * | udpsrc | | funnel | | rtpbin |
473 * | src->sink src->sink |
474 * '--------' | | '--------'
478 * '--------' '--------'
480 /* make funnel for the RTP/RTCP receivers */
481 priv->rtp_resender.funnel = gst_element_factory_make ("funnel", NULL);
482 gst_bin_add (bin, priv->rtp_resender.funnel);
485 gst_element_get_static_pad (priv->rtp_resender.resender, "rtcp_sink");
486 pad = gst_element_get_static_pad (priv->rtp_resender.funnel, "src");
487 gst_pad_link (pad, resenderpad);
488 gst_object_unref (resenderpad);
489 gst_object_unref (pad);
491 if (priv->rtp_resender.udpsrc_v4) {
492 /* we set and keep these to playing so that they don't cause NO_PREROLL return
494 gst_element_set_state (priv->rtp_resender.udpsrc_v4, GST_STATE_PLAYING);
495 gst_element_set_locked_state (priv->rtp_resender.udpsrc_v4, TRUE);
497 gst_bin_add (bin, priv->rtp_resender.udpsrc_v4);
499 /* and link to the funnel v4 */
500 selpad = gst_element_get_request_pad (priv->rtp_resender.funnel, "sink_%u");
501 pad = gst_element_get_static_pad (priv->rtp_resender.udpsrc_v4, "src");
502 gst_pad_link (pad, selpad);
503 gst_object_unref (pad);
504 gst_object_unref (selpad);
507 /* make and add appsrc */
508 priv->rtp_resender.appsrc = gst_element_factory_make ("appsrc", NULL);
509 gst_bin_add (bin, priv->rtp_resender.appsrc);
510 /* and link to the funnel */
511 selpad = gst_element_get_request_pad (priv->rtp_resender.funnel, "sink_%u");
512 pad = gst_element_get_static_pad (priv->rtp_resender.appsrc, "src");
513 gst_pad_link (pad, selpad);
514 gst_object_unref (pad);
515 gst_object_unref (selpad);
517 /* check if we need to set to a special state */
518 if (state != GST_STATE_NULL) {
519 if (priv->rtp_resender.resend_sink)
520 gst_element_set_state (priv->rtp_resender.resend_sink, state);
521 if (priv->rtp_resender.funnel)
522 gst_element_set_state (priv->rtp_resender.funnel, state);
523 if (priv->rtp_resender.appsrc)
524 gst_element_set_state (priv->rtp_resender.appsrc, state);
527 /* make alfec encoder for RTP and link to stream */
528 priv->fecenc = gst_element_factory_make ("alfecencoder", NULL);
529 g_object_set (G_OBJECT (priv->fecenc), "max-size-k", priv->max_size_k, NULL);
530 g_object_set (G_OBJECT (priv->fecenc), "max-size-p", priv->max_size_p, NULL);
531 GST_DEBUG ("k:%d, p:%d", priv->max_size_k, priv->max_size_p);
532 g_object_set (G_OBJECT (priv->fecenc), "next-k", priv->max_size_k, NULL);
533 g_object_set (G_OBJECT (priv->fecenc), "next-p", priv->max_size_p, NULL);
534 g_object_set (G_OBJECT (priv->fecenc), "symbol-length", 1500, NULL);
535 gst_bin_add (bin, priv->fecenc);
537 gst_element_sync_state_with_parent (priv->fecenc);
540 priv->identity = gst_element_factory_make ("identity", NULL);
541 g_object_set (G_OBJECT (priv->identity), "drop-probability", 0.05, NULL);
542 gst_bin_add (bin, priv->identity);
544 gst_element_sync_state_with_parent(priv->identity);
547 in_idle_probe = FALSE;
548 gst_pad_add_probe (priv->send_src, GST_PAD_PROBE_TYPE_IDLE, pad_probe_cb,
551 priv->is_joined = TRUE;
552 g_mutex_unlock (&priv->lock);
559 g_mutex_unlock (&priv->lock);
564 g_mutex_unlock (&priv->lock);
565 GST_WARNING ("failed to allocate ports %u", idx);
572 ext_preparing (GstRTSPMedia * media, GstRTSPStream * stream, guint idx)
574 gboolean ret = FALSE;
575 GstElement *rtpbin = NULL;
576 GstElement *pipeline = NULL;
577 GstRTSPMediaExt *_media = GST_RTSP_MEDIA_EXT (media);
578 GstRTSPMediaExtPrivate *priv;
581 g_return_if_fail (priv != NULL);
583 pipeline = gst_rtsp_media_get_pipeline (media);
584 rtpbin = gst_rtsp_media_get_rtpbin (media);
587 gst_rtsp_media_ext_join_extended_plugin (_media, GST_BIN (pipeline),
588 rtpbin, GST_STATE_NULL, idx);
590 GST_ERROR_OBJECT (_media, "Fatal error to join resender");
592 g_object_unref (pipeline);
593 g_object_unref (rtpbin);
599 gst_rtsp_media_ext_leave_extended_plugin (GstRTSPMediaExt * media, GstBin * bin,
602 GstRTSPMediaExtPrivate *priv;
604 g_return_val_if_fail (GST_IS_BIN (bin), FALSE);
605 g_return_val_if_fail (GST_IS_ELEMENT (rtpbin), FALSE);
608 g_return_val_if_fail (priv != NULL, FALSE);
610 g_mutex_lock (&priv->lock);
611 if (!priv->is_joined)
614 GST_INFO ("media %p leaving rtp resender", media);
616 if (priv->rtp_resender.resend_sink)
617 gst_element_set_state (priv->rtp_resender.resend_sink, GST_STATE_NULL);
618 if (priv->rtp_resender.funnel)
619 gst_element_set_state (priv->rtp_resender.funnel, GST_STATE_NULL);
620 if (priv->rtp_resender.appsrc)
621 gst_element_set_state (priv->rtp_resender.appsrc, GST_STATE_NULL);
623 if (priv->rtp_resender.udpsrc_v4) {
624 /* and set udpsrc to NULL now before removing */
625 gst_element_set_locked_state (priv->rtp_resender.udpsrc_v4, FALSE);
626 gst_element_set_state (priv->rtp_resender.udpsrc_v4, GST_STATE_NULL);
627 /* removing them should also nicely release the request
628 * pads when they finalize */
629 gst_bin_remove (bin, priv->rtp_resender.udpsrc_v4);
632 if (priv->rtp_resender.resend_sink)
633 gst_bin_remove (bin, priv->rtp_resender.resend_sink);
634 if (priv->rtp_resender.appsrc)
635 gst_bin_remove (bin, priv->rtp_resender.appsrc);
636 if (priv->rtp_resender.funnel)
637 gst_bin_remove (bin, priv->rtp_resender.funnel);
639 priv->rtp_resender.udpsrc_v4 = NULL;
640 priv->rtp_resender.resend_sink = NULL;
641 priv->rtp_resender.appsrc = NULL;
642 priv->rtp_resender.funnel = NULL;
644 GST_INFO ("media %p leaving fec encoder", media);
647 gst_element_set_state (priv->fecenc, GST_STATE_NULL);
651 gst_object_unref (priv->send_src);
652 priv->send_src = NULL;
653 priv->is_joined = FALSE;
654 g_mutex_unlock (&priv->lock);
660 g_mutex_unlock (&priv->lock);
667 ext_unpreparing (GstRTSPMedia * media, GstRTSPStream * stream, guint idx)
669 gboolean ret = FALSE;
670 GstElement *rtpbin = NULL;
671 GstElement *pipeline = NULL;
672 GstRTSPMediaExt *_media = GST_RTSP_MEDIA_EXT (media);
673 GstRTSPMediaExtPrivate *priv;
676 g_return_if_fail (priv != NULL);
678 pipeline = gst_rtsp_media_get_pipeline (media);
679 rtpbin = gst_rtsp_media_get_rtpbin (media);
682 gst_rtsp_media_ext_leave_extended_plugin (_media, GST_BIN (pipeline),
686 GST_ERROR_OBJECT (_media, "Fatal error to leave resender");
688 g_object_unref (pipeline);
689 g_object_unref (rtpbin);
695 gst_rtsp_media_ext_get_resent_packets (GstRTSPMediaExt * media)
697 guint resent_packets = 0;
698 GstRTSPMediaExtPrivate *priv;
700 g_return_val_if_fail (GST_IS_RTSP_MEDIA_EXT (media), 0);
703 g_return_val_if_fail (priv != NULL, 0);
705 g_object_get (G_OBJECT (priv->rtp_resender.resender), "rtp-packets-resend",
706 &resent_packets, NULL);
708 return resent_packets;
712 gst_rtsp_media_ext_set_extended_mode (GstRTSPMediaExt * media,
713 GstRTSPMediaExtMode mode)
715 GstRTSPMediaExtPrivate *priv;
717 g_return_if_fail (GST_IS_RTSP_MEDIA_EXT (media));
720 g_return_if_fail (priv != NULL);
726 gst_rtsp_media_ext_set_retrans_port (GstRTSPMediaExt * media, guint port)
728 GstRTSPMediaExtPrivate *priv;
730 g_return_if_fail (GST_IS_RTSP_MEDIA_EXT (media));
733 g_return_if_fail (priv != NULL);
735 priv->retransmit_port = port;
739 gst_rtsp_media_ext_set_fec_value (GstRTSPMediaExt * media, guint max_k,
742 GstRTSPMediaExtPrivate *priv;
744 g_return_if_fail (GST_IS_RTSP_MEDIA_EXT (media));
747 g_return_if_fail (priv != NULL);
749 priv->max_size_k = max_k;
750 priv->max_size_p = max_p;
754 gst_rtsp_media_ext_set_latency_mode (GstRTSPMediaExt * media,
755 GstRTSPMediaExtLatency latency)
757 GstRTSPMediaExtPrivate *priv;
759 g_return_if_fail (GST_IS_RTSP_MEDIA_EXT (media));
762 g_return_if_fail (priv != NULL);
764 priv->latency_mode = latency;
768 gst_rtsp_media_ext_set_next_param (GstRTSPMediaExt * media, gint32 next_k,
771 GstRTSPMediaExtPrivate *priv;
773 g_return_if_fail (GST_IS_RTSP_MEDIA_EXT (media));
776 g_return_if_fail (priv != NULL);
778 g_object_set (G_OBJECT (priv->fecenc), "next-k", next_k, NULL);
779 g_object_set (G_OBJECT (priv->fecenc), "next-p", next_p, NULL);