gstrtph264depay.c 38.2 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
#include <gst/rtp/gstrtpbuffer.h>
29
#include <gst/pbutils/pbutils.h>
30
#include <gst/video/video.h>
31
#include "gstrtph264depay.h"
32
#include "gstrtputils.h"
33

34 35 36
GST_DEBUG_CATEGORY_STATIC (rtph264depay_debug);
#define GST_CAT_DEFAULT (rtph264depay_debug)

37 38 39 40
/* 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
41

42 43
/* 3 zero bytes syncword */
static const guint8 sync_bytes[] = { 0, 0, 0, 1 };
44

45
static GstStaticPadTemplate gst_rtp_h264_depay_src_template =
46
    GST_STATIC_PAD_TEMPLATE ("src",
47 48
    GST_PAD_SRC,
    GST_PAD_ALWAYS,
49 50 51 52
    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 }")
53 54 55 56 57 58 59 60
    );

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\", "
61
        "clock-rate = (int) 90000, " "encoding-name = (string) \"H264\"")
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
        /** 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, " */
78
    /* "max-rcmd-nalu-size = (string) ANY " */
79 80
    );

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

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
90
static GstBuffer *gst_rtp_h264_depay_process (GstRTPBaseDepayload * depayload,
91
    GstRTPBuffer * rtp);
Wim Taymans's avatar
Wim Taymans committed
92
static gboolean gst_rtp_h264_depay_setcaps (GstRTPBaseDepayload * filter,
93
    GstCaps * caps);
Wim Taymans's avatar
Wim Taymans committed
94
static gboolean gst_rtp_h264_depay_handle_event (GstRTPBaseDepayload * depay,
95
    GstEvent * event);
96 97 98 99 100 101

static void
gst_rtp_h264_depay_class_init (GstRtpH264DepayClass * klass)
{
  GObjectClass *gobject_class;
  GstElementClass *gstelement_class;
Wim Taymans's avatar
Wim Taymans committed
102
  GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
103 104 105

  gobject_class = (GObjectClass *) klass;
  gstelement_class = (GstElementClass *) klass;
Wim Taymans's avatar
Wim Taymans committed
106
  gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
107 108 109

  gobject_class->finalize = gst_rtp_h264_depay_finalize;

110 111 112 113
  gst_element_class_add_static_pad_template (gstelement_class,
      &gst_rtp_h264_depay_src_template);
  gst_element_class_add_static_pad_template (gstelement_class,
      &gst_rtp_h264_depay_sink_template);
Wim Taymans's avatar
Wim Taymans committed
114

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

121
  gstrtpbasedepayload_class->process_rtp_packet = gst_rtp_h264_depay_process;
Wim Taymans's avatar
Wim Taymans committed
122 123
  gstrtpbasedepayload_class->set_caps = gst_rtp_h264_depay_setcaps;
  gstrtpbasedepayload_class->handle_event = gst_rtp_h264_depay_handle_event;
124 125 126
}

static void
Wim Taymans's avatar
Wim Taymans committed
127
gst_rtp_h264_depay_init (GstRtpH264Depay * rtph264depay)
128 129
{
  rtph264depay->adapter = gst_adapter_new ();
130
  rtph264depay->picture_adapter = gst_adapter_new ();
131
  rtph264depay->byte_stream = DEFAULT_BYTE_STREAM;
132
  rtph264depay->merge = DEFAULT_ACCESS_UNIT;
133 134 135 136
  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);
137 138
}

139 140 141 142 143 144 145 146 147
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;
148
  rtph264depay->current_fu_type = 0;
149 150 151
  rtph264depay->new_codec_data = FALSE;
  g_ptr_array_set_size (rtph264depay->sps, 0);
  g_ptr_array_set_size (rtph264depay->pps, 0);
152 153
}

154 155 156 157 158 159 160
static void
gst_rtp_h264_depay_finalize (GObject * object)
{
  GstRtpH264Depay *rtph264depay;

  rtph264depay = GST_RTP_H264_DEPAY (object);

161 162 163
  if (rtph264depay->codec_data)
    gst_buffer_unref (rtph264depay->codec_data);

164
  g_object_unref (rtph264depay->adapter);
165
  g_object_unref (rtph264depay->picture_adapter);
166

167 168 169
  g_ptr_array_free (rtph264depay->sps, TRUE);
  g_ptr_array_free (rtph264depay->pps, TRUE);

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

173 174 175 176 177 178 179 180
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
181
      gst_pad_get_allowed_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (rtph264depay));
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 210 211 212

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

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

232 233 234 235 236 237 238 239 240
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;

241
  if (!gst_rtp_read_golomb (&br, sps_id))
242 243 244 245 246 247 248 249 250 251 252 253 254 255
    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;

256
  if (!gst_rtp_read_golomb (&br, pps_id))
257
    return FALSE;
258
  if (!gst_rtp_read_golomb (&br, sps_id))
259 260 261 262 263 264 265 266 267 268
    return FALSE;

  return TRUE;
}


static gboolean
gst_rtp_h264_set_src_caps (GstRtpH264Depay * rtph264depay)
{
  gboolean res;
269
  GstCaps *srccaps;
270
  GstCaps *old_caps;
271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289

  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;
290 291
    guchar level = 0;
    guchar profile_compat = G_MAXUINT8;
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

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

338 339
      GST_DEBUG_OBJECT (rtph264depay, "copy SPS %d of length %u", i,
          (guint) nalmap.size);
340 341 342 343 344 345 346 347 348 349 350 351 352 353
      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);

354 355
      GST_DEBUG_OBJECT (rtph264depay, "copy PPS %d of length %u", i,
          (guint) nalmap.size);
356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371
      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);
  }

372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399
  /* Set profile a level from SPS */
  {
    gint i;
    GstBuffer *max_level_sps = NULL;
    gint level = 0;
    GstMapInfo nalmap;

    /* Get the SPS with the highest level. We assume
     * all SPS have the same profile */
    for (i = 0; i < rtph264depay->sps->len; i++) {
      gst_buffer_map (g_ptr_array_index (rtph264depay->sps, i), &nalmap,
          GST_MAP_READ);
      if (level == 0 || level < nalmap.data[3]) {
        max_level_sps = g_ptr_array_index (rtph264depay->sps, i);
        level = nalmap.data[3];
      }
      gst_buffer_unmap (g_ptr_array_index (rtph264depay->sps, i), &nalmap);
    }

    if (max_level_sps) {
      gst_buffer_map (max_level_sps, &nalmap, GST_MAP_READ);
      gst_codec_utils_h264_caps_set_level_and_profile (srccaps, nalmap.data + 1,
          nalmap.size - 1);
      gst_buffer_unmap (max_level_sps, &nalmap);
    }
  }


400 401
  old_caps =
      gst_pad_get_current_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (rtph264depay));
402

403
  if (old_caps != NULL) {
404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433
    /* Only update the caps if they are not equal. For
     * AVC we don't update caps if only the codec_data
     * changes. This is the same behaviour as in h264parse
     */
    if (rtph264depay->byte_stream) {
      if (!gst_caps_is_equal (srccaps, old_caps))
        res =
            gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (rtph264depay),
            srccaps);
      else
        res = TRUE;
    } else {
      GstCaps *tmp_caps = gst_caps_copy (srccaps);
      GstStructure *old_s, *tmp_s;

      old_s = gst_caps_get_structure (old_caps, 0);
      tmp_s = gst_caps_get_structure (tmp_caps, 0);
      if (gst_structure_has_field (old_s, "codec_data"))
        gst_structure_set_value (tmp_s, "codec_data",
            gst_structure_get_value (old_s, "codec_data"));

      if (!gst_caps_is_equal (old_caps, tmp_caps))
        res =
            gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (rtph264depay),
            srccaps);
      else
        res = TRUE;

      gst_caps_unref (tmp_caps);
    }
434
    gst_caps_unref (old_caps);
435 436 437 438 439 440
  } else {
    res =
        gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (rtph264depay),
        srccaps);
  }

441 442
  gst_caps_unref (srccaps);

443 444 445
  /* Insert SPS and PPS into the stream on next opportunity (if bytestream) */
  if (rtph264depay->byte_stream
      && (rtph264depay->sps->len > 0 || rtph264depay->pps->len > 0)) {
446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493
    gint i;
    GstBuffer *codec_data;
    GstMapInfo map;
    guint8 *data;
    guint len = 0;

    for (i = 0; i < rtph264depay->sps->len; i++) {
      len += 4 + gst_buffer_get_size (g_ptr_array_index (rtph264depay->sps, i));
    }

    for (i = 0; i < rtph264depay->pps->len; i++) {
      len += 4 + gst_buffer_get_size (g_ptr_array_index (rtph264depay->pps, i));
    }

    codec_data = gst_buffer_new_and_alloc (len);
    gst_buffer_map (codec_data, &map, GST_MAP_WRITE);
    data = map.data;

    for (i = 0; i < rtph264depay->sps->len; i++) {
      GstBuffer *sps_buf = g_ptr_array_index (rtph264depay->sps, i);
      guint sps_size = gst_buffer_get_size (sps_buf);

      if (rtph264depay->byte_stream)
        memcpy (data, sync_bytes, sizeof (sync_bytes));
      else
        GST_WRITE_UINT32_BE (data, sps_size);
      gst_buffer_extract (sps_buf, 0, data + 4, -1);
      data += 4 + sps_size;
    }

    for (i = 0; i < rtph264depay->pps->len; i++) {
      GstBuffer *pps_buf = g_ptr_array_index (rtph264depay->pps, i);
      guint pps_size = gst_buffer_get_size (pps_buf);

      if (rtph264depay->byte_stream)
        memcpy (data, sync_bytes, sizeof (sync_bytes));
      else
        GST_WRITE_UINT32_BE (data, pps_size);
      gst_buffer_extract (pps_buf, 0, data + 4, -1);
      data += 4 + pps_size;
    }

    gst_buffer_unmap (codec_data, &map);
    if (rtph264depay->codec_data)
      gst_buffer_unref (rtph264depay->codec_data);
    rtph264depay->codec_data = codec_data;
  }

494 495 496 497 498 499
  if (res)
    rtph264depay->new_codec_data = FALSE;

  return res;
}

500 501 502
gboolean
gst_rtp_h264_add_sps_pps (GstElement * rtph264, GPtrArray * sps_array,
    GPtrArray * pps_array, GstBuffer * nal)
503 504 505 506 507 508 509 510 511 512 513 514 515
{
  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)) {
516
      GST_WARNING_OBJECT (rtph264, "Invalid SPS,"
517 518 519 520
          " can't parse seq_parameter_set_id");
      goto drop;
    }

521 522
    for (i = 0; i < sps_array->len; i++) {
      GstBuffer *sps = g_ptr_array_index (sps_array, i);
523 524 525 526 527 528 529 530 531
      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) {
532
          GST_LOG_OBJECT (rtph264, "Unchanged SPS %u, not updating", sps_id);
533 534 535 536
          gst_buffer_unmap (sps, &spsmap);
          goto drop;
        } else {
          gst_buffer_unmap (sps, &spsmap);
537 538 539
          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);
540 541 542 543 544
          goto done;
        }
      }
      gst_buffer_unmap (sps, &spsmap);
    }
545 546
    GST_LOG_OBJECT (rtph264, "Adding new SPS %u", sps_id);
    g_ptr_array_add (sps_array, nal);
547 548 549 550 551
  } else if (type == 8) {
    guint32 sps_id;
    guint32 pps_id;

    if (!parse_pps (&map, &sps_id, &pps_id)) {
552
      GST_WARNING_OBJECT (rtph264, "Invalid PPS,"
553 554 555 556
          " can't parse seq_parameter_set_id or pic_parameter_set_id");
      goto drop;
    }

557 558
    for (i = 0; i < pps_array->len; i++) {
      GstBuffer *pps = g_ptr_array_index (pps_array, i);
559 560 561 562 563 564 565 566
      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);

567
      if (pps_id == tmp_pps_id) {
568 569
        if (map.size == ppsmap.size &&
            memcmp (map.data, ppsmap.data, ppsmap.size) == 0) {
570 571
          GST_LOG_OBJECT (rtph264, "Unchanged PPS %u:%u, not updating", sps_id,
              pps_id);
572 573 574 575
          gst_buffer_unmap (pps, &ppsmap);
          goto drop;
        } else {
          gst_buffer_unmap (pps, &ppsmap);
576 577 578
          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",
579 580 581 582 583 584
              sps_id, pps_id);
          goto done;
        }
      }
      gst_buffer_unmap (pps, &ppsmap);
    }
585 586
    GST_LOG_OBJECT (rtph264, "Adding new PPS %u:%i", sps_id, pps_id);
    g_ptr_array_add (pps_array, nal);
587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602
  } else {
    goto drop;
  }

done:
  gst_buffer_unmap (nal, &map);

  return TRUE;

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

  return FALSE;
}

603 604 605 606 607 608 609 610 611

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

612 613 614
static gboolean
gst_rtp_h264_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
{
615
  gint clock_rate;
616
  GstStructure *structure = gst_caps_get_structure (caps, 0);
617
  GstRtpH264Depay *rtph264depay;
618
  const gchar *ps;
619
  GstBuffer *codec_data;
Wim Taymans's avatar
Wim Taymans committed
620 621
  GstMapInfo map;
  guint8 *ptr;
622 623

  rtph264depay = GST_RTP_H264_DEPAY (depayload);
624

625 626
  if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
    clock_rate = 90000;
627
  depayload->clock_rate = clock_rate;
628

629 630 631
  /* Base64 encoded, comma separated config NALs */
  ps = gst_structure_get_string (structure, "sprop-parameter-sets");

632 633 634
  /* negotiate with downstream w.r.t. output format and alignment */
  gst_rtp_h264_depay_negotiate (rtph264depay);

635 636 637
  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. */
638 639 640 641 642 643
    gchar **params;
    guint len, total;
    gint i;

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

644 645
    /* count total number of bytes in base64. Also include the sync bytes in
     * front of the params. */
646 647 648
    len = 0;
    for (i = 0; params[i]; i++) {
      len += strlen (params[i]);
649
      len += sizeof (sync_bytes);
650 651 652
    }
    /* we seriously overshoot the length, but it's fine. */
    codec_data = gst_buffer_new_and_alloc (len);
Wim Taymans's avatar
Wim Taymans committed
653

Wim Taymans's avatar
Wim Taymans committed
654 655
    gst_buffer_map (codec_data, &map, GST_MAP_WRITE);
    ptr = map.data;
656 657
    total = 0;
    for (i = 0; params[i]; i++) {
658 659 660
      guint save = 0;
      gint state = 0;

661
      GST_DEBUG_OBJECT (depayload, "decoding param %d (%s)", i, params[i]);
Wim Taymans's avatar
Wim Taymans committed
662 663
      memcpy (ptr, sync_bytes, sizeof (sync_bytes));
      ptr += sizeof (sync_bytes);
664
      len =
Wim Taymans's avatar
Wim Taymans committed
665
          g_base64_decode_step (params[i], strlen (params[i]), ptr, &state,
666 667
          &save);
      GST_DEBUG_OBJECT (depayload, "decoded %d bytes", len);
668
      total += len + sizeof (sync_bytes);
Wim Taymans's avatar
Wim Taymans committed
669
      ptr += len;
670
    }
Wim Taymans's avatar
Wim Taymans committed
671 672
    gst_buffer_unmap (codec_data, &map);
    gst_buffer_resize (codec_data, 0, total);
673
    g_strfreev (params);
674

675 676 677 678 679 680
    /* 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;
681 682 683 684
  } else if (!rtph264depay->byte_stream) {
    gchar **params;
    gint i;

685
    if (ps == NULL)
686 687 688 689
      goto incomplete_caps;

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

690
    GST_DEBUG_OBJECT (depayload, "we have %d params", g_strv_length (params));
691 692 693

    /* start with 7 bytes header */
    for (i = 0; params[i]; i++) {
694 695
      GstBuffer *nal;
      GstMapInfo nalmap;
696 697 698
      gsize nal_len;
      guint save = 0;
      gint state = 0;
699 700

      nal_len = strlen (params[i]);
701 702 703 704
      if (nal_len == 0) {
        GST_WARNING_OBJECT (depayload, "empty param '%s' (#%d)", params[i], i);
        continue;
      }
705 706
      nal = gst_buffer_new_and_alloc (nal_len);
      gst_buffer_map (nal, &nalmap, GST_MAP_READWRITE);
707 708

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

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

714 715
      gst_buffer_unmap (nal, &nalmap);
      gst_buffer_set_size (nal, nal_len);
716

717
      gst_rtp_h264_depay_add_sps_pps (rtph264depay, nal);
718
    }
719
    g_strfreev (params);
720

721 722
    if (rtph264depay->sps->len == 0 || rtph264depay->pps->len == 0)
      goto incomplete_caps;
723 724
  }

725
  return gst_rtp_h264_set_src_caps (rtph264depay);
726 727 728 729

  /* ERRORS */
incomplete_caps:
  {
730 731 732
    GST_DEBUG_OBJECT (depayload, "we have incomplete caps,"
        " doing setcaps later");
    return TRUE;
733
  }
734 735
}

736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756
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;
}

757 758 759
/* 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))
760

761
static GstBuffer *
762
gst_rtp_h264_depay_handle_nal (GstRtpH264Depay * rtph264depay, GstBuffer * nal,
763
    GstClockTime in_timestamp, gboolean marker)
764
{
Wim Taymans's avatar
Wim Taymans committed
765
  GstRTPBaseDepayload *depayload = GST_RTP_BASE_DEPAYLOAD (rtph264depay);
766
  gint nal_type;
Wim Taymans's avatar
Wim Taymans committed
767
  GstMapInfo map;
768
  GstBuffer *outbuf = NULL;
769
  GstClockTime out_timestamp;
770
  gboolean keyframe, out_keyframe;
771

Wim Taymans's avatar
Wim Taymans committed
772 773
  gst_buffer_map (nal, &map, GST_MAP_READ);
  if (G_UNLIKELY (map.size < 5))
774
    goto short_nal;
775

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

779
  keyframe = NAL_TYPE_IS_KEY (nal_type);
780

781
  out_keyframe = keyframe;
782 783
  out_timestamp = in_timestamp;

784 785
  if (!rtph264depay->byte_stream) {
    if (nal_type == 7 || nal_type == 8) {
786
      gst_rtp_h264_depay_add_sps_pps (rtph264depay,
787 788 789 790 791 792 793 794 795 796 797 798 799 800 801
          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
802
      return NULL;
803 804 805 806 807 808 809 810
    }

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


811 812 813
  if (rtph264depay->merge) {
    gboolean start = FALSE, complete = FALSE;

814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834
    /* 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 */
835
        complete = TRUE;
836
      }
837
      GST_DEBUG_OBJECT (depayload, "start %d, complete %d", start, complete);
838

839 840 841 842
      if (complete && rtph264depay->picture_start)
        outbuf = gst_rtp_h264_complete_au (rtph264depay, &out_timestamp,
            &out_keyframe);
    }
843
    /* add to adapter */
Wim Taymans's avatar
Wim Taymans committed
844 845
    gst_buffer_unmap (nal, &map);

846 847 848
    GST_DEBUG_OBJECT (depayload, "adding NAL to picture adapter");
    gst_adapter_push (rtph264depay->picture_adapter, nal);
    rtph264depay->last_ts = in_timestamp;
849
    rtph264depay->last_keyframe |= keyframe;
850
    rtph264depay->picture_start |= start;
851 852 853 854

    if (marker)
      outbuf = gst_rtp_h264_complete_au (rtph264depay, &out_timestamp,
          &out_keyframe);
855 856 857 858
  } else {
    /* no merge, output is input nal */
    GST_DEBUG_OBJECT (depayload, "using NAL as output");
    outbuf = nal;
Wim Taymans's avatar
Wim Taymans committed
859
    gst_buffer_unmap (nal, &map);
860
  }
861

862 863 864 865
  if (outbuf) {
    /* prepend codec_data */
    if (rtph264depay->codec_data) {
      GST_DEBUG_OBJECT (depayload, "prepending codec_data");
866
      gst_rtp_copy_video_meta (rtph264depay, rtph264depay->codec_data, outbuf);
Wim Taymans's avatar
Wim Taymans committed
867
      outbuf = gst_buffer_append (rtph264depay->codec_data, outbuf);
868
      rtph264depay->codec_data = NULL;
869
      out_keyframe = TRUE;
870
    }
Wim Taymans's avatar
Wim Taymans committed
871
    outbuf = gst_buffer_make_writable (outbuf);
872

873
    gst_rtp_drop_non_video_meta (rtph264depay, outbuf);
874

875
    GST_BUFFER_PTS (outbuf) = out_timestamp;
876

877
    if (out_keyframe)
878
      GST_BUFFER_FLAG_UNSET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
879 880
    else
      GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
881 882
  }

883
  return outbuf;
884

885 886 887 888
  /* ERRORS */
short_nal:
  {
    GST_WARNING_OBJECT (depayload, "dropping short NAL");
Wim Taymans's avatar
Wim Taymans committed
889
    gst_buffer_unmap (nal, &map);
890
    gst_buffer_unref (nal);
891
    return NULL;
892
  }
893 894
}

895 896 897
static GstBuffer *
gst_rtp_h264_push_fragmentation_unit (GstRtpH264Depay * rtph264depay,
    gboolean send)
898 899
{
  guint outsize;
Wim Taymans's avatar
Wim Taymans committed
900
  GstMapInfo map;
901 902 903 904 905
  GstBuffer *outbuf;

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

Wim Taymans's avatar
Wim Taymans committed
906
  gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
907 908 909
  GST_DEBUG_OBJECT (rtph264depay, "output %d bytes", outsize);

  if (rtph264depay->byte_stream) {
Wim Taymans's avatar
Wim Taymans committed
910
    memcpy (map.data, sync_bytes, sizeof (sync_bytes));
911 912
  } else {
    outsize -= 4;
Wim Taymans's avatar
Wim Taymans committed
913 914 915 916
    map.data[0] = (outsize >> 24);
    map.data[1] = (outsize >> 16);
    map.data[2] = (outsize >> 8);
    map.data[3] = (outsize);
917
  }
Wim Taymans's avatar
Wim Taymans committed
918
  gst_buffer_unmap (outbuf, &map);
919 920

  rtph264depay->current_fu_type = 0;
921

Wim Taymans's avatar
Wim Taymans committed
922 923 924 925 926 927
  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;
928
  }
Wim Taymans's avatar
Wim Taymans committed
929
  return outbuf;
930 931
}

932
static GstBuffer *
933
gst_rtp_h264_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
934 935
{
  GstRtpH264Depay *rtph264depay;
936
  GstBuffer *outbuf = NULL;
937
  guint8 nal_unit_type;
938 939 940

  rtph264depay = GST_RTP_H264_DEPAY (depayload);

941
  /* flush remaining data on discont */
942
  if (GST_BUFFER_IS_DISCONT (rtp->buffer)) {
943 944
    gst_adapter_clear (rtph264depay->adapter);
    rtph264depay->wait_start = TRUE;
945
    rtph264depay->current_fu_type = 0;
946 947
  }

948 949 950 951
  {
    gint payload_len;
    guint8 *payload;
    guint header_len;
952
    guint8 nal_ref_idc;
Wim Taymans's avatar
Wim Taymans committed
953
    GstMapInfo map;
954
    guint outsize, nalu_size;
955
    GstClockTime timestamp;
956
    gboolean marker;
957

958
    timestamp = GST_BUFFER_PTS (rtp->buffer);
959

960 961 962
    payload_len = gst_rtp_buffer_get_payload_len (rtp);
    payload = gst_rtp_buffer_get_payload (rtp);
    marker = gst_rtp_buffer_get_marker (rtp);
963

964 965
    GST_DEBUG_OBJECT (rtph264depay, "receiving %d bytes", payload_len);

966
    if (payload_len == 0)
Wim Taymans's avatar
Wim Taymans committed
967
      goto empty_packet;
968

969 970 971 972 973 974 975 976 977 978 979
    /* +---------------+
     * |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;

980 981 982
    /* at least one byte header with type */
    header_len = 1;

983 984 985
    GST_DEBUG_OBJECT (rtph264depay, "NRI %d, Type %d", nal_ref_idc,
        nal_unit_type);

986 987 988 989 990
    /* 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))
991
      gst_rtp_h264_push_fragmentation_unit (rtph264depay, TRUE);
992

993 994 995 996 997 998 999 1000
    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 */
1001 1002 1003 1004 1005 1006 1007 1008 1009
        /* 2 byte extra header for DON */
        header_len += 2;
        /* fallthrough */
      case 24:
      {
        /* strip headers */
        payload += header_len;
        payload_len -= header_len;

1010 1011
        rtph264depay->wait_start = FALSE;

1012

1013 1014
        /* STAP-A    Single-time aggregation packet     5.7.1 */
        while (payload_len > 2) {
1015 1016
          /*                      1
           *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
1017 1018 1019 1020 1021 1022
           * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
           * |         NALU Size             |
           * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
           */
          nalu_size = (payload[0] << 8) | payload[1];

1023 1024 1025
          /* dont include nalu_size */
          if (nalu_size > (payload_len - 2))
            nalu_size = payload_len - 2;
1026 1027 1028

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

Wim Taymans's avatar
Wim Taymans committed
1030
          gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
1031
          if (rtph264depay->byte_stream) {
Wim Taymans's avatar
Wim Taymans committed
1032
            memcpy (map.data, sync_bytes, sizeof (sync_bytes));
1033
          } else {
Wim Taymans's avatar
Wim Taymans committed
1034 1035 1036
            map.data[0] = map.data[1] = 0;
            map.data[2] = payload[0];
            map.data[3] = payload[1];
1037 1038 1039 1040 1041 1042
          }

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

Wim Taymans's avatar
Wim Taymans committed
1043 1044
          memcpy (map.data + sizeof (sync_bytes), payload, nalu_size);
          gst_buffer_unmap (outbuf, &map);
1045

1046
          gst_rtp_copy_video_meta (rtph264depay, outbuf, rtp->buffer);
1047

1048 1049 1050 1051 1052
          outbuf =
              gst_rtp_h264_depay_handle_nal (rtph264depay, outbuf, timestamp,
              marker);
          if (outbuf)
            gst_adapter_push (rtph264depay->adapter, outbuf);
1053 1054 1055 1056 1057

          payload += nalu_size;
          payload_len -= nalu_size;
        }

1058
        outsize = gst_adapter_available (rtph264depay->adapter);
1059
        if (outsize > 0)
1060
          outbuf = gst_adapter_take_buffer (rtph264depay->adapter, outsize);
1061
        break;
1062
      }
1063 1064
      case 26:
        /* MTAP16    Multi-time aggregation packet      5.7.2 */
1065
        // header_len = 5;
1066
        /* fallthrough, not implemented */
1067 1068
      case 27:
        /* MTAP24    Multi-time aggregation packet      5.7.2 */
1069
        // header_len = 6;
1070
        goto not_implemented;
1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091
        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);

1092 1093 1094
        if (rtph264depay->wait_start && !S)
          goto waiting_start;

1095 1096
        if (S) {
          /* NAL unit starts here */
1097
          guint8 nal_header;
1098

1099 1100 1101 1102
          /* 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))
1103
            gst_rtp_h264_push_fragmentation_unit (rtph264depay, TRUE);
1104 1105 1106 1107

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

1108 1109
          rtph264depay->wait_start = FALSE;

1110 1111 1112 1113 1114 1115 1116
          /* 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;
1117

1118 1119 1120
          nalu_size = payload_len;
          outsize = nalu_size + sizeof (sync_bytes);
          outbuf = gst_buffer_new_and_alloc (outsize);
Wim Taymans's avatar
Wim Taymans committed
1121

Wim Taymans's avatar
Wim Taymans committed
1122 1123 1124 1125
          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);
1126

1127
          gst_rtp_copy_video_meta (rtph264depay, outbuf, rtp->buffer);
1128

1129
          GST_DEBUG_OBJECT (rtph264depay, "queueing %d bytes", outsize);
1130 1131 1132 1133

          /* and assemble in the adapter */
          gst_adapter_push (rtph264depay->adapter, outbuf);
        } else {
1134 1135 1136
          /* strip off FU indicator and FU header bytes */
          payload += 2;
          payload_len -= 2;
1137

1138
          outsize = payload_len;
1139
          outbuf = gst_buffer_new_and_alloc (outsize);
Wim Taymans's avatar
Wim Taymans committed
1140
          gst_buffer_fill (outbuf, 0, payload, outsize);
1141

1142
          gst_rtp_copy_video_meta (rtph264depay, outbuf, rtp->buffer);
1143

1144
          GST_DEBUG_OBJECT (rtph264depay, "queueing %d bytes", outsize);
1145 1146 1147 1148 1149

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

1150
        outbuf = NULL;
1151
        rtph264depay->fu_marker = marker;
Wim Taymans's avatar
Wim Taymans committed
1152

1153 1154
        /* if NAL unit ends, flush the adapter */
        if (E)
1155
          outbuf = gst_rtp_h264_push_fragmentation_unit (rtph264depay, FALSE);
1156 1157 1158 1159
        break;
      }
      default:
      {
1160 1161
        rtph264depay->wait_start = FALSE;

1162 1163
        /* 1-23   NAL unit  Single NAL unit packet per H.264   5.6 */
        /* the entire payload is the output buffer */
1164 1165
        nalu_size = payload_len;
        outsize = nalu_size + sizeof (sync_bytes);
1166
        outbuf = gst_buffer_new_and_alloc (outsize);
Wim Taymans's avatar
Wim Taymans committed
1167

Wim Taymans's avatar
Wim Taymans committed
1168
        gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
1169
        if (rtph264depay->byte_stream) {
Wim Taymans's avatar
Wim Taymans committed
1170
          memcpy (map.data, sync_bytes, sizeof (sync_bytes));
1171
        } else {
Wim Taymans's avatar
Wim Taymans committed
1172 1173 1174
          map.data[0] = map.data[1] = 0;
          map.data[2] = nalu_size >> 8;
          map.data[3] = nalu_size & 0xff;
1175
        }
Wim Taymans's avatar
Wim Taymans committed
1176 1177
        memcpy (map.data + sizeof (sync_bytes), payload, nalu_size);
        gst_buffer_unmap (outbuf, &map);
1178

1179
        gst_rtp_copy_video_meta (rtph264depay, outbuf, rtp->buffer);
1180

1181 1182
        outbuf = gst_rtp_h264_depay_handle_nal (rtph264depay, outbuf, timestamp,
            marker);
1183
        break;
1184 1185 1186 1187
      }
    }
  }

1188
  return outbuf;
1189 1190

  /* ERRORS */
Wim Taymans's avatar
Wim Taymans committed
1191 1192 1193 1194 1195
empty_packet:
  {
    GST_DEBUG_OBJECT (rtph264depay, "empty packet");
    return NULL;
  }
1196 1197 1198
undefined_type:
  {
    GST_ELEMENT_WARNING (rtph264depay, STREAM, DECODE,
1199
        (NULL), ("Undefined packet type"));
1200 1201
    return NULL;
  }
1202 1203 1204 1205 1206
waiting_start:
  {
    GST_DEBUG_OBJECT (rtph264depay, "waiting for start");
    return NULL;
  }
1207 1208 1209
not_implemented:
  {
    GST_ELEMENT_ERROR (rtph264depay, STREAM, FORMAT,
1210
        (NULL), ("NAL unit type %d not supported yet", nal_unit_type));
1211 1212
    return NULL;
  }
1213 1214
}

1215
static gboolean
Wim Taymans's avatar
Wim Taymans committed
1216
gst_rtp_h264_depay_handle_event (GstRTPBaseDepayload * depay, GstEvent * event)
1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230
{
  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