diff options
Diffstat (limited to 'gst-libs/gst/rtp/gstbasertppayload.c')
-rw-r--r-- | gst-libs/gst/rtp/gstbasertppayload.c | 1018 |
1 files changed, 0 insertions, 1018 deletions
diff --git a/gst-libs/gst/rtp/gstbasertppayload.c b/gst-libs/gst/rtp/gstbasertppayload.c deleted file mode 100644 index 783e4020..00000000 --- a/gst-libs/gst/rtp/gstbasertppayload.c +++ /dev/null @@ -1,1018 +0,0 @@ -/* GStreamer - * Copyright (C) <2005> Wim Taymans <wim@fluendo.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more - */ - -/** - * SECTION:gstbasertppayload - * @short_description: Base class for RTP payloader - * - * <refsect2> - * <para> - * Provides a base class for RTP payloaders - * </para> - * </refsect2> - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include <string.h> - -#include <gst/rtp/gstrtpbuffer.h> - -#include "gstbasertppayload.h" - -GST_DEBUG_CATEGORY_STATIC (basertppayload_debug); -#define GST_CAT_DEFAULT (basertppayload_debug) - -#define GST_BASE_RTP_PAYLOAD_GET_PRIVATE(obj) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_BASE_RTP_PAYLOAD, GstBaseRTPPayloadPrivate)) - -struct _GstBaseRTPPayloadPrivate -{ - gboolean ts_offset_random; - gboolean seqnum_offset_random; - gboolean ssrc_random; - guint16 next_seqnum; - gboolean perfect_rtptime; - - gint64 prop_max_ptime; - gint64 caps_max_ptime; -}; - -/* BaseRTPPayload signals and args */ -enum -{ - /* FILL ME */ - LAST_SIGNAL -}; - -/* FIXME 0.11, a better default is the Ethernet MTU of - * 1500 - sizeof(headers) as pointed out by marcelm in IRC: - * So an Ethernet MTU of 1500, minus 60 for the max IP, minus 8 for UDP, gives - * 1432 bytes or so. And that should be adjusted downward further for other - * encapsulations like PPPoE, so 1400 at most. - */ -#define DEFAULT_MTU 1400 -#define DEFAULT_PT 96 -#define DEFAULT_SSRC -1 -#define DEFAULT_TIMESTAMP_OFFSET -1 -#define DEFAULT_SEQNUM_OFFSET -1 -#define DEFAULT_MAX_PTIME -1 -#define DEFAULT_MIN_PTIME 0 -#define DEFAULT_PERFECT_RTPTIME TRUE - -enum -{ - PROP_0, - PROP_MTU, - PROP_PT, - PROP_SSRC, - PROP_TIMESTAMP_OFFSET, - PROP_SEQNUM_OFFSET, - PROP_MAX_PTIME, - PROP_MIN_PTIME, - PROP_TIMESTAMP, - PROP_SEQNUM, - PROP_PERFECT_RTPTIME, - PROP_LAST -}; - -static void gst_basertppayload_class_init (GstBaseRTPPayloadClass * klass); -static void gst_basertppayload_base_init (GstBaseRTPPayloadClass * klass); -static void gst_basertppayload_init (GstBaseRTPPayload * basertppayload, - gpointer g_class); -static void gst_basertppayload_finalize (GObject * object); - -static gboolean gst_basertppayload_sink_setcaps (GstPad * pad, GstCaps * caps); -static GstCaps *gst_basertppayload_sink_getcaps (GstPad * pad); -static gboolean gst_basertppayload_event (GstPad * pad, GstEvent * event); -static GstFlowReturn gst_basertppayload_chain (GstPad * pad, - GstBuffer * buffer); - -static void gst_basertppayload_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static void gst_basertppayload_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); - -static GstStateChangeReturn gst_basertppayload_change_state (GstElement * - element, GstStateChange transition); - -static GstElementClass *parent_class = NULL; - -/* FIXME 0.11: API should be changed to gst_base_typ_payload_xyz */ - -GType -gst_basertppayload_get_type (void) -{ - static GType basertppayload_type = 0; - - if (!basertppayload_type) { - static const GTypeInfo basertppayload_info = { - sizeof (GstBaseRTPPayloadClass), - (GBaseInitFunc) gst_basertppayload_base_init, - NULL, - (GClassInitFunc) gst_basertppayload_class_init, - NULL, - NULL, - sizeof (GstBaseRTPPayload), - 0, - (GInstanceInitFunc) gst_basertppayload_init, - }; - - basertppayload_type = - g_type_register_static (GST_TYPE_ELEMENT, "GstBaseRTPPayload", - &basertppayload_info, G_TYPE_FLAG_ABSTRACT); - } - return basertppayload_type; -} - -static void -gst_basertppayload_base_init (GstBaseRTPPayloadClass * klass) -{ -} - -static void -gst_basertppayload_class_init (GstBaseRTPPayloadClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *gstelement_class; - - gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; - - g_type_class_add_private (klass, sizeof (GstBaseRTPPayloadPrivate)); - - parent_class = g_type_class_peek_parent (klass); - - gobject_class->finalize = gst_basertppayload_finalize; - - gobject_class->set_property = gst_basertppayload_set_property; - gobject_class->get_property = gst_basertppayload_get_property; - - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MTU, - g_param_spec_uint ("mtu", "MTU", - "Maximum size of one packet", - 28, G_MAXUINT, DEFAULT_MTU, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PT, - g_param_spec_uint ("pt", "payload type", - "The payload type of the packets", 0, 0x80, DEFAULT_PT, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SSRC, - g_param_spec_uint ("ssrc", "SSRC", - "The SSRC of the packets (default == random)", 0, G_MAXUINT32, - DEFAULT_SSRC, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (G_OBJECT_CLASS (klass), - PROP_TIMESTAMP_OFFSET, g_param_spec_uint ("timestamp-offset", - "Timestamp Offset", - "Offset to add to all outgoing timestamps (default = random)", 0, - G_MAXUINT32, DEFAULT_TIMESTAMP_OFFSET, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SEQNUM_OFFSET, - g_param_spec_int ("seqnum-offset", "Sequence number Offset", - "Offset to add to all outgoing seqnum (-1 = random)", -1, G_MAXUINT16, - DEFAULT_SEQNUM_OFFSET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MAX_PTIME, - g_param_spec_int64 ("max-ptime", "Max packet time", - "Maximum duration of the packet data in ns (-1 = unlimited up to MTU)", - -1, G_MAXINT64, DEFAULT_MAX_PTIME, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - /** - * GstBaseRTPAudioPayload:min-ptime: - * - * Minimum duration of the packet data in ns (can't go above MTU) - * - * Since: 0.10.13 - **/ - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MIN_PTIME, - g_param_spec_int64 ("min-ptime", "Min packet time", - "Minimum duration of the packet data in ns (can't go above MTU)", - 0, G_MAXINT64, DEFAULT_MIN_PTIME, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TIMESTAMP, - g_param_spec_uint ("timestamp", "Timestamp", - "The RTP timestamp of the last processed packet", - 0, G_MAXUINT32, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SEQNUM, - g_param_spec_uint ("seqnum", "Sequence number", - "The RTP sequence number of the last processed packet", - 0, G_MAXUINT16, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); - - /** - * GstBaseRTPAudioPayload:perfect-rtptime: - * - * Try to use the offset fields to generate perfect RTP timestamps. when this - * option is disabled, RTP timestamps are generated from the GStreamer - * timestamps, which could result in RTP timestamps that don't increment with - * the amount of data in the packet. - * - * Since: 0.10.25 - */ - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PERFECT_RTPTIME, - g_param_spec_boolean ("perfect-rtptime", "Perfect RTP Time", - "Generate perfect RTP timestamps when possible", - DEFAULT_PERFECT_RTPTIME, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - gstelement_class->change_state = gst_basertppayload_change_state; - - GST_DEBUG_CATEGORY_INIT (basertppayload_debug, "basertppayload", 0, - "Base class for RTP Payloaders"); -} - -static void -gst_basertppayload_init (GstBaseRTPPayload * basertppayload, gpointer g_class) -{ - GstPadTemplate *templ; - GstBaseRTPPayloadPrivate *priv; - - basertppayload->priv = priv = - GST_BASE_RTP_PAYLOAD_GET_PRIVATE (basertppayload); - - templ = - gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "src"); - g_return_if_fail (templ != NULL); - - basertppayload->srcpad = gst_pad_new_from_template (templ, "src"); - gst_element_add_pad (GST_ELEMENT (basertppayload), basertppayload->srcpad); - - templ = - gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "sink"); - g_return_if_fail (templ != NULL); - - basertppayload->sinkpad = gst_pad_new_from_template (templ, "sink"); - gst_pad_set_setcaps_function (basertppayload->sinkpad, - gst_basertppayload_sink_setcaps); - gst_pad_set_getcaps_function (basertppayload->sinkpad, - gst_basertppayload_sink_getcaps); - gst_pad_set_event_function (basertppayload->sinkpad, - gst_basertppayload_event); - gst_pad_set_chain_function (basertppayload->sinkpad, - gst_basertppayload_chain); - gst_element_add_pad (GST_ELEMENT (basertppayload), basertppayload->sinkpad); - - basertppayload->seq_rand = g_rand_new_with_seed (g_random_int ()); - basertppayload->ssrc_rand = g_rand_new_with_seed (g_random_int ()); - basertppayload->ts_rand = g_rand_new_with_seed (g_random_int ()); - - basertppayload->mtu = DEFAULT_MTU; - basertppayload->pt = DEFAULT_PT; - basertppayload->seqnum_offset = DEFAULT_SEQNUM_OFFSET; - basertppayload->ssrc = DEFAULT_SSRC; - basertppayload->ts_offset = DEFAULT_TIMESTAMP_OFFSET; - priv->seqnum_offset_random = (basertppayload->seqnum_offset == -1); - priv->ts_offset_random = (basertppayload->ts_offset == -1); - priv->ssrc_random = (basertppayload->ssrc == -1); - - basertppayload->max_ptime = DEFAULT_MAX_PTIME; - basertppayload->min_ptime = DEFAULT_MIN_PTIME; - basertppayload->priv->perfect_rtptime = DEFAULT_PERFECT_RTPTIME; - - basertppayload->media = NULL; - basertppayload->encoding_name = NULL; - - basertppayload->clock_rate = 0; - - basertppayload->priv->caps_max_ptime = DEFAULT_MAX_PTIME; - basertppayload->priv->prop_max_ptime = DEFAULT_MAX_PTIME; -} - -static void -gst_basertppayload_finalize (GObject * object) -{ - GstBaseRTPPayload *basertppayload; - - basertppayload = GST_BASE_RTP_PAYLOAD (object); - - g_rand_free (basertppayload->seq_rand); - basertppayload->seq_rand = NULL; - g_rand_free (basertppayload->ssrc_rand); - basertppayload->ssrc_rand = NULL; - g_rand_free (basertppayload->ts_rand); - basertppayload->ts_rand = NULL; - - g_free (basertppayload->media); - basertppayload->media = NULL; - g_free (basertppayload->encoding_name); - basertppayload->encoding_name = NULL; - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static gboolean -gst_basertppayload_sink_setcaps (GstPad * pad, GstCaps * caps) -{ - GstBaseRTPPayload *basertppayload; - GstBaseRTPPayloadClass *basertppayload_class; - gboolean ret = TRUE; - - GST_DEBUG_OBJECT (pad, "setting caps %" GST_PTR_FORMAT, caps); - basertppayload = GST_BASE_RTP_PAYLOAD (gst_pad_get_parent (pad)); - basertppayload_class = GST_BASE_RTP_PAYLOAD_GET_CLASS (basertppayload); - - if (basertppayload_class->set_caps) - ret = basertppayload_class->set_caps (basertppayload, caps); - - gst_object_unref (basertppayload); - - return ret; -} - -static GstCaps * -gst_basertppayload_sink_getcaps (GstPad * pad) -{ - GstBaseRTPPayload *basertppayload; - GstBaseRTPPayloadClass *basertppayload_class; - GstCaps *caps = NULL; - - GST_DEBUG_OBJECT (pad, "getting caps"); - - basertppayload = GST_BASE_RTP_PAYLOAD (gst_pad_get_parent (pad)); - basertppayload_class = GST_BASE_RTP_PAYLOAD_GET_CLASS (basertppayload); - - if (basertppayload_class->get_caps) - caps = basertppayload_class->get_caps (basertppayload, pad); - - if (!caps) { - caps = GST_PAD_TEMPLATE_CAPS (GST_PAD_PAD_TEMPLATE (pad)); - GST_DEBUG_OBJECT (pad, - "using pad template %p with caps %p %" GST_PTR_FORMAT, - GST_PAD_PAD_TEMPLATE (pad), caps, caps); - - caps = gst_caps_ref (caps); - } - - gst_object_unref (basertppayload); - - return caps; -} - -static gboolean -gst_basertppayload_event (GstPad * pad, GstEvent * event) -{ - GstBaseRTPPayload *basertppayload; - GstBaseRTPPayloadClass *basertppayload_class; - gboolean res; - - basertppayload = GST_BASE_RTP_PAYLOAD (gst_pad_get_parent (pad)); - basertppayload_class = GST_BASE_RTP_PAYLOAD_GET_CLASS (basertppayload); - - if (basertppayload_class->handle_event) { - res = basertppayload_class->handle_event (pad, event); - if (res) - goto done; - } - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_FLUSH_START: - res = gst_pad_event_default (pad, event); - break; - case GST_EVENT_FLUSH_STOP: - res = gst_pad_event_default (pad, event); - gst_segment_init (&basertppayload->segment, GST_FORMAT_UNDEFINED); - break; - case GST_EVENT_NEWSEGMENT: - { - gboolean update; - gdouble rate; - GstFormat fmt; - gint64 start, stop, position; - - gst_event_parse_new_segment (event, &update, &rate, &fmt, &start, &stop, - &position); - gst_segment_set_newsegment (&basertppayload->segment, update, rate, fmt, - start, stop, position); - - /* fallthrough */ - } - default: - res = gst_pad_event_default (pad, event); - break; - } - -done: - gst_object_unref (basertppayload); - - return res; -} - - -static GstFlowReturn -gst_basertppayload_chain (GstPad * pad, GstBuffer * buffer) -{ - GstBaseRTPPayload *basertppayload; - GstBaseRTPPayloadClass *basertppayload_class; - GstFlowReturn ret; - - basertppayload = GST_BASE_RTP_PAYLOAD (gst_pad_get_parent (pad)); - basertppayload_class = GST_BASE_RTP_PAYLOAD_GET_CLASS (basertppayload); - - if (!basertppayload_class->handle_buffer) - goto no_function; - - ret = basertppayload_class->handle_buffer (basertppayload, buffer); - - gst_object_unref (basertppayload); - - return ret; - - /* ERRORS */ -no_function: - { - GST_ELEMENT_ERROR (basertppayload, STREAM, NOT_IMPLEMENTED, (NULL), - ("subclass did not implement handle_buffer function")); - gst_object_unref (basertppayload); - gst_buffer_unref (buffer); - return GST_FLOW_ERROR; - } -} - -/** - * gst_basertppayload_set_options: - * @payload: a #GstBaseRTPPayload - * @media: the media type (typically "audio" or "video") - * @dynamic: if the payload type is dynamic - * @encoding_name: the encoding name - * @clock_rate: the clock rate of the media - * - * Set the rtp options of the payloader. These options will be set in the caps - * of the payloader. Subclasses must call this method before calling - * gst_basertppayload_push() or gst_basertppayload_set_outcaps(). - */ -void -gst_basertppayload_set_options (GstBaseRTPPayload * payload, - gchar * media, gboolean dynamic, gchar * encoding_name, guint32 clock_rate) -{ - g_return_if_fail (payload != NULL); - g_return_if_fail (clock_rate != 0); - - g_free (payload->media); - payload->media = g_strdup (media); - payload->dynamic = dynamic; - g_free (payload->encoding_name); - payload->encoding_name = g_strdup (encoding_name); - payload->clock_rate = clock_rate; -} - -static gboolean -copy_fixed (GQuark field_id, const GValue * value, GstStructure * dest) -{ - if (gst_value_is_fixed (value)) { - gst_structure_id_set_value (dest, field_id, value); - } - return TRUE; -} - -static void -update_max_ptime (GstBaseRTPPayload * basertppayload) -{ - if (basertppayload->priv->caps_max_ptime != -1 && - basertppayload->priv->prop_max_ptime != -1) - basertppayload->max_ptime = MIN (basertppayload->priv->caps_max_ptime, - basertppayload->priv->prop_max_ptime); - else if (basertppayload->priv->caps_max_ptime != -1) - basertppayload->max_ptime = basertppayload->priv->caps_max_ptime; - else if (basertppayload->priv->prop_max_ptime != -1) - basertppayload->max_ptime = basertppayload->priv->prop_max_ptime; - else - basertppayload->max_ptime = DEFAULT_MAX_PTIME; -} - -/** - * gst_basertppayload_set_outcaps: - * @payload: a #GstBaseRTPPayload - * @fieldname: the first field name or %NULL - * @...: field values - * - * Configure the output caps with the optional parameters. - * - * Variable arguments should be in the form field name, field type - * (as a GType), value(s). The last variable argument should be NULL. - * - * Returns: %TRUE if the caps could be set. - */ -gboolean -gst_basertppayload_set_outcaps (GstBaseRTPPayload * payload, gchar * fieldname, - ...) -{ - GstCaps *srccaps, *peercaps; - gboolean res; - - /* fill in the defaults, their properties cannot be negotiated. */ - srccaps = gst_caps_new_simple ("application/x-rtp", - "media", G_TYPE_STRING, payload->media, - "clock-rate", G_TYPE_INT, payload->clock_rate, - "encoding-name", G_TYPE_STRING, payload->encoding_name, NULL); - - GST_DEBUG_OBJECT (payload, "defaults: %" GST_PTR_FORMAT, srccaps); - - if (fieldname) { - va_list varargs; - - /* override with custom properties */ - va_start (varargs, fieldname); - gst_caps_set_simple_valist (srccaps, fieldname, varargs); - va_end (varargs); - - GST_DEBUG_OBJECT (payload, "custom added: %" GST_PTR_FORMAT, srccaps); - } - - payload->priv->caps_max_ptime = DEFAULT_MAX_PTIME; - payload->abidata.ABI.ptime = 0; - - /* the peer caps can override some of the defaults */ - peercaps = gst_pad_peer_get_caps (payload->srcpad); - if (peercaps == NULL) { - /* no peer caps, just add the other properties */ - gst_caps_set_simple (srccaps, - "payload", G_TYPE_INT, GST_BASE_RTP_PAYLOAD_PT (payload), - "ssrc", G_TYPE_UINT, payload->current_ssrc, - "clock-base", G_TYPE_UINT, payload->ts_base, - "seqnum-base", G_TYPE_UINT, payload->seqnum_base, NULL); - - GST_DEBUG_OBJECT (payload, "no peer caps: %" GST_PTR_FORMAT, srccaps); - } else { - GstCaps *temp; - GstStructure *s, *d; - const GValue *value; - gint pt; - guint max_ptime, ptime; - - /* peer provides caps we can use to fixate, intersect. This always returns a - * writable caps. */ - temp = gst_caps_intersect (srccaps, peercaps); - gst_caps_unref (srccaps); - gst_caps_unref (peercaps); - - if (gst_caps_is_empty (temp)) { - gst_caps_unref (temp); - return FALSE; - } - - /* now fixate, start by taking the first caps */ - gst_caps_truncate (temp); - - /* get first structure */ - s = gst_caps_get_structure (temp, 0); - - if (gst_structure_get_uint (s, "maxptime", &max_ptime)) - payload->priv->caps_max_ptime = max_ptime * GST_MSECOND; - - if (gst_structure_get_uint (s, "ptime", &ptime)) - payload->abidata.ABI.ptime = ptime * GST_MSECOND; - - if (gst_structure_get_int (s, "payload", &pt)) { - /* use peer pt */ - GST_BASE_RTP_PAYLOAD_PT (payload) = pt; - GST_LOG_OBJECT (payload, "using peer pt %d", pt); - } else { - if (gst_structure_has_field (s, "payload")) { - /* can only fixate if there is a field */ - gst_structure_fixate_field_nearest_int (s, "payload", - GST_BASE_RTP_PAYLOAD_PT (payload)); - gst_structure_get_int (s, "payload", &pt); - GST_LOG_OBJECT (payload, "using peer pt %d", pt); - } else { - /* no pt field, use the internal pt */ - pt = GST_BASE_RTP_PAYLOAD_PT (payload); - gst_structure_set (s, "payload", G_TYPE_INT, pt, NULL); - GST_LOG_OBJECT (payload, "using internal pt %d", pt); - } - } - - if (gst_structure_has_field_typed (s, "ssrc", G_TYPE_UINT)) { - value = gst_structure_get_value (s, "ssrc"); - payload->current_ssrc = g_value_get_uint (value); - GST_LOG_OBJECT (payload, "using peer ssrc %08x", payload->current_ssrc); - } else { - /* FIXME, fixate_nearest_uint would be even better */ - gst_structure_set (s, "ssrc", G_TYPE_UINT, payload->current_ssrc, NULL); - GST_LOG_OBJECT (payload, "using internal ssrc %08x", - payload->current_ssrc); - } - - if (gst_structure_has_field_typed (s, "clock-base", G_TYPE_UINT)) { - value = gst_structure_get_value (s, "clock-base"); - payload->ts_base = g_value_get_uint (value); - GST_LOG_OBJECT (payload, "using peer clock-base %u", payload->ts_base); - } else { - /* FIXME, fixate_nearest_uint would be even better */ - gst_structure_set (s, "clock-base", G_TYPE_UINT, payload->ts_base, NULL); - GST_LOG_OBJECT (payload, "using internal clock-base %u", - payload->ts_base); - } - if (gst_structure_has_field_typed (s, "seqnum-base", G_TYPE_UINT)) { - value = gst_structure_get_value (s, "seqnum-base"); - payload->seqnum_base = g_value_get_uint (value); - GST_LOG_OBJECT (payload, "using peer seqnum-base %u", - payload->seqnum_base); - } else { - /* FIXME, fixate_nearest_uint would be even better */ - gst_structure_set (s, "seqnum-base", G_TYPE_UINT, payload->seqnum_base, - NULL); - GST_LOG_OBJECT (payload, "using internal seqnum-base %u", - payload->seqnum_base); - } - - /* make the target caps by copying over all the fixed caps, removing the - * unfixed caps. */ - srccaps = gst_caps_new_simple (gst_structure_get_name (s), NULL); - d = gst_caps_get_structure (srccaps, 0); - - gst_structure_foreach (s, (GstStructureForeachFunc) copy_fixed, d); - - gst_caps_unref (temp); - - GST_DEBUG_OBJECT (payload, "with peer caps: %" GST_PTR_FORMAT, srccaps); - } - - update_max_ptime (payload); - - res = gst_pad_set_caps (GST_BASE_RTP_PAYLOAD_SRCPAD (payload), srccaps); - gst_caps_unref (srccaps); - - return res; -} - -/** - * gst_basertppayload_is_filled: - * @payload: a #GstBaseRTPPayload - * @size: the size of the packet - * @duration: the duration of the packet - * - * Check if the packet with @size and @duration would exceed the configured - * maximum size. - * - * Returns: %TRUE if the packet of @size and @duration would exceed the - * configured MTU or max_ptime. - */ -gboolean -gst_basertppayload_is_filled (GstBaseRTPPayload * payload, - guint size, GstClockTime duration) -{ - if (size > payload->mtu) - return TRUE; - - if (payload->max_ptime != -1 && duration >= payload->max_ptime) - return TRUE; - - return FALSE; -} - -typedef struct -{ - GstBaseRTPPayload *payload; - guint32 ssrc; - guint16 seqnum; - guint8 pt; - GstCaps *caps; - GstClockTime timestamp; - guint64 offset; - guint32 rtptime; -} HeaderData; - -static GstBufferListItem -find_timestamp (GstBuffer ** buffer, guint group, guint idx, HeaderData * data) -{ - data->timestamp = GST_BUFFER_TIMESTAMP (*buffer); - data->offset = GST_BUFFER_OFFSET (*buffer); - - /* stop when we find a timestamp. We take whatever offset is associated with - * the timestamp (if any) to do perfect timestamps when we need to. */ - if (data->timestamp != -1) - return GST_BUFFER_LIST_END; - else - return GST_BUFFER_LIST_CONTINUE; -} - -static GstBufferListItem -set_headers (GstBuffer ** buffer, guint group, guint idx, HeaderData * data) -{ - gst_rtp_buffer_set_ssrc (*buffer, data->ssrc); - gst_rtp_buffer_set_payload_type (*buffer, data->pt); - gst_rtp_buffer_set_seq (*buffer, data->seqnum); - gst_rtp_buffer_set_timestamp (*buffer, data->rtptime); - gst_buffer_set_caps (*buffer, data->caps); - /* increment the seqnum for each buffer */ - data->seqnum++; - - return GST_BUFFER_LIST_SKIP_GROUP; -} - -/* Updates the SSRC, payload type, seqnum and timestamp of the RTP buffer - * before the buffer is pushed. */ -static GstFlowReturn -gst_basertppayload_prepare_push (GstBaseRTPPayload * payload, - gpointer obj, gboolean is_list) -{ - GstBaseRTPPayloadPrivate *priv; - HeaderData data; - - if (payload->clock_rate == 0) - goto no_rate; - - priv = payload->priv; - - /* update first, so that the property is set to the last - * seqnum pushed */ - payload->seqnum = priv->next_seqnum; - - /* fill in the fields we want to set on all headers */ - data.payload = payload; - data.seqnum = payload->seqnum; - data.ssrc = payload->current_ssrc; - data.pt = payload->pt; - data.caps = GST_PAD_CAPS (payload->srcpad); - - /* find the first buffer with a timestamp */ - if (is_list) { - data.timestamp = -1; - data.offset = GST_BUFFER_OFFSET_NONE; - gst_buffer_list_foreach (GST_BUFFER_LIST_CAST (obj), - (GstBufferListFunc) find_timestamp, &data); - } else { - data.timestamp = GST_BUFFER_TIMESTAMP (GST_BUFFER_CAST (obj)); - data.offset = GST_BUFFER_OFFSET (GST_BUFFER_CAST (obj)); - } - - /* convert to RTP time */ - if (priv->perfect_rtptime && data.offset != GST_BUFFER_OFFSET_NONE) { - /* if we have an offset, use that for making an RTP timestamp */ - data.rtptime = payload->ts_base + data.offset; - GST_LOG_OBJECT (payload, - "Using offset %" G_GUINT64_FORMAT " for RTP timestamp", data.offset); - } else if (GST_CLOCK_TIME_IS_VALID (data.timestamp)) { - gint64 rtime; - - /* no offset, use the gstreamer timestamp */ - rtime = gst_segment_to_running_time (&payload->segment, GST_FORMAT_TIME, - data.timestamp); - - GST_LOG_OBJECT (payload, - "Using running_time %" GST_TIME_FORMAT " for RTP timestamp", - GST_TIME_ARGS (rtime)); - - rtime = gst_util_uint64_scale_int (rtime, payload->clock_rate, GST_SECOND); - - /* add running_time in clock-rate units to the base timestamp */ - data.rtptime = payload->ts_base + rtime; - } else { - GST_LOG_OBJECT (payload, - "Using previous RTP timestamp %" G_GUINT32_FORMAT, payload->timestamp); - /* no timestamp to convert, take previous timestamp */ - data.rtptime = payload->timestamp; - } - - /* set ssrc, payload type, seq number, caps and rtptime */ - if (is_list) { - gst_buffer_list_foreach (GST_BUFFER_LIST_CAST (obj), - (GstBufferListFunc) set_headers, &data); - } else { - GstBuffer *buf = GST_BUFFER_CAST (obj); - set_headers (&buf, 0, 0, &data); - } - - priv->next_seqnum = data.seqnum; - payload->timestamp = data.rtptime; - - GST_LOG_OBJECT (payload, - "Preparing to push packet with size %d, seq=%d, rtptime=%u, timestamp %" - GST_TIME_FORMAT, (is_list) ? -1 : - GST_BUFFER_SIZE (GST_BUFFER (obj)), payload->seqnum, data.rtptime, - GST_TIME_ARGS (data.timestamp)); - - return GST_FLOW_OK; - - /* ERRORS */ -no_rate: - { - GST_ELEMENT_ERROR (payload, STREAM, NOT_IMPLEMENTED, (NULL), - ("subclass did not specify clock-rate")); - return GST_FLOW_ERROR; - } -} - -/** - * gst_basertppayload_push_list: - * @payload: a #GstBaseRTPPayload - * @list: a #GstBufferList - * - * Push @list to the peer element of the payloader. The SSRC, payload type, - * seqnum and timestamp of the RTP buffer will be updated first. - * - * This function takes ownership of @list. - * - * Returns: a #GstFlowReturn. - * - * Since: 0.10.24 - */ -GstFlowReturn -gst_basertppayload_push_list (GstBaseRTPPayload * payload, GstBufferList * list) -{ - GstFlowReturn res; - - res = gst_basertppayload_prepare_push (payload, list, TRUE); - - if (G_LIKELY (res == GST_FLOW_OK)) - res = gst_pad_push_list (payload->srcpad, list); - else - gst_buffer_list_unref (list); - - return res; -} - -/** - * gst_basertppayload_push: - * @payload: a #GstBaseRTPPayload - * @buffer: a #GstBuffer - * - * Push @buffer to the peer element of the payloader. The SSRC, payload type, - * seqnum and timestamp of the RTP buffer will be updated first. - * - * This function takes ownership of @buffer. - * - * Returns: a #GstFlowReturn. - */ -GstFlowReturn -gst_basertppayload_push (GstBaseRTPPayload * payload, GstBuffer * buffer) -{ - GstFlowReturn res; - - res = gst_basertppayload_prepare_push (payload, buffer, FALSE); - - if (G_LIKELY (res == GST_FLOW_OK)) - res = gst_pad_push (payload->srcpad, buffer); - else - gst_buffer_unref (buffer); - - return res; -} - -static void -gst_basertppayload_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstBaseRTPPayload *basertppayload; - GstBaseRTPPayloadPrivate *priv; - gint64 val; - - basertppayload = GST_BASE_RTP_PAYLOAD (object); - priv = basertppayload->priv; - - switch (prop_id) { - case PROP_MTU: - basertppayload->mtu = g_value_get_uint (value); - break; - case PROP_PT: - basertppayload->pt = g_value_get_uint (value); - break; - case PROP_SSRC: - val = g_value_get_uint (value); - basertppayload->ssrc = val; - priv->ssrc_random = FALSE; - break; - case PROP_TIMESTAMP_OFFSET: - val = g_value_get_uint (value); - basertppayload->ts_offset = val; - priv->ts_offset_random = FALSE; - break; - case PROP_SEQNUM_OFFSET: - val = g_value_get_int (value); - basertppayload->seqnum_offset = val; - priv->seqnum_offset_random = (val == -1); - GST_DEBUG_OBJECT (basertppayload, "seqnum offset 0x%04x, random %d", - basertppayload->seqnum_offset, priv->seqnum_offset_random); - break; - case PROP_MAX_PTIME: - basertppayload->priv->prop_max_ptime = g_value_get_int64 (value); - update_max_ptime (basertppayload); - break; - case PROP_MIN_PTIME: - basertppayload->min_ptime = g_value_get_int64 (value); - break; - case PROP_PERFECT_RTPTIME: - priv->perfect_rtptime = g_value_get_boolean (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_basertppayload_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstBaseRTPPayload *basertppayload; - GstBaseRTPPayloadPrivate *priv; - - basertppayload = GST_BASE_RTP_PAYLOAD (object); - priv = basertppayload->priv; - - switch (prop_id) { - case PROP_MTU: - g_value_set_uint (value, basertppayload->mtu); - break; - case PROP_PT: - g_value_set_uint (value, basertppayload->pt); - break; - case PROP_SSRC: - if (priv->ssrc_random) - g_value_set_uint (value, -1); - else - g_value_set_uint (value, basertppayload->ssrc); - break; - case PROP_TIMESTAMP_OFFSET: - if (priv->ts_offset_random) - g_value_set_uint (value, -1); - else - g_value_set_uint (value, (guint32) basertppayload->ts_offset); - break; - case PROP_SEQNUM_OFFSET: - if (priv->seqnum_offset_random) - g_value_set_int (value, -1); - else - g_value_set_int (value, (guint16) basertppayload->seqnum_offset); - break; - case PROP_MAX_PTIME: - g_value_set_int64 (value, basertppayload->max_ptime); - break; - case PROP_MIN_PTIME: - g_value_set_int64 (value, basertppayload->min_ptime); - break; - case PROP_TIMESTAMP: - g_value_set_uint (value, basertppayload->timestamp); - break; - case PROP_SEQNUM: - g_value_set_uint (value, basertppayload->seqnum); - break; - case PROP_PERFECT_RTPTIME: - g_value_set_boolean (value, priv->perfect_rtptime); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static GstStateChangeReturn -gst_basertppayload_change_state (GstElement * element, - GstStateChange transition) -{ - GstBaseRTPPayload *basertppayload; - GstBaseRTPPayloadPrivate *priv; - GstStateChangeReturn ret; - - basertppayload = GST_BASE_RTP_PAYLOAD (element); - priv = basertppayload->priv; - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - break; - case GST_STATE_CHANGE_READY_TO_PAUSED: - gst_segment_init (&basertppayload->segment, GST_FORMAT_UNDEFINED); - - if (priv->seqnum_offset_random) - basertppayload->seqnum_base = g_random_int_range (0, G_MAXUINT16); - else - basertppayload->seqnum_base = basertppayload->seqnum_offset; - priv->next_seqnum = basertppayload->seqnum_base; - basertppayload->seqnum = basertppayload->seqnum_base; - - if (priv->ssrc_random) - basertppayload->current_ssrc = g_random_int (); - else - basertppayload->current_ssrc = basertppayload->ssrc; - - if (priv->ts_offset_random) - basertppayload->ts_base = g_random_int (); - else - basertppayload->ts_base = basertppayload->ts_offset; - basertppayload->timestamp = basertppayload->ts_base; - break; - default: - break; - } - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_READY_TO_NULL: - break; - default: - break; - } - return ret; -} |