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