static GstBuffer *
gst_rtp_ilbc_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
{
  GstBuffer *outbuf;
  gboolean marker;

  marker = gst_rtp_buffer_get_marker (rtp);

  GST_DEBUG ("process : got %" G_GSIZE_FORMAT " bytes, mark %d ts %u seqn %d",
      gst_buffer_get_size (rtp->buffer), marker,
      gst_rtp_buffer_get_timestamp (rtp), gst_rtp_buffer_get_seq (rtp));

  outbuf = gst_rtp_buffer_get_payload_buffer (rtp);

  if (marker && outbuf) {
    /* mark start of talkspurt with RESYNC */
    GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC);
  }

  if (outbuf) {
    gst_rtp_drop_meta (GST_ELEMENT_CAST (depayload), outbuf,
        g_quark_from_static_string (GST_META_TAG_AUDIO_STR));
  }

  return outbuf;
}
static GstBuffer *
gst_rtp_g722_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
{
  GstRtpG722Depay *rtpg722depay;
  GstBuffer *outbuf;
  gint payload_len;
  gboolean marker;
  GstRTPBuffer rtp = { NULL };

  rtpg722depay = GST_RTP_G722_DEPAY (depayload);

  gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);

  payload_len = gst_rtp_buffer_get_payload_len (&rtp);

  if (payload_len <= 0)
    goto empty_packet;

  GST_DEBUG_OBJECT (rtpg722depay, "got payload of %d bytes", payload_len);

  outbuf = gst_rtp_buffer_get_payload_buffer (&rtp);
  marker = gst_rtp_buffer_get_marker (&rtp);
  gst_rtp_buffer_unmap (&rtp);

  if (marker && outbuf) {
    /* mark talk spurt with RESYNC */
    GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC);
  }

  if (outbuf) {
    gst_rtp_drop_meta (GST_ELEMENT_CAST (rtpg722depay), outbuf,
        g_quark_from_static_string (GST_META_TAG_AUDIO_STR));
  }

  return outbuf;

  /* ERRORS */
empty_packet:
  {
    GST_ELEMENT_WARNING (rtpg722depay, STREAM, DECODE,
        ("Empty Payload."), (NULL));
    gst_rtp_buffer_unmap (&rtp);
    return NULL;
  }
}
Пример #3
0
static GstFlowReturn
gst_rtp_g723_pay_flush (GstRTPG723Pay * pay)
{
  GstBuffer *outbuf, *payload_buf;
  GstFlowReturn ret;
  guint avail;
  GstRTPBuffer rtp = { NULL };

  avail = gst_adapter_available (pay->adapter);

  outbuf = gst_rtp_buffer_new_allocate (0, 0, 0);

  gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);

  GST_BUFFER_PTS (outbuf) = pay->timestamp;
  GST_BUFFER_DURATION (outbuf) = pay->duration;

  /* copy G723 data as payload */
  payload_buf = gst_adapter_take_buffer_fast (pay->adapter, avail);

  pay->timestamp = GST_CLOCK_TIME_NONE;
  pay->duration = 0;

  /* set discont and marker */
  if (pay->discont) {
    GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
    gst_rtp_buffer_set_marker (&rtp, TRUE);
    pay->discont = FALSE;
  }
  gst_rtp_buffer_unmap (&rtp);
  gst_rtp_drop_meta (GST_ELEMENT_CAST (pay), outbuf,
      g_quark_from_static_string (GST_META_TAG_AUDIO_STR));
  outbuf = gst_buffer_append (outbuf, payload_buf);

  ret = gst_rtp_base_payload_push (GST_RTP_BASE_PAYLOAD (pay), outbuf);

  return ret;
}
static GstBuffer *
gst_rtp_jpeg_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
{
  GstRtpJPEGDepay *rtpjpegdepay;
  GstBuffer *outbuf;
  gint payload_len, header_len;
  guint8 *payload;
  guint frag_offset;
  gint Q;
  guint type, width, height;
  guint16 dri, precision, length;
  guint8 *qtable;

  rtpjpegdepay = GST_RTP_JPEG_DEPAY (depayload);

  if (GST_BUFFER_IS_DISCONT (rtp->buffer)) {
    GST_DEBUG_OBJECT (depayload, "DISCONT, reset adapter");
    gst_adapter_clear (rtpjpegdepay->adapter);
    rtpjpegdepay->discont = TRUE;
  }

  payload_len = gst_rtp_buffer_get_payload_len (rtp);

  if (payload_len < 8)
    goto empty_packet;

  payload = gst_rtp_buffer_get_payload (rtp);
  header_len = 0;

  /*  0                   1                   2                   3
   *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   * | Type-specific |              Fragment Offset                  |
   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   * |      Type     |       Q       |     Width     |     Height    |
   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   */
  frag_offset = (payload[1] << 16) | (payload[2] << 8) | payload[3];
  type = payload[4];
  Q = payload[5];
  width = payload[6] * 8;
  height = payload[7] * 8;

  /* saw a packet with fragment offset > 0 and we don't already have data queued
   * up (most importantly, we don't have a header for this data) -- drop it
   * XXX: maybe we can check if the jpeg is progressive and salvage the data?
   * XXX: not implemented yet because jpegenc can't create progressive jpegs */
  if (frag_offset > 0 && gst_adapter_available (rtpjpegdepay->adapter) == 0)
    goto no_header_packet;

  /* allow frame dimensions > 2040, passed in SDP session or media attributes
   * from gstrtspsrc.c (gst_rtspsrc_sdp_attributes_to_caps), or in caps */
  if (!width)
    width = rtpjpegdepay->media_width;

  if (!height)
    height = rtpjpegdepay->media_height;

  if (width == 0 || height == 0)
    goto invalid_dimension;

  GST_DEBUG_OBJECT (rtpjpegdepay, "frag %u, type %u, Q %d, width %u, height %u",
      frag_offset, type, Q, width, height);

  header_len += 8;
  payload += 8;
  payload_len -= 8;

  dri = 0;
  if (type > 63) {
    if (payload_len < 4)
      goto empty_packet;

    /*  0                   1                   2                   3
     *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     * |       Restart Interval        |F|L|       Restart Count       |
     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     */
    dri = (payload[0] << 8) | payload[1];

    GST_DEBUG_OBJECT (rtpjpegdepay, "DRI %" G_GUINT16_FORMAT, dri);

    payload += 4;
    header_len += 4;
    payload_len -= 4;
  }

  if (Q >= 128 && frag_offset == 0) {
    if (payload_len < 4)
      goto empty_packet;

    /*  0                   1                   2                   3
     *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     * |      MBZ      |   Precision   |             Length            |
     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     * |                    Quantization Table Data                    |
     * |                              ...                              |
     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     */
    precision = payload[1];
    length = (payload[2] << 8) | payload[3];

    GST_DEBUG_OBJECT (rtpjpegdepay, "precision %04x, length %" G_GUINT16_FORMAT,
        precision, length);

    if (Q == 255 && length == 0)
      goto empty_packet;

    payload += 4;
    header_len += 4;
    payload_len -= 4;

    if (length > payload_len)
      goto empty_packet;

    if (length > 0)
      qtable = payload;
    else
      qtable = rtpjpegdepay->qtables[Q];

    payload += length;
    header_len += length;
    payload_len -= length;
  } else {
    length = 0;
    qtable = NULL;
    precision = 0;
  }

  if (frag_offset == 0) {
    GstMapInfo map;
    guint size;

    if (rtpjpegdepay->width != width || rtpjpegdepay->height != height) {
      GstCaps *outcaps;

      outcaps =
          gst_caps_new_simple ("image/jpeg", "framerate", GST_TYPE_FRACTION,
          rtpjpegdepay->frate_num, rtpjpegdepay->frate_denom, "width",
          G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL);
      gst_pad_set_caps (depayload->srcpad, outcaps);
      gst_caps_unref (outcaps);

      rtpjpegdepay->width = width;
      rtpjpegdepay->height = height;
    }

    GST_LOG_OBJECT (rtpjpegdepay, "first packet, length %" G_GUINT16_FORMAT,
        length);

    /* first packet */
    if (length == 0) {
      if (Q < 128) {
        /* no quant table, see if we have one cached */
        qtable = rtpjpegdepay->qtables[Q];
        if (!qtable) {
          GST_DEBUG_OBJECT (rtpjpegdepay, "making Q %d table", Q);
          /* make and cache the table */
          qtable = g_new (guint8, 128);
          MakeTables (rtpjpegdepay, Q, qtable);
          rtpjpegdepay->qtables[Q] = qtable;
        } else {
          GST_DEBUG_OBJECT (rtpjpegdepay, "using cached table for Q %d", Q);
        }
        /* all 8 bit quantizers */
        precision = 0;
      } else {
        if (!qtable)
          goto no_qtable;
      }
    }

    /* I think we can get here with a NULL qtable, so make sure we don't
       go dereferencing it in MakeHeaders if we do */
    if (!qtable)
      goto no_qtable;

    /* max header length, should be big enough */
    outbuf = gst_buffer_new_and_alloc (1000);
    gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
    size = MakeHeaders (map.data, type, width, height, qtable, precision, dri);
    gst_buffer_unmap (outbuf, &map);
    gst_buffer_resize (outbuf, 0, size);

    GST_DEBUG_OBJECT (rtpjpegdepay, "pushing %u bytes of header", size);

    gst_adapter_push (rtpjpegdepay->adapter, outbuf);
  }

  /* take JPEG data, push in the adapter */
  GST_DEBUG_OBJECT (rtpjpegdepay, "pushing data at offset %d", header_len);
  outbuf = gst_rtp_buffer_get_payload_subbuffer (rtp, header_len, -1);
  gst_adapter_push (rtpjpegdepay->adapter, outbuf);
  outbuf = NULL;

  if (gst_rtp_buffer_get_marker (rtp)) {
    guint avail;
    guint8 end[2];
    GstMapInfo map;

    /* last buffer take all data out of the adapter */
    avail = gst_adapter_available (rtpjpegdepay->adapter);
    GST_DEBUG_OBJECT (rtpjpegdepay, "marker set, last buffer");

    if (avail < 2)
      goto invalid_packet;

    /* take the last bytes of the jpeg data to see if there is an EOI
     * marker */
    gst_adapter_copy (rtpjpegdepay->adapter, end, avail - 2, 2);

    if (end[0] != 0xff && end[1] != 0xd9) {
      GST_DEBUG_OBJECT (rtpjpegdepay, "no EOI marker, adding one");

      /* no EOI marker, add one */
      outbuf = gst_buffer_new_and_alloc (2);
      gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
      map.data[0] = 0xff;
      map.data[1] = 0xd9;
      gst_buffer_unmap (outbuf, &map);

      gst_adapter_push (rtpjpegdepay->adapter, outbuf);
      avail += 2;
    }
    outbuf = gst_adapter_take_buffer (rtpjpegdepay->adapter, avail);

    if (rtpjpegdepay->discont) {
      GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
      rtpjpegdepay->discont = FALSE;
    }

    gst_rtp_drop_meta (GST_ELEMENT_CAST (rtpjpegdepay), outbuf,
        g_quark_from_static_string (GST_META_TAG_VIDEO_STR));

    GST_DEBUG_OBJECT (rtpjpegdepay, "returning %u bytes", avail);
  }

  return outbuf;

  /* ERRORS */
empty_packet:
  {
    GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, DECODE,
        ("Empty Payload."), (NULL));
    return NULL;
  }
invalid_dimension:
  {
    GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, FORMAT,
        ("Invalid Dimension %dx%d.", width, height), (NULL));
    return NULL;
  }
no_qtable:
  {
    GST_WARNING_OBJECT (rtpjpegdepay, "no qtable");
    return NULL;
  }
invalid_packet:
  {
    GST_WARNING_OBJECT (rtpjpegdepay, "invalid packet");
    gst_adapter_flush (rtpjpegdepay->adapter,
        gst_adapter_available (rtpjpegdepay->adapter));
    return NULL;
  }
no_header_packet:
  {
    GST_WARNING_OBJECT (rtpjpegdepay,
        "discarding data packets received when we have no header");
    return NULL;
  }
}
Пример #5
0
static GstBuffer *
gst_rtp_qcelp_depay_process (GstRTPBaseDepayload * depayload,
    GstRTPBuffer * rtp)
{
  GstRtpQCELPDepay *depay;
  GstBuffer *outbuf;
  GstClockTime timestamp;
  guint payload_len, offset, index;
  guint8 *payload;
  guint LLL, NNN;

  depay = GST_RTP_QCELP_DEPAY (depayload);

  payload_len = gst_rtp_buffer_get_payload_len (rtp);

  if (payload_len < 2)
    goto too_small;

  timestamp = GST_BUFFER_PTS (rtp->buffer);

  payload = gst_rtp_buffer_get_payload (rtp);

  /*  0 1 2 3 4 5 6 7
   * +-+-+-+-+-+-+-+-+
   * |RR | LLL | NNN |
   * +-+-+-+-+-+-+-+-+
   */
  /* RR = payload[0] >> 6; */
  LLL = (payload[0] & 0x38) >> 3;
  NNN = (payload[0] & 0x07);

  payload_len--;
  payload++;

  GST_DEBUG_OBJECT (depay, "LLL %u, NNN %u", LLL, NNN);

  if (LLL > 5)
    goto invalid_lll;

  if (NNN > LLL)
    goto invalid_nnn;

  if (LLL != 0) {
    /* we are interleaved */
    if (!depay->interleaved) {
      guint size;

      GST_DEBUG_OBJECT (depay, "starting interleaving group");
      /* bundling is not allowed to change in one interleave group */
      depay->bundling = count_packets (depay, payload, payload_len);
      GST_DEBUG_OBJECT (depay, "got bundling of %u", depay->bundling);
      /* we have one bundle where NNN goes from 0 to L, we don't store the index
       * 0 frames, so L+1 packets. Each packet has 'bundling - 1' packets */
      size = (depay->bundling - 1) * (LLL + 1);
      /* create the array to hold the packets */
      if (depay->packets == NULL)
        depay->packets = g_ptr_array_sized_new (size);
      GST_DEBUG_OBJECT (depay, "created packet array of size %u", size);
      g_ptr_array_set_size (depay->packets, size);
      /* we were previously not interleaved, figure out how much space we
       * need to deinterleave */
      depay->interleaved = TRUE;
    }
  } else {
    /* we are not interleaved */
    if (depay->interleaved) {
      GST_DEBUG_OBJECT (depay, "stopping interleaving");
      /* flush packets if we were previously interleaved */
      flush_packets (depay);
    }
    depay->bundling = 0;
  }

  index = 0;
  offset = 1;

  while (payload_len > 0) {
    gint frame_len;
    gboolean do_erasure;

    frame_len = get_frame_len (depay, payload[0]);
    GST_DEBUG_OBJECT (depay, "got frame len %d", frame_len);

    if (frame_len == 0)
      goto invalid_frame;

    if (frame_len < 0) {
      /* need to add an erasure frame but we can recover */
      frame_len = -frame_len;
      do_erasure = TRUE;
    } else {
      do_erasure = FALSE;
    }

    if (frame_len > payload_len)
      goto invalid_frame;

    if (do_erasure) {
      /* create erasure frame */
      outbuf = create_erasure_buffer (depay);
    } else {
      /* each frame goes into its buffer */
      outbuf = gst_rtp_buffer_get_payload_subbuffer (rtp, offset, frame_len);
    }

    GST_BUFFER_PTS (outbuf) = timestamp;
    GST_BUFFER_DURATION (outbuf) = FRAME_DURATION;

    gst_rtp_drop_meta (GST_ELEMENT_CAST (depayload), outbuf,
        g_quark_from_static_string (GST_META_TAG_AUDIO_STR));

    if (!depay->interleaved || index == 0) {
      /* not interleaved or first frame in packet, just push */
      gst_rtp_base_depayload_push (depayload, outbuf);

      if (timestamp != -1)
        timestamp += FRAME_DURATION;
    } else {
      /* put in interleave buffer */
      add_packet (depay, LLL, NNN, index, outbuf);

      if (timestamp != -1)
        timestamp += (FRAME_DURATION * (LLL + 1));
    }

    payload_len -= frame_len;
    payload += frame_len;
    offset += frame_len;
    index++;

    /* discard excess packets */
    if (depay->bundling > 0 && depay->bundling <= index)
      break;
  }
  while (index < depay->bundling) {
    GST_DEBUG_OBJECT (depay, "filling with erasure buffer");
    /* fill remainder with erasure packets */
    outbuf = create_erasure_buffer (depay);
    add_packet (depay, LLL, NNN, index, outbuf);
    index++;
  }
  if (depay->interleaved && LLL == NNN) {
    GST_DEBUG_OBJECT (depay, "interleave group ended, flushing");
    /* we have the complete interleave group, flush */
    flush_packets (depay);
  }

  return NULL;

  /* ERRORS */
too_small:
  {
    GST_ELEMENT_WARNING (depay, STREAM, DECODE,
        (NULL), ("QCELP RTP payload too small (%d)", payload_len));
    return NULL;
  }
invalid_lll:
  {
    GST_ELEMENT_WARNING (depay, STREAM, DECODE,
        (NULL), ("QCELP RTP invalid LLL received (%d)", LLL));
    return NULL;
  }
invalid_nnn:
  {
    GST_ELEMENT_WARNING (depay, STREAM, DECODE,
        (NULL), ("QCELP RTP invalid NNN received (%d)", NNN));
    return NULL;
  }
invalid_frame:
  {
    GST_ELEMENT_WARNING (depay, STREAM, DECODE,
        (NULL), ("QCELP RTP invalid frame received"));
    return NULL;
  }
}
Пример #6
0
static GstBuffer *
gst_rtp_vp9_depay_process (GstRTPBaseDepayload * depay, GstRTPBuffer * rtp)
{
  GstRtpVP9Depay *self = GST_RTP_VP9_DEPAY (depay);
  GstBuffer *payload;
  guint8 *data;
  guint hdrsize = 1;
  guint size;
  gint spatial_layer = 0;
  gboolean i_bit, p_bit, l_bit, f_bit, b_bit, e_bit, v_bit;

  if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (rtp->buffer))) {
    GST_LOG_OBJECT (self, "Discontinuity, flushing adapter");
    gst_adapter_clear (self->adapter);
    self->started = FALSE;
  }

  size = gst_rtp_buffer_get_payload_len (rtp);

  /* Mandatory with at least one header and one vp9 byte */
  if (G_UNLIKELY (size < hdrsize + 1))
    goto too_small;

  data = gst_rtp_buffer_get_payload (rtp);
  i_bit = (data[0] & 0x80) != 0;
  p_bit = (data[0] & 0x40) != 0;
  l_bit = (data[0] & 0x20) != 0;
  f_bit = (data[0] & 0x10) != 0;
  b_bit = (data[0] & 0x08) != 0;
  e_bit = (data[0] & 0x04) != 0;
  v_bit = (data[0] & 0x02) != 0;

  if (G_UNLIKELY (!self->started)) {
    /* Check if this is the start of a VP9 layer frame, otherwise bail */
    if (!b_bit)
      goto done;

    self->started = TRUE;
  }

  GST_TRACE_OBJECT (self, "IPLFBEV : %d%d%d%d%d%d%d", i_bit, p_bit, l_bit,
      f_bit, b_bit, e_bit, v_bit);

  /* Check I optional header Picture ID */
  if (i_bit) {
    hdrsize++;
    if (G_UNLIKELY (size < hdrsize + 1))
      goto too_small;
    /* Check M for 15 bits PictureID */
    if ((data[1] & 0x80) != 0) {
      hdrsize++;
      if (G_UNLIKELY (size < hdrsize + 1))
        goto too_small;
    }
  }

  /* flexible-mode not implemented */
  g_assert (!f_bit);

  /* Check L optional header layer indices */
  if (l_bit) {
    hdrsize++;
    /* Check TL0PICIDX temporal layer zero index (non-flexible mode) */
    if (!f_bit)
      hdrsize++;
  }

  /* Check V optional Scalability Structure */
  if (v_bit) {
    guint n_s, y_bit, g_bit;
    guint8 *ss = &data[hdrsize];
    guint sssize = 1;

    if (G_UNLIKELY (size < hdrsize + sssize + 1))
      goto too_small;

    n_s = (ss[0] & 0xe0) >> 5;
    y_bit = (ss[0] & 0x10) != 0;
    g_bit = (ss[0] & 0x08) != 0;

    GST_TRACE_OBJECT (self, "SS header: N_S=%u, Y=%u, G=%u", n_s, y_bit, g_bit);

    sssize += y_bit ? (n_s + 1) * 4 : 0;
    if (G_UNLIKELY (size < hdrsize + sssize + 1))
      goto too_small;

    if (y_bit) {
      guint i;
      for (i = 0; i <= n_s; i++) {
        /* For now, simply use the last layer specified for width and height */
        self->ss_width = ss[1 + i * 4] * 256 + ss[2 + i * 4];
        self->ss_height = ss[3 + i * 4] * 256 + ss[4 + i * 4];
        GST_TRACE_OBJECT (self, "N_S[%d]: WIDTH=%u, HEIGHT=%u", i,
            self->ss_width, self->ss_height);
      }
    }

    if (g_bit) {
      guint i, j;
      guint n_g = ss[sssize];
      sssize++;
      if (G_UNLIKELY (size < hdrsize + sssize + 1))
        goto too_small;
      for (i = 0; i < n_g; i++) {
        guint t = (ss[sssize] & 0xe0) >> 5;
        guint u = (ss[sssize] & 0x10) >> 4;
        guint r = (ss[sssize] & 0x0c) >> 2;
        GST_TRACE_OBJECT (self, "N_G[%u]: 0x%02x -> T=%u, U=%u, R=%u", i,
            ss[sssize], t, u, r);
        for (j = 0; j < r; j++)
          GST_TRACE_OBJECT (self, "  R[%u]: P_DIFF=%u", j, ss[sssize + 1 + j]);
        sssize += 1 + r;
        if (G_UNLIKELY (size < hdrsize + sssize + 1))
          goto too_small;
      }
    }
    hdrsize += sssize;
  }

  GST_DEBUG_OBJECT (depay, "hdrsize %u, size %u", hdrsize, size);

  if (G_UNLIKELY (hdrsize >= size))
    goto too_small;

  payload = gst_rtp_buffer_get_payload_subbuffer (rtp, hdrsize, -1);
  {
    GstMapInfo map;
    gst_buffer_map (payload, &map, GST_MAP_READ);
    GST_MEMDUMP_OBJECT (self, "vp9 payload", map.data, 16);
    gst_buffer_unmap (payload, &map);
  }
  gst_adapter_push (self->adapter, payload);

  /* Marker indicates that it was the last rtp packet for this frame */
  if (gst_rtp_buffer_get_marker (rtp)) {
    GstBuffer *out;
    gboolean key_frame_first_layer = !p_bit && spatial_layer == 0;


    if (gst_adapter_available (self->adapter) < 10)
      goto too_small;

    out = gst_adapter_take_buffer (self->adapter,
        gst_adapter_available (self->adapter));

    self->started = FALSE;

    /* mark keyframes */
    out = gst_buffer_make_writable (out);
    /* Filter away all metas that are not sensible to copy */
    gst_rtp_drop_meta (GST_ELEMENT_CAST (self), out,
        g_quark_from_static_string (GST_META_TAG_VIDEO_STR));
    if (!key_frame_first_layer) {
      GST_BUFFER_FLAG_SET (out, GST_BUFFER_FLAG_DELTA_UNIT);

      if (!self->caps_sent) {
        gst_buffer_unref (out);
        out = NULL;
        GST_INFO_OBJECT (self, "Dropping inter-frame before intra-frame");
        gst_pad_push_event (GST_RTP_BASE_DEPAYLOAD_SINKPAD (depay),
            gst_video_event_new_upstream_force_key_unit (GST_CLOCK_TIME_NONE,
                TRUE, 0));
      }
    } else {
      GST_BUFFER_FLAG_UNSET (out, GST_BUFFER_FLAG_DELTA_UNIT);

      if (self->last_width != self->ss_width ||
          self->last_height != self->ss_height) {
        GstCaps *srccaps;

        /* Width and height are optional in the RTP header. Consider to parse
         * the frame header in addition if missing from RTP header */
        if (self->ss_width != 0 && self->ss_height != 0) {
          srccaps = gst_caps_new_simple ("video/x-vp9",
              "framerate", GST_TYPE_FRACTION, 0, 1,
              "width", G_TYPE_INT, self->ss_width,
              "height", G_TYPE_INT, self->ss_height, NULL);
        } else {
          srccaps = gst_caps_new_simple ("video/x-vp9",
              "framerate", GST_TYPE_FRACTION, 0, 1, NULL);
        }

        gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depay), srccaps);
        gst_caps_unref (srccaps);

        self->caps_sent = TRUE;
        self->last_width = self->ss_width;
        self->last_height = self->ss_height;
        self->ss_width = 0;
        self->ss_height = 0;
      }
    }

    return out;
  }

done:
  return NULL;

too_small:
  GST_LOG_OBJECT (self, "Invalid rtp packet (too small), ignoring");
  gst_adapter_clear (self->adapter);
  self->started = FALSE;

  goto done;
}
Пример #7
0
static GstBuffer *
gst_rtp_L16_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
{
  GstRtpL16Depay *rtpL16depay;
  GstBuffer *outbuf;
  gint payload_len;
  gboolean marker;
  GstAudioInfo *info;

  rtpL16depay = GST_RTP_L16_DEPAY (depayload);

  payload_len = gst_rtp_buffer_get_payload_len (rtp);

  if (payload_len <= 0)
    goto empty_packet;

  GST_DEBUG_OBJECT (rtpL16depay, "got payload of %d bytes", payload_len);

  outbuf = gst_rtp_buffer_get_payload_buffer (rtp);
  marker = gst_rtp_buffer_get_marker (rtp);

  if (marker) {
    /* mark talk spurt with RESYNC */
    GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC);
  }

  outbuf = gst_buffer_make_writable (outbuf);
  info = &rtpL16depay->info;

  if (payload_len % ((info->finfo->width * info->channels) / 8) != 0)
    goto wrong_payload_size;

  if (rtpL16depay->order &&
      !gst_audio_buffer_reorder_channels (outbuf,
          info->finfo->format, info->channels,
          info->position, rtpL16depay->order->pos)) {
    goto reorder_failed;
  }

  gst_rtp_drop_meta (GST_ELEMENT_CAST (rtpL16depay), outbuf,
      g_quark_from_static_string (GST_META_TAG_AUDIO_STR));

  return outbuf;

  /* ERRORS */
empty_packet:
  {
    GST_ELEMENT_WARNING (rtpL16depay, STREAM, DECODE,
        ("Empty Payload."), (NULL));
    return NULL;
  }
wrong_payload_size:
  {
    GST_ELEMENT_WARNING (rtpL16depay, STREAM, DECODE,
        ("Wrong Payload Size."), (NULL));
    return NULL;
  }
reorder_failed:
  {
    GST_ELEMENT_ERROR (rtpL16depay, STREAM, DECODE,
        ("Channel reordering failed."), (NULL));
    return NULL;
  }
}
Пример #8
0
static GstFlowReturn
gst_rtp_j2k_depay_flush_frame (GstRTPBaseDepayload * depayload)
{
  GstRtpJ2KDepay *rtpj2kdepay;
  guint8 end[2];
  guint avail;

  GstFlowReturn ret = GST_FLOW_OK;

  rtpj2kdepay = GST_RTP_J2K_DEPAY (depayload);

  /* flush pending tile */
  gst_rtp_j2k_depay_flush_tile (depayload);

  /* last buffer take all data out of the adapter */
  avail = gst_adapter_available (rtpj2kdepay->f_adapter);
  if (avail == 0)
    goto done;

  if (avail > 2) {
    GstBuffer *outbuf;

    /* take the last bytes of the JPEG 2000 data to see if there is an EOC
     * marker */
    gst_adapter_copy (rtpj2kdepay->f_adapter, end, avail - 2, 2);

    if (end[0] != 0xff && end[1] != 0xd9) {
      end[0] = 0xff;
      end[1] = 0xd9;

      GST_DEBUG_OBJECT (rtpj2kdepay, "no EOC marker, adding one");

      /* no EOI marker, add one */
      outbuf = gst_buffer_new_and_alloc (2);
      gst_buffer_fill (outbuf, 0, end, 2);

      gst_adapter_push (rtpj2kdepay->f_adapter, outbuf);
      avail += 2;
    }

    GST_DEBUG_OBJECT (rtpj2kdepay, "pushing buffer of %u bytes", avail);
    outbuf = gst_adapter_take_buffer (rtpj2kdepay->f_adapter, avail);
    gst_rtp_drop_meta (GST_ELEMENT_CAST (depayload),
        outbuf, g_quark_from_static_string (GST_META_TAG_VIDEO_STR));
    ret = gst_rtp_base_depayload_push (depayload, outbuf);
  } else {
    GST_WARNING_OBJECT (rtpj2kdepay, "empty packet");
    gst_adapter_clear (rtpj2kdepay->f_adapter);
  }

  /* we accept any mh_id now */
  rtpj2kdepay->last_mh_id = -1;

  /* reset state */
  rtpj2kdepay->next_frag = 0;
  rtpj2kdepay->have_sync = FALSE;

done:
  /* we can't keep headers with mh_id of 0 */
  store_mheader (rtpj2kdepay, 0, NULL);

  return ret;
}
Пример #9
0
static GstBuffer *
gst_rtp_celt_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
{
  GstBuffer *outbuf = NULL;
  guint8 *payload;
  guint offset, pos, payload_len, total_size, size;
  guint8 s;
  gint clock_rate = 0, frame_size = 0;
  GstClockTime framesize_ns = 0, timestamp;
  guint n = 0;
  GstRtpCELTDepay *rtpceltdepay;

  rtpceltdepay = GST_RTP_CELT_DEPAY (depayload);
  clock_rate = depayload->clock_rate;
  frame_size = rtpceltdepay->frame_size;
  framesize_ns = gst_util_uint64_scale_int (frame_size, GST_SECOND, clock_rate);

  timestamp = GST_BUFFER_PTS (rtp->buffer);

  GST_LOG_OBJECT (depayload,
      "got %" G_GSIZE_FORMAT " bytes, mark %d ts %u seqn %d",
      gst_buffer_get_size (rtp->buffer), gst_rtp_buffer_get_marker (rtp),
      gst_rtp_buffer_get_timestamp (rtp), gst_rtp_buffer_get_seq (rtp));

  GST_LOG_OBJECT (depayload, "got clock-rate=%d, frame_size=%d, "
      "_ns=%" GST_TIME_FORMAT ", timestamp=%" GST_TIME_FORMAT, clock_rate,
      frame_size, GST_TIME_ARGS (framesize_ns), GST_TIME_ARGS (timestamp));

  payload = gst_rtp_buffer_get_payload (rtp);
  payload_len = gst_rtp_buffer_get_payload_len (rtp);

  /* first count how many bytes are consumed by the size headers and make offset
   * point to the first data byte */
  total_size = 0;
  offset = 0;
  while (total_size < payload_len) {
    do {
      s = payload[offset++];
      total_size += s + 1;
    } while (s == 0xff);
  }

  /* offset is now pointing to the payload */
  total_size = 0;
  pos = 0;
  while (total_size < payload_len) {
    n++;
    size = 0;
    do {
      s = payload[pos++];
      size += s;
      total_size += s + 1;
    } while (s == 0xff);

    outbuf = gst_rtp_buffer_get_payload_subbuffer (rtp, offset, size);
    offset += size;

    if (frame_size != -1 && clock_rate != -1) {
      GST_BUFFER_PTS (outbuf) = timestamp + framesize_ns * n;
      GST_BUFFER_DURATION (outbuf) = framesize_ns;
    }
    GST_LOG_OBJECT (depayload, "push timestamp=%"
        GST_TIME_FORMAT ", duration=%" GST_TIME_FORMAT,
        GST_TIME_ARGS (GST_BUFFER_PTS (outbuf)),
        GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)));

    gst_rtp_drop_meta (GST_ELEMENT_CAST (depayload), outbuf,
        g_quark_from_static_string (GST_META_TAG_AUDIO_STR));

    gst_rtp_base_depayload_push (depayload, outbuf);
  }

  return NULL;
}
static GstBuffer *
gst_rtp_vp8_depay_process (GstRTPBaseDepayload * depay, GstRTPBuffer * rtp)
{
  GstRtpVP8Depay *self = GST_RTP_VP8_DEPAY (depay);
  GstBuffer *payload;
  guint8 *data;
  guint hdrsize;
  guint size;

  if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (rtp->buffer))) {
    GST_LOG_OBJECT (self, "Discontinuity, flushing adapter");
    gst_adapter_clear (self->adapter);
    self->started = FALSE;
  }

  size = gst_rtp_buffer_get_payload_len (rtp);

  /* At least one header and one vp8 byte */
  if (G_UNLIKELY (size < 2))
    goto too_small;

  data = gst_rtp_buffer_get_payload (rtp);

  if (G_UNLIKELY (!self->started)) {
    /* Check if this is the start of a VP8 frame, otherwise bail */
    /* S=1 and PartID= 0 */
    if ((data[0] & 0x17) != 0x10)
      goto done;

    self->started = TRUE;
  }

  hdrsize = 1;
  /* Check X optional header */
  if ((data[0] & 0x80) != 0) {
    hdrsize++;
    /* Check I optional header */
    if ((data[1] & 0x80) != 0) {
      if (G_UNLIKELY (size < 3))
        goto too_small;
      hdrsize++;
      /* Check for 16 bits PictureID */
      if ((data[2] & 0x80) != 0)
        hdrsize++;
    }
    /* Check L optional header */
    if ((data[1] & 0x40) != 0)
      hdrsize++;
    /* Check T or K optional headers */
    if ((data[1] & 0x20) != 0 || (data[1] & 0x10) != 0)
      hdrsize++;
  }
  GST_DEBUG_OBJECT (depay, "hdrsize %u, size %u", hdrsize, size);

  if (G_UNLIKELY (hdrsize >= size))
    goto too_small;

  payload = gst_rtp_buffer_get_payload_subbuffer (rtp, hdrsize, -1);
  gst_adapter_push (self->adapter, payload);

  /* Marker indicates that it was the last rtp packet for this frame */
  if (gst_rtp_buffer_get_marker (rtp)) {
    GstBuffer *out;
    guint8 header[10];

    if (gst_adapter_available (self->adapter) < 10)
      goto too_small;
    gst_adapter_copy (self->adapter, &header, 0, 10);

    out = gst_adapter_take_buffer (self->adapter,
        gst_adapter_available (self->adapter));

    self->started = FALSE;

    /* mark keyframes */
    out = gst_buffer_make_writable (out);
    /* Filter away all metas that are not sensible to copy */
    gst_rtp_drop_meta (GST_ELEMENT_CAST (self), out,
        g_quark_from_static_string (GST_META_TAG_VIDEO_STR));
    if ((header[0] & 0x01)) {
      GST_BUFFER_FLAG_SET (out, GST_BUFFER_FLAG_DELTA_UNIT);

      if (!self->caps_sent) {
        gst_buffer_unref (out);
        out = NULL;
        GST_INFO_OBJECT (self, "Dropping inter-frame before intra-frame");
        gst_pad_push_event (GST_RTP_BASE_DEPAYLOAD_SINKPAD (depay),
            gst_video_event_new_upstream_force_key_unit (GST_CLOCK_TIME_NONE,
                TRUE, 0));
      }
    } else {
      guint profile, width, height;

      GST_BUFFER_FLAG_UNSET (out, GST_BUFFER_FLAG_DELTA_UNIT);

      profile = (header[0] & 0x0e) >> 1;
      width = GST_READ_UINT16_LE (header + 6) & 0x3fff;
      height = GST_READ_UINT16_LE (header + 8) & 0x3fff;

      if (G_UNLIKELY (self->last_width != width ||
              self->last_height != height || self->last_profile != profile)) {
        gchar profile_str[3];
        GstCaps *srccaps;

        snprintf (profile_str, 3, "%u", profile);
        srccaps = gst_caps_new_simple ("video/x-vp8",
            "framerate", GST_TYPE_FRACTION, 0, 1,
            "height", G_TYPE_INT, height,
            "width", G_TYPE_INT, width,
            "profile", G_TYPE_STRING, profile_str, NULL);

        gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depay), srccaps);
        gst_caps_unref (srccaps);

        self->caps_sent = TRUE;
        self->last_width = width;
        self->last_height = height;
        self->last_profile = profile;
      }
    }

    return out;
  }

done:
  return NULL;

too_small:
  GST_LOG_OBJECT (self, "Invalid rtp packet (too small), ignoring");
  gst_adapter_clear (self->adapter);
  self->started = FALSE;

  goto done;
}
static GstBuffer *
gst_rtp_mpa_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
{
  GstRtpMPADepay *rtpmpadepay;
  GstBuffer *outbuf;
  gint payload_len;
#if 0
  guint8 *payload;
  guint16 frag_offset;
#endif
  gboolean marker;

  rtpmpadepay = GST_RTP_MPA_DEPAY (depayload);

  payload_len = gst_rtp_buffer_get_payload_len (rtp);

  if (payload_len <= 4)
    goto empty_packet;

#if 0
  payload = gst_rtp_buffer_get_payload (&rtp);
  /* strip off header
   *
   *  0                   1                   2                   3
   *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   * |             MBZ               |          Frag_offset          |
   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   */
  frag_offset = (payload[2] << 8) | payload[3];
#endif

  /* subbuffer skipping the 4 header bytes */
  outbuf = gst_rtp_buffer_get_payload_subbuffer (rtp, 4, -1);
  marker = gst_rtp_buffer_get_marker (rtp);

  if (marker) {
    /* mark start of talkspurt with RESYNC */
    GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC);
  }
  GST_DEBUG_OBJECT (rtpmpadepay,
      "gst_rtp_mpa_depay_chain: pushing buffer of size %" G_GSIZE_FORMAT "",
      gst_buffer_get_size (outbuf));

  if (outbuf) {
    gst_rtp_drop_meta (GST_ELEMENT_CAST (rtpmpadepay), outbuf,
        g_quark_from_static_string (GST_META_TAG_AUDIO_STR));
  }

  /* FIXME, we can push half mpeg frames when they are split over multiple
   * RTP packets */
  return outbuf;

  /* ERRORS */
empty_packet:
  {
    GST_ELEMENT_WARNING (rtpmpadepay, STREAM, DECODE,
        ("Empty Payload."), (NULL));
    return NULL;
  }
}
static GstBuffer *
gst_rtp_mpv_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
{
  GstRtpMPVDepay *rtpmpvdepay;
  GstBuffer *outbuf = NULL;

  rtpmpvdepay = GST_RTP_MPV_DEPAY (depayload);

  {
    gint payload_len, payload_header;
    guint8 *payload;
    guint8 T;

    payload_len = gst_rtp_buffer_get_payload_len (rtp);
    payload = gst_rtp_buffer_get_payload (rtp);
    payload_header = 0;

    if (payload_len <= 4)
      goto empty_packet;

    /* 3.4 MPEG Video-specific header
     *
     *  0                   1                   2                   3
     *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     * |    MBZ  |T|         TR        | |N|S|B|E|  P  | | BFC | | FFC |
     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     *                                  AN              FBV     FFV
     */
    T = (payload[0] & 0x04);

    payload_len -= 4;
    payload_header += 4;
    payload += 4;

    if (T) {
      /* 
       * 3.4.1 MPEG-2 Video-specific header extension
       *
       *  0                   1                   2                   3
       *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
       * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       * |X|E|f_[0,0]|f_[0,1]|f_[1,0]|f_[1,1]| DC| PS|T|P|C|Q|V|A|R|H|G|D|
       * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       */
      if (payload_len <= 4)
        goto empty_packet;

      payload_len -= 4;
      payload_header += 4;
      payload += 4;
    }

    outbuf = gst_rtp_buffer_get_payload_subbuffer (rtp, payload_header, -1);

    if (outbuf) {
      GST_DEBUG_OBJECT (rtpmpvdepay,
          "gst_rtp_mpv_depay_chain: pushing buffer of size %" G_GSIZE_FORMAT,
          gst_buffer_get_size (outbuf));
      gst_rtp_drop_meta (GST_ELEMENT_CAST (rtpmpvdepay), outbuf,
          g_quark_from_static_string (GST_META_TAG_VIDEO_STR));

    }
  }

  return outbuf;

  /* ERRORS */
empty_packet:
  {
    GST_ELEMENT_WARNING (rtpmpvdepay, STREAM, DECODE,
        (NULL), ("Empty payload."));
    return NULL;
  }
}