Example #1
0
static GstFlowReturn
gst_udpsrc_create (GstPushSrc * psrc, GstBuffer ** buf)
{
  GstUDPSrc *udpsrc;
  GstBuffer *outbuf = NULL;
  GSocketAddress *saddr = NULL;
  gint flags = G_SOCKET_MSG_NONE;
  gboolean try_again;
  GError *err = NULL;
  gssize res;
  gsize offset;

  udpsrc = GST_UDPSRC_CAST (psrc);

  if (!gst_udpsrc_ensure_mem (udpsrc))
    goto memory_alloc_error;

retry:

  do {
    gint64 timeout;

    try_again = FALSE;

    if (udpsrc->timeout)
      timeout = udpsrc->timeout / 1000;
    else
      timeout = -1;

    GST_LOG_OBJECT (udpsrc, "doing select, timeout %" G_GINT64_FORMAT, timeout);

    if (!g_socket_condition_timed_wait (udpsrc->used_socket, G_IO_IN | G_IO_PRI,
            timeout, udpsrc->cancellable, &err)) {
      if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_BUSY)
          || g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
        goto stopped;
      } else if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_TIMED_OUT)) {
        g_clear_error (&err);
        /* timeout, post element message */
        gst_element_post_message (GST_ELEMENT_CAST (udpsrc),
            gst_message_new_element (GST_OBJECT_CAST (udpsrc),
                gst_structure_new ("GstUDPSrcTimeout",
                    "timeout", G_TYPE_UINT64, udpsrc->timeout, NULL)));
      } else {
        goto select_error;
      }

      try_again = TRUE;
    }
  } while (G_UNLIKELY (try_again));

  if (saddr != NULL) {
    g_object_unref (saddr);
    saddr = NULL;
  }

  res =
      g_socket_receive_message (udpsrc->used_socket, &saddr, udpsrc->vec, 2,
      NULL, NULL, &flags, udpsrc->cancellable, &err);

  if (G_UNLIKELY (res < 0)) {
    /* EHOSTUNREACH for a UDP socket means that a packet sent with udpsink
     * generated a "port unreachable" ICMP response. We ignore that and try
     * again. */
    if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_HOST_UNREACHABLE)) {
      g_clear_error (&err);
      goto retry;
    }
    goto receive_error;
  }

  /* remember maximum packet size */
  if (res > udpsrc->max_size)
    udpsrc->max_size = res;

  outbuf = gst_buffer_new ();

  /* append first memory chunk to buffer */
  gst_buffer_append_memory (outbuf, udpsrc->mem);

  /* if the packet didn't fit into the first chunk, add second one as well */
  if (res > udpsrc->map.size) {
    gst_buffer_append_memory (outbuf, udpsrc->mem_max);
    gst_memory_unmap (udpsrc->mem_max, &udpsrc->map_max);
    udpsrc->vec[1].buffer = NULL;
    udpsrc->vec[1].size = 0;
    udpsrc->mem_max = NULL;
  }

  /* make sure we allocate a new chunk next time (we do this only here because
   * we look at map.size to see if the second memory chunk is needed above) */
  gst_memory_unmap (udpsrc->mem, &udpsrc->map);
  udpsrc->vec[0].buffer = NULL;
  udpsrc->vec[0].size = 0;
  udpsrc->mem = NULL;

  offset = udpsrc->skip_first_bytes;

  if (G_UNLIKELY (offset > 0 && res < offset))
    goto skip_error;

  gst_buffer_resize (outbuf, offset, res - offset);

  /* use buffer metadata so receivers can also track the address */
  if (saddr) {
    gst_buffer_add_net_address_meta (outbuf, saddr);
    g_object_unref (saddr);
    saddr = NULL;
  }

  GST_LOG_OBJECT (udpsrc, "read packet of %d bytes", (int) res);

  *buf = GST_BUFFER_CAST (outbuf);

  return GST_FLOW_OK;

  /* ERRORS */
memory_alloc_error:
  {
    GST_ELEMENT_ERROR (udpsrc, RESOURCE, READ, (NULL),
        ("Failed to allocate or map memory"));
    return GST_FLOW_ERROR;
  }
select_error:
  {
    GST_ELEMENT_ERROR (udpsrc, RESOURCE, READ, (NULL),
        ("select error: %s", err->message));
    g_clear_error (&err);
    return GST_FLOW_ERROR;
  }
stopped:
  {
    GST_DEBUG ("stop called");
    g_clear_error (&err);
    return GST_FLOW_FLUSHING;
  }
receive_error:
  {
    if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_BUSY) ||
        g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
      g_clear_error (&err);
      return GST_FLOW_FLUSHING;
    } else {
      GST_ELEMENT_ERROR (udpsrc, RESOURCE, READ, (NULL),
          ("receive error %" G_GSSIZE_FORMAT ": %s", res, err->message));
      g_clear_error (&err);
      return GST_FLOW_ERROR;
    }
  }
skip_error:
  {
    gst_buffer_unref (outbuf);

    GST_ELEMENT_ERROR (udpsrc, STREAM, DECODE, (NULL),
        ("UDP buffer to small to skip header"));
    return GST_FLOW_ERROR;
  }
}
Example #2
0
static GstFlowReturn
gst_udpsrc_create (GstPushSrc * psrc, GstBuffer ** buf)
{
  GstUDPSrc *udpsrc;
  GstBuffer *outbuf = NULL;
  GSocketAddress *saddr = NULL;
  GSocketAddress **p_saddr;
  gint flags = G_SOCKET_MSG_NONE;
  gboolean try_again;
  GError *err = NULL;
  gssize res;
  gsize offset;

  udpsrc = GST_UDPSRC_CAST (psrc);

  if (!gst_udpsrc_ensure_mem (udpsrc))
    goto memory_alloc_error;

  /* Retrieve sender address unless we've been configured not to do so */
  p_saddr = (udpsrc->retrieve_sender_address) ? &saddr : NULL;

retry:

  do {
    gint64 timeout;

    try_again = FALSE;

    if (udpsrc->timeout)
      timeout = udpsrc->timeout / 1000;
    else
      timeout = -1;

    GST_LOG_OBJECT (udpsrc, "doing select, timeout %" G_GINT64_FORMAT, timeout);

    if (!g_socket_condition_timed_wait (udpsrc->used_socket, G_IO_IN | G_IO_PRI,
            timeout, udpsrc->cancellable, &err)) {
      if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_BUSY)
          || g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
        goto stopped;
      } else if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_TIMED_OUT)) {
        g_clear_error (&err);
        /* timeout, post element message */
        gst_element_post_message (GST_ELEMENT_CAST (udpsrc),
            gst_message_new_element (GST_OBJECT_CAST (udpsrc),
                gst_structure_new ("GstUDPSrcTimeout",
                    "timeout", G_TYPE_UINT64, udpsrc->timeout, NULL)));
      } else {
        goto select_error;
      }

      try_again = TRUE;
    }
  } while (G_UNLIKELY (try_again));

  if (saddr != NULL) {
    g_object_unref (saddr);
    saddr = NULL;
  }

  res =
      g_socket_receive_message (udpsrc->used_socket, p_saddr, udpsrc->vec, 2,
      NULL, NULL, &flags, udpsrc->cancellable, &err);

  if (G_UNLIKELY (res < 0)) {
    /* G_IO_ERROR_HOST_UNREACHABLE for a UDP socket means that a packet sent
     * with udpsink generated a "port unreachable" ICMP response. We ignore
     * that and try again.
     * On Windows we get G_IO_ERROR_CONNECTION_CLOSED instead */
#if GLIB_CHECK_VERSION(2,44,0)
    if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_HOST_UNREACHABLE) ||
        g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED)) {
#else
    if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_HOST_UNREACHABLE)) {
#endif
      g_clear_error (&err);
      goto retry;
    }
    goto receive_error;
  }

  /* remember maximum packet size */
  if (res > udpsrc->max_size)
    udpsrc->max_size = res;

  outbuf = gst_buffer_new ();

  /* append first memory chunk to buffer */
  gst_buffer_append_memory (outbuf, udpsrc->mem);

  /* if the packet didn't fit into the first chunk, add second one as well */
  if (res > udpsrc->map.size) {
    gst_buffer_append_memory (outbuf, udpsrc->mem_max);
    gst_memory_unmap (udpsrc->mem_max, &udpsrc->map_max);
    udpsrc->vec[1].buffer = NULL;
    udpsrc->vec[1].size = 0;
    udpsrc->mem_max = NULL;
  }

  /* make sure we allocate a new chunk next time (we do this only here because
   * we look at map.size to see if the second memory chunk is needed above) */
  gst_memory_unmap (udpsrc->mem, &udpsrc->map);
  udpsrc->vec[0].buffer = NULL;
  udpsrc->vec[0].size = 0;
  udpsrc->mem = NULL;

  offset = udpsrc->skip_first_bytes;

  if (G_UNLIKELY (offset > 0 && res < offset))
    goto skip_error;

  gst_buffer_resize (outbuf, offset, res - offset);

  /* use buffer metadata so receivers can also track the address */
  if (saddr) {
    gst_buffer_add_net_address_meta (outbuf, saddr);
    g_object_unref (saddr);
    saddr = NULL;
  }

  GST_LOG_OBJECT (udpsrc, "read packet of %d bytes", (int) res);

  *buf = GST_BUFFER_CAST (outbuf);

  return GST_FLOW_OK;

  /* ERRORS */
memory_alloc_error:
  {
    GST_ELEMENT_ERROR (udpsrc, RESOURCE, READ, (NULL),
        ("Failed to allocate or map memory"));
    return GST_FLOW_ERROR;
  }
select_error:
  {
    GST_ELEMENT_ERROR (udpsrc, RESOURCE, READ, (NULL),
        ("select error: %s", err->message));
    g_clear_error (&err);
    return GST_FLOW_ERROR;
  }
stopped:
  {
    GST_DEBUG ("stop called");
    g_clear_error (&err);
    return GST_FLOW_FLUSHING;
  }
receive_error:
  {
    if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_BUSY) ||
        g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
      g_clear_error (&err);
      return GST_FLOW_FLUSHING;
    } else {
      GST_ELEMENT_ERROR (udpsrc, RESOURCE, READ, (NULL),
          ("receive error %" G_GSSIZE_FORMAT ": %s", res, err->message));
      g_clear_error (&err);
      return GST_FLOW_ERROR;
    }
  }
skip_error:
  {
    gst_buffer_unref (outbuf);

    GST_ELEMENT_ERROR (udpsrc, STREAM, DECODE, (NULL),
        ("UDP buffer to small to skip header"));
    return GST_FLOW_ERROR;
  }
}

static gboolean
gst_udpsrc_set_uri (GstUDPSrc * src, const gchar * uri, GError ** error)
{
  gchar *address;
  guint16 port;

  if (!gst_udp_parse_uri (uri, &address, &port))
    goto wrong_uri;

  if (port == (guint16) - 1)
    port = UDP_DEFAULT_PORT;

  g_free (src->address);
  src->address = address;
  src->port = port;

  g_free (src->uri);
  src->uri = g_strdup (uri);

  return TRUE;

  /* ERRORS */
wrong_uri:
  {
    GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
        ("error parsing uri %s", uri));
    g_set_error_literal (error, GST_URI_ERROR, GST_URI_ERROR_BAD_URI,
        "Could not parse UDP URI");
    return FALSE;
  }
}