mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	add clock
Add a gstreamer pinos clock that reports the time at the server
This commit is contained in:
		
							parent
							
								
									0b380dd43e
								
							
						
					
					
						commit
						f86b50d202
					
				
					 11 changed files with 259 additions and 72 deletions
				
			
		| 
						 | 
					@ -268,6 +268,7 @@ plugin_LTLIBRARIES = libgstpinos.la
 | 
				
			||||||
libgstpinos_la_SOURCES = \
 | 
					libgstpinos_la_SOURCES = \
 | 
				
			||||||
                        gst/gstburstcache.c \
 | 
					                        gst/gstburstcache.c \
 | 
				
			||||||
                        gst/gstpinos.c \
 | 
					                        gst/gstpinos.c \
 | 
				
			||||||
 | 
					                        gst/gstpinosclock.c \
 | 
				
			||||||
                        gst/gstpinosformat.c \
 | 
					                        gst/gstpinosformat.c \
 | 
				
			||||||
                        gst/gstpinosdeviceprovider.c \
 | 
					                        gst/gstpinosdeviceprovider.c \
 | 
				
			||||||
                        gst/gstpinossrc.c \
 | 
					                        gst/gstpinossrc.c \
 | 
				
			||||||
| 
						 | 
					@ -281,7 +282,7 @@ libgstpinos_la_LIBADD =  $(GST_BASE_LIBS) $(GST_LIBS) $(GLIB_LIBS) $(LIBM) -lgst
 | 
				
			||||||
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/gstpinosformat.h \
 | 
							 gst/gstpinosclock.h gst/gstpinosformat.h \
 | 
				
			||||||
		 gst/gstpinossink.h gst/gstpinosdeviceprovider.h
 | 
							 gst/gstpinossink.h gst/gstpinosdeviceprovider.h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
###################################
 | 
					###################################
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -95,7 +95,8 @@ struct _PinosStreamPrivate
 | 
				
			||||||
  GArray *buffer_ids;
 | 
					  GArray *buffer_ids;
 | 
				
			||||||
  gboolean in_order;
 | 
					  gboolean in_order;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  gint64 last_timestamp;
 | 
					  gint64 last_ticks;
 | 
				
			||||||
 | 
					  gint32 last_rate;
 | 
				
			||||||
  gint64 last_monotonic;
 | 
					  gint64 last_monotonic;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -637,6 +638,23 @@ send_need_input (PinosStream *stream, uint32_t port_id)
 | 
				
			||||||
  spa_control_clear (&control);
 | 
					  spa_control_clear (&control);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					add_request_clock_update (PinosStream *stream, SpaControlBuilder *builder)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  SpaControlCmdNodeEvent cne;
 | 
				
			||||||
 | 
					  SpaNodeEvent ne;
 | 
				
			||||||
 | 
					  SpaNodeEventRequestClockUpdate rcu;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  cne.event = ≠
 | 
				
			||||||
 | 
					  ne.type = SPA_NODE_EVENT_TYPE_REQUEST_CLOCK_UPDATE;
 | 
				
			||||||
 | 
					  ne.data = &rcu;
 | 
				
			||||||
 | 
					  ne.size = sizeof (rcu);
 | 
				
			||||||
 | 
					  rcu.update_mask = SPA_NODE_EVENT_REQUEST_CLOCK_UPDATE_TIME;
 | 
				
			||||||
 | 
					  rcu.timestamp = 0;
 | 
				
			||||||
 | 
					  rcu.offset = 0;
 | 
				
			||||||
 | 
					  spa_control_builder_add_cmd (builder, SPA_CONTROL_CMD_NODE_EVENT, &cne);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
send_reuse_buffer (PinosStream *stream, uint32_t port_id, uint32_t buffer_id)
 | 
					send_reuse_buffer (PinosStream *stream, uint32_t port_id, uint32_t buffer_id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -794,6 +812,7 @@ handle_node_command (PinosStream    *stream,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      g_debug ("stream %p: start", stream);
 | 
					      g_debug ("stream %p: start", stream);
 | 
				
			||||||
      control_builder_init (stream, &builder);
 | 
					      control_builder_init (stream, &builder);
 | 
				
			||||||
 | 
					      add_request_clock_update (stream, &builder);
 | 
				
			||||||
      if (priv->direction == PINOS_DIRECTION_INPUT)
 | 
					      if (priv->direction == PINOS_DIRECTION_INPUT)
 | 
				
			||||||
        add_need_input (stream, &builder, 0);
 | 
					        add_need_input (stream, &builder, 0);
 | 
				
			||||||
      add_state_change (stream, &builder, SPA_NODE_STATE_STREAMING);
 | 
					      add_state_change (stream, &builder, SPA_NODE_STATE_STREAMING);
 | 
				
			||||||
| 
						 | 
					@ -816,8 +835,8 @@ handle_node_command (PinosStream    *stream,
 | 
				
			||||||
    case SPA_NODE_COMMAND_CLOCK_UPDATE:
 | 
					    case SPA_NODE_COMMAND_CLOCK_UPDATE:
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      SpaNodeCommandClockUpdate *cu = command->data;
 | 
					      SpaNodeCommandClockUpdate *cu = command->data;
 | 
				
			||||||
      g_debug ("got clock update %"PRId64", %"PRId64, cu->timestamp, cu->monotonic_time);
 | 
					      priv->last_ticks = cu->ticks;
 | 
				
			||||||
      priv->last_timestamp = cu->timestamp;
 | 
					      priv->last_rate = cu->rate;
 | 
				
			||||||
      priv->last_monotonic = cu->monotonic_time;
 | 
					      priv->last_monotonic = cu->monotonic_time;
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -1050,20 +1069,9 @@ on_timeout (gpointer user_data)
 | 
				
			||||||
  PinosStreamPrivate *priv = stream->priv;
 | 
					  PinosStreamPrivate *priv = stream->priv;
 | 
				
			||||||
  SpaControlBuilder builder;
 | 
					  SpaControlBuilder builder;
 | 
				
			||||||
  SpaControl control;
 | 
					  SpaControl control;
 | 
				
			||||||
  SpaControlCmdNodeEvent cne;
 | 
					 | 
				
			||||||
  SpaNodeEvent ne;
 | 
					 | 
				
			||||||
  SpaNodeEventRequestClockUpdate rcu;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  cne.event = ≠
 | 
					 | 
				
			||||||
  ne.type = SPA_NODE_EVENT_TYPE_REQUEST_CLOCK_UPDATE;
 | 
					 | 
				
			||||||
  ne.data = &rcu;
 | 
					 | 
				
			||||||
  ne.size = sizeof (rcu);
 | 
					 | 
				
			||||||
  rcu.update_mask = SPA_NODE_EVENT_REQUEST_CLOCK_UPDATE_TIME;
 | 
					 | 
				
			||||||
  rcu.timestamp = 0;
 | 
					 | 
				
			||||||
  rcu.offset = 0;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  control_builder_init (stream, &builder);
 | 
					  control_builder_init (stream, &builder);
 | 
				
			||||||
  spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_NODE_EVENT, &cne);
 | 
					  add_request_clock_update (stream, &builder);
 | 
				
			||||||
  spa_control_builder_end (&builder, &control);
 | 
					  spa_control_builder_end (&builder, &control);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (spa_control_write (&control, priv->fd) < 0)
 | 
					  if (spa_control_write (&control, priv->fd) < 0)
 | 
				
			||||||
| 
						 | 
					@ -1540,6 +1548,26 @@ pinos_stream_disconnect (PinosStream *stream)
 | 
				
			||||||
  return TRUE;
 | 
					  return TRUE;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					gboolean
 | 
				
			||||||
 | 
					pinos_stream_get_time (PinosStream     *stream,
 | 
				
			||||||
 | 
					                       PinosTime       *time)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  PinosStreamPrivate *priv;
 | 
				
			||||||
 | 
					  gint64 now, elapsed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  g_return_val_if_fail (PINOS_IS_STREAM (stream), FALSE);
 | 
				
			||||||
 | 
					  priv = stream->priv;
 | 
				
			||||||
 | 
					  g_return_val_if_fail (time, FALSE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  now = g_get_monotonic_time ();
 | 
				
			||||||
 | 
					  elapsed = now - (priv->last_monotonic / 1000);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  time->ticks = priv->last_ticks + (elapsed * priv->last_rate) / G_USEC_PER_SEC;
 | 
				
			||||||
 | 
					  time->rate = priv->last_rate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return TRUE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * pinos_stream_get_empty_buffer:
 | 
					 * pinos_stream_get_empty_buffer:
 | 
				
			||||||
 * @stream: a #PinosStream
 | 
					 * @stream: a #PinosStream
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -64,6 +64,11 @@ typedef enum {
 | 
				
			||||||
  PINOS_STREAM_MODE_RINGBUFFER = 1,
 | 
					  PINOS_STREAM_MODE_RINGBUFFER = 1,
 | 
				
			||||||
} PinosStreamMode;
 | 
					} PinosStreamMode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct {
 | 
				
			||||||
 | 
					  gint64 ticks;
 | 
				
			||||||
 | 
					  gint32 rate;
 | 
				
			||||||
 | 
					} PinosTime;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * PinosStream:
 | 
					 * PinosStream:
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
| 
						 | 
					@ -110,6 +115,9 @@ gboolean         pinos_stream_start_allocation  (PinosStream     *stream,
 | 
				
			||||||
gboolean         pinos_stream_start             (PinosStream     *stream);
 | 
					gboolean         pinos_stream_start             (PinosStream     *stream);
 | 
				
			||||||
gboolean         pinos_stream_stop              (PinosStream     *stream);
 | 
					gboolean         pinos_stream_stop              (PinosStream     *stream);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					gboolean         pinos_stream_get_time          (PinosStream     *stream,
 | 
				
			||||||
 | 
					                                                 PinosTime       *time);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
guint            pinos_stream_get_empty_buffer  (PinosStream     *stream);
 | 
					guint            pinos_stream_get_empty_buffer  (PinosStream     *stream);
 | 
				
			||||||
gboolean         pinos_stream_recycle_buffer    (PinosStream     *stream,
 | 
					gboolean         pinos_stream_recycle_buffer    (PinosStream     *stream,
 | 
				
			||||||
                                                 guint            id);
 | 
					                                                 guint            id);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										88
									
								
								pinos/gst/gstpinosclock.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								pinos/gst/gstpinosclock.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,88 @@
 | 
				
			||||||
 | 
					/* 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 Street, Suite 500,
 | 
				
			||||||
 | 
					 * Boston, MA 02110-1335, USA.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef HAVE_CONFIG_H
 | 
				
			||||||
 | 
					#include "config.h"
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <gst/gst.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "gstpinosclock.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					GST_DEBUG_CATEGORY_STATIC (gst_pinos_clock_debug_category);
 | 
				
			||||||
 | 
					#define GST_CAT_DEFAULT gst_pinos_clock_debug_category
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					G_DEFINE_TYPE (GstPinosClock, gst_pinos_clock, GST_TYPE_SYSTEM_CLOCK);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					GstClock *
 | 
				
			||||||
 | 
					gst_pinos_clock_new (PinosStream *stream)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  GstPinosClock *clock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  clock = g_object_new (GST_TYPE_PINOS_CLOCK, NULL);
 | 
				
			||||||
 | 
					  clock->stream = stream;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return GST_CLOCK_CAST (clock);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static GstClockTime
 | 
				
			||||||
 | 
					gst_pinos_clock_get_internal_time (GstClock * clock)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  GstPinosClock *pclock = (GstPinosClock *) clock;
 | 
				
			||||||
 | 
					  GstClockTime result;
 | 
				
			||||||
 | 
					  PinosTime t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  pinos_stream_get_time (pclock->stream, &t);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  result = gst_util_uint64_scale_int (t.ticks, GST_SECOND, t.rate);
 | 
				
			||||||
 | 
					  GST_DEBUG ("%"PRId64", %d %"PRId64, t.ticks, t.rate, result);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					gst_pinos_clock_finalize (GObject * object)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  GstPinosClock *clock = GST_PINOS_CLOCK (object);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  GST_DEBUG_OBJECT (clock, "finalize");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  G_OBJECT_CLASS (gst_pinos_clock_parent_class)->finalize (object);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					gst_pinos_clock_class_init (GstPinosClockClass * klass)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 | 
				
			||||||
 | 
					  GstClockClass *gstclock_class = GST_CLOCK_CLASS (klass);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  gobject_class->finalize = gst_pinos_clock_finalize;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  gstclock_class->get_internal_time = gst_pinos_clock_get_internal_time;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  GST_DEBUG_CATEGORY_INIT (gst_pinos_clock_debug_category, "pinosclock", 0,
 | 
				
			||||||
 | 
					      "debug category for pinosclock object");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					gst_pinos_clock_init (GstPinosClock * clock)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  GST_OBJECT_FLAG_SET (clock, GST_CLOCK_FLAG_CAN_SET_MASTER);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										62
									
								
								pinos/gst/gstpinosclock.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								pinos/gst/gstpinosclock.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,62 @@
 | 
				
			||||||
 | 
					/* 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_CLOCK_H__
 | 
				
			||||||
 | 
					#define __GST_PINOS_CLOCK_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <gst/gst.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <client/pinos.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					G_BEGIN_DECLS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define GST_TYPE_PINOS_CLOCK \
 | 
				
			||||||
 | 
					  (gst_pinos_clock_get_type())
 | 
				
			||||||
 | 
					#define GST_PINOS_CLOCK(obj) \
 | 
				
			||||||
 | 
					  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PINOS_CLOCK,GstPinosClock))
 | 
				
			||||||
 | 
					#define GST_PINOS_CLOCK_CLASS(klass) \
 | 
				
			||||||
 | 
					  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PINOS_CLOCK,GstPinosClockClass))
 | 
				
			||||||
 | 
					#define GST_IS_PINOS_CLOCK(obj) \
 | 
				
			||||||
 | 
					  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PINOS_CLOCK))
 | 
				
			||||||
 | 
					#define GST_IS_PINOS_CLOCK_CLASS(klass) \
 | 
				
			||||||
 | 
					  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PINOS_CLOCK))
 | 
				
			||||||
 | 
					#define GST_PINOS_CLOCK_GET_CLASS(klass) \
 | 
				
			||||||
 | 
					  (G_TYPE_INSTANCE_GET_CLASS ((klass), GST_TYPE_PINOS_CLOCK, GstPinosClockClass))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct _GstPinosClock GstPinosClock;
 | 
				
			||||||
 | 
					typedef struct _GstPinosClockClass GstPinosClockClass;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct _GstPinosClock {
 | 
				
			||||||
 | 
					  GstSystemClock parent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  PinosStream *stream;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct _GstPinosClockClass {
 | 
				
			||||||
 | 
					  GstSystemClockClass parent_class;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					GType gst_pinos_clock_get_type (void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					GstClock *      gst_pinos_clock_new           (PinosStream *stream);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					G_END_DECLS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* __GST_PINOS_CLOCK_H__ */
 | 
				
			||||||
| 
						 | 
					@ -48,6 +48,7 @@
 | 
				
			||||||
#include <spa/include/spa/memory.h>
 | 
					#include <spa/include/spa/memory.h>
 | 
				
			||||||
#include <spa/include/spa/buffer.h>
 | 
					#include <spa/include/spa/buffer.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "gstpinosclock.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static GQuark process_mem_data_quark;
 | 
					static GQuark process_mem_data_quark;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -269,6 +270,7 @@ gst_pinos_src_init (GstPinosSrc * src)
 | 
				
			||||||
  gst_base_src_set_format (GST_BASE_SRC (src), GST_FORMAT_TIME);
 | 
					  gst_base_src_set_format (GST_BASE_SRC (src), GST_FORMAT_TIME);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  GST_OBJECT_FLAG_SET (src, GST_ELEMENT_FLAG_PROVIDE_CLOCK);
 | 
					  GST_OBJECT_FLAG_SET (src, GST_ELEMENT_FLAG_PROVIDE_CLOCK);
 | 
				
			||||||
 | 
					  gst_base_src_set_live (GST_BASE_SRC (src), TRUE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  g_queue_init (&src->queue);
 | 
					  g_queue_init (&src->queue);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -523,30 +525,10 @@ parse_stream_properties (GstPinosSrc *pinossrc, PinosProperties *props)
 | 
				
			||||||
  var = pinos_properties_get (props, "pinos.latency.max");
 | 
					  var = pinos_properties_get (props, "pinos.latency.max");
 | 
				
			||||||
  pinossrc->max_latency = var ? (GstClockTime) atoi (var) : GST_CLOCK_TIME_NONE;
 | 
					  pinossrc->max_latency = var ? (GstClockTime) atoi (var) : GST_CLOCK_TIME_NONE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  var = pinos_properties_get (props, "pinos.clock.type");
 | 
					  pinossrc->is_live = TRUE;
 | 
				
			||||||
  if (var != NULL) {
 | 
					  pinossrc->min_latency = 100000000;
 | 
				
			||||||
    GST_DEBUG_OBJECT (pinossrc, "got clock type %s", var);
 | 
					  pinossrc->max_latency = GST_CLOCK_TIME_NONE;
 | 
				
			||||||
    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 (pinossrc, "making net clock for %s:%d %" G_GUINT64_FORMAT, address, port, base_time);
 | 
					 | 
				
			||||||
      if (pinossrc->clock)
 | 
					 | 
				
			||||||
        gst_object_unref (pinossrc->clock);
 | 
					 | 
				
			||||||
      pinossrc->clock = gst_net_client_clock_new ("pinosclock", address, port, base_time);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      gst_element_post_message (GST_ELEMENT_CAST (pinossrc),
 | 
					 | 
				
			||||||
          gst_message_new_clock_provide (GST_OBJECT_CAST (pinossrc),
 | 
					 | 
				
			||||||
            pinossrc->clock, TRUE));
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
static gboolean
 | 
					static gboolean
 | 
				
			||||||
gst_pinos_src_stream_start (GstPinosSrc *pinossrc)
 | 
					gst_pinos_src_stream_start (GstPinosSrc *pinossrc)
 | 
				
			||||||
| 
						 | 
					@ -817,6 +799,8 @@ gst_pinos_src_query (GstBaseSrc * src, GstQuery * query)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  switch (GST_QUERY_TYPE (query)) {
 | 
					  switch (GST_QUERY_TYPE (query)) {
 | 
				
			||||||
    case GST_QUERY_LATENCY:
 | 
					    case GST_QUERY_LATENCY:
 | 
				
			||||||
 | 
					      pinossrc->min_latency = 10000000;
 | 
				
			||||||
 | 
					      pinossrc->max_latency = GST_CLOCK_TIME_NONE;
 | 
				
			||||||
      gst_query_set_latency (query, pinossrc->is_live, pinossrc->min_latency, pinossrc->max_latency);
 | 
					      gst_query_set_latency (query, pinossrc->is_live, pinossrc->min_latency, pinossrc->max_latency);
 | 
				
			||||||
      res = TRUE;
 | 
					      res = TRUE;
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
| 
						 | 
					@ -1004,6 +988,7 @@ gst_pinos_src_open (GstPinosSrc * pinossrc)
 | 
				
			||||||
  g_signal_connect (pinossrc->stream, "add-buffer", (GCallback) on_add_buffer, pinossrc);
 | 
					  g_signal_connect (pinossrc->stream, "add-buffer", (GCallback) on_add_buffer, pinossrc);
 | 
				
			||||||
  g_signal_connect (pinossrc->stream, "remove-buffer", (GCallback) on_remove_buffer, pinossrc);
 | 
					  g_signal_connect (pinossrc->stream, "remove-buffer", (GCallback) on_remove_buffer, pinossrc);
 | 
				
			||||||
  g_signal_connect (pinossrc->stream, "new-buffer", (GCallback) on_new_buffer, pinossrc);
 | 
					  g_signal_connect (pinossrc->stream, "new-buffer", (GCallback) on_new_buffer, pinossrc);
 | 
				
			||||||
 | 
					  pinossrc->clock = gst_pinos_clock_new (pinossrc->stream);
 | 
				
			||||||
  pinos_main_loop_unlock (pinossrc->loop);
 | 
					  pinos_main_loop_unlock (pinossrc->loop);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return TRUE;
 | 
					  return TRUE;
 | 
				
			||||||
| 
						 | 
					@ -1031,6 +1016,7 @@ gst_pinos_src_close (GstPinosSrc * pinossrc)
 | 
				
			||||||
  g_main_context_unref (pinossrc->context);
 | 
					  g_main_context_unref (pinossrc->context);
 | 
				
			||||||
  GST_OBJECT_LOCK (pinossrc);
 | 
					  GST_OBJECT_LOCK (pinossrc);
 | 
				
			||||||
  pinossrc->stream_state = PINOS_STREAM_STATE_UNCONNECTED;
 | 
					  pinossrc->stream_state = PINOS_STREAM_STATE_UNCONNECTED;
 | 
				
			||||||
 | 
					  g_clear_object (&pinossrc->clock);
 | 
				
			||||||
  g_clear_object (&pinossrc->stream);
 | 
					  g_clear_object (&pinossrc->stream);
 | 
				
			||||||
  GST_OBJECT_UNLOCK (pinossrc);
 | 
					  GST_OBJECT_UNLOCK (pinossrc);
 | 
				
			||||||
  clear_queue (pinossrc);
 | 
					  clear_queue (pinossrc);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -292,6 +292,29 @@ suspend_node (PinosNode *this)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					send_clock_update (PinosNode *this)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  PinosNodePrivate *priv = this->priv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (priv->clock) {
 | 
				
			||||||
 | 
					    SpaNodeCommand cmd;
 | 
				
			||||||
 | 
					    SpaNodeCommandClockUpdate cu;
 | 
				
			||||||
 | 
					    SpaResult res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cmd.type = SPA_NODE_COMMAND_CLOCK_UPDATE;
 | 
				
			||||||
 | 
					    cmd.data = &cu;
 | 
				
			||||||
 | 
					    cmd.size = sizeof (cu);
 | 
				
			||||||
 | 
					    cu.change_mask = SPA_NODE_COMMAND_CLOCK_UPDATE_TIME;
 | 
				
			||||||
 | 
					    res = spa_clock_get_time (priv->clock, &cu.rate, &cu.ticks, &cu.monotonic_time);
 | 
				
			||||||
 | 
					    cu.scale = (1 << 16) | 1;
 | 
				
			||||||
 | 
					    cu.state = SPA_CLOCK_STATE_RUNNING;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if ((res = spa_node_send_command (this->node, &cmd)) < 0)
 | 
				
			||||||
 | 
					      g_debug ("got error %d", res);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static gboolean
 | 
					static gboolean
 | 
				
			||||||
node_set_state (PinosNode       *this,
 | 
					node_set_state (PinosNode       *this,
 | 
				
			||||||
                PinosNodeState   state)
 | 
					                PinosNodeState   state)
 | 
				
			||||||
| 
						 | 
					@ -482,26 +505,9 @@ on_node_event (SpaNode *node, SpaNodeEvent *event, void *user_data)
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    case SPA_NODE_EVENT_TYPE_REQUEST_CLOCK_UPDATE:
 | 
					    case SPA_NODE_EVENT_TYPE_REQUEST_CLOCK_UPDATE:
 | 
				
			||||||
    {
 | 
					      send_clock_update (this);
 | 
				
			||||||
      SpaResult res;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      if (priv->clock) {
 | 
					 | 
				
			||||||
        SpaNodeCommand cmd;
 | 
					 | 
				
			||||||
        SpaNodeCommandClockUpdate cu;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        cmd.type = SPA_NODE_COMMAND_CLOCK_UPDATE;
 | 
					 | 
				
			||||||
        cmd.data = &cu;
 | 
					 | 
				
			||||||
        cmd.size = sizeof (cu);
 | 
					 | 
				
			||||||
        cu.change_mask = SPA_NODE_COMMAND_CLOCK_UPDATE_TIME;
 | 
					 | 
				
			||||||
        res = spa_clock_get_time (priv->clock, &cu.timestamp, &cu.monotonic_time);
 | 
					 | 
				
			||||||
        cu.scale = (1 << 16) | 1;
 | 
					 | 
				
			||||||
        cu.state = SPA_CLOCK_STATE_RUNNING;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if ((res = spa_node_send_command (this->node, &cmd)) < 0)
 | 
					 | 
				
			||||||
          g_debug ("got error %d", res);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    }
 | 
					
 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
      g_debug ("node %p: got event %d", this, event->type);
 | 
					      g_debug ("node %p: got event %d", this, event->type);
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -107,7 +107,8 @@ struct _SpaClock {
 | 
				
			||||||
                                      const SpaProps   *props);
 | 
					                                      const SpaProps   *props);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  SpaResult   (*get_time)            (SpaClock         *clock,
 | 
					  SpaResult   (*get_time)            (SpaClock         *clock,
 | 
				
			||||||
                                      int64_t          *clock_time,
 | 
					                                      int32_t          *rate,
 | 
				
			||||||
 | 
					                                      int64_t          *ticks,
 | 
				
			||||||
                                      int64_t          *monotonic_time);
 | 
					                                      int64_t          *monotonic_time);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -48,11 +48,12 @@ struct _SpaNodeCommand {
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * SpaNodeCommandClockUpdate:
 | 
					 * SpaNodeCommandClockUpdate:
 | 
				
			||||||
 * @change_mask: marks which fields are updated
 | 
					 * @change_mask: marks which fields are updated
 | 
				
			||||||
 * @timestamp: the new timestamp, when @change_mask = 1<<0
 | 
					 * @rate: the number of  @ticks per second
 | 
				
			||||||
 * @monotonic_time: the new monotonic time associated with @timestamp, when
 | 
					 * @ticks: the new ticks, when @change_mask = 1<<0
 | 
				
			||||||
 *                  @change_mask = 1<<0
 | 
					 * @monotonic_time: the new monotonic time in nanoseconds associated with
 | 
				
			||||||
 | 
					 *                  @ticks, when @change_mask = 1<<0
 | 
				
			||||||
 * @offset: the difference between the time when this update was generated
 | 
					 * @offset: the difference between the time when this update was generated
 | 
				
			||||||
 *          and @monotonic_time
 | 
					 *          and @monotonic_time in nanoseconds
 | 
				
			||||||
 * @scale: update to the speed stored as Q16.16, @change_mask = 1<<1
 | 
					 * @scale: update to the speed stored as Q16.16, @change_mask = 1<<1
 | 
				
			||||||
 * @state: the new clock state, when @change_mask = 1<<2
 | 
					 * @state: the new clock state, when @change_mask = 1<<2
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					@ -61,7 +62,8 @@ typedef struct {
 | 
				
			||||||
#define SPA_NODE_COMMAND_CLOCK_UPDATE_SCALE       (1 << 1)
 | 
					#define SPA_NODE_COMMAND_CLOCK_UPDATE_SCALE       (1 << 1)
 | 
				
			||||||
#define SPA_NODE_COMMAND_CLOCK_UPDATE_STATE       (1 << 2)
 | 
					#define SPA_NODE_COMMAND_CLOCK_UPDATE_STATE       (1 << 2)
 | 
				
			||||||
  uint32_t      change_mask;
 | 
					  uint32_t      change_mask;
 | 
				
			||||||
  int64_t       timestamp;
 | 
					  int32_t       rate;
 | 
				
			||||||
 | 
					  int64_t       ticks;
 | 
				
			||||||
  int64_t       monotonic_time;
 | 
					  int64_t       monotonic_time;
 | 
				
			||||||
  int64_t       offset;
 | 
					  int64_t       offset;
 | 
				
			||||||
  int32_t       scale;
 | 
					  int32_t       scale;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -115,7 +115,7 @@ typedef struct {
 | 
				
			||||||
  SpaAllocParamBuffers param_buffers;
 | 
					  SpaAllocParamBuffers param_buffers;
 | 
				
			||||||
  SpaPortStatus status;
 | 
					  SpaPortStatus status;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  int64_t last_timestamp;
 | 
					  int64_t last_ticks;
 | 
				
			||||||
  int64_t last_monotonic;
 | 
					  int64_t last_monotonic;
 | 
				
			||||||
} SpaV4l2State;
 | 
					} SpaV4l2State;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -759,7 +759,8 @@ spa_v4l2_source_clock_set_props (SpaClock       *clock,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static SpaResult
 | 
					static SpaResult
 | 
				
			||||||
spa_v4l2_source_clock_get_time (SpaClock         *clock,
 | 
					spa_v4l2_source_clock_get_time (SpaClock         *clock,
 | 
				
			||||||
                                int64_t          *clock_time,
 | 
					                                int32_t          *rate,
 | 
				
			||||||
 | 
					                                int64_t          *ticks,
 | 
				
			||||||
                                int64_t          *monotonic_time)
 | 
					                                int64_t          *monotonic_time)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  SpaV4l2Source *this;
 | 
					  SpaV4l2Source *this;
 | 
				
			||||||
| 
						 | 
					@ -771,8 +772,10 @@ spa_v4l2_source_clock_get_time (SpaClock         *clock,
 | 
				
			||||||
  this = (SpaV4l2Source *) clock->handle;
 | 
					  this = (SpaV4l2Source *) clock->handle;
 | 
				
			||||||
  state = &this->state[0];
 | 
					  state = &this->state[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (clock_time)
 | 
					  if (rate)
 | 
				
			||||||
    *clock_time = state->last_timestamp;
 | 
					    *rate = 1000000;
 | 
				
			||||||
 | 
					  if (ticks)
 | 
				
			||||||
 | 
					    *ticks = state->last_ticks;
 | 
				
			||||||
  if (monotonic_time)
 | 
					  if (monotonic_time)
 | 
				
			||||||
    *monotonic_time = state->last_monotonic;
 | 
					    *monotonic_time = state->last_monotonic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -788,7 +788,8 @@ spa_v4l2_set_format (SpaV4l2Source *this, V4l2Format *f, bool try_only)
 | 
				
			||||||
  state->info.flags = SPA_PORT_INFO_FLAG_CAN_ALLOC_BUFFERS |
 | 
					  state->info.flags = SPA_PORT_INFO_FLAG_CAN_ALLOC_BUFFERS |
 | 
				
			||||||
                      SPA_PORT_INFO_FLAG_CAN_USE_BUFFERS;
 | 
					                      SPA_PORT_INFO_FLAG_CAN_USE_BUFFERS;
 | 
				
			||||||
  state->info.maxbuffering = -1;
 | 
					  state->info.maxbuffering = -1;
 | 
				
			||||||
  state->info.latency = -1;
 | 
					  state->info.latency = (streamparm.parm.capture.timeperframe.numerator * 1000000000LL) /
 | 
				
			||||||
 | 
					                        streamparm.parm.capture.timeperframe.denominator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  state->info.n_params = 1;
 | 
					  state->info.n_params = 1;
 | 
				
			||||||
  state->info.params = state->params;
 | 
					  state->info.params = state->params;
 | 
				
			||||||
| 
						 | 
					@ -834,12 +835,13 @@ mmap_read (SpaV4l2Source *this)
 | 
				
			||||||
  if (buf.flags & V4L2_BUF_FLAG_ERROR)
 | 
					  if (buf.flags & V4L2_BUF_FLAG_ERROR)
 | 
				
			||||||
    b->header.flags |= SPA_BUFFER_FLAG_CORRUPTED;
 | 
					    b->header.flags |= SPA_BUFFER_FLAG_CORRUPTED;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  state->last_ticks = (int64_t)buf.timestamp.tv_sec * 1000000 + (uint64_t)buf.timestamp.tv_usec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  b->header.seq = buf.sequence;
 | 
					  b->header.seq = buf.sequence;
 | 
				
			||||||
  b->header.pts = (uint64_t)buf.timestamp.tv_sec * 1000000000lu + (uint64_t)buf.timestamp.tv_usec * 1000lu;
 | 
					  b->header.pts = state->last_ticks * 1000;
 | 
				
			||||||
  state->last_timestamp = b->header.pts;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (buf.flags & V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC)
 | 
					  if (buf.flags & V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC)
 | 
				
			||||||
    state->last_monotonic = state->last_timestamp;
 | 
					    state->last_monotonic = b->header.pts;
 | 
				
			||||||
  else
 | 
					  else
 | 
				
			||||||
    state->last_monotonic = SPA_TIME_INVALID;
 | 
					    state->last_monotonic = SPA_TIME_INVALID;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue