예제 #1
0
/**
 * rtp_jitter_buffer_insert:
 * @jbuf: an #RTPJitterBuffer
 * @buf: a buffer
 * @time: a running_time when this buffer was received in nanoseconds
 * @clock_rate: the clock-rate of the payload of @buf
 * @max_delay: the maximum lateness of @buf
 * @tail: TRUE when the tail element changed.
 *
 * Inserts @buf into the packet queue of @jbuf. The sequence number of the
 * packet will be used to sort the packets. This function takes ownerhip of
 * @buf when the function returns %TRUE.
 * @buf should have writable metadata when calling this function.
 *
 * Returns: %FALSE if a packet with the same number already existed.
 */
gboolean
rtp_jitter_buffer_insert (RTPJitterBuffer * jbuf, GstBuffer * buf,
    GstClockTime time, guint32 clock_rate, GstClockTime max_delay,
    gboolean * tail)
{
  GList *list;
  guint32 rtptime;
  guint16 seqnum;

  g_return_val_if_fail (jbuf != NULL, FALSE);
  g_return_val_if_fail (buf != NULL, FALSE);

  seqnum = gst_rtp_buffer_get_seq (buf);

  /* loop the list to skip strictly smaller seqnum buffers */
  for (list = jbuf->packets->head; list; list = g_list_next (list)) {
    guint16 qseq;
    gint gap;

    qseq = gst_rtp_buffer_get_seq (GST_BUFFER_CAST (list->data));

    /* compare the new seqnum to the one in the buffer */
    gap = gst_rtp_buffer_compare_seqnum (seqnum, qseq);

    /* we hit a packet with the same seqnum, notify a duplicate */
    if (G_UNLIKELY (gap == 0))
      goto duplicate;

    /* seqnum > qseq, we can stop looking */
    if (G_LIKELY (gap < 0))
      break;
  }

  /* do skew calculation by measuring the difference between rtptime and the
   * receive time, this function will retimestamp @buf with the skew corrected
   * running time. */
  rtptime = gst_rtp_buffer_get_timestamp (buf);
  time = calculate_skew (jbuf, rtptime, time, clock_rate, max_delay);
  GST_BUFFER_TIMESTAMP (buf) = time;

  /* It's more likely that the packet was inserted in the front of the buffer */
  if (G_LIKELY (list))
    g_queue_insert_before (jbuf->packets, list, buf);
  else
    g_queue_push_tail (jbuf->packets, buf);

  /* tail was changed when we did not find a previous packet, we set the return
   * flag when requested. */
  if (G_LIKELY (tail))
    *tail = (list == NULL);

  return TRUE;

  /* ERRORS */
duplicate:
  {
    GST_WARNING ("duplicate packet %d found", (gint) seqnum);
    return FALSE;
  }
}
예제 #2
0
static gint
_compare_fec_map_info (gconstpointer a, gconstpointer b, gpointer userdata)
{
  guint16 aseq =
      gst_rtp_buffer_get_seq (&RTP_FEC_MAP_INFO_NTH (userdata, a)->rtp);
  guint16 bseq =
      gst_rtp_buffer_get_seq (&RTP_FEC_MAP_INFO_NTH (userdata, b)->rtp);
  return gst_rtp_buffer_compare_seqnum (bseq, aseq);
}
static GstBuffer *
gst_rtp_pcma_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
{
    GstBuffer *outbuf = NULL;
    gboolean marker;
    guint len;

    marker = gst_rtp_buffer_get_marker (buf);

    GST_DEBUG ("process : got %d bytes, mark %d ts %u seqn %d",
               GST_BUFFER_SIZE (buf), marker,
               gst_rtp_buffer_get_timestamp (buf), gst_rtp_buffer_get_seq (buf));

    len = gst_rtp_buffer_get_payload_len (buf);
    outbuf = gst_rtp_buffer_get_payload_buffer (buf);

    if (outbuf) {
        GST_BUFFER_DURATION (outbuf) =
            gst_util_uint64_scale_int (len, GST_SECOND, depayload->clock_rate);

        if (marker) {
            /* mark start of talkspurt with DISCONT */
            GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
        }
    }

    return outbuf;
}
예제 #4
0
파일: rtpmux.c 프로젝트: zsx/ossbuild
void
lock_check_cb (GstPad * pad, int i)
{
  GstStructure *s;
  GstEvent *event;

  if (i % 2)
    s = gst_structure_new ("stream-lock", "lock", G_TYPE_BOOLEAN, FALSE, NULL);
  else
    s = gst_structure_new ("stream-lock", "lock", G_TYPE_BOOLEAN, TRUE, NULL);

  event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM_OOB, s);
  gst_pad_push_event (pad, event);

  if (i % 2) {
    fail_unless (buffers == NULL);
  } else {
    fail_unless (buffers && g_list_length (buffers) == 1);
    fail_unless (gst_rtp_buffer_get_ssrc (buffers->data) == 55);
    fail_unless (gst_rtp_buffer_get_timestamp (buffers->data) ==
        200 - 57 + 1000 + i);
    fail_unless (gst_rtp_buffer_get_seq (buffers->data) == 100 + 1 + (i / 2));
    g_list_foreach (buffers, (GFunc) gst_buffer_unref, NULL);
    g_list_free (buffers);
    buffers = NULL;
  }
}
예제 #5
0
static GstBuffer *
gst_rtp_pcmu_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
{
  GstBuffer *outbuf = NULL;
  guint len;
  gboolean marker;
  GstRTPBuffer rtp = { NULL };

  gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);

  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 (buf), marker,
      gst_rtp_buffer_get_timestamp (&rtp), gst_rtp_buffer_get_seq (&rtp));

  len = gst_rtp_buffer_get_payload_len (&rtp);
  outbuf = gst_rtp_buffer_get_payload_buffer (&rtp);
  gst_rtp_buffer_unmap (&rtp);

  if (outbuf) {
    GST_BUFFER_DURATION (outbuf) =
        gst_util_uint64_scale_int (len, GST_SECOND, depayload->clock_rate);

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

  return outbuf;
}
예제 #6
0
static GstBuffer *
gst_rtp_ilbc_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
{
  GstBuffer *outbuf;
  gboolean marker;
  GstRTPBuffer rtp = { NULL };

  gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);

  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 (buf), marker,
      gst_rtp_buffer_get_timestamp (&rtp), gst_rtp_buffer_get_seq (&rtp));

  outbuf = gst_rtp_buffer_get_payload_buffer (&rtp);

  gst_rtp_buffer_unmap (&rtp);

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

  return outbuf;
}
예제 #7
0
static GstBuffer *
gst_rtp_gsm_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
{
  GstBuffer *outbuf = NULL;
  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;
}
예제 #8
0
파일: rtpmux.c 프로젝트: zsx/ossbuild
void
basic_check_cb (GstPad * pad, int i)
{
  fail_unless (buffers && g_list_length (buffers) == 1);
  fail_unless (gst_rtp_buffer_get_ssrc (buffers->data) == 55);
  fail_unless (gst_rtp_buffer_get_timestamp (buffers->data) ==
      200 - 57 + 1000 + i);
  fail_unless (gst_rtp_buffer_get_seq (buffers->data) == 100 + 1 + i);
}
예제 #9
0
static GstPadProbeReturn
rtpsession_sinkpad_probe2 (GstPad * pad, GstPadProbeInfo * info,
    gpointer user_data)
{
  GstPadProbeReturn ret = GST_PAD_PROBE_OK;

  if (info->type == (GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_PUSH)) {
    GstBuffer *buffer = GST_BUFFER (info->data);
    GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
    guint payload_type = 0;

    static gint i = 0;

    /* retrieve current ssrc for retransmission stream only */
    gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp);
    payload_type = gst_rtp_buffer_get_payload_type (&rtp);
    if (payload_type == 99) {
      if (i < 3)
        rtx_ssrc_before = gst_rtp_buffer_get_ssrc (&rtp);
      else
        rtx_ssrc_after = gst_rtp_buffer_get_ssrc (&rtp);
    } else {
      /* ask to retransmit every packet */
      GstEvent *event = gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
          gst_structure_new ("GstRTPRetransmissionRequest",
              "seqnum", G_TYPE_UINT, gst_rtp_buffer_get_seq (&rtp),
              "ssrc", G_TYPE_UINT, gst_rtp_buffer_get_ssrc (&rtp),
              NULL));
      gst_pad_push_event (pad, event);

      if (i < 3)
        ssrc_before = gst_rtp_buffer_get_ssrc (&rtp);
      else
        ssrc_after = gst_rtp_buffer_get_ssrc (&rtp);
    }
    gst_rtp_buffer_unmap (&rtp);

    /* feint a collision on recv_rtcp_sink pad of gstrtpsession
     * (note that after being marked as collied the rtpsession ignores
     * all non bye packets)
     */
    if (i == 2) {
      GstBuffer *rtcp_buffer = create_rtcp_app (rtx_ssrc_before, 0);

      /* push collied packet on recv_rtcp_sink */
      gst_pad_push (srcpad, rtcp_buffer);
    }

    ++i;
  }

  return ret;
}
예제 #10
0
static void
basic_check_cb (GstPad * pad, int i)
{
  GstRTPBuffer rtpbuffer = GST_RTP_BUFFER_INIT;
  fail_unless (buffers && g_list_length (buffers) == 1);

  gst_rtp_buffer_map (buffers->data, GST_MAP_READ, &rtpbuffer);
  fail_unless_equals_int (66, gst_rtp_buffer_get_ssrc (&rtpbuffer));
  fail_unless_equals_int64 (200 - 57 + 1000 + i,
      gst_rtp_buffer_get_timestamp (&rtpbuffer));
  fail_unless_equals_int (100 + 1 + i, gst_rtp_buffer_get_seq (&rtpbuffer));
  gst_rtp_buffer_unmap (&rtpbuffer);
}
예제 #11
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);
}
예제 #12
0
static void
gst_rtp_ulpfec_dec_start (GstRtpUlpFecDec * self, GstBufferList * buflist,
    guint8 fec_pt, guint16 lost_seq)
{
  guint fec_packets = 0;
  gsize i;

  g_assert (NULL == self->info_media);
  g_assert (0 == self->info_fec->len);
  g_assert (0 == self->info_arr->len);

  g_array_set_size (self->info_arr, gst_buffer_list_length (buflist));

  for (i = 0;
      i < gst_buffer_list_length (buflist) && !self->lost_packet_from_storage;
      ++i) {
    GstBuffer *buffer = gst_buffer_list_get (buflist, i);
    RtpUlpFecMapInfo *info = RTP_FEC_MAP_INFO_NTH (self, i);

    if (!rtp_ulpfec_map_info_map (gst_buffer_ref (buffer), info))
      g_assert_not_reached ();

    if (fec_pt == gst_rtp_buffer_get_payload_type (&info->rtp)) {
      GST_DEBUG_RTP_PACKET (self, "rtp header (fec)", &info->rtp);

      ++fec_packets;
      if (rtp_ulpfec_buffer_is_valid (&info->rtp)) {
        GST_DEBUG_FEC_PACKET (self, &info->rtp);
        g_ptr_array_add (self->info_fec, GUINT_TO_POINTER (i));
      }
    } else {
      GST_LOG_RTP_PACKET (self, "rtp header (incoming)", &info->rtp);

      if (lost_seq == gst_rtp_buffer_get_seq (&info->rtp)) {
        GST_DEBUG_OBJECT (self, "Received lost packet from from the storage");
        g_list_free (self->info_media);
        self->info_media = NULL;
        self->lost_packet_from_storage = TRUE;
      }
      self->info_media =
          g_list_insert_sorted_with_data (self->info_media,
          GUINT_TO_POINTER (i), _compare_fec_map_info, self);
    }
  }
  if (!self->lost_packet_from_storage) {
    self->fec_packets_received += fec_packets;
    self->fec_packets_rejected += fec_packets - self->info_fec->len;
  }
}
예제 #13
0
static guint64
gst_rtp_ulpfec_dec_get_media_buffers_mask (GstRtpUlpFecDec * self,
    guint16 fec_seq_base)
{
  guint64 mask = 0;
  GList *it;

  for (it = self->info_media; it; it = it->next) {
    RtpUlpFecMapInfo *info = RTP_FEC_MAP_INFO_NTH (self, it->data);
    mask |=
        rtp_ulpfec_packet_mask_from_seqnum (gst_rtp_buffer_get_seq (&info->rtp),
        fec_seq_base, TRUE);
  }
  return mask;
}
static GstFlowReturn gst_scream_queue_sink_chain(GstPad *pad, GstObject *parent, GstBuffer *buffer)
{
    GstScreamQueue *self = GST_SCREAM_QUEUE(parent);
    GstRTPBuffer rtp_buffer = GST_RTP_BUFFER_INIT;
    GstFlowReturn flow_ret = GST_FLOW_OK;
    GstScreamDataQueueRtpItem *rtp_item;

    if (GST_PAD_IS_FLUSHING(pad)) {
        flow_ret = GST_FLOW_FLUSHING;
        goto end;
    }

    if (!gst_rtp_buffer_map(buffer, GST_MAP_READ, &rtp_buffer)) {
        flow_ret = GST_FLOW_ERROR;
        goto end;
    }

    rtp_item = g_slice_new(GstScreamDataQueueRtpItem);
    ((GstDataQueueItem *)rtp_item)->object = GST_MINI_OBJECT(buffer);
    ((GstDataQueueItem *)rtp_item)->size = gst_buffer_get_size(buffer);
    ((GstDataQueueItem *)rtp_item)->visible = TRUE;
    ((GstDataQueueItem *)rtp_item)->duration = GST_BUFFER_DURATION(buffer);
    ((GstDataQueueItem *)rtp_item)->destroy = (GDestroyNotify) gst_scream_data_queue_rtp_item_free;

    ((GstScreamDataQueueItem *)rtp_item)->type = GST_SCREAM_DATA_QUEUE_ITEM_TYPE_RTP;
    ((GstScreamDataQueueItem *)rtp_item)->rtp_ssrc = gst_rtp_buffer_get_ssrc(&rtp_buffer);
    rtp_item->rtp_pt = gst_rtp_buffer_get_payload_type(&rtp_buffer);
    rtp_item->gst_ts = GST_BUFFER_PTS(buffer);
    rtp_item->rtp_seq = gst_rtp_buffer_get_seq(&rtp_buffer);
    rtp_item->rtp_ts = gst_rtp_buffer_get_timestamp(&rtp_buffer);
    rtp_item->rtp_marker = gst_rtp_buffer_get_marker(&rtp_buffer);
    rtp_item->rtp_payload_size = gst_rtp_buffer_get_payload_len(&rtp_buffer);
    rtp_item->enqueued_time = get_gst_time_us(self);
    gst_rtp_buffer_unmap(&rtp_buffer);

    if (self->pass_through) {
        rtp_item->adapted = FALSE;
        GST_LOG_OBJECT(self, "passing through: pt = %u, seq: %u, pass: %u", rtp_item->rtp_pt, rtp_item->rtp_seq, self->pass_through);
        gst_data_queue_push(self->approved_packets, (GstDataQueueItem *)rtp_item);
        goto end;
    }

    GST_LOG_OBJECT(self, "queuing: pt = %u, seq: %u, pass: %u", rtp_item->rtp_pt, rtp_item->rtp_seq, self->pass_through);
    g_async_queue_push(self->incoming_packets, (gpointer)rtp_item);

end:
    return flow_ret;
}
예제 #15
0
static GstBuffer *
gst_rtp_celt_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
{
  GstBuffer *outbuf = NULL;
  guint8 *payload;
  guint offset, pos, payload_len, total_size, size;
  guint8 s;

  GST_DEBUG ("process : got %d bytes, mark %d ts %u seqn %d",
      GST_BUFFER_SIZE (buf),
      gst_rtp_buffer_get_marker (buf),
      gst_rtp_buffer_get_timestamp (buf), gst_rtp_buffer_get_seq (buf));

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

  /* 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) {
    size = 0;
    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) {
    size = 0;
    do {
      s = payload[pos++];
      size += s;
      total_size += size + 1;
    } while (s == 0xff);

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

    gst_base_rtp_depayload_push (depayload, outbuf);
  }
  return NULL;
}
예제 #16
0
static GstBuffer *
gst_rtp_ulpfec_dec_recover_from_storage (GstRtpUlpFecDec * self,
    guint8 * dst_pt, guint16 * dst_seq)
{
  RtpUlpFecMapInfo *info;

  if (self->lost_packet_returned)
    return NULL;

  g_assert (g_list_length (self->info_media) == 1);

  info = RTP_FEC_MAP_INFO_NTH (self, self->info_media->data);
  *dst_seq = gst_rtp_buffer_get_seq (&info->rtp);
  *dst_pt = gst_rtp_buffer_get_payload_type (&info->rtp);
  self->lost_packet_returned = TRUE;
  GST_DEBUG_RTP_PACKET (self, "rtp header (recovered)", &info->rtp);
  return gst_buffer_ref (info->rtp.buffer);
}
예제 #17
0
static GstBuffer *
gst_rtp_ilbc_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
{
  GstBuffer *outbuf;
  gboolean marker;

  marker = gst_rtp_buffer_get_marker (buf);

  GST_DEBUG ("process : got %d bytes, mark %d ts %u seqn %d",
      GST_BUFFER_SIZE (buf), marker,
      gst_rtp_buffer_get_timestamp (buf), gst_rtp_buffer_get_seq (buf));

  outbuf = gst_rtp_buffer_get_payload_buffer (buf);

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

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

    return outbuf;
}
예제 #19
0
static GstBuffer *
gst_rtp_speex_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
{
  GstBuffer *outbuf = NULL;
  GstRTPBuffer rtp = { NULL };

  gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);

  GST_DEBUG ("process : got %" G_GSIZE_FORMAT " bytes, mark %d ts %u seqn %d",
      gst_buffer_get_size (buf),
      gst_rtp_buffer_get_marker (&rtp),
      gst_rtp_buffer_get_timestamp (&rtp), gst_rtp_buffer_get_seq (&rtp));

  /* nothing special to be done */
  outbuf = gst_rtp_buffer_get_payload_buffer (&rtp);
  gst_rtp_buffer_unmap (&rtp);

  if (outbuf)
    GST_BUFFER_DURATION (outbuf) = 20 * GST_MSECOND;

  return outbuf;
}
예제 #20
0
static void
packet_recovered_cb (GObject * internal_storage, GstBuffer * buffer,
    GList * infos)
{
  gboolean found = FALSE;
  GstRTPBuffer rtp = { NULL };

  fail_unless (gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp));

  for (GList * it = infos; it; it = it->next) {
    RecoveredPacketInfo *info = it->data;
    if (gst_rtp_buffer_get_seq (&rtp) == info->seq) {
      fail_unless_equals_int (gst_rtp_buffer_get_payload_type (&rtp), info->pt);
      fail_unless_equals_int (gst_rtp_buffer_get_ssrc (&rtp), info->ssrc);
      found = TRUE;
      break;
    }
  }

  gst_rtp_buffer_unmap (&rtp);
  fail_unless (found);
}
예제 #21
0
static void
lock_check_cb (GstPad * pad, int i)
{
  GstBuffer *inbuf;

  if (i % 2) {
    fail_unless (buffers == NULL);
  } else {
    GstRTPBuffer rtpbuffer = GST_RTP_BUFFER_INIT;

    fail_unless (buffers && g_list_length (buffers) == 1);
    gst_rtp_buffer_map (buffers->data, GST_MAP_READ, &rtpbuffer);
    fail_unless_equals_int (66, gst_rtp_buffer_get_ssrc (&rtpbuffer));
    fail_unless_equals_int64 (200 - 57 + 1000 + i,
        gst_rtp_buffer_get_timestamp (&rtpbuffer));
    fail_unless_equals_int (100 + 1 + i, gst_rtp_buffer_get_seq (&rtpbuffer));
    gst_rtp_buffer_unmap (&rtpbuffer);

    inbuf = gst_rtp_buffer_new_allocate (10, 0, 0);
    GST_BUFFER_PTS (inbuf) = i * 1000 + 500;
    GST_BUFFER_DURATION (inbuf) = 1000;
    gst_rtp_buffer_map (inbuf, GST_MAP_WRITE, &rtpbuffer);
    gst_rtp_buffer_set_version (&rtpbuffer, 2);
    gst_rtp_buffer_set_payload_type (&rtpbuffer, 98);
    gst_rtp_buffer_set_ssrc (&rtpbuffer, 44);
    gst_rtp_buffer_set_timestamp (&rtpbuffer, 200 + i);
    gst_rtp_buffer_set_seq (&rtpbuffer, 2000 + i);
    gst_rtp_buffer_unmap (&rtpbuffer);
    fail_unless (gst_pad_push (pad, inbuf) == GST_FLOW_OK);


    g_list_foreach (buffers, (GFunc) gst_buffer_unref, NULL);
    g_list_free (buffers);
    buffers = NULL;
  }
}
예제 #22
0
static GstBuffer *
gst_rtp_sv3v_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
{

  GstRtpSV3VDepay *rtpsv3vdepay;
  GstBuffer *outbuf;
  guint16 seq;

  rtpsv3vdepay = GST_RTP_SV3V_DEPAY (depayload);

  if (!gst_rtp_buffer_validate (buf))
    goto bad_packet;

  /* flush on sequence number gaps */
  seq = gst_rtp_buffer_get_seq (buf);
  if (seq != rtpsv3vdepay->nextseq) {
    gst_adapter_clear (rtpsv3vdepay->adapter);
  }
  rtpsv3vdepay->nextseq = seq + 1;

  {
    gint payload_len;
    guint8 *payload;
    gboolean M;
    gboolean C, S, E;

    payload_len = gst_rtp_buffer_get_payload_len (buf);
    if (payload_len < 3)
      goto bad_packet;

    payload = gst_rtp_buffer_get_payload (buf);

    M = gst_rtp_buffer_get_marker (buf);

    /* This is all a guess:
     *                      1 1 1 1 1 1
     *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 
     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     * |0|C|S|E|0|0|0|0|0|0|0|0|0|0|0|0|
     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     *
     * C: config, packet contains config info
     * S: start, packet contains start of frame
     * E: end, packet contains end of frame
     */
    /* this seems to indicate a packet with a config string sent before each
     * keyframe */
    C = (payload[0] & 0x40) == 0x40;

    /* redundant with the RTP marker bit */
    S = (payload[0] & 0x20) == 0x20;
    E = (payload[0] & 0x10) == 0x10;

    if (C) {
      GstCaps *caps;
      GstBuffer *codec_data;
      GValue value = { 0 };

      /* if we already have caps, we don't need to do anything. FIXME, check if
       * something changed. */
      if (GST_PAD_CAPS (GST_BASE_RTP_DEPAYLOAD_SRCPAD (depayload)))
        return NULL;

      /* No idea... These are the two examples I found.. */
      if (payload[2] == 0x1d) {
        rtpsv3vdepay->width = 160;
        rtpsv3vdepay->height = 128;
      } else if (payload[2] == 0xdd) {
        rtpsv3vdepay->width = 320;
        rtpsv3vdepay->height = 240;
      }

      /* we need a dummy empty codec data */
      g_value_init (&value, GST_TYPE_BUFFER);
      gst_value_deserialize (&value, "");
      codec_data = gst_value_get_buffer (&value);

      caps = gst_caps_new_simple ("video/x-svq",
          "svqversion", G_TYPE_INT, 3,
          "width", G_TYPE_INT, rtpsv3vdepay->width,
          "height", G_TYPE_INT, rtpsv3vdepay->height,
          "codec_data", GST_TYPE_BUFFER, codec_data, NULL);
      gst_pad_set_caps (GST_BASE_RTP_DEPAYLOAD_SRCPAD (depayload), caps);
      gst_caps_unref (caps);
      g_value_unset (&value);

      return NULL;
    }

    /* store data in adapter, stip off 2 bytes header */
    outbuf = gst_rtp_buffer_get_payload_subbuffer (buf, 2, -1);
    gst_adapter_push (rtpsv3vdepay->adapter, outbuf);

    if (M) {
      /* frame is completed: push contents of adapter */
      guint avail;

      avail = gst_adapter_available (rtpsv3vdepay->adapter);
      outbuf = gst_adapter_take_buffer (rtpsv3vdepay->adapter, avail);

      /* timestamp for complete buffer is that of last buffer as well */
      gst_buffer_set_caps (outbuf, GST_PAD_CAPS (depayload->srcpad));

      return outbuf;
    }
  }
  return NULL;

  /* ERRORS */
bad_packet:
  {
    GST_ELEMENT_WARNING (rtpsv3vdepay, STREAM, DECODE,
        ("Packet did not validate"), (NULL));
    return NULL;
  }
}
static GstFlowReturn
gst_base_rtp_depayload_chain (GstPad * pad, GstBuffer * in)
{
  GstBaseRTPDepayload *filter;
  GstBaseRTPDepayloadPrivate *priv;
  GstBaseRTPDepayloadClass *bclass;
  GstFlowReturn ret = GST_FLOW_OK;
  GstBuffer *out_buf;
  GstClockTime timestamp;
  guint16 seqnum;
  guint32 rtptime;
  gboolean reset_seq, discont;
  gint gap;

  filter = GST_BASE_RTP_DEPAYLOAD (GST_OBJECT_PARENT (pad));
  priv = filter->priv;

  /* we must have a setcaps first */
  if (G_UNLIKELY (!priv->negotiated))
    goto not_negotiated;

  /* we must validate, it's possible that this element is plugged right after a
   * network receiver and we don't want to operate on invalid data */
  if (G_UNLIKELY (!gst_rtp_buffer_validate (in)))
    goto invalid_buffer;

  priv->discont = GST_BUFFER_IS_DISCONT (in);

  timestamp = GST_BUFFER_TIMESTAMP (in);
  /* convert to running_time and save the timestamp, this is the timestamp
   * we put on outgoing buffers. */
  timestamp = gst_segment_to_running_time (&filter->segment, GST_FORMAT_TIME,
      timestamp);
  priv->timestamp = timestamp;
  priv->duration = GST_BUFFER_DURATION (in);

  seqnum = gst_rtp_buffer_get_seq (in);
  rtptime = gst_rtp_buffer_get_timestamp (in);
  reset_seq = TRUE;
  discont = FALSE;

  GST_LOG_OBJECT (filter, "discont %d, seqnum %u, rtptime %u, timestamp %"
      GST_TIME_FORMAT, priv->discont, seqnum, rtptime,
      GST_TIME_ARGS (timestamp));

  /* Check seqnum. This is a very simple check that makes sure that the seqnums
   * are striclty increasing, dropping anything that is out of the ordinary. We
   * can only do this when the next_seqnum is known. */
  if (G_LIKELY (priv->next_seqnum != -1)) {
    gap = gst_rtp_buffer_compare_seqnum (seqnum, priv->next_seqnum);

    /* if we have no gap, all is fine */
    if (G_UNLIKELY (gap != 0)) {
      GST_LOG_OBJECT (filter, "got packet %u, expected %u, gap %d", seqnum,
          priv->next_seqnum, gap);
      if (gap < 0) {
        /* seqnum > next_seqnum, we are missing some packets, this is always a
         * DISCONT. */
        GST_LOG_OBJECT (filter, "%d missing packets", gap);
        discont = TRUE;
      } else {
        /* seqnum < next_seqnum, we have seen this packet before or the sender
         * could be restarted. If the packet is not too old, we throw it away as
         * a duplicate, otherwise we mark discont and continue. 100 misordered
         * packets is a good threshold. See also RFC 4737. */
        if (gap < 100)
          goto dropping;

        GST_LOG_OBJECT (filter,
            "%d > 100, packet too old, sender likely restarted", gap);
        discont = TRUE;
      }
    }
  }
  priv->next_seqnum = (seqnum + 1) & 0xffff;

  if (G_UNLIKELY (discont && !priv->discont)) {
    GST_LOG_OBJECT (filter, "mark DISCONT on input buffer");
    /* we detected a seqnum discont but the buffer was not flagged with a discont,
     * set the discont flag so that the subclass can throw away old data. */
    priv->discont = TRUE;
    GST_BUFFER_FLAG_SET (in, GST_BUFFER_FLAG_DISCONT);
  }

  bclass = GST_BASE_RTP_DEPAYLOAD_GET_CLASS (filter);

  if (G_UNLIKELY (bclass->process == NULL))
    goto no_process;

  /* let's send it out to processing */
  out_buf = bclass->process (filter, in);
  if (out_buf) {
    /* we pass rtptime as backward compatibility, in reality, the incomming
     * buffer timestamp is always applied to the outgoing packet. */
    ret = gst_base_rtp_depayload_push_ts (filter, rtptime, out_buf);
  }
  gst_buffer_unref (in);

  return ret;

  /* ERRORS */
not_negotiated:
  {
    /* this is not fatal but should be filtered earlier */
    GST_ELEMENT_ERROR (filter, CORE, NEGOTIATION, (NULL),
        ("Not RTP format was negotiated"));
    gst_buffer_unref (in);
    return GST_FLOW_NOT_NEGOTIATED;
  }
invalid_buffer:
  {
    /* this is not fatal but should be filtered earlier */
    GST_ELEMENT_WARNING (filter, STREAM, DECODE, (NULL),
        ("Received invalid RTP payload, dropping"));
    gst_buffer_unref (in);
    return GST_FLOW_OK;
  }
dropping:
  {
    GST_WARNING_OBJECT (filter, "%d <= 100, dropping old packet", gap);
    gst_buffer_unref (in);
    return GST_FLOW_OK;
  }
no_process:
  {
    /* this is not fatal but should be filtered earlier */
    GST_ELEMENT_ERROR (filter, STREAM, NOT_IMPLEMENTED, (NULL),
        ("The subclass does not have a process method"));
    gst_buffer_unref (in);
    return GST_FLOW_ERROR;
  }
}
예제 #24
0
gboolean
kms_rtp_synchronizer_process_rtp_buffer_mapped (KmsRtpSynchronizer * self,
    GstRTPBuffer * rtp_buffer, GError ** error)
{
  GstBuffer *buffer = rtp_buffer->buffer;
  guint64 pts_orig, ext_ts, last_sr_ext_ts, last_sr_ntp_ns_time;
  guint64 diff_ntp_ns_time;
  guint8 pt;
  guint32 ssrc, ts;
  gint32 clock_rate;
  gboolean ret = TRUE;

  ssrc = gst_rtp_buffer_get_ssrc (rtp_buffer);

  KMS_RTP_SYNCHRONIZER_LOCK (self);

  if (self->priv->ssrc == 0) {
    self->priv->ssrc = ssrc;
  } else if (ssrc != self->priv->ssrc) {
    gchar *msg = g_strdup_printf ("Invalid SSRC (%u), not matching with %u",
        ssrc, self->priv->ssrc);

    GST_ERROR_OBJECT (self, "%s", msg);
    g_set_error_literal (error, KMS_RTP_SYNC_ERROR, KMS_RTP_SYNC_INVALID_DATA,
        msg);
    g_free (msg);

    KMS_RTP_SYNCHRONIZER_UNLOCK (self);

    return FALSE;
  }

  pt = gst_rtp_buffer_get_payload_type (rtp_buffer);
  if (pt != self->priv->pt || self->priv->clock_rate <= 0) {
    gchar *msg =
        g_strdup_printf ("Invalid clock-rate %d for PT %u, not changing PTS",
        self->priv->clock_rate, pt);

    GST_ERROR_OBJECT (self, "%s", msg);
    g_set_error_literal (error, KMS_RTP_SYNC_ERROR, KMS_RTP_SYNC_INVALID_DATA,
        msg);
    g_free (msg);

    KMS_RTP_SYNCHRONIZER_UNLOCK (self);

    return FALSE;
  }

  pts_orig = GST_BUFFER_PTS (buffer);
  ts = gst_rtp_buffer_get_timestamp (rtp_buffer);
  gst_rtp_buffer_ext_timestamp (&self->priv->ext_ts, ts);

  if (self->priv->feeded_sorted) {
    if (self->priv->fs_last_ext_ts != -1
        && self->priv->ext_ts < self->priv->fs_last_ext_ts) {
      guint16 seq = gst_rtp_buffer_get_seq (rtp_buffer);
      gchar *msg =
          g_strdup_printf
          ("Received an unsorted RTP buffer when expecting sorted (ssrc: %"
          G_GUINT32_FORMAT ", seq: %" G_GUINT16_FORMAT ", ts: %"
          G_GUINT32_FORMAT ", ext_ts: %" G_GUINT64_FORMAT
          "). Moving to unsorted mode",
          ssrc, seq, ts, self->priv->ext_ts);

      GST_ERROR_OBJECT (self, "%s", msg);
      g_set_error_literal (error, KMS_RTP_SYNC_ERROR, KMS_RTP_SYNC_INVALID_DATA,
          msg);
      g_free (msg);

      self->priv->feeded_sorted = FALSE;
      ret = FALSE;
    } else if (self->priv->ext_ts == self->priv->fs_last_ext_ts) {
      GST_BUFFER_PTS (buffer) = self->priv->fs_last_pts;
      goto end;
    }
  }

  if (!self->priv->base_initiated) {
    GST_DEBUG_OBJECT (self,
        "Do not sync data for SSRC %u and PT %u, interpolating PTS", ssrc, pt);

    if (!self->priv->base_interpolate_initiated) {
      self->priv->base_interpolate_ext_ts = self->priv->ext_ts;
      self->priv->base_interpolate_time = GST_BUFFER_PTS (buffer);
      self->priv->base_interpolate_initiated = TRUE;
    } else {
      buffer = gst_buffer_make_writable (buffer);
      GST_BUFFER_PTS (buffer) = self->priv->base_interpolate_time;
      kms_rtp_synchronizer_rtp_diff (self, rtp_buffer, self->priv->clock_rate,
          self->priv->base_interpolate_ext_ts);
    }
  } else {
    gboolean wrapped_down, wrapped_up;

    wrapped_down = wrapped_up = FALSE;

    buffer = gst_buffer_make_writable (buffer);
    GST_BUFFER_PTS (buffer) = self->priv->base_sync_time;

    if (self->priv->last_sr_ntp_ns_time > self->priv->base_ntp_ns_time) {
      diff_ntp_ns_time =
          self->priv->last_sr_ntp_ns_time - self->priv->base_ntp_ns_time;
      wrapped_up = diff_ntp_ns_time > (G_MAXUINT64 - GST_BUFFER_PTS (buffer));
      GST_BUFFER_PTS (buffer) += diff_ntp_ns_time;
    } else if (self->priv->last_sr_ntp_ns_time < self->priv->base_ntp_ns_time) {
      diff_ntp_ns_time =
          self->priv->base_ntp_ns_time - self->priv->last_sr_ntp_ns_time;
      wrapped_down = GST_BUFFER_PTS (buffer) < diff_ntp_ns_time;
      GST_BUFFER_PTS (buffer) -= diff_ntp_ns_time;
    }
    /* if equals do nothing */

    kms_rtp_synchronizer_rtp_diff_full (self, rtp_buffer,
        self->priv->clock_rate, self->priv->last_sr_ext_ts, wrapped_down,
        wrapped_up);
  }

  if (self->priv->feeded_sorted) {
    if (GST_BUFFER_PTS (buffer) < self->priv->fs_last_pts) {
      guint16 seq = gst_rtp_buffer_get_seq (rtp_buffer);

      GST_WARNING_OBJECT (self,
          "Non monotonic PTS assignment in sorted mode (ssrc: %"
          G_GUINT32_FORMAT ", seq: %" G_GUINT16_FORMAT ", ts: %"
          G_GUINT32_FORMAT ", ext_ts: %" G_GUINT64_FORMAT
          "). Forcing monotonic", ssrc, seq, ts, self->priv->ext_ts);

      GST_BUFFER_PTS (buffer) = self->priv->fs_last_pts;
    }

    self->priv->fs_last_ext_ts = self->priv->ext_ts;
    self->priv->fs_last_pts = GST_BUFFER_PTS (buffer);
  }

end:
  clock_rate = self->priv->clock_rate;
  ext_ts = self->priv->ext_ts;
  last_sr_ext_ts = self->priv->last_sr_ext_ts;
  last_sr_ntp_ns_time = self->priv->last_sr_ntp_ns_time;

  KMS_RTP_SYNCHRONIZER_UNLOCK (self);

  kms_rtp_sync_context_write_stats (self->priv->context, ssrc, clock_rate,
      pts_orig, GST_BUFFER_PTS (buffer), GST_BUFFER_DTS (buffer), ext_ts,
      last_sr_ntp_ns_time, last_sr_ext_ts);

  return ret;
}
예제 #25
0
static GstBuffer *
gst_rtp_qdm2_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
{
  GstRtpQDM2Depay *rtpqdm2depay;
  GstBuffer *outbuf;
  guint16 seq;

  rtpqdm2depay = GST_RTP_QDM2_DEPAY (depayload);

  {
    gint payload_len;
    guint8 *payload;
    guint avail;
    guint pos = 0;

    payload_len = gst_rtp_buffer_get_payload_len (buf);
    if (payload_len < 3)
      goto bad_packet;

    payload = gst_rtp_buffer_get_payload (buf);
    seq = gst_rtp_buffer_get_seq (buf);
    if (G_UNLIKELY (seq != rtpqdm2depay->nextseq)) {
      GST_DEBUG ("GAP in sequence number, Resetting data !");
      /* Flush previous data */
      flush_data (rtpqdm2depay);
      /* And store new timestamp */
      rtpqdm2depay->ptimestamp = rtpqdm2depay->timestamp;
      rtpqdm2depay->timestamp = GST_BUFFER_TIMESTAMP (buf);
      /* And that previous data will be pushed at the bottom */
    }
    rtpqdm2depay->nextseq = seq + 1;

    GST_DEBUG ("Payload size %d 0x%x sequence:%d", payload_len, payload_len,
        seq);

    GST_MEMDUMP ("Incoming payload", payload, payload_len);

    while (pos < payload_len) {
      switch (payload[pos]) {
        case 0x80:{
          GST_DEBUG ("Unrecognized 0x80 marker, skipping 12 bytes");
          pos += 12;
        }
          break;
        case 0xff:
          /* HEADERS */
          GST_DEBUG ("Headers");
          /* Store the incoming timestamp */
          rtpqdm2depay->ptimestamp = rtpqdm2depay->timestamp;
          rtpqdm2depay->timestamp = GST_BUFFER_TIMESTAMP (buf);
          /* flush the internal data if needed */
          flush_data (rtpqdm2depay);
          if (G_UNLIKELY (!rtpqdm2depay->configured)) {
            guint8 *ourdata;
            GstBuffer *codecdata;
            GstCaps *caps;

            /* First bytes are unknown */
            GST_MEMDUMP ("Header", payload + pos, 32);
            ourdata = payload + pos + 10;
            pos += 10;
            rtpqdm2depay->channs = GST_READ_UINT32_BE (payload + pos + 4);
            rtpqdm2depay->samplerate = GST_READ_UINT32_BE (payload + pos + 8);
            rtpqdm2depay->bitrate = GST_READ_UINT32_BE (payload + pos + 12);
            rtpqdm2depay->blocksize = GST_READ_UINT32_BE (payload + pos + 16);
            rtpqdm2depay->framesize = GST_READ_UINT32_BE (payload + pos + 20);
            rtpqdm2depay->packetsize = GST_READ_UINT32_BE (payload + pos + 24);
            /* 16 bit empty block (0x02 0x00) */
            pos += 30;
            GST_DEBUG
                ("channs:%d, samplerate:%d, bitrate:%d, blocksize:%d, framesize:%d, packetsize:%d",
                rtpqdm2depay->channs, rtpqdm2depay->samplerate,
                rtpqdm2depay->bitrate, rtpqdm2depay->blocksize,
                rtpqdm2depay->framesize, rtpqdm2depay->packetsize);

            /* Caps */
            codecdata = gst_buffer_new_and_alloc (48);
            memcpy (GST_BUFFER_DATA (codecdata), headheader, 20);
            memcpy (GST_BUFFER_DATA (codecdata) + 20, ourdata, 28);

            caps = gst_caps_new_simple ("audio/x-qdm2",
                "samplesize", G_TYPE_INT, 16,
                "rate", G_TYPE_INT, rtpqdm2depay->samplerate,
                "channels", G_TYPE_INT, rtpqdm2depay->channs,
                "codec_data", GST_TYPE_BUFFER, codecdata, NULL);
            gst_pad_set_caps (GST_BASE_RTP_DEPAYLOAD_SRCPAD (depayload), caps);
            gst_caps_unref (caps);
            rtpqdm2depay->configured = TRUE;
          } else {
            GST_DEBUG ("Already configured, skipping headers");
            pos += 40;
          }
          break;
        default:{
          /* Shuffled packet contents */
          guint packetid = payload[pos++];
          guint packettype = payload[pos++];
          guint packlen = payload[pos++];
          guint hsize = 2;

          GST_DEBUG ("Packet id:%d, type:0x%x, len:%d",
              packetid, packettype, packlen);

          /* Packets bigger than 0xff bytes have a type with the high bit set */
          if (G_UNLIKELY (packettype & 0x80)) {
            packettype &= 0x7f;
            packlen <<= 8;
            packlen |= payload[pos++];
            hsize = 3;
            GST_DEBUG ("Packet id:%d, type:0x%x, len:%d",
                packetid, packettype, packlen);
          }

          if (packettype > 0x7f) {
            GST_ERROR ("HOUSTON WE HAVE A PROBLEM !!!!");
          }
          add_packet (rtpqdm2depay, packetid, packlen + hsize,
              payload + pos - hsize);
          pos += packlen;
        }
      }
    }

    GST_DEBUG ("final pos %d", pos);

    avail = gst_adapter_available (rtpqdm2depay->adapter);
    if (G_UNLIKELY (avail)) {
      GST_DEBUG ("Pushing out %d bytes of collected data", avail);
      outbuf = gst_adapter_take_buffer (rtpqdm2depay->adapter, avail);
      GST_BUFFER_TIMESTAMP (outbuf) = rtpqdm2depay->ptimestamp;
      GST_DEBUG ("Outgoing buffer timestamp %" GST_TIME_FORMAT,
          GST_TIME_ARGS (rtpqdm2depay->ptimestamp));
      return outbuf;
    }
  }
  return NULL;

  /* ERRORS */
bad_packet:
  {
    GST_ELEMENT_WARNING (rtpqdm2depay, STREAM, DECODE,
        (NULL), ("Packet was too short"));
    return NULL;
  }
}
예제 #26
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);
}
예제 #27
0
파일: fecdec.c 프로젝트: dasty/gstrtpfec
void fec_dec_push_media_packet(fec_dec *dec, GstBuffer *packet)
{
    guint32 original_seqnum;
    original_seqnum = gst_rtp_buffer_get_seq(packet);

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

    if (dec->has_snbase)
    {
        guint32 corrected_seqnum;
        corrected_seqnum = fec_dec_correct_seqnum(dec, original_seqnum);

        GST_DEBUG("Pushing media packet with seqnum %u, current snbase is %u", original_seqnum, dec->cur_snbase);

        if ((corrected_seqnum - (guint32)(dec->cur_snbase)) >= dec->num_media_packets)
        {
            GST_DEBUG("Distance between FEC packets and incoming media packets is too large - purging %u FEC packets and setting has_snbase to FALSE", dec->num_received_fec_packets);

            dec->has_snbase = FALSE;
            dec->blacklisted_snbase = dec->cur_snbase;
            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;

            GST_DEBUG("Pushing media packet with seqnum %u, no current snbase set", original_seqnum);
            g_queue_push_tail(dec->media_packets, gst_buffer_ref(packet));
            g_hash_table_add(dec->media_packet_set, GINT_TO_POINTER(original_seqnum));
            ++dec->num_received_media_packets;
        }
        else if ((corrected_seqnum >= (guint32)(dec->cur_snbase)) && (corrected_seqnum <= ((guint32)(dec->cur_snbase) + ((guint32)(dec->num_media_packets)) - 1)))
        {
            g_queue_push_tail(dec->media_packets, gst_buffer_ref(packet));
            g_hash_table_add(dec->media_packet_set, GINT_TO_POINTER(original_seqnum));
            ++dec->num_received_media_packets;
            dec->received_media_packet_mask |= (1ul << (corrected_seqnum - dec->cur_snbase));
            dec->max_packet_size = MAX(dec->max_packet_size, GST_BUFFER_SIZE(packet));

            fec_dec_check_state(dec);
        }
        else
        {
            GST_DEBUG("Received media packet with seqnum %u outside bounds [%u, %u] - pushing aborted", original_seqnum, dec->cur_snbase, dec->cur_snbase + dec->num_media_packets - 1);
        }
    }
    else
    {
        GST_DEBUG("Pushing media packet with seqnum %u, no current snbase set", original_seqnum);
        g_queue_push_tail(dec->media_packets, gst_buffer_ref(packet));
        g_hash_table_add(dec->media_packet_set, GINT_TO_POINTER(original_seqnum));
        ++dec->num_received_media_packets;
    }

    if (dec->num_received_media_packets > dec->num_media_packets)
    {
        guint i;

        GST_DEBUG("Too many media packets in queue - deleting the %u oldest packets", dec->num_received_media_packets - dec->num_media_packets);

        for (i = dec->num_media_packets; i < dec->num_received_media_packets; ++i)
        {
            GstBuffer *media_packet;
            guint16 seqnum;

            media_packet = g_queue_pop_head(dec->media_packets);
            seqnum = gst_rtp_buffer_get_seq(packet);
            g_hash_table_remove(dec->media_packet_set, GINT_TO_POINTER(seqnum));

            gst_buffer_unref(media_packet);
        }

        dec->num_received_media_packets = dec->num_media_packets;
    }
}
예제 #28
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);
}
예제 #29
0
/*
 * This function should be called while holding the filter lock
 */
static gboolean
gst_srtp_dec_decode_buffer (GstSrtpDec * filter, GstPad * pad, GstBuffer * buf,
    gboolean is_rtcp, guint32 ssrc)
{
  GstMapInfo map;
  err_status_t err;
  gint size;

  GST_LOG_OBJECT (pad, "Received %s buffer of size %" G_GSIZE_FORMAT
      " with SSRC = %u", is_rtcp ? "RTCP" : "RTP", gst_buffer_get_size (buf),
      ssrc);

  /* Change buffer to remove protection */
  buf = gst_buffer_make_writable (buf);

  gst_buffer_map (buf, &map, GST_MAP_READWRITE);
  size = map.size;

unprotect:

  gst_srtp_init_event_reporter ();

  if (is_rtcp)
    err = srtp_unprotect_rtcp (filter->session, map.data, &size);
  else {
    /* If ROC has changed, we know we need to set the initial RTP
     * sequence number too. */
    if (filter->roc_changed) {
      srtp_stream_t stream;

      stream = srtp_get_stream (filter->session, htonl (ssrc));

      if (stream) {
        guint16 seqnum = 0;
        GstRTPBuffer rtpbuf = GST_RTP_BUFFER_INIT;

        gst_rtp_buffer_map (buf,
            GST_MAP_READ | GST_RTP_BUFFER_MAP_FLAG_SKIP_PADDING, &rtpbuf);
        seqnum = gst_rtp_buffer_get_seq (&rtpbuf);
        gst_rtp_buffer_unmap (&rtpbuf);

        /* We finally add the RTP sequence number to the current
         * rollover counter. */
        stream->rtp_rdbx.index &= ~0xFFFF;
        stream->rtp_rdbx.index |= seqnum;
      }

      filter->roc_changed = FALSE;
    }
    err = srtp_unprotect (filter->session, map.data, &size);
  }

  GST_OBJECT_UNLOCK (filter);

  if (err != err_status_ok) {
    GST_WARNING_OBJECT (pad,
        "Unable to unprotect buffer (unprotect failed code %d)", err);

    /* Signal user depending on type of error */
    switch (err) {
      case err_status_key_expired:
        GST_OBJECT_LOCK (filter);

        /* Update stream */
        if (find_stream_by_ssrc (filter, ssrc)) {
          GST_OBJECT_UNLOCK (filter);
          if (request_key_with_signal (filter, ssrc, SIGNAL_HARD_LIMIT)) {
            GST_OBJECT_LOCK (filter);
            goto unprotect;
          } else {
            GST_WARNING_OBJECT (filter, "Hard limit reached, no new key, "
                "dropping");
          }
        } else {
          GST_WARNING_OBJECT (filter, "Could not find matching stream, "
              "dropping");
        }
        break;
      case err_status_auth_fail:
        GST_WARNING_OBJECT (filter, "Error authentication packet, dropping");
        break;
      case err_status_cipher_fail:
        GST_WARNING_OBJECT (filter, "Error while decrypting packet, dropping");
        break;
      default:
        GST_WARNING_OBJECT (filter, "Other error, dropping");
        break;
    }

    gst_buffer_unmap (buf, &map);

    GST_OBJECT_LOCK (filter);
    return FALSE;
  }

  gst_buffer_unmap (buf, &map);

  gst_buffer_set_size (buf, size);

  GST_OBJECT_LOCK (filter);
  return TRUE;
}
예제 #30
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;
}