Rework pay/depay elements

Rename the payloader and depayloader to pinospay/pinosdepay because they
now store data in a pinos specific format.
Subclass GstElement because they are not real transform elements.
Rework/remove some buffer functions that are not used by some more
performant ones.
This commit is contained in:
Wim Taymans 2015-08-27 16:41:25 +02:00
parent eada50916a
commit c2cf359076
13 changed files with 582 additions and 660 deletions

View file

@ -150,8 +150,8 @@ pinos_monitor_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
# Client library #
###################################
pinosgstsource = gst/gstfdpay.h gst/gstfdpay.c \
gst/gstfddepay.h gst/gstfddepay.c \
pinosgstsource = gst/gstpinospay.h gst/gstpinospay.c \
gst/gstpinosdepay.h gst/gstpinosdepay.c \
gst/gsttmpfileallocator.h gst/gsttmpfileallocator.c \
wire-protocol.h
@ -219,8 +219,8 @@ plugin_LTLIBRARIES = libgstpinos.la
libgstpinos_la_SOURCES = \
gst/gstpinos.c \
gst/gstfdpay.c \
gst/gstfddepay.c \
gst/gstpinospay.c \
gst/gstpinosdepay.c \
gst/gstpinosdeviceprovider.c \
gst/gstpinossrc.c \
gst/gstpinossink.c
@ -231,7 +231,7 @@ libgstpinos_la_LIBADD = $(GST_BASE_LIBS) $(GST_LIBS) $(GLIB_LIBS) $(LIBM) -lgst
libpinos-@PINOS_MAJORMINOR@.la libpinoscore-@PINOS_MAJORMINOR@.la
libgstpinos_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
noinst_HEADERS = gst/gstpinossrc.h gst/gstpinossink.h gst/gstfdpay.h gst/gstfddepay.h gst/gstpinosdeviceprovider.h
noinst_HEADERS = gst/gstpinossrc.h gst/gstpinossink.h gst/gstpinospay.h gst/gstpinosdepay.h gst/gstpinosdeviceprovider.h
###################################
# Some minor stuff #

View file

@ -30,18 +30,30 @@
G_STATIC_ASSERT (sizeof (PinosStackBuffer) <= sizeof (PinosBuffer));
/**
* pinos_buffer_init_data:
* @buffer: a #PinosBuffer
* @data: data
* @size: size of @data
* @message: (transfer full): a #GSocketControlMessage
*
* Initialize @buffer with @data and @size and @message. @data and size
* must not be modified until pinos_buffer_clear() is called.
*
* Ownership is taken of @message.
*/
void
pinos_buffer_init_take_data (PinosBuffer *buffer,
gpointer data,
gsize size,
GSocketControlMessage *message)
pinos_buffer_init_data (PinosBuffer *buffer,
gpointer data,
gsize size,
GSocketControlMessage *message)
{
PinosStackBuffer *sb = PSB (buffer);
sb->magic = PSB_MAGIC;
sb->data = data;
sb->size = size;
sb->allocated_size = size;
sb->allocated_size = 0;
sb->message = message;
}
@ -52,7 +64,9 @@ pinos_buffer_clear (PinosBuffer *buffer)
g_return_val_if_fail (is_valid_buffer (buffer), -1);
g_free (sb->data);
sb->magic = 0;
if (sb->allocated_size)
g_free (sb->data);
sb->size = 0;
sb->allocated_size = 0;
g_clear_object (&sb->message);
@ -120,59 +134,39 @@ not_found:
}
/**
* pinos_buffer_get_socket_control_message:
* pinos_buffer_steal_data:
* @buffer: a #PinosBuffer
* @size: output size
* @message: output #GSocketControlMessage
*
* Get the #GSocketControlMessage of @buffer
* Take the data and control message from @buffer.
*
* Returns: the #GSocketControlMessage it remains valid as long as @buffer
* is valid
* Returns: the data of @buffer.
*/
GSocketControlMessage *
pinos_buffer_get_socket_control_message (PinosBuffer *buffer)
{
PinosStackBuffer *sb = PSB (buffer);
g_return_val_if_fail (is_valid_buffer (buffer), NULL);
return sb->message;
}
/**
* pinos_buffer_get_size:
* @buffer: a #PinosBuffer
*
* Get the total size needed to store @buffer with pinos_buffer_store().
*
* Returns: the serialized size of @buffer.
*/
gsize
pinos_buffer_get_size (PinosBuffer *buffer)
gpointer
pinos_buffer_steal (PinosBuffer *buffer,
gsize *size,
GSocketControlMessage **message)
{
PinosStackBuffer *sb = PSB (buffer);
gpointer data;
g_return_val_if_fail (is_valid_buffer (buffer), 0);
return sizeof (PinosStackHeader) + sb->size;
}
if (size)
*size = sb->size;
if (message)
*message = sb->message;
/**
* pinos_buffer_store:
* @buffer: a #PinosBuffer
* @data: destination
*
* Store the contents of @buffer in @data. @data must be large enough, see
* pinos_buffer_get_size().
*/
void
pinos_buffer_store (PinosBuffer *buffer,
gpointer data)
{
PinosStackBuffer *sb = PSB (buffer);
data = sb->data;
g_return_val_if_fail (is_valid_buffer (buffer), 0);
sb->magic = 0;
sb->data = NULL;
sb->size = 0;
sb->allocated_size = 0;
sb->message = NULL;
memcpy (data, sb->data, sizeof (PinosStackHeader) + sb->size);
return data;
}
/**

View file

@ -44,7 +44,7 @@ struct _PinosBuffer {
gsize x[16];
};
void pinos_buffer_init_take_data (PinosBuffer *buffer,
void pinos_buffer_init_data (PinosBuffer *buffer,
gpointer data,
gsize size,
GSocketControlMessage *message);
@ -57,12 +57,10 @@ const PinosBufferHeader *
int pinos_buffer_get_fd (PinosBuffer *buffer,
gint index,
GError **error);
GSocketControlMessage *
pinos_buffer_get_socket_control_message (PinosBuffer *buffer);
gsize pinos_buffer_get_size (PinosBuffer *buffer);
void pinos_buffer_store (PinosBuffer *buffer,
gpointer data);
gpointer pinos_buffer_steal (PinosBuffer *buffer,
gsize *size,
GSocketControlMessage **message);
typedef enum {

View file

@ -1,233 +0,0 @@
/* GStreamer
* Copyright (C) 2014 William Manley <will@williammanley.net>
*
* 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.
*
* <refsect2>
* <title>Example launch line</title>
* |[
* gst-launch -v fakesrc ! fddepay ! FIXME ! fakesink
* ]|
* FIXME Describe what the pipeline does.
* </refsect2>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstfddepay.h"
#include <gst/net/gstnetcontrolmessagemeta.h>
#include <gst/gst.h>
#include <gst/base/gstbasetransform.h>
#include <gst/allocators/gstfdmemory.h>
#include <gio/gunixfdmessage.h>
#include <fcntl.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#include <client/pinos.h>
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 <will@williammanley.net>");
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->fd_allocator = gst_fd_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->fd_allocator != NULL) {
g_object_unref (G_OBJECT (fddepay->fd_allocator));
fddepay->fd_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);
PinosBuffer pbuf;
PinosBufferIter it;
GstNetControlMessageMeta * meta;
GSocketControlMessage *msg = NULL;
const PinosBufferHeader *hdr;
gpointer data;
gsize size;
GError *err = NULL;
GST_DEBUG_OBJECT (fddepay, "transform_ip");
gst_buffer_extract_dup (buf, 0, gst_buffer_get_size (buf), &data, &size);
meta = ((GstNetControlMessageMeta*) gst_buffer_get_meta (
buf, GST_NET_CONTROL_MESSAGE_META_API_TYPE));
if (meta) {
msg = meta->message;
gst_buffer_remove_meta (buf, (GstMeta *) meta);
meta = NULL;
}
pinos_buffer_init_take_data (&pbuf, data, size, msg);
gst_buffer_remove_all_memory (buf);
pinos_buffer_iter_init (&it, &pbuf);
while (pinos_buffer_iter_next (&it)) {
switch (pinos_buffer_iter_get_type (&it)) {
case PINOS_PACKET_TYPE_FD_PAYLOAD:
{
GstMemory *fdmem = NULL;
PinosPacketFDPayload p;
int fd;
pinos_buffer_iter_parse_fd_payload (&it, &p);
fd = pinos_buffer_get_fd (&pbuf, p.fd_index, &err);
if (fd == -1)
goto error;
fdmem = gst_fd_allocator_alloc (fddepay->fd_allocator, fd,
p.offset + p.size, GST_FD_MEMORY_FLAG_NONE);
gst_memory_resize (fdmem, p.offset, p.size);
gst_buffer_append_memory (buf, fdmem);
break;
}
default:
break;
}
}
hdr = pinos_buffer_get_header (&pbuf, NULL);
GST_BUFFER_OFFSET (buf) = hdr->seq;
return GST_FLOW_OK;
error:
{
GST_ELEMENT_ERROR (fddepay, RESOURCE, SETTINGS, (NULL),
("can't get fd: %s", err->message));
g_clear_error (&err);
return GST_FLOW_ERROR;
}
}

View file

@ -1,297 +0,0 @@
/* GStreamer
* Copyright (C) 2014 William Manley <will@williammanley.net>
*
* 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.
*
* <refsect2>
* <title>Example launch line</title>
* |[
* 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.
* </refsect2>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gst/gst.h>
#include <gst/allocators/gstfdmemory.h>
#include <gst/base/gstbasetransform.h>
#include "gstfdpay.h"
#include "gsttmpfileallocator.h"
#include <gst/net/gstnetcontrolmessagemeta.h>
#include <gio/gunixfdmessage.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <client/pinos.h>
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 <will@williammanley.net>");
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 (PinosBuffer) + 30;
}
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, &params);
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;
PinosBuffer pbuf;
PinosBufferBuilder builder;
PinosBufferHeader hdr;
PinosPacketFDPayload p;
gsize size;
GST_DEBUG_OBJECT (fdpay, "transform_ip");
fdmem = gst_fdpay_get_fd_memory (fdpay, inbuf);
hdr.flags = 0;
hdr.seq = GST_BUFFER_OFFSET (inbuf);
hdr.pts = GST_BUFFER_TIMESTAMP (inbuf) + GST_ELEMENT_CAST (trans)->base_time;
hdr.dts_offset = 0;
pinos_buffer_builder_init (&builder);
pinos_buffer_builder_set_header (&builder, &hdr);
p.fd_index = pinos_buffer_builder_add_fd (&builder, gst_fd_memory_get_fd (fdmem), &err);
if (p.fd_index == -1)
goto add_fd_failed;
p.id = 0;
p.offset = fdmem->offset;
p.size = fdmem->size;
pinos_buffer_builder_add_fd_payload (&builder, &p);
pinos_buffer_builder_end (&builder, &pbuf);
gst_memory_unref(fdmem);
fdmem = NULL;
gst_buffer_add_net_control_message_meta (outbuf,
pinos_buffer_get_socket_control_message (&pbuf));
size = pinos_buffer_get_size (&pbuf);
gst_buffer_map (outbuf, &info, GST_MAP_WRITE);
pinos_buffer_store (&pbuf, info.data);
gst_buffer_unmap (outbuf, &info);
gst_buffer_resize (outbuf, 0, size);
pinos_buffer_clear (&pbuf);
return GST_FLOW_OK;
/* ERRORS */
add_fd_failed:
{
GST_WARNING_OBJECT (trans, "Adding fd failed: %s", err->message);
gst_memory_unref(fdmem);
g_clear_error (&err);
return GST_FLOW_ERROR;
}
}

View file

@ -1,49 +0,0 @@
/* GStreamer
* Copyright (C) 2014 William Manley <will@williammanley.net>
*
* 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 <gst/base/gstbasetransform.h>
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

View file

@ -35,18 +35,18 @@
#include "gstpinossrc.h"
#include "gstpinossink.h"
#include "gstpinosdeviceprovider.h"
#include "gstfdpay.h"
#include "gstfddepay.h"
#include "gstpinospay.h"
#include "gstpinosdepay.h"
GST_DEBUG_CATEGORY (pinos_debug);
static gboolean
plugin_init (GstPlugin * plugin)
{
gst_element_register (plugin, "pinosfdpay", GST_RANK_NONE,
GST_TYPE_FDPAY);
gst_element_register (plugin, "pinosfddepay", GST_RANK_NONE,
GST_TYPE_FDDEPAY);
gst_element_register (plugin, "pinospay", GST_RANK_NONE,
GST_TYPE_PINOS_PAY);
gst_element_register (plugin, "pinosdepay", GST_RANK_NONE,
GST_TYPE_PINOS_DEPAY);
gst_element_register (plugin, "pinossrc", GST_RANK_PRIMARY + 1,
GST_TYPE_PINOS_SRC);
gst_element_register (plugin, "pinossink", GST_RANK_NONE,

192
src/gst/gstpinosdepay.c Normal file
View file

@ -0,0 +1,192 @@
/* GStreamer
* Copyright (C) 2014 William Manley <will@williammanley.net>
* (C) 2015 Wim Taymans <wim.taymans@gmail.com>
*
* 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-gstpinosdepay
*
* The pinosdepay element does FIXME stuff.
*
* <refsect2>
* <title>Example launch line</title>
* |[
* gst-launch -v fakesrc ! pinosdepay ! FIXME ! fakesink
* ]|
* FIXME Describe what the pipeline does.
* </refsect2>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstpinosdepay.h"
#include <gst/net/gstnetcontrolmessagemeta.h>
#include <gst/gst.h>
#include <gst/base/gstbasetransform.h>
#include <gst/allocators/gstfdmemory.h>
#include <gio/gunixfdmessage.h>
#include <fcntl.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#include <client/pinos.h>
GST_DEBUG_CATEGORY_STATIC (gst_pinos_depay_debug_category);
#define GST_CAT_DEFAULT gst_pinos_depay_debug_category
/* prototypes */
/* pad templates */
static GstStaticPadTemplate gst_pinos_depay_src_template =
GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS_ANY);
static GstStaticPadTemplate gst_pinos_depay_sink_template =
GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("application/x-pinos"));
/* class initialization */
G_DEFINE_TYPE_WITH_CODE (GstPinosDepay, gst_pinos_depay, GST_TYPE_ELEMENT,
GST_DEBUG_CATEGORY_INIT (gst_pinos_depay_debug_category, "pinosdepay", 0,
"debug category for pinosdepay element"));
static GstFlowReturn
gst_pinos_depay_chain (GstPad *pad, GstObject * parent, GstBuffer * buffer)
{
GstPinosDepay *depay = GST_PINOS_DEPAY (parent);
GstBuffer *outbuf;
GstMapInfo info;
PinosBuffer pbuf;
PinosBufferIter it;
GstNetControlMessageMeta * meta;
GSocketControlMessage *msg = NULL;
const PinosBufferHeader *hdr;
GError *err = NULL;
meta = ((GstNetControlMessageMeta*) gst_buffer_get_meta (
buffer, GST_NET_CONTROL_MESSAGE_META_API_TYPE));
if (meta) {
msg = meta->message;
gst_buffer_remove_meta (buffer, (GstMeta *) meta);
meta = NULL;
}
outbuf = gst_buffer_new ();
gst_buffer_map (buffer, &info, GST_MAP_READ);
pinos_buffer_init_data (&pbuf, info.data, info.size, msg);
pinos_buffer_iter_init (&it, &pbuf);
while (pinos_buffer_iter_next (&it)) {
switch (pinos_buffer_iter_get_type (&it)) {
case PINOS_PACKET_TYPE_FD_PAYLOAD:
{
GstMemory *fdmem = NULL;
PinosPacketFDPayload p;
int fd;
pinos_buffer_iter_parse_fd_payload (&it, &p);
fd = pinos_buffer_get_fd (&pbuf, p.fd_index, &err);
if (fd == -1)
goto error;
fdmem = gst_fd_allocator_alloc (depay->fd_allocator, fd,
p.offset + p.size, GST_FD_MEMORY_FLAG_NONE);
gst_memory_resize (fdmem, p.offset, p.size);
gst_buffer_append_memory (outbuf, fdmem);
break;
}
default:
break;
}
}
hdr = pinos_buffer_get_header (&pbuf, NULL);
GST_BUFFER_OFFSET (buffer) = hdr->seq;
pinos_buffer_clear (&pbuf);
gst_buffer_unmap (buffer, &info);
gst_buffer_unref (buffer);
return gst_pad_push (depay->srcpad, outbuf);
error:
{
GST_ELEMENT_ERROR (depay, RESOURCE, SETTINGS, (NULL),
("can't get fd: %s", err->message));
g_clear_error (&err);
return GST_FLOW_ERROR;
}
}
static void
gst_pinos_depay_finalize (GObject * object)
{
GstPinosDepay *depay = GST_PINOS_DEPAY (object);
GST_DEBUG_OBJECT (depay, "finalize");
g_object_unref (depay->fd_allocator);
G_OBJECT_CLASS (gst_pinos_depay_parent_class)->finalize (object);
}
static void
gst_pinos_depay_class_init (GstPinosDepayClass * klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GstElementClass *element_class =
GST_ELEMENT_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 (element_class,
gst_static_pad_template_get (&gst_pinos_depay_src_template));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&gst_pinos_depay_sink_template));
gst_element_class_set_static_metadata (element_class,
"Pinos Deplayloder", "Generic",
"Pinos Depayloader for zero-copy IPC via Pinos",
"Wim Taymans <wim.taymans@gmail.com>");
gobject_class->finalize = gst_pinos_depay_finalize;
}
static void
gst_pinos_depay_init (GstPinosDepay * depay)
{
depay->srcpad = gst_pad_new_from_static_template (&gst_pinos_depay_src_template, "src");
gst_element_add_pad (GST_ELEMENT (depay), depay->srcpad);
depay->sinkpad = gst_pad_new_from_static_template (&gst_pinos_depay_sink_template, "sink");
gst_pad_set_chain_function (depay->sinkpad, gst_pinos_depay_chain);
gst_element_add_pad (GST_ELEMENT (depay), depay->sinkpad);
depay->fd_allocator = gst_fd_allocator_new ();
}

View file

@ -1,5 +1,6 @@
/* GStreamer
* Copyright (C) 2014 William Manley <will@williammanley.net>
* Copyright (C) 2015 Wim Taymans <wim.taymans@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@ -17,32 +18,37 @@
* Boston, MA 02110-1301, USA.
*/
#ifndef _GST_FDDEPAY_H_
#define _GST_FDDEPAY_H_
#ifndef _GST_PINOS_DEPAY_H_
#define _GST_PINOS_DEPAY_H_
#include <gst/base/gstbasetransform.h>
#include <gst/gst.h>
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
#define GST_TYPE_PINOS_DEPAY (gst_pinos_depay_get_type())
#define GST_PINOS_DEPAY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PINOS_DEPAY,GstPinosDepay))
#define GST_PINOS_DEPAY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PINOS_DEPAY,GstPinosDepayClass))
#define GST_IS_PINOS_DEPAY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PINOS_DEPAY))
#define GST_IS_PINOS_DEPAY_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PINOS_DEPAY))
typedef struct _GstPinosDepay GstPinosDepay;
typedef struct _GstPinosDepayClass GstPinosDepayClass;
struct _GstPinosDepay
{
GstBaseTransform base_fddepay;
GstElement parent;
GstPad *srcpad, *sinkpad;
GstAllocator *fd_allocator;
};
struct _GstFddepayClass
struct _GstPinosDepayClass
{
GstBaseTransformClass base_fddepay_class;
GstElementClass parent_class;
};
GType gst_fddepay_get_type (void);
GType gst_pinos_depay_get_type (void);
G_END_DECLS
#endif

254
src/gst/gstpinospay.c Normal file
View file

@ -0,0 +1,254 @@
/* GStreamer
* Copyright (C) 2014 William Manley <will@williammanley.net>
*
* 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-gstpinospay
*
* The pinospay element converts regular GStreamer buffers into the format
* expected by Pinos.
*
* <refsect2>
* <title>Example launch line</title>
* |[
* gst-launch-1.0 -v videotestsrc ! video/x-raw,format=RGB,width=1920,height=1080 \
* ! pinospay ! 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.
* </refsect2>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gst/gst.h>
#include <gst/allocators/gstfdmemory.h>
#include <gst/base/gstbasetransform.h>
#include "gstpinospay.h"
#include "gsttmpfileallocator.h"
#include <gst/net/gstnetcontrolmessagemeta.h>
#include <gio/gunixfdmessage.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <client/pinos.h>
GST_DEBUG_CATEGORY_STATIC (gst_pinos_pay_debug_category);
#define GST_CAT_DEFAULT gst_pinos_pay_debug_category
/* prototypes */
/* pad templates */
static GstStaticPadTemplate gst_pinos_pay_src_template =
GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("application/x-pinos"));
static GstStaticPadTemplate gst_pinos_pay_sink_template =
GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS_ANY);
/* class initialization */
G_DEFINE_TYPE_WITH_CODE (GstPinosPay, gst_pinos_pay, GST_TYPE_ELEMENT,
GST_DEBUG_CATEGORY_INIT (gst_pinos_pay_debug_category, "pinospay", 0,
"debug category for pinospay element"));
/* propose allocation query parameters for input buffers */
static gboolean
gst_pinos_pay_query (GstPad * pad, GstObject * parent, GstQuery * query)
{
GstPinosPay *pay = GST_PINOS_PAY (parent);
gboolean res = FALSE;
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_ALLOCATION:
{
GST_DEBUG_OBJECT (pay, "propose_allocation");
gst_query_add_allocation_param (query, pay->allocator, NULL);
res = TRUE;
break;
}
default:
res = gst_pad_query_default (pad, parent, query);
break;
}
return res;
}
static gboolean
gst_pinos_pay_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
{
GstPinosPay *pay = GST_PINOS_PAY (parent);
gboolean res = FALSE;
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_CAPS:
{
GstCaps *caps;
caps = gst_caps_new_empty_simple ("application/x-pinos");
res = gst_pad_push_event (pay->srcpad, gst_event_new_caps (caps));
gst_caps_unref (caps);
gst_event_unref (event);
break;
}
default:
res = gst_pad_event_default (pad, parent, event);
break;
}
return res;
}
static GstMemory *
gst_pinos_pay_get_fd_memory (GstPinosPay * 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, &params);
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_pinos_pay_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
{
GstPinosPay *pay = GST_PINOS_PAY (parent);
GstMemory *fdmem = NULL;
GError *err = NULL;
GstBuffer *outbuf;
PinosBuffer pbuf;
PinosBufferBuilder builder;
PinosBufferHeader hdr;
PinosPacketFDPayload p;
gsize size;
gpointer data;
GSocketControlMessage *msg;
hdr.flags = 0;
hdr.seq = GST_BUFFER_OFFSET (buffer);
hdr.pts = GST_BUFFER_PTS (buffer) + GST_ELEMENT_CAST (pay)->base_time;
hdr.dts_offset = 0;
pinos_buffer_builder_init (&builder);
pinos_buffer_builder_set_header (&builder, &hdr);
fdmem = gst_pinos_pay_get_fd_memory (pay, buffer);
p.fd_index = pinos_buffer_builder_add_fd (&builder, gst_fd_memory_get_fd (fdmem), &err);
if (p.fd_index == -1)
goto add_fd_failed;
p.id = 0;
p.offset = fdmem->offset;
p.size = fdmem->size;
pinos_buffer_builder_add_fd_payload (&builder, &p);
pinos_buffer_builder_end (&builder, &pbuf);
gst_memory_unref(fdmem);
fdmem = NULL;
data = pinos_buffer_steal (&pbuf, &size, &msg);
outbuf = gst_buffer_new_wrapped (data, size);
GST_BUFFER_PTS (outbuf) = GST_BUFFER_PTS (buffer);
GST_BUFFER_DTS (outbuf) = GST_BUFFER_DTS (buffer);
GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buffer);
GST_BUFFER_OFFSET (outbuf) = GST_BUFFER_OFFSET (buffer);
GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET_END (buffer);
gst_buffer_unref (buffer);
gst_buffer_add_net_control_message_meta (outbuf, msg);
g_object_unref (msg);
return gst_pad_push (pay->srcpad, outbuf);
/* ERRORS */
add_fd_failed:
{
GST_WARNING_OBJECT (pay, "Adding fd failed: %s", err->message);
gst_memory_unref(fdmem);
g_clear_error (&err);
return GST_FLOW_ERROR;
}
}
static void
gst_pinos_pay_finalize (GObject * object)
{
GstPinosPay *pay = GST_PINOS_PAY (object);
GST_DEBUG_OBJECT (pay, "finalize");
g_object_unref (pay->allocator);
G_OBJECT_CLASS (gst_pinos_pay_parent_class)->finalize (object);
}
static void
gst_pinos_pay_init (GstPinosPay * pay)
{
pay->srcpad = gst_pad_new_from_static_template (&gst_pinos_pay_src_template, "src");
gst_element_add_pad (GST_ELEMENT (pay), pay->srcpad);
pay->sinkpad = gst_pad_new_from_static_template (&gst_pinos_pay_sink_template, "sink");
gst_pad_set_chain_function (pay->sinkpad, gst_pinos_pay_chain);
gst_pad_set_event_function (pay->sinkpad, gst_pinos_pay_sink_event);
gst_pad_set_query_function (pay->sinkpad, gst_pinos_pay_query);
gst_element_add_pad (GST_ELEMENT (pay), pay->sinkpad);
pay->allocator = gst_tmpfile_allocator_new ();
}
static void
gst_pinos_pay_class_init (GstPinosPayClass * klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&gst_pinos_pay_src_template));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&gst_pinos_pay_sink_template));
gst_element_class_set_static_metadata (element_class,
"Pinos Payloader", "Generic",
"Pinos Payloader for zero-copy IPC with Pinos",
"Wim Taymans <wim.taymans@gmail.com>");
gobject_class->finalize = gst_pinos_pay_finalize;
}

57
src/gst/gstpinospay.h Normal file
View file

@ -0,0 +1,57 @@
/* GStreamer
* Copyright (C) 2014 William Manley <will@williammanley.net>
* (C) 2015 Wim Taymans <wim.taymans@gmail.com>
*
* 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_PINOS_PAY_H_
#define _GST_PINOS_PAY_H_
#include <gst/gst.h>
G_BEGIN_DECLS
#define GST_TYPE_PINOS_PAY (gst_pinos_pay_get_type())
#define GST_PINOS_PAY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PINOS_PAY,GstPinosPay))
#define GST_PINOS_PAY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PINOS_PAY,GstPinosPayClass))
#define GST_IS_PINOS_PAY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PINOS_PAY))
#define GST_IS_PINOS_PAY_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PINOS_PAY))
typedef struct _GstPinosPay GstPinosPay;
typedef struct _GstPinosPayClass GstPinosPayClass;
struct _GstPinosPay
{
GstElement parent;
gboolean negotiated;
GstPad *srcpad, *sinkpad;
GstAllocator *allocator;
};
struct _GstPinosPayClass
{
GstElementClass parent_class;
};
GType gst_pinos_pay_get_type (void);
G_END_DECLS
#endif

View file

@ -126,7 +126,7 @@ setup_pipeline (PinosGstSource *source, GError **error)
gst_bin_add (GST_BIN (priv->pipeline), priv->filter);
gst_element_link (priv->element, priv->filter);
elem = gst_element_factory_make ("pinosfdpay", NULL);
elem = gst_element_factory_make ("pinospay", NULL);
gst_bin_add (GST_BIN (priv->pipeline), elem);
gst_element_link (priv->filter, elem);

View file

@ -38,7 +38,7 @@ on_socket_notify (GObject *gobject,
GstCaps *caps;
GError *error = NULL;
pipeline = gst_parse_launch ("socketsrc name=src ! pinosfddepay ! capsfilter name=filter ! videoconvert ! xvimagesink", &error);
pipeline = gst_parse_launch ("socketsrc name=src ! pinosdepay ! capsfilter name=filter ! videoconvert ! xvimagesink", &error);
if (error != NULL) {
g_warning ("error creating pipeline: %s", error->message);
g_clear_error (&error);