From 8b02c9040a66be648a9cce498f18e45d8c6491f2 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 16 Apr 2015 19:45:26 +0200 Subject: [PATCH] pulsevideo: add gstreamer elements Add custom gstreamer elements to pad/depay Add pv_init() to register new elements --- configure.ac | 24 ++- src/Makefile.am | 15 +- src/client/pulsevideo.c | 33 ++++ src/client/pulsevideo.h | 2 + src/daemon/main.c | 5 +- src/gst/gstfddepay.c | 235 +++++++++++++++++++++++++++++ src/gst/gstfddepay.h | 48 ++++++ src/gst/gstfdpay.c | 276 ++++++++++++++++++++++++++++++++++ src/gst/gstfdpay.h | 49 ++++++ src/gst/gsttmpfileallocator.c | 145 ++++++++++++++++++ src/gst/gsttmpfileallocator.h | 37 +++++ src/gst/wire-protocol.h | 33 ++++ src/tests/test-client.c | 5 +- src/tests/test-subscribe.c | 5 +- 14 files changed, 898 insertions(+), 14 deletions(-) create mode 100644 src/client/pulsevideo.c create mode 100644 src/gst/gstfddepay.c create mode 100644 src/gst/gstfddepay.h create mode 100644 src/gst/gstfdpay.c create mode 100644 src/gst/gstfdpay.h create mode 100644 src/gst/gsttmpfileallocator.c create mode 100644 src/gst/gsttmpfileallocator.h create mode 100644 src/gst/wire-protocol.h diff --git a/configure.ac b/configure.ac index c4ca9b6d5..d7525c6a2 100644 --- a/configure.ac +++ b/configure.ac @@ -179,11 +179,31 @@ AC_SUBST([GDBUS_CODEGEN], [`$PKG_CONFIG --variable gdbus_codegen gio-2.0`]) #### GStreamer #### -PKG_CHECK_MODULES(GST, gstreamer-1.0 >= 1.4.0, dummy=yes, - AC_MSG_ERROR(GStreamer >= 1.4.0 is required)) +PKG_CHECK_MODULES(GST, gstreamer-1.0-uninstalled >= 1.5.0, dummy=yes, + AC_MSG_ERROR(GStreamer >= 1.5.0 is required)) AC_SUBST(GST_CFLAGS) AC_SUBST(GST_LIBS) +PKG_CHECK_MODULES(GSTBASE, gstreamer-base-1.0-uninstalled >= 1.5.0, dummy=yes, + AC_MSG_ERROR(GStreamer Base>= 1.5.0 is required)) +GST_CFLAGS="$GST_CFLAGS $GSTBASE_CFLAGS" +GST_LIBS="$GST_LIBS $GSTBASE_LIBS" + +PKG_CHECK_MODULES(GSTPBASE, gstreamer-plugins-base-1.0-uninstalled >= 1.5.0, dummy=yes, + AC_MSG_ERROR(GStreamer Plugins Base>= 1.5.0 is required)) +GST_CFLAGS="$GST_CFLAGS $GSTPBASE_CFLAGS" +GST_LIBS="$GST_LIBS $GSTPBASE_LIBS" + +PKG_CHECK_MODULES(GSTNET, gstreamer-net-1.0-uninstalled >= 1.5.0, dummy=yes, + AC_MSG_ERROR(GStreamer Net>= 1.5.0 is required)) +GST_CFLAGS="$GST_CFLAGS $GSTNET_CFLAGS" +GST_LIBS="$GST_LIBS $GSTNET_LIBS" + +PKG_CHECK_MODULES(GSTALLOC, gstreamer-allocators-1.0-uninstalled >= 1.5.0, dummy=yes, + AC_MSG_ERROR(GStreamer Allocators>= 1.5.0 is required)) +GST_CFLAGS="$GST_CFLAGS $GSTALLOC_CFLAGS" +GST_LIBS="$GST_LIBS $GSTALLOC_LIBS" + #### Build and Install man pages #### AC_ARG_ENABLE([manpages], diff --git a/src/Makefile.am b/src/Makefile.am index 905cdf8d1..9c33337cc 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -142,12 +142,17 @@ test_subscribe_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) # Client library # ################################### +pulsevideogstsource = gst/gstfdpay.h gst/gstfdpay.c \ + gst/gstfddepay.h gst/gstfddepay.c \ + gst/gsttmpfileallocator.h gst/gsttmpfileallocator.c \ + wire-protocol.h + pulsevideoinclude_HEADERS = \ + client/pulsevideo.h \ client/pv-context.h \ client/pv-enumtypes.h \ client/pv-stream.h \ client/pv-subscribe.h \ - client/pv-subscribe.h \ dbus/org-pulsevideo.h lib_LTLIBRARIES = \ @@ -158,12 +163,14 @@ libpulsevideo_@PV_MAJORMINOR@_la_SOURCES = \ client/pv-context.h client/pv-context.c \ client/pv-enumtypes.h client/pv-enumtypes.c \ client/pv-stream.h client/pv-stream.c \ - dbus/org-pulsevideo.c + client/pulsevideo.c \ + dbus/org-pulsevideo.c \ + $(pulsevideogstsource) -libpulsevideo_@PV_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) +libpulsevideo_@PV_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) $(GST_CFLAGS) libpulsevideo_@PV_MAJORMINOR@_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version -libpulsevideo_@PV_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) $(LTLIBICONV) +libpulsevideo_@PV_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) $(LTLIBICONV) $(GST_LIBS) ################################### # Daemon core library # diff --git a/src/client/pulsevideo.c b/src/client/pulsevideo.c new file mode 100644 index 000000000..597a55202 --- /dev/null +++ b/src/client/pulsevideo.c @@ -0,0 +1,33 @@ +/* Pulsevideo + * Copyright (C) 2015 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "client/pulsevideo.h" + +#include "gst/gstfdpay.h" +#include "gst/gstfddepay.h" + +void +pv_init (int *argc, char **argv[]) +{ + gst_init (argc, argv); + + gst_element_register (NULL, "pvfdpay", GST_RANK_NONE, GST_TYPE_FDPAY); + gst_element_register (NULL, "pvfddepay", GST_RANK_NONE, GST_TYPE_FDDEPAY); +} + diff --git a/src/client/pulsevideo.h b/src/client/pulsevideo.h index a2b6c5fc9..377ce3f9f 100644 --- a/src/client/pulsevideo.h +++ b/src/client/pulsevideo.h @@ -24,5 +24,7 @@ #include #include +void pv_init (int *argc, char **argv[]); + #endif /* __PULSEVIDEO_H__ */ diff --git a/src/daemon/main.c b/src/daemon/main.c index 294b3f4af..3b6e79b18 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -20,7 +20,8 @@ #include #include -#include "server/pv-daemon.h" +#include +#include gint main (gint argc, gchar *argv[]) @@ -28,7 +29,7 @@ main (gint argc, gchar *argv[]) PvDaemon *daemon; GMainLoop *loop; - gst_init (&argc, &argv); + pv_init (&argc, &argv); loop = g_main_loop_new (NULL, FALSE); diff --git a/src/gst/gstfddepay.c b/src/gst/gstfddepay.c new file mode 100644 index 000000000..830a1fd35 --- /dev/null +++ b/src/gst/gstfddepay.c @@ -0,0 +1,235 @@ +/* GStreamer + * Copyright (C) 2014 William Manley + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Suite 500, + * Boston, MA 02110-1335, USA. + */ +/** + * SECTION:element-gstfddepay + * + * The fddepay element does FIXME stuff. + * + * + * Example launch line + * |[ + * gst-launch -v fakesrc ! fddepay ! FIXME ! fakesink + * ]| + * FIXME Describe what the pipeline does. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstfddepay.h" +#include "wire-protocol.h" +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + + +GST_DEBUG_CATEGORY_STATIC (gst_fddepay_debug_category); +#define GST_CAT_DEFAULT gst_fddepay_debug_category + +/* prototypes */ + + +static GstCaps *gst_fddepay_transform_caps (GstBaseTransform * trans, + GstPadDirection direction, GstCaps * caps, GstCaps * filter); +static void gst_fddepay_dispose (GObject * object); + +static GstFlowReturn gst_fddepay_transform_ip (GstBaseTransform * trans, + GstBuffer * buf); + +/* pad templates */ + +static GstStaticCaps fd_caps = GST_STATIC_CAPS ("application/x-fd"); + +static GstStaticPadTemplate gst_fddepay_src_template = +GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS_ANY); + +static GstStaticPadTemplate gst_fddepay_sink_template = +GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("application/x-fd")); + + +/* class initialization */ + +G_DEFINE_TYPE_WITH_CODE (GstFddepay, gst_fddepay, GST_TYPE_BASE_TRANSFORM, + GST_DEBUG_CATEGORY_INIT (gst_fddepay_debug_category, "fddepay", 0, + "debug category for fddepay element")); + +static void +gst_fddepay_class_init (GstFddepayClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GstBaseTransformClass *base_transform_class = + GST_BASE_TRANSFORM_CLASS (klass); + + /* Setting up pads and setting metadata should be moved to + base_class_init if you intend to subclass this class. */ + gst_element_class_add_pad_template (GST_ELEMENT_CLASS (klass), + gst_static_pad_template_get (&gst_fddepay_src_template)); + gst_element_class_add_pad_template (GST_ELEMENT_CLASS (klass), + gst_static_pad_template_get (&gst_fddepay_sink_template)); + + gst_element_class_set_static_metadata (GST_ELEMENT_CLASS (klass), + "Simple FD Deplayloder", "Generic", + "Simple File-descriptor Depayloader for zero-copy video IPC", + "William Manley "); + + gobject_class->dispose = gst_fddepay_dispose; + base_transform_class->transform_caps = + GST_DEBUG_FUNCPTR (gst_fddepay_transform_caps); + base_transform_class->transform_ip = + GST_DEBUG_FUNCPTR (gst_fddepay_transform_ip); + +} + +static void +gst_fddepay_init (GstFddepay * fddepay) +{ + fddepay->dmabuf_allocator = gst_dmabuf_allocator_new (); +} + +void +gst_fddepay_dispose (GObject * object) +{ + GstFddepay *fddepay = GST_FDDEPAY (object); + + GST_DEBUG_OBJECT (fddepay, "dispose"); + + /* clean up as possible. may be called multiple times */ + if (fddepay->dmabuf_allocator != NULL) { + g_object_unref (G_OBJECT (fddepay->dmabuf_allocator)); + fddepay->dmabuf_allocator = NULL; + } + + G_OBJECT_CLASS (gst_fddepay_parent_class)->dispose (object); +} + +static GstCaps * +gst_fddepay_transform_caps (GstBaseTransform * trans, GstPadDirection direction, + GstCaps * caps, GstCaps * filter) +{ + GstFddepay *fddepay = GST_FDDEPAY (trans); + GstCaps *othercaps; + + GST_DEBUG_OBJECT (fddepay, "transform_caps"); + + + if (direction == GST_PAD_SRC) { + /* transform caps going upstream */ + othercaps = gst_static_caps_get (&fd_caps); + } else { + /* transform caps going downstream */ + othercaps = gst_caps_new_any (); + } + + if (filter) { + GstCaps *intersect; + + intersect = gst_caps_intersect (othercaps, filter); + gst_caps_unref (othercaps); + + return intersect; + } else { + return othercaps; + } +} + +static GstFlowReturn +gst_fddepay_transform_ip (GstBaseTransform * trans, GstBuffer * buf) +{ + GstFddepay *fddepay = GST_FDDEPAY (trans); + FDMessage msg; + GstMemory *dmabufmem = NULL; + GstNetControlMessageMeta * meta; + int *fds = NULL; + int fds_len = 0; + int fd = -1; + + GST_DEBUG_OBJECT (fddepay, "transform_ip"); + + if (gst_buffer_get_size (buf) != sizeof (msg)) { + /* We're guaranteed that we can't `read` from a socket across an attached + * file descriptor so we should get the data in chunks no bigger than + * sizeof(FDMessage) */ + GST_WARNING_OBJECT (fddepay, "fddepay: Received wrong amount of data " + "between fds."); + goto error; + } + + gst_buffer_extract (buf, 0, &msg, sizeof (msg)); + + meta = ((GstNetControlMessageMeta*) gst_buffer_get_meta ( + buf, GST_NET_CONTROL_MESSAGE_META_API_TYPE)); + + if (meta && + g_socket_control_message_get_msg_type (meta->message) == SCM_RIGHTS) { + fds = g_unix_fd_message_steal_fds ((GUnixFDMessage*) meta->message, + &fds_len); + meta = NULL; + } + + if (fds == NULL || fds_len != 1) { + GST_WARNING_OBJECT (fddepay, "fddepay: Expect to receive 1 FD for each " + "buffer, received %i", fds_len); + goto error; + } + fd = dup (fds[0]); + if (fd < 0) { + GST_WARNING_OBJECT (fddepay, "fddepay: Could not dup FD %i: %s", fds[0], + strerror (errno)); + goto error; + } + fcntl (fd, F_SETFD, FD_CLOEXEC); + g_free (fds); + fds = NULL; + + /* FIXME: Use stat to find out the size of the file, to make sure that the + * size we've been told is the true size for safety and security. */ + dmabufmem = gst_dmabuf_allocator_alloc (fddepay->dmabuf_allocator, fd, + msg.offset + msg.size); + gst_memory_resize (dmabufmem, msg.offset, msg.size); + + gst_buffer_remove_all_memory (buf); + gst_buffer_remove_meta (buf, + gst_buffer_get_meta (buf, GST_NET_CONTROL_MESSAGE_META_API_TYPE)); + gst_buffer_append_memory (buf, dmabufmem); + dmabufmem = NULL; + + return GST_FLOW_OK; +error: + if (fds) + g_free (fds); + if (fd >= 0) + close (fd); + return GST_FLOW_ERROR; +} diff --git a/src/gst/gstfddepay.h b/src/gst/gstfddepay.h new file mode 100644 index 000000000..c31e789d4 --- /dev/null +++ b/src/gst/gstfddepay.h @@ -0,0 +1,48 @@ +/* GStreamer + * Copyright (C) 2014 William Manley + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _GST_FDDEPAY_H_ +#define _GST_FDDEPAY_H_ + +#include + +G_BEGIN_DECLS +#define GST_TYPE_FDDEPAY (gst_fddepay_get_type()) +#define GST_FDDEPAY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FDDEPAY,GstFddepay)) +#define GST_FDDEPAY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FDDEPAY,GstFddepayClass)) +#define GST_IS_FDDEPAY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FDDEPAY)) +#define GST_IS_FDDEPAY_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FDDEPAY)) +typedef struct _GstFddepay GstFddepay; +typedef struct _GstFddepayClass GstFddepayClass; + +struct _GstFddepay +{ + GstBaseTransform base_fddepay; + GstAllocator *dmabuf_allocator; +}; + +struct _GstFddepayClass +{ + GstBaseTransformClass base_fddepay_class; +}; + +GType gst_fddepay_get_type (void); + +G_END_DECLS +#endif diff --git a/src/gst/gstfdpay.c b/src/gst/gstfdpay.c new file mode 100644 index 000000000..4b3787e2c --- /dev/null +++ b/src/gst/gstfdpay.c @@ -0,0 +1,276 @@ +/* GStreamer + * Copyright (C) 2014 William Manley + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Suite 500, + * Boston, MA 02110-1335, USA. + */ +/** + * SECTION:element-gstfdpay + * + * The tmpfilepay element enables zero-copy passing of buffers between + * processes by allocating memory in a temporary file. This is a proof of + * concept example. + * + * + * Example launch line + * |[ + * gst-launch-1.0 -v videotestsrc ! video/x-raw,format=RGB,width=1920,height=1080 \ + * ! fdpay ! fdsink fd=1 \ + * | gst-launch-1.0 fdsrc fd=0 ! fddepay \ + * ! video/x-raw,format=RGB,width=1920,height=1080 ! autovideosink + * ]| + * Video frames are created in the first gst-launch-1.0 process and displayed + * by the second with no copying. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "wire-protocol.h" + +#include +#include +#include +#include "gstfdpay.h" +#include "gsttmpfileallocator.h" + +#include +#include + +#include +#include +#include + +GST_DEBUG_CATEGORY_STATIC (gst_fdpay_debug_category); +#define GST_CAT_DEFAULT gst_fdpay_debug_category + +#define GST_UNREF(x) \ + do { \ + if ( x ) \ + gst_object_unref ( x ); \ + x = NULL; \ + } while (0); + + +/* prototypes */ + +static void gst_fdpay_dispose (GObject * object); + +static GstCaps *gst_fdpay_transform_caps (GstBaseTransform * trans, + GstPadDirection direction, GstCaps * caps, GstCaps * filter); +static gboolean gst_fdpay_transform_size (GstBaseTransform *trans, + GstPadDirection direction, GstCaps *caps, gsize size, GstCaps *othercaps, + gsize *othersize); +static gboolean gst_fdpay_propose_allocation (GstBaseTransform * trans, + GstQuery * decide_query, GstQuery * query); +static GstFlowReturn gst_fdpay_transform (GstBaseTransform * trans, + GstBuffer * inbuf, GstBuffer * outbuf); + +/* pad templates */ + +static GstStaticCaps fd_caps = GST_STATIC_CAPS ("application/x-fd"); + +static GstStaticPadTemplate gst_fdpay_src_template = +GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("application/x-fd")); + +static GstStaticPadTemplate gst_fdpay_sink_template = +GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS_ANY); + + +/* class initialization */ + +G_DEFINE_TYPE_WITH_CODE (GstFdpay, gst_fdpay, GST_TYPE_BASE_TRANSFORM, + GST_DEBUG_CATEGORY_INIT (gst_fdpay_debug_category, "fdpay", 0, + "debug category for fdpay element")); + +static void +gst_fdpay_class_init (GstFdpayClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GstBaseTransformClass *base_transform_class = + GST_BASE_TRANSFORM_CLASS (klass); + + /* Setting up pads and setting metadata should be moved to + base_class_init if you intend to subclass this class. */ + gst_element_class_add_pad_template (GST_ELEMENT_CLASS (klass), + gst_static_pad_template_get (&gst_fdpay_src_template)); + gst_element_class_add_pad_template (GST_ELEMENT_CLASS (klass), + gst_static_pad_template_get (&gst_fdpay_sink_template)); + + gst_element_class_set_static_metadata (GST_ELEMENT_CLASS (klass), + "Simple FD Payloader", "Generic", + "Simple File-descriptor Payloader for zero-copy video IPC", + "William Manley "); + + gobject_class->dispose = gst_fdpay_dispose; + base_transform_class->transform_caps = + GST_DEBUG_FUNCPTR (gst_fdpay_transform_caps); + base_transform_class->propose_allocation = + GST_DEBUG_FUNCPTR (gst_fdpay_propose_allocation); + base_transform_class->transform = + GST_DEBUG_FUNCPTR (gst_fdpay_transform); + base_transform_class->transform_size = + GST_DEBUG_FUNCPTR (gst_fdpay_transform_size); +} + +static void +gst_fdpay_init (GstFdpay * fdpay) +{ + fdpay->allocator = gst_tmpfile_allocator_new (); +} + +void +gst_fdpay_dispose (GObject * object) +{ + GstFdpay *fdpay = GST_FDPAY (object); + + GST_DEBUG_OBJECT (fdpay, "dispose"); + + /* clean up as possible. may be called multiple times */ + GST_UNREF(fdpay->allocator); + + G_OBJECT_CLASS (gst_fdpay_parent_class)->dispose (object); +} + +static GstCaps * +gst_fdpay_transform_caps (GstBaseTransform * trans, GstPadDirection direction, + GstCaps * caps, GstCaps * filter) +{ + GstFdpay *fdpay = GST_FDPAY (trans); + GstCaps *othercaps; + + GST_DEBUG_OBJECT (fdpay, "transform_caps"); + + + if (direction == GST_PAD_SRC) { + /* transform caps going upstream */ + othercaps = gst_caps_new_any (); + } else { + /* transform caps going downstream */ + othercaps = gst_static_caps_get (&fd_caps); + } + + if (filter) { + GstCaps *intersect; + + intersect = gst_caps_intersect (othercaps, filter); + gst_caps_unref (othercaps); + + return intersect; + } else { + return othercaps; + } +} + +static gboolean +gst_fdpay_transform_size (GstBaseTransform *trans, GstPadDirection direction, + GstCaps *caps, gsize size, GstCaps *othercaps, gsize *othersize) +{ + if (direction == GST_PAD_SRC) { + /* transform size going upstream - don't know how to do this */ + return FALSE; + } else { + /* transform size going downstream */ + *othersize = sizeof (FDMessage); + } + + return TRUE; +} + +/* propose allocation query parameters for input buffers */ +static gboolean +gst_fdpay_propose_allocation (GstBaseTransform * trans, + GstQuery * decide_query, GstQuery * query) +{ + GstFdpay *fdpay = GST_FDPAY (trans); + + GST_DEBUG_OBJECT (fdpay, "propose_allocation"); + + gst_query_add_allocation_param (query, fdpay->allocator, NULL); + + return TRUE; +} + +static GstMemory * +gst_fdpay_get_fd_memory (GstFdpay * tmpfilepay, GstBuffer * buffer) +{ + GstMemory *mem = NULL; + + if (gst_buffer_n_memory (buffer) == 1 + && gst_is_fd_memory (gst_buffer_peek_memory (buffer, 0))) + mem = gst_buffer_get_memory (buffer, 0); + else { + GstMapInfo info; + GstAllocationParams params = {0, 0, 0, 0, { NULL, }}; + gsize size = gst_buffer_get_size (buffer); + GST_INFO_OBJECT (tmpfilepay, "Buffer cannot be payloaded without copying"); + mem = gst_allocator_alloc (tmpfilepay->allocator, size, ¶ms); + if (!gst_memory_map (mem, &info, GST_MAP_WRITE)) + return NULL; + gst_buffer_extract (buffer, 0, info.data, size); + gst_memory_unmap (mem, &info); + } + return mem; +} + +static GstFlowReturn +gst_fdpay_transform (GstBaseTransform * trans, GstBuffer * inbuf, + GstBuffer * outbuf) +{ + GstFdpay *fdpay = GST_FDPAY (trans); + GstMemory *fdmem = NULL; + GstMapInfo info; + GError *err = NULL; + GSocketControlMessage *fdmsg = NULL; + FDMessage msg = { 0, 0 }; + + GST_DEBUG_OBJECT (fdpay, "transform_ip"); + + fdmem = gst_fdpay_get_fd_memory (fdpay, inbuf); + + msg.size = fdmem->size; + msg.offset = fdmem->offset; + + fdmsg = g_unix_fd_message_new (); + if (!g_unix_fd_message_append_fd ((GUnixFDMessage*) fdmsg, + gst_fd_memory_get_fd (fdmem), &err)) { + goto append_fd_failed; + } + gst_memory_unref(fdmem); + fdmem = NULL; + + gst_buffer_add_net_control_message_meta (outbuf, fdmsg); + g_clear_object (&fdmsg); + + gst_buffer_map (outbuf, &info, GST_MAP_WRITE); + memcpy (info.data, &msg, sizeof (msg)); + gst_buffer_unmap (outbuf, &info); + + return GST_FLOW_OK; +append_fd_failed: + GST_WARNING_OBJECT (trans, "Appending fd failed: %s", err->message); + gst_memory_unref(fdmem); + g_clear_error (&err); + g_clear_object (&fdmsg); + return GST_FLOW_ERROR; +} diff --git a/src/gst/gstfdpay.h b/src/gst/gstfdpay.h new file mode 100644 index 000000000..f506ac57c --- /dev/null +++ b/src/gst/gstfdpay.h @@ -0,0 +1,49 @@ +/* GStreamer + * Copyright (C) 2014 William Manley + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _GST_FDPAY_H_ +#define _GST_FDPAY_H_ + +#include + +G_BEGIN_DECLS +#define GST_TYPE_FDPAY (gst_fdpay_get_type()) +#define GST_FDPAY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FDPAY,GstFdpay)) +#define GST_FDPAY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FDPAY,GstFdpayClass)) +#define GST_IS_FDPAY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FDPAY)) +#define GST_IS_FDPAY_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FDPAY)) +typedef struct _GstFdpay GstFdpay; +typedef struct _GstFdpayClass GstFdpayClass; + +struct _GstFdpay +{ + GstBaseTransform base_fdpay; + GstAllocator * allocator; + +}; + +struct _GstFdpayClass +{ + GstBaseTransformClass base_fdpay_class; +}; + +GType gst_fdpay_get_type (void); + +G_END_DECLS +#endif diff --git a/src/gst/gsttmpfileallocator.c b/src/gst/gsttmpfileallocator.c new file mode 100644 index 000000000..7dfae0749 --- /dev/null +++ b/src/gst/gsttmpfileallocator.c @@ -0,0 +1,145 @@ +/* GStreamer + * Copyright (C) 2014 William Manley + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#define _GNU_SOURCE + +#include "gsttmpfileallocator.h" +#include + +#include +#include +#include +#include + +#define PAGE_ALIGN 4095 + +#define GST_TYPE_TMPFILE_ALLOCATOR (gst_tmpfile_allocator_get_type ()) + +typedef struct +{ + GstFdAllocator parent; +} GstTmpFileAllocator; + +typedef struct +{ + GstFdAllocatorClass parent_class; +} GstTmpFileAllocatorClass; + +GType gst_tmpfile_allocator_get_type (void); +G_DEFINE_TYPE (GstTmpFileAllocator, gst_tmpfile_allocator, GST_TYPE_FD_ALLOCATOR); + +static int +tmpfile_create (GstTmpFileAllocator * allocator, gsize size) +{ + char filename[] = "/dev/shm/tmpfilepay.XXXXXX"; + int fd, result; + + GST_DEBUG_OBJECT (allocator, "tmpfile_create"); + + fd = mkostemp (filename, O_CLOEXEC); + if (fd == -1) { + GST_WARNING_OBJECT (allocator, "Failed to create temporary file: %s", + strerror (errno)); + return -1; + } + unlink (filename); + + result = ftruncate (fd, size); + if (result == -1) { + GST_WARNING_OBJECT (allocator, "Failed to resize temporary file: %s", + strerror (errno)); + close (fd); + return -1; + } + + return fd; +} + + +inline static gsize +pad (gsize off, gsize align) +{ + return (off + align) / (align + 1) * (align + 1); +} + +static GstMemory * +gst_tmpfile_allocator_alloc (GstAllocator * allocator, gsize size, + GstAllocationParams * params) +{ + GstTmpFileAllocator *alloc = (GstTmpFileAllocator *) allocator; + GstFdAllocator *fdalloc = GST_FD_ALLOCATOR_CAST (allocator); + GstFdAllocatorClass *klass = GST_FD_ALLOCATOR_GET_CLASS (alloc); + GstMemory *mem; + int fd; + gsize maxsize; + + g_return_val_if_fail (params != NULL, NULL); + + maxsize = + pad (size + pad (params->prefix, params->align) + params->padding, + PAGE_ALIGN); + + fd = tmpfile_create (alloc, maxsize); + if (fd < 0) + return NULL; + + mem = klass->alloc (fdalloc, fd, maxsize, GST_FD_MEMORY_FLAG_NONE); + gst_memory_resize (mem, pad (params->prefix, params->align), size); + + return mem; +} + +static void +gst_tmpfile_allocator_class_init (GstTmpFileAllocatorClass * klass) +{ + GstAllocatorClass *allocator_class; + + allocator_class = (GstAllocatorClass *) klass; + + allocator_class->alloc = gst_tmpfile_allocator_alloc; +} + +static void +gst_tmpfile_allocator_init (GstTmpFileAllocator * allocator) +{ + GstAllocator *alloc = GST_ALLOCATOR_CAST (allocator); + + alloc->mem_type = GST_ALLOCATOR_TMPFILE; +} + +GstAllocator * +gst_tmpfile_allocator_new (void) +{ + return g_object_new (GST_TYPE_TMPFILE_ALLOCATOR, NULL); +} + +gint +gst_tmpfile_memory_get_fd (GstMemory * mem) +{ + g_return_val_if_fail (gst_is_tmpfile_memory (mem), -1); + + return gst_fd_memory_get_fd (mem); +} + +gboolean +gst_is_tmpfile_memory (GstMemory * mem) +{ + return gst_memory_is_type (mem, GST_ALLOCATOR_TMPFILE); +} + diff --git a/src/gst/gsttmpfileallocator.h b/src/gst/gsttmpfileallocator.h new file mode 100644 index 000000000..7636893ca --- /dev/null +++ b/src/gst/gsttmpfileallocator.h @@ -0,0 +1,37 @@ +/* GStreamer + * Copyright (C) 2014 William Manley + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _GST_TMPFILE_ALLOCATOR_H_ +#define _GST_TMPFILE_ALLOCATOR_H_ + +#include + +G_BEGIN_DECLS + +#define GST_ALLOCATOR_TMPFILE "tmpfile" + + +/* Allocator that allocates memory from a file stored on a tmpfs */ +GstAllocator* gst_tmpfile_allocator_new (void); + +gint gst_tmpfile_memory_get_fd (GstMemory * mem); +gboolean gst_is_tmpfile_memory (GstMemory * mem); + +G_END_DECLS +#endif /* _GST_TMPFILE_ALLOCATOR_H_ */ diff --git a/src/gst/wire-protocol.h b/src/gst/wire-protocol.h new file mode 100644 index 000000000..79735a56c --- /dev/null +++ b/src/gst/wire-protocol.h @@ -0,0 +1,33 @@ +/* GStreamer + * Copyright (C) 2014 William Manley + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _GST_FDPAY_WIRE_PROTOCOL_H_ +#define _GST_FDPAY_WIRE_PROTOCOL_H_ + +#include + +/* Almost the simplest possible FD passing protocol. Each message should have + * a file-descriptor attached which should be mmapable. The data in the FD can + * be found at offset and is size bytes long. */ +typedef struct { + uint64_t offset; + uint64_t size; +} FDMessage; + +#endif diff --git a/src/tests/test-client.c b/src/tests/test-client.c index 7e30e3f84..98da7f0a2 100644 --- a/src/tests/test-client.c +++ b/src/tests/test-client.c @@ -20,8 +20,7 @@ #include #include -#include -#include +#include #define CAPS "video/x-raw, format=(string)YUY2, width=(int)320, height=(int)240, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, framerate=(fraction)30/1" @@ -112,7 +111,7 @@ main (gint argc, gchar *argv[]) { PvContext *c; - gst_init (&argc, &argv); + pv_init (&argc, &argv); loop = g_main_loop_new (NULL, FALSE); diff --git a/src/tests/test-subscribe.c b/src/tests/test-subscribe.c index 739394f08..84ddc6d31 100644 --- a/src/tests/test-subscribe.c +++ b/src/tests/test-subscribe.c @@ -19,8 +19,7 @@ #include -#include -#include +#include static GMainLoop *loop; @@ -60,7 +59,7 @@ main (gint argc, gchar *argv[]) { PvContext *c; - gst_init (&argc, &argv); + pv_init (&argc, &argv); loop = g_main_loop_new (NULL, FALSE);