gstrtpmp4vpay.c 19 KB
Newer Older
1
/* GStreamer
2
 * Copyright (C) <2005> Wim Taymans <wim.taymans@gmail.com>
3 4 5 6 7 8 9 10 11
 *
 * 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 13 14 15 16 17
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
18 19 20 21 22 23 24 25 26 27
 */

#ifdef HAVE_CONFIG_H
#  include "config.h"
#endif

#include <string.h>

#include <gst/rtp/gstrtpbuffer.h>

28
#include "gstrtpmp4vpay.h"
29

30
GST_DEBUG_CATEGORY_STATIC (rtpmp4vpay_debug);
31 32
#define GST_CAT_DEFAULT (rtpmp4vpay_debug)

33
static GstStaticPadTemplate gst_rtp_mp4v_pay_sink_template =
34
    GST_STATIC_PAD_TEMPLATE ("sink",
35 36 37
    GST_PAD_SINK,
    GST_PAD_ALWAYS,
    GST_STATIC_CAPS ("video/mpeg,"
38
        "mpegversion=(int) 4," "systemstream=(boolean)false;" "video/x-xvid")
39 40
    );

41
static GstStaticPadTemplate gst_rtp_mp4v_pay_src_template =
42 43 44
GST_STATIC_PAD_TEMPLATE ("src",
    GST_PAD_SRC,
    GST_PAD_ALWAYS,
45 46
    GST_STATIC_CAPS ("application/x-rtp, "
        "media = (string) \"video\", "
47
        "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
48 49
        "clock-rate = (int) [1, MAX ], " "encoding-name = (string) \"MP4V-ES\""
        /* two string params
50
         *
51 52
         "profile-level-id = (string) [1,MAX]"
         "config = (string) [1,MAX]"
53
         */
54 55 56
    )
    );

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
57
#define DEFAULT_SEND_CONFIG     FALSE
58
#define DEFAULT_BUFFER_LIST     FALSE
59
#define DEFAULT_CONFIG_INTERVAL 0
Wim Taymans's avatar
Wim Taymans committed
60 61 62 63

enum
{
  ARG_0,
64
  ARG_SEND_CONFIG,
65 66
  ARG_BUFFER_LIST,
  ARG_CONFIG_INTERVAL
Wim Taymans's avatar
Wim Taymans committed
67 68
};

69

70
static void gst_rtp_mp4v_pay_finalize (GObject * object);
71

72
static void gst_rtp_mp4v_pay_set_property (GObject * object, guint prop_id,
Wim Taymans's avatar
Wim Taymans committed
73
    const GValue * value, GParamSpec * pspec);
74
static void gst_rtp_mp4v_pay_get_property (GObject * object, guint prop_id,
Wim Taymans's avatar
Wim Taymans committed
75 76
    GValue * value, GParamSpec * pspec);

77
static gboolean gst_rtp_mp4v_pay_setcaps (GstBaseRTPPayload * payload,
78
    GstCaps * caps);
79 80
static GstFlowReturn gst_rtp_mp4v_pay_handle_buffer (GstBaseRTPPayload *
    payload, GstBuffer * buffer);
81
static gboolean gst_rtp_mp4v_pay_handle_event (GstPad * pad, GstEvent * event);
82

Wim Taymans's avatar
Wim Taymans committed
83 84
GST_BOILERPLATE (GstRtpMP4VPay, gst_rtp_mp4v_pay, GstBaseRTPPayload,
    GST_TYPE_BASE_RTP_PAYLOAD)
85

Wim Taymans's avatar
Wim Taymans committed
86
     static void gst_rtp_mp4v_pay_base_init (gpointer klass)
87 88 89 90
{
  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);

  gst_element_class_add_pad_template (element_class,
91
      gst_static_pad_template_get (&gst_rtp_mp4v_pay_src_template));
92
  gst_element_class_add_pad_template (element_class,
93
      gst_static_pad_template_get (&gst_rtp_mp4v_pay_sink_template));
94

95
  gst_element_class_set_details_simple (element_class,
Wim Taymans's avatar
Wim Taymans committed
96
      "RTP MPEG4 Video payloader", "Codec/Payloader/Network/RTP",
97 98
      "Payload MPEG-4 video as RTP packets (RFC 3016)",
      "Wim Taymans <wim.taymans@gmail.com>");
99 100 101
}

static void
102
gst_rtp_mp4v_pay_class_init (GstRtpMP4VPayClass * klass)
103 104
{
  GObjectClass *gobject_class;
105
  GstBaseRTPPayloadClass *gstbasertppayload_class;
106 107

  gobject_class = (GObjectClass *) klass;
108
  gstbasertppayload_class = (GstBaseRTPPayloadClass *) klass;
109

110 111
  gobject_class->set_property = gst_rtp_mp4v_pay_set_property;
  gobject_class->get_property = gst_rtp_mp4v_pay_get_property;
Wim Taymans's avatar
Wim Taymans committed
112 113 114 115

  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SEND_CONFIG,
      g_param_spec_boolean ("send-config", "Send Config",
          "Send the config parameters in RTP packets as well",
116
          DEFAULT_SEND_CONFIG, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Wim Taymans's avatar
Wim Taymans committed
117

118 119 120 121 122
  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BUFFER_LIST,
      g_param_spec_boolean ("buffer-list", "Buffer Array",
          "Use Buffer Arrays",
          DEFAULT_BUFFER_LIST, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));

123 124 125 126 127 128 129 130
  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_CONFIG_INTERVAL,
      g_param_spec_uint ("config-interval", "Config Send Interval",
          "Send Config Insertion Interval in seconds (configuration headers "
          "will be multiplexed in the data stream when detected.) (0 = disabled)",
          0, 3600, DEFAULT_CONFIG_INTERVAL,
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
      );

131
  gobject_class->finalize = gst_rtp_mp4v_pay_finalize;
132

133 134
  gstbasertppayload_class->set_caps = gst_rtp_mp4v_pay_setcaps;
  gstbasertppayload_class->handle_buffer = gst_rtp_mp4v_pay_handle_buffer;
135
  gstbasertppayload_class->handle_event = gst_rtp_mp4v_pay_handle_event;
136 137 138

  GST_DEBUG_CATEGORY_INIT (rtpmp4vpay_debug, "rtpmp4vpay", 0,
      "MP4 video RTP Payloader");
139 140 141
}

static void
Wim Taymans's avatar
Wim Taymans committed
142
gst_rtp_mp4v_pay_init (GstRtpMP4VPay * rtpmp4vpay, GstRtpMP4VPayClass * klass)
143
{
144 145 146
  rtpmp4vpay->adapter = gst_adapter_new ();
  rtpmp4vpay->rate = 90000;
  rtpmp4vpay->profile = 1;
147
  rtpmp4vpay->buffer_list = DEFAULT_BUFFER_LIST;
148
  rtpmp4vpay->send_config = DEFAULT_SEND_CONFIG;
149
  rtpmp4vpay->need_config = TRUE;
150 151
  rtpmp4vpay->config_interval = DEFAULT_CONFIG_INTERVAL;
  rtpmp4vpay->last_config = -1;
152

153
  rtpmp4vpay->config = NULL;
154 155
}

156
static void
157
gst_rtp_mp4v_pay_finalize (GObject * object)
158
{
159
  GstRtpMP4VPay *rtpmp4vpay;
160

161
  rtpmp4vpay = GST_RTP_MP4V_PAY (object);
162

163
  if (rtpmp4vpay->config) {
164
    gst_buffer_unref (rtpmp4vpay->config);
165 166
    rtpmp4vpay->config = NULL;
  }
167 168
  g_object_unref (rtpmp4vpay->adapter);
  rtpmp4vpay->adapter = NULL;
169

170 171 172
  G_OBJECT_CLASS (parent_class)->finalize (object);
}

173
static gboolean
174
gst_rtp_mp4v_pay_new_caps (GstRtpMP4VPay * rtpmp4vpay)
175
{
176 177
  gchar *profile, *config;
  GValue v = { 0 };
178
  gboolean res;
179

180
  profile = g_strdup_printf ("%d", rtpmp4vpay->profile);
181
  g_value_init (&v, GST_TYPE_BUFFER);
182
  gst_value_set_buffer (&v, rtpmp4vpay->config);
183 184
  config = gst_value_serialize (&v);

185
  res = gst_basertppayload_set_outcaps (GST_BASE_RTP_PAYLOAD (rtpmp4vpay),
186 187 188 189 190 191 192
      "profile-level-id", G_TYPE_STRING, profile,
      "config", G_TYPE_STRING, config, NULL);

  g_value_unset (&v);

  g_free (profile);
  g_free (config);
193 194

  return res;
195 196 197
}

static gboolean
198
gst_rtp_mp4v_pay_setcaps (GstBaseRTPPayload * payload, GstCaps * caps)
199
{
200
  GstRtpMP4VPay *rtpmp4vpay;
201
  GstStructure *structure;
202
  const GValue *codec_data;
203
  gboolean res;
204

205
  rtpmp4vpay = GST_RTP_MP4V_PAY (payload);
206

207 208 209
  gst_basertppayload_set_options (payload, "video", TRUE, "MP4V-ES",
      rtpmp4vpay->rate);

210 211
  res = TRUE;

212
  structure = gst_caps_get_structure (caps, 0);
213 214 215 216
  codec_data = gst_structure_get_value (structure, "codec_data");
  if (codec_data) {
    GST_LOG_OBJECT (rtpmp4vpay, "got codec_data");
    if (G_VALUE_TYPE (codec_data) == GST_TYPE_BUFFER) {
217 218 219 220
      GstBuffer *buffer;
      guint8 *data;
      guint size;

221
      buffer = gst_value_get_buffer (codec_data);
222 223 224 225 226 227 228 229

      data = GST_BUFFER_DATA (buffer);
      size = GST_BUFFER_SIZE (buffer);

      if (size < 5)
        goto done;

      rtpmp4vpay->profile = data[4];
230
      GST_LOG_OBJECT (rtpmp4vpay, "configuring codec_data, profile %d",
231 232 233 234 235
          data[4]);

      if (rtpmp4vpay->config)
        gst_buffer_unref (rtpmp4vpay->config);
      rtpmp4vpay->config = gst_buffer_copy (buffer);
236
      res = gst_rtp_mp4v_pay_new_caps (rtpmp4vpay);
237 238 239 240
    }
  }

done:
241
  return res;
242 243
}

244 245 246 247 248 249
static void
gst_rtp_mp4v_pay_empty (GstRtpMP4VPay * rtpmp4vpay)
{
  gst_adapter_clear (rtpmp4vpay->adapter);
}

250
static GstFlowReturn
251
gst_rtp_mp4v_pay_flush (GstRtpMP4VPay * rtpmp4vpay)
252 253 254
{
  guint avail;
  GstBuffer *outbuf;
255
  GstBuffer *outbuf_data = NULL;
256
  GstFlowReturn ret;
257 258
  GstBufferList *list = NULL;
  GstBufferListIterator *it = NULL;
259 260 261 262 263 264

  /* the data available in the adapter is either smaller
   * than the MTU or bigger. In the case it is smaller, the complete
   * adapter contents can be put in one packet. In the case the
   * adapter has more than one MTU, we need to split the MP4V data
   * over multiple packets. */
265
  avail = gst_adapter_available (rtpmp4vpay->adapter);
266

267
  if (rtpmp4vpay->config == NULL && rtpmp4vpay->need_config) {
268 269 270 271 272
    /* when we don't have a config yet, flush things out */
    gst_adapter_flush (rtpmp4vpay->adapter, avail);
    avail = 0;
  }

273 274 275
  if (!avail)
    return GST_FLOW_OK;

276 277
  ret = GST_FLOW_OK;

278 279 280 281 282 283 284 285
  if (rtpmp4vpay->buffer_list) {
    /* Use buffer lists. Each frame will be put into a list
     * of buffers and the whole list will be pushed downstream
     * at once */
    list = gst_buffer_list_new ();
    it = gst_buffer_list_iterate (list);
  }

286 287 288 289 290 291 292
  while (avail > 0) {
    guint towrite;
    guint8 *payload;
    guint payload_len;
    guint packet_len;

    /* this will be the total lenght of the packet */
293
    packet_len = gst_rtp_buffer_calc_packet_len (avail, 0, 0);
294 295

    /* fill one MTU or all available bytes */
296
    towrite = MIN (packet_len, GST_BASE_RTP_PAYLOAD_MTU (rtpmp4vpay));
297 298

    /* this is the payload length */
299
    payload_len = gst_rtp_buffer_calc_payload_len (towrite, 0, 0);
300

301 302 303 304 305 306 307 308 309 310 311
    if (rtpmp4vpay->buffer_list) {
      /* create buffer without payload. The payload will be put
       * in next buffer instead. Both buffers will be then added
       * to the list */
      outbuf = gst_rtp_buffer_new_allocate (0, 0, 0);

      /* Take buffer with the payload from the adapter */
      outbuf_data = gst_adapter_take_buffer (rtpmp4vpay->adapter, payload_len);
    } else {
      /* create buffer to hold the payload */
      outbuf = gst_rtp_buffer_new_allocate (payload_len, 0, 0);
312

313 314
      /* copy payload */
      payload = gst_rtp_buffer_get_payload (outbuf);
315

316 317 318
      gst_adapter_copy (rtpmp4vpay->adapter, payload, 0, payload_len);
      gst_adapter_flush (rtpmp4vpay->adapter, payload_len);
    }
319 320 321

    avail -= payload_len;

322
    gst_rtp_buffer_set_marker (outbuf, avail == 0);
323

324
    GST_BUFFER_TIMESTAMP (outbuf) = rtpmp4vpay->first_timestamp;
325

326 327 328 329 330 331 332 333 334 335 336 337 338 339 340
    if (rtpmp4vpay->buffer_list) {
      /* create a new group to hold the rtp header and the payload */
      gst_buffer_list_iterator_add_group (it);
      gst_buffer_list_iterator_add (it, outbuf);
      gst_buffer_list_iterator_add (it, outbuf_data);
    } else {
      ret = gst_basertppayload_push (GST_BASE_RTP_PAYLOAD (rtpmp4vpay), outbuf);
    }
  }

  if (rtpmp4vpay->buffer_list) {
    gst_buffer_list_iterator_free (it);
    /* push the whole buffer list at once */
    ret =
        gst_basertppayload_push_list (GST_BASE_RTP_PAYLOAD (rtpmp4vpay), list);
341 342 343 344 345
  }

  return ret;
}

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
346 347 348 349 350 351
#define VOS_STARTCODE                   0x000001B0
#define VOS_ENDCODE                     0x000001B1
#define USER_DATA_STARTCODE             0x000001B2
#define GOP_STARTCODE                   0x000001B3
#define VISUAL_OBJECT_STARTCODE         0x000001B5
#define VOP_STARTCODE                   0x000001B6
352 353

static gboolean
354
gst_rtp_mp4v_pay_depay_data (GstRtpMP4VPay * enc, guint8 * data, guint size,
355
    gint * strip, gboolean * vopi)
356 357 358
{
  guint32 code;
  gboolean result;
359
  *vopi = FALSE;
360

Wim Taymans's avatar
Wim Taymans committed
361 362
  *strip = 0;

363 364 365 366
  if (size < 5)
    return FALSE;

  code = GST_READ_UINT32_BE (data);
367
  GST_DEBUG_OBJECT (enc, "start code 0x%08x", code);
368 369 370

  switch (code) {
    case VOS_STARTCODE:
371
    case 0x00000101:
372 373 374 375 376 377
    {
      gint i;
      guint8 profile;
      gboolean newprofile = FALSE;
      gboolean equal;

378 379 380
      if (code == VOS_STARTCODE) {
        /* profile_and_level_indication */
        profile = data[4];
381

382
        GST_DEBUG_OBJECT (enc, "VOS profile 0x%08x", profile);
383

384 385 386 387
        if (profile != enc->profile) {
          newprofile = TRUE;
          enc->profile = profile;
        }
388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411
      }

      /* up to the next GOP_STARTCODE or VOP_STARTCODE is
       * the config information */
      code = 0xffffffff;
      for (i = 5; i < size - 4; i++) {
        code = (code << 8) | data[i];
        if (code == GOP_STARTCODE || code == VOP_STARTCODE)
          break;
      }
      i -= 3;
      /* see if config changed */
      equal = FALSE;
      if (enc->config) {
        if (GST_BUFFER_SIZE (enc->config) == i) {
          equal = memcmp (GST_BUFFER_DATA (enc->config), data, i) == 0;
        }
      }
      /* if config string changed or new profile, make new caps */
      if (!equal || newprofile) {
        if (enc->config)
          gst_buffer_unref (enc->config);
        enc->config = gst_buffer_new_and_alloc (i);
        memcpy (GST_BUFFER_DATA (enc->config), data, i);
412
        gst_rtp_mp4v_pay_new_caps (enc);
413
      }
Wim Taymans's avatar
Wim Taymans committed
414 415
      *strip = i;
      /* we need to flush out the current packet. */
416 417 418 419
      result = TRUE;
      break;
    }
    case VOP_STARTCODE:
420
      GST_DEBUG_OBJECT (enc, "VOP");
Wim Taymans's avatar
Wim Taymans committed
421
      /* VOP startcode, we don't have to flush the packet */
422
      result = FALSE;
423 424 425 426 427 428 429 430 431 432
      /* vop-coding-type == I-frame */
      if (size > 4 && (data[4] >> 6 == 0)) {
        GST_DEBUG_OBJECT (enc, "VOP-I");
        *vopi = TRUE;
      }
      break;
    case GOP_STARTCODE:
      GST_DEBUG_OBJECT (enc, "GOP");
      *vopi = TRUE;
      result = TRUE;
433
      break;
434 435 436 437
    case 0x00000100:
      enc->need_config = FALSE;
      result = TRUE;
      break;
438
    default:
439 440 441 442 443 444 445 446
      if (code >= 0x20 && code <= 0x2f) {
        GST_DEBUG_OBJECT (enc, "short header");
        result = FALSE;
      } else {
        GST_DEBUG_OBJECT (enc, "other startcode");
        /* all other startcodes need a flush */
        result = TRUE;
      }
447 448 449 450 451
      break;
  }
  return result;
}

452 453 454
/* we expect buffers starting on startcodes. 
 */
static GstFlowReturn
455
gst_rtp_mp4v_pay_handle_buffer (GstBaseRTPPayload * basepayload,
456
    GstBuffer * buffer)
457
{
458
  GstRtpMP4VPay *rtpmp4vpay;
459 460 461
  GstFlowReturn ret;
  guint size, avail;
  guint packet_len;
462 463
  guint8 *data;
  gboolean flush;
Wim Taymans's avatar
Wim Taymans committed
464
  gint strip;
465
  GstClockTime timestamp, duration;
466 467
  gboolean vopi;
  gboolean send_config;
Wim Taymans's avatar
Wim Taymans committed
468 469

  ret = GST_FLOW_OK;
470
  send_config = FALSE;
471

472
  rtpmp4vpay = GST_RTP_MP4V_PAY (basepayload);
473 474

  size = GST_BUFFER_SIZE (buffer);
475
  data = GST_BUFFER_DATA (buffer);
476
  timestamp = GST_BUFFER_TIMESTAMP (buffer);
477
  duration = GST_BUFFER_DURATION (buffer);
478
  avail = gst_adapter_available (rtpmp4vpay->adapter);
479

480 481 482
  if (duration == -1)
    duration = 0;

Wim Taymans's avatar
Wim Taymans committed
483 484
  /* empty buffer, take timestamp */
  if (avail == 0) {
485
    rtpmp4vpay->first_timestamp = timestamp;
486
    rtpmp4vpay->duration = 0;
Wim Taymans's avatar
Wim Taymans committed
487 488
  }

489
  /* depay incomming data and see if we need to start a new RTP
490
   * packet */
491
  flush = gst_rtp_mp4v_pay_depay_data (rtpmp4vpay, data, size, &strip, &vopi);
Wim Taymans's avatar
Wim Taymans committed
492 493
  if (strip) {
    /* strip off config if requested */
494
    if (!rtpmp4vpay->send_config) {
Wim Taymans's avatar
Wim Taymans committed
495 496
      GstBuffer *subbuf;

497 498 499
      GST_LOG_OBJECT (rtpmp4vpay, "stripping config at %d, size %d", strip,
          size - strip);

Wim Taymans's avatar
Wim Taymans committed
500 501
      /* strip off header */
      subbuf = gst_buffer_create_sub (buffer, strip, size - strip);
502
      GST_BUFFER_TIMESTAMP (subbuf) = timestamp;
Wim Taymans's avatar
Wim Taymans committed
503 504 505 506
      gst_buffer_unref (buffer);
      buffer = subbuf;

      size = GST_BUFFER_SIZE (buffer);
507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562
    } else {
      GST_LOG_OBJECT (rtpmp4vpay, "found config in stream");
      rtpmp4vpay->last_config = timestamp;
    }
  }

  /* there is a config request, see if we need to insert it */
  if (rtpmp4vpay->send_config && vopi && (rtpmp4vpay->config_interval > 0) &&
      rtpmp4vpay->config) {
    if (rtpmp4vpay->last_config != -1) {
      guint64 diff;

      GST_LOG_OBJECT (rtpmp4vpay,
          "now %" GST_TIME_FORMAT ", last VOP-I %" GST_TIME_FORMAT,
          GST_TIME_ARGS (timestamp), GST_TIME_ARGS (rtpmp4vpay->last_config));

      /* calculate diff between last config in milliseconds */
      if (timestamp > rtpmp4vpay->last_config) {
        diff = timestamp - rtpmp4vpay->last_config;
      } else {
        diff = 0;
      }

      GST_DEBUG_OBJECT (rtpmp4vpay,
          "interval since last config %" GST_TIME_FORMAT, GST_TIME_ARGS (diff));

      /* bigger than interval, queue config */
      /* FIXME should convert timestamps to running time */
      if (GST_TIME_AS_SECONDS (diff) >= rtpmp4vpay->config_interval) {
        GST_DEBUG_OBJECT (rtpmp4vpay, "time to send config");
        send_config = TRUE;
      }
    } else {
      /* no known previous config time, send now */
      GST_DEBUG_OBJECT (rtpmp4vpay, "no previous config time, send now");
      send_config = TRUE;
    }

    if (send_config) {
      /* we need to send config now first */
      GstBuffer *superbuf;

      GST_LOG_OBJECT (rtpmp4vpay, "inserting config in stream");

      /* insert header */
      superbuf = gst_buffer_merge (rtpmp4vpay->config, buffer);

      GST_BUFFER_TIMESTAMP (superbuf) = timestamp;
      gst_buffer_unref (buffer);
      buffer = superbuf;

      size = GST_BUFFER_SIZE (buffer);

      if (timestamp != -1) {
        rtpmp4vpay->last_config = timestamp;
      }
Wim Taymans's avatar
Wim Taymans committed
563 564
    }
  }
565

Wim Taymans's avatar
Wim Taymans committed
566 567
  /* if we need to flush, do so now */
  if (flush) {
568
    ret = gst_rtp_mp4v_pay_flush (rtpmp4vpay);
569
    rtpmp4vpay->first_timestamp = timestamp;
570
    rtpmp4vpay->duration = 0;
571
    avail = 0;
572 573
  }

Wim Taymans's avatar
Wim Taymans committed
574
  /* get packet length of data and see if we exceeded MTU. */
575
  packet_len = gst_rtp_buffer_calc_packet_len (avail + size, 0, 0);
576

577
  if (gst_basertppayload_is_filled (basepayload,
578 579
          packet_len, rtpmp4vpay->duration + duration)) {
    ret = gst_rtp_mp4v_pay_flush (rtpmp4vpay);
580
    rtpmp4vpay->first_timestamp = timestamp;
581
    rtpmp4vpay->duration = 0;
582 583
  }

584
  /* push new data */
585
  gst_adapter_push (rtpmp4vpay->adapter, buffer);
586

587
  rtpmp4vpay->duration += duration;
588

589 590 591
  return ret;
}

592
static gboolean
593
gst_rtp_mp4v_pay_handle_event (GstPad * pad, GstEvent * event)
594 595 596 597 598 599 600 601 602
{
  GstRtpMP4VPay *rtpmp4vpay;

  rtpmp4vpay = GST_RTP_MP4V_PAY (gst_pad_get_parent (pad));

  GST_DEBUG ("Got event: %s", GST_EVENT_TYPE_NAME (event));

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_NEWSEGMENT:
603 604 605
    case GST_EVENT_EOS:
      /* This flush call makes sure that the last buffer is always pushed
       * to the base payloader */
606 607 608 609 610 611 612 613 614 615 616
      gst_rtp_mp4v_pay_flush (rtpmp4vpay);
      break;
    case GST_EVENT_FLUSH_STOP:
      gst_rtp_mp4v_pay_empty (rtpmp4vpay);
      break;
    default:
      break;
  }

  g_object_unref (rtpmp4vpay);

617 618
  /* let parent handle event too */
  return FALSE;
619 620
}

Wim Taymans's avatar
Wim Taymans committed
621
static void
622
gst_rtp_mp4v_pay_set_property (GObject * object, guint prop_id,
Wim Taymans's avatar
Wim Taymans committed
623 624
    const GValue * value, GParamSpec * pspec)
{
625
  GstRtpMP4VPay *rtpmp4vpay;
Wim Taymans's avatar
Wim Taymans committed
626

627
  rtpmp4vpay = GST_RTP_MP4V_PAY (object);
Wim Taymans's avatar
Wim Taymans committed
628 629 630

  switch (prop_id) {
    case ARG_SEND_CONFIG:
631
      rtpmp4vpay->send_config = g_value_get_boolean (value);
Wim Taymans's avatar
Wim Taymans committed
632
      break;
633 634 635
    case ARG_BUFFER_LIST:
      rtpmp4vpay->buffer_list = g_value_get_boolean (value);
      break;
636 637 638
    case ARG_CONFIG_INTERVAL:
      rtpmp4vpay->config_interval = g_value_get_uint (value);
      break;
Wim Taymans's avatar
Wim Taymans committed
639 640 641 642 643 644
    default:
      break;
  }
}

static void
645
gst_rtp_mp4v_pay_get_property (GObject * object, guint prop_id,
Wim Taymans's avatar
Wim Taymans committed
646 647
    GValue * value, GParamSpec * pspec)
{
648
  GstRtpMP4VPay *rtpmp4vpay;
Wim Taymans's avatar
Wim Taymans committed
649

650
  rtpmp4vpay = GST_RTP_MP4V_PAY (object);
Wim Taymans's avatar
Wim Taymans committed
651 652 653

  switch (prop_id) {
    case ARG_SEND_CONFIG:
654
      g_value_set_boolean (value, rtpmp4vpay->send_config);
Wim Taymans's avatar
Wim Taymans committed
655
      break;
656 657 658
    case ARG_BUFFER_LIST:
      g_value_set_boolean (value, rtpmp4vpay->buffer_list);
      break;
659 660 661
    case ARG_CONFIG_INTERVAL:
      g_value_set_uint (value, rtpmp4vpay->config_interval);
      break;
Wim Taymans's avatar
Wim Taymans committed
662 663 664 665 666
    default:
      break;
  }
}

667
gboolean
668
gst_rtp_mp4v_pay_plugin_init (GstPlugin * plugin)
669
{
670
  return gst_element_register (plugin, "rtpmp4vpay",
671
      GST_RANK_SECONDARY, GST_TYPE_RTP_MP4V_PAY);
672
}