static gboolean gst_udpsrc_negotiate (GstBaseSrc * basesrc) { GstUDPSrc *src = GST_UDPSRC_CAST (basesrc); gboolean ret; /* just chain up to the default implementation, we just want to * retrieve the allocator at the end of it (if there is one) */ ret = GST_BASE_SRC_CLASS (parent_class)->negotiate (basesrc); if (ret) { GstAllocationParams new_params; GstAllocator *new_allocator = NULL; /* retrieve new allocator */ gst_base_src_get_allocator (basesrc, &new_allocator, &new_params); if (src->allocator != new_allocator || memcmp (&src->params, &new_params, sizeof (GstAllocationParams)) != 0) { /* drop old allocator and throw away any memory allocated with it */ gst_udpsrc_reset_memory_allocator (src); /* and save the new allocator and/or new allocation parameters */ src->allocator = new_allocator; src->params = new_params; GST_INFO_OBJECT (src, "new allocator: %" GST_PTR_FORMAT, new_allocator); } } return ret; }
static GstFlowReturn gst_udpsrc_create (GstPushSrc * psrc, GstBuffer ** buf) { GstFlowReturn ret = GST_FLOW_OK; GstUDPSrc *udpsrc; GstBuffer *outbuf; gsize offset; gssize readsize; gssize res; gboolean try_again; GError *err = NULL; udpsrc = GST_UDPSRC_CAST (psrc); retry: /* quick check, avoid going in select when we already have data */ readsize = g_socket_get_available_bytes (udpsrc->used_socket); if (readsize > 0) goto no_select; do { gint64 timeout; try_again = FALSE; if (udpsrc->timeout) timeout = udpsrc->timeout / 1000; else timeout = -1; GST_LOG_OBJECT (udpsrc, "doing select, timeout %" G_GUINT64_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)); /* ask how much is available for reading on the socket, this should be exactly * one UDP packet. We will check the return value, though, because in some * case it can return 0 and we don't want a 0 sized buffer. */ readsize = g_socket_get_available_bytes (udpsrc->used_socket); if (G_UNLIKELY (readsize < 0)) goto get_available_error; /* If we get here and the readsize is zero, then either select was woken up * by activity that is not a read, or a poll error occurred, or a UDP packet * was received that has no data. Since we cannot identify which case it is, * we handle all of them. This could possibly lead to a UDP packet getting * lost, but since UDP is not reliable, we can accept this. */ if (G_UNLIKELY (!readsize)) { /* try to read a packet (and it will be ignored), * in case a packet with no data arrived */ res = g_socket_receive_from (udpsrc->used_socket, NULL, NULL, 0, udpsrc->cancellable, &err); if (G_UNLIKELY (res < 0)) goto receive_error; /* poll again */ goto retry; } no_select: GST_LOG_OBJECT (udpsrc, "ioctl says %d bytes available", (int) readsize); /* sanity check value from _get_available_bytes(), which might be as * large as the kernel-side buffer on some operating systems */ if (g_socket_get_family (udpsrc->used_socket) == G_SOCKET_FAMILY_IPV4) readsize = MIN (MAX_IPV4_UDP_PACKET_SIZE, readsize); ret = gst_pad_alloc_buffer (GST_BASE_SRC (udpsrc)->srcpad, GST_BUFFER_OFFSET_NONE, readsize, NULL, &outbuf); if (GST_FLOW_OK != ret) goto alloc_failed; offset = 0; res = g_socket_receive_from (udpsrc->used_socket, NULL, (gchar *) GST_BUFFER_DATA (outbuf), GST_BUFFER_SIZE (outbuf), 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)) { gst_buffer_unref (outbuf); outbuf = NULL; g_clear_error (&err); goto retry; } goto receive_error; } /* patch offset and size when stripping off the headers */ if (G_UNLIKELY (udpsrc->skip_first_bytes != 0)) { if (G_UNLIKELY (readsize < udpsrc->skip_first_bytes)) goto skip_error; offset += udpsrc->skip_first_bytes; res -= udpsrc->skip_first_bytes; } GST_BUFFER_OFFSET (outbuf) = offset; GST_BUFFER_SIZE (outbuf) = res; GST_LOG_OBJECT (udpsrc, "read %d bytes", (int) readsize); *buf = GST_BUFFER_CAST (outbuf); return ret; /* ERRORS */ 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_WRONG_STATE; } get_available_error: { GST_ELEMENT_ERROR (udpsrc, RESOURCE, READ, (NULL), ("get available bytes failed")); return GST_FLOW_ERROR; } alloc_failed: { GST_DEBUG ("Allocation failed"); return ret; } receive_error: { gst_buffer_unref (outbuf); 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_WRONG_STATE; } 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 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; } }
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; } }