gstbasertppayload.c 33.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11
/* 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
12
 * Library General Public License for more
13 14
 */

15 16 17 18 19 20 21
/**
 * SECTION:gstbasertppayload
 * @short_description: Base class for RTP payloader
 *
 * Provides a base class for RTP payloaders
 */

22 23 24 25 26 27 28 29 30 31
#ifdef HAVE_CONFIG_H
#  include "config.h"
#endif

#include <string.h>

#include <gst/rtp/gstrtpbuffer.h>

#include "gstbasertppayload.h"

32
GST_DEBUG_CATEGORY_STATIC (basertppayload_debug);
33 34
#define GST_CAT_DEFAULT (basertppayload_debug)

35 36 37 38 39 40 41 42 43
#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;
44
  gboolean perfect_rtptime;
45
  gint notified_first_timestamp;
46 47 48

  gint64 prop_max_ptime;
  gint64 caps_max_ptime;
49 50
};

51 52 53 54 55 56 57
/* BaseRTPPayload signals and args */
enum
{
  /* FILL ME */
  LAST_SIGNAL
};

58
/* FIXME 0.11, a better default is the Ethernet MTU of
59 60 61 62 63
 * 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.
 */
64
#define DEFAULT_MTU                     1400
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
65 66 67 68 69
#define DEFAULT_PT                      96
#define DEFAULT_SSRC                    -1
#define DEFAULT_TIMESTAMP_OFFSET        -1
#define DEFAULT_SEQNUM_OFFSET           -1
#define DEFAULT_MAX_PTIME               -1
70
#define DEFAULT_MIN_PTIME               0
71
#define DEFAULT_PERFECT_RTPTIME         TRUE
72
#define DEFAULT_PTIME_MULTIPLE          0
73 74 75 76 77 78 79

enum
{
  PROP_0,
  PROP_MTU,
  PROP_PT,
  PROP_SSRC,
80
  PROP_TIMESTAMP_OFFSET,
81
  PROP_SEQNUM_OFFSET,
82
  PROP_MAX_PTIME,
83
  PROP_MIN_PTIME,
84
  PROP_TIMESTAMP,
85 86
  PROP_SEQNUM,
  PROP_PERFECT_RTPTIME,
87
  PROP_PTIME_MULTIPLE,
88
  PROP_LAST
89 90 91 92 93 94 95 96
};

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);

97 98
static gboolean gst_basertppayload_sink_setcaps (GstPad * pad, GstCaps * caps);
static GstCaps *gst_basertppayload_sink_getcaps (GstPad * pad);
99
static gboolean gst_basertppayload_event (GstPad * pad, GstEvent * event);
100 101 102 103 104 105 106 107 108 109 110 111 112
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;

113 114
/* FIXME 0.11: API should be changed to gst_base_typ_payload_xyz */

115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
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;

154 155
  g_type_class_add_private (klass, sizeof (GstBaseRTPPayloadPrivate));

156
  parent_class = g_type_class_peek_parent (klass);
157 158 159 160 161 162 163 164 165

  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",
166 167
          28, G_MAXUINT, DEFAULT_MTU,
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
168 169
  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PT,
      g_param_spec_uint ("pt", "payload type",
170 171
          "The payload type of the packets", 0, 0x80, DEFAULT_PT,
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
172
  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SSRC,
173
      g_param_spec_uint ("ssrc", "SSRC",
174 175
          "The SSRC of the packets (default == random)", 0, G_MAXUINT32,
          DEFAULT_SSRC, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
176
  g_object_class_install_property (G_OBJECT_CLASS (klass),
177
      PROP_TIMESTAMP_OFFSET, g_param_spec_uint ("timestamp-offset",
178
          "Timestamp Offset",
179
          "Offset to add to all outgoing timestamps (default = random)", 0,
180 181
          G_MAXUINT32, DEFAULT_TIMESTAMP_OFFSET,
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
182 183
  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SEQNUM_OFFSET,
      g_param_spec_int ("seqnum-offset", "Sequence number Offset",
184
          "Offset to add to all outgoing seqnum (-1 = random)", -1, G_MAXUINT16,
185
          DEFAULT_SEQNUM_OFFSET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
186 187 188
  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)",
189 190
          -1, G_MAXINT64, DEFAULT_MAX_PTIME,
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
191 192 193 194 195 196 197 198 199 200
  /**
   * 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)",
201 202
          0, G_MAXINT64, DEFAULT_MIN_PTIME,
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
203

204 205
  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TIMESTAMP,
      g_param_spec_uint ("timestamp", "Timestamp",
206
          "The RTP timestamp of the last processed packet",
207
          0, G_MAXUINT32, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
208 209
  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SEQNUM,
      g_param_spec_uint ("seqnum", "Sequence number",
210
          "The RTP sequence number of the last processed packet",
211
          0, G_MAXUINT16, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
212

213 214 215 216 217 218 219 220 221 222 223 224 225 226
  /**
   * 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));
227 228 229 230 231 232 233 234 235 236 237 238
  /**
   * GstBaseRTPAudioPayload:ptime-multiple:
   *
   * Force buffers to be multiples of this duration in ns (0 disables)
   *
   * Since: 0.10.29
   **/
  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PTIME_MULTIPLE,
      g_param_spec_int64 ("ptime-multiple", "Packet time multiple",
          "Force buffers to be multiples of this duration in ns (0 disables)",
          0, G_MAXINT64, DEFAULT_PTIME_MULTIPLE,
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
239

240
  gstelement_class->change_state = gst_basertppayload_change_state;
241 242 243

  GST_DEBUG_CATEGORY_INIT (basertppayload_debug, "basertppayload", 0,
      "Base class for RTP Payloaders");
244 245 246 247 248 249
}

static void
gst_basertppayload_init (GstBaseRTPPayload * basertppayload, gpointer g_class)
{
  GstPadTemplate *templ;
250 251 252 253
  GstBaseRTPPayloadPrivate *priv;

  basertppayload->priv = priv =
      GST_BASE_RTP_PAYLOAD_GET_PRIVATE (basertppayload);
254 255 256 257 258 259 260 261 262 263 264 265 266 267

  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,
268
      gst_basertppayload_sink_setcaps);
269
  gst_pad_set_getcaps_function (basertppayload->sinkpad,
270
      gst_basertppayload_sink_getcaps);
271 272
  gst_pad_set_event_function (basertppayload->sinkpad,
      gst_basertppayload_event);
273 274 275 276
  gst_pad_set_chain_function (basertppayload->sinkpad,
      gst_basertppayload_chain);
  gst_element_add_pad (GST_ELEMENT (basertppayload), basertppayload->sinkpad);

277 278 279
  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 ());
280 281 282

  basertppayload->mtu = DEFAULT_MTU;
  basertppayload->pt = DEFAULT_PT;
283
  basertppayload->seqnum_offset = DEFAULT_SEQNUM_OFFSET;
284
  basertppayload->ssrc = DEFAULT_SSRC;
285
  basertppayload->ts_offset = DEFAULT_TIMESTAMP_OFFSET;
286 287 288 289
  priv->seqnum_offset_random = (basertppayload->seqnum_offset == -1);
  priv->ts_offset_random = (basertppayload->ts_offset == -1);
  priv->ssrc_random = (basertppayload->ssrc == -1);

290
  basertppayload->max_ptime = DEFAULT_MAX_PTIME;
291
  basertppayload->min_ptime = DEFAULT_MIN_PTIME;
292
  basertppayload->priv->perfect_rtptime = DEFAULT_PERFECT_RTPTIME;
293
  basertppayload->abidata.ABI.ptime_multiple = DEFAULT_PTIME_MULTIPLE;
294

295 296 297
  basertppayload->media = NULL;
  basertppayload->encoding_name = NULL;

298
  basertppayload->clock_rate = 0;
299 300 301

  basertppayload->priv->caps_max_ptime = DEFAULT_MAX_PTIME;
  basertppayload->priv->prop_max_ptime = DEFAULT_MAX_PTIME;
302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
}

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;

318 319 320 321 322
  g_free (basertppayload->media);
  basertppayload->media = NULL;
  g_free (basertppayload->encoding_name);
  basertppayload->encoding_name = NULL;

323 324 325 326
  G_OBJECT_CLASS (parent_class)->finalize (object);
}

static gboolean
327
gst_basertppayload_sink_setcaps (GstPad * pad, GstCaps * caps)
328 329 330 331 332
{
  GstBaseRTPPayload *basertppayload;
  GstBaseRTPPayloadClass *basertppayload_class;
  gboolean ret = TRUE;

333
  GST_DEBUG_OBJECT (pad, "setting caps %" GST_PTR_FORMAT, caps);
334 335 336 337 338 339 340 341 342 343 344
  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;
}

345
static GstCaps *
346
gst_basertppayload_sink_getcaps (GstPad * pad)
347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373
{
  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;
}

374 375 376 377
static gboolean
gst_basertppayload_event (GstPad * pad, GstEvent * event)
{
  GstBaseRTPPayload *basertppayload;
378
  GstBaseRTPPayloadClass *basertppayload_class;
379 380 381
  gboolean res;

  basertppayload = GST_BASE_RTP_PAYLOAD (gst_pad_get_parent (pad));
382 383
  if (G_UNLIKELY (basertppayload == NULL)) {
    gst_event_unref (event);
384
    return FALSE;
385
  }
386 387 388 389
  basertppayload_class = GST_BASE_RTP_PAYLOAD_GET_CLASS (basertppayload);

  if (basertppayload_class->handle_event) {
    res = basertppayload_class->handle_event (pad, event);
390 391
    if (res)
      goto done;
392
  }
393 394 395 396 397 398 399 400 401 402 403 404

  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;
405
      gdouble rate, arate;
406 407
      GstFormat fmt;
      gint64 start, stop, position;
408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423
      GstSegment *segment;

      segment = &basertppayload->segment;

      gst_event_parse_new_segment_full (event, &update, &rate, &arate, &fmt,
          &start, &stop, &position);
      gst_segment_set_newsegment_full (segment, update, rate, arate, fmt, start,
          stop, position);

      GST_DEBUG_OBJECT (basertppayload,
          "configured NEWSEGMENT update %d, rate %lf, applied rate %lf, "
          "format %d, "
          "%" G_GINT64_FORMAT " -- %" G_GINT64_FORMAT ", time %"
          G_GINT64_FORMAT ", accum %" G_GINT64_FORMAT, update, rate, arate,
          segment->format, segment->start, segment->stop, segment->time,
          segment->accum);
424
      /* fallthrough */
425
    }
426 427 428 429 430
    default:
      res = gst_pad_event_default (pad, event);
      break;
  }

431
done:
432 433 434 435 436 437
  gst_object_unref (basertppayload);

  return res;
}


438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459
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:
  {
460 461
    GST_ELEMENT_ERROR (basertppayload, STREAM, NOT_IMPLEMENTED, (NULL),
        ("subclass did not implement handle_buffer function"));
462
    gst_object_unref (basertppayload);
463
    gst_buffer_unref (buffer);
464 465 466 467
    return GST_FLOW_ERROR;
  }
}

468 469 470 471 472
/**
 * gst_basertppayload_set_options:
 * @payload: a #GstBaseRTPPayload
 * @media: the media type (typically "audio" or "video")
 * @dynamic: if the payload type is dynamic
473
 * @encoding_name: the encoding name
474 475 476 477 478 479
 * @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().
 */
480 481
void
gst_basertppayload_set_options (GstBaseRTPPayload * payload,
482 483
    const gchar * media, gboolean dynamic, const gchar * encoding_name,
    guint32 clock_rate)
484 485 486 487 488 489 490 491 492 493 494 495
{
  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;
}

496
static gboolean
497 498 499 500 501 502 503 504
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;
}

505 506 507 508 509 510 511 512 513 514 515 516 517 518 519
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;
}

520 521 522 523 524 525 526 527 528 529 530 531 532
/**
 * 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.
 */
533
gboolean
534 535
gst_basertppayload_set_outcaps (GstBaseRTPPayload * payload,
    const gchar * fieldname, ...)
536
{
537
  GstCaps *srccaps, *peercaps;
538
  gboolean res;
539

Wim Taymans's avatar
Wim Taymans committed
540
  /* fill in the defaults, their properties cannot be negotiated. */
541 542
  srccaps = gst_caps_new_simple ("application/x-rtp",
      "media", G_TYPE_STRING, payload->media,
543
      "clock-rate", G_TYPE_INT, payload->clock_rate,
544
      "encoding-name", G_TYPE_STRING, payload->encoding_name, NULL);
545

546 547
  GST_DEBUG_OBJECT (payload, "defaults: %" GST_PTR_FORMAT, srccaps);

548 549 550
  if (fieldname) {
    va_list varargs;

551
    /* override with custom properties */
552
    va_start (varargs, fieldname);
553
    gst_caps_set_simple_valist (srccaps, fieldname, varargs);
554
    va_end (varargs);
555 556

    GST_DEBUG_OBJECT (payload, "custom added: %" GST_PTR_FORMAT, srccaps);
557 558
  }

559
  payload->priv->caps_max_ptime = DEFAULT_MAX_PTIME;
560
  payload->abidata.ABI.ptime = 0;
561

562 563 564 565 566 567 568 569 570
  /* 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);
571 572

    GST_DEBUG_OBJECT (payload, "no peer caps: %" GST_PTR_FORMAT, srccaps);
573 574
  } else {
    GstCaps *temp;
575
    GstStructure *s, *d;
576 577
    const GValue *value;
    gint pt;
578
    guint max_ptime, ptime;
579 580 581 582 583 584 585

    /* 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);

586 587 588 589 590
    if (gst_caps_is_empty (temp)) {
      gst_caps_unref (temp);
      return FALSE;
    }

591 592 593 594
    /* now fixate, start by taking the first caps */
    gst_caps_truncate (temp);

    /* get first structure */
595
    s = gst_caps_get_structure (temp, 0);
596

597
    if (gst_structure_get_uint (s, "maxptime", &max_ptime))
598 599
      payload->priv->caps_max_ptime = max_ptime * GST_MSECOND;

600
    if (gst_structure_get_uint (s, "ptime", &ptime))
601
      payload->abidata.ABI.ptime = ptime * GST_MSECOND;
602

603 604
    if (gst_structure_get_int (s, "payload", &pt)) {
      /* use peer pt */
605
      GST_BASE_RTP_PAYLOAD_PT (payload) = pt;
606 607
      GST_LOG_OBJECT (payload, "using peer pt %d", pt);
    } else {
608 609 610 611
      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));
612 613
        gst_structure_get_int (s, "payload", &pt);
        GST_LOG_OBJECT (payload, "using peer pt %d", pt);
614
      } else {
615 616 617
        /* no pt field, use the internal pt */
        pt = GST_BASE_RTP_PAYLOAD_PT (payload);
        gst_structure_set (s, "payload", G_TYPE_INT, pt, NULL);
618
        GST_LOG_OBJECT (payload, "using internal pt %d", pt);
619 620 621 622 623 624
      }
    }

    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);
625
      GST_LOG_OBJECT (payload, "using peer ssrc %08x", payload->current_ssrc);
626 627 628
    } else {
      /* FIXME, fixate_nearest_uint would be even better */
      gst_structure_set (s, "ssrc", G_TYPE_UINT, payload->current_ssrc, NULL);
629 630
      GST_LOG_OBJECT (payload, "using internal ssrc %08x",
          payload->current_ssrc);
631 632 633 634 635
    }

    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);
636
      GST_LOG_OBJECT (payload, "using peer clock-base %u", payload->ts_base);
637 638 639
    } else {
      /* FIXME, fixate_nearest_uint would be even better */
      gst_structure_set (s, "clock-base", G_TYPE_UINT, payload->ts_base, NULL);
640 641
      GST_LOG_OBJECT (payload, "using internal clock-base %u",
          payload->ts_base);
642 643 644 645
    }
    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);
646 647
      GST_LOG_OBJECT (payload, "using peer seqnum-base %u",
          payload->seqnum_base);
648 649 650 651
    } else {
      /* FIXME, fixate_nearest_uint would be even better */
      gst_structure_set (s, "seqnum-base", G_TYPE_UINT, payload->seqnum_base,
          NULL);
652 653
      GST_LOG_OBJECT (payload, "using internal seqnum-base %u",
          payload->seqnum_base);
654
    }
655 656 657 658 659 660 661 662

    /* 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);

663 664
    gst_caps_unref (temp);

665
    GST_DEBUG_OBJECT (payload, "with peer caps: %" GST_PTR_FORMAT, srccaps);
666 667
  }

668 669
  update_max_ptime (payload);

670
  res = gst_pad_set_caps (GST_BASE_RTP_PAYLOAD_SRCPAD (payload), srccaps);
671 672
  gst_caps_unref (srccaps);

673
  return res;
674 675
}

676 677 678 679 680 681
/**
 * gst_basertppayload_is_filled:
 * @payload: a #GstBaseRTPPayload
 * @size: the size of the packet
 * @duration: the duration of the packet
 *
Wim Taymans's avatar
Wim Taymans committed
682
 * Check if the packet with @size and @duration would exceed the configured
683 684 685 686 687
 * maximum size.
 *
 * Returns: %TRUE if the packet of @size and @duration would exceed the
 * configured MTU or max_ptime.
 */
688 689 690 691 692 693 694 695 696 697 698 699 700
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;
}

701
typedef struct
702
{
703 704 705 706 707
  GstBaseRTPPayload *payload;
  guint32 ssrc;
  guint16 seqnum;
  guint8 pt;
  GstCaps *caps;
708
  GstClockTime timestamp;
709
  guint64 offset;
710
  guint32 rtptime;
711 712 713 714 715 716
} HeaderData;

static GstBufferListItem
find_timestamp (GstBuffer ** buffer, guint group, guint idx, HeaderData * data)
{
  data->timestamp = GST_BUFFER_TIMESTAMP (*buffer);
717
  data->offset = GST_BUFFER_OFFSET (*buffer);
718

719 720
  /* 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. */
721
  if (data->timestamp != -1)
722 723 724 725 726 727 728 729 730 731 732 733 734
    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);
735
  /* increment the seqnum for each buffer */
736 737 738 739 740 741 742 743 744 745 746
  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)
{
747
  GstBaseRTPPayloadPrivate *priv;
748
  HeaderData data;
749 750 751 752

  if (payload->clock_rate == 0)
    goto no_rate;

753 754
  priv = payload->priv;

755 756
  /* update first, so that the property is set to the last
   * seqnum pushed */
757
  payload->seqnum = priv->next_seqnum;
758

759 760 761 762 763 764 765 766 767
  /* 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) {
768 769
    data.timestamp = -1;
    data.offset = GST_BUFFER_OFFSET_NONE;
770 771 772 773
    gst_buffer_list_foreach (GST_BUFFER_LIST_CAST (obj),
        (GstBufferListFunc) find_timestamp, &data);
  } else {
    data.timestamp = GST_BUFFER_TIMESTAMP (GST_BUFFER_CAST (obj));
774
    data.offset = GST_BUFFER_OFFSET (GST_BUFFER_CAST (obj));
775
  }
776

777
  /* convert to RTP time */
778
  if (priv->perfect_rtptime && data.offset != GST_BUFFER_OFFSET_NONE) {
779 780
    /* if we have an offset, use that for making an RTP timestamp */
    data.rtptime = payload->ts_base + data.offset;
Wim Taymans's avatar
Wim Taymans committed
781 782
    GST_LOG_OBJECT (payload,
        "Using offset %" G_GUINT64_FORMAT " for RTP timestamp", data.offset);
783
  } else if (GST_CLOCK_TIME_IS_VALID (data.timestamp)) {
784 785
    gint64 rtime;

786
    /* no offset, use the gstreamer timestamp */
787
    rtime = gst_segment_to_running_time (&payload->segment, GST_FORMAT_TIME,
788
        data.timestamp);
789

790 791 792 793 794 795 796 797 798 799
    if (rtime == -1) {
      GST_LOG_OBJECT (payload, "Clipped timestamp, using base RTP timestamp");
      rtime = 0;
    } else {
      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);
    }
800
    /* add running_time in clock-rate units to the base timestamp */
801
    data.rtptime = payload->ts_base + rtime;
802
  } else {
Wim Taymans's avatar
Wim Taymans committed
803
    GST_LOG_OBJECT (payload,
804
        "Using previous RTP timestamp %" G_GUINT32_FORMAT, payload->timestamp);
805
    /* no timestamp to convert, take previous timestamp */
806
    data.rtptime = payload->timestamp;
807
  }
808

809 810 811 812 813 814 815 816
  /* 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);
  }
817

818 819
  priv->next_seqnum = data.seqnum;
  payload->timestamp = data.rtptime;
820

821
  GST_LOG_OBJECT (payload,
822 823 824 825
      "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));
826

827 828
  if (g_atomic_int_compare_and_exchange (&payload->
          priv->notified_first_timestamp, 1, 0)) {
829 830 831 832
    g_object_notify (G_OBJECT (payload), "timestamp");
    g_object_notify (G_OBJECT (payload), "seqnum");
  }

833
  return GST_FLOW_OK;
834 835 836 837

  /* ERRORS */
no_rate:
  {
838
    GST_ELEMENT_ERROR (payload, STREAM, NOT_IMPLEMENTED, (NULL),
839
        ("subclass did not specify clock-rate"));
840 841 842 843
    return GST_FLOW_ERROR;
  }
}

844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879
/**
 * 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.
880
 *
881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899
 * 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;
}

900 901 902 903 904
static void
gst_basertppayload_set_property (GObject * object, guint prop_id,
    const GValue * value, GParamSpec * pspec)
{
  GstBaseRTPPayload *basertppayload;
905 906
  GstBaseRTPPayloadPrivate *priv;
  gint64 val;
907 908

  basertppayload = GST_BASE_RTP_PAYLOAD (object);
909
  priv = basertppayload->priv;
910 911 912 913 914 915 916 917 918

  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:
919
      val = g_value_get_uint (value);
920
      basertppayload->ssrc = val;
921
      priv->ssrc_random = FALSE;
922
      break;
923
    case PROP_TIMESTAMP_OFFSET:
924
      val = g_value_get_uint (value);
925
      basertppayload->ts_offset = val;
926
      priv->ts_offset_random = FALSE;
927
      break;
928
    case PROP_SEQNUM_OFFSET:
929 930 931 932 933
      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);
934
      break;
935
    case PROP_MAX_PTIME:
936 937
      basertppayload->priv->prop_max_ptime = g_value_get_int64 (value);
      update_max_ptime (basertppayload);
938
      break;
939 940 941
    case PROP_MIN_PTIME:
      basertppayload->min_ptime = g_value_get_int64 (value);
      break;
942 943 944
    case PROP_PERFECT_RTPTIME:
      priv->perfect_rtptime = g_value_get_boolean (value);
      break;
945 946 947
    case PROP_PTIME_MULTIPLE:
      basertppayload->abidata.ABI.ptime_multiple = g_value_get_int64 (value);
      break;
948 949 950 951 952 953 954 955 956 957 958
    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;
959
  GstBaseRTPPayloadPrivate *priv;
960 961

  basertppayload = GST_BASE_RTP_PAYLOAD (object);
962
  priv = basertppayload->priv;
963 964 965 966 967 968 969 970 971

  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:
972
      if (priv->ssrc_random)
973
        g_value_set_uint (value, -1);
974
      else
975
        g_value_set_uint (value, basertppayload->ssrc);
976
      break;
977
    case PROP_TIMESTAMP_OFFSET:
978
      if (priv->ts_offset_random)
979
        g_value_set_uint (value, -1);
980
      else
981
        g_value_set_uint (value, (guint32) basertppayload->ts_offset);
982
      break;
983
    case PROP_SEQNUM_OFFSET:
984 985 986 987
      if (priv->seqnum_offset_random)
        g_value_set_int (value, -1);
      else
        g_value_set_int (value, (guint16) basertppayload->seqnum_offset);
988
      break;
989 990 991
    case PROP_MAX_PTIME:
      g_value_set_int64 (value, basertppayload->max_ptime);
      break;
992 993 994
    case PROP_MIN_PTIME:
      g_value_set_int64 (value, basertppayload->min_ptime);
      break;
995 996 997 998 999 1000
    case PROP_TIMESTAMP:
      g_value_set_uint (value, basertppayload->timestamp);
      break;
    case PROP_SEQNUM:
      g_value_set_uint (value, basertppayload->seqnum);
      break;
1001 1002 1003
    case PROP_PERFECT_RTPTIME:
      g_value_set_boolean (value, priv->perfect_rtptime);
      break;
1004 1005 1006
    case PROP_PTIME_MULTIPLE:
      g_value_set_int64 (value, basertppayload->abidata.ABI.ptime_multiple);
      break;
1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}

static GstStateChangeReturn
gst_basertppayload_change_state (GstElement * element,
    GstStateChange transition)
{
  GstBaseRTPPayload *basertppayload;
1018
  GstBaseRTPPayloadPrivate *priv;
1019 1020 1021
  GstStateChangeReturn ret;

  basertppayload = GST_BASE_RTP_PAYLOAD (element);
1022
  priv = basertppayload->priv;
1023 1024 1025 1026 1027

  switch (transition) {
    case GST_STATE_CHANGE_NULL_TO_READY:
      break;
    case GST_STATE_CHANGE_READY_TO_PAUSED:
1028
      gst_segment_init (&basertppayload->segment, GST_FORMAT_UNDEFINED);
1029

1030
      if (priv->seqnum_offset_random)
1031
        basertppayload->seqnum_base = g_random_int_range (0, G_MAXUINT16);
1032 1033
      else
        basertppayload->seqnum_base = basertppayload->seqnum_offset;
1034
      priv->next_seqnum = basertppayload->seqnum_base;