gstrtpmp4vpay.c 17.2 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
 * 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
Tim-Philipp Müller's avatar
Tim-Philipp Müller committed
16 17
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
 * Boston, MA 02110-1301, USA.
18 19 20 21 22 23 24 25 26
 */

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

#include <string.h>

#include <gst/rtp/gstrtpbuffer.h>
27
#include <gst/video/video.h>
28

29
#include "gstrtpmp4vpay.h"
30
#include "gstrtputils.h"
31

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

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

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

59
#define DEFAULT_CONFIG_INTERVAL 0
Wim Taymans's avatar
Wim Taymans committed
60 61 62

enum
{
63 64
  PROP_0,
  PROP_CONFIG_INTERVAL
Wim Taymans's avatar
Wim Taymans committed
65 66
};

67

68
static void gst_rtp_mp4v_pay_finalize (GObject * object);
69

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

Wim Taymans's avatar
Wim Taymans committed
75
static gboolean gst_rtp_mp4v_pay_setcaps (GstRTPBasePayload * payload,
76
    GstCaps * caps);
Wim Taymans's avatar
Wim Taymans committed
77
static GstFlowReturn gst_rtp_mp4v_pay_handle_buffer (GstRTPBasePayload *
78
    payload, GstBuffer * buffer);
Wim Taymans's avatar
Wim Taymans committed
79
static gboolean gst_rtp_mp4v_pay_sink_event (GstRTPBasePayload * pay,
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
80
    GstEvent * event);
81

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
82
#define gst_rtp_mp4v_pay_parent_class parent_class
Wim Taymans's avatar
Wim Taymans committed
83
G_DEFINE_TYPE (GstRtpMP4VPay, gst_rtp_mp4v_pay, GST_TYPE_RTP_BASE_PAYLOAD)
84

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
85
     static void gst_rtp_mp4v_pay_class_init (GstRtpMP4VPayClass * klass)
86 87
{
  GObjectClass *gobject_class;
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
88
  GstElementClass *gstelement_class;
Wim Taymans's avatar
Wim Taymans committed
89
  GstRTPBasePayloadClass *gstrtpbasepayload_class;
90 91

  gobject_class = (GObjectClass *) klass;
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
92
  gstelement_class = (GstElementClass *) klass;
Wim Taymans's avatar
Wim Taymans committed
93
  gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
94

95 96
  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
97

98 99 100 101
  gst_element_class_add_static_pad_template (gstelement_class,
      &gst_rtp_mp4v_pay_src_template);
  gst_element_class_add_static_pad_template (gstelement_class,
      &gst_rtp_mp4v_pay_sink_template);
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
102

103
  gst_element_class_set_static_metadata (gstelement_class,
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
104 105 106 107
      "RTP MPEG4 Video payloader", "Codec/Payloader/Network/RTP",
      "Payload MPEG-4 video as RTP packets (RFC 3016)",
      "Wim Taymans <wim.taymans@gmail.com>");

108
  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_CONFIG_INTERVAL,
109 110 111 112 113 114 115
      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)
      );

116
  gobject_class->finalize = gst_rtp_mp4v_pay_finalize;
117

Wim Taymans's avatar
Wim Taymans committed
118 119
  gstrtpbasepayload_class->set_caps = gst_rtp_mp4v_pay_setcaps;
  gstrtpbasepayload_class->handle_buffer = gst_rtp_mp4v_pay_handle_buffer;
Wim Taymans's avatar
Wim Taymans committed
120
  gstrtpbasepayload_class->sink_event = gst_rtp_mp4v_pay_sink_event;
121 122 123

  GST_DEBUG_CATEGORY_INIT (rtpmp4vpay_debug, "rtpmp4vpay", 0,
      "MP4 video RTP Payloader");
124 125 126
}

static void
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
127
gst_rtp_mp4v_pay_init (GstRtpMP4VPay * rtpmp4vpay)
128
{
129 130 131
  rtpmp4vpay->adapter = gst_adapter_new ();
  rtpmp4vpay->rate = 90000;
  rtpmp4vpay->profile = 1;
132
  rtpmp4vpay->need_config = TRUE;
133 134
  rtpmp4vpay->config_interval = DEFAULT_CONFIG_INTERVAL;
  rtpmp4vpay->last_config = -1;
135

136
  rtpmp4vpay->config = NULL;
137 138
}

139
static void
140
gst_rtp_mp4v_pay_finalize (GObject * object)
141
{
142
  GstRtpMP4VPay *rtpmp4vpay;
143

144
  rtpmp4vpay = GST_RTP_MP4V_PAY (object);
145

146
  if (rtpmp4vpay->config) {
147
    gst_buffer_unref (rtpmp4vpay->config);
148 149
    rtpmp4vpay->config = NULL;
  }
150 151
  g_object_unref (rtpmp4vpay->adapter);
  rtpmp4vpay->adapter = NULL;
152

153 154 155
  G_OBJECT_CLASS (parent_class)->finalize (object);
}

156
static gboolean
157
gst_rtp_mp4v_pay_new_caps (GstRtpMP4VPay * rtpmp4vpay)
158
{
159 160
  gchar *profile, *config;
  GValue v = { 0 };
161
  gboolean res;
162

163
  profile = g_strdup_printf ("%d", rtpmp4vpay->profile);
164
  g_value_init (&v, GST_TYPE_BUFFER);
165
  gst_value_set_buffer (&v, rtpmp4vpay->config);
166 167
  config = gst_value_serialize (&v);

Wim Taymans's avatar
Wim Taymans committed
168
  res = gst_rtp_base_payload_set_outcaps (GST_RTP_BASE_PAYLOAD (rtpmp4vpay),
169 170 171 172 173 174 175
      "profile-level-id", G_TYPE_STRING, profile,
      "config", G_TYPE_STRING, config, NULL);

  g_value_unset (&v);

  g_free (profile);
  g_free (config);
176 177

  return res;
178 179 180
}

static gboolean
Wim Taymans's avatar
Wim Taymans committed
181
gst_rtp_mp4v_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
182
{
183
  GstRtpMP4VPay *rtpmp4vpay;
184
  GstStructure *structure;
185
  const GValue *codec_data;
186
  gboolean res;
187

188
  rtpmp4vpay = GST_RTP_MP4V_PAY (payload);
189

Wim Taymans's avatar
Wim Taymans committed
190
  gst_rtp_base_payload_set_options (payload, "video", TRUE, "MP4V-ES",
191 192
      rtpmp4vpay->rate);

193 194
  res = TRUE;

195
  structure = gst_caps_get_structure (caps, 0);
196 197 198 199
  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) {
200 201
      GstBuffer *buffer;

202
      buffer = gst_value_get_buffer (codec_data);
203

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
204
      if (gst_buffer_get_size (buffer) < 5)
205 206
        goto done;

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
207
      gst_buffer_extract (buffer, 4, &rtpmp4vpay->profile, 1);
208
      GST_LOG_OBJECT (rtpmp4vpay, "configuring codec_data, profile %d",
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
209
          rtpmp4vpay->profile);
210 211 212 213

      if (rtpmp4vpay->config)
        gst_buffer_unref (rtpmp4vpay->config);
      rtpmp4vpay->config = gst_buffer_copy (buffer);
214
      res = gst_rtp_mp4v_pay_new_caps (rtpmp4vpay);
215 216 217 218
    }
  }

done:
219
  return res;
220 221
}

222 223 224 225 226 227
static void
gst_rtp_mp4v_pay_empty (GstRtpMP4VPay * rtpmp4vpay)
{
  gst_adapter_clear (rtpmp4vpay->adapter);
}

228 229
#define RTP_HEADER_LEN 12

230
static GstFlowReturn
231
gst_rtp_mp4v_pay_flush (GstRtpMP4VPay * rtpmp4vpay)
232
{
233
  guint avail, mtu;
234
  GstBuffer *outbuf;
235
  GstBuffer *outbuf_data = NULL;
236
  GstFlowReturn ret;
237
  GstBufferList *list = NULL;
238 239 240 241 242 243

  /* 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. */
244
  avail = gst_adapter_available (rtpmp4vpay->adapter);
245

246
  if (rtpmp4vpay->config == NULL && rtpmp4vpay->need_config) {
247 248 249 250 251
    /* when we don't have a config yet, flush things out */
    gst_adapter_flush (rtpmp4vpay->adapter, avail);
    avail = 0;
  }

252 253 254
  if (!avail)
    return GST_FLOW_OK;

255
  mtu = GST_RTP_BASE_PAYLOAD_MTU (rtpmp4vpay);
256

257 258 259
  /* Use buffer lists. Each frame will be put into a list
   * of buffers and the whole list will be pushed downstream
   * at once */
260
  list = gst_buffer_list_new_sized ((avail / (mtu - RTP_HEADER_LEN)) + 1);
261

262 263 264 265
  while (avail > 0) {
    guint towrite;
    guint payload_len;
    guint packet_len;
266
    GstRTPBuffer rtp = { NULL };
267 268

    /* this will be the total lenght of the packet */
269
    packet_len = gst_rtp_buffer_calc_packet_len (avail, 0, 0);
270 271

    /* fill one MTU or all available bytes */
272
    towrite = MIN (packet_len, mtu);
273 274

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

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
277 278 279
    /* create buffer without payload. The payload will be put
     * in next buffer instead. Both buffers will be merged */
    outbuf = gst_rtp_buffer_new_allocate (0, 0, 0);
280

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
281
    /* Take buffer with the payload from the adapter */
282 283
    outbuf_data = gst_adapter_take_buffer_fast (rtpmp4vpay->adapter,
        payload_len);
284 285 286

    avail -= payload_len;

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
287 288 289
    gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
    gst_rtp_buffer_set_marker (&rtp, avail == 0);
    gst_rtp_buffer_unmap (&rtp);
290
    gst_rtp_copy_video_meta (rtpmp4vpay, outbuf, outbuf_data);
Wim Taymans's avatar
Wim Taymans committed
291
    outbuf = gst_buffer_append (outbuf, outbuf_data);
292

293
    GST_BUFFER_PTS (outbuf) = rtpmp4vpay->first_timestamp;
294

295 296
    /* add to list */
    gst_buffer_list_insert (list, -1, outbuf);
297 298
  }

299 300 301
  /* push the whole buffer list at once */
  ret =
      gst_rtp_base_payload_push_list (GST_RTP_BASE_PAYLOAD (rtpmp4vpay), list);
302 303 304 305

  return ret;
}

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
306 307 308 309 310 311
#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
312 313

static gboolean
314
gst_rtp_mp4v_pay_depay_data (GstRtpMP4VPay * enc, guint8 * data, guint size,
315
    gint * strip, gboolean * vopi)
316 317 318
{
  guint32 code;
  gboolean result;
319
  *vopi = FALSE;
320

Wim Taymans's avatar
Wim Taymans committed
321 322
  *strip = 0;

323 324 325 326
  if (size < 5)
    return FALSE;

  code = GST_READ_UINT32_BE (data);
327
  GST_DEBUG_OBJECT (enc, "start code 0x%08x", code);
328 329 330

  switch (code) {
    case VOS_STARTCODE:
331
    case 0x00000101:
332 333 334 335 336 337
    {
      gint i;
      guint8 profile;
      gboolean newprofile = FALSE;
      gboolean equal;

338 339 340
      if (code == VOS_STARTCODE) {
        /* profile_and_level_indication */
        profile = data[4];
341

342
        GST_DEBUG_OBJECT (enc, "VOS profile 0x%08x", profile);
343

344 345 346 347
        if (profile != enc->profile) {
          newprofile = TRUE;
          enc->profile = profile;
        }
348 349 350 351 352 353 354 355 356 357 358 359 360 361
      }

      /* 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) {
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
362 363
        if (gst_buffer_get_size (enc->config) == i) {
          equal = gst_buffer_memcmp (enc->config, 0, data, i) == 0;
364 365 366 367 368 369 370
        }
      }
      /* 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);
Wim Taymans's avatar
Wim Taymans committed
371 372 373

        gst_buffer_fill (enc->config, 0, data, i);

374
        gst_rtp_mp4v_pay_new_caps (enc);
375
      }
Wim Taymans's avatar
Wim Taymans committed
376 377
      *strip = i;
      /* we need to flush out the current packet. */
378 379 380 381
      result = TRUE;
      break;
    }
    case VOP_STARTCODE:
382
      GST_DEBUG_OBJECT (enc, "VOP");
Wim Taymans's avatar
Wim Taymans committed
383
      /* VOP startcode, we don't have to flush the packet */
384
      result = FALSE;
385 386 387 388 389 390 391 392 393 394
      /* 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;
395
      break;
396 397 398 399
    case 0x00000100:
      enc->need_config = FALSE;
      result = TRUE;
      break;
400
    default:
401 402 403 404 405 406 407 408
      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;
      }
409 410 411 412 413
      break;
  }
  return result;
}

414 415 416
/* we expect buffers starting on startcodes. 
 */
static GstFlowReturn
Wim Taymans's avatar
Wim Taymans committed
417
gst_rtp_mp4v_pay_handle_buffer (GstRTPBasePayload * basepayload,
418
    GstBuffer * buffer)
419
{
420
  GstRtpMP4VPay *rtpmp4vpay;
421
  GstFlowReturn ret;
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
422
  guint avail;
423
  guint packet_len;
Wim Taymans's avatar
Wim Taymans committed
424 425
  GstMapInfo map;
  gsize size;
426
  gboolean flush;
Wim Taymans's avatar
Wim Taymans committed
427
  gint strip;
428
  GstClockTime timestamp, duration;
429 430
  gboolean vopi;
  gboolean send_config;
Wim Taymans's avatar
Wim Taymans committed
431 432

  ret = GST_FLOW_OK;
433
  send_config = FALSE;
434

435
  rtpmp4vpay = GST_RTP_MP4V_PAY (basepayload);
436

Wim Taymans's avatar
Wim Taymans committed
437 438
  gst_buffer_map (buffer, &map, GST_MAP_READ);
  size = map.size;
439
  timestamp = GST_BUFFER_PTS (buffer);
440
  duration = GST_BUFFER_DURATION (buffer);
441
  avail = gst_adapter_available (rtpmp4vpay->adapter);
442

443 444 445
  if (duration == -1)
    duration = 0;

Wim Taymans's avatar
Wim Taymans committed
446 447
  /* empty buffer, take timestamp */
  if (avail == 0) {
448
    rtpmp4vpay->first_timestamp = timestamp;
449
    rtpmp4vpay->duration = 0;
Wim Taymans's avatar
Wim Taymans committed
450 451
  }

452
  /* depay incomming data and see if we need to start a new RTP
453
   * packet */
Wim Taymans's avatar
Wim Taymans committed
454 455 456
  flush =
      gst_rtp_mp4v_pay_depay_data (rtpmp4vpay, map.data, size, &strip, &vopi);
  gst_buffer_unmap (buffer, &map);
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
457

Wim Taymans's avatar
Wim Taymans committed
458 459
  if (strip) {
    /* strip off config if requested */
460
    if (!(rtpmp4vpay->config_interval > 0)) {
Wim Taymans's avatar
Wim Taymans committed
461 462
      GstBuffer *subbuf;

463
      GST_LOG_OBJECT (rtpmp4vpay, "stripping config at %d, size %d", strip,
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
464
          (gint) size - strip);
465

Wim Taymans's avatar
Wim Taymans committed
466
      /* strip off header */
467
      subbuf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL, strip,
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
468
          size - strip);
469
      GST_BUFFER_PTS (subbuf) = timestamp;
Wim Taymans's avatar
Wim Taymans committed
470 471 472
      gst_buffer_unref (buffer);
      buffer = subbuf;

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
473
      size = gst_buffer_get_size (buffer);
474 475 476 477 478 479 480
    } 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 */
481
  if (vopi && (rtpmp4vpay->config_interval > 0) && rtpmp4vpay->config) {
482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515
    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 */
      GST_LOG_OBJECT (rtpmp4vpay, "inserting config in stream");

      /* insert header */
Wim Taymans's avatar
Wim Taymans committed
516
      buffer = gst_buffer_append (gst_buffer_ref (rtpmp4vpay->config), buffer);
517

518
      GST_BUFFER_PTS (buffer) = timestamp;
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
519
      size = gst_buffer_get_size (buffer);
520 521 522 523

      if (timestamp != -1) {
        rtpmp4vpay->last_config = timestamp;
      }
Wim Taymans's avatar
Wim Taymans committed
524 525
    }
  }
526

Wim Taymans's avatar
Wim Taymans committed
527 528
  /* if we need to flush, do so now */
  if (flush) {
529
    ret = gst_rtp_mp4v_pay_flush (rtpmp4vpay);
530
    rtpmp4vpay->first_timestamp = timestamp;
531
    rtpmp4vpay->duration = 0;
532
    avail = 0;
533 534
  }

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

Wim Taymans's avatar
Wim Taymans committed
538
  if (gst_rtp_base_payload_is_filled (basepayload,
539 540
          packet_len, rtpmp4vpay->duration + duration)) {
    ret = gst_rtp_mp4v_pay_flush (rtpmp4vpay);
541
    rtpmp4vpay->first_timestamp = timestamp;
542
    rtpmp4vpay->duration = 0;
543 544
  }

545
  /* push new data */
546
  gst_adapter_push (rtpmp4vpay->adapter, buffer);
547

548
  rtpmp4vpay->duration += duration;
549

550 551 552
  return ret;
}

553
static gboolean
Wim Taymans's avatar
Wim Taymans committed
554
gst_rtp_mp4v_pay_sink_event (GstRTPBasePayload * pay, GstEvent * event)
555 556 557
{
  GstRtpMP4VPay *rtpmp4vpay;

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
558
  rtpmp4vpay = GST_RTP_MP4V_PAY (pay);
559 560 561 562

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

  switch (GST_EVENT_TYPE (event)) {
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
563
    case GST_EVENT_SEGMENT:
564 565 566
    case GST_EVENT_EOS:
      /* This flush call makes sure that the last buffer is always pushed
       * to the base payloader */
567 568 569 570 571 572 573 574 575
      gst_rtp_mp4v_pay_flush (rtpmp4vpay);
      break;
    case GST_EVENT_FLUSH_STOP:
      gst_rtp_mp4v_pay_empty (rtpmp4vpay);
      break;
    default:
      break;
  }

576
  /* let parent handle event too */
Wim Taymans's avatar
Wim Taymans committed
577
  return GST_RTP_BASE_PAYLOAD_CLASS (parent_class)->sink_event (pay, event);
578 579
}

Wim Taymans's avatar
Wim Taymans committed
580
static void
581
gst_rtp_mp4v_pay_set_property (GObject * object, guint prop_id,
Wim Taymans's avatar
Wim Taymans committed
582 583
    const GValue * value, GParamSpec * pspec)
{
584
  GstRtpMP4VPay *rtpmp4vpay;
Wim Taymans's avatar
Wim Taymans committed
585

586
  rtpmp4vpay = GST_RTP_MP4V_PAY (object);
Wim Taymans's avatar
Wim Taymans committed
587 588

  switch (prop_id) {
589
    case PROP_CONFIG_INTERVAL:
590 591
      rtpmp4vpay->config_interval = g_value_get_uint (value);
      break;
Wim Taymans's avatar
Wim Taymans committed
592 593 594 595 596 597
    default:
      break;
  }
}

static void
598
gst_rtp_mp4v_pay_get_property (GObject * object, guint prop_id,
Wim Taymans's avatar
Wim Taymans committed
599 600
    GValue * value, GParamSpec * pspec)
{
601
  GstRtpMP4VPay *rtpmp4vpay;
Wim Taymans's avatar
Wim Taymans committed
602

603
  rtpmp4vpay = GST_RTP_MP4V_PAY (object);
Wim Taymans's avatar
Wim Taymans committed
604 605

  switch (prop_id) {
606
    case PROP_CONFIG_INTERVAL:
607 608
      g_value_set_uint (value, rtpmp4vpay->config_interval);
      break;
Wim Taymans's avatar
Wim Taymans committed
609 610 611 612 613
    default:
      break;
  }
}

614
gboolean
615
gst_rtp_mp4v_pay_plugin_init (GstPlugin * plugin)
616
{
617
  return gst_element_register (plugin, "rtpmp4vpay",
618
      GST_RANK_SECONDARY, GST_TYPE_RTP_MP4V_PAY);
619
}