mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	Cleanups
Remove old code Only depend on GStreamer for the plugins Rename STOP to PAUSE because that's what it really does Start working on format_fixate. Remove default property value from props Fix framerate
This commit is contained in:
		
							parent
							
								
									da5fb808e7
								
							
						
					
					
						commit
						fbd6304663
					
				
					 43 changed files with 97 additions and 3631 deletions
				
			
		| 
						 | 
					@ -161,8 +161,6 @@ pinos_monitor_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
 | 
				
			||||||
#         Client library          #
 | 
					#         Client library          #
 | 
				
			||||||
###################################
 | 
					###################################
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pinosgstsource = gst/gsttmpfileallocator.h gst/gsttmpfileallocator.c
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pinosinclude_HEADERS = \
 | 
					pinosinclude_HEADERS = \
 | 
				
			||||||
		client/context.h \
 | 
							client/context.h \
 | 
				
			||||||
		client/enumtypes.h \
 | 
							client/enumtypes.h \
 | 
				
			||||||
| 
						 | 
					@ -189,13 +187,11 @@ libpinos_@PINOS_MAJORMINOR@_la_SOURCES = \
 | 
				
			||||||
		client/pinos.c client/pinos.h \
 | 
							client/pinos.c client/pinos.h \
 | 
				
			||||||
		client/fdmanager.c client/fdmanager.h \
 | 
							client/fdmanager.c client/fdmanager.h \
 | 
				
			||||||
		client/ringbuffer.c client/ringbuffer.h \
 | 
							client/ringbuffer.c client/ringbuffer.h \
 | 
				
			||||||
		client/subscribe.c client/subscribe.h \
 | 
							client/subscribe.c client/subscribe.h
 | 
				
			||||||
		$(pinosgstsource)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					libpinos_@PINOS_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS)
 | 
				
			||||||
libpinos_@PINOS_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) $(GST_CFLAGS)
 | 
					 | 
				
			||||||
libpinos_@PINOS_MAJORMINOR@_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version
 | 
					libpinos_@PINOS_MAJORMINOR@_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version
 | 
				
			||||||
libpinos_@PINOS_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) $(LTLIBICONV) $(GST_LIBS) $(GST_BASE_LIBS) -lgstvideo-1.0 -lgstaudio-1.0
 | 
					libpinos_@PINOS_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) $(LTLIBICONV)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
###################################
 | 
					###################################
 | 
				
			||||||
#      Daemon core library        #
 | 
					#      Daemon core library        #
 | 
				
			||||||
| 
						 | 
					@ -241,24 +237,16 @@ libgstpinos_la_SOURCES = \
 | 
				
			||||||
                        gst/gstpinossrc.c \
 | 
					                        gst/gstpinossrc.c \
 | 
				
			||||||
                        gst/gstpinossink.c  \
 | 
					                        gst/gstpinossink.c  \
 | 
				
			||||||
                        gst/gstpinospool.c
 | 
					                        gst/gstpinospool.c
 | 
				
			||||||
                        #gst/gstpinosdepay.c
 | 
					 | 
				
			||||||
                        #gst/gstpinosportsrc.c
 | 
					 | 
				
			||||||
                        #gst/gstpinosportsink.c
 | 
					 | 
				
			||||||
                        #gst/gstpinossocketsink.c
 | 
					 | 
				
			||||||
                        #gst/gstpinospay.c
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
libgstpinos_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(GLIB_CFLAGS)
 | 
					libgstpinos_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(GLIB_CFLAGS)
 | 
				
			||||||
libgstpinos_la_LDFLAGS = $(AM_LDFLAGS) $(GST_PLUGIN_LDFLAGS)
 | 
					libgstpinos_la_LDFLAGS = $(AM_LDFLAGS) $(GST_PLUGIN_LDFLAGS)
 | 
				
			||||||
libgstpinos_la_LIBADD =  $(GST_BASE_LIBS) $(GST_LIBS) $(GLIB_LIBS) $(LIBM) -lgstvideo-1.0 \
 | 
					libgstpinos_la_LIBADD =  $(GST_BASE_LIBS) $(GST_LIBS) $(GLIB_LIBS) $(LIBM) -lgstvideo-1.0 -lgstaudio-1.0 \
 | 
				
			||||||
			 libpinos-@PINOS_MAJORMINOR@.la libpinoscore-@PINOS_MAJORMINOR@.la $(AM_LIBADD)
 | 
								 libpinos-@PINOS_MAJORMINOR@.la libpinoscore-@PINOS_MAJORMINOR@.la $(AM_LIBADD)
 | 
				
			||||||
libgstpinos_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
 | 
					libgstpinos_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
noinst_HEADERS = gst/gstburstcache.h gst/gstpinossrc.h \
 | 
					noinst_HEADERS = gst/gstburstcache.h gst/gstpinossrc.h \
 | 
				
			||||||
		 gst/gstpinossocketsink.h gst/gstpinosportsink.h \
 | 
					 | 
				
			||||||
		 gst/gstpinosportsrc.h \
 | 
					 | 
				
			||||||
		 gst/gstpinosformat.h \
 | 
							 gst/gstpinosformat.h \
 | 
				
			||||||
		 gst/gstpinossink.h gst/gstpinospay.h \
 | 
							 gst/gstpinossink.h gst/gstpinosdeviceprovider.h
 | 
				
			||||||
		 gst/gstpinosdepay.h gst/gstpinosdeviceprovider.h
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
###################################
 | 
					###################################
 | 
				
			||||||
#        Some minor stuff         #
 | 
					#        Some minor stuff         #
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,7 +17,7 @@
 | 
				
			||||||
 * Boston, MA 02110-1301, USA.
 | 
					 * Boston, MA 02110-1301, USA.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <gst/gst.h>
 | 
					#include <glib.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "pinos/client/pinos.h"
 | 
					#include "pinos/client/pinos.h"
 | 
				
			||||||
#include "spa/include/spa/memory.h"
 | 
					#include "spa/include/spa/memory.h"
 | 
				
			||||||
| 
						 | 
					@ -33,7 +33,6 @@
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
pinos_init (int *argc, char **argv[])
 | 
					pinos_init (int *argc, char **argv[])
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  gst_init (argc, argv);
 | 
					 | 
				
			||||||
  spa_memory_init ();
 | 
					  spa_memory_init ();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -769,7 +769,7 @@ parse_control (PinosStream *stream,
 | 
				
			||||||
        stream_set_state (stream, PINOS_STREAM_STATE_STREAMING, NULL);
 | 
					        stream_set_state (stream, PINOS_STREAM_STATE_STREAMING, NULL);
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      case SPA_CONTROL_CMD_STOP:
 | 
					      case SPA_CONTROL_CMD_PAUSE:
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        SpaControlBuilder builder;
 | 
					        SpaControlBuilder builder;
 | 
				
			||||||
        SpaControl control;
 | 
					        SpaControl control;
 | 
				
			||||||
| 
						 | 
					@ -1292,7 +1292,7 @@ do_stop (PinosStream *stream)
 | 
				
			||||||
  SpaControlBuilder builder;
 | 
					  SpaControlBuilder builder;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  control_builder_init (stream, &builder);
 | 
					  control_builder_init (stream, &builder);
 | 
				
			||||||
  spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_STOP, NULL);
 | 
					  spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_PAUSE, NULL);
 | 
				
			||||||
  g_object_unref (stream);
 | 
					  g_object_unref (stream);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return FALSE;
 | 
					  return FALSE;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -32,14 +32,9 @@
 | 
				
			||||||
#include "config.h"
 | 
					#include "config.h"
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//#include "gstpinossocketsink.h"
 | 
					 | 
				
			||||||
#include "gstpinosportsink.h"
 | 
					 | 
				
			||||||
#include "gstpinosportsrc.h"
 | 
					 | 
				
			||||||
#include "gstpinossrc.h"
 | 
					#include "gstpinossrc.h"
 | 
				
			||||||
#include "gstpinossink.h"
 | 
					#include "gstpinossink.h"
 | 
				
			||||||
#include "gstpinosdeviceprovider.h"
 | 
					#include "gstpinosdeviceprovider.h"
 | 
				
			||||||
#include "gstpinospay.h"
 | 
					 | 
				
			||||||
#include "gstpinosdepay.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
GST_DEBUG_CATEGORY (pinos_debug);
 | 
					GST_DEBUG_CATEGORY (pinos_debug);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -48,20 +43,10 @@ plugin_init (GstPlugin * plugin)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  pinos_init (NULL, NULL);
 | 
					  pinos_init (NULL, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//  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_element_register (plugin, "pinossrc", GST_RANK_PRIMARY + 1,
 | 
				
			||||||
      GST_TYPE_PINOS_SRC);
 | 
					      GST_TYPE_PINOS_SRC);
 | 
				
			||||||
  gst_element_register (plugin, "pinossink", GST_RANK_NONE,
 | 
					  gst_element_register (plugin, "pinossink", GST_RANK_NONE,
 | 
				
			||||||
      GST_TYPE_PINOS_SINK);
 | 
					      GST_TYPE_PINOS_SINK);
 | 
				
			||||||
 // gst_element_register (plugin, "pinossocketsink", GST_RANK_NONE,
 | 
					 | 
				
			||||||
 //     GST_TYPE_PINOS_SOCKET_SINK);
 | 
					 | 
				
			||||||
 // gst_element_register (plugin, "pinosportsink", GST_RANK_NONE,
 | 
					 | 
				
			||||||
 //     GST_TYPE_PINOS_PORT_SINK);
 | 
					 | 
				
			||||||
//  gst_element_register (plugin, "pinosportsrc", GST_RANK_NONE,
 | 
					 | 
				
			||||||
//      GST_TYPE_PINOS_PORT_SRC);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (!gst_device_provider_register (plugin, "pinosdeviceprovider",
 | 
					  if (!gst_device_provider_register (plugin, "pinosdeviceprovider",
 | 
				
			||||||
       GST_RANK_PRIMARY + 1, GST_TYPE_PINOS_DEVICE_PROVIDER))
 | 
					       GST_RANK_PRIMARY + 1, GST_TYPE_PINOS_DEVICE_PROVIDER))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,409 +0,0 @@
 | 
				
			||||||
/* 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
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static GQuark fdids_quark;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
enum
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  PROP_0,
 | 
					 | 
				
			||||||
  PROP_CAPS,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* 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 (GstPinosDepay, gst_pinos_depay, GST_TYPE_ELEMENT);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static gboolean
 | 
					 | 
				
			||||||
gst_pinos_depay_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GstPinosDepay *depay = GST_PINOS_DEPAY (parent);
 | 
					 | 
				
			||||||
  gboolean res = FALSE;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  switch (GST_EVENT_TYPE (event)) {
 | 
					 | 
				
			||||||
    case GST_EVENT_SEGMENT:
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      GstSegment segment;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      gst_segment_init (&segment, GST_FORMAT_TIME);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      res = gst_pad_push_event (depay->srcpad, gst_event_new_segment (&segment));
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    case GST_EVENT_CAPS:
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      GstCaps *caps;
 | 
					 | 
				
			||||||
      GstStructure *str;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      gst_event_parse_caps (event, &caps);
 | 
					 | 
				
			||||||
      str = gst_caps_get_structure (caps, 0);
 | 
					 | 
				
			||||||
      depay->pinos_input = gst_structure_has_name (str, "application/x-pinos");
 | 
					 | 
				
			||||||
      gst_event_unref (event);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      res = gst_pad_push_event (depay->srcpad, gst_event_new_caps (depay->caps));
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    default:
 | 
					 | 
				
			||||||
      res = gst_pad_event_default (pad, parent, event);
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  return res;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
reuse_fds (GstPinosDepay *this, GstBuffer *buffer)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GArray *fdids;
 | 
					 | 
				
			||||||
  guint i;
 | 
					 | 
				
			||||||
  PinosBufferBuilder b;
 | 
					 | 
				
			||||||
  PinosPacketReuseMem r;
 | 
					 | 
				
			||||||
  PinosBuffer pbuf;
 | 
					 | 
				
			||||||
  gsize size;
 | 
					 | 
				
			||||||
  gpointer data;
 | 
					 | 
				
			||||||
  GstBuffer *outbuf;
 | 
					 | 
				
			||||||
  GstEvent *ev;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  fdids = gst_mini_object_steal_qdata (GST_MINI_OBJECT_CAST (buffer),
 | 
					 | 
				
			||||||
      fdids_quark);
 | 
					 | 
				
			||||||
  if (fdids == NULL)
 | 
					 | 
				
			||||||
    return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  pinos_buffer_builder_init (&b);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  for (i = 0; i < fdids->len; i++) {
 | 
					 | 
				
			||||||
    r.id = g_array_index (fdids, guint32, i);
 | 
					 | 
				
			||||||
    GST_LOG ("reuse mem id %d", r.id);
 | 
					 | 
				
			||||||
    pinos_buffer_builder_add_reuse_mem (&b, &r);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  pinos_buffer_builder_end (&b, &pbuf);
 | 
					 | 
				
			||||||
  g_array_unref (fdids);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  data = pinos_buffer_steal_data (&pbuf, &size);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  outbuf = gst_buffer_new_wrapped (data, size);
 | 
					 | 
				
			||||||
  ev = gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
 | 
					 | 
				
			||||||
          gst_structure_new ("GstNetworkMessage",
 | 
					 | 
				
			||||||
              "object", G_TYPE_OBJECT, this,
 | 
					 | 
				
			||||||
              "buffer", GST_TYPE_BUFFER, outbuf, NULL));
 | 
					 | 
				
			||||||
  gst_buffer_unref (outbuf);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  gst_pad_push_event (this->sinkpad, ev);
 | 
					 | 
				
			||||||
  g_object_unref (this);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static GstFlowReturn
 | 
					 | 
				
			||||||
gst_pinos_depay_chain (GstPad *pad, GstObject * parent, GstBuffer * buffer)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GstPinosDepay *depay = GST_PINOS_DEPAY (parent);
 | 
					 | 
				
			||||||
  GstBuffer *outbuf = NULL;
 | 
					 | 
				
			||||||
  GstMapInfo info;
 | 
					 | 
				
			||||||
  PinosBuffer pbuf;
 | 
					 | 
				
			||||||
  PinosBufferIter it;
 | 
					 | 
				
			||||||
  GstNetControlMessageMeta * meta;
 | 
					 | 
				
			||||||
  GError *err = NULL;
 | 
					 | 
				
			||||||
  GArray *fdids = NULL;
 | 
					 | 
				
			||||||
  GUnixFDList *fds = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  meta = ((GstNetControlMessageMeta*) gst_buffer_get_meta (
 | 
					 | 
				
			||||||
      buffer, GST_NET_CONTROL_MESSAGE_META_API_TYPE));
 | 
					 | 
				
			||||||
  if (meta) {
 | 
					 | 
				
			||||||
    if (G_IS_UNIX_FD_MESSAGE (meta->message)) {
 | 
					 | 
				
			||||||
      fds = g_unix_fd_message_get_fd_list (G_UNIX_FD_MESSAGE (meta->message));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  gst_buffer_map (buffer, &info, GST_MAP_READ);
 | 
					 | 
				
			||||||
  pinos_buffer_init_data (&pbuf, info.data, info.size, NULL, 0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  pinos_buffer_iter_init (&it, &pbuf);
 | 
					 | 
				
			||||||
  while (pinos_buffer_iter_next (&it)) {
 | 
					 | 
				
			||||||
    switch (pinos_buffer_iter_get_type (&it)) {
 | 
					 | 
				
			||||||
      case PINOS_PACKET_TYPE_HEADER:
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        PinosPacketHeader hdr;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (!pinos_buffer_iter_parse_header  (&it, &hdr))
 | 
					 | 
				
			||||||
          goto error;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (outbuf == NULL)
 | 
					 | 
				
			||||||
          outbuf = gst_buffer_new ();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        GST_INFO ("pts %" G_GUINT64_FORMAT ", dts_offset %"G_GUINT64_FORMAT, hdr.pts, hdr.dts_offset);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#if 0
 | 
					 | 
				
			||||||
        if (GST_CLOCK_TIME_IS_VALID (hdr.pts)) {
 | 
					 | 
				
			||||||
          GST_BUFFER_PTS (outbuf) = hdr.pts;
 | 
					 | 
				
			||||||
          if (GST_BUFFER_PTS (outbuf) + hdr.dts_offset > 0)
 | 
					 | 
				
			||||||
            GST_BUFFER_DTS (outbuf) = GST_BUFFER_PTS (outbuf) + hdr.dts_offset;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
        GST_BUFFER_OFFSET (outbuf) = hdr.seq;
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      case PINOS_PACKET_TYPE_ADD_MEM:
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        GstMemory *fdmem = NULL;
 | 
					 | 
				
			||||||
        PinosPacketAddMem p;
 | 
					 | 
				
			||||||
        int fd;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (!pinos_buffer_iter_parse_add_mem (&it, &p))
 | 
					 | 
				
			||||||
          goto error;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        fd = g_unix_fd_list_get (fds, 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);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        g_hash_table_insert (depay->mem_ids, GINT_TO_POINTER (p.id), fdmem);
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      case PINOS_PACKET_TYPE_REMOVE_MEM:
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        PinosPacketRemoveMem p;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (!pinos_buffer_iter_parse_remove_mem (&it, &p))
 | 
					 | 
				
			||||||
          goto error;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        g_hash_table_remove (depay->mem_ids, GINT_TO_POINTER (p.id));
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      case PINOS_PACKET_TYPE_PROCESS_MEM:
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        GstMemory *fdmem = NULL;
 | 
					 | 
				
			||||||
        PinosPacketProcessMem p;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (!pinos_buffer_iter_parse_process_mem (&it, &p))
 | 
					 | 
				
			||||||
          goto error;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        fdmem = g_hash_table_lookup (depay->mem_ids, GINT_TO_POINTER (p.id));
 | 
					 | 
				
			||||||
        if (fdmem == NULL)
 | 
					 | 
				
			||||||
          goto error;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (outbuf == NULL)
 | 
					 | 
				
			||||||
          outbuf = gst_buffer_new ();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        fdmem = gst_memory_share (fdmem, p.offset, p.size);
 | 
					 | 
				
			||||||
        gst_buffer_append_memory (outbuf, fdmem);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (fdids == NULL)
 | 
					 | 
				
			||||||
          fdids = g_array_new (FALSE, FALSE, sizeof (guint32));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        GST_LOG ("track fd index %d", p.id);
 | 
					 | 
				
			||||||
        g_array_append_val (fdids, p.id);
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      case PINOS_PACKET_TYPE_FORMAT_CHANGE:
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        PinosPacketFormatChange change;
 | 
					 | 
				
			||||||
        GstCaps *caps;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (!pinos_buffer_iter_parse_format_change (&it, &change))
 | 
					 | 
				
			||||||
          goto error;
 | 
					 | 
				
			||||||
        GST_DEBUG ("got format change %d %s", change.id, change.format);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        caps = gst_caps_from_string (change.format);
 | 
					 | 
				
			||||||
        if (caps) {
 | 
					 | 
				
			||||||
          gst_caps_take (&depay->caps, caps);
 | 
					 | 
				
			||||||
          gst_pad_push_event (depay->srcpad, gst_event_new_caps (depay->caps));
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      default:
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  pinos_buffer_iter_init (&it, &pbuf);
 | 
					 | 
				
			||||||
  pinos_buffer_unref (&pbuf);
 | 
					 | 
				
			||||||
  gst_buffer_unmap (buffer, &info);
 | 
					 | 
				
			||||||
  gst_buffer_unref (buffer);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (outbuf) {
 | 
					 | 
				
			||||||
    if (fdids != NULL) {
 | 
					 | 
				
			||||||
      gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (outbuf),
 | 
					 | 
				
			||||||
          fdids_quark, fdids, NULL);
 | 
					 | 
				
			||||||
      gst_mini_object_weak_ref (GST_MINI_OBJECT_CAST (outbuf),
 | 
					 | 
				
			||||||
          (GstMiniObjectNotify) reuse_fds, g_object_ref (depay));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return gst_pad_push (depay->srcpad, outbuf);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  else
 | 
					 | 
				
			||||||
    return GST_FLOW_OK;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
error:
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    GST_ELEMENT_ERROR (depay, RESOURCE, SETTINGS, (NULL),
 | 
					 | 
				
			||||||
        ("can't get fd: %s", err->message));
 | 
					 | 
				
			||||||
    g_clear_error (&err);
 | 
					 | 
				
			||||||
    gst_buffer_unref (outbuf);
 | 
					 | 
				
			||||||
    return GST_FLOW_ERROR;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
gst_pinos_depay_set_property (GObject * object, guint prop_id,
 | 
					 | 
				
			||||||
    const GValue * value, GParamSpec * pspec)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GstPinosDepay *depay = GST_PINOS_DEPAY (object);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  switch (prop_id) {
 | 
					 | 
				
			||||||
    case PROP_CAPS:
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      const GstCaps *caps;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      caps = gst_value_get_caps (value);
 | 
					 | 
				
			||||||
      gst_caps_replace (&depay->caps, (GstCaps *)caps);
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    default:
 | 
					 | 
				
			||||||
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
gst_pinos_depay_get_property (GObject * object, guint prop_id,
 | 
					 | 
				
			||||||
    GValue * value, GParamSpec * pspec)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GstPinosDepay *depay = GST_PINOS_DEPAY (object);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  switch (prop_id) {
 | 
					 | 
				
			||||||
    case PROP_CAPS:
 | 
					 | 
				
			||||||
      gst_value_set_caps (value, depay->caps);
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    default:
 | 
					 | 
				
			||||||
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
gst_pinos_depay_finalize (GObject * object)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GstPinosDepay *depay = GST_PINOS_DEPAY (object);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  GST_DEBUG_OBJECT (depay, "finalize");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  gst_caps_replace (&depay->caps, NULL);
 | 
					 | 
				
			||||||
  g_object_unref (depay->fd_allocator);
 | 
					 | 
				
			||||||
  g_hash_table_unref (depay->mem_ids);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  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);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  gobject_class->finalize = gst_pinos_depay_finalize;
 | 
					 | 
				
			||||||
  gobject_class->set_property = gst_pinos_depay_set_property;
 | 
					 | 
				
			||||||
  gobject_class->get_property = gst_pinos_depay_get_property;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  g_object_class_install_property (gobject_class, PROP_CAPS,
 | 
					 | 
				
			||||||
      g_param_spec_boxed ("caps", "Caps",
 | 
					 | 
				
			||||||
          "The caps of the source pad", GST_TYPE_CAPS,
 | 
					 | 
				
			||||||
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /* 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>");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  GST_DEBUG_CATEGORY_INIT (gst_pinos_depay_debug_category, "pinosdepay", 0,
 | 
					 | 
				
			||||||
      "debug category for pinosdepay element");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  fdids_quark = g_quark_from_static_string ("GstPinosDepayFDIds");
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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_pad_set_event_function (depay->sinkpad, gst_pinos_depay_sink_event);
 | 
					 | 
				
			||||||
  gst_element_add_pad (GST_ELEMENT (depay), depay->sinkpad);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  depay->fd_allocator = gst_fd_allocator_new ();
 | 
					 | 
				
			||||||
  depay->mem_ids = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) gst_memory_unref);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,58 +0,0 @@
 | 
				
			||||||
/* 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
 | 
					 | 
				
			||||||
 * 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_DEPAY_H_
 | 
					 | 
				
			||||||
#define _GST_PINOS_DEPAY_H_
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <gst/gst.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
G_BEGIN_DECLS
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GstElement parent;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  GstCaps *caps;
 | 
					 | 
				
			||||||
  gboolean pinos_input;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  GstPad *srcpad, *sinkpad;
 | 
					 | 
				
			||||||
  GstAllocator *fd_allocator;
 | 
					 | 
				
			||||||
  GHashTable *mem_ids;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct _GstPinosDepayClass
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GstElementClass parent_class;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
GType gst_pinos_depay_get_type (void);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
G_END_DECLS
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,615 +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-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 <gst/video/video.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <gio/gunixfdmessage.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <fcntl.h>
 | 
					 | 
				
			||||||
#include <string.h>
 | 
					 | 
				
			||||||
#include <unistd.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
GST_DEBUG_CATEGORY_STATIC (gst_pinos_pay_debug_category);
 | 
					 | 
				
			||||||
#define GST_CAT_DEFAULT gst_pinos_pay_debug_category
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static GQuark fdids_quark;
 | 
					 | 
				
			||||||
static GQuark orig_buffer_quark;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* 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
 | 
					 | 
				
			||||||
do_allocation (GstPinosPay *pay, GstCaps *caps)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GstQuery *query;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  GST_DEBUG_OBJECT (pay, "doing allocation query");
 | 
					 | 
				
			||||||
  query = gst_query_new_allocation (caps, TRUE);
 | 
					 | 
				
			||||||
  if (!gst_pad_peer_query (pay->srcpad, query)) {
 | 
					 | 
				
			||||||
    /* not a problem, just debug a little */
 | 
					 | 
				
			||||||
    GST_DEBUG_OBJECT (pay, "peer ALLOCATION query failed");
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  if (!gst_query_find_allocation_meta (query,
 | 
					 | 
				
			||||||
      GST_NET_CONTROL_MESSAGE_META_API_TYPE, NULL))
 | 
					 | 
				
			||||||
    goto no_meta;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  gst_query_unref (query);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return TRUE;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /* ERRORS */
 | 
					 | 
				
			||||||
no_meta:
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    GST_ELEMENT_ERROR (pay, STREAM, FORMAT,
 | 
					 | 
				
			||||||
        ("Incompatible downstream element"),
 | 
					 | 
				
			||||||
        ("The downstream element does not handle control-message metadata API"));
 | 
					 | 
				
			||||||
    gst_query_unref (query);
 | 
					 | 
				
			||||||
    return FALSE;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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;
 | 
					 | 
				
			||||||
      GstStructure *str;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      gst_event_parse_caps (event, &caps);
 | 
					 | 
				
			||||||
      str = gst_caps_get_structure (caps, 0);
 | 
					 | 
				
			||||||
      pay->pinos_input = gst_structure_has_name (str, "application/x-pinos");
 | 
					 | 
				
			||||||
      gst_event_unref (event);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      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);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      if (res)
 | 
					 | 
				
			||||||
        /* now negotiate the allocation */
 | 
					 | 
				
			||||||
        res = do_allocation (pay, caps);
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    default:
 | 
					 | 
				
			||||||
      res = gst_pad_event_default (pad, parent, event);
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  return res;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
client_buffer_sent (GstPinosPay *pay, GstBuffer *buffer,
 | 
					 | 
				
			||||||
    GObject *obj)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GArray *fdids;
 | 
					 | 
				
			||||||
  guint i;
 | 
					 | 
				
			||||||
  const gchar *client_path;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  fdids = gst_mini_object_get_qdata (GST_MINI_OBJECT_CAST (buffer), fdids_quark);
 | 
					 | 
				
			||||||
  if (fdids == NULL)
 | 
					 | 
				
			||||||
    return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /* get the client path of this socket */
 | 
					 | 
				
			||||||
  client_path = g_object_get_data (obj, "pinos-client-path");
 | 
					 | 
				
			||||||
  if (client_path == NULL)
 | 
					 | 
				
			||||||
    return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  for (i = 0; i < fdids->len; i++) {
 | 
					 | 
				
			||||||
    gint id = g_array_index (fdids, guint32, i);
 | 
					 | 
				
			||||||
    /* now store the id/client-path/buffer in the fdmanager */
 | 
					 | 
				
			||||||
    GST_LOG ("fd index %d, client %s increment refcount of buffer %p", id, client_path, buffer);
 | 
					 | 
				
			||||||
    pinos_fd_manager_add (pay->fdmanager,
 | 
					 | 
				
			||||||
                          client_path, id,
 | 
					 | 
				
			||||||
                          gst_buffer_ref (buffer),
 | 
					 | 
				
			||||||
                          (GDestroyNotify) gst_buffer_unref);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
client_buffer_received (GstPinosPay *pay, GstBuffer *buffer,
 | 
					 | 
				
			||||||
    GObject *obj)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  PinosBuffer pbuf;
 | 
					 | 
				
			||||||
  PinosBufferIter it;
 | 
					 | 
				
			||||||
  PinosBufferBuilder b;
 | 
					 | 
				
			||||||
  GstMapInfo info;
 | 
					 | 
				
			||||||
  const gchar *client_path;
 | 
					 | 
				
			||||||
  gboolean have_out = FALSE;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  client_path = g_object_get_data (obj, "pinos-client-path");
 | 
					 | 
				
			||||||
  if (client_path == NULL)
 | 
					 | 
				
			||||||
    return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (pay->pinos_input) {
 | 
					 | 
				
			||||||
    pinos_buffer_builder_init (&b);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  gst_buffer_map (buffer, &info, GST_MAP_READ);
 | 
					 | 
				
			||||||
  pinos_buffer_init_data (&pbuf, info.data, info.size, NULL, 0);
 | 
					 | 
				
			||||||
  pinos_buffer_iter_init (&it, &pbuf);
 | 
					 | 
				
			||||||
  while (pinos_buffer_iter_next (&it)) {
 | 
					 | 
				
			||||||
    switch (pinos_buffer_iter_get_type (&it)) {
 | 
					 | 
				
			||||||
      case PINOS_PACKET_TYPE_REUSE_MEM:
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        PinosPacketReuseMem p;
 | 
					 | 
				
			||||||
        gint id;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (!pinos_buffer_iter_parse_reuse_mem (&it, &p))
 | 
					 | 
				
			||||||
          continue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        id = p.id;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        GST_LOG ("fd index %d for client %s is reused", id, client_path);
 | 
					 | 
				
			||||||
        pinos_fd_manager_remove (pay->fdmanager, client_path, id);
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      case PINOS_PACKET_TYPE_REFRESH_REQUEST:
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        PinosPacketRefreshRequest p;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (!pinos_buffer_iter_parse_refresh_request (&it, &p))
 | 
					 | 
				
			||||||
          continue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        GST_LOG ("refresh request");
 | 
					 | 
				
			||||||
        if (!pay->pinos_input) {
 | 
					 | 
				
			||||||
          gst_pad_push_event (pay->sinkpad,
 | 
					 | 
				
			||||||
              gst_video_event_new_upstream_force_key_unit (p.pts,
 | 
					 | 
				
			||||||
              p.request_type == 1, 0));
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
          pinos_buffer_builder_add_refresh_request (&b, &p);
 | 
					 | 
				
			||||||
          have_out = TRUE;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      default:
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  pinos_buffer_iter_end (&it);
 | 
					 | 
				
			||||||
  pinos_buffer_unref (&pbuf);
 | 
					 | 
				
			||||||
  gst_buffer_unmap (buffer, &info);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (pay->pinos_input) {
 | 
					 | 
				
			||||||
    GstBuffer *outbuf;
 | 
					 | 
				
			||||||
    GstEvent *ev;
 | 
					 | 
				
			||||||
    gsize size;
 | 
					 | 
				
			||||||
    gpointer data;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (have_out) {
 | 
					 | 
				
			||||||
      pinos_buffer_builder_end (&b, &pbuf);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      data = pinos_buffer_steal_data (&pbuf, &size);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      outbuf = gst_buffer_new_wrapped (data, size);
 | 
					 | 
				
			||||||
      ev = gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
 | 
					 | 
				
			||||||
              gst_structure_new ("GstNetworkMessage",
 | 
					 | 
				
			||||||
                  "object", G_TYPE_OBJECT, pay,
 | 
					 | 
				
			||||||
                  "buffer", GST_TYPE_BUFFER, outbuf, NULL));
 | 
					 | 
				
			||||||
      gst_buffer_unref (outbuf);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      gst_pad_push_event (pay->sinkpad, ev);
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      pinos_buffer_builder_clear (&b);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static gboolean
 | 
					 | 
				
			||||||
gst_pinos_pay_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GstPinosPay *pay = GST_PINOS_PAY (parent);
 | 
					 | 
				
			||||||
  gboolean res = FALSE;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  switch (GST_EVENT_TYPE (event)) {
 | 
					 | 
				
			||||||
    case GST_EVENT_CUSTOM_UPSTREAM:
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      if (gst_event_has_name (event, "GstNetworkMessageDispatched")) {
 | 
					 | 
				
			||||||
        const GstStructure *str = gst_event_get_structure (event);
 | 
					 | 
				
			||||||
        GstBuffer *buf;
 | 
					 | 
				
			||||||
        GObject *obj;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        gst_structure_get (str, "object", G_TYPE_OBJECT, &obj,
 | 
					 | 
				
			||||||
            "buffer", GST_TYPE_BUFFER, &buf, NULL);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        client_buffer_sent (pay, buf, obj);
 | 
					 | 
				
			||||||
        gst_buffer_unref (buf);
 | 
					 | 
				
			||||||
        g_object_unref (obj);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      else if (gst_event_has_name (event, "GstNetworkMessage")) {
 | 
					 | 
				
			||||||
        const GstStructure *str = gst_event_get_structure (event);
 | 
					 | 
				
			||||||
        GstBuffer *buf;
 | 
					 | 
				
			||||||
        GObject *obj;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        gst_structure_get (str, "object", G_TYPE_OBJECT, &obj,
 | 
					 | 
				
			||||||
            "buffer", GST_TYPE_BUFFER, &buf, NULL);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        client_buffer_received (pay, buf, obj);
 | 
					 | 
				
			||||||
        gst_buffer_unref (buf);
 | 
					 | 
				
			||||||
        g_object_unref (obj);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      res = TRUE;
 | 
					 | 
				
			||||||
      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, gboolean *tmpfile)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  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);
 | 
					 | 
				
			||||||
    *tmpfile = gst_is_tmpfile_memory (mem);
 | 
					 | 
				
			||||||
  } 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);
 | 
					 | 
				
			||||||
    *tmpfile = TRUE;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  return mem;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
release_fds (GstPinosPay *pay, GstBuffer *buffer)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GArray *fdids;
 | 
					 | 
				
			||||||
  guint i;
 | 
					 | 
				
			||||||
  PinosBufferBuilder b;
 | 
					 | 
				
			||||||
  PinosPacketReuseMem r;
 | 
					 | 
				
			||||||
  PinosBuffer pbuf;
 | 
					 | 
				
			||||||
  gsize size;
 | 
					 | 
				
			||||||
  gpointer data;
 | 
					 | 
				
			||||||
  GstBuffer *outbuf;
 | 
					 | 
				
			||||||
  GstEvent *ev;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  fdids = gst_mini_object_steal_qdata (GST_MINI_OBJECT_CAST (buffer),
 | 
					 | 
				
			||||||
      fdids_quark);
 | 
					 | 
				
			||||||
  if (fdids == NULL)
 | 
					 | 
				
			||||||
    return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  pinos_buffer_builder_init (&b);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  for (i = 0; i < fdids->len; i++) {
 | 
					 | 
				
			||||||
    r.id = g_array_index (fdids, guint32, i);
 | 
					 | 
				
			||||||
    GST_LOG ("release fd index %d", r.id);
 | 
					 | 
				
			||||||
    pinos_buffer_builder_add_reuse_mem (&b, &r);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  pinos_buffer_builder_end (&b, &pbuf);
 | 
					 | 
				
			||||||
  g_array_unref (fdids);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  data = pinos_buffer_steal_data (&pbuf, &size);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  outbuf = gst_buffer_new_wrapped (data, size);
 | 
					 | 
				
			||||||
  ev = gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
 | 
					 | 
				
			||||||
          gst_structure_new ("GstNetworkMessage",
 | 
					 | 
				
			||||||
              "object", G_TYPE_OBJECT, pay,
 | 
					 | 
				
			||||||
              "buffer", GST_TYPE_BUFFER, outbuf, NULL));
 | 
					 | 
				
			||||||
  gst_buffer_unref (outbuf);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  gst_pad_push_event (pay->sinkpad, ev);
 | 
					 | 
				
			||||||
  g_object_unref (pay);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static GstFlowReturn
 | 
					 | 
				
			||||||
gst_pinos_pay_chain_pinos (GstPinosPay *pay, GstBuffer * buffer)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GstMapInfo info;
 | 
					 | 
				
			||||||
  PinosBuffer pbuf;
 | 
					 | 
				
			||||||
  PinosBufferIter it;
 | 
					 | 
				
			||||||
  GArray *fdids = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  gst_buffer_map (buffer, &info, GST_MAP_READ);
 | 
					 | 
				
			||||||
  pinos_buffer_init_data (&pbuf, info.data, info.size, NULL, 0);
 | 
					 | 
				
			||||||
  pinos_buffer_iter_init (&it, &pbuf);
 | 
					 | 
				
			||||||
  while (pinos_buffer_iter_next (&it)) {
 | 
					 | 
				
			||||||
    switch (pinos_buffer_iter_get_type (&it)) {
 | 
					 | 
				
			||||||
      case PINOS_PACKET_TYPE_PROCESS_MEM:
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        PinosPacketProcessMem p;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (!pinos_buffer_iter_parse_process_mem (&it, &p))
 | 
					 | 
				
			||||||
          continue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (fdids == NULL)
 | 
					 | 
				
			||||||
          fdids = g_array_new (FALSE, FALSE, sizeof (guint32));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        GST_LOG ("track fd index %d", p.id);
 | 
					 | 
				
			||||||
        g_array_append_val (fdids, p.id);
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      case PINOS_PACKET_TYPE_FORMAT_CHANGE:
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        PinosPacketFormatChange p;
 | 
					 | 
				
			||||||
        GstCaps * caps;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (!pinos_buffer_iter_parse_format_change (&it, &p))
 | 
					 | 
				
			||||||
          continue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        caps = gst_caps_from_string (p.format);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        gst_element_post_message (GST_ELEMENT (pay),
 | 
					 | 
				
			||||||
            gst_message_new_element (GST_OBJECT (pay),
 | 
					 | 
				
			||||||
                gst_structure_new ("PinosPayloaderFormatChange",
 | 
					 | 
				
			||||||
                    "format", GST_TYPE_CAPS, caps, NULL)));
 | 
					 | 
				
			||||||
        gst_caps_unref (caps);
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      default:
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  pinos_buffer_iter_end (&it);
 | 
					 | 
				
			||||||
  pinos_buffer_unref (&pbuf);
 | 
					 | 
				
			||||||
  gst_buffer_unmap (buffer, &info);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (fdids != NULL) {
 | 
					 | 
				
			||||||
    gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (buffer),
 | 
					 | 
				
			||||||
        fdids_quark, fdids, NULL);
 | 
					 | 
				
			||||||
    gst_mini_object_weak_ref (GST_MINI_OBJECT_CAST (buffer),
 | 
					 | 
				
			||||||
        (GstMiniObjectNotify) release_fds, g_object_ref (pay));
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return gst_pad_push (pay->srcpad, buffer);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static GstFlowReturn
 | 
					 | 
				
			||||||
gst_pinos_pay_chain_other (GstPinosPay *pay, GstBuffer * buffer)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GstMemory *fdmem = NULL;
 | 
					 | 
				
			||||||
  GError *err = NULL;
 | 
					 | 
				
			||||||
  GstBuffer *outbuf;
 | 
					 | 
				
			||||||
  PinosBuffer pbuf;
 | 
					 | 
				
			||||||
  PinosBufferBuilder builder;
 | 
					 | 
				
			||||||
  PinosPacketHeader hdr;
 | 
					 | 
				
			||||||
  PinosPacketAddMem am;
 | 
					 | 
				
			||||||
  PinosPacketProcessMem p;
 | 
					 | 
				
			||||||
  PinosPacketRemoveMem rm;
 | 
					 | 
				
			||||||
  gsize size;
 | 
					 | 
				
			||||||
  gpointer data;
 | 
					 | 
				
			||||||
  GSocketControlMessage *msg;
 | 
					 | 
				
			||||||
  gboolean tmpfile = TRUE;
 | 
					 | 
				
			||||||
  gint *fds, n_fds, i;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  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_add_header (&builder, &hdr);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  msg = g_unix_fd_message_new ();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  fdmem = gst_pinos_pay_get_fd_memory (pay, buffer, &tmpfile);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  am.id = pinos_fd_manager_get_id (pay->fdmanager);
 | 
					 | 
				
			||||||
  am.fd_index = pinos_buffer_builder_add_fd (&builder, gst_fd_memory_get_fd (fdmem));
 | 
					 | 
				
			||||||
  am.offset = 0;
 | 
					 | 
				
			||||||
  am.size = fdmem->size;
 | 
					 | 
				
			||||||
  p.id = am.id;
 | 
					 | 
				
			||||||
  p.offset = fdmem->offset;
 | 
					 | 
				
			||||||
  p.size = fdmem->size;
 | 
					 | 
				
			||||||
  rm.id = am.id;
 | 
					 | 
				
			||||||
  pinos_buffer_builder_add_add_mem (&builder, &am);
 | 
					 | 
				
			||||||
  pinos_buffer_builder_add_process_mem (&builder, &p);
 | 
					 | 
				
			||||||
  pinos_buffer_builder_add_remove_mem (&builder, &rm);
 | 
					 | 
				
			||||||
  pinos_buffer_builder_end (&builder, &pbuf);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  data = pinos_buffer_steal_data (&pbuf, &size);
 | 
					 | 
				
			||||||
  fds = pinos_buffer_steal_fds (&pbuf, &n_fds);
 | 
					 | 
				
			||||||
  pinos_buffer_unref (&pbuf);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  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);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  msg = g_unix_fd_message_new ();
 | 
					 | 
				
			||||||
  for (i = 0; i < n_fds; i++) {
 | 
					 | 
				
			||||||
    if (!g_unix_fd_message_append_fd (G_UNIX_FD_MESSAGE (msg), fds[i], &err))
 | 
					 | 
				
			||||||
      goto add_fd_failed;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  gst_buffer_add_net_control_message_meta (outbuf, msg);
 | 
					 | 
				
			||||||
  g_object_unref (msg);
 | 
					 | 
				
			||||||
  g_free (fds);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  gst_memory_unref(fdmem);
 | 
					 | 
				
			||||||
  fdmem = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (!tmpfile) {
 | 
					 | 
				
			||||||
    GArray *fdids;
 | 
					 | 
				
			||||||
    /* we are using the original buffer fd in the control message, we need
 | 
					 | 
				
			||||||
     * to make sure it is not reused before everyone is finished with it.
 | 
					 | 
				
			||||||
     * We tag the output buffer with the array of fds in it and the original
 | 
					 | 
				
			||||||
     * buffer (to keep it alive). All clients that receive the fd will
 | 
					 | 
				
			||||||
     * increment outbuf refcount, all clients that do release-fd on the fd
 | 
					 | 
				
			||||||
     * will decrease the refcount again. */
 | 
					 | 
				
			||||||
    fdids = g_array_new (FALSE, FALSE, sizeof (guint32));
 | 
					 | 
				
			||||||
    g_array_append_val (fdids, p.id);
 | 
					 | 
				
			||||||
    gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (outbuf),
 | 
					 | 
				
			||||||
        fdids_quark, fdids, (GDestroyNotify) g_array_unref);
 | 
					 | 
				
			||||||
    gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (outbuf),
 | 
					 | 
				
			||||||
        orig_buffer_quark, buffer, (GDestroyNotify) gst_buffer_unref);
 | 
					 | 
				
			||||||
  } else {
 | 
					 | 
				
			||||||
    gst_buffer_unref (buffer);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return gst_pad_push (pay->srcpad, outbuf);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /* ERRORS */
 | 
					 | 
				
			||||||
add_fd_failed:
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    GST_WARNING_OBJECT (pay, "Adding fd failed: %s", err->message);
 | 
					 | 
				
			||||||
    gst_object_unref(msg);
 | 
					 | 
				
			||||||
    g_clear_error (&err);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return GST_FLOW_ERROR;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static GstFlowReturn
 | 
					 | 
				
			||||||
gst_pinos_pay_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GstPinosPay *pay = GST_PINOS_PAY (parent);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (pay->pinos_input)
 | 
					 | 
				
			||||||
    return gst_pinos_pay_chain_pinos (pay, buffer);
 | 
					 | 
				
			||||||
  else
 | 
					 | 
				
			||||||
    return gst_pinos_pay_chain_other (pay, buffer);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
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_unref (pay->fdmanager);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  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_pad_set_event_function (pay->srcpad, gst_pinos_pay_src_event);
 | 
					 | 
				
			||||||
  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 ();
 | 
					 | 
				
			||||||
  pay->fdmanager = pinos_fd_manager_get (PINOS_FD_MANAGER_DEFAULT);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  fdids_quark = g_quark_from_static_string ("GstPinosPayFDIds");
 | 
					 | 
				
			||||||
  orig_buffer_quark = g_quark_from_static_string ("GstPinosPayOrigBuffer");
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,60 +0,0 @@
 | 
				
			||||||
/* 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>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <client/pinos.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 pinos_input;
 | 
					 | 
				
			||||||
  GstPad *srcpad, *sinkpad;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  GstAllocator *allocator;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  PinosFdManager *fdmanager;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct _GstPinosPayClass
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GstElementClass parent_class;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
GType gst_pinos_pay_get_type (void);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
G_END_DECLS
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif /* _GST_PINOS_PAY_H_ */
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,402 +0,0 @@
 | 
				
			||||||
/* GStreamer
 | 
					 | 
				
			||||||
 * Copyright (C) <2016> 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.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * SECTION:element-pinosportsink
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef HAVE_CONFIG_H
 | 
					 | 
				
			||||||
#include "config.h"
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <string.h>
 | 
					 | 
				
			||||||
#include <stdlib.h>
 | 
					 | 
				
			||||||
#include <fcntl.h>
 | 
					 | 
				
			||||||
#include <sys/socket.h>
 | 
					 | 
				
			||||||
#include <unistd.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <gio/gunixfdmessage.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <gst/allocators/gstfdmemory.h>
 | 
					 | 
				
			||||||
#include <gst/net/gstnetcontrolmessagemeta.h>
 | 
					 | 
				
			||||||
#include <gst/video/video.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "gstpinosportsink.h"
 | 
					 | 
				
			||||||
#include "gsttmpfileallocator.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
GST_DEBUG_CATEGORY_STATIC (pinos_port_sink_debug);
 | 
					 | 
				
			||||||
#define GST_CAT_DEFAULT pinos_port_sink_debug
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static GstStaticPadTemplate gst_pinos_port_sink_template =
 | 
					 | 
				
			||||||
GST_STATIC_PAD_TEMPLATE ("sink",
 | 
					 | 
				
			||||||
    GST_PAD_SINK,
 | 
					 | 
				
			||||||
    GST_PAD_ALWAYS,
 | 
					 | 
				
			||||||
    GST_STATIC_CAPS_ANY
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
enum
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  PROP_0,
 | 
					 | 
				
			||||||
  PROP_PORT,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define gst_pinos_port_sink_parent_class parent_class
 | 
					 | 
				
			||||||
G_DEFINE_TYPE (GstPinosPortSink, gst_pinos_port_sink, GST_TYPE_BASE_SINK);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static gboolean
 | 
					 | 
				
			||||||
gst_pinos_port_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GstPinosPortSink *this = GST_PINOS_PORT_SINK (bsink);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  gst_query_add_allocation_param (query, this->allocator, NULL);
 | 
					 | 
				
			||||||
  gst_query_add_allocation_meta (query, GST_NET_CONTROL_MESSAGE_META_API_TYPE,
 | 
					 | 
				
			||||||
            NULL);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return TRUE;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static gboolean
 | 
					 | 
				
			||||||
on_received_buffer (PinosPort *port, PinosBuffer *pbuf, GError **error, gpointer user_data)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GstPinosPortSink *this = user_data;
 | 
					 | 
				
			||||||
  GstEvent *ev;
 | 
					 | 
				
			||||||
  PinosBufferIter it;
 | 
					 | 
				
			||||||
  PinosBufferBuilder b;
 | 
					 | 
				
			||||||
  gboolean have_out = FALSE;
 | 
					 | 
				
			||||||
  guint8 buffer[1024];
 | 
					 | 
				
			||||||
  gint fds[8];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (this->pinos_input) {
 | 
					 | 
				
			||||||
    pinos_buffer_builder_init_into (&b, buffer, 1024, fds, 8);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  pinos_buffer_iter_init (&it, pbuf);
 | 
					 | 
				
			||||||
  while (pinos_buffer_iter_next (&it)) {
 | 
					 | 
				
			||||||
    switch (pinos_buffer_iter_get_type (&it)) {
 | 
					 | 
				
			||||||
      case PINOS_PACKET_TYPE_REFRESH_REQUEST:
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        PinosPacketRefreshRequest p;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (!pinos_buffer_iter_parse_refresh_request (&it, &p))
 | 
					 | 
				
			||||||
          continue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        GST_LOG ("refresh request");
 | 
					 | 
				
			||||||
        if (!this->pinos_input) {
 | 
					 | 
				
			||||||
          gst_pad_push_event (GST_BASE_SINK_PAD (this),
 | 
					 | 
				
			||||||
              gst_video_event_new_upstream_force_key_unit (p.pts,
 | 
					 | 
				
			||||||
              p.request_type == 1, 0));
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
          pinos_buffer_builder_add_refresh_request (&b, &p);
 | 
					 | 
				
			||||||
          have_out = TRUE;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      default:
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  pinos_buffer_iter_end (&it);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (this->pinos_input) {
 | 
					 | 
				
			||||||
    GstBuffer *outbuf;
 | 
					 | 
				
			||||||
    gsize size;
 | 
					 | 
				
			||||||
    gpointer data;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (have_out) {
 | 
					 | 
				
			||||||
      pinos_buffer_builder_end (&b, pbuf);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      data = pinos_buffer_steal_data (pbuf, &size);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      outbuf = gst_buffer_new_wrapped (data, size);
 | 
					 | 
				
			||||||
      ev = gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
 | 
					 | 
				
			||||||
              gst_structure_new ("GstNetworkMessage",
 | 
					 | 
				
			||||||
                  "object", G_TYPE_OBJECT, this,
 | 
					 | 
				
			||||||
                  "buffer", GST_TYPE_BUFFER, outbuf, NULL));
 | 
					 | 
				
			||||||
      gst_buffer_unref (outbuf);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      gst_pad_push_event (GST_BASE_SINK_PAD (this), ev);
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      pinos_buffer_builder_clear (&b);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  return TRUE;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
set_port (GstPinosPortSink *this, PinosPort *port)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  if (this->port)
 | 
					 | 
				
			||||||
    g_object_unref (this->port);
 | 
					 | 
				
			||||||
  this->port = port;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  pinos_port_set_received_buffer_cb (port, on_received_buffer, this, NULL);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
gst_pinos_port_sink_set_property (GObject * object, guint prop_id,
 | 
					 | 
				
			||||||
    const GValue * value, GParamSpec * pspec)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GstPinosPortSink *this = GST_PINOS_PORT_SINK (object);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  switch (prop_id) {
 | 
					 | 
				
			||||||
    case PROP_PORT:
 | 
					 | 
				
			||||||
      set_port (this, g_value_dup_object (value));
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    default:
 | 
					 | 
				
			||||||
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
gst_pinos_port_sink_get_property (GObject * object, guint prop_id,
 | 
					 | 
				
			||||||
    GValue * value, GParamSpec * pspec)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GstPinosPortSink *this = GST_PINOS_PORT_SINK (object);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  switch (prop_id) {
 | 
					 | 
				
			||||||
    case PROP_PORT:
 | 
					 | 
				
			||||||
      g_value_set_object (value, this->port);
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    default:
 | 
					 | 
				
			||||||
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static GstCaps *
 | 
					 | 
				
			||||||
gst_pinos_port_sink_getcaps (GstBaseSink * bsink, GstCaps * filter)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GstPinosPortSink *this = GST_PINOS_PORT_SINK (bsink);
 | 
					 | 
				
			||||||
  GBytes *filt, *formats;
 | 
					 | 
				
			||||||
  gchar *cstr;
 | 
					 | 
				
			||||||
  GstCaps *result;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (filter) {
 | 
					 | 
				
			||||||
    cstr = gst_caps_to_string (filter);
 | 
					 | 
				
			||||||
    filt = g_bytes_new_take (cstr, strlen (cstr) + 1);
 | 
					 | 
				
			||||||
  } else {
 | 
					 | 
				
			||||||
    filt = NULL;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  formats = pinos_port_filter_formats (this->port, filt, NULL);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (filt)
 | 
					 | 
				
			||||||
    g_bytes_unref (filt);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (formats) {
 | 
					 | 
				
			||||||
    result = gst_caps_from_string (g_bytes_get_data (formats, NULL));
 | 
					 | 
				
			||||||
    g_bytes_unref (formats);
 | 
					 | 
				
			||||||
  } else {
 | 
					 | 
				
			||||||
    result = gst_caps_new_empty ();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static gboolean
 | 
					 | 
				
			||||||
gst_pinos_port_sink_setcaps (GstBaseSink * bsink, GstCaps * caps)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GstPinosPortSink *this = GST_PINOS_PORT_SINK (bsink);
 | 
					 | 
				
			||||||
  GstStructure *str;
 | 
					 | 
				
			||||||
  gchar *cstr;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  str = gst_caps_get_structure (caps, 0);
 | 
					 | 
				
			||||||
  this->pinos_input = gst_structure_has_name (str, "application/x-pinos");
 | 
					 | 
				
			||||||
  if (!this->pinos_input) {
 | 
					 | 
				
			||||||
    GError *error = NULL;
 | 
					 | 
				
			||||||
    PinosBufferBuilder builder;
 | 
					 | 
				
			||||||
    PinosBuffer pbuf;
 | 
					 | 
				
			||||||
    PinosPacketFormatChange fc;
 | 
					 | 
				
			||||||
    guint8 buffer[1024];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pinos_buffer_builder_init_into (&builder, buffer, 1024, NULL, 0);
 | 
					 | 
				
			||||||
    fc.id = 0;
 | 
					 | 
				
			||||||
    fc.format = cstr = gst_caps_to_string (caps);
 | 
					 | 
				
			||||||
    pinos_buffer_builder_add_format_change (&builder, &fc);
 | 
					 | 
				
			||||||
    pinos_buffer_builder_end (&builder, &pbuf);
 | 
					 | 
				
			||||||
    g_free (cstr);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (!pinos_port_send_buffer (this->port, &pbuf, &error)) {
 | 
					 | 
				
			||||||
      GST_WARNING ("format update failed: %s", error->message);
 | 
					 | 
				
			||||||
      g_clear_error (&error);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    pinos_buffer_unref (&pbuf);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return GST_BASE_SINK_CLASS (parent_class)->set_caps (bsink, caps);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static GstFlowReturn
 | 
					 | 
				
			||||||
gst_pinos_port_sink_render_pinos (GstPinosPortSink * this, GstBuffer * buffer)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GstMapInfo info;
 | 
					 | 
				
			||||||
  PinosBuffer pbuf;
 | 
					 | 
				
			||||||
  GError *error = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  gst_buffer_map (buffer, &info, GST_MAP_READ);
 | 
					 | 
				
			||||||
  pinos_buffer_init_data (&pbuf, info.data, info.size, NULL, 0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (!pinos_port_send_buffer (this->port, &pbuf, &error)) {
 | 
					 | 
				
			||||||
    GST_WARNING ("send failed: %s", error->message);
 | 
					 | 
				
			||||||
    g_clear_error (&error);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  gst_buffer_unmap (buffer, &info);
 | 
					 | 
				
			||||||
  pinos_buffer_unref (&pbuf);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return GST_FLOW_OK;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static GstMemory *
 | 
					 | 
				
			||||||
gst_pinos_port_sink_get_fd_memory (GstPinosPortSink * this, GstBuffer * buffer, gboolean *tmpfile)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  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);
 | 
					 | 
				
			||||||
    *tmpfile = gst_is_tmpfile_memory (mem);
 | 
					 | 
				
			||||||
  } else {
 | 
					 | 
				
			||||||
    GstMapInfo info;
 | 
					 | 
				
			||||||
    GstAllocationParams params = {0, 0, 0, 0, { NULL, }};
 | 
					 | 
				
			||||||
    gsize size = gst_buffer_get_size (buffer);
 | 
					 | 
				
			||||||
    GST_INFO_OBJECT (this, "Buffer cannot be sent without copying");
 | 
					 | 
				
			||||||
    mem = gst_allocator_alloc (this->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);
 | 
					 | 
				
			||||||
    *tmpfile = TRUE;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  return mem;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static GstFlowReturn
 | 
					 | 
				
			||||||
gst_pinos_port_sink_render_other (GstPinosPortSink * this, GstBuffer * buffer)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GstMemory *fdmem = NULL;
 | 
					 | 
				
			||||||
  GError *error = NULL;
 | 
					 | 
				
			||||||
  PinosBuffer pbuf;
 | 
					 | 
				
			||||||
  PinosBufferBuilder builder;
 | 
					 | 
				
			||||||
  PinosPacketHeader hdr;
 | 
					 | 
				
			||||||
  PinosPacketAddMem am;
 | 
					 | 
				
			||||||
  PinosPacketProcessMem p;
 | 
					 | 
				
			||||||
  PinosPacketRemoveMem rm;
 | 
					 | 
				
			||||||
  gboolean tmpfile = TRUE;
 | 
					 | 
				
			||||||
  guint8 send_buffer[1024];
 | 
					 | 
				
			||||||
  gint send_fds[8];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  hdr.flags = 0;
 | 
					 | 
				
			||||||
  hdr.seq = GST_BUFFER_OFFSET (buffer);
 | 
					 | 
				
			||||||
  hdr.pts = GST_BUFFER_PTS (buffer) + GST_ELEMENT_CAST (this)->base_time;
 | 
					 | 
				
			||||||
  hdr.dts_offset = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  pinos_buffer_builder_init_into (&builder, send_buffer, 1024, send_fds, 8);
 | 
					 | 
				
			||||||
  pinos_buffer_builder_add_header (&builder, &hdr);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  fdmem = gst_pinos_port_sink_get_fd_memory (this, buffer, &tmpfile);
 | 
					 | 
				
			||||||
  am.id = pinos_fd_manager_get_id (this->fdmanager);
 | 
					 | 
				
			||||||
  am.fd_index = pinos_buffer_builder_add_fd (&builder, gst_fd_memory_get_fd (fdmem));
 | 
					 | 
				
			||||||
  am.offset = 0;
 | 
					 | 
				
			||||||
  am.size = fdmem->size + fdmem->offset;
 | 
					 | 
				
			||||||
  p.id = am.id;
 | 
					 | 
				
			||||||
  p.offset = fdmem->offset;
 | 
					 | 
				
			||||||
  p.size = fdmem->size;
 | 
					 | 
				
			||||||
  rm.id = am.id;
 | 
					 | 
				
			||||||
  pinos_buffer_builder_add_add_mem (&builder, &am);
 | 
					 | 
				
			||||||
  pinos_buffer_builder_add_process_mem (&builder, &p);
 | 
					 | 
				
			||||||
  pinos_buffer_builder_add_remove_mem (&builder, &rm);
 | 
					 | 
				
			||||||
  pinos_buffer_builder_end (&builder, &pbuf);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  GST_LOG ("send %d %"G_GUINT64_FORMAT" %"G_GUINT64_FORMAT" %"G_GUINT64_FORMAT,
 | 
					 | 
				
			||||||
      p.id, hdr.pts, GST_BUFFER_PTS (buffer), GST_ELEMENT_CAST (this)->base_time);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (!pinos_port_send_buffer (this->port, &pbuf, &error)) {
 | 
					 | 
				
			||||||
    GST_WARNING ("send failed: %s", error->message);
 | 
					 | 
				
			||||||
    g_clear_error (&error);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  pinos_buffer_steal_fds (&pbuf, NULL);
 | 
					 | 
				
			||||||
  pinos_buffer_unref (&pbuf);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  gst_memory_unref(fdmem);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return GST_FLOW_OK;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static GstFlowReturn
 | 
					 | 
				
			||||||
gst_pinos_port_sink_render (GstBaseSink * bsink, GstBuffer * buffer)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GstPinosPortSink *this = GST_PINOS_PORT_SINK (bsink);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (this->pinos_input)
 | 
					 | 
				
			||||||
    return gst_pinos_port_sink_render_pinos (this, buffer);
 | 
					 | 
				
			||||||
  else
 | 
					 | 
				
			||||||
    return gst_pinos_port_sink_render_other (this, buffer);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
gst_pinos_port_sink_finalize (GObject * object)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  G_OBJECT_CLASS (parent_class)->finalize (object);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
gst_pinos_port_sink_class_init (GstPinosPortSinkClass * klass)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GObjectClass *gobject_class;
 | 
					 | 
				
			||||||
  GstElementClass *gstelement_class;
 | 
					 | 
				
			||||||
  GstBaseSinkClass *gstbasesink_class;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  gobject_class = (GObjectClass *) klass;
 | 
					 | 
				
			||||||
  gstelement_class = (GstElementClass *) klass;
 | 
					 | 
				
			||||||
  gstbasesink_class = (GstBaseSinkClass *) klass;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  gobject_class->finalize = gst_pinos_port_sink_finalize;
 | 
					 | 
				
			||||||
  gobject_class->set_property = gst_pinos_port_sink_set_property;
 | 
					 | 
				
			||||||
  gobject_class->get_property = gst_pinos_port_sink_get_property;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  g_object_class_install_property (gobject_class, PROP_PORT,
 | 
					 | 
				
			||||||
      g_param_spec_object ("port", "Port",
 | 
					 | 
				
			||||||
          "The pinos port object", PINOS_TYPE_PORT,
 | 
					 | 
				
			||||||
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  gst_element_class_set_static_metadata (gstelement_class,
 | 
					 | 
				
			||||||
      "Pinos Port sink", "Sink/Video",
 | 
					 | 
				
			||||||
      "Send data to pinos port", "Wim Taymans <wim.taymans@gmail.com>");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  gst_element_class_add_pad_template (gstelement_class,
 | 
					 | 
				
			||||||
      gst_static_pad_template_get (&gst_pinos_port_sink_template));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  gstbasesink_class->get_caps = gst_pinos_port_sink_getcaps;
 | 
					 | 
				
			||||||
  gstbasesink_class->set_caps = gst_pinos_port_sink_setcaps;
 | 
					 | 
				
			||||||
  gstbasesink_class->propose_allocation = gst_pinos_port_sink_propose_allocation;
 | 
					 | 
				
			||||||
  gstbasesink_class->render = gst_pinos_port_sink_render;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  GST_DEBUG_CATEGORY_INIT (pinos_port_sink_debug, "pinosportsink", 0,
 | 
					 | 
				
			||||||
      "Pinos Socket Sink");
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
gst_pinos_port_sink_init (GstPinosPortSink * this)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  this->allocator = gst_tmpfile_allocator_new ();
 | 
					 | 
				
			||||||
  this->fdmanager = pinos_fd_manager_get (PINOS_FD_MANAGER_DEFAULT);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,66 +0,0 @@
 | 
				
			||||||
/* GStreamer
 | 
					 | 
				
			||||||
 * Copyright (C) <2016> 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_PORT_SINK_H__
 | 
					 | 
				
			||||||
#define __GST_PINOS_PORT_SINK_H__
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <gio/gio.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <client/pinos.h>
 | 
					 | 
				
			||||||
#include <server/port.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <gst/gst.h>
 | 
					 | 
				
			||||||
#include <gst/base/gstbasesink.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
G_BEGIN_DECLS
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define GST_TYPE_PINOS_PORT_SINK            (gst_pinos_port_sink_get_type())
 | 
					 | 
				
			||||||
#define GST_PINOS_PORT_SINK(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PINOS_PORT_SINK,GstPinosPortSink))
 | 
					 | 
				
			||||||
#define GST_PINOS_PORT_SINK_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PINOS_PORT_SINK,GstPinosPortSinkClass))
 | 
					 | 
				
			||||||
#define GST_IS_PINOS_PORT_SINK(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PINOS_PORT_SINK))
 | 
					 | 
				
			||||||
#define GST_IS_PINOS_PORT_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PINOS_PORT_SINK))
 | 
					 | 
				
			||||||
#define GST_PINOS_PORT_SINK_CAST(obj)       ((GstPinosPortSink *) (obj))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct _GstPinosPortSink GstPinosPortSink;
 | 
					 | 
				
			||||||
typedef struct _GstPinosPortSinkClass GstPinosPortSinkClass;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * GstPinosPortSink:
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Opaque data structure.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
struct _GstPinosPortSink {
 | 
					 | 
				
			||||||
  GstBaseSink element;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  gboolean pinos_input;
 | 
					 | 
				
			||||||
  GstAllocator *allocator;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  PinosPort *port;
 | 
					 | 
				
			||||||
  PinosFdManager *fdmanager;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct _GstPinosPortSinkClass {
 | 
					 | 
				
			||||||
  GstBaseSinkClass parent_class;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
GType gst_pinos_port_sink_get_type (void);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
G_END_DECLS
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif /* __GST_PINOS_PORT_SINK_H__ */
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,649 +0,0 @@
 | 
				
			||||||
/* GStreamer
 | 
					 | 
				
			||||||
 * 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
 | 
					 | 
				
			||||||
 * 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.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * SECTION:element-pinosportsrc
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * <refsect2>
 | 
					 | 
				
			||||||
 * <title>Example launch line</title>
 | 
					 | 
				
			||||||
 * |[
 | 
					 | 
				
			||||||
 * gst-launch -v pinosportsrc ! videoconvert ! ximagesink
 | 
					 | 
				
			||||||
 * ]| Shows pinos output in an X window.
 | 
					 | 
				
			||||||
 * </refsect2>
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef HAVE_CONFIG_H
 | 
					 | 
				
			||||||
#include "config.h"
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#include "gstpinosportsrc.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <string.h>
 | 
					 | 
				
			||||||
#include <stdlib.h>
 | 
					 | 
				
			||||||
#include <fcntl.h>
 | 
					 | 
				
			||||||
#include <sys/socket.h>
 | 
					 | 
				
			||||||
#include <unistd.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <gio/gunixfdmessage.h>
 | 
					 | 
				
			||||||
#include <gst/net/gstnetclientclock.h>
 | 
					 | 
				
			||||||
#include <gst/allocators/gstfdmemory.h>
 | 
					 | 
				
			||||||
#include <gst/video/video.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static GQuark process_mem_data_quark;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
GST_DEBUG_CATEGORY_STATIC (pinos_port_src_debug);
 | 
					 | 
				
			||||||
#define GST_CAT_DEFAULT pinos_port_src_debug
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
enum
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  PROP_0,
 | 
					 | 
				
			||||||
  PROP_PORT,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define PINOSS_VIDEO_CAPS GST_VIDEO_CAPS_MAKE (GST_VIDEO_FORMATS_ALL)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static GstStaticPadTemplate gst_pinos_port_src_template =
 | 
					 | 
				
			||||||
GST_STATIC_PAD_TEMPLATE ("src",
 | 
					 | 
				
			||||||
    GST_PAD_SRC,
 | 
					 | 
				
			||||||
    GST_PAD_ALWAYS,
 | 
					 | 
				
			||||||
    GST_STATIC_CAPS_ANY
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define gst_pinos_port_src_parent_class parent_class
 | 
					 | 
				
			||||||
G_DEFINE_TYPE (GstPinosPortSrc, gst_pinos_port_src, GST_TYPE_PUSH_SRC);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static GstStateChangeReturn
 | 
					 | 
				
			||||||
gst_pinos_port_src_change_state (GstElement * element, GstStateChange transition);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static GstCaps *gst_pinos_port_src_getcaps (GstBaseSrc * bsrc, GstCaps * filter);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static GstFlowReturn gst_pinos_port_src_create (GstPushSrc * psrc,
 | 
					 | 
				
			||||||
    GstBuffer ** buffer);
 | 
					 | 
				
			||||||
static gboolean gst_pinos_port_src_start (GstBaseSrc * basesrc);
 | 
					 | 
				
			||||||
static gboolean gst_pinos_port_src_stop (GstBaseSrc * basesrc);
 | 
					 | 
				
			||||||
static gboolean gst_pinos_port_src_event (GstBaseSrc * src, GstEvent * event);
 | 
					 | 
				
			||||||
static gboolean gst_pinos_port_src_query (GstBaseSrc * src, GstQuery * query);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct {
 | 
					 | 
				
			||||||
  GstPinosPortSrc *src;
 | 
					 | 
				
			||||||
  PinosPacketProcessMem p;
 | 
					 | 
				
			||||||
} ProcessMemData;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
process_mem_data_destroy (gpointer user_data)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  ProcessMemData *data = user_data;
 | 
					 | 
				
			||||||
  GstPinosPortSrc *this = data->src;
 | 
					 | 
				
			||||||
  PinosBufferBuilder b;
 | 
					 | 
				
			||||||
  PinosPacketReuseMem r;
 | 
					 | 
				
			||||||
  PinosBuffer pbuf;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  r.id = data->p.id;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  GST_DEBUG_OBJECT (this, "destroy %d", r.id);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  pinos_buffer_builder_init (&b);
 | 
					 | 
				
			||||||
  pinos_buffer_builder_add_reuse_mem (&b, &r);
 | 
					 | 
				
			||||||
  pinos_buffer_builder_end (&b, &pbuf);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  pinos_port_send_buffer (this->port, &pbuf, NULL);
 | 
					 | 
				
			||||||
  pinos_buffer_unref (&pbuf);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  gst_object_unref (this);
 | 
					 | 
				
			||||||
  g_slice_free (ProcessMemData, data);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static gboolean
 | 
					 | 
				
			||||||
on_received_buffer (PinosPort   *port,
 | 
					 | 
				
			||||||
                    PinosBuffer *pbuf,
 | 
					 | 
				
			||||||
                    GError     **error,
 | 
					 | 
				
			||||||
                    gpointer     user_data)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GstPinosPortSrc *this = user_data;
 | 
					 | 
				
			||||||
  PinosBufferIter it;
 | 
					 | 
				
			||||||
  GstBuffer *buf = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  GST_LOG_OBJECT (this, "got new buffer");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  pinos_buffer_iter_init (&it, pbuf);
 | 
					 | 
				
			||||||
  while (pinos_buffer_iter_next (&it)) {
 | 
					 | 
				
			||||||
    switch (pinos_buffer_iter_get_type (&it)) {
 | 
					 | 
				
			||||||
      case PINOS_PACKET_TYPE_HEADER:
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        PinosPacketHeader hdr;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (!pinos_buffer_iter_parse_header  (&it, &hdr))
 | 
					 | 
				
			||||||
          break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (buf == NULL)
 | 
					 | 
				
			||||||
          buf = gst_buffer_new ();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        GST_INFO ("pts %" G_GUINT64_FORMAT ", dts_offset %"G_GUINT64_FORMAT, hdr.pts, hdr.dts_offset);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (GST_CLOCK_TIME_IS_VALID (hdr.pts)) {
 | 
					 | 
				
			||||||
          GST_BUFFER_PTS (buf) = hdr.pts;
 | 
					 | 
				
			||||||
          if (GST_BUFFER_PTS (buf) + hdr.dts_offset > 0)
 | 
					 | 
				
			||||||
            GST_BUFFER_DTS (buf) = GST_BUFFER_PTS (buf) + hdr.dts_offset;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        GST_BUFFER_OFFSET (buf) = hdr.seq;
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      case PINOS_PACKET_TYPE_ADD_MEM:
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        GstMemory *fdmem = NULL;
 | 
					 | 
				
			||||||
        PinosPacketAddMem p;
 | 
					 | 
				
			||||||
        int fd;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (!pinos_buffer_iter_parse_add_mem (&it, &p))
 | 
					 | 
				
			||||||
          break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        fd = pinos_buffer_get_fd (pbuf, p.fd_index);
 | 
					 | 
				
			||||||
        if (fd == -1)
 | 
					 | 
				
			||||||
          break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        fdmem = gst_fd_allocator_alloc (this->fd_allocator, dup (fd),
 | 
					 | 
				
			||||||
                  p.offset + p.size, GST_FD_MEMORY_FLAG_NONE);
 | 
					 | 
				
			||||||
        gst_memory_resize (fdmem, p.offset, p.size);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        g_hash_table_insert (this->mem_ids, GINT_TO_POINTER (p.id), fdmem);
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      case PINOS_PACKET_TYPE_REMOVE_MEM:
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        PinosPacketRemoveMem p;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (!pinos_buffer_iter_parse_remove_mem (&it, &p))
 | 
					 | 
				
			||||||
          break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        g_hash_table_remove (this->mem_ids, GINT_TO_POINTER (p.id));
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      case PINOS_PACKET_TYPE_PROCESS_MEM:
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        GstMemory *fdmem = NULL;
 | 
					 | 
				
			||||||
        ProcessMemData data;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (!pinos_buffer_iter_parse_process_mem  (&it, &data.p))
 | 
					 | 
				
			||||||
          break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (!(fdmem = g_hash_table_lookup (this->mem_ids, GINT_TO_POINTER (data.p.id))))
 | 
					 | 
				
			||||||
          break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (buf == NULL)
 | 
					 | 
				
			||||||
          buf = gst_buffer_new ();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        fdmem = gst_memory_share (fdmem, data.p.offset, data.p.size);
 | 
					 | 
				
			||||||
        gst_buffer_append_memory (buf, fdmem);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        data.src = gst_object_ref (this);
 | 
					 | 
				
			||||||
        gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (fdmem),
 | 
					 | 
				
			||||||
                                   process_mem_data_quark,
 | 
					 | 
				
			||||||
                                   g_slice_dup (ProcessMemData, &data),
 | 
					 | 
				
			||||||
                                   process_mem_data_destroy);
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      case PINOS_PACKET_TYPE_FORMAT_CHANGE:
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        PinosPacketFormatChange change;
 | 
					 | 
				
			||||||
        GstCaps *caps;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (!pinos_buffer_iter_parse_format_change  (&it, &change))
 | 
					 | 
				
			||||||
          break;
 | 
					 | 
				
			||||||
        GST_DEBUG ("got format change %d %s", change.id, change.format);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        caps = gst_caps_from_string (change.format);
 | 
					 | 
				
			||||||
        gst_base_src_set_caps (GST_BASE_SRC (this), caps);
 | 
					 | 
				
			||||||
        gst_caps_unref (caps);
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      default:
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  pinos_buffer_iter_end (&it);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (buf) {
 | 
					 | 
				
			||||||
    g_queue_push_tail (&this->queue, buf);
 | 
					 | 
				
			||||||
    g_cond_signal (&this->cond);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return TRUE;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
set_port (GstPinosPortSrc *this, PinosPort *port)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  g_debug ("set port %p", port);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (this->port)
 | 
					 | 
				
			||||||
    g_object_unref (this->port);
 | 
					 | 
				
			||||||
  this->port = port;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  pinos_port_set_received_buffer_cb (port, on_received_buffer, this, NULL);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
gst_pinos_port_src_set_property (GObject * object, guint prop_id,
 | 
					 | 
				
			||||||
    const GValue * value, GParamSpec * pspec)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GstPinosPortSrc *this = GST_PINOS_PORT_SRC (object);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  switch (prop_id) {
 | 
					 | 
				
			||||||
    case PROP_PORT:
 | 
					 | 
				
			||||||
      set_port (this, g_value_dup_object (value));
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    default:
 | 
					 | 
				
			||||||
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
gst_pinos_port_src_get_property (GObject * object, guint prop_id,
 | 
					 | 
				
			||||||
    GValue * value, GParamSpec * pspec)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GstPinosPortSrc *this = GST_PINOS_PORT_SRC (object);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  switch (prop_id) {
 | 
					 | 
				
			||||||
    case PROP_PORT:
 | 
					 | 
				
			||||||
      g_value_set_object (value, this->port);
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    default:
 | 
					 | 
				
			||||||
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static GstClock *
 | 
					 | 
				
			||||||
gst_pinos_port_src_provide_clock (GstElement * elem)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GstPinosPortSrc *this = GST_PINOS_PORT_SRC (elem);
 | 
					 | 
				
			||||||
  GstClock *clock;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  GST_OBJECT_LOCK (this);
 | 
					 | 
				
			||||||
  if (!GST_OBJECT_FLAG_IS_SET (this, GST_ELEMENT_FLAG_PROVIDE_CLOCK))
 | 
					 | 
				
			||||||
    goto clock_disabled;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (this->clock)
 | 
					 | 
				
			||||||
    clock = GST_CLOCK_CAST (gst_object_ref (this->clock));
 | 
					 | 
				
			||||||
  else
 | 
					 | 
				
			||||||
    clock = NULL;
 | 
					 | 
				
			||||||
  GST_OBJECT_UNLOCK (this);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return clock;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /* ERRORS */
 | 
					 | 
				
			||||||
clock_disabled:
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    GST_DEBUG_OBJECT (this, "clock provide disabled");
 | 
					 | 
				
			||||||
    GST_OBJECT_UNLOCK (this);
 | 
					 | 
				
			||||||
    return NULL;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static gboolean
 | 
					 | 
				
			||||||
gst_pinos_port_src_unlock (GstBaseSrc * basesrc)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GstPinosPortSrc *this = GST_PINOS_PORT_SRC (basesrc);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  GST_DEBUG_OBJECT (this, "setting flushing");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  GST_OBJECT_LOCK (this);
 | 
					 | 
				
			||||||
  this->flushing = TRUE;
 | 
					 | 
				
			||||||
  g_cond_signal (&this->cond);
 | 
					 | 
				
			||||||
  GST_OBJECT_UNLOCK (this);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return TRUE;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static gboolean
 | 
					 | 
				
			||||||
gst_pinos_port_src_unlock_stop (GstBaseSrc * basesrc)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GstPinosPortSrc *this = GST_PINOS_PORT_SRC (basesrc);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  GST_DEBUG_OBJECT (this, "unsetting flushing");
 | 
					 | 
				
			||||||
  this->flushing = FALSE;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return TRUE;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
gst_pinos_port_src_finalize (GObject * object)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GstPinosPortSrc *this = GST_PINOS_PORT_SRC (object);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  g_queue_foreach (&this->queue, (GFunc) gst_mini_object_unref, NULL);
 | 
					 | 
				
			||||||
  g_queue_clear (&this->queue);
 | 
					 | 
				
			||||||
  g_cond_clear (&this->cond);
 | 
					 | 
				
			||||||
  g_object_unref (this->fd_allocator);
 | 
					 | 
				
			||||||
  g_object_unref (this->port);
 | 
					 | 
				
			||||||
  if (this->clock)
 | 
					 | 
				
			||||||
    gst_object_unref (this->clock);
 | 
					 | 
				
			||||||
  g_hash_table_unref (this->mem_ids);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  G_OBJECT_CLASS (parent_class)->finalize (object);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
gst_pinos_port_src_class_init (GstPinosPortSrcClass * klass)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GObjectClass *gobject_class;
 | 
					 | 
				
			||||||
  GstElementClass *gstelement_class;
 | 
					 | 
				
			||||||
  GstBaseSrcClass *gstbasesrc_class;
 | 
					 | 
				
			||||||
  GstPushSrcClass *gstpushsrc_class;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  gobject_class = (GObjectClass *) klass;
 | 
					 | 
				
			||||||
  gstelement_class = (GstElementClass *) klass;
 | 
					 | 
				
			||||||
  gstbasesrc_class = (GstBaseSrcClass *) klass;
 | 
					 | 
				
			||||||
  gstpushsrc_class = (GstPushSrcClass *) klass;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  gobject_class->finalize = gst_pinos_port_src_finalize;
 | 
					 | 
				
			||||||
  gobject_class->set_property = gst_pinos_port_src_set_property;
 | 
					 | 
				
			||||||
  gobject_class->get_property = gst_pinos_port_src_get_property;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  g_object_class_install_property (gobject_class, PROP_PORT,
 | 
					 | 
				
			||||||
              g_param_spec_object ("port", "Port",
 | 
					 | 
				
			||||||
                                   "The pinos port object",
 | 
					 | 
				
			||||||
                                   PINOS_TYPE_PORT,
 | 
					 | 
				
			||||||
                                   G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  gstelement_class->provide_clock = gst_pinos_port_src_provide_clock;
 | 
					 | 
				
			||||||
  gstelement_class->change_state = gst_pinos_port_src_change_state;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  gst_element_class_set_static_metadata (gstelement_class,
 | 
					 | 
				
			||||||
      "Pinos source", "Source/Video",
 | 
					 | 
				
			||||||
      "Uses pinos to create video", "Wim Taymans <wim.taymans@gmail.com>");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  gst_element_class_add_pad_template (gstelement_class,
 | 
					 | 
				
			||||||
      gst_static_pad_template_get (&gst_pinos_port_src_template));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  gstbasesrc_class->get_caps = gst_pinos_port_src_getcaps;
 | 
					 | 
				
			||||||
  gstbasesrc_class->unlock = gst_pinos_port_src_unlock;
 | 
					 | 
				
			||||||
  gstbasesrc_class->unlock_stop = gst_pinos_port_src_unlock_stop;
 | 
					 | 
				
			||||||
  gstbasesrc_class->start = gst_pinos_port_src_start;
 | 
					 | 
				
			||||||
  gstbasesrc_class->stop = gst_pinos_port_src_stop;
 | 
					 | 
				
			||||||
  gstbasesrc_class->event = gst_pinos_port_src_event;
 | 
					 | 
				
			||||||
  gstbasesrc_class->query = gst_pinos_port_src_query;
 | 
					 | 
				
			||||||
  gstpushsrc_class->create = gst_pinos_port_src_create;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  GST_DEBUG_CATEGORY_INIT (pinos_port_src_debug, "pinosportsrc", 0,
 | 
					 | 
				
			||||||
      "Pinos Source");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  process_mem_data_quark = g_quark_from_static_string ("GstPinosPortSrcProcessMemQuark");
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
gst_pinos_port_src_init (GstPinosPortSrc * src)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  /* we operate in time */
 | 
					 | 
				
			||||||
  gst_base_src_set_format (GST_BASE_SRC (src), GST_FORMAT_TIME);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  GST_OBJECT_FLAG_SET (src, GST_ELEMENT_FLAG_PROVIDE_CLOCK);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  g_cond_init (&src->cond);
 | 
					 | 
				
			||||||
  g_queue_init (&src->queue);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  src->fd_allocator = gst_fd_allocator_new ();
 | 
					 | 
				
			||||||
  src->mem_ids = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) gst_memory_unref);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
parse_stream_properties (GstPinosPortSrc *this, PinosProperties *props)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  const gchar *var;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  var = pinos_properties_get (props, "pinos.latency.is-live");
 | 
					 | 
				
			||||||
  this->is_live = var ? (atoi (var) == 1) : FALSE;
 | 
					 | 
				
			||||||
  gst_base_src_set_live (GST_BASE_SRC (this), this->is_live);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  var = pinos_properties_get (props, "pinos.latency.min");
 | 
					 | 
				
			||||||
  this->min_latency = var ? (GstClockTime) atoi (var) : 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  var = pinos_properties_get (props, "pinos.latency.max");
 | 
					 | 
				
			||||||
  this->max_latency = var ? (GstClockTime) atoi (var) : GST_CLOCK_TIME_NONE;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  var = pinos_properties_get (props, "pinos.clock.type");
 | 
					 | 
				
			||||||
  if (var != NULL) {
 | 
					 | 
				
			||||||
    GST_DEBUG_OBJECT (this, "got clock type %s", var);
 | 
					 | 
				
			||||||
    if (strcmp (var, "gst.net.time.provider") == 0) {
 | 
					 | 
				
			||||||
      const gchar *address;
 | 
					 | 
				
			||||||
      gint port;
 | 
					 | 
				
			||||||
      GstClockTime base_time;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      address = pinos_properties_get (props, "pinos.clock.address");
 | 
					 | 
				
			||||||
      port = atoi (pinos_properties_get (props, "pinos.clock.port"));
 | 
					 | 
				
			||||||
      base_time = atoll (pinos_properties_get (props, "pinos.clock.base-time"));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      GST_DEBUG_OBJECT (this, "making net clock for %s:%d %" G_GUINT64_FORMAT, address, port, base_time);
 | 
					 | 
				
			||||||
      if (this->clock)
 | 
					 | 
				
			||||||
        gst_object_unref (this->clock);
 | 
					 | 
				
			||||||
      this->clock = gst_net_client_clock_new ("pinosclock", address, port, base_time);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      gst_element_post_message (GST_ELEMENT_CAST (this),
 | 
					 | 
				
			||||||
          gst_message_new_clock_provide (GST_OBJECT_CAST (this),
 | 
					 | 
				
			||||||
            this->clock, TRUE));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static GstCaps *
 | 
					 | 
				
			||||||
gst_pinos_port_src_getcaps (GstBaseSrc * bsrc, GstCaps * filter)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GstPinosPortSrc *this = GST_PINOS_PORT_SRC (bsrc);
 | 
					 | 
				
			||||||
  GBytes *format;
 | 
					 | 
				
			||||||
  GstCaps *caps = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  GST_DEBUG ("getting caps");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  g_object_get (this->port, "format", &format, NULL);
 | 
					 | 
				
			||||||
  if (format) {
 | 
					 | 
				
			||||||
    GST_DEBUG ("have format %s", (gchar *)g_bytes_get_data (format, NULL));
 | 
					 | 
				
			||||||
    caps = gst_caps_from_string (g_bytes_get_data (format, NULL));
 | 
					 | 
				
			||||||
    g_bytes_unref (format);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  return caps;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static gboolean
 | 
					 | 
				
			||||||
gst_pinos_port_src_event (GstBaseSrc * src, GstEvent * event)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  gboolean res = FALSE;
 | 
					 | 
				
			||||||
  GstPinosPortSrc *this;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  this = GST_PINOS_PORT_SRC (src);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  switch (GST_EVENT_TYPE (event)) {
 | 
					 | 
				
			||||||
    case GST_EVENT_CUSTOM_UPSTREAM:
 | 
					 | 
				
			||||||
      if (gst_video_event_is_force_key_unit (event)) {
 | 
					 | 
				
			||||||
        GstClockTime running_time;
 | 
					 | 
				
			||||||
        gboolean all_headers;
 | 
					 | 
				
			||||||
        guint count;
 | 
					 | 
				
			||||||
        PinosPacketRefreshRequest refresh;
 | 
					 | 
				
			||||||
        PinosBufferBuilder b;
 | 
					 | 
				
			||||||
        PinosBuffer pbuf;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        gst_video_event_parse_upstream_force_key_unit (event,
 | 
					 | 
				
			||||||
                &running_time, &all_headers, &count);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        refresh.last_id = 0;
 | 
					 | 
				
			||||||
        refresh.request_type = all_headers ? 1 : 0;
 | 
					 | 
				
			||||||
        refresh.pts = running_time;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        pinos_buffer_builder_init (&b);
 | 
					 | 
				
			||||||
        pinos_buffer_builder_add_refresh_request (&b, &refresh);
 | 
					 | 
				
			||||||
        pinos_buffer_builder_end (&b, &pbuf);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        GST_DEBUG_OBJECT (this, "send refresh request");
 | 
					 | 
				
			||||||
        pinos_port_send_buffer (this->port, &pbuf, NULL);
 | 
					 | 
				
			||||||
        pinos_buffer_unref (&pbuf);
 | 
					 | 
				
			||||||
        res = TRUE;
 | 
					 | 
				
			||||||
      } else {
 | 
					 | 
				
			||||||
        res = GST_BASE_SRC_CLASS (parent_class)->event (src, event);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    default:
 | 
					 | 
				
			||||||
      res = GST_BASE_SRC_CLASS (parent_class)->event (src, event);
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  return res;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static gboolean
 | 
					 | 
				
			||||||
gst_pinos_port_src_query (GstBaseSrc * src, GstQuery * query)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  gboolean res = FALSE;
 | 
					 | 
				
			||||||
  GstPinosPortSrc *this;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  this = GST_PINOS_PORT_SRC (src);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  switch (GST_QUERY_TYPE (query)) {
 | 
					 | 
				
			||||||
    case GST_QUERY_LATENCY:
 | 
					 | 
				
			||||||
      gst_query_set_latency (query, this->is_live, this->min_latency, this->max_latency);
 | 
					 | 
				
			||||||
      res = TRUE;
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    default:
 | 
					 | 
				
			||||||
      res = GST_BASE_SRC_CLASS (parent_class)->query (src, query);
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  return res;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static GstFlowReturn
 | 
					 | 
				
			||||||
gst_pinos_port_src_create (GstPushSrc * psrc, GstBuffer ** buffer)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GstPinosPortSrc *this;
 | 
					 | 
				
			||||||
  GstClockTime pts, dts, base_time;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  this = GST_PINOS_PORT_SRC (psrc);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  GST_OBJECT_LOCK (this);
 | 
					 | 
				
			||||||
  while (TRUE) {
 | 
					 | 
				
			||||||
    if (this->flushing)
 | 
					 | 
				
			||||||
      goto streaming_stopped;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    *buffer = g_queue_pop_head (&this->queue);
 | 
					 | 
				
			||||||
    if (*buffer != NULL)
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    g_cond_wait (&this->cond, GST_OBJECT_GET_LOCK (this));
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  GST_OBJECT_UNLOCK (this);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  base_time = GST_ELEMENT_CAST (psrc)->base_time;
 | 
					 | 
				
			||||||
  pts = GST_BUFFER_PTS (*buffer);
 | 
					 | 
				
			||||||
  dts = GST_BUFFER_DTS (*buffer);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (GST_CLOCK_TIME_IS_VALID (pts))
 | 
					 | 
				
			||||||
    pts = (pts >= base_time ? pts - base_time : 0);
 | 
					 | 
				
			||||||
  if (GST_CLOCK_TIME_IS_VALID (dts))
 | 
					 | 
				
			||||||
    dts = (dts >= base_time ? dts - base_time : 0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  GST_INFO ("pts %" G_GUINT64_FORMAT ", dts %"G_GUINT64_FORMAT
 | 
					 | 
				
			||||||
      ", base-time %"GST_TIME_FORMAT" -> %"GST_TIME_FORMAT", %"GST_TIME_FORMAT,
 | 
					 | 
				
			||||||
      GST_BUFFER_PTS (*buffer), GST_BUFFER_DTS (*buffer), GST_TIME_ARGS (base_time),
 | 
					 | 
				
			||||||
      GST_TIME_ARGS (pts), GST_TIME_ARGS (dts));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  GST_BUFFER_PTS (*buffer) = pts;
 | 
					 | 
				
			||||||
  GST_BUFFER_DTS (*buffer) = dts;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return GST_FLOW_OK;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
streaming_stopped:
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    GST_OBJECT_UNLOCK (this);
 | 
					 | 
				
			||||||
    return GST_FLOW_FLUSHING;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static gboolean
 | 
					 | 
				
			||||||
gst_pinos_port_src_start (GstBaseSrc * basesrc)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  PinosProperties *props;
 | 
					 | 
				
			||||||
  GstPinosPortSrc *this;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  this = GST_PINOS_PORT_SRC (basesrc);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  props = pinos_port_get_properties (this->port);
 | 
					 | 
				
			||||||
  if (props)
 | 
					 | 
				
			||||||
    parse_stream_properties (this, props);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return TRUE;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
clear_queue (GstPinosPortSrc *this)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  g_queue_foreach (&this->queue, (GFunc) gst_mini_object_unref, NULL);
 | 
					 | 
				
			||||||
  g_queue_clear (&this->queue);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static gboolean
 | 
					 | 
				
			||||||
gst_pinos_port_src_stop (GstBaseSrc * basesrc)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GstPinosPortSrc *this;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  this = GST_PINOS_PORT_SRC (basesrc);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  clear_queue (this);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return TRUE;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static GstStateChangeReturn
 | 
					 | 
				
			||||||
gst_pinos_port_src_change_state (GstElement * element, GstStateChange transition)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GstStateChangeReturn ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  switch (transition) {
 | 
					 | 
				
			||||||
    case GST_STATE_CHANGE_NULL_TO_READY:
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case GST_STATE_CHANGE_READY_TO_PAUSED:
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
 | 
					 | 
				
			||||||
      /* uncork and start recording */
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
 | 
					 | 
				
			||||||
      /* stop recording ASAP by corking */
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    default:
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  switch (transition) {
 | 
					 | 
				
			||||||
    case GST_STATE_CHANGE_READY_TO_PAUSED:
 | 
					 | 
				
			||||||
      if (gst_base_src_is_live (GST_BASE_SRC (element)))
 | 
					 | 
				
			||||||
        ret = GST_STATE_CHANGE_NO_PREROLL;
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case GST_STATE_CHANGE_PAUSED_TO_READY:
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case GST_STATE_CHANGE_READY_TO_NULL:
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    default:
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,82 +0,0 @@
 | 
				
			||||||
/* GStreamer
 | 
					 | 
				
			||||||
 * 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
 | 
					 | 
				
			||||||
 * 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_PORT_SRC_H__
 | 
					 | 
				
			||||||
#define __GST_PINOS_PORT_SRC_H__
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <gst/gst.h>
 | 
					 | 
				
			||||||
#include <gst/base/gstpushsrc.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <client/pinos.h>
 | 
					 | 
				
			||||||
#include <server/port.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
G_BEGIN_DECLS
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define GST_TYPE_PINOS_PORT_SRC \
 | 
					 | 
				
			||||||
  (gst_pinos_port_src_get_type())
 | 
					 | 
				
			||||||
#define GST_PINOS_PORT_SRC(obj) \
 | 
					 | 
				
			||||||
  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PINOS_PORT_SRC,GstPinosPortSrc))
 | 
					 | 
				
			||||||
#define GST_PINOS_PORT_SRC_CLASS(klass) \
 | 
					 | 
				
			||||||
  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PINOS_PORT_SRC,GstPinosPortSrcClass))
 | 
					 | 
				
			||||||
#define GST_IS_PINOS_PORT_SRC(obj) \
 | 
					 | 
				
			||||||
  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PINOS_PORT_SRC))
 | 
					 | 
				
			||||||
#define GST_IS_PINOS_PORT_SRC_CLASS(klass) \
 | 
					 | 
				
			||||||
  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PINOS_PORT_SRC))
 | 
					 | 
				
			||||||
#define GST_PINOS_PORT_SRC_CAST(obj) \
 | 
					 | 
				
			||||||
  ((GstPinosPortSrc *) (obj))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct _GstPinosPortSrc GstPinosPortSrc;
 | 
					 | 
				
			||||||
typedef struct _GstPinosPortSrcClass GstPinosPortSrcClass;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * GstPinosPortSrc:
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Opaque data structure.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
struct _GstPinosPortSrc {
 | 
					 | 
				
			||||||
  GstPushSrc element;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /*< private >*/
 | 
					 | 
				
			||||||
  PinosPort *port;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  gboolean negotiated;
 | 
					 | 
				
			||||||
  gboolean flushing;
 | 
					 | 
				
			||||||
  gboolean started;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  gboolean is_live;
 | 
					 | 
				
			||||||
  GstClockTime min_latency;
 | 
					 | 
				
			||||||
  GstClockTime max_latency;
 | 
					 | 
				
			||||||
  GstClock *clock;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  GstAllocator *fd_allocator;
 | 
					 | 
				
			||||||
  GHashTable *mem_ids;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  GQueue queue;
 | 
					 | 
				
			||||||
  GCond cond;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct _GstPinosPortSrcClass {
 | 
					 | 
				
			||||||
  GstPushSrcClass parent_class;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
GType gst_pinos_port_src_get_type (void);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
G_END_DECLS
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif /* __GST_PINOS_PORT_SRC_H__ */
 | 
					 | 
				
			||||||
| 
						 | 
					@ -45,7 +45,6 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <spa/include/spa/buffer.h>
 | 
					#include <spa/include/spa/buffer.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "gsttmpfileallocator.h"
 | 
					 | 
				
			||||||
#include "gstpinosformat.h"
 | 
					#include "gstpinosformat.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static GQuark process_mem_data_quark;
 | 
					static GQuark process_mem_data_quark;
 | 
				
			||||||
| 
						 | 
					@ -216,7 +215,7 @@ gst_pinos_sink_class_init (GstPinosSinkClass * klass)
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
gst_pinos_sink_init (GstPinosSink * sink)
 | 
					gst_pinos_sink_init (GstPinosSink * sink)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  sink->allocator = gst_tmpfile_allocator_new ();
 | 
					  sink->allocator = gst_fd_allocator_new ();
 | 
				
			||||||
  sink->pool =  gst_pinos_pool_new ();
 | 
					  sink->pool =  gst_pinos_pool_new ();
 | 
				
			||||||
  sink->client_name = pinos_client_name();
 | 
					  sink->client_name = pinos_client_name();
 | 
				
			||||||
  sink->mode = DEFAULT_PROP_MODE;
 | 
					  sink->mode = DEFAULT_PROP_MODE;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,904 +0,0 @@
 | 
				
			||||||
/* GStreamer
 | 
					 | 
				
			||||||
 * Copyright (C) <2016> 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.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * SECTION:element-pinossocketsink
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef HAVE_CONFIG_H
 | 
					 | 
				
			||||||
#include "config.h"
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <string.h>
 | 
					 | 
				
			||||||
#include <stdlib.h>
 | 
					 | 
				
			||||||
#include <fcntl.h>
 | 
					 | 
				
			||||||
#include <sys/socket.h>
 | 
					 | 
				
			||||||
#include <unistd.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <gio/gunixfdmessage.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <gst/allocators/gstfdmemory.h>
 | 
					 | 
				
			||||||
#include <gst/net/gstnetcontrolmessagemeta.h>
 | 
					 | 
				
			||||||
#include <gst/video/video.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "gstpinossocketsink.h"
 | 
					 | 
				
			||||||
#include "gsttmpfileallocator.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct _MyReader MyReader;
 | 
					 | 
				
			||||||
typedef struct _MySource MySource;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct _MyReader {
 | 
					 | 
				
			||||||
  GstBurstCacheReader reader;
 | 
					 | 
				
			||||||
  GSocket *socket;
 | 
					 | 
				
			||||||
  MySource *source;
 | 
					 | 
				
			||||||
  guint id;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct _MySource {
 | 
					 | 
				
			||||||
  GSource source;
 | 
					 | 
				
			||||||
  GIOCondition condition;
 | 
					 | 
				
			||||||
  gpointer tag;
 | 
					 | 
				
			||||||
  MyReader *reader;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef gboolean (*MyReaderSourceFunc) (MyReader *reader, GIOCondition condition, gpointer user_data);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static gboolean
 | 
					 | 
				
			||||||
mysource_dispatch (GSource     *source,
 | 
					 | 
				
			||||||
                   GSourceFunc  callback,
 | 
					 | 
				
			||||||
                   gpointer     user_data)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  MyReaderSourceFunc func = (MyReaderSourceFunc)callback;
 | 
					 | 
				
			||||||
  MySource *mysource = (MySource *)source;
 | 
					 | 
				
			||||||
  MyReader *myreader = mysource->reader;
 | 
					 | 
				
			||||||
  guint events;
 | 
					 | 
				
			||||||
  gboolean ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  events = g_source_query_unix_fd (source, mysource->tag);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  ret = (*func) (myreader, events, user_data);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static GSourceFuncs mysource_funcs =
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  NULL, NULL, /* check, prepare */
 | 
					 | 
				
			||||||
  mysource_dispatch,
 | 
					 | 
				
			||||||
  NULL, /* finalize */
 | 
					 | 
				
			||||||
  NULL,
 | 
					 | 
				
			||||||
  NULL,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static GQuark fdids_quark;
 | 
					 | 
				
			||||||
static GQuark orig_buffer_quark;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
GST_DEBUG_CATEGORY_STATIC (pinos_socket_sink_debug);
 | 
					 | 
				
			||||||
#define GST_CAT_DEFAULT pinos_socket_sink_debug
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static GstStaticPadTemplate gst_pinos_socket_sink_template =
 | 
					 | 
				
			||||||
GST_STATIC_PAD_TEMPLATE ("sink",
 | 
					 | 
				
			||||||
    GST_PAD_SINK,
 | 
					 | 
				
			||||||
    GST_PAD_ALWAYS,
 | 
					 | 
				
			||||||
    GST_STATIC_CAPS_ANY
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
enum
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  PROP_0,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  PROP_NUM_HANDLES,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* PinosSocketSink signals and args */
 | 
					 | 
				
			||||||
enum
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  /* methods */
 | 
					 | 
				
			||||||
  SIGNAL_ADD,
 | 
					 | 
				
			||||||
  SIGNAL_REMOVE,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  LAST_SIGNAL
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static guint gst_pinos_socket_sink_signals[LAST_SIGNAL] = { 0 };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define gst_pinos_socket_sink_parent_class parent_class
 | 
					 | 
				
			||||||
G_DEFINE_TYPE (GstPinosSocketSink, gst_pinos_socket_sink, GST_TYPE_BASE_SINK);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static gboolean
 | 
					 | 
				
			||||||
gst_pinos_socket_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GstPinosSocketSink *this = GST_PINOS_SOCKET_SINK (bsink);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  gst_query_add_allocation_param (query, this->allocator, NULL);
 | 
					 | 
				
			||||||
  gst_query_add_allocation_meta (query, GST_NET_CONTROL_MESSAGE_META_API_TYPE,
 | 
					 | 
				
			||||||
            NULL);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return TRUE;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
gst_pinos_socket_sink_set_property (GObject * object, guint prop_id,
 | 
					 | 
				
			||||||
    const GValue * value, GParamSpec * pspec)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  switch (prop_id) {
 | 
					 | 
				
			||||||
    default:
 | 
					 | 
				
			||||||
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
gst_pinos_socket_sink_get_property (GObject * object, guint prop_id,
 | 
					 | 
				
			||||||
    GValue * value, GParamSpec * pspec)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GstPinosSocketSink *this = GST_PINOS_SOCKET_SINK (object);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  switch (prop_id) {
 | 
					 | 
				
			||||||
    case PROP_NUM_HANDLES:
 | 
					 | 
				
			||||||
      g_value_set_uint (value, g_hash_table_size (this->hash));
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    default:
 | 
					 | 
				
			||||||
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static gboolean
 | 
					 | 
				
			||||||
gst_pinos_socket_sink_setcaps (GstBaseSink * bsink, GstCaps * caps)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GstPinosSocketSink *this = GST_PINOS_SOCKET_SINK (bsink);
 | 
					 | 
				
			||||||
  GstStructure *str;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  str = gst_caps_get_structure (caps, 0);
 | 
					 | 
				
			||||||
  this->pinos_input = gst_structure_has_name (str, "application/x-pinos");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return GST_BASE_SINK_CLASS (parent_class)->set_caps (bsink, caps);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
reuse_fds (GstPinosSocketSink *this, GstBuffer *buffer)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GArray *fdids;
 | 
					 | 
				
			||||||
  guint i;
 | 
					 | 
				
			||||||
  PinosBufferBuilder b;
 | 
					 | 
				
			||||||
  PinosPacketReuseMem r;
 | 
					 | 
				
			||||||
  PinosBuffer pbuf;
 | 
					 | 
				
			||||||
  gsize size;
 | 
					 | 
				
			||||||
  gpointer data;
 | 
					 | 
				
			||||||
  GstBuffer *outbuf;
 | 
					 | 
				
			||||||
  GstEvent *ev;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  fdids = gst_mini_object_steal_qdata (GST_MINI_OBJECT_CAST (buffer),
 | 
					 | 
				
			||||||
      fdids_quark);
 | 
					 | 
				
			||||||
  if (fdids == NULL)
 | 
					 | 
				
			||||||
    return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  pinos_buffer_builder_init (&b);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  for (i = 0; i < fdids->len; i++) {
 | 
					 | 
				
			||||||
    r.id = g_array_index (fdids, guint32, i);
 | 
					 | 
				
			||||||
    GST_LOG ("reuse fd index %d", r.id);
 | 
					 | 
				
			||||||
    pinos_buffer_builder_add_reuse_mem (&b, &r);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  pinos_buffer_builder_end (&b, &pbuf);
 | 
					 | 
				
			||||||
  g_array_unref (fdids);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  data = pinos_buffer_steal_data (&pbuf, &size);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  outbuf = gst_buffer_new_wrapped (data, size);
 | 
					 | 
				
			||||||
  ev = gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
 | 
					 | 
				
			||||||
          gst_structure_new ("GstNetworkMessage",
 | 
					 | 
				
			||||||
              "object", G_TYPE_OBJECT, this,
 | 
					 | 
				
			||||||
              "buffer", GST_TYPE_BUFFER, outbuf, NULL));
 | 
					 | 
				
			||||||
  gst_buffer_unref (outbuf);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  gst_pad_push_event (GST_BASE_SINK_PAD (this), ev);
 | 
					 | 
				
			||||||
  g_object_unref (this);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static GstFlowReturn
 | 
					 | 
				
			||||||
gst_pinos_socket_sink_render_pinos (GstPinosSocketSink * this, GstBuffer * buffer)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GstMapInfo info;
 | 
					 | 
				
			||||||
  PinosBuffer pbuf;
 | 
					 | 
				
			||||||
  PinosBufferIter it;
 | 
					 | 
				
			||||||
  GArray *fdids = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  gst_buffer_map (buffer, &info, GST_MAP_READ);
 | 
					 | 
				
			||||||
  pinos_buffer_init_data (&pbuf, info.data, info.size, NULL, 0);
 | 
					 | 
				
			||||||
  pinos_buffer_iter_init (&it, &pbuf);
 | 
					 | 
				
			||||||
  while (pinos_buffer_iter_next (&it)) {
 | 
					 | 
				
			||||||
    switch (pinos_buffer_iter_get_type (&it)) {
 | 
					 | 
				
			||||||
      case PINOS_PACKET_TYPE_PROCESS_MEM:
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        PinosPacketProcessMem p;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (!pinos_buffer_iter_parse_process_mem (&it, &p))
 | 
					 | 
				
			||||||
          continue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (fdids == NULL)
 | 
					 | 
				
			||||||
          fdids = g_array_new (FALSE, FALSE, sizeof (guint32));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        GST_LOG ("track fd id %d", p.id);
 | 
					 | 
				
			||||||
        g_array_append_val (fdids, p.id);
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      case PINOS_PACKET_TYPE_FORMAT_CHANGE:
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        PinosPacketFormatChange p;
 | 
					 | 
				
			||||||
        GstCaps * caps;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (!pinos_buffer_iter_parse_format_change (&it, &p))
 | 
					 | 
				
			||||||
          continue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        caps = gst_caps_from_string (p.format);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        gst_element_post_message (GST_ELEMENT (this),
 | 
					 | 
				
			||||||
            gst_message_new_element (GST_OBJECT (this),
 | 
					 | 
				
			||||||
                gst_structure_new ("PinosPayloaderFormatChange",
 | 
					 | 
				
			||||||
                    "format", GST_TYPE_CAPS, caps, NULL)));
 | 
					 | 
				
			||||||
        gst_caps_unref (caps);
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      default:
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  pinos_buffer_iter_end (&it);
 | 
					 | 
				
			||||||
  pinos_buffer_unref (&pbuf);
 | 
					 | 
				
			||||||
  gst_buffer_unmap (buffer, &info);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (fdids != NULL) {
 | 
					 | 
				
			||||||
    gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (buffer),
 | 
					 | 
				
			||||||
        fdids_quark, fdids, NULL);
 | 
					 | 
				
			||||||
    gst_mini_object_weak_ref (GST_MINI_OBJECT_CAST (buffer),
 | 
					 | 
				
			||||||
        (GstMiniObjectNotify) reuse_fds, g_object_ref (this));
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  gst_burst_cache_queue_buffer (this->cache, gst_buffer_ref (buffer));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return GST_FLOW_OK;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static GstMemory *
 | 
					 | 
				
			||||||
gst_pinos_socket_sink_get_fd_memory (GstPinosSocketSink * this, GstBuffer * buffer, gboolean *tmpfile)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  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);
 | 
					 | 
				
			||||||
    *tmpfile = gst_is_tmpfile_memory (mem);
 | 
					 | 
				
			||||||
  } else {
 | 
					 | 
				
			||||||
    GstMapInfo info;
 | 
					 | 
				
			||||||
    GstAllocationParams params = {0, 0, 0, 0, { NULL, }};
 | 
					 | 
				
			||||||
    gsize size = gst_buffer_get_size (buffer);
 | 
					 | 
				
			||||||
    GST_INFO_OBJECT (this, "Buffer cannot be sent without copying");
 | 
					 | 
				
			||||||
    mem = gst_allocator_alloc (this->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);
 | 
					 | 
				
			||||||
    *tmpfile = TRUE;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  return mem;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static GstFlowReturn
 | 
					 | 
				
			||||||
gst_pinos_socket_sink_render_other (GstPinosSocketSink * this, GstBuffer * buffer)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GstMemory *fdmem = NULL;
 | 
					 | 
				
			||||||
  GError *err = NULL;
 | 
					 | 
				
			||||||
  GstBuffer *outbuf;
 | 
					 | 
				
			||||||
  PinosBuffer pbuf;
 | 
					 | 
				
			||||||
  PinosBufferBuilder builder;
 | 
					 | 
				
			||||||
  PinosPacketHeader hdr;
 | 
					 | 
				
			||||||
  PinosPacketAddMem am;
 | 
					 | 
				
			||||||
  PinosPacketProcessMem p;
 | 
					 | 
				
			||||||
  PinosPacketRemoveMem rm;
 | 
					 | 
				
			||||||
  gsize size;
 | 
					 | 
				
			||||||
  gpointer data;
 | 
					 | 
				
			||||||
  GSocketControlMessage *msg;
 | 
					 | 
				
			||||||
  gboolean tmpfile = TRUE;
 | 
					 | 
				
			||||||
  gint *fds, n_fds, i;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  hdr.flags = 0;
 | 
					 | 
				
			||||||
  hdr.seq = GST_BUFFER_OFFSET (buffer);
 | 
					 | 
				
			||||||
  hdr.pts = GST_BUFFER_PTS (buffer) + GST_ELEMENT_CAST (this)->base_time;
 | 
					 | 
				
			||||||
  hdr.dts_offset = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  pinos_buffer_builder_init (&builder);
 | 
					 | 
				
			||||||
  pinos_buffer_builder_add_header (&builder, &hdr);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  fdmem = gst_pinos_socket_sink_get_fd_memory (this, buffer, &tmpfile);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  am.id = pinos_fd_manager_get_id (this->fdmanager);
 | 
					 | 
				
			||||||
  am.fd_index = pinos_buffer_builder_add_fd (&builder, gst_fd_memory_get_fd (fdmem));
 | 
					 | 
				
			||||||
  am.offset = 0;
 | 
					 | 
				
			||||||
  am.size = fdmem->size;
 | 
					 | 
				
			||||||
  p.id = am.id;
 | 
					 | 
				
			||||||
  p.offset = fdmem->offset;
 | 
					 | 
				
			||||||
  p.size = fdmem->size;
 | 
					 | 
				
			||||||
  rm.id = am.id;
 | 
					 | 
				
			||||||
  pinos_buffer_builder_add_add_mem (&builder, &am);
 | 
					 | 
				
			||||||
  pinos_buffer_builder_add_process_mem (&builder, &p);
 | 
					 | 
				
			||||||
  pinos_buffer_builder_add_remove_mem (&builder, &rm);
 | 
					 | 
				
			||||||
  pinos_buffer_builder_end (&builder, &pbuf);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  GST_LOG ("send %d %"G_GUINT64_FORMAT" %"G_GUINT64_FORMAT" %"G_GUINT64_FORMAT,
 | 
					 | 
				
			||||||
      p.id, hdr.pts, GST_BUFFER_PTS (buffer), GST_ELEMENT_CAST (this)->base_time);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  data = pinos_buffer_steal_data (&pbuf, &size);
 | 
					 | 
				
			||||||
  fds = pinos_buffer_steal_fds (&pbuf, &n_fds);
 | 
					 | 
				
			||||||
  pinos_buffer_unref (&pbuf);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  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);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  msg = g_unix_fd_message_new ();
 | 
					 | 
				
			||||||
  for (i = 0; i < n_fds; i++) {
 | 
					 | 
				
			||||||
    if (!g_unix_fd_message_append_fd (G_UNIX_FD_MESSAGE (msg), fds[i], &err))
 | 
					 | 
				
			||||||
      goto add_fd_failed;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  gst_buffer_add_net_control_message_meta (outbuf, msg);
 | 
					 | 
				
			||||||
  g_object_unref (msg);
 | 
					 | 
				
			||||||
  g_free (fds);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  gst_memory_unref(fdmem);
 | 
					 | 
				
			||||||
  fdmem = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (!tmpfile) {
 | 
					 | 
				
			||||||
    GArray *fdids;
 | 
					 | 
				
			||||||
    /* we are using the original buffer fd in the control message, we need
 | 
					 | 
				
			||||||
     * to make sure it is not reused before everyone is finished with it.
 | 
					 | 
				
			||||||
     * We tag the output buffer with the array of fds in it and the original
 | 
					 | 
				
			||||||
     * buffer (to keep it alive). All clients that receive the fd will
 | 
					 | 
				
			||||||
     * increment outbuf refcount, all clients that do release-fd on the fd
 | 
					 | 
				
			||||||
     * will decrease the refcount again. */
 | 
					 | 
				
			||||||
    fdids = g_array_new (FALSE, FALSE, sizeof (guint32));
 | 
					 | 
				
			||||||
    g_array_append_val (fdids, p.id);
 | 
					 | 
				
			||||||
    gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (outbuf),
 | 
					 | 
				
			||||||
        fdids_quark, fdids, (GDestroyNotify) g_array_unref);
 | 
					 | 
				
			||||||
    gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (outbuf),
 | 
					 | 
				
			||||||
        orig_buffer_quark, gst_buffer_ref (buffer), (GDestroyNotify) gst_buffer_unref);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  gst_burst_cache_queue_buffer (this->cache, outbuf);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return GST_FLOW_OK;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /* ERRORS */
 | 
					 | 
				
			||||||
add_fd_failed:
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    GST_WARNING_OBJECT (this, "Adding fd failed: %s", err->message);
 | 
					 | 
				
			||||||
    gst_memory_unref(fdmem);
 | 
					 | 
				
			||||||
    g_clear_error (&err);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return GST_FLOW_ERROR;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static GstFlowReturn
 | 
					 | 
				
			||||||
gst_pinos_socket_sink_render (GstBaseSink * bsink, GstBuffer * buffer)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GstPinosSocketSink *this = GST_PINOS_SOCKET_SINK (bsink);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (this->pinos_input)
 | 
					 | 
				
			||||||
    return gst_pinos_socket_sink_render_pinos (this, buffer);
 | 
					 | 
				
			||||||
  else
 | 
					 | 
				
			||||||
    return gst_pinos_socket_sink_render_other (this, buffer);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static gboolean
 | 
					 | 
				
			||||||
gst_pinos_socket_sink_start (GstBaseSink * basesink)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  return TRUE;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static gboolean
 | 
					 | 
				
			||||||
gst_pinos_socket_sink_stop (GstBaseSink * basesink)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  return TRUE;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static gpointer
 | 
					 | 
				
			||||||
socketsink_loop (GstPinosSocketSink * this)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  g_main_loop_run (this->loop);
 | 
					 | 
				
			||||||
  return NULL;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static gboolean
 | 
					 | 
				
			||||||
gst_pinos_socket_sink_open (GstPinosSocketSink * this)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GError *error = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  this->context = g_main_context_new ();
 | 
					 | 
				
			||||||
  this->loop = g_main_loop_new (this->context, TRUE);
 | 
					 | 
				
			||||||
  GST_DEBUG ("context %p, loop %p", this->context, this->loop);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  this->thread = g_thread_try_new ("PinosSocketSink",
 | 
					 | 
				
			||||||
                                   (GThreadFunc) socketsink_loop,
 | 
					 | 
				
			||||||
                                   this,
 | 
					 | 
				
			||||||
                                   &error);
 | 
					 | 
				
			||||||
  if (this->thread == NULL)
 | 
					 | 
				
			||||||
    goto thread_error;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return TRUE;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /* ERRORS */
 | 
					 | 
				
			||||||
thread_error:
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    GST_ELEMENT_ERROR (this, RESOURCE, FAILED,
 | 
					 | 
				
			||||||
        ("Failed to start mainloop thread: %s", error->message), (NULL));
 | 
					 | 
				
			||||||
    g_clear_error (&error);
 | 
					 | 
				
			||||||
    g_clear_pointer (&this->loop, g_main_loop_unref);
 | 
					 | 
				
			||||||
    g_clear_pointer (&this->context, g_main_context_unref);
 | 
					 | 
				
			||||||
    return FALSE;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static gboolean
 | 
					 | 
				
			||||||
gst_pinos_socket_sink_close (GstPinosSocketSink * this)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  gst_burst_cache_remove_buffers (this->cache);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  GST_DEBUG ("context %p, loop %p", this->context, this->loop);
 | 
					 | 
				
			||||||
  g_main_loop_quit (this->loop);
 | 
					 | 
				
			||||||
  g_thread_join (this->thread);
 | 
					 | 
				
			||||||
  this->thread = NULL;
 | 
					 | 
				
			||||||
  g_clear_pointer (&this->loop, g_main_loop_unref);
 | 
					 | 
				
			||||||
  g_clear_pointer (&this->context, g_main_context_unref);
 | 
					 | 
				
			||||||
  g_hash_table_remove_all (this->hash);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return TRUE;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static GstStateChangeReturn
 | 
					 | 
				
			||||||
gst_pinos_socket_sink_change_state (GstElement * element, GstStateChange transition)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GstStateChangeReturn ret;
 | 
					 | 
				
			||||||
  GstPinosSocketSink *this = GST_PINOS_SOCKET_SINK_CAST (element);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  switch (transition) {
 | 
					 | 
				
			||||||
    case GST_STATE_CHANGE_NULL_TO_READY:
 | 
					 | 
				
			||||||
      if (!gst_pinos_socket_sink_open (this))
 | 
					 | 
				
			||||||
        goto open_failed;
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case GST_STATE_CHANGE_READY_TO_PAUSED:
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    default:
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  switch (transition) {
 | 
					 | 
				
			||||||
    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case GST_STATE_CHANGE_PAUSED_TO_READY:
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case GST_STATE_CHANGE_READY_TO_NULL:
 | 
					 | 
				
			||||||
      gst_pinos_socket_sink_close (this);
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    default:
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  return ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /* ERRORS */
 | 
					 | 
				
			||||||
open_failed:
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    return GST_STATE_CHANGE_FAILURE;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
myreader_receive_buffer (GstPinosSocketSink *this, MyReader *myreader)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  MySource *mysource = myreader->source;
 | 
					 | 
				
			||||||
  gssize navail, nread, maxmem;
 | 
					 | 
				
			||||||
  GstEvent *ev;
 | 
					 | 
				
			||||||
  gchar *mem;
 | 
					 | 
				
			||||||
  PinosBuffer pbuf;
 | 
					 | 
				
			||||||
  PinosBufferIter it;
 | 
					 | 
				
			||||||
  PinosBufferBuilder b;
 | 
					 | 
				
			||||||
  const gchar *client_path;
 | 
					 | 
				
			||||||
  gboolean have_out = FALSE;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  navail = g_socket_get_available_bytes (myreader->socket);
 | 
					 | 
				
			||||||
  maxmem = MAX (navail, 1);
 | 
					 | 
				
			||||||
  mem = g_malloc (maxmem);
 | 
					 | 
				
			||||||
  nread = g_socket_receive (myreader->socket, mem, maxmem, NULL, NULL);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (nread <= 0) {
 | 
					 | 
				
			||||||
    GST_DEBUG ("client closed");
 | 
					 | 
				
			||||||
    mysource->condition &= ~G_IO_IN;
 | 
					 | 
				
			||||||
    g_source_modify_unix_fd ((GSource *)mysource, mysource->tag, mysource->condition);
 | 
					 | 
				
			||||||
    g_free (mem);
 | 
					 | 
				
			||||||
    return;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  client_path = g_object_get_data (G_OBJECT (myreader->socket), "pinos-client-path");
 | 
					 | 
				
			||||||
  if (client_path == NULL)
 | 
					 | 
				
			||||||
    return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (this->pinos_input) {
 | 
					 | 
				
			||||||
    pinos_buffer_builder_init (&b);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  pinos_buffer_init_data (&pbuf, mem, maxmem, NULL, 0);
 | 
					 | 
				
			||||||
  pinos_buffer_iter_init (&it, &pbuf);
 | 
					 | 
				
			||||||
  while (pinos_buffer_iter_next (&it)) {
 | 
					 | 
				
			||||||
    switch (pinos_buffer_iter_get_type (&it)) {
 | 
					 | 
				
			||||||
      case PINOS_PACKET_TYPE_REUSE_MEM:
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        PinosPacketReuseMem p;
 | 
					 | 
				
			||||||
        gint id;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (!pinos_buffer_iter_parse_reuse_mem (&it, &p))
 | 
					 | 
				
			||||||
          continue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        id = p.id;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        GST_LOG ("fd id %d for client %s is reused", id, client_path);
 | 
					 | 
				
			||||||
        pinos_fd_manager_remove (this->fdmanager, client_path, id);
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
     case PINOS_PACKET_TYPE_REFRESH_REQUEST:
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        PinosPacketRefreshRequest p;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (!pinos_buffer_iter_parse_refresh_request (&it, &p))
 | 
					 | 
				
			||||||
          continue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        GST_LOG ("refresh request");
 | 
					 | 
				
			||||||
        if (!this->pinos_input) {
 | 
					 | 
				
			||||||
          gst_pad_push_event (GST_BASE_SINK_PAD (this),
 | 
					 | 
				
			||||||
              gst_video_event_new_upstream_force_key_unit (p.pts,
 | 
					 | 
				
			||||||
              p.request_type == 1, 0));
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
          pinos_buffer_builder_add_refresh_request (&b, &p);
 | 
					 | 
				
			||||||
          have_out = TRUE;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      default:
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  pinos_buffer_iter_end (&it);
 | 
					 | 
				
			||||||
  pinos_buffer_unref (&pbuf);
 | 
					 | 
				
			||||||
  g_free (mem);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (this->pinos_input) {
 | 
					 | 
				
			||||||
    GstBuffer *outbuf;
 | 
					 | 
				
			||||||
    gsize size;
 | 
					 | 
				
			||||||
    gpointer data;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (have_out) {
 | 
					 | 
				
			||||||
      pinos_buffer_builder_end (&b, &pbuf);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      data = pinos_buffer_steal_data (&pbuf, &size);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      outbuf = gst_buffer_new_wrapped (data, size);
 | 
					 | 
				
			||||||
      ev = gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
 | 
					 | 
				
			||||||
              gst_structure_new ("GstNetworkMessage",
 | 
					 | 
				
			||||||
                  "object", G_TYPE_OBJECT, this,
 | 
					 | 
				
			||||||
                  "buffer", GST_TYPE_BUFFER, outbuf, NULL));
 | 
					 | 
				
			||||||
      gst_buffer_unref (outbuf);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      gst_pad_push_event (GST_BASE_SINK_PAD (this), ev);
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      pinos_buffer_builder_clear (&b);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
myreader_callback (GstBurstCache *cache,
 | 
					 | 
				
			||||||
                   GstBurstCacheReader *reader,
 | 
					 | 
				
			||||||
                   gpointer user_data)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  MyReader *myreader = (MyReader *) reader;
 | 
					 | 
				
			||||||
  MySource *mysource = myreader->source;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  GST_LOG ("%p: callback", reader);
 | 
					 | 
				
			||||||
  mysource->condition |= G_IO_OUT;
 | 
					 | 
				
			||||||
  g_source_modify_unix_fd ((GSource *)mysource, mysource->tag, mysource->condition);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define VEC_MAX 8
 | 
					 | 
				
			||||||
#define CMSG_MAX 255
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
myreader_send_buffer (GstPinosSocketSink *this, MyReader *myreader, GstBuffer *buf)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GstMapInfo maps[VEC_MAX];
 | 
					 | 
				
			||||||
  GOutputVector vec[VEC_MAX];
 | 
					 | 
				
			||||||
  GSocketControlMessage *cmsgs[CMSG_MAX];
 | 
					 | 
				
			||||||
  guint i, mem_len;
 | 
					 | 
				
			||||||
  gpointer iter_state = NULL;
 | 
					 | 
				
			||||||
  GstMeta *meta;
 | 
					 | 
				
			||||||
  gsize msg_count = 0;
 | 
					 | 
				
			||||||
  gssize wrote;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  mem_len = MIN (gst_buffer_n_memory (buf), VEC_MAX);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  for (i = 0; i < mem_len; i++) {
 | 
					 | 
				
			||||||
    GstMapInfo map = { 0 };
 | 
					 | 
				
			||||||
    GstMemory *mem = gst_buffer_peek_memory (buf, i);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (!gst_memory_map (mem, &map, GST_MAP_READ))
 | 
					 | 
				
			||||||
      g_error ("Unable to map memory %p.  This should never happen.", mem);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    vec[i].buffer = map.data;
 | 
					 | 
				
			||||||
    vec[i].size = map.size;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    maps[i] = map;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  while ((meta = gst_buffer_iterate_meta (buf, &iter_state)) != NULL
 | 
					 | 
				
			||||||
      && msg_count < CMSG_MAX) {
 | 
					 | 
				
			||||||
    if (meta->info->api == GST_NET_CONTROL_MESSAGE_META_API_TYPE)
 | 
					 | 
				
			||||||
      cmsgs[msg_count++] = ((GstNetControlMessageMeta *) meta)->message;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  wrote = g_socket_send_message (myreader->socket, NULL, vec, mem_len, cmsgs, msg_count, 0,
 | 
					 | 
				
			||||||
      NULL, NULL);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  for (i = 0; i < mem_len; i++)
 | 
					 | 
				
			||||||
    gst_memory_unmap (maps[i].memory, &maps[i]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (wrote < 0) {
 | 
					 | 
				
			||||||
    GST_DEBUG_OBJECT (this, "error sending to reader");
 | 
					 | 
				
			||||||
  } else {
 | 
					 | 
				
			||||||
    GArray *fdids;
 | 
					 | 
				
			||||||
    const gchar *client_path;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fdids = gst_mini_object_get_qdata (GST_MINI_OBJECT_CAST (buf), fdids_quark);
 | 
					 | 
				
			||||||
    if (fdids == NULL)
 | 
					 | 
				
			||||||
      return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* get the client path of this socket */
 | 
					 | 
				
			||||||
    client_path = g_object_get_data (G_OBJECT (myreader->socket), "pinos-client-path");
 | 
					 | 
				
			||||||
    if (client_path == NULL)
 | 
					 | 
				
			||||||
      return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (i = 0; i < fdids->len; i++) {
 | 
					 | 
				
			||||||
      gint id = g_array_index (fdids, guint32, i);
 | 
					 | 
				
			||||||
      /* now store the id/client-path/buffer in the fdmanager */
 | 
					 | 
				
			||||||
      GST_LOG ("fd index %d, client %s increment refcount of buffer %p", id, client_path, buf);
 | 
					 | 
				
			||||||
      pinos_fd_manager_add (this->fdmanager,
 | 
					 | 
				
			||||||
                            client_path, id,
 | 
					 | 
				
			||||||
                            gst_buffer_ref (buf),
 | 
					 | 
				
			||||||
                            (GDestroyNotify) gst_buffer_unref);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static gboolean
 | 
					 | 
				
			||||||
myreader_source_func (GstBurstCacheReader *reader, GIOCondition condition, gpointer user_data)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GstPinosSocketSink *this = user_data;
 | 
					 | 
				
			||||||
  MyReader *myreader = (MyReader *) reader;
 | 
					 | 
				
			||||||
  MySource *mysource = myreader->source;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  GST_LOG ("%p: io condition %d", reader, condition);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (condition & (G_IO_HUP | G_IO_ERR)) {
 | 
					 | 
				
			||||||
    GST_DEBUG ("client error");
 | 
					 | 
				
			||||||
    return FALSE;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  if (condition & G_IO_IN) {
 | 
					 | 
				
			||||||
    myreader_receive_buffer (this, myreader);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  if (condition & G_IO_OUT) {
 | 
					 | 
				
			||||||
    GstBuffer *buf = NULL;
 | 
					 | 
				
			||||||
    GstBurstCacheResult res;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    res = gst_burst_cache_get_buffer (this->cache, reader, &buf);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    switch (res) {
 | 
					 | 
				
			||||||
      case GST_BURST_CACHE_RESULT_ERROR:
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      case GST_BURST_CACHE_RESULT_OK:
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      case GST_BURST_CACHE_RESULT_WAIT:
 | 
					 | 
				
			||||||
        mysource->condition &= ~G_IO_OUT;
 | 
					 | 
				
			||||||
        g_source_modify_unix_fd ((GSource *)mysource, mysource->tag, mysource->condition);
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      case GST_BURST_CACHE_RESULT_EOS:
 | 
					 | 
				
			||||||
        gst_burst_cache_remove_reader (this->cache, reader, FALSE);
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (buf) {
 | 
					 | 
				
			||||||
      myreader_send_buffer (this, myreader, buf);
 | 
					 | 
				
			||||||
      gst_buffer_unref (buf);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return TRUE;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
myreader_destroy (MyReader *myreader)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  gst_burst_cache_reader_destroy ((GstBurstCacheReader *)myreader);
 | 
					 | 
				
			||||||
  g_clear_object (&myreader->socket);
 | 
					 | 
				
			||||||
  g_source_destroy ((GSource*) myreader->source);
 | 
					 | 
				
			||||||
  myreader->id = 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
gst_pinos_socket_sink_add (GstPinosSocketSink * this, GSocket *socket)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GstBurstCacheReader *reader;
 | 
					 | 
				
			||||||
  MyReader *myreader;
 | 
					 | 
				
			||||||
  MySource *mysource;
 | 
					 | 
				
			||||||
  int fd;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  fd = g_socket_get_fd (socket);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (g_hash_table_lookup (this->hash, GINT_TO_POINTER (fd)))
 | 
					 | 
				
			||||||
    return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  reader = gst_burst_cache_reader_new (this->cache,
 | 
					 | 
				
			||||||
                                       (GstBurstCacheReaderCallback) myreader_callback,
 | 
					 | 
				
			||||||
                                       this,
 | 
					 | 
				
			||||||
                                       NULL);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  reader->hook.destroy = (GDestroyNotify) myreader_destroy;
 | 
					 | 
				
			||||||
  myreader = (MyReader *)reader;
 | 
					 | 
				
			||||||
  myreader->socket = g_object_ref (socket);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  mysource = (MySource*) g_source_new (&mysource_funcs, sizeof (MySource));
 | 
					 | 
				
			||||||
  mysource->reader = myreader;
 | 
					 | 
				
			||||||
  mysource->condition = G_IO_IN;
 | 
					 | 
				
			||||||
  mysource->tag = g_source_add_unix_fd ((GSource*)mysource, fd, mysource->condition);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  myreader->source = mysource;
 | 
					 | 
				
			||||||
  g_source_set_callback ((GSource*)mysource,
 | 
					 | 
				
			||||||
                         (GSourceFunc) myreader_source_func,
 | 
					 | 
				
			||||||
                         this, NULL);
 | 
					 | 
				
			||||||
  myreader->id = g_source_attach ((GSource*)mysource, this->context);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  g_hash_table_insert (this->hash, GINT_TO_POINTER (fd), reader);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  gst_burst_cache_add_reader (this->cache, reader);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
gst_pinos_socket_sink_remove (GstPinosSocketSink * this, GSocket *socket, gboolean drain)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GstBurstCacheReader *reader;
 | 
					 | 
				
			||||||
  MyReader *myreader;
 | 
					 | 
				
			||||||
  int fd;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  fd = g_socket_get_fd (socket);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  myreader = g_hash_table_lookup (this->hash, GINT_TO_POINTER (fd));
 | 
					 | 
				
			||||||
  if (myreader == NULL)
 | 
					 | 
				
			||||||
    return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  g_hash_table_remove (this->hash, GINT_TO_POINTER (fd));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  reader = (GstBurstCacheReader *) myreader;
 | 
					 | 
				
			||||||
  gst_burst_cache_remove_reader (this->cache, reader, drain);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
gst_pinos_socket_sink_finalize (GObject * object)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GstPinosSocketSink *this = GST_PINOS_SOCKET_SINK (object);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  g_clear_pointer (&this->hash, g_hash_table_unref);
 | 
					 | 
				
			||||||
  g_clear_pointer (&this->cache, g_object_unref);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  G_OBJECT_CLASS (parent_class)->finalize (object);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
gst_pinos_socket_sink_class_init (GstPinosSocketSinkClass * klass)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  GObjectClass *gobject_class;
 | 
					 | 
				
			||||||
  GstElementClass *gstelement_class;
 | 
					 | 
				
			||||||
  GstBaseSinkClass *gstbasesink_class;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  gobject_class = (GObjectClass *) klass;
 | 
					 | 
				
			||||||
  gstelement_class = (GstElementClass *) klass;
 | 
					 | 
				
			||||||
  gstbasesink_class = (GstBaseSinkClass *) klass;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  gobject_class->finalize = gst_pinos_socket_sink_finalize;
 | 
					 | 
				
			||||||
  gobject_class->set_property = gst_pinos_socket_sink_set_property;
 | 
					 | 
				
			||||||
  gobject_class->get_property = gst_pinos_socket_sink_get_property;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  g_object_class_install_property (gobject_class, PROP_NUM_HANDLES,
 | 
					 | 
				
			||||||
      g_param_spec_uint ("num-handles", "Number of handles",
 | 
					 | 
				
			||||||
          "The current number of client handles",
 | 
					 | 
				
			||||||
          0, G_MAXUINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  gstelement_class->change_state = gst_pinos_socket_sink_change_state;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /**
 | 
					 | 
				
			||||||
   * GstPinosSocketSink::add:
 | 
					 | 
				
			||||||
   * @gstpinossocketsink: the pinossocketsink element to emit this signal on
 | 
					 | 
				
			||||||
   * @socket:             the socket to add to pinossocketsink
 | 
					 | 
				
			||||||
   *
 | 
					 | 
				
			||||||
   * Hand the given open file descriptor to pinossocketsink to write to.
 | 
					 | 
				
			||||||
   */
 | 
					 | 
				
			||||||
  gst_pinos_socket_sink_signals[SIGNAL_ADD] =
 | 
					 | 
				
			||||||
      g_signal_new ("add", G_TYPE_FROM_CLASS (klass),
 | 
					 | 
				
			||||||
      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
 | 
					 | 
				
			||||||
      G_STRUCT_OFFSET (GstPinosSocketSinkClass, add), NULL, NULL,
 | 
					 | 
				
			||||||
      g_cclosure_marshal_generic, G_TYPE_NONE, 1, G_TYPE_SOCKET);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /**
 | 
					 | 
				
			||||||
   * GstPinosSocketSink::remove:
 | 
					 | 
				
			||||||
   * @gstpinossocketsink: the pinossocketsink element to emit this signal on
 | 
					 | 
				
			||||||
   * @socket:             the socket to remove from pinossocketsink
 | 
					 | 
				
			||||||
   * @drain:              if pending data should be written first.
 | 
					 | 
				
			||||||
   *
 | 
					 | 
				
			||||||
   * Remove the given open file descriptor from pinossocketsink.
 | 
					 | 
				
			||||||
   */
 | 
					 | 
				
			||||||
  gst_pinos_socket_sink_signals[SIGNAL_REMOVE] =
 | 
					 | 
				
			||||||
      g_signal_new ("remove", G_TYPE_FROM_CLASS (klass),
 | 
					 | 
				
			||||||
      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
 | 
					 | 
				
			||||||
      G_STRUCT_OFFSET (GstPinosSocketSinkClass, remove), NULL, NULL,
 | 
					 | 
				
			||||||
      g_cclosure_marshal_generic, G_TYPE_NONE, 2, G_TYPE_SOCKET, G_TYPE_BOOLEAN);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  gst_element_class_set_static_metadata (gstelement_class,
 | 
					 | 
				
			||||||
      "Pinos FD sink", "Sink/Video",
 | 
					 | 
				
			||||||
      "Send data to pinos clients", "Wim Taymans <wim.taymans@gmail.com>");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  gst_element_class_add_pad_template (gstelement_class,
 | 
					 | 
				
			||||||
      gst_static_pad_template_get (&gst_pinos_socket_sink_template));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  gstbasesink_class->set_caps = gst_pinos_socket_sink_setcaps;
 | 
					 | 
				
			||||||
  gstbasesink_class->propose_allocation = gst_pinos_socket_sink_propose_allocation;
 | 
					 | 
				
			||||||
  gstbasesink_class->start = gst_pinos_socket_sink_start;
 | 
					 | 
				
			||||||
  gstbasesink_class->stop = gst_pinos_socket_sink_stop;
 | 
					 | 
				
			||||||
  gstbasesink_class->render = gst_pinos_socket_sink_render;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  klass->add = GST_DEBUG_FUNCPTR (gst_pinos_socket_sink_add);
 | 
					 | 
				
			||||||
  klass->remove = GST_DEBUG_FUNCPTR (gst_pinos_socket_sink_remove);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  fdids_quark = g_quark_from_static_string ("GstPinosSocketSinkFDIds");
 | 
					 | 
				
			||||||
  orig_buffer_quark = g_quark_from_static_string ("GstPinosSocketSinkOrigBuffer");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  GST_DEBUG_CATEGORY_INIT (pinos_socket_sink_debug, "pinossocketsink", 0,
 | 
					 | 
				
			||||||
      "Pinos Socket Sink");
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
gst_pinos_socket_sink_init (GstPinosSocketSink * this)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  this->hash = g_hash_table_new (g_direct_hash, g_direct_equal);
 | 
					 | 
				
			||||||
  this->cache = gst_burst_cache_new (sizeof (MyReader));
 | 
					 | 
				
			||||||
  this->allocator = gst_tmpfile_allocator_new ();
 | 
					 | 
				
			||||||
  this->fdmanager = pinos_fd_manager_get (PINOS_FD_MANAGER_DEFAULT);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,74 +0,0 @@
 | 
				
			||||||
/* GStreamer
 | 
					 | 
				
			||||||
 * Copyright (C) <2016> 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_SOCKET_SINK_H__
 | 
					 | 
				
			||||||
#define __GST_PINOS_SOCKET_SINK_H__
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <gio/gio.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <client/pinos.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <gst/gst.h>
 | 
					 | 
				
			||||||
#include <gst/base/gstbasesink.h>
 | 
					 | 
				
			||||||
#include <gst/gstburstcache.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
G_BEGIN_DECLS
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define GST_TYPE_PINOS_SOCKET_SINK            (gst_pinos_socket_sink_get_type())
 | 
					 | 
				
			||||||
#define GST_PINOS_SOCKET_SINK(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PINOS_SOCKET_SINK,GstPinosSocketSink))
 | 
					 | 
				
			||||||
#define GST_PINOS_SOCKET_SINK_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PINOS_SOCKET_SINK,GstPinosSocketSinkClass))
 | 
					 | 
				
			||||||
#define GST_IS_PINOS_SOCKET_SINK(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PINOS_SOCKET_SINK))
 | 
					 | 
				
			||||||
#define GST_IS_PINOS_SOCKET_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PINOS_SOCKET_SINK))
 | 
					 | 
				
			||||||
#define GST_PINOS_SOCKET_SINK_CAST(obj)       ((GstPinosSocketSink *) (obj))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct _GstPinosSocketSink GstPinosSocketSink;
 | 
					 | 
				
			||||||
typedef struct _GstPinosSocketSinkClass GstPinosSocketSinkClass;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * GstPinosSocketSink:
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Opaque data structure.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
struct _GstPinosSocketSink {
 | 
					 | 
				
			||||||
  GstBaseSink element;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  gboolean pinos_input;
 | 
					 | 
				
			||||||
  GstAllocator *allocator;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  GstBurstCache *cache;
 | 
					 | 
				
			||||||
  GHashTable *hash;
 | 
					 | 
				
			||||||
  GThread *thread;
 | 
					 | 
				
			||||||
  GMainLoop *loop;
 | 
					 | 
				
			||||||
  GMainContext *context;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  PinosFdManager *fdmanager;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct _GstPinosSocketSinkClass {
 | 
					 | 
				
			||||||
  GstBaseSinkClass parent_class;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  void          (*add)          (GstPinosSocketSink *sink, GSocket *socket);
 | 
					 | 
				
			||||||
  void          (*remove)       (GstPinosSocketSink *sink, GSocket *socket, gboolean drain);
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
GType gst_pinos_socket_sink_get_type (void);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
G_END_DECLS
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif /* __GST_PINOS_SOCKET_SINK_H__ */
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,144 +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.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define _GNU_SOURCE
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "gsttmpfileallocator.h"
 | 
					 | 
				
			||||||
#include <gst/allocators/gstfdmemory.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <fcntl.h>
 | 
					 | 
				
			||||||
#include <stdlib.h>
 | 
					 | 
				
			||||||
#include <string.h>
 | 
					 | 
				
			||||||
#include <unistd.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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;
 | 
					 | 
				
			||||||
  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 = gst_fd_allocator_alloc (allocator, 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;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  GST_OBJECT_FLAG_UNSET (allocator, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,37 +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_TMPFILE_ALLOCATOR_H_
 | 
					 | 
				
			||||||
#define _GST_TMPFILE_ALLOCATOR_H_
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <gst/gst.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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_ */
 | 
					 | 
				
			||||||
| 
						 | 
					@ -266,7 +266,7 @@ stop_pipeline (PinosSpaAlsaSink *sink)
 | 
				
			||||||
    pthread_join (priv->thread, NULL);
 | 
					    pthread_join (priv->thread, NULL);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  cmd.type = SPA_COMMAND_STOP;
 | 
					  cmd.type = SPA_COMMAND_PAUSE;
 | 
				
			||||||
  if ((res = spa_node_send_command (node->node, &cmd)) < 0)
 | 
					  if ((res = spa_node_send_command (node->node, &cmd)) < 0)
 | 
				
			||||||
    g_debug ("got error %d", res);
 | 
					    g_debug ("got error %d", res);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -238,7 +238,7 @@ stop_pipeline (PinosSpaV4l2Source *this)
 | 
				
			||||||
    pthread_join (priv->thread, NULL);
 | 
					    pthread_join (priv->thread, NULL);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  cmd.type = SPA_COMMAND_STOP;
 | 
					  cmd.type = SPA_COMMAND_PAUSE;
 | 
				
			||||||
  if ((res = spa_node_send_command (node->node, &cmd)) < 0)
 | 
					  if ((res = spa_node_send_command (node->node, &cmd)) < 0)
 | 
				
			||||||
    g_debug ("got error %d", res);
 | 
					    g_debug ("got error %d", res);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -252,6 +252,8 @@ again:
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  spa_debug_format (format);
 | 
					  spa_debug_format (format);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  spa_format_fixate (format);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if ((res = spa_node_port_set_format (priv->output_node, priv->output_port, 0, format)) < 0) {
 | 
					  if ((res = spa_node_port_set_format (priv->output_node, priv->output_port, 0, format)) < 0) {
 | 
				
			||||||
    g_warning ("error set format output: %d", res);
 | 
					    g_warning ("error set format output: %d", res);
 | 
				
			||||||
    return res;
 | 
					    return res;
 | 
				
			||||||
| 
						 | 
					@ -383,13 +385,13 @@ do_start (PinosLink *this)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static SpaResult
 | 
					static SpaResult
 | 
				
			||||||
do_stop (PinosLink *this)
 | 
					do_pause (PinosLink *this)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  PinosLinkPrivate *priv = this->priv;
 | 
					  PinosLinkPrivate *priv = this->priv;
 | 
				
			||||||
  SpaCommand cmd;
 | 
					  SpaCommand cmd;
 | 
				
			||||||
  SpaResult res;
 | 
					  SpaResult res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  cmd.type = SPA_COMMAND_STOP;
 | 
					  cmd.type = SPA_COMMAND_PAUSE;
 | 
				
			||||||
  if ((res = spa_node_send_command (priv->input_node, &cmd)) < 0)
 | 
					  if ((res = spa_node_send_command (priv->input_node, &cmd)) < 0)
 | 
				
			||||||
    g_warning ("got error %d", res);
 | 
					    g_warning ("got error %d", res);
 | 
				
			||||||
  if ((res = spa_node_send_command (priv->output_node, &cmd)) < 0)
 | 
					  if ((res = spa_node_send_command (priv->output_node, &cmd)) < 0)
 | 
				
			||||||
| 
						 | 
					@ -476,7 +478,7 @@ on_deactivate (PinosPort *port, gpointer user_data)
 | 
				
			||||||
  else
 | 
					  else
 | 
				
			||||||
    pinos_port_deactivate (priv->input);
 | 
					    pinos_port_deactivate (priv->input);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  do_stop (this);
 | 
					  do_pause (this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return TRUE;
 | 
					  return TRUE;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,8 +17,6 @@
 | 
				
			||||||
 * Boston, MA 02110-1301, USA.
 | 
					 * Boston, MA 02110-1301, USA.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <gst/gst.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <client/pinos.h>
 | 
					#include <client/pinos.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static GMainLoop *loop;
 | 
					static GMainLoop *loop;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -30,8 +30,8 @@ typedef struct _SpaCommand SpaCommand;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef enum {
 | 
					typedef enum {
 | 
				
			||||||
  SPA_COMMAND_INVALID                 =  0,
 | 
					  SPA_COMMAND_INVALID                 =  0,
 | 
				
			||||||
 | 
					  SPA_COMMAND_PAUSE,
 | 
				
			||||||
  SPA_COMMAND_START,
 | 
					  SPA_COMMAND_START,
 | 
				
			||||||
  SPA_COMMAND_STOP,
 | 
					 | 
				
			||||||
  SPA_COMMAND_FLUSH,
 | 
					  SPA_COMMAND_FLUSH,
 | 
				
			||||||
  SPA_COMMAND_DRAIN,
 | 
					  SPA_COMMAND_DRAIN,
 | 
				
			||||||
  SPA_COMMAND_MARKER,
 | 
					  SPA_COMMAND_MARKER,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -75,7 +75,7 @@ typedef enum {
 | 
				
			||||||
  SPA_CONTROL_CMD_SET_PROPERTY             = 35,
 | 
					  SPA_CONTROL_CMD_SET_PROPERTY             = 35,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  SPA_CONTROL_CMD_START                    = 36,
 | 
					  SPA_CONTROL_CMD_START                    = 36,
 | 
				
			||||||
  SPA_CONTROL_CMD_STOP                     = 37,
 | 
					  SPA_CONTROL_CMD_PAUSE                    = 37,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /* both */
 | 
					  /* both */
 | 
				
			||||||
  SPA_CONTROL_CMD_ADD_MEM                  = 64,
 | 
					  SPA_CONTROL_CMD_ADD_MEM                  = 64,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -89,6 +89,8 @@ typedef enum {
 | 
				
			||||||
  SPA_PROP_ID_MEDIA_CUSTOM_START = 200,
 | 
					  SPA_PROP_ID_MEDIA_CUSTOM_START = 200,
 | 
				
			||||||
} SpaFormatProps;
 | 
					} SpaFormatProps;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SpaResult  spa_format_fixate (SpaFormat *format);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef __cplusplus
 | 
					#ifdef __cplusplus
 | 
				
			||||||
}  /* extern "C" */
 | 
					}  /* extern "C" */
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -119,8 +119,6 @@ typedef struct {
 | 
				
			||||||
 * @flags: property flags
 | 
					 * @flags: property flags
 | 
				
			||||||
 * @type: property type
 | 
					 * @type: property type
 | 
				
			||||||
 * @max_size: maximum size of property value
 | 
					 * @max_size: maximum size of property value
 | 
				
			||||||
 * @default_size: size of default value
 | 
					 | 
				
			||||||
 * @default_value: default value of property
 | 
					 | 
				
			||||||
 * @range_type: type of the range values
 | 
					 * @range_type: type of the range values
 | 
				
			||||||
 * @n_range_values: number of elements in @range_values
 | 
					 * @n_range_values: number of elements in @range_values
 | 
				
			||||||
 * @range_values: array of possible values
 | 
					 * @range_values: array of possible values
 | 
				
			||||||
| 
						 | 
					@ -134,8 +132,6 @@ typedef struct {
 | 
				
			||||||
  SpaPropFlags              flags;
 | 
					  SpaPropFlags              flags;
 | 
				
			||||||
  SpaPropType               type;
 | 
					  SpaPropType               type;
 | 
				
			||||||
  size_t                    maxsize;
 | 
					  size_t                    maxsize;
 | 
				
			||||||
  size_t                    default_size;
 | 
					 | 
				
			||||||
  const void               *default_value;
 | 
					 | 
				
			||||||
  SpaPropRangeType          range_type;
 | 
					  SpaPropRangeType          range_type;
 | 
				
			||||||
  unsigned int              n_range_values;
 | 
					  unsigned int              n_range_values;
 | 
				
			||||||
  const SpaPropRangeInfo   *range_values;
 | 
					  const SpaPropRangeInfo   *range_values;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -140,49 +140,42 @@ static const SpaPropInfo raw_format_prop_info[] =
 | 
				
			||||||
  { SPA_PROP_ID_AUDIO_FORMAT,       "format", "The media format",
 | 
					  { SPA_PROP_ID_AUDIO_FORMAT,       "format", "The media format",
 | 
				
			||||||
                                    SPA_PROP_FLAG_READWRITE,
 | 
					                                    SPA_PROP_FLAG_READWRITE,
 | 
				
			||||||
                                    SPA_PROP_TYPE_UINT32, sizeof (uint32_t),
 | 
					                                    SPA_PROP_TYPE_UINT32, sizeof (uint32_t),
 | 
				
			||||||
                                    sizeof (uint32_t), &default_info.format,
 | 
					 | 
				
			||||||
                                    SPA_PROP_RANGE_TYPE_ENUM, SPA_N_ELEMENTS (format_format_range), format_format_range,
 | 
					                                    SPA_PROP_RANGE_TYPE_ENUM, SPA_N_ELEMENTS (format_format_range), format_format_range,
 | 
				
			||||||
                                    NULL,
 | 
					                                    NULL,
 | 
				
			||||||
                                    offsetof (SpaAudioRawFormat, info.format) },
 | 
					                                    offsetof (SpaAudioRawFormat, info.format) },
 | 
				
			||||||
  { SPA_PROP_ID_AUDIO_FLAGS,        "flags", "Sample Flags",
 | 
					  { SPA_PROP_ID_AUDIO_FLAGS,        "flags", "Sample Flags",
 | 
				
			||||||
                                    SPA_PROP_FLAG_READWRITE,
 | 
					                                    SPA_PROP_FLAG_READWRITE,
 | 
				
			||||||
                                    SPA_PROP_TYPE_UINT32, sizeof (uint32_t),
 | 
					                                    SPA_PROP_TYPE_UINT32, sizeof (uint32_t),
 | 
				
			||||||
                                    sizeof (uint32_t), &default_info.flags,
 | 
					 | 
				
			||||||
                                    SPA_PROP_RANGE_TYPE_FLAGS, SPA_N_ELEMENTS (flags_range), flags_range,
 | 
					                                    SPA_PROP_RANGE_TYPE_FLAGS, SPA_N_ELEMENTS (flags_range), flags_range,
 | 
				
			||||||
                                    NULL,
 | 
					                                    NULL,
 | 
				
			||||||
                                    offsetof (SpaAudioRawFormat, info.flags) },
 | 
					                                    offsetof (SpaAudioRawFormat, info.flags) },
 | 
				
			||||||
  { SPA_PROP_ID_AUDIO_LAYOUT,       "layout", "Sample Layout",
 | 
					  { SPA_PROP_ID_AUDIO_LAYOUT,       "layout", "Sample Layout",
 | 
				
			||||||
                                    SPA_PROP_FLAG_READWRITE,
 | 
					                                    SPA_PROP_FLAG_READWRITE,
 | 
				
			||||||
                                    SPA_PROP_TYPE_UINT32, sizeof (uint32_t),
 | 
					                                    SPA_PROP_TYPE_UINT32, sizeof (uint32_t),
 | 
				
			||||||
                                    sizeof (uint32_t), &default_info.layout,
 | 
					 | 
				
			||||||
                                    SPA_PROP_RANGE_TYPE_ENUM, SPA_N_ELEMENTS (layouts_range), layouts_range,
 | 
					                                    SPA_PROP_RANGE_TYPE_ENUM, SPA_N_ELEMENTS (layouts_range), layouts_range,
 | 
				
			||||||
                                    NULL,
 | 
					                                    NULL,
 | 
				
			||||||
                                    offsetof (SpaAudioRawFormat, info.layout) },
 | 
					                                    offsetof (SpaAudioRawFormat, info.layout) },
 | 
				
			||||||
  { SPA_PROP_ID_AUDIO_RATE,         "rate", "Audio sample rate",
 | 
					  { SPA_PROP_ID_AUDIO_RATE,         "rate", "Audio sample rate",
 | 
				
			||||||
                                    SPA_PROP_FLAG_READWRITE,
 | 
					                                    SPA_PROP_FLAG_READWRITE,
 | 
				
			||||||
                                    SPA_PROP_TYPE_UINT32, sizeof (uint32_t),
 | 
					                                    SPA_PROP_TYPE_UINT32, sizeof (uint32_t),
 | 
				
			||||||
                                    sizeof (uint32_t), &default_info.rate,
 | 
					 | 
				
			||||||
                                    SPA_PROP_RANGE_TYPE_MIN_MAX, 2, uint32_range,
 | 
					                                    SPA_PROP_RANGE_TYPE_MIN_MAX, 2, uint32_range,
 | 
				
			||||||
                                    NULL,
 | 
					                                    NULL,
 | 
				
			||||||
                                    offsetof (SpaAudioRawFormat, info.rate) },
 | 
					                                    offsetof (SpaAudioRawFormat, info.rate) },
 | 
				
			||||||
  { SPA_PROP_ID_AUDIO_CHANNELS,     "channels", "Audio channels",
 | 
					  { SPA_PROP_ID_AUDIO_CHANNELS,     "channels", "Audio channels",
 | 
				
			||||||
                                    SPA_PROP_FLAG_READWRITE,
 | 
					                                    SPA_PROP_FLAG_READWRITE,
 | 
				
			||||||
                                    SPA_PROP_TYPE_UINT32, sizeof (uint32_t),
 | 
					                                    SPA_PROP_TYPE_UINT32, sizeof (uint32_t),
 | 
				
			||||||
                                    sizeof (uint32_t), &default_info.channels,
 | 
					 | 
				
			||||||
                                    SPA_PROP_RANGE_TYPE_MIN_MAX, 2, uint32_range,
 | 
					                                    SPA_PROP_RANGE_TYPE_MIN_MAX, 2, uint32_range,
 | 
				
			||||||
                                    NULL,
 | 
					                                    NULL,
 | 
				
			||||||
                                    offsetof (SpaAudioRawFormat, info.channels) },
 | 
					                                    offsetof (SpaAudioRawFormat, info.channels) },
 | 
				
			||||||
  { SPA_PROP_ID_AUDIO_CHANNEL_MASK, "channel-mask", "Audio channel mask",
 | 
					  { SPA_PROP_ID_AUDIO_CHANNEL_MASK, "channel-mask", "Audio channel mask",
 | 
				
			||||||
                                    SPA_PROP_FLAG_READWRITE,
 | 
					                                    SPA_PROP_FLAG_READWRITE,
 | 
				
			||||||
                                    SPA_PROP_TYPE_BITMASK, sizeof (uint32_t),
 | 
					                                    SPA_PROP_TYPE_BITMASK, sizeof (uint32_t),
 | 
				
			||||||
                                    sizeof (uint32_t), &default_info.channel_mask,
 | 
					 | 
				
			||||||
                                    SPA_PROP_RANGE_TYPE_NONE, 0, NULL,
 | 
					                                    SPA_PROP_RANGE_TYPE_NONE, 0, NULL,
 | 
				
			||||||
                                    NULL,
 | 
					                                    NULL,
 | 
				
			||||||
                                    offsetof (SpaAudioRawFormat, info.channel_mask) },
 | 
					                                    offsetof (SpaAudioRawFormat, info.channel_mask) },
 | 
				
			||||||
  { SPA_PROP_ID_AUDIO_RAW_INFO,     "info", "the SpaAudioRawInfo structure",
 | 
					  { SPA_PROP_ID_AUDIO_RAW_INFO,     "info", "the SpaAudioRawInfo structure",
 | 
				
			||||||
                                    SPA_PROP_FLAG_READWRITE,
 | 
					                                    SPA_PROP_FLAG_READWRITE,
 | 
				
			||||||
                                    SPA_PROP_TYPE_POINTER, sizeof (SpaAudioRawInfo),
 | 
					                                    SPA_PROP_TYPE_POINTER, sizeof (SpaAudioRawInfo),
 | 
				
			||||||
                                    0, NULL,
 | 
					 | 
				
			||||||
                                    SPA_PROP_RANGE_TYPE_NONE, 0, NULL,
 | 
					                                    SPA_PROP_RANGE_TYPE_NONE, 0, NULL,
 | 
				
			||||||
                                    NULL,
 | 
					                                    NULL,
 | 
				
			||||||
                                    offsetof (SpaAudioRawFormat, info) },
 | 
					                                    offsetof (SpaAudioRawFormat, info) },
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -358,8 +358,6 @@ parse_props (SpaMemory *mem, void *p, off_t offset)
 | 
				
			||||||
      pi->name = SPA_MEMBER (tp, SPA_PTR_TO_INT (pi->name), char);
 | 
					      pi->name = SPA_MEMBER (tp, SPA_PTR_TO_INT (pi->name), char);
 | 
				
			||||||
    if (pi->description)
 | 
					    if (pi->description)
 | 
				
			||||||
      pi->description = SPA_MEMBER (tp, SPA_PTR_TO_INT (pi->description), char);
 | 
					      pi->description = SPA_MEMBER (tp, SPA_PTR_TO_INT (pi->description), char);
 | 
				
			||||||
    if (pi->default_value)
 | 
					 | 
				
			||||||
      pi->default_value = SPA_MEMBER (tp, SPA_PTR_TO_INT (pi->default_value), void);
 | 
					 | 
				
			||||||
    if (pi->range_values)
 | 
					    if (pi->range_values)
 | 
				
			||||||
      pi->range_values = SPA_MEMBER (tp, SPA_PTR_TO_INT (pi->range_values), SpaPropRangeInfo);
 | 
					      pi->range_values = SPA_MEMBER (tp, SPA_PTR_TO_INT (pi->range_values), SpaPropRangeInfo);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -528,7 +526,7 @@ spa_control_iter_parse_cmd (SpaControlIter *iter,
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case SPA_CONTROL_CMD_START:
 | 
					    case SPA_CONTROL_CMD_START:
 | 
				
			||||||
    case SPA_CONTROL_CMD_STOP:
 | 
					    case SPA_CONTROL_CMD_PAUSE:
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* bidirectional */
 | 
					    /* bidirectional */
 | 
				
			||||||
| 
						 | 
					@ -814,8 +812,8 @@ calc_props_len (const SpaProps *props)
 | 
				
			||||||
    len += sizeof (SpaPropInfo);
 | 
					    len += sizeof (SpaPropInfo);
 | 
				
			||||||
    len += pi->name ? strlen (pi->name) + 1 : 0;
 | 
					    len += pi->name ? strlen (pi->name) + 1 : 0;
 | 
				
			||||||
    len += pi->description ? strlen (pi->description) + 1 : 0;
 | 
					    len += pi->description ? strlen (pi->description) + 1 : 0;
 | 
				
			||||||
    /* for the value and the default value */
 | 
					    /* for the value */
 | 
				
			||||||
    len += pi->maxsize + pi->default_size;
 | 
					    len += pi->maxsize;
 | 
				
			||||||
    for (j = 0; j < pi->n_range_values; j++) {
 | 
					    for (j = 0; j < pi->n_range_values; j++) {
 | 
				
			||||||
      ri = (SpaPropRangeInfo *)&pi->range_values[j];
 | 
					      ri = (SpaPropRangeInfo *)&pi->range_values[j];
 | 
				
			||||||
      len += sizeof (SpaPropRangeInfo);
 | 
					      len += sizeof (SpaPropRangeInfo);
 | 
				
			||||||
| 
						 | 
					@ -879,13 +877,6 @@ write_props (void *p, const SpaProps *props, off_t offset)
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      pi->description = 0;
 | 
					      pi->description = 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (pi->default_value) {
 | 
					 | 
				
			||||||
      memcpy (p, pi->default_value, pi->default_size);
 | 
					 | 
				
			||||||
      pi->default_value = SPA_INT_TO_PTR (SPA_PTRDIFF (p, tp));
 | 
					 | 
				
			||||||
      p += pi->default_size;
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      pi->default_value = 0;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    for (j = 0; j < pi->n_range_values; j++) {
 | 
					    for (j = 0; j < pi->n_range_values; j++) {
 | 
				
			||||||
      if (ri->name) {
 | 
					      if (ri->name) {
 | 
				
			||||||
        slen = strlen (ri->name) + 1;
 | 
					        slen = strlen (ri->name) + 1;
 | 
				
			||||||
| 
						 | 
					@ -1157,7 +1148,7 @@ spa_control_builder_add_cmd (SpaControlBuilder *builder,
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case SPA_CONTROL_CMD_START:
 | 
					    case SPA_CONTROL_CMD_START:
 | 
				
			||||||
    case SPA_CONTROL_CMD_STOP:
 | 
					    case SPA_CONTROL_CMD_PAUSE:
 | 
				
			||||||
      p = builder_add_cmd (sb, cmd, 0);
 | 
					      p = builder_add_cmd (sb, cmd, 0);
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -328,12 +328,6 @@ spa_debug_props (const SpaProps *props, bool print_ranges)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fprintf (stderr, "%-23.23s %s. ", "", prop_type_names[info->type].CCName);
 | 
					    fprintf (stderr, "%-23.23s %s. ", "", prop_type_names[info->type].CCName);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fprintf (stderr, "Default: ");
 | 
					 | 
				
			||||||
    if (info->default_value)
 | 
					 | 
				
			||||||
      print_value (info, info->default_size, info->default_value);
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
      fprintf (stderr, "None");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    res = spa_props_get_prop (props, i, &value);
 | 
					    res = spa_props_get_prop (props, i, &value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fprintf (stderr, ". Current: ");
 | 
					    fprintf (stderr, ". Current: ");
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,10 +27,53 @@
 | 
				
			||||||
SpaResult
 | 
					SpaResult
 | 
				
			||||||
spa_format_to_string (const SpaFormat *format, char **result)
 | 
					spa_format_to_string (const SpaFormat *format, char **result)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  SpaResult res;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (format == NULL || result == NULL)
 | 
					  if (format == NULL || result == NULL)
 | 
				
			||||||
    return SPA_RESULT_INVALID_ARGUMENTS;
 | 
					    return SPA_RESULT_INVALID_ARGUMENTS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return SPA_RESULT_OK;
 | 
					  return SPA_RESULT_OK;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SpaResult
 | 
				
			||||||
 | 
					spa_format_fixate (SpaFormat *format)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  unsigned int i, j;
 | 
				
			||||||
 | 
					  SpaProps *props;
 | 
				
			||||||
 | 
					  uint32_t mask;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (format == NULL)
 | 
				
			||||||
 | 
					    return SPA_RESULT_INVALID_ARGUMENTS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  props = &format->props;
 | 
				
			||||||
 | 
					  mask = props->unset_mask;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for (i = 0; i < props->n_prop_info; i++) {
 | 
				
			||||||
 | 
					    if (mask & 1) {
 | 
				
			||||||
 | 
					      const SpaPropInfo *pi = &props->prop_info[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      switch (pi->range_type) {
 | 
				
			||||||
 | 
					        case SPA_PROP_RANGE_TYPE_NONE:
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
						case SPA_PROP_RANGE_TYPE_MIN_MAX:
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
						case SPA_PROP_RANGE_TYPE_STEP:
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
						case SPA_PROP_RANGE_TYPE_ENUM:
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          for (j = 0; j < pi->n_range_values; j++) {
 | 
				
			||||||
 | 
					            const SpaPropRangeInfo *ri = &pi->range_values[j];
 | 
				
			||||||
 | 
					            memcpy (SPA_MEMBER (props, pi->offset, void), ri->value, ri->size);
 | 
				
			||||||
 | 
					            props->unset_mask &= ~(1 << i);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
						case SPA_PROP_RANGE_TYPE_FLAGS:
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        default:
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    mask >>= 1;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return SPA_RESULT_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,7 @@ spalib_sources = ['audio-raw.c',
 | 
				
			||||||
                  'buffer.c',
 | 
					                  'buffer.c',
 | 
				
			||||||
                  'control.c',
 | 
					                  'control.c',
 | 
				
			||||||
                  'debug.c',
 | 
					                  'debug.c',
 | 
				
			||||||
 | 
					                  'format.c',
 | 
				
			||||||
                  'memory.c',
 | 
					                  'memory.c',
 | 
				
			||||||
                  'props.c',
 | 
					                  'props.c',
 | 
				
			||||||
                  'ringbuffer.c',
 | 
					                  'ringbuffer.c',
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -376,105 +376,90 @@ static const SpaPropInfo raw_format_prop_info[] =
 | 
				
			||||||
  { SPA_PROP_ID_VIDEO_FORMAT,       "format", "The media format",
 | 
					  { SPA_PROP_ID_VIDEO_FORMAT,       "format", "The media format",
 | 
				
			||||||
                                    SPA_PROP_FLAG_READWRITE,
 | 
					                                    SPA_PROP_FLAG_READWRITE,
 | 
				
			||||||
                                    SPA_PROP_TYPE_UINT32, sizeof (uint32_t),
 | 
					                                    SPA_PROP_TYPE_UINT32, sizeof (uint32_t),
 | 
				
			||||||
                                    sizeof (uint32_t), &default_info.format,
 | 
					 | 
				
			||||||
                                    SPA_PROP_RANGE_TYPE_ENUM, SPA_N_ELEMENTS (format_range), format_range,
 | 
					                                    SPA_PROP_RANGE_TYPE_ENUM, SPA_N_ELEMENTS (format_range), format_range,
 | 
				
			||||||
                                    NULL,
 | 
					                                    NULL,
 | 
				
			||||||
                                    offsetof (SpaVideoRawFormat, info.format) },
 | 
					                                    offsetof (SpaVideoRawFormat, info.format) },
 | 
				
			||||||
  { SPA_PROP_ID_VIDEO_SIZE,         "size", "Video size",
 | 
					  { SPA_PROP_ID_VIDEO_SIZE,         "size", "Video size",
 | 
				
			||||||
                                    SPA_PROP_FLAG_READWRITE,
 | 
					                                    SPA_PROP_FLAG_READWRITE,
 | 
				
			||||||
                                    SPA_PROP_TYPE_RECTANGLE, sizeof (SpaRectangle),
 | 
					                                    SPA_PROP_TYPE_RECTANGLE, sizeof (SpaRectangle),
 | 
				
			||||||
                                    sizeof (SpaRectangle), &default_info.size,
 | 
					 | 
				
			||||||
                                    SPA_PROP_RANGE_TYPE_MIN_MAX, 2, size_range,
 | 
					                                    SPA_PROP_RANGE_TYPE_MIN_MAX, 2, size_range,
 | 
				
			||||||
                                    NULL,
 | 
					                                    NULL,
 | 
				
			||||||
                                    offsetof (SpaVideoRawFormat, info.size) },
 | 
					                                    offsetof (SpaVideoRawFormat, info.size) },
 | 
				
			||||||
  { SPA_PROP_ID_VIDEO_FRAMERATE,    "framerate", "Video framerate",
 | 
					  { SPA_PROP_ID_VIDEO_FRAMERATE,    "framerate", "Video framerate",
 | 
				
			||||||
                                    SPA_PROP_FLAG_READWRITE,
 | 
					                                    SPA_PROP_FLAG_READWRITE,
 | 
				
			||||||
                                    SPA_PROP_TYPE_FRACTION, sizeof (SpaFraction),
 | 
					                                    SPA_PROP_TYPE_FRACTION, sizeof (SpaFraction),
 | 
				
			||||||
                                    sizeof (SpaFraction), &default_info.framerate,
 | 
					 | 
				
			||||||
                                    SPA_PROP_RANGE_TYPE_MIN_MAX, 2, framerate_range,
 | 
					                                    SPA_PROP_RANGE_TYPE_MIN_MAX, 2, framerate_range,
 | 
				
			||||||
                                    NULL,
 | 
					                                    NULL,
 | 
				
			||||||
                                    offsetof (SpaVideoRawFormat, info.framerate) },
 | 
					                                    offsetof (SpaVideoRawFormat, info.framerate) },
 | 
				
			||||||
  { SPA_PROP_ID_VIDEO_MAX_FRAMERATE, "max-framerate", "Video max framerate",
 | 
					  { SPA_PROP_ID_VIDEO_MAX_FRAMERATE, "max-framerate", "Video max framerate",
 | 
				
			||||||
                                    SPA_PROP_FLAG_READWRITE | SPA_PROP_FLAG_OPTIONAL,
 | 
					                                    SPA_PROP_FLAG_READWRITE | SPA_PROP_FLAG_OPTIONAL,
 | 
				
			||||||
                                    SPA_PROP_TYPE_FRACTION, sizeof (SpaFraction),
 | 
					                                    SPA_PROP_TYPE_FRACTION, sizeof (SpaFraction),
 | 
				
			||||||
                                    sizeof (SpaFraction), &default_info.max_framerate,
 | 
					 | 
				
			||||||
                                    SPA_PROP_RANGE_TYPE_MIN_MAX, 2, framerate_range,
 | 
					                                    SPA_PROP_RANGE_TYPE_MIN_MAX, 2, framerate_range,
 | 
				
			||||||
                                    NULL,
 | 
					                                    NULL,
 | 
				
			||||||
                                    offsetof (SpaVideoRawFormat, info.max_framerate) },
 | 
					                                    offsetof (SpaVideoRawFormat, info.max_framerate) },
 | 
				
			||||||
  { SPA_PROP_ID_VIDEO_VIEWS,        "views", "Video number of views",
 | 
					  { SPA_PROP_ID_VIDEO_VIEWS,        "views", "Video number of views",
 | 
				
			||||||
                                    SPA_PROP_FLAG_READWRITE | SPA_PROP_FLAG_OPTIONAL,
 | 
					                                    SPA_PROP_FLAG_READWRITE | SPA_PROP_FLAG_OPTIONAL,
 | 
				
			||||||
                                    SPA_PROP_TYPE_UINT32, sizeof (uint32_t),
 | 
					                                    SPA_PROP_TYPE_UINT32, sizeof (uint32_t),
 | 
				
			||||||
                                    sizeof (uint32_t), &default_info.views,
 | 
					 | 
				
			||||||
                                    SPA_PROP_RANGE_TYPE_MIN_MAX, 2, uint32_range,
 | 
					                                    SPA_PROP_RANGE_TYPE_MIN_MAX, 2, uint32_range,
 | 
				
			||||||
                                    NULL,
 | 
					                                    NULL,
 | 
				
			||||||
                                    offsetof (SpaVideoRawFormat, info.views) },
 | 
					                                    offsetof (SpaVideoRawFormat, info.views) },
 | 
				
			||||||
  { SPA_PROP_ID_VIDEO_INTERLACE_MODE, "interlace-mode", "Interlace mode",
 | 
					  { SPA_PROP_ID_VIDEO_INTERLACE_MODE, "interlace-mode", "Interlace mode",
 | 
				
			||||||
                                    SPA_PROP_FLAG_READWRITE | SPA_PROP_FLAG_OPTIONAL,
 | 
					                                    SPA_PROP_FLAG_READWRITE | SPA_PROP_FLAG_OPTIONAL,
 | 
				
			||||||
                                    SPA_PROP_TYPE_UINT32, sizeof (uint32_t),
 | 
					                                    SPA_PROP_TYPE_UINT32, sizeof (uint32_t),
 | 
				
			||||||
                                    sizeof (uint32_t), &default_info.interlace_mode,
 | 
					 | 
				
			||||||
                                    SPA_PROP_RANGE_TYPE_ENUM, SPA_N_ELEMENTS (interlace_mode_range), interlace_mode_range,
 | 
					                                    SPA_PROP_RANGE_TYPE_ENUM, SPA_N_ELEMENTS (interlace_mode_range), interlace_mode_range,
 | 
				
			||||||
                                    NULL,
 | 
					                                    NULL,
 | 
				
			||||||
                                    offsetof (SpaVideoRawFormat, info.interlace_mode) },
 | 
					                                    offsetof (SpaVideoRawFormat, info.interlace_mode) },
 | 
				
			||||||
  { SPA_PROP_ID_VIDEO_PIXEL_ASPECT_RATIO, "pixel-aspect-ratio", "Video pixel aspect ratio",
 | 
					  { SPA_PROP_ID_VIDEO_PIXEL_ASPECT_RATIO, "pixel-aspect-ratio", "Video pixel aspect ratio",
 | 
				
			||||||
                                    SPA_PROP_FLAG_READWRITE | SPA_PROP_FLAG_OPTIONAL,
 | 
					                                    SPA_PROP_FLAG_READWRITE | SPA_PROP_FLAG_OPTIONAL,
 | 
				
			||||||
                                    SPA_PROP_TYPE_FRACTION, sizeof (SpaFraction),
 | 
					                                    SPA_PROP_TYPE_FRACTION, sizeof (SpaFraction),
 | 
				
			||||||
                                    sizeof (SpaFraction), &default_info.pixel_aspect_ratio,
 | 
					 | 
				
			||||||
                                    SPA_PROP_RANGE_TYPE_MIN_MAX, 2, framerate_range,
 | 
					                                    SPA_PROP_RANGE_TYPE_MIN_MAX, 2, framerate_range,
 | 
				
			||||||
                                    NULL,
 | 
					                                    NULL,
 | 
				
			||||||
                                    offsetof (SpaVideoRawFormat, info.pixel_aspect_ratio) },
 | 
					                                    offsetof (SpaVideoRawFormat, info.pixel_aspect_ratio) },
 | 
				
			||||||
  { SPA_PROP_ID_VIDEO_MULTIVIEW_MODE, "multiview-mode", "Multiview mode",
 | 
					  { SPA_PROP_ID_VIDEO_MULTIVIEW_MODE, "multiview-mode", "Multiview mode",
 | 
				
			||||||
                                    SPA_PROP_FLAG_READWRITE | SPA_PROP_FLAG_OPTIONAL,
 | 
					                                    SPA_PROP_FLAG_READWRITE | SPA_PROP_FLAG_OPTIONAL,
 | 
				
			||||||
                                    SPA_PROP_TYPE_UINT32, sizeof (uint32_t),
 | 
					                                    SPA_PROP_TYPE_UINT32, sizeof (uint32_t),
 | 
				
			||||||
                                    sizeof (uint32_t), &default_info.multiview_mode,
 | 
					 | 
				
			||||||
                                    SPA_PROP_RANGE_TYPE_ENUM, SPA_N_ELEMENTS (multiview_mode_range), multiview_mode_range,
 | 
					                                    SPA_PROP_RANGE_TYPE_ENUM, SPA_N_ELEMENTS (multiview_mode_range), multiview_mode_range,
 | 
				
			||||||
                                    NULL,
 | 
					                                    NULL,
 | 
				
			||||||
                                    offsetof (SpaVideoRawFormat, info.multiview_mode) },
 | 
					                                    offsetof (SpaVideoRawFormat, info.multiview_mode) },
 | 
				
			||||||
  { SPA_PROP_ID_VIDEO_MULTIVIEW_FLAGS, "multiview-flags", "Multiview flags",
 | 
					  { SPA_PROP_ID_VIDEO_MULTIVIEW_FLAGS, "multiview-flags", "Multiview flags",
 | 
				
			||||||
                                    SPA_PROP_FLAG_READWRITE | SPA_PROP_FLAG_OPTIONAL,
 | 
					                                    SPA_PROP_FLAG_READWRITE | SPA_PROP_FLAG_OPTIONAL,
 | 
				
			||||||
                                    SPA_PROP_TYPE_UINT32, sizeof (uint32_t),
 | 
					                                    SPA_PROP_TYPE_UINT32, sizeof (uint32_t),
 | 
				
			||||||
                                    sizeof (uint32_t), &default_info.multiview_flags,
 | 
					 | 
				
			||||||
                                    SPA_PROP_RANGE_TYPE_FLAGS, SPA_N_ELEMENTS (multiview_flags_range), multiview_flags_range,
 | 
					                                    SPA_PROP_RANGE_TYPE_FLAGS, SPA_N_ELEMENTS (multiview_flags_range), multiview_flags_range,
 | 
				
			||||||
                                    NULL,
 | 
					                                    NULL,
 | 
				
			||||||
                                    offsetof (SpaVideoRawFormat, info.multiview_flags) },
 | 
					                                    offsetof (SpaVideoRawFormat, info.multiview_flags) },
 | 
				
			||||||
  { SPA_PROP_ID_VIDEO_CHROMA_SITE,  "chroma-site", "Chroma site",
 | 
					  { SPA_PROP_ID_VIDEO_CHROMA_SITE,  "chroma-site", "Chroma site",
 | 
				
			||||||
                                    SPA_PROP_FLAG_READWRITE | SPA_PROP_FLAG_OPTIONAL,
 | 
					                                    SPA_PROP_FLAG_READWRITE | SPA_PROP_FLAG_OPTIONAL,
 | 
				
			||||||
                                    SPA_PROP_TYPE_UINT32, sizeof (uint32_t),
 | 
					                                    SPA_PROP_TYPE_UINT32, sizeof (uint32_t),
 | 
				
			||||||
                                    sizeof (uint32_t), &default_info.chroma_site,
 | 
					 | 
				
			||||||
                                    SPA_PROP_RANGE_TYPE_FLAGS, SPA_N_ELEMENTS (chroma_site_range), chroma_site_range,
 | 
					                                    SPA_PROP_RANGE_TYPE_FLAGS, SPA_N_ELEMENTS (chroma_site_range), chroma_site_range,
 | 
				
			||||||
                                    NULL,
 | 
					                                    NULL,
 | 
				
			||||||
                                    offsetof (SpaVideoRawFormat, info.chroma_site) },
 | 
					                                    offsetof (SpaVideoRawFormat, info.chroma_site) },
 | 
				
			||||||
  { SPA_PROP_ID_VIDEO_COLOR_RANGE,  "color-range", "Color range",
 | 
					  { SPA_PROP_ID_VIDEO_COLOR_RANGE,  "color-range", "Color range",
 | 
				
			||||||
                                    SPA_PROP_FLAG_READWRITE | SPA_PROP_FLAG_OPTIONAL,
 | 
					                                    SPA_PROP_FLAG_READWRITE | SPA_PROP_FLAG_OPTIONAL,
 | 
				
			||||||
                                    SPA_PROP_TYPE_UINT32, sizeof (uint32_t),
 | 
					                                    SPA_PROP_TYPE_UINT32, sizeof (uint32_t),
 | 
				
			||||||
                                    sizeof (uint32_t), &default_info.color_range,
 | 
					 | 
				
			||||||
                                    SPA_PROP_RANGE_TYPE_ENUM, SPA_N_ELEMENTS (color_range_range), color_range_range,
 | 
					                                    SPA_PROP_RANGE_TYPE_ENUM, SPA_N_ELEMENTS (color_range_range), color_range_range,
 | 
				
			||||||
                                    NULL,
 | 
					                                    NULL,
 | 
				
			||||||
                                    offsetof (SpaVideoRawFormat, info.color_range) },
 | 
					                                    offsetof (SpaVideoRawFormat, info.color_range) },
 | 
				
			||||||
  { SPA_PROP_ID_VIDEO_COLOR_MATRIX,  "color-matrix", "Color matrix",
 | 
					  { SPA_PROP_ID_VIDEO_COLOR_MATRIX,  "color-matrix", "Color matrix",
 | 
				
			||||||
                                    SPA_PROP_FLAG_READWRITE | SPA_PROP_FLAG_OPTIONAL,
 | 
					                                    SPA_PROP_FLAG_READWRITE | SPA_PROP_FLAG_OPTIONAL,
 | 
				
			||||||
                                    SPA_PROP_TYPE_UINT32, sizeof (uint32_t),
 | 
					                                    SPA_PROP_TYPE_UINT32, sizeof (uint32_t),
 | 
				
			||||||
                                    sizeof (uint32_t), &default_info.color_matrix,
 | 
					 | 
				
			||||||
                                    SPA_PROP_RANGE_TYPE_ENUM, SPA_N_ELEMENTS (color_matrix_range), color_matrix_range,
 | 
					                                    SPA_PROP_RANGE_TYPE_ENUM, SPA_N_ELEMENTS (color_matrix_range), color_matrix_range,
 | 
				
			||||||
                                    NULL,
 | 
					                                    NULL,
 | 
				
			||||||
                                    offsetof (SpaVideoRawFormat, info.color_matrix) },
 | 
					                                    offsetof (SpaVideoRawFormat, info.color_matrix) },
 | 
				
			||||||
  { SPA_PROP_ID_VIDEO_TRANSFER_FUNCTION,  "transfer-function", "Transfer function",
 | 
					  { SPA_PROP_ID_VIDEO_TRANSFER_FUNCTION,  "transfer-function", "Transfer function",
 | 
				
			||||||
                                    SPA_PROP_FLAG_READWRITE | SPA_PROP_FLAG_OPTIONAL,
 | 
					                                    SPA_PROP_FLAG_READWRITE | SPA_PROP_FLAG_OPTIONAL,
 | 
				
			||||||
                                    SPA_PROP_TYPE_UINT32, sizeof (uint32_t),
 | 
					                                    SPA_PROP_TYPE_UINT32, sizeof (uint32_t),
 | 
				
			||||||
                                    sizeof (uint32_t), &default_info.transfer_function,
 | 
					 | 
				
			||||||
                                    SPA_PROP_RANGE_TYPE_ENUM, SPA_N_ELEMENTS (transfer_function_range), transfer_function_range,
 | 
					                                    SPA_PROP_RANGE_TYPE_ENUM, SPA_N_ELEMENTS (transfer_function_range), transfer_function_range,
 | 
				
			||||||
                                    NULL,
 | 
					                                    NULL,
 | 
				
			||||||
                                    offsetof (SpaVideoRawFormat, info.transfer_function) },
 | 
					                                    offsetof (SpaVideoRawFormat, info.transfer_function) },
 | 
				
			||||||
  { SPA_PROP_ID_VIDEO_COLOR_PRIMARIES,  "color-primaries", "Color primaries",
 | 
					  { SPA_PROP_ID_VIDEO_COLOR_PRIMARIES,  "color-primaries", "Color primaries",
 | 
				
			||||||
                                    SPA_PROP_FLAG_READWRITE | SPA_PROP_FLAG_OPTIONAL,
 | 
					                                    SPA_PROP_FLAG_READWRITE | SPA_PROP_FLAG_OPTIONAL,
 | 
				
			||||||
                                    SPA_PROP_TYPE_UINT32, sizeof (uint32_t),
 | 
					                                    SPA_PROP_TYPE_UINT32, sizeof (uint32_t),
 | 
				
			||||||
                                    sizeof (uint32_t), &default_info.color_primaries,
 | 
					 | 
				
			||||||
                                    SPA_PROP_RANGE_TYPE_ENUM, SPA_N_ELEMENTS (color_primaries_range), color_primaries_range,
 | 
					                                    SPA_PROP_RANGE_TYPE_ENUM, SPA_N_ELEMENTS (color_primaries_range), color_primaries_range,
 | 
				
			||||||
                                    NULL,
 | 
					                                    NULL,
 | 
				
			||||||
                                    offsetof (SpaVideoRawFormat, info.color_primaries) },
 | 
					                                    offsetof (SpaVideoRawFormat, info.color_primaries) },
 | 
				
			||||||
  { SPA_PROP_ID_VIDEO_RAW_INFO,     "info", "the SpaVideoRawInfo structure",
 | 
					  { SPA_PROP_ID_VIDEO_RAW_INFO,     "info", "the SpaVideoRawInfo structure",
 | 
				
			||||||
                                    SPA_PROP_FLAG_READWRITE | SPA_PROP_FLAG_OPTIONAL,
 | 
					                                    SPA_PROP_FLAG_READWRITE | SPA_PROP_FLAG_OPTIONAL,
 | 
				
			||||||
                                    SPA_PROP_TYPE_POINTER, sizeof (SpaVideoRawInfo),
 | 
					                                    SPA_PROP_TYPE_POINTER, sizeof (SpaVideoRawInfo),
 | 
				
			||||||
                                    0, NULL,
 | 
					 | 
				
			||||||
                                    SPA_PROP_RANGE_TYPE_NONE, 0, NULL,
 | 
					                                    SPA_PROP_RANGE_TYPE_NONE, 0, NULL,
 | 
				
			||||||
                                    NULL,
 | 
					                                    NULL,
 | 
				
			||||||
                                    offsetof (SpaVideoRawFormat, info) },
 | 
					                                    offsetof (SpaVideoRawFormat, info) },
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -126,42 +126,36 @@ static const SpaPropInfo prop_info[] =
 | 
				
			||||||
  { PROP_ID_DEVICE,            "device", "ALSA device, as defined in an asound configuration file",
 | 
					  { PROP_ID_DEVICE,            "device", "ALSA device, as defined in an asound configuration file",
 | 
				
			||||||
                                SPA_PROP_FLAG_READWRITE,
 | 
					                                SPA_PROP_FLAG_READWRITE,
 | 
				
			||||||
                                SPA_PROP_TYPE_STRING, 63,
 | 
					                                SPA_PROP_TYPE_STRING, 63,
 | 
				
			||||||
                                strlen (default_device)+1, default_device,
 | 
					 | 
				
			||||||
                                SPA_PROP_RANGE_TYPE_NONE, 0, NULL,
 | 
					                                SPA_PROP_RANGE_TYPE_NONE, 0, NULL,
 | 
				
			||||||
                                NULL,
 | 
					                                NULL,
 | 
				
			||||||
                                offsetof (SpaALSASinkProps, device) },
 | 
					                                offsetof (SpaALSASinkProps, device) },
 | 
				
			||||||
  { PROP_ID_DEVICE_NAME,       "device-name", "Human-readable name of the sound device",
 | 
					  { PROP_ID_DEVICE_NAME,       "device-name", "Human-readable name of the sound device",
 | 
				
			||||||
                                SPA_PROP_FLAG_READABLE,
 | 
					                                SPA_PROP_FLAG_READABLE,
 | 
				
			||||||
                                SPA_PROP_TYPE_STRING, 127,
 | 
					                                SPA_PROP_TYPE_STRING, 127,
 | 
				
			||||||
                                0, NULL,
 | 
					 | 
				
			||||||
                                SPA_PROP_RANGE_TYPE_NONE, 0, NULL,
 | 
					                                SPA_PROP_RANGE_TYPE_NONE, 0, NULL,
 | 
				
			||||||
                                NULL,
 | 
					                                NULL,
 | 
				
			||||||
                                offsetof (SpaALSASinkProps, device_name) },
 | 
					                                offsetof (SpaALSASinkProps, device_name) },
 | 
				
			||||||
  { PROP_ID_CARD_NAME,         "card-name", "Human-readable name of the sound card",
 | 
					  { PROP_ID_CARD_NAME,         "card-name", "Human-readable name of the sound card",
 | 
				
			||||||
                                SPA_PROP_FLAG_READABLE,
 | 
					                                SPA_PROP_FLAG_READABLE,
 | 
				
			||||||
                                SPA_PROP_TYPE_STRING, 127,
 | 
					                                SPA_PROP_TYPE_STRING, 127,
 | 
				
			||||||
                                0, NULL,
 | 
					 | 
				
			||||||
                                SPA_PROP_RANGE_TYPE_NONE, 0, NULL,
 | 
					                                SPA_PROP_RANGE_TYPE_NONE, 0, NULL,
 | 
				
			||||||
                                NULL,
 | 
					                                NULL,
 | 
				
			||||||
                                offsetof (SpaALSASinkProps, card_name) },
 | 
					                                offsetof (SpaALSASinkProps, card_name) },
 | 
				
			||||||
  { PROP_ID_BUFFER_TIME,       "buffer-time", "The total size of the buffer in time",
 | 
					  { PROP_ID_BUFFER_TIME,       "buffer-time", "The total size of the buffer in time",
 | 
				
			||||||
                                SPA_PROP_FLAG_READWRITE,
 | 
					                                SPA_PROP_FLAG_READWRITE,
 | 
				
			||||||
                                SPA_PROP_TYPE_UINT32, sizeof (uint32_t),
 | 
					                                SPA_PROP_TYPE_UINT32, sizeof (uint32_t),
 | 
				
			||||||
                                sizeof (uint32_t), &default_buffer_time,
 | 
					 | 
				
			||||||
                                SPA_PROP_RANGE_TYPE_MIN_MAX, 2, uint32_range,
 | 
					                                SPA_PROP_RANGE_TYPE_MIN_MAX, 2, uint32_range,
 | 
				
			||||||
                                NULL,
 | 
					                                NULL,
 | 
				
			||||||
                                offsetof (SpaALSASinkProps, buffer_time) },
 | 
					                                offsetof (SpaALSASinkProps, buffer_time) },
 | 
				
			||||||
  { PROP_ID_PERIOD_TIME,       "period-time", "The size of a period in time",
 | 
					  { PROP_ID_PERIOD_TIME,       "period-time", "The size of a period in time",
 | 
				
			||||||
                                SPA_PROP_FLAG_READWRITE,
 | 
					                                SPA_PROP_FLAG_READWRITE,
 | 
				
			||||||
                                SPA_PROP_TYPE_UINT32, sizeof (uint32_t),
 | 
					                                SPA_PROP_TYPE_UINT32, sizeof (uint32_t),
 | 
				
			||||||
                                sizeof (uint32_t), &default_period_time,
 | 
					 | 
				
			||||||
                                SPA_PROP_RANGE_TYPE_MIN_MAX, 2, uint32_range,
 | 
					                                SPA_PROP_RANGE_TYPE_MIN_MAX, 2, uint32_range,
 | 
				
			||||||
                                NULL,
 | 
					                                NULL,
 | 
				
			||||||
                                offsetof (SpaALSASinkProps, period_time) },
 | 
					                                offsetof (SpaALSASinkProps, period_time) },
 | 
				
			||||||
  { PROP_ID_PERIOD_EVENT,      "period-event", "Generate an event each period",
 | 
					  { PROP_ID_PERIOD_EVENT,      "period-event", "Generate an event each period",
 | 
				
			||||||
                                SPA_PROP_FLAG_READWRITE,
 | 
					                                SPA_PROP_FLAG_READWRITE,
 | 
				
			||||||
                                SPA_PROP_TYPE_BOOL, sizeof (bool),
 | 
					                                SPA_PROP_TYPE_BOOL, sizeof (bool),
 | 
				
			||||||
                                sizeof (bool), &default_period_event,
 | 
					 | 
				
			||||||
                                SPA_PROP_RANGE_TYPE_NONE, 0, NULL,
 | 
					                                SPA_PROP_RANGE_TYPE_NONE, 0, NULL,
 | 
				
			||||||
                                NULL,
 | 
					                                NULL,
 | 
				
			||||||
                                offsetof (SpaALSASinkProps, period_event) },
 | 
					                                offsetof (SpaALSASinkProps, period_event) },
 | 
				
			||||||
| 
						 | 
					@ -239,7 +233,7 @@ spa_alsa_sink_node_send_command (SpaNode       *node,
 | 
				
			||||||
        this->event_cb (node, &event, this->user_data);
 | 
					        this->event_cb (node, &event, this->user_data);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case SPA_COMMAND_STOP:
 | 
					    case SPA_COMMAND_PAUSE:
 | 
				
			||||||
      spa_alsa_stop (this);
 | 
					      spa_alsa_stop (this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (this->event_cb) {
 | 
					      if (this->event_cb) {
 | 
				
			||||||
| 
						 | 
					@ -250,7 +244,7 @@ spa_alsa_sink_node_send_command (SpaNode       *node,
 | 
				
			||||||
        event.port_id = -1;
 | 
					        event.port_id = -1;
 | 
				
			||||||
        event.data = ≻
 | 
					        event.data = ≻
 | 
				
			||||||
        event.size = sizeof (sc);
 | 
					        event.size = sizeof (sc);
 | 
				
			||||||
        sc.state = SPA_NODE_STATE_STREAMING;
 | 
					        sc.state = SPA_NODE_STATE_PAUSED;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this->event_cb (node, &event, this->user_data);
 | 
					        this->event_cb (node, &event, this->user_data);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -161,7 +161,7 @@ spa_audiomixer_node_send_command (SpaNode       *node,
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case SPA_COMMAND_STOP:
 | 
					    case SPA_COMMAND_PAUSE:
 | 
				
			||||||
      if (this->event_cb) {
 | 
					      if (this->event_cb) {
 | 
				
			||||||
        SpaEvent event;
 | 
					        SpaEvent event;
 | 
				
			||||||
        SpaEventStateChange sc;
 | 
					        SpaEventStateChange sc;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -87,21 +87,18 @@ static const SpaPropInfo prop_info[] =
 | 
				
			||||||
  { PROP_ID_WAVE,              "wave", "Oscillator waveform",
 | 
					  { PROP_ID_WAVE,              "wave", "Oscillator waveform",
 | 
				
			||||||
                               SPA_PROP_FLAG_READWRITE,
 | 
					                               SPA_PROP_FLAG_READWRITE,
 | 
				
			||||||
                               SPA_PROP_TYPE_UINT32, sizeof (uint32_t),
 | 
					                               SPA_PROP_TYPE_UINT32, sizeof (uint32_t),
 | 
				
			||||||
                               sizeof (uint32_t), &default_wave,
 | 
					 | 
				
			||||||
                               SPA_PROP_RANGE_TYPE_ENUM, SPA_N_ELEMENTS (wave_range), wave_range,
 | 
					                               SPA_PROP_RANGE_TYPE_ENUM, SPA_N_ELEMENTS (wave_range), wave_range,
 | 
				
			||||||
                               NULL,
 | 
					                               NULL,
 | 
				
			||||||
                               offsetof (SpaAudioTestSrcProps, wave) },
 | 
					                               offsetof (SpaAudioTestSrcProps, wave) },
 | 
				
			||||||
  { PROP_ID_FREQ,              "freq", "Frequency of test signal. The sample rate needs to be at least 4 times higher",
 | 
					  { PROP_ID_FREQ,              "freq", "Frequency of test signal. The sample rate needs to be at least 4 times higher",
 | 
				
			||||||
                               SPA_PROP_FLAG_READWRITE,
 | 
					                               SPA_PROP_FLAG_READWRITE,
 | 
				
			||||||
                               SPA_PROP_TYPE_DOUBLE, sizeof (double),
 | 
					                               SPA_PROP_TYPE_DOUBLE, sizeof (double),
 | 
				
			||||||
                               sizeof (double), &default_freq,
 | 
					 | 
				
			||||||
                               SPA_PROP_RANGE_TYPE_MIN_MAX, 2, freq_range,
 | 
					                               SPA_PROP_RANGE_TYPE_MIN_MAX, 2, freq_range,
 | 
				
			||||||
                               NULL,
 | 
					                               NULL,
 | 
				
			||||||
                               offsetof (SpaAudioTestSrcProps, freq) },
 | 
					                               offsetof (SpaAudioTestSrcProps, freq) },
 | 
				
			||||||
  { PROP_ID_VOLUME,            "volume", "The Volume factor",
 | 
					  { PROP_ID_VOLUME,            "volume", "The Volume factor",
 | 
				
			||||||
                               SPA_PROP_FLAG_READWRITE,
 | 
					                               SPA_PROP_FLAG_READWRITE,
 | 
				
			||||||
                               SPA_PROP_TYPE_DOUBLE, sizeof (double),
 | 
					                               SPA_PROP_TYPE_DOUBLE, sizeof (double),
 | 
				
			||||||
                               sizeof (double), &default_volume,
 | 
					 | 
				
			||||||
                               SPA_PROP_RANGE_TYPE_MIN_MAX, 2, volume_range,
 | 
					                               SPA_PROP_RANGE_TYPE_MIN_MAX, 2, volume_range,
 | 
				
			||||||
                               NULL,
 | 
					                               NULL,
 | 
				
			||||||
                               offsetof (SpaAudioTestSrcProps, volume) },
 | 
					                               offsetof (SpaAudioTestSrcProps, volume) },
 | 
				
			||||||
| 
						 | 
					@ -185,7 +182,7 @@ spa_audiotestsrc_node_send_command (SpaNode       *node,
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case SPA_COMMAND_STOP:
 | 
					    case SPA_COMMAND_PAUSE:
 | 
				
			||||||
      if (this->event_cb) {
 | 
					      if (this->event_cb) {
 | 
				
			||||||
        SpaEvent event;
 | 
					        SpaEvent event;
 | 
				
			||||||
        SpaEventStateChange sc;
 | 
					        SpaEventStateChange sc;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -156,7 +156,7 @@ spa_ffmpeg_dec_node_send_command (SpaNode       *node,
 | 
				
			||||||
        this->event_cb (node, &event, this->user_data);
 | 
					        this->event_cb (node, &event, this->user_data);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case SPA_COMMAND_STOP:
 | 
					    case SPA_COMMAND_PAUSE:
 | 
				
			||||||
      if (this->event_cb) {
 | 
					      if (this->event_cb) {
 | 
				
			||||||
        SpaEvent event;
 | 
					        SpaEvent event;
 | 
				
			||||||
        SpaEventStateChange sc;
 | 
					        SpaEventStateChange sc;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -156,7 +156,7 @@ spa_ffmpeg_enc_node_send_command (SpaNode       *node,
 | 
				
			||||||
        this->event_cb (node, &event, this->user_data);
 | 
					        this->event_cb (node, &event, this->user_data);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case SPA_COMMAND_STOP:
 | 
					    case SPA_COMMAND_PAUSE:
 | 
				
			||||||
      if (this->event_cb) {
 | 
					      if (this->event_cb) {
 | 
				
			||||||
        SpaEvent event;
 | 
					        SpaEvent event;
 | 
				
			||||||
        SpaEventStateChange sc;
 | 
					        SpaEventStateChange sc;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -91,7 +91,6 @@ static const SpaPropInfo prop_info[PROP_ID_LAST] =
 | 
				
			||||||
  { PROP_ID_SOCKET,            "socket", "The Socket factor",
 | 
					  { PROP_ID_SOCKET,            "socket", "The Socket factor",
 | 
				
			||||||
                               SPA_PROP_FLAG_READWRITE,
 | 
					                               SPA_PROP_FLAG_READWRITE,
 | 
				
			||||||
                               SPA_PROP_TYPE_INT, sizeof (int),
 | 
					                               SPA_PROP_TYPE_INT, sizeof (int),
 | 
				
			||||||
                               sizeof (int), NULL,
 | 
					 | 
				
			||||||
                               SPA_PROP_RANGE_TYPE_NONE, 0, NULL,
 | 
					                               SPA_PROP_RANGE_TYPE_NONE, 0, NULL,
 | 
				
			||||||
                               NULL,
 | 
					                               NULL,
 | 
				
			||||||
                               offsetof (SpaProxyProps, socketfd) },
 | 
					                               offsetof (SpaProxyProps, socketfd) },
 | 
				
			||||||
| 
						 | 
					@ -234,7 +233,7 @@ spa_proxy_node_send_command (SpaNode       *node,
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case SPA_COMMAND_STOP:
 | 
					    case SPA_COMMAND_PAUSE:
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      SpaControlBuilder builder;
 | 
					      SpaControlBuilder builder;
 | 
				
			||||||
      SpaControl control;
 | 
					      SpaControl control;
 | 
				
			||||||
| 
						 | 
					@ -242,7 +241,7 @@ spa_proxy_node_send_command (SpaNode       *node,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      /* send start */
 | 
					      /* send start */
 | 
				
			||||||
      spa_control_builder_init_into (&builder, buf, sizeof (buf), NULL, 0);
 | 
					      spa_control_builder_init_into (&builder, buf, sizeof (buf), NULL, 0);
 | 
				
			||||||
      spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_STOP, NULL);
 | 
					      spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_PAUSE, NULL);
 | 
				
			||||||
      spa_control_builder_end (&builder, &control);
 | 
					      spa_control_builder_end (&builder, &control);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if ((res = spa_control_write (&control, this->fds[0].fd)) < 0)
 | 
					      if ((res = spa_control_write (&control, this->fds[0].fd)) < 0)
 | 
				
			||||||
| 
						 | 
					@ -342,13 +341,16 @@ do_update_port (SpaProxy                *this,
 | 
				
			||||||
  SpaEvent event;
 | 
					  SpaEvent event;
 | 
				
			||||||
  SpaProxyPort *port;
 | 
					  SpaProxyPort *port;
 | 
				
			||||||
  SpaEventPortAdded pa;
 | 
					  SpaEventPortAdded pa;
 | 
				
			||||||
 | 
					  unsigned int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  port = &this->ports[pu->port_id];
 | 
					  port = &this->ports[pu->port_id];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (pu->change_mask & SPA_CONTROL_CMD_PORT_UPDATE_POSSIBLE_FORMATS) {
 | 
					  if (pu->change_mask & SPA_CONTROL_CMD_PORT_UPDATE_POSSIBLE_FORMATS) {
 | 
				
			||||||
    port->n_formats = pu->n_possible_formats;
 | 
					    port->n_formats = pu->n_possible_formats;
 | 
				
			||||||
    port->formats = pu->possible_formats;
 | 
					    port->formats = pu->possible_formats;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i = 0; i < port->n_formats; i++)
 | 
				
			||||||
 | 
					      spa_debug_format (port->formats[i]);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (pu->change_mask & SPA_CONTROL_CMD_PORT_UPDATE_PROPS) {
 | 
					  if (pu->change_mask & SPA_CONTROL_CMD_PORT_UPDATE_PROPS) {
 | 
				
			||||||
| 
						 | 
					@ -969,7 +971,7 @@ parse_control (SpaProxy   *this,
 | 
				
			||||||
      case SPA_CONTROL_CMD_SET_FORMAT:
 | 
					      case SPA_CONTROL_CMD_SET_FORMAT:
 | 
				
			||||||
      case SPA_CONTROL_CMD_SET_PROPERTY:
 | 
					      case SPA_CONTROL_CMD_SET_PROPERTY:
 | 
				
			||||||
      case SPA_CONTROL_CMD_START:
 | 
					      case SPA_CONTROL_CMD_START:
 | 
				
			||||||
      case SPA_CONTROL_CMD_STOP:
 | 
					      case SPA_CONTROL_CMD_PAUSE:
 | 
				
			||||||
        fprintf (stderr, "proxy %p: got unexpected control %d\n", this, cmd);
 | 
					        fprintf (stderr, "proxy %p: got unexpected control %d\n", this, cmd);
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -142,21 +142,18 @@ static const SpaPropInfo prop_info[] =
 | 
				
			||||||
  { PROP_ID_DEVICE,            "device", "V4l2 device location",
 | 
					  { PROP_ID_DEVICE,            "device", "V4l2 device location",
 | 
				
			||||||
                                SPA_PROP_FLAG_READWRITE,
 | 
					                                SPA_PROP_FLAG_READWRITE,
 | 
				
			||||||
                                SPA_PROP_TYPE_STRING, 63,
 | 
					                                SPA_PROP_TYPE_STRING, 63,
 | 
				
			||||||
                                strlen (default_device)+1, default_device,
 | 
					 | 
				
			||||||
                                SPA_PROP_RANGE_TYPE_NONE, 0, NULL,
 | 
					                                SPA_PROP_RANGE_TYPE_NONE, 0, NULL,
 | 
				
			||||||
                                NULL,
 | 
					                                NULL,
 | 
				
			||||||
                                offsetof (SpaV4l2SourceProps, device) },
 | 
					                                offsetof (SpaV4l2SourceProps, device) },
 | 
				
			||||||
  { PROP_ID_DEVICE_NAME,       "device-name", "Human-readable name of the device",
 | 
					  { PROP_ID_DEVICE_NAME,       "device-name", "Human-readable name of the device",
 | 
				
			||||||
                                SPA_PROP_FLAG_READABLE,
 | 
					                                SPA_PROP_FLAG_READABLE,
 | 
				
			||||||
                                SPA_PROP_TYPE_STRING, 127,
 | 
					                                SPA_PROP_TYPE_STRING, 127,
 | 
				
			||||||
                                0, NULL,
 | 
					 | 
				
			||||||
                                SPA_PROP_RANGE_TYPE_NONE, 0, NULL,
 | 
					                                SPA_PROP_RANGE_TYPE_NONE, 0, NULL,
 | 
				
			||||||
                                NULL,
 | 
					                                NULL,
 | 
				
			||||||
                                offsetof (SpaV4l2SourceProps, device_name) },
 | 
					                                offsetof (SpaV4l2SourceProps, device_name) },
 | 
				
			||||||
  { PROP_ID_DEVICE_FD,          "device-fd", "Device file descriptor",
 | 
					  { PROP_ID_DEVICE_FD,          "device-fd", "Device file descriptor",
 | 
				
			||||||
                                SPA_PROP_FLAG_READABLE,
 | 
					                                SPA_PROP_FLAG_READABLE,
 | 
				
			||||||
                                SPA_PROP_TYPE_UINT32, sizeof (uint32_t),
 | 
					                                SPA_PROP_TYPE_UINT32, sizeof (uint32_t),
 | 
				
			||||||
                                0, NULL,
 | 
					 | 
				
			||||||
                                SPA_PROP_RANGE_TYPE_NONE, 0, NULL,
 | 
					                                SPA_PROP_RANGE_TYPE_NONE, 0, NULL,
 | 
				
			||||||
                                NULL,
 | 
					                                NULL,
 | 
				
			||||||
                                offsetof (SpaV4l2SourceProps, device_fd) },
 | 
					                                offsetof (SpaV4l2SourceProps, device_fd) },
 | 
				
			||||||
| 
						 | 
					@ -237,7 +234,7 @@ spa_v4l2_source_node_send_command (SpaNode       *node,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      send_state_change (this, SPA_NODE_STATE_STREAMING);
 | 
					      send_state_change (this, SPA_NODE_STATE_STREAMING);
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case SPA_COMMAND_STOP:
 | 
					    case SPA_COMMAND_PAUSE:
 | 
				
			||||||
      spa_v4l2_stop (this);
 | 
					      spa_v4l2_stop (this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      send_state_change (this, SPA_NODE_STATE_PAUSED);
 | 
					      send_state_change (this, SPA_NODE_STATE_PAUSED);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -385,13 +385,13 @@ spa_v4l2_set_format (SpaV4l2Source *this, V4l2Format *f, bool try_only)
 | 
				
			||||||
  fmt.fmt.pix.field = V4L2_FIELD_ANY;
 | 
					  fmt.fmt.pix.field = V4L2_FIELD_ANY;
 | 
				
			||||||
  fmt.fmt.pix.width = f->size.width;
 | 
					  fmt.fmt.pix.width = f->size.width;
 | 
				
			||||||
  fmt.fmt.pix.height = f->size.height;
 | 
					  fmt.fmt.pix.height = f->size.height;
 | 
				
			||||||
  streamparm.parm.capture.timeperframe.numerator = f->framerate.denom;
 | 
					  streamparm.parm.capture.timeperframe.numerator = f->framerate.num;
 | 
				
			||||||
  streamparm.parm.capture.timeperframe.denominator = f->framerate.num;
 | 
					  streamparm.parm.capture.timeperframe.denominator = f->framerate.denom;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fprintf (stderr, "set %08x %dx%d %d/%d\n", fmt.fmt.pix.pixelformat,
 | 
					  fprintf (stderr, "set %08x %dx%d %d/%d\n", fmt.fmt.pix.pixelformat,
 | 
				
			||||||
      fmt.fmt.pix.width, fmt.fmt.pix.height,
 | 
					      fmt.fmt.pix.width, fmt.fmt.pix.height,
 | 
				
			||||||
      streamparm.parm.capture.timeperframe.denominator,
 | 
					      streamparm.parm.capture.timeperframe.numerator,
 | 
				
			||||||
      streamparm.parm.capture.timeperframe.numerator);
 | 
					      streamparm.parm.capture.timeperframe.denominator);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  reqfmt = fmt;
 | 
					  reqfmt = fmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -407,6 +407,11 @@ spa_v4l2_set_format (SpaV4l2Source *this, V4l2Format *f, bool try_only)
 | 
				
			||||||
  if (xioctl (state->fd, VIDIOC_S_PARM, &streamparm) < 0)
 | 
					  if (xioctl (state->fd, VIDIOC_S_PARM, &streamparm) < 0)
 | 
				
			||||||
    perror ("VIDIOC_S_PARM");
 | 
					    perror ("VIDIOC_S_PARM");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fprintf (stderr, "got %08x %dx%d %d/%d\n", fmt.fmt.pix.pixelformat,
 | 
				
			||||||
 | 
					      fmt.fmt.pix.width, fmt.fmt.pix.height,
 | 
				
			||||||
 | 
					      streamparm.parm.capture.timeperframe.numerator,
 | 
				
			||||||
 | 
					      streamparm.parm.capture.timeperframe.denominator);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (reqfmt.fmt.pix.pixelformat != fmt.fmt.pix.pixelformat ||
 | 
					  if (reqfmt.fmt.pix.pixelformat != fmt.fmt.pix.pixelformat ||
 | 
				
			||||||
      reqfmt.fmt.pix.width != fmt.fmt.pix.width ||
 | 
					      reqfmt.fmt.pix.width != fmt.fmt.pix.width ||
 | 
				
			||||||
      reqfmt.fmt.pix.height != fmt.fmt.pix.height)
 | 
					      reqfmt.fmt.pix.height != fmt.fmt.pix.height)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -78,14 +78,12 @@ static const SpaPropInfo prop_info[] =
 | 
				
			||||||
  { PROP_ID_VOLUME,            "volume", "The Volume factor",
 | 
					  { PROP_ID_VOLUME,            "volume", "The Volume factor",
 | 
				
			||||||
                               SPA_PROP_FLAG_READWRITE,
 | 
					                               SPA_PROP_FLAG_READWRITE,
 | 
				
			||||||
                               SPA_PROP_TYPE_DOUBLE, sizeof (double),
 | 
					                               SPA_PROP_TYPE_DOUBLE, sizeof (double),
 | 
				
			||||||
                               sizeof (double), &default_volume,
 | 
					 | 
				
			||||||
                               SPA_PROP_RANGE_TYPE_MIN_MAX, 2, volume_range,
 | 
					                               SPA_PROP_RANGE_TYPE_MIN_MAX, 2, volume_range,
 | 
				
			||||||
                               NULL,
 | 
					                               NULL,
 | 
				
			||||||
                               offsetof (SpaVolumeProps, volume) },
 | 
					                               offsetof (SpaVolumeProps, volume) },
 | 
				
			||||||
  { PROP_ID_MUTE,              "mute", "Mute",
 | 
					  { PROP_ID_MUTE,              "mute", "Mute",
 | 
				
			||||||
                               SPA_PROP_FLAG_READWRITE,
 | 
					                               SPA_PROP_FLAG_READWRITE,
 | 
				
			||||||
                               SPA_PROP_TYPE_BOOL, sizeof (bool),
 | 
					                               SPA_PROP_TYPE_BOOL, sizeof (bool),
 | 
				
			||||||
                               sizeof (bool), &default_mute,
 | 
					 | 
				
			||||||
                               SPA_PROP_RANGE_TYPE_NONE, 0, NULL,
 | 
					                               SPA_PROP_RANGE_TYPE_NONE, 0, NULL,
 | 
				
			||||||
                               NULL,
 | 
					                               NULL,
 | 
				
			||||||
                               offsetof (SpaVolumeProps, mute) },
 | 
					                               offsetof (SpaVolumeProps, mute) },
 | 
				
			||||||
| 
						 | 
					@ -168,7 +166,7 @@ spa_volume_node_send_command (SpaNode       *node,
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case SPA_COMMAND_STOP:
 | 
					    case SPA_COMMAND_PAUSE:
 | 
				
			||||||
      if (this->event_cb) {
 | 
					      if (this->event_cb) {
 | 
				
			||||||
        SpaEvent event;
 | 
					        SpaEvent event;
 | 
				
			||||||
        SpaEventStateChange sc;
 | 
					        SpaEventStateChange sc;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -100,21 +100,18 @@ static const SpaPropInfo prop_info[] =
 | 
				
			||||||
  { PROP_ID_DEVICE,            "device", "Xv device location",
 | 
					  { PROP_ID_DEVICE,            "device", "Xv device location",
 | 
				
			||||||
                                SPA_PROP_FLAG_READWRITE,
 | 
					                                SPA_PROP_FLAG_READWRITE,
 | 
				
			||||||
                                SPA_PROP_TYPE_STRING, 63,
 | 
					                                SPA_PROP_TYPE_STRING, 63,
 | 
				
			||||||
                                strlen (default_device)+1, default_device,
 | 
					 | 
				
			||||||
                                SPA_PROP_RANGE_TYPE_NONE, 0, NULL,
 | 
					                                SPA_PROP_RANGE_TYPE_NONE, 0, NULL,
 | 
				
			||||||
                                NULL,
 | 
					                                NULL,
 | 
				
			||||||
                                offsetof (SpaXvSinkProps, device) },
 | 
					                                offsetof (SpaXvSinkProps, device) },
 | 
				
			||||||
  { PROP_ID_DEVICE_NAME,       "device-name", "Human-readable name of the device",
 | 
					  { PROP_ID_DEVICE_NAME,       "device-name", "Human-readable name of the device",
 | 
				
			||||||
                                SPA_PROP_FLAG_READABLE,
 | 
					                                SPA_PROP_FLAG_READABLE,
 | 
				
			||||||
                                SPA_PROP_TYPE_STRING, 127,
 | 
					                                SPA_PROP_TYPE_STRING, 127,
 | 
				
			||||||
                                0, NULL,
 | 
					 | 
				
			||||||
                                SPA_PROP_RANGE_TYPE_NONE, 0, NULL,
 | 
					                                SPA_PROP_RANGE_TYPE_NONE, 0, NULL,
 | 
				
			||||||
                                NULL,
 | 
					                                NULL,
 | 
				
			||||||
                                offsetof (SpaXvSinkProps, device_name) },
 | 
					                                offsetof (SpaXvSinkProps, device_name) },
 | 
				
			||||||
  { PROP_ID_DEVICE_FD,          "device-fd", "Device file descriptor",
 | 
					  { PROP_ID_DEVICE_FD,          "device-fd", "Device file descriptor",
 | 
				
			||||||
                                SPA_PROP_FLAG_READABLE,
 | 
					                                SPA_PROP_FLAG_READABLE,
 | 
				
			||||||
                                SPA_PROP_TYPE_UINT32, sizeof (uint32_t),
 | 
					                                SPA_PROP_TYPE_UINT32, sizeof (uint32_t),
 | 
				
			||||||
                                0, NULL,
 | 
					 | 
				
			||||||
                                SPA_PROP_RANGE_TYPE_NONE, 0, NULL,
 | 
					                                SPA_PROP_RANGE_TYPE_NONE, 0, NULL,
 | 
				
			||||||
                                NULL,
 | 
					                                NULL,
 | 
				
			||||||
                                offsetof (SpaXvSinkProps, device_fd) },
 | 
					                                offsetof (SpaXvSinkProps, device_fd) },
 | 
				
			||||||
| 
						 | 
					@ -192,7 +189,7 @@ spa_xv_sink_node_send_command (SpaNode       *node,
 | 
				
			||||||
        this->event_cb (node, &event, this->user_data);
 | 
					        this->event_cb (node, &event, this->user_data);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case SPA_COMMAND_STOP:
 | 
					    case SPA_COMMAND_PAUSE:
 | 
				
			||||||
      spa_xv_stop (this);
 | 
					      spa_xv_stop (this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (this->event_cb) {
 | 
					      if (this->event_cb) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -331,7 +331,7 @@ run_async_sink (AppData *data)
 | 
				
			||||||
    pthread_join (data->thread, NULL);
 | 
					    pthread_join (data->thread, NULL);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  cmd.type = SPA_COMMAND_STOP;
 | 
					  cmd.type = SPA_COMMAND_PAUSE;
 | 
				
			||||||
  if ((res = spa_node_send_command (data->sink, &cmd)) < 0)
 | 
					  if ((res = spa_node_send_command (data->sink, &cmd)) < 0)
 | 
				
			||||||
    printf ("got error %d\n", res);
 | 
					    printf ("got error %d\n", res);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -439,7 +439,7 @@ run_async_source (AppData *data)
 | 
				
			||||||
    pthread_join (data->thread, NULL);
 | 
					    pthread_join (data->thread, NULL);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  cmd.type = SPA_COMMAND_STOP;
 | 
					  cmd.type = SPA_COMMAND_PAUSE;
 | 
				
			||||||
  if ((res = spa_node_send_command (data->source, &cmd)) < 0)
 | 
					  if ((res = spa_node_send_command (data->source, &cmd)) < 0)
 | 
				
			||||||
    printf ("got error %d\n", res);
 | 
					    printf ("got error %d\n", res);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue