From 39505584e14be177db8cc7b6c3ac39df21d72774 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 9 Sep 2014 12:15:43 +0100 Subject: [PATCH] udpsrc: rework memory allocation bits and ensure we always have two chunks of memories to read into First chunk is the likely/expected buffer size, second is as fallback in case the packet is larger in the end. Next step: actually use these. --- gst/udp/gstudpsrc.c | 112 +++++++++++++++++++++++++++++++++++++++----- gst/udp/gstudpsrc.h | 6 +++ 2 files changed, 106 insertions(+), 12 deletions(-) diff --git a/gst/udp/gstudpsrc.c b/gst/udp/gstudpsrc.c index cfde461639..f1ac2231e7 100644 --- a/gst/udp/gstudpsrc.c +++ b/gst/udp/gstudpsrc.c @@ -3,6 +3,8 @@ * Copyright (C) <2005> Nokia Corporation * Copyright (C) <2012> Collabora Ltd. * Author: Sebastian Dröge + * Copyright (C) 2014 Tim-Philipp Müller + * Copyright (C) 2014 Centricular Ltd * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -392,9 +394,35 @@ gst_udpsrc_getcaps (GstBaseSrc * src, GstCaps * filter) return result; } +static void +gst_udpsrc_reset_memory_allocator (GstUDPSrc * src) +{ + if (src->mem != NULL) { + gst_memory_unmap (src->mem, &src->map); + gst_memory_unref (src->mem); + src->mem = NULL; + } + if (src->mem_max != NULL) { + gst_memory_unmap (src->mem_max, &src->map_max); + gst_memory_unref (src->mem_max); + src->mem_max = NULL; + } + + src->vec[0].buffer = NULL; + src->vec[0].size = 0; + src->vec[1].buffer = NULL; + src->vec[1].size = 0; + + if (src->allocator != NULL) { + gst_object_unref (src->allocator); + src->allocator = NULL; + } +} + 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 @@ -402,22 +430,76 @@ gst_udpsrc_negotiate (GstBaseSrc * basesrc) ret = GST_BASE_SRC_CLASS (parent_class)->negotiate (basesrc); if (ret) { - GstUDPSrc *src; + GstAllocationParams new_params; + GstAllocator *new_allocator = NULL; - src = GST_UDPSRC (basesrc); + /* retrieve new allocator */ + gst_base_src_get_allocator (basesrc, &new_allocator, &new_params); - if (src->allocator != NULL) { - gst_object_unref (src->allocator); - src->allocator = NULL; + 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); } - - gst_base_src_get_allocator (basesrc, &src->allocator, &src->params); - GST_INFO_OBJECT (src, "allocator: %" GST_PTR_FORMAT, src->allocator); } return ret; } +static gboolean +gst_udpsrc_alloc_mem (GstUDPSrc * src, GstMemory ** p_mem, GstMapInfo * map, + gsize size) +{ + GstMemory *mem; + + mem = gst_allocator_alloc (src->allocator, size, &src->params); + + if (!gst_memory_map (mem, map, GST_MAP_WRITE)) { + gst_memory_unref (mem); + memset (map, 0, sizeof (GstMapInfo)); + return FALSE; + } + *p_mem = mem; + return TRUE; +} + +static gboolean +gst_udpsrc_ensure_mem (GstUDPSrc * src) +{ + if (src->mem == NULL) { + gsize mem_size = 1500; /* typical max. MTU */ + + /* if packets are likely to be smaller, just use that size, otherwise + * default to assuming incoming packets are around MTU size */ + if (src->max_size > 0 && src->max_size < mem_size) + mem_size = src->max_size; + + if (!gst_udpsrc_alloc_mem (src, &src->mem, &src->map, mem_size)) + return FALSE; + + src->vec[0].buffer = src->map.data; + src->vec[0].size = src->map.size; + } + + if (src->mem_max == NULL) { + gsize max_size = MAX_IPV4_UDP_PACKET_SIZE; + + if (!gst_udpsrc_alloc_mem (src, &src->mem_max, &src->map_max, max_size)) + return FALSE; + + src->vec[1].buffer = src->map_max.data; + src->vec[1].size = src->map_max.size; + } + + return TRUE; +} + static GstFlowReturn gst_udpsrc_create (GstPushSrc * psrc, GstBuffer ** buf) { @@ -434,6 +516,9 @@ gst_udpsrc_create (GstPushSrc * psrc, GstBuffer ** buf) udpsrc = GST_UDPSRC_CAST (psrc); + if (!gst_udpsrc_ensure_mem (udpsrc)) + goto memory_alloc_error; + retry: /* quick check, avoid going in select when we already have data */ readsize = g_socket_get_available_bytes (udpsrc->used_socket); @@ -565,6 +650,12 @@ no_select: return ret; /* 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), @@ -1139,10 +1230,7 @@ gst_udpsrc_close (GstUDPSrc * src) src->addr = NULL; } - if (src->allocator != NULL) { - gst_object_unref (src->allocator); - src->allocator = NULL; - } + gst_udpsrc_reset_memory_allocator (src); return TRUE; } diff --git a/gst/udp/gstudpsrc.h b/gst/udp/gstudpsrc.h index 525888111c..48976a4785 100644 --- a/gst/udp/gstudpsrc.h +++ b/gst/udp/gstudpsrc.h @@ -74,6 +74,12 @@ struct _GstUDPSrc { GstAllocator *allocator; GstAllocationParams params; + GstMemory *mem; + GstMapInfo map; + GstMemory *mem_max; + GstMapInfo map_max; + GInputVector vec[2]; + gchar *uri; };