コード例 #1
0
ファイル: gstrtpbuffer.c プロジェクト: zsx/ossbuild
/**
 * gst_rtp_buffer_get_payload_subbuffer:
 * @buffer: the buffer
 * @offset: the offset in the payload
 * @len: the length in the payload
 *
 * Create a subbuffer of the payload of the RTP packet in @buffer. @offset bytes
 * are skipped in the payload and the subbuffer will be of size @len.
 * If @len is -1 the total payload starting from @offset if subbuffered.
 *
 * Returns: A new buffer with the specified data of the payload.
 *
 * Since: 0.10.10
 */
GstBuffer *
gst_rtp_buffer_get_payload_subbuffer (GstBuffer * buffer, guint offset,
    guint len)
{
  guint poffset, plen;

  plen = gst_rtp_buffer_get_payload_len (buffer);
  /* we can't go past the length */
  if (G_UNLIKELY (offset >= plen))
    goto wrong_offset;

  /* apply offset */
  poffset = gst_rtp_buffer_get_header_len (buffer) + offset;
  plen -= offset;

  /* see if we need to shrink the buffer based on @len */
  if (len != -1 && len < plen)
    plen = len;

  return gst_buffer_create_sub (buffer, poffset, plen);

  /* ERRORS */
wrong_offset:
  {
    g_warning ("offset=%u should be less then plen=%u", offset, plen);
    return NULL;
  }
}
コード例 #2
0
EXPORT_C
#endif

GstBuffer *
gst_rtp_buffer_get_payload_subbuffer (GstBuffer * buffer, guint offset,
    guint len)
{
  guint poffset, plen;

  g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL);
  g_return_val_if_fail (GST_BUFFER_DATA (buffer) != NULL, NULL);

  plen = gst_rtp_buffer_get_payload_len (buffer);
  /* we can't go past the length */
  if (G_UNLIKELY (offset >= plen)) {
    GST_WARNING ("offset=%u should be less then plen=%u", offset, plen);
    return (NULL);
  }

  /* apply offset */
  poffset = gst_rtp_buffer_get_header_len (buffer) + offset;
  plen -= offset;

  /* see if we need to shrink the buffer based on @len */
  if (len != -1 && len < plen)
    plen = len;

  return gst_buffer_create_sub (buffer, poffset, plen);
}
コード例 #3
0
EXPORT_C
#endif

gpointer
gst_rtp_buffer_get_payload (GstBuffer * buffer)
{
  return GST_BUFFER_DATA (buffer) + gst_rtp_buffer_get_header_len (buffer);
}
コード例 #4
0
EXPORT_C
#endif

gpointer
gst_rtp_buffer_get_payload (GstBuffer * buffer)
{
  g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL);
  g_return_val_if_fail (GST_BUFFER_DATA (buffer) != NULL, NULL);

  return GST_BUFFER_DATA (buffer) + gst_rtp_buffer_get_header_len (buffer);
}
コード例 #5
0
static void
compare_rtp_packets (GstBuffer * a, GstBuffer * b)
{
  GstRTPBuffer rtp_a = GST_RTP_BUFFER_INIT;
  GstRTPBuffer rtp_b = GST_RTP_BUFFER_INIT;

  gst_rtp_buffer_map (a, GST_MAP_READ, &rtp_a);
  gst_rtp_buffer_map (b, GST_MAP_READ, &rtp_b);

  fail_unless_equals_int (gst_rtp_buffer_get_header_len (&rtp_a),
      gst_rtp_buffer_get_header_len (&rtp_b));
  fail_unless_equals_int (gst_rtp_buffer_get_version (&rtp_a),
      gst_rtp_buffer_get_version (&rtp_b));
  fail_unless_equals_int (gst_rtp_buffer_get_ssrc (&rtp_a),
      gst_rtp_buffer_get_ssrc (&rtp_b));
  fail_unless_equals_int (gst_rtp_buffer_get_seq (&rtp_a),
      gst_rtp_buffer_get_seq (&rtp_b));
  fail_unless_equals_int (gst_rtp_buffer_get_csrc_count (&rtp_a),
      gst_rtp_buffer_get_csrc_count (&rtp_b));
  fail_unless_equals_int (gst_rtp_buffer_get_marker (&rtp_a),
      gst_rtp_buffer_get_marker (&rtp_b));
  fail_unless_equals_int (gst_rtp_buffer_get_payload_type (&rtp_a),
      gst_rtp_buffer_get_payload_type (&rtp_b));
  fail_unless_equals_int (gst_rtp_buffer_get_timestamp (&rtp_a),
      gst_rtp_buffer_get_timestamp (&rtp_b));
  fail_unless_equals_int (gst_rtp_buffer_get_extension (&rtp_a),
      gst_rtp_buffer_get_extension (&rtp_b));

  fail_unless_equals_int (gst_rtp_buffer_get_payload_len (&rtp_a),
      gst_rtp_buffer_get_payload_len (&rtp_b));
  fail_unless_equals_int (memcmp (gst_rtp_buffer_get_payload (&rtp_a),
          gst_rtp_buffer_get_payload (&rtp_b),
          gst_rtp_buffer_get_payload_len (&rtp_a)), 0);

  gst_rtp_buffer_unmap (&rtp_a);
  gst_rtp_buffer_unmap (&rtp_b);
}
コード例 #6
0
ファイル: gstrtpbuffer.c プロジェクト: zsx/ossbuild
/**
 * gst_rtp_buffer_get_payload_len:
 * @buffer: the buffer
 *
 * Get the length of the payload of the RTP packet in @buffer.
 *
 * Returns: The length of the payload in @buffer.
 */
guint
gst_rtp_buffer_get_payload_len (GstBuffer * buffer)
{
  guint len, size;
  guint8 *data;

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

  len = size - gst_rtp_buffer_get_header_len (buffer);

  if (GST_RTP_HEADER_PADDING (data))
    len -= data[size - 1];

  return len;
}
コード例 #7
0
EXPORT_C
#endif

guint
gst_rtp_buffer_get_payload_len (GstBuffer * buffer)
{
  guint len, size;

  g_return_val_if_fail (GST_IS_BUFFER (buffer), 0);
  g_return_val_if_fail (GST_BUFFER_DATA (buffer) != NULL, 0);

  size = GST_BUFFER_SIZE (buffer);

  len = size - gst_rtp_buffer_get_header_len (buffer);

  if (GST_RTP_HEADER_PADDING (buffer))
    len -= GST_BUFFER_DATA (buffer)[size - 1];

  return len;
}
コード例 #8
0
ファイル: fecdec.c プロジェクト: dasty/gstrtpfec
void fec_dec_push_fec_packet(fec_dec *dec, GstBuffer *packet)
{
    guint8 *fec_data;
    guint32 snbase;
    guint16 seqnum;
    GList *link;

    fec_data = GST_BUFFER_DATA(packet) + gst_rtp_buffer_get_header_len(packet);
    snbase = (((guint16)(fec_data[0])) << 8) | (((guint16)(fec_data[1])) << 0);
    seqnum = gst_rtp_buffer_get_seq(packet);

    GST_DEBUG("Received FEC packet, snbase %u, index %u, seqnum %u", snbase, (guint)(fec_data[12]), seqnum);

    if (snbase == dec->blacklisted_snbase)
    {
        GST_DEBUG("Ignoring FEC packet since data from this snbase has been restored already (= the packet is not needed)");
        return;
    }

    if (g_hash_table_lookup_extended(dec->fec_packet_set, GINT_TO_POINTER(seqnum), NULL, NULL))
    {
        GST_DEBUG("FEC packet with seqnum %u is already in queue - discarding duplicate", seqnum);
        return;
    }

    if (dec->cur_snbase != snbase)
    {
        GST_DEBUG("snbase changed from %u to %u - purging FEC queue (%u FEC packets and %u media packets present)", dec->cur_snbase, snbase, dec->num_received_fec_packets, dec->num_received_media_packets);
        g_queue_foreach(dec->fec_packets, fec_dec_clear_packet, NULL);
        g_queue_clear(dec->fec_packets);
        g_hash_table_remove_all(dec->fec_packet_set);
        dec->num_received_fec_packets = 0;
    }

    dec->cur_snbase = snbase;
    dec->has_snbase = TRUE;
    dec->received_media_packet_mask = 0;
    dec->num_received_media_packets = 0;
    dec->max_packet_size = 0;
    g_queue_push_tail(dec->fec_packets, gst_buffer_ref(packet));
    g_hash_table_add(dec->fec_packet_set, GINT_TO_POINTER(seqnum));
    ++dec->num_received_fec_packets;

    for (link = g_queue_peek_head_link(dec->media_packets); link != NULL;)
    {
        GstBuffer *media_packet;
        guint32 corrected_seqnum;

        media_packet = link->data;
        seqnum = gst_rtp_buffer_get_seq(media_packet);
        corrected_seqnum = fec_dec_correct_seqnum(dec, seqnum);

        if ((corrected_seqnum < snbase) || (corrected_seqnum > (snbase + dec->num_media_packets - 1)))
        {
            GList *old_link;

            GST_DEBUG("Found media packet with seqnum %u outside bounds [%u, %u] - purging", seqnum, snbase, snbase + dec->num_media_packets - 1);
            g_hash_table_remove(dec->media_packet_set, GINT_TO_POINTER(seqnum));
            gst_buffer_unref(media_packet);

            old_link = link;
            link = link->next;
            g_queue_delete_link(dec->media_packets, old_link);
        }
        else
        {
            dec->max_packet_size = MAX(dec->max_packet_size, GST_BUFFER_SIZE(media_packet));
            dec->received_media_packet_mask |= (1ul << (corrected_seqnum - dec->cur_snbase));
            ++dec->num_received_media_packets;
            link = link->next;
        }
    }

    fec_dec_check_state(dec);
}
コード例 #9
0
ファイル: fecdec.c プロジェクト: dasty/gstrtpfec
static void fec_dec_recover_packets(fec_dec *dec)
{
    of_session_t *session;
    of_rs_parameters_t params;
    void **encoding_symbol_tab;
    guint i;
    GList *link;

    assert(dec->has_snbase);
    assert(dec->max_packet_size > 0);

    encoding_symbol_tab = malloc(sizeof(void*) * (dec->num_media_packets + dec->num_fec_packets));
    memset(encoding_symbol_tab, 0, sizeof(void*) * (dec->num_media_packets + dec->num_fec_packets));

    for (link = g_queue_peek_head_link(dec->media_packets); link != NULL; link = link->next)
    {
        GstBuffer *media_packet;
        guint32 seqnum;

        media_packet = link->data;
        seqnum = fec_dec_correct_seqnum(dec, gst_rtp_buffer_get_seq(media_packet));

        encoding_symbol_tab[seqnum - dec->cur_snbase] = GST_BUFFER_DATA(media_packet);
    }

    for (link = g_queue_peek_head_link(dec->fec_packets); link != NULL; link = link->next)
    {
        GstBuffer *packet;
        guint8 *fec_data;
        guint8 esi;

        packet = link->data;
        fec_data = GST_BUFFER_DATA(packet) + gst_rtp_buffer_get_header_len(packet);
        esi = fec_data[12];

        encoding_symbol_tab[esi + dec->num_media_packets] = fec_data + RTP_FEC_HEADER_SIZE + 1;
    }

    params.nb_source_symbols = dec->num_media_packets;
    params.nb_repair_symbols = dec->num_fec_packets;
    params.encoding_symbol_length = dec->max_packet_size;

    of_create_codec_instance(&session, OF_CODEC_REED_SOLOMON_GF_2_8_STABLE, OF_DECODER, 0);
    of_set_fec_parameters(session, (of_parameters_t*)(&params));
    of_set_callback_functions(session, fec_dec_source_packet_cb, NULL, dec);

#if 1
    for (i = 0; i < dec->num_media_packets + dec->num_fec_packets; ++i)
    {
        if (encoding_symbol_tab[i] != 0)
            of_decode_with_new_symbol(session, encoding_symbol_tab[i], i);
    }
#else
    of_set_available_symbols(session, encoding_symbol_tab);
#endif

    if (!of_is_decoding_complete(session))
    {
        of_finish_decoding(session);
    }

    free(encoding_symbol_tab);
    of_release_codec_instance(session);
}
コード例 #10
0
/* Get a DV frame, chop it up in pieces, and push the pieces to the RTP layer.
 */
static GstFlowReturn
gst_rtp_dv_pay_handle_buffer (GstRTPBasePayload * basepayload,
    GstBuffer * buffer)
{
  GstRTPDVPay *rtpdvpay;
  guint max_payload_size;
  GstBuffer *outbuf;
  GstFlowReturn ret = GST_FLOW_OK;
  gint hdrlen;
  gsize size;
  GstMapInfo map;
  guint8 *data;
  guint8 *dest;
  guint filled;
  GstRTPBuffer rtp = { NULL, };

  rtpdvpay = GST_RTP_DV_PAY (basepayload);

  hdrlen = gst_rtp_buffer_calc_header_len (0);
  /* DV frames are made up from a bunch of DIF blocks. DIF blocks are 80 bytes
   * each, and we should put an integral number of them in each RTP packet.
   * Therefore, we round the available room down to the nearest multiple of 80.
   *
   * The available room is just the packet MTU, minus the RTP header length. */
  max_payload_size = ((GST_RTP_BASE_PAYLOAD_MTU (rtpdvpay) - hdrlen) / 80) * 80;

  /* The length of the buffer to transmit. */
  if (!gst_buffer_map (buffer, &map, GST_MAP_READ)) {
    GST_ELEMENT_ERROR (rtpdvpay, CORE, FAILED,
        (NULL), ("Failed to map buffer"));
    gst_buffer_unref (buffer);
    return GST_FLOW_ERROR;
  }
  data = map.data;
  size = map.size;

  GST_DEBUG_OBJECT (rtpdvpay,
      "DV RTP payloader got buffer of %" G_GSIZE_FORMAT
      " bytes, splitting in %u byte " "payload fragments, at time %"
      GST_TIME_FORMAT, size, max_payload_size,
      GST_TIME_ARGS (GST_BUFFER_PTS (buffer)));

  if (!rtpdvpay->negotiated) {
    gst_dv_pay_negotiate (rtpdvpay, data, size);
    /* if we have not yet scanned the stream for its type, do so now */
    rtpdvpay->negotiated = TRUE;
  }

  outbuf = NULL;
  dest = NULL;
  filled = 0;

  /* while we have a complete DIF chunks left */
  while (size >= 80) {
    /* Allocate a new buffer, set the timestamp */
    if (outbuf == NULL) {
      outbuf = gst_rtp_buffer_new_allocate (max_payload_size, 0, 0);
      GST_BUFFER_PTS (outbuf) = GST_BUFFER_PTS (buffer);

      if (!gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp)) {
        gst_buffer_unref (outbuf);
        GST_ELEMENT_ERROR (rtpdvpay, CORE, FAILED,
            (NULL), ("Failed to map RTP buffer"));
        ret = GST_FLOW_ERROR;
        goto beach;
      }
      dest = gst_rtp_buffer_get_payload (&rtp);
      filled = 0;
    }

    /* inspect the DIF chunk, if we don't need to include it, skip to the next one. */
    if (include_dif (rtpdvpay, data)) {
      /* copy data in packet */
      memcpy (dest, data, 80);

      dest += 80;
      filled += 80;
    }

    /* go to next dif chunk */
    size -= 80;
    data += 80;

    /* push out the buffer if the next one would exceed the max packet size or
     * when we are pushing the last packet */
    if (filled + 80 > max_payload_size || size < 80) {
      if (size < 160) {
        guint hlen;

        /* set marker */
        gst_rtp_buffer_set_marker (&rtp, TRUE);

        /* shrink buffer to last packet */
        hlen = gst_rtp_buffer_get_header_len (&rtp);
        gst_rtp_buffer_set_packet_len (&rtp, hlen + filled);
      }

      /* Push out the created piece, and check for errors. */
      gst_rtp_buffer_unmap (&rtp);
      ret = gst_rtp_base_payload_push (basepayload, outbuf);
      if (ret != GST_FLOW_OK)
        break;

      outbuf = NULL;
    }
  }

beach:
  gst_buffer_unmap (buffer, &map);
  gst_buffer_unref (buffer);

  return ret;
}
コード例 #11
0
ファイル: gstrtpasfpay.c プロジェクト: dylansong77/gstreamer
static GstFlowReturn
gst_rtp_asf_pay_handle_packet (GstRtpAsfPay * rtpasfpay, GstBuffer * buffer)
{
  GstBaseRTPPayload *rtppay;
  GstAsfPacketInfo *packetinfo;
  guint8 flags;
  guint8 *data;
  guint32 packet_util_size;
  guint32 packet_offset;
  guint32 size_left;
  GstFlowReturn ret = GST_FLOW_OK;

  rtppay = GST_BASE_RTP_PAYLOAD (rtpasfpay);
  packetinfo = &rtpasfpay->packetinfo;

  if (!gst_asf_parse_packet (buffer, packetinfo, TRUE,
          rtpasfpay->asfinfo.packet_size)) {
    GST_ERROR_OBJECT (rtpasfpay, "Error while parsing asf packet");
    gst_buffer_unref (buffer);
    return GST_FLOW_ERROR;
  }

  if (packetinfo->packet_size == 0)
    packetinfo->packet_size = rtpasfpay->asfinfo.packet_size;

  GST_LOG_OBJECT (rtpasfpay, "Packet size: %" G_GUINT32_FORMAT
      ", padding: %" G_GUINT32_FORMAT, packetinfo->packet_size,
      packetinfo->padding);

  /* update padding field to 0 */
  if (packetinfo->padding > 0) {
    GstAsfPacketInfo info;
    /* find padding field offset */
    guint offset = packetinfo->err_cor_len + 2 +
        gst_asf_get_var_size_field_len (packetinfo->packet_field_type) +
        gst_asf_get_var_size_field_len (packetinfo->seq_field_type);
    buffer = gst_buffer_make_writable (buffer);
    switch (packetinfo->padd_field_type) {
      case ASF_FIELD_TYPE_DWORD:
        GST_WRITE_UINT32_LE (&(GST_BUFFER_DATA (buffer)[offset]), 0);
        break;
      case ASF_FIELD_TYPE_WORD:
        GST_WRITE_UINT16_LE (&(GST_BUFFER_DATA (buffer)[offset]), 0);
        break;
      case ASF_FIELD_TYPE_BYTE:
        GST_BUFFER_DATA (buffer)[offset] = 0;
        break;
      case ASF_FIELD_TYPE_NONE:
      default:
        break;
    }
    gst_asf_parse_packet (buffer, &info, FALSE, 0);
  }

  if (packetinfo->padding != 0)
    packet_util_size = rtpasfpay->asfinfo.packet_size - packetinfo->padding;
  else
    packet_util_size = packetinfo->packet_size;
  packet_offset = 0;
  while (packet_util_size > 0) {
    /* Even if we don't fill completely an output buffer we
     * push it when we add an fragment. Because it seems that
     * it is not possible to determine where a asf packet
     * fragment ends inside a rtp packet payload.
     * This flag tells us to push the packet.
     */
    gboolean force_push = FALSE;

    /* we have no output buffer pending, create one */
    if (rtpasfpay->current == NULL) {
      GST_LOG_OBJECT (rtpasfpay, "Creating new output buffer");
      rtpasfpay->current =
          gst_rtp_buffer_new_allocate_len (GST_BASE_RTP_PAYLOAD_MTU (rtpasfpay),
          0, 0);
      rtpasfpay->cur_off = gst_rtp_buffer_get_header_len (rtpasfpay->current);
      rtpasfpay->has_ts = FALSE;
      rtpasfpay->marker = FALSE;
    }
    data = GST_BUFFER_DATA (rtpasfpay->current) + rtpasfpay->cur_off;
    size_left = GST_BUFFER_SIZE (rtpasfpay->current) - rtpasfpay->cur_off;

    GST_DEBUG_OBJECT (rtpasfpay, "Input buffer bytes consumed: %"
        G_GUINT32_FORMAT "/%" G_GUINT32_FORMAT, packet_offset,
        GST_BUFFER_SIZE (buffer));

    GST_DEBUG_OBJECT (rtpasfpay, "Output rtpbuffer status");
    GST_DEBUG_OBJECT (rtpasfpay, "Current offset: %" G_GUINT32_FORMAT,
        rtpasfpay->cur_off);
    GST_DEBUG_OBJECT (rtpasfpay, "Size left: %" G_GUINT32_FORMAT, size_left);
    GST_DEBUG_OBJECT (rtpasfpay, "Has ts: %s",
        rtpasfpay->has_ts ? "yes" : "no");
    if (rtpasfpay->has_ts) {
      GST_DEBUG_OBJECT (rtpasfpay, "Ts: %" G_GUINT32_FORMAT, rtpasfpay->ts);
    }

    flags = 0;
    if (packetinfo->has_keyframe) {
      flags = flags | 0x80;
    }
    flags = flags | 0x20;       /* Relative timestamp is present */

    if (!rtpasfpay->has_ts) {
      /* this is the first asf packet, its send time is the 
       * rtp packet timestamp */
      rtpasfpay->has_ts = TRUE;
      rtpasfpay->ts = packetinfo->send_time;
    }

    if (GST_BUFFER_SIZE (rtpasfpay->current) - rtpasfpay->cur_off >=
        packet_util_size + 8) {
      /* enough space for the rest of the packet */
      if (packet_offset == 0) {
        flags = flags | 0x40;
        GST_WRITE_UINT24_BE (data + 1, packet_util_size);
      } else {
        GST_WRITE_UINT24_BE (data + 1, packet_offset);
        force_push = TRUE;
      }
      data[0] = flags;
      GST_WRITE_UINT32_BE (data + 4,
          (gint32) (packetinfo->send_time) - (gint32) rtpasfpay->ts);
      memcpy (data + 8, GST_BUFFER_DATA (buffer) + packet_offset,
          packet_util_size);

      /* updating status variables */
      rtpasfpay->cur_off += 8 + packet_util_size;
      size_left -= packet_util_size + 8;
      packet_offset += packet_util_size;
      packet_util_size = 0;
      rtpasfpay->marker = TRUE;
    } else {
      /* fragment packet */
      data[0] = flags;
      GST_WRITE_UINT24_BE (data + 1, packet_offset);
      GST_WRITE_UINT32_BE (data + 4,
          (gint32) (packetinfo->send_time) - (gint32) rtpasfpay->ts);
      memcpy (data + 8, GST_BUFFER_DATA (buffer) + packet_offset,
          size_left - 8);

      /* updating status variables */
      rtpasfpay->cur_off += size_left;
      packet_offset += size_left - 8;
      packet_util_size -= size_left - 8;
      size_left = 0;
      force_push = TRUE;
    }

    /* there is not enough room for any more buffers */
    if (force_push || size_left <= 8) {

      if (size_left != 0) {
        /* trim remaining bytes not used */
        GstBuffer *aux = gst_buffer_create_sub (rtpasfpay->current, 0,
            GST_BUFFER_SIZE (rtpasfpay->current) - size_left);
        gst_buffer_unref (rtpasfpay->current);
        rtpasfpay->current = aux;
      }
      gst_rtp_buffer_set_ssrc (rtpasfpay->current, rtppay->current_ssrc);
      gst_rtp_buffer_set_marker (rtpasfpay->current, rtpasfpay->marker);
      gst_rtp_buffer_set_payload_type (rtpasfpay->current,
          GST_BASE_RTP_PAYLOAD_PT (rtppay));
      gst_rtp_buffer_set_seq (rtpasfpay->current, rtppay->seqnum + 1);
      gst_rtp_buffer_set_timestamp (rtpasfpay->current, packetinfo->send_time);

      GST_BUFFER_TIMESTAMP (rtpasfpay->current) = GST_BUFFER_TIMESTAMP (buffer);

      gst_buffer_set_caps (rtpasfpay->current,
          GST_PAD_CAPS (GST_BASE_RTP_PAYLOAD_SRCPAD (rtppay)));

      rtppay->seqnum++;
      rtppay->timestamp = packetinfo->send_time;

      GST_DEBUG_OBJECT (rtpasfpay, "Pushing rtp buffer");
      ret =
          gst_pad_push (GST_BASE_RTP_PAYLOAD_SRCPAD (rtppay),
          rtpasfpay->current);
      rtpasfpay->current = NULL;
      if (ret != GST_FLOW_OK) {
        gst_buffer_unref (buffer);
        return ret;
      }
    }
  }
  gst_buffer_unref (buffer);
  return ret;
}