gstrtph264depay.c 34.7 KB
Newer Older
1
/* GStreamer
2
 * Copyright (C) <2006> Wim Taymans <wim.taymans@gmail.com>
3
4
5
6
7
8
9
10
11
12
13
14
15
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more 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
 */

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

24
#include <stdio.h>
25
26
#include <string.h>

27
#include <gst/base/gstbitreader.h>
28
29
30
#include <gst/rtp/gstrtpbuffer.h>
#include "gstrtph264depay.h"

31
32
33
GST_DEBUG_CATEGORY_STATIC (rtph264depay_debug);
#define GST_CAT_DEFAULT (rtph264depay_debug)

34
35
36
37
/* This is what we'll default to when downstream hasn't
 * expressed a restriction or preference via caps */
#define DEFAULT_BYTE_STREAM   TRUE
#define DEFAULT_ACCESS_UNIT   FALSE
38

39
40
/* 3 zero bytes syncword */
static const guint8 sync_bytes[] = { 0, 0, 0, 1 };
41

42
static GstStaticPadTemplate gst_rtp_h264_depay_src_template =
43
    GST_STATIC_PAD_TEMPLATE ("src",
44
45
    GST_PAD_SRC,
    GST_PAD_ALWAYS,
46
47
48
49
    GST_STATIC_CAPS ("video/x-h264, "
        "stream-format = (string) avc, alignment = (string) au; "
        "video/x-h264, "
        "stream-format = (string) byte-stream, alignment = (string) { nal, au }")
50
51
52
53
54
55
56
57
    );

static GstStaticPadTemplate gst_rtp_h264_depay_sink_template =
GST_STATIC_PAD_TEMPLATE ("sink",
    GST_PAD_SINK,
    GST_PAD_ALWAYS,
    GST_STATIC_CAPS ("application/x-rtp, "
        "media = (string) \"video\", "
58
        "clock-rate = (int) 90000, " "encoding-name = (string) \"H264\"")
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
        /** optional parameters **/
    /* "profile-level-id = (string) ANY, " */
    /* "max-mbps = (string) ANY, " */
    /* "max-fs = (string) ANY, " */
    /* "max-cpb = (string) ANY, " */
    /* "max-dpb = (string) ANY, " */
    /* "max-br = (string) ANY, " */
    /* "redundant-pic-cap = (string) { \"0\", \"1\" }, " */
    /* "sprop-parameter-sets = (string) ANY, " */
    /* "parameter-add = (string) { \"0\", \"1\" }, " */
    /* "packetization-mode = (string) { \"0\", \"1\", \"2\" }, " */
    /* "sprop-interleaving-depth = (string) ANY, " */
    /* "sprop-deint-buf-req = (string) ANY, " */
    /* "deint-buf-cap = (string) ANY, " */
    /* "sprop-init-buf-time = (string) ANY, " */
    /* "sprop-max-don-diff = (string) ANY, " */
75
    /* "max-rcmd-nalu-size = (string) ANY " */
76
77
    );

Wim Taymans's avatar
Wim Taymans committed
78
79
#define gst_rtp_h264_depay_parent_class parent_class
G_DEFINE_TYPE (GstRtpH264Depay, gst_rtp_h264_depay,
Wim Taymans's avatar
Wim Taymans committed
80
    GST_TYPE_RTP_BASE_DEPAYLOAD);
81
82
83
84
85
86

static void gst_rtp_h264_depay_finalize (GObject * object);

static GstStateChangeReturn gst_rtp_h264_depay_change_state (GstElement *
    element, GstStateChange transition);

Wim Taymans's avatar
Wim Taymans committed
87
static GstBuffer *gst_rtp_h264_depay_process (GstRTPBaseDepayload * depayload,
88
    GstBuffer * buf);
Wim Taymans's avatar
Wim Taymans committed
89
static gboolean gst_rtp_h264_depay_setcaps (GstRTPBaseDepayload * filter,
90
    GstCaps * caps);
Wim Taymans's avatar
Wim Taymans committed
91
static gboolean gst_rtp_h264_depay_handle_event (GstRTPBaseDepayload * depay,
92
    GstEvent * event);
93
94
95
96
97
98

static void
gst_rtp_h264_depay_class_init (GstRtpH264DepayClass * klass)
{
  GObjectClass *gobject_class;
  GstElementClass *gstelement_class;
Wim Taymans's avatar
Wim Taymans committed
99
  GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
100
101
102

  gobject_class = (GObjectClass *) klass;
  gstelement_class = (GstElementClass *) klass;
Wim Taymans's avatar
Wim Taymans committed
103
  gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
104
105
106

  gobject_class->finalize = gst_rtp_h264_depay_finalize;

Wim Taymans's avatar
Wim Taymans committed
107
108
109
110
111
  gst_element_class_add_pad_template (gstelement_class,
      gst_static_pad_template_get (&gst_rtp_h264_depay_src_template));
  gst_element_class_add_pad_template (gstelement_class,
      gst_static_pad_template_get (&gst_rtp_h264_depay_sink_template));

112
  gst_element_class_set_static_metadata (gstelement_class,
Wim Taymans's avatar
Wim Taymans committed
113
114
115
      "RTP H264 depayloader", "Codec/Depayloader/Network/RTP",
      "Extracts H264 video from RTP packets (RFC 3984)",
      "Wim Taymans <wim.taymans@gmail.com>");
116
  gstelement_class->change_state = gst_rtp_h264_depay_change_state;
117

Wim Taymans's avatar
Wim Taymans committed
118
119
120
  gstrtpbasedepayload_class->process = gst_rtp_h264_depay_process;
  gstrtpbasedepayload_class->set_caps = gst_rtp_h264_depay_setcaps;
  gstrtpbasedepayload_class->handle_event = gst_rtp_h264_depay_handle_event;
121
122
123
}

static void
Wim Taymans's avatar
Wim Taymans committed
124
gst_rtp_h264_depay_init (GstRtpH264Depay * rtph264depay)
125
126
{
  rtph264depay->adapter = gst_adapter_new ();
127
  rtph264depay->picture_adapter = gst_adapter_new ();
128
  rtph264depay->byte_stream = DEFAULT_BYTE_STREAM;
129
  rtph264depay->merge = DEFAULT_ACCESS_UNIT;
130
131
132
133
  rtph264depay->sps = g_ptr_array_new_with_free_func (
      (GDestroyNotify) gst_buffer_unref);
  rtph264depay->pps = g_ptr_array_new_with_free_func (
      (GDestroyNotify) gst_buffer_unref);
134
135
}

136
137
138
139
140
141
142
143
144
static void
gst_rtp_h264_depay_reset (GstRtpH264Depay * rtph264depay)
{
  gst_adapter_clear (rtph264depay->adapter);
  rtph264depay->wait_start = TRUE;
  gst_adapter_clear (rtph264depay->picture_adapter);
  rtph264depay->picture_start = FALSE;
  rtph264depay->last_keyframe = FALSE;
  rtph264depay->last_ts = 0;
145
  rtph264depay->current_fu_type = 0;
146
147
148
  rtph264depay->new_codec_data = FALSE;
  g_ptr_array_set_size (rtph264depay->sps, 0);
  g_ptr_array_set_size (rtph264depay->pps, 0);
149
150
}

151
152
153
154
155
156
157
static void
gst_rtp_h264_depay_finalize (GObject * object)
{
  GstRtpH264Depay *rtph264depay;

  rtph264depay = GST_RTP_H264_DEPAY (object);

158
159
160
  if (rtph264depay->codec_data)
    gst_buffer_unref (rtph264depay->codec_data);

161
  g_object_unref (rtph264depay->adapter);
162
  g_object_unref (rtph264depay->picture_adapter);
163

164
165
166
  g_ptr_array_free (rtph264depay->sps, TRUE);
  g_ptr_array_free (rtph264depay->pps, TRUE);

167
168
169
  G_OBJECT_CLASS (parent_class)->finalize (object);
}

170
171
172
173
174
175
176
177
static void
gst_rtp_h264_depay_negotiate (GstRtpH264Depay * rtph264depay)
{
  GstCaps *caps;
  gint byte_stream = -1;
  gint merge = -1;

  caps =
Wim Taymans's avatar
Wim Taymans committed
178
      gst_pad_get_allowed_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (rtph264depay));
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209

  GST_DEBUG_OBJECT (rtph264depay, "allowed caps: %" GST_PTR_FORMAT, caps);

  if (caps) {
    if (gst_caps_get_size (caps) > 0) {
      GstStructure *s = gst_caps_get_structure (caps, 0);
      const gchar *str = NULL;

      if ((str = gst_structure_get_string (s, "stream-format"))) {
        if (strcmp (str, "avc") == 0) {
          byte_stream = FALSE;
        } else if (strcmp (str, "byte-stream") == 0) {
          byte_stream = TRUE;
        } else {
          GST_DEBUG_OBJECT (rtph264depay, "unknown stream-format: %s", str);
        }
      }

      if ((str = gst_structure_get_string (s, "alignment"))) {
        if (strcmp (str, "au") == 0) {
          merge = TRUE;
        } else if (strcmp (str, "nal") == 0) {
          merge = FALSE;
        } else {
          GST_DEBUG_OBJECT (rtph264depay, "unknown alignment: %s", str);
        }
      }
    }
    gst_caps_unref (caps);
  }

210
  if (byte_stream != -1) {
211
212
    GST_DEBUG_OBJECT (rtph264depay, "downstream requires byte-stream %d",
        byte_stream);
213
214
215
216
217
    rtph264depay->byte_stream = byte_stream;
  } else {
    GST_DEBUG_OBJECT (rtph264depay, "defaulting to byte-stream %d",
        DEFAULT_BYTE_STREAM);
    rtph264depay->byte_stream = DEFAULT_BYTE_STREAM;
218
  }
219
  if (merge != -1) {
220
    GST_DEBUG_OBJECT (rtph264depay, "downstream requires merge %d", merge);
221
222
223
224
225
    rtph264depay->merge = merge;
  } else {
    GST_DEBUG_OBJECT (rtph264depay, "defaulting to merge %d",
        DEFAULT_ACCESS_UNIT);
    rtph264depay->merge = DEFAULT_ACCESS_UNIT;
226
227
228
  }
}

229
230
/* Stolen from bad/gst/mpegtsdemux/payloader_parsers.c */
/* variable length Exp-Golomb parsing according to H.264 spec 9.1*/
231
static gboolean
232
read_golomb (GstBitReader * br, guint32 * value)
233
{
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
  guint8 b, leading_zeros = -1;
  *value = 1;

  for (b = 0; !b; leading_zeros++) {
    if (!gst_bit_reader_get_bits_uint8 (br, &b, 1))
      return FALSE;
    *value *= 2;
  }

  *value = (*value >> 1) - 1;
  if (leading_zeros > 0) {
    guint32 tmp = 0;
    if (!gst_bit_reader_get_bits_uint32 (br, &tmp, leading_zeros))
      return FALSE;
    *value += tmp;
  }

  return TRUE;
}

static gboolean
parse_sps (GstMapInfo * map, guint32 * sps_id)
{
  GstBitReader br = GST_BIT_READER_INIT (map->data + 4,
      map->size - 4);

  if (map->size < 5)
    return FALSE;

  if (!read_golomb (&br, sps_id))
    return FALSE;

  return TRUE;
}

static gboolean
parse_pps (GstMapInfo * map, guint32 * sps_id, guint32 * pps_id)
{
  GstBitReader br = GST_BIT_READER_INIT (map->data + 1,
      map->size - 1);

  if (map->size < 2)
    return FALSE;

  if (!read_golomb (&br, pps_id))
    return FALSE;
  if (!read_golomb (&br, sps_id))
    return FALSE;

  return TRUE;
}


static gboolean
gst_rtp_h264_set_src_caps (GstRtpH264Depay * rtph264depay)
{
  gboolean res;
291
  GstCaps *srccaps;
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
  guchar level = 0;
  guchar profile_compat = G_MAXUINT8;

  if (!rtph264depay->byte_stream &&
      (!rtph264depay->new_codec_data ||
          rtph264depay->sps->len == 0 || rtph264depay->pps->len == 0))
    return TRUE;

  srccaps = gst_caps_new_simple ("video/x-h264",
      "stream-format", G_TYPE_STRING,
      rtph264depay->byte_stream ? "byte-stream" : "avc",
      "alignment", G_TYPE_STRING, rtph264depay->merge ? "au" : "nal", NULL);

  if (!rtph264depay->byte_stream) {
    GstBuffer *codec_data;
    GstMapInfo map;
    GstMapInfo nalmap;
    guint8 *data;
    guint len;
    guint new_size;
    guint i;

    /* start with 7 bytes header */
    len = 7;
    /* count sps & pps */
    for (i = 0; i < rtph264depay->sps->len; i++)
      len += 2 + gst_buffer_get_size (g_ptr_array_index (rtph264depay->sps, i));
    for (i = 0; i < rtph264depay->pps->len; i++)
      len += 2 + gst_buffer_get_size (g_ptr_array_index (rtph264depay->pps, i));

    codec_data = gst_buffer_new_and_alloc (len);
    g_debug ("alloc_len: %u", len);
    gst_buffer_map (codec_data, &map, GST_MAP_READWRITE);
    data = map.data;

    /* 8 bits version == 1 */
    *data++ = 1;

    /* According to: ISO/IEC 14496-15:2004(E) section 5.2.4.1
     * The level is the max level of all SPSes
     * A profile compat bit can only be set if all SPSes include that bit
     */
    for (i = 0; i < rtph264depay->sps->len; i++) {
      gst_buffer_map (g_ptr_array_index (rtph264depay->sps, i), &nalmap,
          GST_MAP_READ);
      profile_compat &= nalmap.data[2];
      level = MAX (level, nalmap.data[3]);
      gst_buffer_unmap (g_ptr_array_index (rtph264depay->sps, i), &nalmap);
    }

    /* Assume all SPSes use the same profile, so extract from the first SPS */
    gst_buffer_map (g_ptr_array_index (rtph264depay->sps, 0), &nalmap,
        GST_MAP_READ);
    *data++ = nalmap.data[1];
    gst_buffer_unmap (g_ptr_array_index (rtph264depay->sps, 0), &nalmap);
    *data++ = profile_compat;
    *data++ = level;

    /* 6 bits reserved | 2 bits lengthSizeMinusOn */
    *data++ = 0xff;
    /* 3 bits reserved | 5 bits numOfSequenceParameterSets */
    *data++ = 0xe0 | (rtph264depay->sps->len & 0x1f);

    /* copy all SPS */
    for (i = 0; i < rtph264depay->sps->len; i++) {
      gst_buffer_map (g_ptr_array_index (rtph264depay->sps, i), &nalmap,
          GST_MAP_READ);

360
361
      GST_DEBUG_OBJECT (rtph264depay, "copy SPS %d of length %u", i,
          (guint) nalmap.size);
362
363
364
365
366
367
368
369
370
371
372
373
374
375
      GST_WRITE_UINT16_BE (data, nalmap.size);
      data += 2;
      memcpy (data, nalmap.data, nalmap.size);
      data += nalmap.size;
      gst_buffer_unmap (g_ptr_array_index (rtph264depay->sps, i), &nalmap);
    }

    /* 8 bits numOfPictureParameterSets */
    *data++ = rtph264depay->pps->len;
    /* copy all PPS */
    for (i = 0; i < rtph264depay->pps->len; i++) {
      gst_buffer_map (g_ptr_array_index (rtph264depay->pps, i), &nalmap,
          GST_MAP_READ);

376
377
      GST_DEBUG_OBJECT (rtph264depay, "copy PPS %d of length %u", i,
          (guint) nalmap.size);
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
      GST_WRITE_UINT16_BE (data, nalmap.size);
      data += 2;
      memcpy (data, nalmap.data, nalmap.size);
      data += nalmap.size;
      gst_buffer_unmap (g_ptr_array_index (rtph264depay->pps, i), &nalmap);
    }

    new_size = data - map.data;
    gst_buffer_unmap (codec_data, &map);
    gst_buffer_set_size (codec_data, new_size);


    gst_caps_set_simple (srccaps,
        "codec_data", GST_TYPE_BUFFER, codec_data, NULL);
    gst_buffer_unref (codec_data);
  }

  res = gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (rtph264depay),
      srccaps);
  gst_caps_unref (srccaps);

  if (res)
    rtph264depay->new_codec_data = FALSE;

  return res;
}

405
406
407
gboolean
gst_rtp_h264_add_sps_pps (GstElement * rtph264, GPtrArray * sps_array,
    GPtrArray * pps_array, GstBuffer * nal)
408
409
410
411
412
413
414
415
416
417
418
419
420
{
  GstMapInfo map;
  guchar type;
  guint i;

  gst_buffer_map (nal, &map, GST_MAP_READ);

  type = map.data[0] & 0x1f;

  if (type == 7) {
    guint32 sps_id;

    if (!parse_sps (&map, &sps_id)) {
421
      GST_WARNING_OBJECT (rtph264, "Invalid SPS,"
422
423
424
425
          " can't parse seq_parameter_set_id");
      goto drop;
    }

426
427
    for (i = 0; i < sps_array->len; i++) {
      GstBuffer *sps = g_ptr_array_index (sps_array, i);
428
429
430
431
432
433
434
435
436
      GstMapInfo spsmap;
      guint32 tmp_sps_id;

      gst_buffer_map (sps, &spsmap, GST_MAP_READ);
      parse_sps (&spsmap, &tmp_sps_id);

      if (sps_id == tmp_sps_id) {
        if (map.size == spsmap.size &&
            memcmp (map.data, spsmap.data, spsmap.size) == 0) {
437
          GST_LOG_OBJECT (rtph264, "Unchanged SPS %u, not updating", sps_id);
438
439
440
441
          gst_buffer_unmap (sps, &spsmap);
          goto drop;
        } else {
          gst_buffer_unmap (sps, &spsmap);
442
443
444
          g_ptr_array_remove_index_fast (sps_array, i);
          g_ptr_array_add (sps_array, nal);
          GST_LOG_OBJECT (rtph264, "Modified SPS %u, replacing", sps_id);
445
446
447
448
449
          goto done;
        }
      }
      gst_buffer_unmap (sps, &spsmap);
    }
450
451
    GST_LOG_OBJECT (rtph264, "Adding new SPS %u", sps_id);
    g_ptr_array_add (sps_array, nal);
452
453
454
455
456
  } else if (type == 8) {
    guint32 sps_id;
    guint32 pps_id;

    if (!parse_pps (&map, &sps_id, &pps_id)) {
457
      GST_WARNING_OBJECT (rtph264, "Invalid PPS,"
458
459
460
461
          " can't parse seq_parameter_set_id or pic_parameter_set_id");
      goto drop;
    }

462
463
    for (i = 0; i < pps_array->len; i++) {
      GstBuffer *pps = g_ptr_array_index (pps_array, i);
464
465
466
467
468
469
470
471
472
473
474
      GstMapInfo ppsmap;
      guint32 tmp_sps_id;
      guint32 tmp_pps_id;


      gst_buffer_map (pps, &ppsmap, GST_MAP_READ);
      parse_pps (&ppsmap, &tmp_sps_id, &tmp_pps_id);

      if (sps_id == tmp_sps_id && pps_id == tmp_pps_id) {
        if (map.size == ppsmap.size &&
            memcmp (map.data, ppsmap.data, ppsmap.size) == 0) {
475
476
          GST_LOG_OBJECT (rtph264, "Unchanged PPS %u:%u, not updating", sps_id,
              pps_id);
477
478
479
480
          gst_buffer_unmap (pps, &ppsmap);
          goto drop;
        } else {
          gst_buffer_unmap (pps, &ppsmap);
481
482
483
          g_ptr_array_remove_index_fast (pps_array, i);
          g_ptr_array_add (pps_array, nal);
          GST_LOG_OBJECT (rtph264, "Modified PPS %u:%u, replacing",
484
485
486
487
488
489
              sps_id, pps_id);
          goto done;
        }
      }
      gst_buffer_unmap (pps, &ppsmap);
    }
490
491
    GST_LOG_OBJECT (rtph264, "Adding new PPS %u:%i", sps_id, pps_id);
    g_ptr_array_add (pps_array, nal);
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
  } else {
    goto drop;
  }

done:
  gst_buffer_unmap (nal, &map);

  return TRUE;

drop:
  gst_buffer_unmap (nal, &map);
  gst_buffer_unref (nal);

  return FALSE;
}

508
509
510
511
512
513
514
515
516

static void
gst_rtp_h264_depay_add_sps_pps (GstRtpH264Depay * rtph264depay, GstBuffer * nal)
{
  if (gst_rtp_h264_add_sps_pps (GST_ELEMENT (rtph264depay),
          rtph264depay->sps, rtph264depay->pps, nal))
    rtph264depay->new_codec_data = TRUE;
}

517
518
519
static gboolean
gst_rtp_h264_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
{
520
  gint clock_rate;
521
  GstStructure *structure = gst_caps_get_structure (caps, 0);
522
  GstRtpH264Depay *rtph264depay;
523
  const gchar *ps;
524
  GstBuffer *codec_data;
Wim Taymans's avatar
Wim Taymans committed
525
526
  GstMapInfo map;
  guint8 *ptr;
527
528

  rtph264depay = GST_RTP_H264_DEPAY (depayload);
529

530
531
  if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
    clock_rate = 90000;
532
  depayload->clock_rate = clock_rate;
533

534
535
536
  /* Base64 encoded, comma separated config NALs */
  ps = gst_structure_get_string (structure, "sprop-parameter-sets");

537
538
539
  /* negotiate with downstream w.r.t. output format and alignment */
  gst_rtp_h264_depay_negotiate (rtph264depay);

540
541
542
  if (rtph264depay->byte_stream && ps != NULL) {
    /* for bytestream we only need the parameter sets but we don't error out
     * when they are not there, we assume they are in the stream. */
543
544
545
546
547
548
    gchar **params;
    guint len, total;
    gint i;

    params = g_strsplit (ps, ",", 0);

549
550
    /* count total number of bytes in base64. Also include the sync bytes in
     * front of the params. */
551
552
553
    len = 0;
    for (i = 0; params[i]; i++) {
      len += strlen (params[i]);
554
      len += sizeof (sync_bytes);
555
556
557
    }
    /* we seriously overshoot the length, but it's fine. */
    codec_data = gst_buffer_new_and_alloc (len);
Wim Taymans's avatar
Wim Taymans committed
558

Wim Taymans's avatar
Wim Taymans committed
559
560
    gst_buffer_map (codec_data, &map, GST_MAP_WRITE);
    ptr = map.data;
561
562
    total = 0;
    for (i = 0; params[i]; i++) {
563
564
565
      guint save = 0;
      gint state = 0;

566
      GST_DEBUG_OBJECT (depayload, "decoding param %d (%s)", i, params[i]);
Wim Taymans's avatar
Wim Taymans committed
567
568
      memcpy (ptr, sync_bytes, sizeof (sync_bytes));
      ptr += sizeof (sync_bytes);
569
      len =
Wim Taymans's avatar
Wim Taymans committed
570
          g_base64_decode_step (params[i], strlen (params[i]), ptr, &state,
571
572
          &save);
      GST_DEBUG_OBJECT (depayload, "decoded %d bytes", len);
573
      total += len + sizeof (sync_bytes);
Wim Taymans's avatar
Wim Taymans committed
574
      ptr += len;
575
    }
Wim Taymans's avatar
Wim Taymans committed
576
577
    gst_buffer_unmap (codec_data, &map);
    gst_buffer_resize (codec_data, 0, total);
578
    g_strfreev (params);
579

580
581
582
583
584
585
    /* keep the codec_data, we need to send it as the first buffer. We cannot
     * push it in the adapter because the adapter might be flushed on discont.
     */
    if (rtph264depay->codec_data)
      gst_buffer_unref (rtph264depay->codec_data);
    rtph264depay->codec_data = codec_data;
586
587
588
589
  } else if (!rtph264depay->byte_stream) {
    gchar **params;
    gint i;

590
    if (ps == NULL)
591
592
593
594
      goto incomplete_caps;

    params = g_strsplit (ps, ",", 0);

595
    GST_DEBUG_OBJECT (depayload, "we have %d params", g_strv_length (params));
596
597
598

    /* start with 7 bytes header */
    for (i = 0; params[i]; i++) {
599
600
      GstBuffer *nal;
      GstMapInfo nalmap;
601
602
603
      gsize nal_len;
      guint save = 0;
      gint state = 0;
604
605

      nal_len = strlen (params[i]);
606
607
      nal = gst_buffer_new_and_alloc (nal_len);
      gst_buffer_map (nal, &nalmap, GST_MAP_READWRITE);
608
609

      nal_len =
610
          g_base64_decode_step (params[i], nal_len, nalmap.data, &state, &save);
611

612
613
      GST_DEBUG_OBJECT (depayload, "adding param %d as %s", i,
          ((nalmap.data[0] & 0x1f) == 7) ? "SPS" : "PPS");
Wim Taymans's avatar
Wim Taymans committed
614

615
616
      gst_buffer_unmap (nal, &nalmap);
      gst_buffer_set_size (nal, nal_len);
617

618
      gst_rtp_h264_depay_add_sps_pps (rtph264depay, nal);
619
    }
620
    g_strfreev (params);
621

622
623
    if (rtph264depay->sps->len == 0 || rtph264depay->pps->len == 0)
      goto incomplete_caps;
624
625
  }

626
  return gst_rtp_h264_set_src_caps (rtph264depay);
627
628
629
630

  /* ERRORS */
incomplete_caps:
  {
631
632
633
    GST_DEBUG_OBJECT (depayload, "we have incomplete caps,"
        " doing setcaps later");
    return TRUE;
634
  }
635
636
}

637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
static GstBuffer *
gst_rtp_h264_complete_au (GstRtpH264Depay * rtph264depay,
    GstClockTime * out_timestamp, gboolean * out_keyframe)
{
  guint outsize;
  GstBuffer *outbuf;

  /* we had a picture in the adapter and we completed it */
  GST_DEBUG_OBJECT (rtph264depay, "taking completed AU");
  outsize = gst_adapter_available (rtph264depay->picture_adapter);
  outbuf = gst_adapter_take_buffer (rtph264depay->picture_adapter, outsize);

  *out_timestamp = rtph264depay->last_ts;
  *out_keyframe = rtph264depay->last_keyframe;

  rtph264depay->last_keyframe = FALSE;
  rtph264depay->picture_start = FALSE;

  return outbuf;
}

658
659
660
/* SPS/PPS/IDR considered key, all others DELTA;
 * so downstream waiting for keyframe can pick up at SPS/PPS/IDR */
#define NAL_TYPE_IS_KEY(nt) (((nt) == 5) || ((nt) == 7) || ((nt) == 8))
661

662
static GstBuffer *
663
gst_rtp_h264_depay_handle_nal (GstRtpH264Depay * rtph264depay, GstBuffer * nal,
664
    GstClockTime in_timestamp, gboolean marker)
665
{
Wim Taymans's avatar
Wim Taymans committed
666
  GstRTPBaseDepayload *depayload = GST_RTP_BASE_DEPAYLOAD (rtph264depay);
667
  gint nal_type;
Wim Taymans's avatar
Wim Taymans committed
668
  GstMapInfo map;
669
  GstBuffer *outbuf = NULL;
670
  GstClockTime out_timestamp;
671
  gboolean keyframe, out_keyframe;
672

Wim Taymans's avatar
Wim Taymans committed
673
674
  gst_buffer_map (nal, &map, GST_MAP_READ);
  if (G_UNLIKELY (map.size < 5))
675
    goto short_nal;
676

Wim Taymans's avatar
Wim Taymans committed
677
  nal_type = map.data[4] & 0x1f;
678
679
  GST_DEBUG_OBJECT (rtph264depay, "handle NAL type %d", nal_type);

680
  keyframe = NAL_TYPE_IS_KEY (nal_type);
681

682
  out_keyframe = keyframe;
683
684
  out_timestamp = in_timestamp;

685
686
  if (!rtph264depay->byte_stream) {
    if (nal_type == 7 || nal_type == 8) {
687
      gst_rtp_h264_depay_add_sps_pps (rtph264depay,
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
          gst_buffer_copy_region (nal, GST_BUFFER_COPY_ALL,
              4, gst_buffer_get_size (nal) - 4));
      gst_buffer_unmap (nal, &map);
      gst_buffer_unref (nal);
      return NULL;
    } else if (rtph264depay->sps->len == 0 || rtph264depay->pps->len == 0) {
      /* Down push down any buffer in non-bytestream mode if the SPS/PPS haven't
       * go through yet
       */
      gst_pad_push_event (GST_RTP_BASE_DEPAYLOAD_SINKPAD (depayload),
          gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
              gst_structure_new ("GstForceKeyUnit",
                  "all-headers", G_TYPE_BOOLEAN, TRUE, NULL)));
      gst_buffer_unmap (nal, &map);
      gst_buffer_unref (nal);
Wim Taymans's avatar
Wim Taymans committed
703
      return NULL;
704
705
706
707
708
709
710
711
    }

    if (rtph264depay->new_codec_data &&
        rtph264depay->sps->len > 0 && rtph264depay->pps->len > 0)
      gst_rtp_h264_set_src_caps (rtph264depay);
  }


712
713
714
  if (rtph264depay->merge) {
    gboolean start = FALSE, complete = FALSE;

715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
    /* marker bit isn't mandatory so in the following code we try to guess
     * an AU boundary by detecting a new picture start */
    if (!marker) {
      /* consider a coded slices (IDR or not) to start a picture,
       * (so ending the previous one) if first_mb_in_slice == 0
       * (non-0 is part of previous one) */
      /* NOTE this is not entirely according to Access Unit specs in 7.4.1.2.4,
       * but in practice it works in sane cases, needs not much parsing,
       * and also works with broken frame_num in NAL (where spec-wise would fail) */
      /* FIXME: this code isn't correct for interlaced content as AUs should be
       * constructed with pairs of fields and the guess here will just push out
       * AUs with a single field in it */
      if (nal_type == 1 || nal_type == 2 || nal_type == 5) {
        /* we have a picture start */
        start = TRUE;
        if (map.data[5] & 0x80) {
          /* first_mb_in_slice == 0 completes a picture */
          complete = TRUE;
        }
      } else if (nal_type >= 6 && nal_type <= 9) {
        /* SEI, SPS, PPS, AU terminate picture */
736
        complete = TRUE;
737
      }
738
      GST_DEBUG_OBJECT (depayload, "start %d, complete %d", start, complete);
739

740
741
742
743
      if (complete && rtph264depay->picture_start)
        outbuf = gst_rtp_h264_complete_au (rtph264depay, &out_timestamp,
            &out_keyframe);
    }
744
    /* add to adapter */
Wim Taymans's avatar
Wim Taymans committed
745
746
    gst_buffer_unmap (nal, &map);

747
748
749
    GST_DEBUG_OBJECT (depayload, "adding NAL to picture adapter");
    gst_adapter_push (rtph264depay->picture_adapter, nal);
    rtph264depay->last_ts = in_timestamp;
750
    rtph264depay->last_keyframe |= keyframe;
751
    rtph264depay->picture_start |= start;
752
753
754
755

    if (marker)
      outbuf = gst_rtp_h264_complete_au (rtph264depay, &out_timestamp,
          &out_keyframe);
756
757
758
759
  } else {
    /* no merge, output is input nal */
    GST_DEBUG_OBJECT (depayload, "using NAL as output");
    outbuf = nal;
Wim Taymans's avatar
Wim Taymans committed
760
    gst_buffer_unmap (nal, &map);
761
  }
762

763
764
765
766
  if (outbuf) {
    /* prepend codec_data */
    if (rtph264depay->codec_data) {
      GST_DEBUG_OBJECT (depayload, "prepending codec_data");
Wim Taymans's avatar
Wim Taymans committed
767
      outbuf = gst_buffer_append (rtph264depay->codec_data, outbuf);
768
      rtph264depay->codec_data = NULL;
769
      out_keyframe = TRUE;
770
    }
Wim Taymans's avatar
Wim Taymans committed
771
    outbuf = gst_buffer_make_writable (outbuf);
772

773
    GST_BUFFER_TIMESTAMP (outbuf) = out_timestamp;
774

775
    if (out_keyframe)
776
      GST_BUFFER_FLAG_UNSET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
777
778
    else
      GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
779
780
  }

781
  return outbuf;
782

783
784
785
786
  /* ERRORS */
short_nal:
  {
    GST_WARNING_OBJECT (depayload, "dropping short NAL");
Wim Taymans's avatar
Wim Taymans committed
787
    gst_buffer_unmap (nal, &map);
788
    gst_buffer_unref (nal);
789
    return NULL;
790
  }
791
792
}

793
794
795
static GstBuffer *
gst_rtp_h264_push_fragmentation_unit (GstRtpH264Depay * rtph264depay,
    gboolean send)
796
797
{
  guint outsize;
Wim Taymans's avatar
Wim Taymans committed
798
  GstMapInfo map;
799
800
801
802
803
  GstBuffer *outbuf;

  outsize = gst_adapter_available (rtph264depay->adapter);
  outbuf = gst_adapter_take_buffer (rtph264depay->adapter, outsize);

Wim Taymans's avatar
Wim Taymans committed
804
  gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
805
806
807
  GST_DEBUG_OBJECT (rtph264depay, "output %d bytes", outsize);

  if (rtph264depay->byte_stream) {
Wim Taymans's avatar
Wim Taymans committed
808
    memcpy (map.data, sync_bytes, sizeof (sync_bytes));
809
810
  } else {
    outsize -= 4;
Wim Taymans's avatar
Wim Taymans committed
811
812
813
814
    map.data[0] = (outsize >> 24);
    map.data[1] = (outsize >> 16);
    map.data[2] = (outsize >> 8);
    map.data[3] = (outsize);
815
  }
Wim Taymans's avatar
Wim Taymans committed
816
  gst_buffer_unmap (outbuf, &map);
817
818

  rtph264depay->current_fu_type = 0;
819

Wim Taymans's avatar
Wim Taymans committed
820
821
822
823
824
825
  outbuf = gst_rtp_h264_depay_handle_nal (rtph264depay, outbuf,
      rtph264depay->fu_timestamp, rtph264depay->fu_marker);

  if (send && outbuf) {
    gst_rtp_base_depayload_push (GST_RTP_BASE_DEPAYLOAD (rtph264depay), outbuf);
    outbuf = NULL;
826
  }
Wim Taymans's avatar
Wim Taymans committed
827
  return outbuf;
828
829
}

830
static GstBuffer *
Wim Taymans's avatar
Wim Taymans committed
831
gst_rtp_h264_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
832
833
{
  GstRtpH264Depay *rtph264depay;
834
  GstBuffer *outbuf = NULL;
835
  guint8 nal_unit_type;
Wim Taymans's avatar
Wim Taymans committed
836
  GstRTPBuffer rtp = { NULL };
837
838
839

  rtph264depay = GST_RTP_H264_DEPAY (depayload);

840
841
842
843
  /* flush remaining data on discont */
  if (GST_BUFFER_IS_DISCONT (buf)) {
    gst_adapter_clear (rtph264depay->adapter);
    rtph264depay->wait_start = TRUE;
844
    rtph264depay->current_fu_type = 0;
845
846
  }

847
848
849
850
  {
    gint payload_len;
    guint8 *payload;
    guint header_len;
851
    guint8 nal_ref_idc;
Wim Taymans's avatar
Wim Taymans committed
852
    GstMapInfo map;
853
    guint outsize, nalu_size;
854
    GstClockTime timestamp;
855
    gboolean marker;
856

857
    timestamp = GST_BUFFER_TIMESTAMP (buf);
858

Wim Taymans's avatar
Wim Taymans committed
859
860
861
862
    gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);

    payload_len = gst_rtp_buffer_get_payload_len (&rtp);
    payload = gst_rtp_buffer_get_payload (&rtp);
Wim Taymans's avatar
Wim Taymans committed
863
    marker = gst_rtp_buffer_get_marker (&rtp);
864

865
866
    GST_DEBUG_OBJECT (rtph264depay, "receiving %d bytes", payload_len);

867
    if (payload_len == 0)
Wim Taymans's avatar
Wim Taymans committed
868
      goto empty_packet;
869

870
871
872
873
874
875
876
877
878
879
880
    /* +---------------+
     * |0|1|2|3|4|5|6|7|
     * +-+-+-+-+-+-+-+-+
     * |F|NRI|  Type   |
     * +---------------+
     *
     * F must be 0.
     */
    nal_ref_idc = (payload[0] & 0x60) >> 5;
    nal_unit_type = payload[0] & 0x1f;

881
882
883
    /* at least one byte header with type */
    header_len = 1;

884
885
886
    GST_DEBUG_OBJECT (rtph264depay, "NRI %d, Type %d", nal_ref_idc,
        nal_unit_type);

887
888
889
890
891
    /* If FU unit was being processed, but the current nal is of a different
     * type.  Assume that the remote payloader is buggy (didn't set the end bit
     * when the FU ended) and send out what we gathered thusfar */
    if (G_UNLIKELY (rtph264depay->current_fu_type != 0 &&
            nal_unit_type != rtph264depay->current_fu_type))
892
      gst_rtp_h264_push_fragmentation_unit (rtph264depay, TRUE);
893

894
895
896
897
898
899
900
901
    switch (nal_unit_type) {
      case 0:
      case 30:
      case 31:
        /* undefined */
        goto undefined_type;
      case 25:
        /* STAP-B    Single-time aggregation packet     5.7.1 */
902
903
904
905
906
907
908
909
910
        /* 2 byte extra header for DON */
        header_len += 2;
        /* fallthrough */
      case 24:
      {
        /* strip headers */
        payload += header_len;
        payload_len -= header_len;

911
912
        rtph264depay->wait_start = FALSE;

913

914
915
916
917
918
919
920
921
922
923
        /* STAP-A    Single-time aggregation packet     5.7.1 */
        while (payload_len > 2) {
          /*                      1          
           *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 
           * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
           * |         NALU Size             |
           * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
           */
          nalu_size = (payload[0] << 8) | payload[1];

924
925
926
          /* dont include nalu_size */
          if (nalu_size > (payload_len - 2))
            nalu_size = payload_len - 2;
927
928
929

          outsize = nalu_size + sizeof (sync_bytes);
          outbuf = gst_buffer_new_and_alloc (outsize);
Wim Taymans's avatar
Wim Taymans committed
930

Wim Taymans's avatar
Wim Taymans committed
931
          gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
932
          if (rtph264depay->byte_stream) {
Wim Taymans's avatar
Wim Taymans committed
933
            memcpy (map.data, sync_bytes, sizeof (sync_bytes));
934
          } else {
Wim Taymans's avatar
Wim Taymans committed
935
936
937
            map.data[0] = map.data[1] = 0;
            map.data[2] = payload[0];
            map.data[3] = payload[1];
938
939
940
941
942
943
          }

          /* strip NALU size */
          payload += 2;
          payload_len -= 2;

Wim Taymans's avatar
Wim Taymans committed
944
945
          memcpy (map.data + sizeof (sync_bytes), payload, nalu_size);
          gst_buffer_unmap (outbuf, &map);
946

947
          gst_adapter_push (rtph264depay->adapter, outbuf);
948
949
950
951
952

          payload += nalu_size;
          payload_len -= nalu_size;
        }

953
954
        outsize = gst_adapter_available (rtph264depay->adapter);
        outbuf = gst_adapter_take_buffer (rtph264depay->adapter, outsize);
955

956
957
        outbuf = gst_rtp_h264_depay_handle_nal (rtph264depay, outbuf, timestamp,
            marker);
958
        break;
959
      }
960
961
      case 26:
        /* MTAP16    Multi-time aggregation packet      5.7.2 */
962
        header_len = 5;
963
        /* fallthrough, not implemented */
964
965
      case 27:
        /* MTAP24    Multi-time aggregation packet      5.7.2 */
966
        header_len = 6;
967
        goto not_implemented;
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
        break;
      case 28:
      case 29:
      {
        /* FU-A      Fragmentation unit                 5.8 */
        /* FU-B      Fragmentation unit                 5.8 */
        gboolean S, E;

        /* +---------------+
         * |0|1|2|3|4|5|6|7|
         * +-+-+-+-+-+-+-+-+
         * |S|E|R|  Type   |
         * +---------------+
         *
         * R is reserved and always 0
         */
        S = (payload[1] & 0x80) == 0x80;
        E = (payload[1] & 0x40) == 0x40;

        GST_DEBUG_OBJECT (rtph264depay, "S %d, E %d", S, E);

989
990
991
        if (rtph264depay->wait_start && !S)
          goto waiting_start;

992
993
        if (S) {
          /* NAL unit starts here */
994
          guint8 nal_header;
995

996
997
998
999
          /* If a new FU unit started, while still processing an older one.
           * Assume that the remote payloader is buggy (doesn't set the end
           * bit) and send out what we've gathered thusfar */
          if (G_UNLIKELY (rtph264depay->current_fu_type != 0))
1000
            gst_rtp_h264_push_fragmentation_unit (rtph264depay, TRUE);
1001
1002
1003
1004

          rtph264depay->current_fu_type = nal_unit_type;
          rtph264depay->fu_timestamp = timestamp;

1005
1006
          rtph264depay->wait_start = FALSE;

1007
1008
1009
1010
1011
1012
1013
          /* reconstruct NAL header */
          nal_header = (payload[0] & 0xe0) | (payload[1] & 0x1f);

          /* strip type header, keep FU header, we'll reuse it to reconstruct
           * the NAL header. */
          payload += 1;
          payload_len -= 1;
1014

1015
1016
1017
          nalu_size = payload_len;
          outsize = nalu_size + sizeof (sync_bytes);
          outbuf = gst_buffer_new_and_alloc (outsize);
Wim Taymans's avatar
Wim Taymans committed
1018

Wim Taymans's avatar
Wim Taymans committed
1019
1020
1021
1022
          gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
          memcpy (map.data + sizeof (sync_bytes), payload, nalu_size);
          map.data[sizeof (sync_bytes)] = nal_header;
          gst_buffer_unmap (outbuf, &map);
1023
1024

          GST_DEBUG_OBJECT (rtph264depay, "queueing %d bytes", outsize);
1025
1026
1027
1028

          /* and assemble in the adapter */
          gst_adapter_push (rtph264depay->adapter, outbuf);
        } else {
1029
1030
1031
          /* strip off FU indicator and FU header bytes */
          payload += 2;
          payload_len -= 2;
1032

1033
          outsize = payload_len;
1034
          outbuf = gst_buffer_new_and_alloc (outsize);
Wim Taymans's avatar
Wim Taymans committed
1035
          gst_buffer_fill (outbuf, 0, payload, outsize);
1036
1037

          GST_DEBUG_OBJECT (rtph264depay, "queueing %d bytes", outsize);
1038
1039
1040
1041
1042

          /* and assemble in the adapter */
          gst_adapter_push (rtph264depay->adapter, outbuf);
        }

1043
        outbuf = NULL;
1044
        rtph264depay->fu_marker = marker;
Wim Taymans's avatar
Wim Taymans committed
1045

1046
1047
        /* if NAL unit ends, flush the adapter */
        if (E)
1048
          outbuf = gst_rtp_h264_push_fragmentation_unit (rtph264depay, FALSE);
1049
1050
1051
1052
        break;
      }
      default:
      {
1053
1054
        rtph264depay->wait_start = FALSE;

1055
1056
        /* 1-23   NAL unit  Single NAL unit packet per H.264   5.6 */
        /* the entire payload is the output buffer */
1057
1058
        nalu_size = payload_len;
        outsize = nalu_size + sizeof (sync_bytes);
1059
        outbuf = gst_buffer_new_and_alloc (outsize);
Wim Taymans's avatar
Wim Taymans committed
1060

Wim Taymans's avatar
Wim Taymans committed
1061
        gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
1062
        if (rtph264depay->byte_stream) {
Wim Taymans's avatar
Wim Taymans committed
1063
          memcpy (map.data, sync_bytes, sizeof (sync_bytes));
1064
        } else {
Wim Taymans's avatar
Wim Taymans committed
1065
1066
1067
          map.data[0] = map.data[1] = 0;
          map.data[2] = nalu_size >> 8;
          map.data[3] = nalu_size & 0xff;
1068
        }
Wim Taymans's avatar
Wim Taymans committed
1069
1070
        memcpy (map.data + sizeof (sync_bytes), payload, nalu_size);
        gst_buffer_unmap (outbuf, &map);
1071

1072
1073
        outbuf = gst_rtp_h264_depay_handle_nal (rtph264depay, outbuf, timestamp,
            marker);
1074
        break;
1075
1076
      }
    }
Wim Taymans's avatar
Wim Taymans committed
1077
    gst_rtp_buffer_unmap (&rtp);
1078
1079
  }

1080
  return outbuf;
1081
1082

  /* ERRORS */
Wim Taymans's avatar
Wim Taymans committed
1083
1084
1085
1086
1087
1088
empty_packet:
  {
    GST_DEBUG_OBJECT (rtph264depay, "empty packet");
    gst_rtp_buffer_unmap (&rtp);
    return NULL;
  }
1089
1090
1091
undefined_type:
  {
    GST_ELEMENT_WARNING (rtph264depay, STREAM, DECODE,
1092
        (NULL), ("Undefined packet type"));
Wim Taymans's avatar
Wim Taymans committed
1093
    gst_rtp_buffer_unmap (&rtp);
1094
1095
    return NULL;
  }
1096
1097
1098
waiting_start:
  {
    GST_DEBUG_OBJECT (rtph264depay, "waiting for start");
Wim Taymans's avatar
Wim Taymans committed
1099
    gst_rtp_buffer_unmap (&rtp);
1100
1101
    return NULL;
  }
1102
1103
1104
not_implemented:
  {
    GST_ELEMENT_ERROR (rtph264depay, STREAM, FORMAT,
1105
        (NULL), ("NAL unit type %d not supported yet", nal_unit_type));
Wim Taymans's avatar
Wim Taymans committed
1106
    gst_rtp_buffer_unmap (&rtp);
1107
1108
    return NULL;
  }
1109
1110
}

1111
static gboolean
Wim Taymans's avatar
Wim Taymans committed
1112
gst_rtp_h264_depay_handle_event (GstRTPBaseDepayload * depay, GstEvent * event)
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
{
  GstRtpH264Depay *rtph264depay;

  rtph264depay = GST_RTP_H264_DEPAY (depay);

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_FLUSH_STOP:
      gst_rtp_h264_depay_reset (rtph264depay);
      break;
    default:
      break;
  }

  return
Wim Taymans's avatar
Wim Taymans committed
1127
      GST_RTP_BASE_DEPAYLOAD_CLASS (parent_class)->handle_event (depay, event);
1128
1129
}

1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
static GstStateChangeReturn
gst_rtp_h264_depay_change_state (GstElement * element,
    GstStateChange transition)
{
  GstRtpH264Depay *rtph264depay;
  GstStateChangeReturn ret;

  rtph264depay = GST_RTP_H264_DEPAY (element);

  switch (transition) {
    case GST_STATE_CHANGE_NULL_TO_READY:
      break;
    case GST_STATE_CHANGE_READY_TO_PAUSED:
1143
      gst_rtp_h264_depay_reset (rtph264depay);
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
      break;
    default:
      break;
  }

  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);

  switch (transition) {
    case GST_STATE_CHANGE_READY_TO_NULL:
      break;
    default:
      break;
  }
  return ret;
}

gboolean
gst_rtp_h264_depay_plugin_init (GstPlugin * plugin)
{
1163
1164
1165
  GST_DEBUG_CATEGORY_INIT (rtph264depay_debug, "rtph264depay", 0,
      "H264 Video RTP Depayloader");

1166
  return gst_element_register (plugin, "rtph264depay",
1167
      GST_RANK_SECONDARY, GST_TYPE_RTP_H264_DEPAY);
1168
}