mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-02 09:01:50 -05:00 
			
		
		
		
	examples: add video upload example
Add an example of a node that makes a video available. Improve buffer reuse in stream. Add more video formats
This commit is contained in:
		
							parent
							
								
									c7333c46cc
								
							
						
					
					
						commit
						db16de85bb
					
				
					 16 changed files with 466 additions and 93 deletions
				
			
		| 
						 | 
				
			
			@ -51,6 +51,7 @@ typedef struct {
 | 
			
		|||
} MemId;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
  SpaList link;
 | 
			
		||||
  uint32_t id;
 | 
			
		||||
  bool used;
 | 
			
		||||
  void *buf_ptr;
 | 
			
		||||
| 
						 | 
				
			
			@ -72,8 +73,6 @@ typedef struct
 | 
			
		|||
  uint32_t port_id;
 | 
			
		||||
  uint32_t pending_seq;
 | 
			
		||||
 | 
			
		||||
  PinosStreamFlags flags;
 | 
			
		||||
 | 
			
		||||
  PinosStreamMode mode;
 | 
			
		||||
 | 
			
		||||
  int rtfd;
 | 
			
		||||
| 
						 | 
				
			
			@ -91,6 +90,9 @@ typedef struct
 | 
			
		|||
  PinosArray buffer_ids;
 | 
			
		||||
  bool in_order;
 | 
			
		||||
 | 
			
		||||
  SpaList free;
 | 
			
		||||
  bool in_need_buffer;
 | 
			
		||||
 | 
			
		||||
  int64_t last_ticks;
 | 
			
		||||
  int32_t last_rate;
 | 
			
		||||
  int64_t last_monotonic;
 | 
			
		||||
| 
						 | 
				
			
			@ -130,6 +132,7 @@ clear_buffers (PinosStream *stream)
 | 
			
		|||
  }
 | 
			
		||||
  impl->buffer_ids.size = 0;
 | 
			
		||||
  impl->in_order = true;
 | 
			
		||||
  spa_list_init (&impl->free);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
| 
						 | 
				
			
			@ -230,6 +233,7 @@ pinos_stream_new (PinosContext    *context,
 | 
			
		|||
  pinos_array_init (&impl->buffer_ids, 32);
 | 
			
		||||
  pinos_array_ensure_size (&impl->buffer_ids, sizeof (BufferId) * 64);
 | 
			
		||||
  impl->pending_seq = SPA_ID_INVALID;
 | 
			
		||||
  spa_list_init (&impl->free);
 | 
			
		||||
 | 
			
		||||
  spa_list_insert (&context->stream_list, &this->link);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -255,11 +259,32 @@ unhandle_socket (PinosStream *stream)
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
set_possible_formats (PinosStream *stream,
 | 
			
		||||
                      int          n_possible_formats,
 | 
			
		||||
                      SpaFormat  **possible_formats)
 | 
			
		||||
{
 | 
			
		||||
  PinosStreamImpl *impl = SPA_CONTAINER_OF (stream, PinosStreamImpl, this);
 | 
			
		||||
  int i;
 | 
			
		||||
 | 
			
		||||
  if (impl->possible_formats) {
 | 
			
		||||
    for (i = 0; i < impl->n_possible_formats; i++)
 | 
			
		||||
      free (impl->possible_formats[i]);
 | 
			
		||||
    free (impl->possible_formats);
 | 
			
		||||
    impl->possible_formats = NULL;
 | 
			
		||||
  }
 | 
			
		||||
  impl->n_possible_formats = n_possible_formats;
 | 
			
		||||
  if (n_possible_formats > 0) {
 | 
			
		||||
    impl->possible_formats = malloc (n_possible_formats * sizeof (SpaFormat *));
 | 
			
		||||
    for (i = 0; i < n_possible_formats; i++)
 | 
			
		||||
      impl->possible_formats[i] = spa_format_copy (possible_formats[i]);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
pinos_stream_destroy (PinosStream *stream)
 | 
			
		||||
{
 | 
			
		||||
  PinosStreamImpl *impl = SPA_CONTAINER_OF (stream, PinosStreamImpl, this);
 | 
			
		||||
  int i;
 | 
			
		||||
 | 
			
		||||
  pinos_log_debug ("stream %p: destroy", stream);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -272,12 +297,7 @@ pinos_stream_destroy (PinosStream *stream)
 | 
			
		|||
  if (impl->node_proxy)
 | 
			
		||||
    pinos_signal_remove (&impl->node_proxy_destroy);
 | 
			
		||||
 | 
			
		||||
  if (impl->possible_formats) {
 | 
			
		||||
    for (i = 0; i < impl->n_possible_formats; i++) {
 | 
			
		||||
      free (impl->possible_formats[i]);
 | 
			
		||||
    }
 | 
			
		||||
    free (impl->possible_formats);
 | 
			
		||||
  }
 | 
			
		||||
  set_possible_formats (stream, 0, NULL);
 | 
			
		||||
 | 
			
		||||
  if (impl->format)
 | 
			
		||||
    free (impl->format);
 | 
			
		||||
| 
						 | 
				
			
			@ -332,7 +352,7 @@ add_port_update (PinosStream *stream, uint32_t change_mask)
 | 
			
		|||
                                    change_mask,
 | 
			
		||||
                                    impl->n_possible_formats,
 | 
			
		||||
                                    (const SpaFormat **) impl->possible_formats,
 | 
			
		||||
                                    (const SpaFormat *) impl->format,
 | 
			
		||||
                                    impl->format,
 | 
			
		||||
                                    NULL,
 | 
			
		||||
                                    &impl->port_info);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -357,18 +377,12 @@ send_need_input (PinosStream *stream)
 | 
			
		|||
static inline void
 | 
			
		||||
send_have_output (PinosStream *stream)
 | 
			
		||||
{
 | 
			
		||||
#if 0
 | 
			
		||||
  PinosStreamImpl *impl = SPA_CONTAINER_OF (stream, PinosStreamImpl, this);
 | 
			
		||||
  SpaEventNodeHaveOutput ho;
 | 
			
		||||
  SpaEvent ho = SPA_EVENT_INIT (stream->context->type.event_node.HaveOutput);
 | 
			
		||||
  uint64_t cmd = 1;
 | 
			
		||||
 | 
			
		||||
  pinos_log_debug ("stream %p: have output", stream);
 | 
			
		||||
 | 
			
		||||
  ho.event.type = SPA_EVENT_NODE_HAVE_OUTPUT;
 | 
			
		||||
  ho.event.size = sizeof (ho);
 | 
			
		||||
  pinos_transport_add_event (impl->trans, &ho.event);
 | 
			
		||||
  pinos_transport_add_event (impl->trans, &ho);
 | 
			
		||||
  write (impl->rtfd, &cmd, 8);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
| 
						 | 
				
			
			@ -451,11 +465,13 @@ find_buffer (PinosStream *stream, uint32_t id)
 | 
			
		|||
static inline void
 | 
			
		||||
reuse_buffer (PinosStream *stream, uint32_t id)
 | 
			
		||||
{
 | 
			
		||||
  PinosStreamImpl *impl = SPA_CONTAINER_OF (stream, PinosStreamImpl, this);
 | 
			
		||||
  BufferId *bid;
 | 
			
		||||
 | 
			
		||||
  if ((bid = find_buffer (stream, id)) && bid->used) {
 | 
			
		||||
    pinos_log_trace ("stream %p: reuse buffer %u", stream, id);
 | 
			
		||||
    bid->used = false;
 | 
			
		||||
    spa_list_insert (impl->free.prev, &bid->link);
 | 
			
		||||
    pinos_signal_emit (&stream->new_buffer, stream, id);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -470,8 +486,6 @@ handle_rtnode_event (PinosStream  *stream,
 | 
			
		|||
  if (SPA_EVENT_TYPE (event) == context->type.event_node.HaveOutput) {
 | 
			
		||||
    int i;
 | 
			
		||||
 | 
			
		||||
    pinos_log_trace ("stream %p: have output", stream);
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < impl->trans->area->n_inputs; i++) {
 | 
			
		||||
      SpaPortIO *input = &impl->trans->inputs[i];
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -498,7 +512,9 @@ handle_rtnode_event (PinosStream  *stream,
 | 
			
		|||
      output->buffer_id = SPA_ID_INVALID;
 | 
			
		||||
    }
 | 
			
		||||
    pinos_log_trace ("stream %p: need input", stream);
 | 
			
		||||
    impl->in_need_buffer = true;
 | 
			
		||||
    pinos_signal_emit (&stream->need_buffer, stream);
 | 
			
		||||
    impl->in_need_buffer = false;
 | 
			
		||||
  }
 | 
			
		||||
  else if (SPA_EVENT_TYPE (event) == context->type.event_node.ReuseBuffer) {
 | 
			
		||||
    SpaEventNodeReuseBuffer *p = (SpaEventNodeReuseBuffer *) event;
 | 
			
		||||
| 
						 | 
				
			
			@ -607,8 +623,11 @@ handle_node_command (PinosStream      *stream,
 | 
			
		|||
 | 
			
		||||
    if (impl->direction == SPA_DIRECTION_INPUT)
 | 
			
		||||
      send_need_input (stream);
 | 
			
		||||
    else
 | 
			
		||||
    else {
 | 
			
		||||
      impl->in_need_buffer = true;
 | 
			
		||||
      pinos_signal_emit (&stream->need_buffer, stream);
 | 
			
		||||
      impl->in_need_buffer = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    stream_set_state (stream, PINOS_STREAM_STATE_STREAMING, NULL);
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -773,7 +792,13 @@ client_node_use_buffers (void                  *object,
 | 
			
		|||
    }
 | 
			
		||||
    len = pinos_array_get_len (&impl->buffer_ids, BufferId);
 | 
			
		||||
    bid = pinos_array_add (&impl->buffer_ids, sizeof (BufferId));
 | 
			
		||||
    if (impl->direction == SPA_DIRECTION_OUTPUT) {
 | 
			
		||||
      bid->used = false;
 | 
			
		||||
      spa_list_insert (impl->free.prev, &bid->link);
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
      bid->used = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    b = buffers[i].buffer;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -926,7 +951,8 @@ on_node_proxy_destroy (PinosListener *listener,
 | 
			
		|||
 * @mode: a #PinosStreamMode
 | 
			
		||||
 * @port_path: the port path to connect to or %NULL to get the default port
 | 
			
		||||
 * @flags: a #PinosStreamFlags
 | 
			
		||||
 * @possible_formats: (transfer full): a #GPtrArray with possible accepted formats
 | 
			
		||||
 * @n_possible_formats: number of items in @possible_formats
 | 
			
		||||
 * @possible_formats: an array with possible accepted formats
 | 
			
		||||
 *
 | 
			
		||||
 * Connect @stream for input or output on @port_path.
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			@ -951,10 +977,7 @@ pinos_stream_connect (PinosStream      *stream,
 | 
			
		|||
  impl->port_id = 0;
 | 
			
		||||
  impl->mode = mode;
 | 
			
		||||
 | 
			
		||||
  impl->flags = flags;
 | 
			
		||||
 | 
			
		||||
  impl->n_possible_formats = n_possible_formats;
 | 
			
		||||
  impl->possible_formats = possible_formats;
 | 
			
		||||
  set_possible_formats (stream, n_possible_formats, possible_formats);
 | 
			
		||||
 | 
			
		||||
  stream_set_state (stream, PINOS_STREAM_STATE_CONNECTING, NULL);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -963,6 +986,9 @@ pinos_stream_connect (PinosStream      *stream,
 | 
			
		|||
  if (port_path)
 | 
			
		||||
    pinos_properties_set (stream->properties,
 | 
			
		||||
                          "pinos.target.node", port_path);
 | 
			
		||||
  if (flags & PINOS_STREAM_FLAG_AUTOCONNECT)
 | 
			
		||||
    pinos_properties_set (stream->properties,
 | 
			
		||||
                          "pinos.autoconnect", "1");
 | 
			
		||||
 | 
			
		||||
  impl->node_proxy = pinos_proxy_new (stream->context,
 | 
			
		||||
                                      SPA_ID_INVALID,
 | 
			
		||||
| 
						 | 
				
			
			@ -1028,34 +1054,6 @@ pinos_stream_finish_format (PinosStream     *stream,
 | 
			
		|||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * pinos_stream_start:
 | 
			
		||||
 * @stream: a #PinosStream
 | 
			
		||||
 *
 | 
			
		||||
 * Start capturing from @stream.
 | 
			
		||||
 *
 | 
			
		||||
 * Returns: %true on success.
 | 
			
		||||
 */
 | 
			
		||||
bool
 | 
			
		||||
pinos_stream_start (PinosStream     *stream)
 | 
			
		||||
{
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * pinos_stream_stop:
 | 
			
		||||
 * @stream: a #PinosStream
 | 
			
		||||
 *
 | 
			
		||||
 * Stop capturing from @stream.
 | 
			
		||||
 *
 | 
			
		||||
 * Returns: %true on success.
 | 
			
		||||
 */
 | 
			
		||||
bool
 | 
			
		||||
pinos_stream_stop (PinosStream *stream)
 | 
			
		||||
{
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * pinos_stream_disconnect:
 | 
			
		||||
 * @stream: a #PinosStream
 | 
			
		||||
| 
						 | 
				
			
			@ -1111,11 +1109,12 @@ pinos_stream_get_empty_buffer (PinosStream *stream)
 | 
			
		|||
  PinosStreamImpl *impl = SPA_CONTAINER_OF (stream, PinosStreamImpl, this);
 | 
			
		||||
  BufferId *bid;
 | 
			
		||||
 | 
			
		||||
  pinos_array_for_each (bid, &impl->buffer_ids) {
 | 
			
		||||
    if (!bid->used)
 | 
			
		||||
      return bid->id;
 | 
			
		||||
  }
 | 
			
		||||
  if (spa_list_is_empty (&impl->free))
 | 
			
		||||
    return SPA_ID_INVALID;
 | 
			
		||||
 | 
			
		||||
  bid = spa_list_first (&impl->free, BufferId, link);
 | 
			
		||||
 | 
			
		||||
  return bid->id;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -1134,8 +1133,15 @@ pinos_stream_recycle_buffer (PinosStream *stream,
 | 
			
		|||
  PinosStreamImpl *impl = SPA_CONTAINER_OF (stream, PinosStreamImpl, this);
 | 
			
		||||
  SpaEventNodeReuseBuffer rb = SPA_EVENT_NODE_REUSE_BUFFER_INIT (stream->context->type.event_node.ReuseBuffer,
 | 
			
		||||
                                                                 impl->port_id, id);
 | 
			
		||||
  BufferId *bid;
 | 
			
		||||
  uint64_t cmd = 1;
 | 
			
		||||
 | 
			
		||||
  if ((bid = find_buffer (stream, id)) == NULL || !bid->used)
 | 
			
		||||
    return false;
 | 
			
		||||
 | 
			
		||||
  bid->used = false;
 | 
			
		||||
  spa_list_insert (impl->free.prev, &bid->link);
 | 
			
		||||
 | 
			
		||||
  pinos_transport_add_event (impl->trans, (SpaEvent *)&rb);
 | 
			
		||||
  write (impl->rtfd, &cmd, 8);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1192,9 +1198,11 @@ pinos_stream_send_buffer (PinosStream     *stream,
 | 
			
		|||
 | 
			
		||||
  if ((bid = find_buffer (stream, id)) && !bid->used) {
 | 
			
		||||
    bid->used = true;
 | 
			
		||||
    spa_list_remove (&bid->link);
 | 
			
		||||
    impl->trans->outputs[0].buffer_id = id;
 | 
			
		||||
    impl->trans->outputs[0].status = SPA_RESULT_HAVE_OUTPUT;
 | 
			
		||||
    pinos_log_trace ("stream %p: send buffer %d", stream, id);
 | 
			
		||||
    if (!impl->in_need_buffer)
 | 
			
		||||
      send_have_output (stream);
 | 
			
		||||
  } else {
 | 
			
		||||
    pinos_log_debug ("stream %p: output %u was used", stream, id);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -115,11 +115,6 @@ bool             pinos_stream_finish_format     (PinosStream     *stream,
 | 
			
		|||
                                                 SpaAllocParam  **params,
 | 
			
		||||
                                                 uint32_t         n_params);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool             pinos_stream_start             (PinosStream     *stream);
 | 
			
		||||
bool             pinos_stream_stop              (PinosStream     *stream);
 | 
			
		||||
 | 
			
		||||
bool             pinos_stream_get_time          (PinosStream     *stream,
 | 
			
		||||
                                                 PinosTime       *time);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -48,6 +48,8 @@ pinos_type_init (PinosType *type)
 | 
			
		|||
  type->spa_node = spa_type_map_get_id (type->map, SPA_TYPE__Node);
 | 
			
		||||
  type->spa_clock = spa_type_map_get_id (type->map, SPA_TYPE__Clock);
 | 
			
		||||
  type->spa_monitor = spa_type_map_get_id (type->map, SPA_TYPE__Monitor);
 | 
			
		||||
  type->spa_format = spa_type_map_get_id (type->map, SPA_TYPE__Format);
 | 
			
		||||
  type->spa_props = spa_type_map_get_id (type->map, SPA_TYPE__Props);
 | 
			
		||||
 | 
			
		||||
  spa_type_event_node_map (type->map, &type->event_node);
 | 
			
		||||
  spa_type_command_node_map (type->map, &type->command_node);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -53,6 +53,8 @@ struct _PinosType {
 | 
			
		|||
  SpaType spa_node;
 | 
			
		||||
  SpaType spa_clock;
 | 
			
		||||
  SpaType spa_monitor;
 | 
			
		||||
  SpaType spa_format;
 | 
			
		||||
  SpaType spa_props;
 | 
			
		||||
 | 
			
		||||
  SpaTypeEventNode event_node;
 | 
			
		||||
  SpaTypeCommandNode command_node;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										5
									
								
								pinos/examples/meson.build
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								pinos/examples/meson.build
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
executable('video-src',
 | 
			
		||||
  'video-src.c',
 | 
			
		||||
  install: false,
 | 
			
		||||
  dependencies : [pinos_dep],
 | 
			
		||||
)
 | 
			
		||||
							
								
								
									
										272
									
								
								pinos/examples/video-src.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										272
									
								
								pinos/examples/video-src.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,272 @@
 | 
			
		|||
/* Pinos
 | 
			
		||||
 * Copyright (C) 2017 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <sys/mman.h>
 | 
			
		||||
 | 
			
		||||
#include <spa/include/spa/type-map.h>
 | 
			
		||||
#include <spa/include/spa/format-utils.h>
 | 
			
		||||
#include <spa/include/spa/video/format-utils.h>
 | 
			
		||||
#include <spa/include/spa/format-builder.h>
 | 
			
		||||
#include <spa/include/spa/props.h>
 | 
			
		||||
 | 
			
		||||
#include <pinos/client/pinos.h>
 | 
			
		||||
#include <pinos/client/sig.h>
 | 
			
		||||
#include <spa/lib/debug.h>
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
  uint32_t format;
 | 
			
		||||
  uint32_t props;
 | 
			
		||||
  SpaTypeMediaType media_type;
 | 
			
		||||
  SpaTypeMediaSubtype media_subtype;
 | 
			
		||||
  SpaTypeFormatVideo format_video;
 | 
			
		||||
  SpaTypeVideoFormat video_format;
 | 
			
		||||
} Type;
 | 
			
		||||
 | 
			
		||||
static inline void
 | 
			
		||||
init_type (Type *type, SpaTypeMap *map)
 | 
			
		||||
{
 | 
			
		||||
  type->format = spa_type_map_get_id (map, SPA_TYPE__Format);
 | 
			
		||||
  type->props = spa_type_map_get_id (map, SPA_TYPE__Props);
 | 
			
		||||
  spa_type_media_type_map (map, &type->media_type);
 | 
			
		||||
  spa_type_media_subtype_map (map, &type->media_subtype);
 | 
			
		||||
  spa_type_format_video_map (map, &type->format_video);
 | 
			
		||||
  spa_type_video_format_map (map, &type->video_format);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define WIDTH 320
 | 
			
		||||
#define HEIGHT 240
 | 
			
		||||
#define BPP    3
 | 
			
		||||
#define STRIDE (BPP * WIDTH)
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
  Type type;
 | 
			
		||||
 | 
			
		||||
  bool running;
 | 
			
		||||
  PinosLoop *loop;
 | 
			
		||||
  SpaSource *timer;
 | 
			
		||||
 | 
			
		||||
  PinosContext *context;
 | 
			
		||||
  PinosListener on_state_changed;
 | 
			
		||||
 | 
			
		||||
  PinosStream *stream;
 | 
			
		||||
  PinosListener on_stream_state_changed;
 | 
			
		||||
  PinosListener on_stream_format_changed;
 | 
			
		||||
 | 
			
		||||
  uint8_t params_buffer[1024];
 | 
			
		||||
  int counter;
 | 
			
		||||
} Data;
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
on_timeout (SpaLoopUtils *utils,
 | 
			
		||||
            SpaSource    *source,
 | 
			
		||||
            void         *userdata)
 | 
			
		||||
{
 | 
			
		||||
  Data *data = userdata;
 | 
			
		||||
  uint32_t id;
 | 
			
		||||
  SpaBuffer *buf;
 | 
			
		||||
  int i, j;
 | 
			
		||||
  uint8_t *p, *map;
 | 
			
		||||
 | 
			
		||||
  id = pinos_stream_get_empty_buffer (data->stream);
 | 
			
		||||
  if (id == SPA_ID_INVALID)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  buf = pinos_stream_peek_buffer (data->stream, id);
 | 
			
		||||
 | 
			
		||||
  if (buf->datas[0].type == SPA_DATA_TYPE_MEMFD) {
 | 
			
		||||
    map = mmap (NULL, buf->datas[0].maxsize + buf->datas[0].mapoffset, PROT_READ | PROT_WRITE,
 | 
			
		||||
                    MAP_SHARED, buf->datas[0].fd, 0);
 | 
			
		||||
    p = SPA_MEMBER (map, buf->datas[0].mapoffset, uint8_t);
 | 
			
		||||
  }
 | 
			
		||||
  else if (buf->datas[0].type == SPA_DATA_TYPE_MEMPTR) {
 | 
			
		||||
    map = NULL;
 | 
			
		||||
    p = buf->datas[0].data;
 | 
			
		||||
  } else
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < HEIGHT; i++) {
 | 
			
		||||
    for (j = 0; j < WIDTH * BPP; j++) {
 | 
			
		||||
      p[j] = data->counter + j * i;
 | 
			
		||||
    }
 | 
			
		||||
    p += STRIDE;
 | 
			
		||||
    data->counter += 13;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (map)
 | 
			
		||||
    munmap (map, buf->datas[0].maxsize);
 | 
			
		||||
 | 
			
		||||
  pinos_stream_send_buffer (data->stream, id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
on_stream_state_changed (PinosListener  *listener,
 | 
			
		||||
                         PinosStream    *stream)
 | 
			
		||||
{
 | 
			
		||||
  Data *data = SPA_CONTAINER_OF (listener, Data, on_stream_state_changed);
 | 
			
		||||
 | 
			
		||||
  printf ("stream state: \"%s\"\n", pinos_stream_state_as_string (stream->state));
 | 
			
		||||
 | 
			
		||||
  switch (stream->state) {
 | 
			
		||||
    case PINOS_STREAM_STATE_PAUSED:
 | 
			
		||||
      pinos_loop_update_timer (data->loop,
 | 
			
		||||
                               data->timer,
 | 
			
		||||
                               NULL,
 | 
			
		||||
                               NULL,
 | 
			
		||||
                               false);
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case PINOS_STREAM_STATE_STREAMING:
 | 
			
		||||
    {
 | 
			
		||||
      struct timespec timeout, interval;
 | 
			
		||||
 | 
			
		||||
      timeout.tv_sec = 0;
 | 
			
		||||
      timeout.tv_nsec = 1;
 | 
			
		||||
      interval.tv_sec = 0;
 | 
			
		||||
      interval.tv_nsec = 40 * SPA_NSEC_PER_MSEC;
 | 
			
		||||
 | 
			
		||||
      pinos_loop_update_timer (data->loop,
 | 
			
		||||
                               data->timer,
 | 
			
		||||
                               &timeout,
 | 
			
		||||
                               &interval,
 | 
			
		||||
                               false);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    default:
 | 
			
		||||
      break;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define PROP(f,key,type,...)                                                    \
 | 
			
		||||
          SPA_POD_PROP (f,key,0,type,1,__VA_ARGS__)
 | 
			
		||||
#define PROP_U_MM(f,key,type,...)                                               \
 | 
			
		||||
          SPA_POD_PROP (f,key,SPA_POD_PROP_FLAG_UNSET |                         \
 | 
			
		||||
                              SPA_POD_PROP_RANGE_MIN_MAX,type,3,__VA_ARGS__)
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
on_stream_format_changed (PinosListener  *listener,
 | 
			
		||||
                          PinosStream    *stream,
 | 
			
		||||
                          SpaFormat      *format)
 | 
			
		||||
{
 | 
			
		||||
  Data *data = SPA_CONTAINER_OF (listener, Data, on_stream_format_changed);
 | 
			
		||||
  PinosContext *ctx = stream->context;
 | 
			
		||||
  SpaPODBuilder b = { NULL };
 | 
			
		||||
  SpaPODFrame f[2];
 | 
			
		||||
  SpaAllocParam *params[2];
 | 
			
		||||
 | 
			
		||||
  spa_pod_builder_init (&b, data->params_buffer, sizeof (data->params_buffer));
 | 
			
		||||
  spa_pod_builder_object (&b, &f[0], 0, ctx->type.alloc_param_buffers.Buffers,
 | 
			
		||||
      PROP      (&f[1], ctx->type.alloc_param_buffers.size,    SPA_POD_TYPE_INT, STRIDE * HEIGHT),
 | 
			
		||||
      PROP      (&f[1], ctx->type.alloc_param_buffers.stride,  SPA_POD_TYPE_INT, STRIDE),
 | 
			
		||||
      PROP_U_MM (&f[1], ctx->type.alloc_param_buffers.buffers, SPA_POD_TYPE_INT, 32, 2, 32),
 | 
			
		||||
      PROP      (&f[1], ctx->type.alloc_param_buffers.align,   SPA_POD_TYPE_INT, 16));
 | 
			
		||||
  params[0] = SPA_POD_BUILDER_DEREF (&b, f[0].ref, SpaAllocParam);
 | 
			
		||||
 | 
			
		||||
  spa_pod_builder_object (&b, &f[0], 0, ctx->type.alloc_param_meta_enable.MetaEnable,
 | 
			
		||||
    PROP      (&f[1], ctx->type.alloc_param_meta_enable.type, SPA_POD_TYPE_INT, SPA_META_TYPE_HEADER));
 | 
			
		||||
  params[1] = SPA_POD_BUILDER_DEREF (&b, f[0].ref, SpaAllocParam);
 | 
			
		||||
 | 
			
		||||
  pinos_stream_finish_format (stream, SPA_RESULT_OK, params, 2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
on_state_changed (PinosListener  *listener,
 | 
			
		||||
                  PinosContext   *context)
 | 
			
		||||
{
 | 
			
		||||
  Data *data = SPA_CONTAINER_OF (listener, Data, on_state_changed);
 | 
			
		||||
 | 
			
		||||
  switch (context->state) {
 | 
			
		||||
    case PINOS_CONTEXT_STATE_ERROR:
 | 
			
		||||
      printf ("context error: %s\n", context->error);
 | 
			
		||||
      data->running = false;
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case PINOS_CONTEXT_STATE_CONNECTED:
 | 
			
		||||
    {
 | 
			
		||||
      SpaFormat *formats[1];
 | 
			
		||||
      uint8_t buffer[1024];
 | 
			
		||||
      SpaPODBuilder b = SPA_POD_BUILDER_INIT (buffer, sizeof (buffer));
 | 
			
		||||
      SpaPODFrame f[2];
 | 
			
		||||
 | 
			
		||||
      printf ("context state: \"%s\"\n", pinos_context_state_as_string (context->state));
 | 
			
		||||
 | 
			
		||||
      data->stream = pinos_stream_new (context, "video-src", NULL);
 | 
			
		||||
 | 
			
		||||
      spa_pod_builder_format (&b, &f[0], data->type.format,
 | 
			
		||||
         data->type.media_type.video, data->type.media_subtype.raw,
 | 
			
		||||
         PROP (&f[1], data->type.format_video.format,    SPA_POD_TYPE_ID,  data->type.video_format.RGB),
 | 
			
		||||
         PROP (&f[1], data->type.format_video.size,      SPA_POD_TYPE_RECTANGLE, WIDTH, HEIGHT),
 | 
			
		||||
         PROP (&f[1], data->type.format_video.framerate, SPA_POD_TYPE_FRACTION,  25, 1));
 | 
			
		||||
 | 
			
		||||
      formats[0] = SPA_POD_BUILDER_DEREF (&b, f[0].ref, SpaFormat);
 | 
			
		||||
 | 
			
		||||
      pinos_signal_add (&data->stream->state_changed,
 | 
			
		||||
                        &data->on_stream_state_changed,
 | 
			
		||||
                        on_stream_state_changed);
 | 
			
		||||
      pinos_signal_add (&data->stream->format_changed,
 | 
			
		||||
                        &data->on_stream_format_changed,
 | 
			
		||||
                        on_stream_format_changed);
 | 
			
		||||
 | 
			
		||||
      pinos_stream_connect (data->stream,
 | 
			
		||||
                            PINOS_DIRECTION_OUTPUT,
 | 
			
		||||
                            PINOS_STREAM_MODE_BUFFER,
 | 
			
		||||
                            NULL,
 | 
			
		||||
                            PINOS_STREAM_FLAG_NONE,
 | 
			
		||||
                            1,
 | 
			
		||||
                            formats);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    default:
 | 
			
		||||
      printf ("context state: \"%s\"\n", pinos_context_state_as_string (context->state));
 | 
			
		||||
      break;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
main (int argc, char *argv[])
 | 
			
		||||
{
 | 
			
		||||
  Data data = { 0, };
 | 
			
		||||
 | 
			
		||||
  pinos_init (&argc, &argv);
 | 
			
		||||
 | 
			
		||||
  data.loop = pinos_loop_new ();
 | 
			
		||||
  data.running = true;
 | 
			
		||||
  data.context = pinos_context_new (data.loop, "video-src", NULL);
 | 
			
		||||
 | 
			
		||||
  init_type (&data.type, data.context->type.map);
 | 
			
		||||
 | 
			
		||||
  data.timer = pinos_loop_add_timer (data.loop, on_timeout, &data);
 | 
			
		||||
 | 
			
		||||
  pinos_signal_add (&data.context->state_changed,
 | 
			
		||||
                    &data.on_state_changed,
 | 
			
		||||
                    on_state_changed);
 | 
			
		||||
 | 
			
		||||
  pinos_context_connect (data.context);
 | 
			
		||||
 | 
			
		||||
  pinos_loop_enter (data.loop);
 | 
			
		||||
  while (data.running) {
 | 
			
		||||
    pinos_loop_iterate (data.loop, -1);
 | 
			
		||||
  }
 | 
			
		||||
  pinos_loop_leave (data.loop);
 | 
			
		||||
 | 
			
		||||
  pinos_context_destroy (data.context);
 | 
			
		||||
  pinos_loop_destroy (data.loop);
 | 
			
		||||
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -140,6 +140,19 @@ static const uint32_t *video_format_map[] = {
 | 
			
		|||
  &type.video_format.P010_10LE,
 | 
			
		||||
  &type.video_format.IYU2,
 | 
			
		||||
  &type.video_format.VYUY,
 | 
			
		||||
  &type.video_format.GBRA,
 | 
			
		||||
  &type.video_format.GBRA_10BE,
 | 
			
		||||
  &type.video_format.GBRA_10LE,
 | 
			
		||||
  &type.video_format.GBR_12BE,
 | 
			
		||||
  &type.video_format.GBR_12LE,
 | 
			
		||||
  &type.video_format.GBRA_12BE,
 | 
			
		||||
  &type.video_format.GBRA_12LE,
 | 
			
		||||
  &type.video_format.I420_12BE,
 | 
			
		||||
  &type.video_format.I420_12LE,
 | 
			
		||||
  &type.video_format.I422_12BE,
 | 
			
		||||
  &type.video_format.I422_12LE,
 | 
			
		||||
  &type.video_format.Y444_12BE,
 | 
			
		||||
  &type.video_format.Y444_12LE,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#if __BYTE_ORDER == __BIG_ENDIAN
 | 
			
		||||
| 
						 | 
				
			
			@ -367,13 +380,16 @@ handle_video_fields (ConvertData *d)
 | 
			
		|||
  value = gst_structure_get_value (d->cs, "format");
 | 
			
		||||
  if (value) {
 | 
			
		||||
    const char *v;
 | 
			
		||||
    int idx;
 | 
			
		||||
    for (i = 0; (v = get_nth_string (value, i)); i++) {
 | 
			
		||||
      if (i == 0)
 | 
			
		||||
        spa_pod_builder_push_prop (&d->b, &f,
 | 
			
		||||
                                   type.format_video.format,
 | 
			
		||||
                                   get_range_type (value));
 | 
			
		||||
 | 
			
		||||
      spa_pod_builder_id (&d->b, *video_format_map[gst_video_format_from_string (v)]);
 | 
			
		||||
      idx = gst_video_format_from_string (v);
 | 
			
		||||
      if (idx < SPA_N_ELEMENTS (video_format_map))
 | 
			
		||||
        spa_pod_builder_id (&d->b, *video_format_map[idx]);
 | 
			
		||||
    }
 | 
			
		||||
    if (i > 1)
 | 
			
		||||
      SPA_POD_BUILDER_DEREF (&d->b, f.ref, SpaPODProp)->body.flags |= SPA_POD_PROP_FLAG_UNSET;
 | 
			
		||||
| 
						 | 
				
			
			@ -424,13 +440,16 @@ handle_audio_fields (ConvertData *d)
 | 
			
		|||
  value = gst_structure_get_value (d->cs, "format");
 | 
			
		||||
  if (value) {
 | 
			
		||||
    const char *v;
 | 
			
		||||
    int idx;
 | 
			
		||||
    for (i = 0; (v = get_nth_string (value, i)); i++) {
 | 
			
		||||
      if (i == 0)
 | 
			
		||||
        spa_pod_builder_push_prop (&d->b, &f,
 | 
			
		||||
                                   type.format_audio.format,
 | 
			
		||||
                                   get_range_type (value));
 | 
			
		||||
 | 
			
		||||
      spa_pod_builder_id (&d->b, *audio_format_map[gst_audio_format_from_string (v)]);
 | 
			
		||||
      idx = gst_audio_format_from_string (v);
 | 
			
		||||
      if (idx < SPA_N_ELEMENTS (audio_format_map))
 | 
			
		||||
        spa_pod_builder_id (&d->b, *audio_format_map[idx]);
 | 
			
		||||
    }
 | 
			
		||||
    if (i > 1)
 | 
			
		||||
      SPA_POD_BUILDER_DEREF (&d->b, f.ref, SpaPODProp)->body.flags |= SPA_POD_PROP_FLAG_UNSET;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -777,7 +777,6 @@ gst_pinos_sink_stop (GstBaseSink * basesink)
 | 
			
		|||
 | 
			
		||||
  pinos_thread_main_loop_lock (pinossink->main_loop);
 | 
			
		||||
  if (pinossink->stream) {
 | 
			
		||||
    pinos_stream_stop (pinossink->stream);
 | 
			
		||||
    pinos_stream_disconnect (pinossink->stream);
 | 
			
		||||
    pinos_stream_destroy (pinossink->stream);
 | 
			
		||||
    pinossink->stream = NULL;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -571,11 +571,8 @@ parse_stream_properties (GstPinosSrc *pinossrc, PinosProperties *props)
 | 
			
		|||
static gboolean
 | 
			
		||||
gst_pinos_src_stream_start (GstPinosSrc *pinossrc)
 | 
			
		||||
{
 | 
			
		||||
  gboolean res;
 | 
			
		||||
 | 
			
		||||
  pinos_thread_main_loop_lock (pinossrc->main_loop);
 | 
			
		||||
  GST_DEBUG_OBJECT (pinossrc, "doing stream start");
 | 
			
		||||
  res = pinos_stream_start (pinossrc->stream);
 | 
			
		||||
  while (TRUE) {
 | 
			
		||||
    PinosStreamState state = pinossrc->stream->state;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -601,7 +598,7 @@ gst_pinos_src_stream_start (GstPinosSrc *pinossrc)
 | 
			
		|||
  pinos_thread_main_loop_signal (pinossrc->main_loop, FALSE);
 | 
			
		||||
  pinos_thread_main_loop_unlock (pinossrc->main_loop);
 | 
			
		||||
 | 
			
		||||
  return res;
 | 
			
		||||
  return TRUE;
 | 
			
		||||
 | 
			
		||||
start_error:
 | 
			
		||||
  {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,3 +6,4 @@ subdir('daemon')
 | 
			
		|||
subdir('tools')
 | 
			
		||||
subdir('modules')
 | 
			
		||||
subdir('gst')
 | 
			
		||||
subdir('examples')
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -177,7 +177,7 @@ try_link_port (PinosNode *node,
 | 
			
		|||
{
 | 
			
		||||
  ModuleImpl *impl = info->impl;
 | 
			
		||||
  PinosProperties *props;
 | 
			
		||||
  const char *path;
 | 
			
		||||
  const char *str;
 | 
			
		||||
  uint32_t path_id;
 | 
			
		||||
  char *error = NULL;
 | 
			
		||||
  PinosLink *link;
 | 
			
		||||
| 
						 | 
				
			
			@ -189,13 +189,19 @@ try_link_port (PinosNode *node,
 | 
			
		|||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  path = pinos_properties_get (props, "pinos.target.node");
 | 
			
		||||
  if (path == NULL)
 | 
			
		||||
  str = pinos_properties_get (props, "pinos.target.node");
 | 
			
		||||
  if (str != NULL)
 | 
			
		||||
    path_id = atoi (str);
 | 
			
		||||
  else {
 | 
			
		||||
    str = pinos_properties_get (props, "pinos.autoconnect");
 | 
			
		||||
    if (str == NULL || atoi (str) == 0) {
 | 
			
		||||
      pinos_log_debug ("module %p: node does not need autoconnect", impl);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    path_id = SPA_ID_INVALID;
 | 
			
		||||
  else
 | 
			
		||||
    path_id = atoi (path);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  pinos_log_debug ("module %p: try to find and link to node '%s'", impl, path);
 | 
			
		||||
  pinos_log_debug ("module %p: try to find and link to node '%d'", impl, path_id);
 | 
			
		||||
 | 
			
		||||
  target = pinos_core_find_port (impl->core,
 | 
			
		||||
                                 port,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -159,26 +159,31 @@ spa_proxy_node_set_props (SpaNode         *node,
 | 
			
		|||
  return SPA_RESULT_NOT_IMPLEMENTED;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
static inline void
 | 
			
		||||
do_flush (SpaProxy *this)
 | 
			
		||||
{
 | 
			
		||||
  uint64_t cmd = 1;
 | 
			
		||||
  write (this->data_source.fd, &cmd, 8);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void
 | 
			
		||||
send_need_input (SpaProxy *this)
 | 
			
		||||
{
 | 
			
		||||
  PinosClientNodeImpl *impl = SPA_CONTAINER_OF (this, PinosClientNodeImpl, proxy);
 | 
			
		||||
  SpaEvent event = SPA_EVENT_INIT (impl->core->type.event_node.NeedInput);
 | 
			
		||||
  uint64_t cmd = 1;
 | 
			
		||||
 | 
			
		||||
  pinos_transport_add_event (impl->transport, &event);
 | 
			
		||||
  write (this->data_source.fd, &cmd, 8);
 | 
			
		||||
  do_flush (this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
static inline void
 | 
			
		||||
send_have_output (SpaProxy *this)
 | 
			
		||||
{
 | 
			
		||||
  PinosClientNodeImpl *impl = SPA_CONTAINER_OF (this, PinosClientNodeImpl, proxy);
 | 
			
		||||
  SpaEvent event = SPA_EVENT_INIT (impl->core->type.event_node.HaveOutput);
 | 
			
		||||
  uint64_t cmd = 1;
 | 
			
		||||
 | 
			
		||||
  pinos_transport_add_event (impl->transport, &event);
 | 
			
		||||
  write (this->data_source.fd, &cmd, 8);
 | 
			
		||||
  do_flush (this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static SpaResult
 | 
			
		||||
| 
						 | 
				
			
			@ -808,6 +813,8 @@ spa_proxy_node_process_input (SpaNode *node)
 | 
			
		|||
    if (!io)
 | 
			
		||||
      continue;
 | 
			
		||||
 | 
			
		||||
    pinos_log_trace ("%d %d", io->status, io->buffer_id);
 | 
			
		||||
 | 
			
		||||
    impl->transport->inputs[i] = *io;
 | 
			
		||||
    io->status = SPA_RESULT_OK;
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -822,7 +829,7 @@ spa_proxy_node_process_output (SpaNode *node)
 | 
			
		|||
  SpaProxy *this;
 | 
			
		||||
  PinosClientNodeImpl *impl;
 | 
			
		||||
  int i;
 | 
			
		||||
  bool send_need = false;
 | 
			
		||||
  bool send_need = false, flush = false;
 | 
			
		||||
 | 
			
		||||
  if (node == NULL)
 | 
			
		||||
    return SPA_RESULT_INVALID_ARGUMENTS;
 | 
			
		||||
| 
						 | 
				
			
			@ -844,6 +851,7 @@ spa_proxy_node_process_output (SpaNode *node)
 | 
			
		|||
 | 
			
		||||
      pinos_transport_add_event (impl->transport, (SpaEvent *)&rb);
 | 
			
		||||
      io->buffer_id = SPA_ID_INVALID;
 | 
			
		||||
      flush = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    tmp = impl->transport->outputs[i];
 | 
			
		||||
| 
						 | 
				
			
			@ -858,6 +866,8 @@ spa_proxy_node_process_output (SpaNode *node)
 | 
			
		|||
  }
 | 
			
		||||
  if (send_need)
 | 
			
		||||
    send_need_input (this);
 | 
			
		||||
  else if (flush)
 | 
			
		||||
    do_flush (this);
 | 
			
		||||
 | 
			
		||||
  return SPA_RESULT_HAVE_OUTPUT;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -866,6 +876,20 @@ static SpaResult
 | 
			
		|||
handle_node_event (SpaProxy *this,
 | 
			
		||||
                   SpaEvent *event)
 | 
			
		||||
{
 | 
			
		||||
  PinosClientNodeImpl *impl = SPA_CONTAINER_OF (this, PinosClientNodeImpl, proxy);
 | 
			
		||||
  int i;
 | 
			
		||||
 | 
			
		||||
  if (SPA_EVENT_TYPE (event) == impl->core->type.event_node.HaveOutput) {
 | 
			
		||||
    for (i = 0; i < MAX_OUTPUTS; i++) {
 | 
			
		||||
      SpaPortIO *io = this->out_ports[i].io;
 | 
			
		||||
 | 
			
		||||
      if (!io)
 | 
			
		||||
        continue;
 | 
			
		||||
 | 
			
		||||
      *io = impl->transport->outputs[i];
 | 
			
		||||
      pinos_log_trace ("%d %d", io->status, io->buffer_id);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  this->event_cb (&this->node, event, this->user_data);
 | 
			
		||||
  return SPA_RESULT_OK;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -333,7 +333,6 @@ on_node_event (SpaNode *node, SpaEvent *event, void *user_data)
 | 
			
		|||
 | 
			
		||||
    spa_list_for_each (outport, &this->output_ports, link) {
 | 
			
		||||
      PinosLink *link;
 | 
			
		||||
      PinosPort *inport;
 | 
			
		||||
      SpaPortIO *po;
 | 
			
		||||
 | 
			
		||||
      po = &outport->io;
 | 
			
		||||
| 
						 | 
				
			
			@ -343,17 +342,22 @@ on_node_event (SpaNode *node, SpaEvent *event, void *user_data)
 | 
			
		|||
      pinos_log_trace ("node %p: have output %d", this, po->buffer_id);
 | 
			
		||||
 | 
			
		||||
      spa_list_for_each (link, &outport->rt.links, rt.output_link) {
 | 
			
		||||
        PinosPort *inport;
 | 
			
		||||
 | 
			
		||||
        if (link->rt.input == NULL || link->rt.output == NULL)
 | 
			
		||||
          continue;
 | 
			
		||||
 | 
			
		||||
        inport = link->rt.input;
 | 
			
		||||
        inport->io = *po;
 | 
			
		||||
 | 
			
		||||
        pinos_log_trace ("node %p: do process input %d", this, po->buffer_id);
 | 
			
		||||
 | 
			
		||||
        if ((res = spa_node_process_input (inport->node->node)) < 0)
 | 
			
		||||
          pinos_log_warn ("node %p: got process input %d", inport->node, res);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    if ((res = spa_node_process_output (this->node)) < 0)
 | 
			
		||||
    res = spa_node_process_output (this->node);
 | 
			
		||||
    if (res < 0 && res != SPA_RESULT_HAVE_OUTPUT)
 | 
			
		||||
      pinos_log_warn ("node %p: got process output %d", this, res);
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -96,6 +96,19 @@ typedef struct
 | 
			
		|||
  uint32_t P010_10LE;
 | 
			
		||||
  uint32_t IYU2;
 | 
			
		||||
  uint32_t VYUY;
 | 
			
		||||
  uint32_t GBRA;
 | 
			
		||||
  uint32_t GBRA_10BE;
 | 
			
		||||
  uint32_t GBRA_10LE;
 | 
			
		||||
  uint32_t GBR_12BE;
 | 
			
		||||
  uint32_t GBR_12LE;
 | 
			
		||||
  uint32_t GBRA_12BE;
 | 
			
		||||
  uint32_t GBRA_12LE;
 | 
			
		||||
  uint32_t I420_12BE;
 | 
			
		||||
  uint32_t I420_12LE;
 | 
			
		||||
  uint32_t I422_12BE;
 | 
			
		||||
  uint32_t I422_12LE;
 | 
			
		||||
  uint32_t Y444_12BE;
 | 
			
		||||
  uint32_t Y444_12LE;
 | 
			
		||||
} SpaTypeVideoFormat;
 | 
			
		||||
 | 
			
		||||
static inline void
 | 
			
		||||
| 
						 | 
				
			
			@ -167,6 +180,19 @@ spa_type_video_format_map (SpaTypeMap *map, SpaTypeVideoFormat *type)
 | 
			
		|||
    type->P010_10LE    = spa_type_map_get_id (map, SPA_TYPE_VIDEO_FORMAT__P010_10LE);
 | 
			
		||||
    type->IYU2         = spa_type_map_get_id (map, SPA_TYPE_VIDEO_FORMAT__IYU2);
 | 
			
		||||
    type->VYUY         = spa_type_map_get_id (map, SPA_TYPE_VIDEO_FORMAT__VYUY);
 | 
			
		||||
    type->GBRA         = spa_type_map_get_id (map, SPA_TYPE_VIDEO_FORMAT__GBRA);
 | 
			
		||||
    type->GBRA_10BE    = spa_type_map_get_id (map, SPA_TYPE_VIDEO_FORMAT__GBRA_10BE);
 | 
			
		||||
    type->GBRA_10LE    = spa_type_map_get_id (map, SPA_TYPE_VIDEO_FORMAT__GBRA_10LE);
 | 
			
		||||
    type->GBR_12BE     = spa_type_map_get_id (map, SPA_TYPE_VIDEO_FORMAT__GBR_12BE);
 | 
			
		||||
    type->GBR_12LE     = spa_type_map_get_id (map, SPA_TYPE_VIDEO_FORMAT__GBR_12LE);
 | 
			
		||||
    type->GBRA_12BE    = spa_type_map_get_id (map, SPA_TYPE_VIDEO_FORMAT__GBRA_12BE);
 | 
			
		||||
    type->GBRA_12LE    = spa_type_map_get_id (map, SPA_TYPE_VIDEO_FORMAT__GBRA_12LE);
 | 
			
		||||
    type->I420_12BE    = spa_type_map_get_id (map, SPA_TYPE_VIDEO_FORMAT__I420_12BE);
 | 
			
		||||
    type->I420_12LE    = spa_type_map_get_id (map, SPA_TYPE_VIDEO_FORMAT__I420_12LE);
 | 
			
		||||
    type->I422_12BE    = spa_type_map_get_id (map, SPA_TYPE_VIDEO_FORMAT__I422_12BE);
 | 
			
		||||
    type->I422_12LE    = spa_type_map_get_id (map, SPA_TYPE_VIDEO_FORMAT__I422_12LE);
 | 
			
		||||
    type->Y444_12BE    = spa_type_map_get_id (map, SPA_TYPE_VIDEO_FORMAT__Y444_12BE);
 | 
			
		||||
    type->Y444_12LE    = spa_type_map_get_id (map, SPA_TYPE_VIDEO_FORMAT__Y444_12LE);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -101,6 +101,19 @@ typedef struct _SpaVideoInfoRaw SpaVideoInfoRaw;
 | 
			
		|||
#define SPA_TYPE_VIDEO_FORMAT__P010_10LE      SPA_TYPE_VIDEO_FORMAT_BASE "P010_10LE"
 | 
			
		||||
#define SPA_TYPE_VIDEO_FORMAT__IYU2           SPA_TYPE_VIDEO_FORMAT_BASE "IYU2"
 | 
			
		||||
#define SPA_TYPE_VIDEO_FORMAT__VYUY           SPA_TYPE_VIDEO_FORMAT_BASE "VYUY"
 | 
			
		||||
#define SPA_TYPE_VIDEO_FORMAT__GBRA           SPA_TYPE_VIDEO_FORMAT_BASE "GBRA"
 | 
			
		||||
#define SPA_TYPE_VIDEO_FORMAT__GBRA_10BE      SPA_TYPE_VIDEO_FORMAT_BASE "GBRA_10BE"
 | 
			
		||||
#define SPA_TYPE_VIDEO_FORMAT__GBRA_10LE      SPA_TYPE_VIDEO_FORMAT_BASE "GBRA_10LE"
 | 
			
		||||
#define SPA_TYPE_VIDEO_FORMAT__GBR_12BE       SPA_TYPE_VIDEO_FORMAT_BASE "GBR_12BE"
 | 
			
		||||
#define SPA_TYPE_VIDEO_FORMAT__GBR_12LE       SPA_TYPE_VIDEO_FORMAT_BASE "GBR_12LE"
 | 
			
		||||
#define SPA_TYPE_VIDEO_FORMAT__GBRA_12BE      SPA_TYPE_VIDEO_FORMAT_BASE "GBRA_12BE"
 | 
			
		||||
#define SPA_TYPE_VIDEO_FORMAT__GBRA_12LE      SPA_TYPE_VIDEO_FORMAT_BASE "GBRA_12LE"
 | 
			
		||||
#define SPA_TYPE_VIDEO_FORMAT__I420_12BE      SPA_TYPE_VIDEO_FORMAT_BASE "I420_12BE"
 | 
			
		||||
#define SPA_TYPE_VIDEO_FORMAT__I420_12LE      SPA_TYPE_VIDEO_FORMAT_BASE "I420_12LE"
 | 
			
		||||
#define SPA_TYPE_VIDEO_FORMAT__I422_12BE      SPA_TYPE_VIDEO_FORMAT_BASE "I422_12BE"
 | 
			
		||||
#define SPA_TYPE_VIDEO_FORMAT__I422_12LE      SPA_TYPE_VIDEO_FORMAT_BASE "I422_12LE"
 | 
			
		||||
#define SPA_TYPE_VIDEO_FORMAT__Y444_12BE      SPA_TYPE_VIDEO_FORMAT_BASE "Y444_12BE"
 | 
			
		||||
#define SPA_TYPE_VIDEO_FORMAT__Y444_12LE      SPA_TYPE_VIDEO_FORMAT_BASE "Y444_12LE"
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * SpaVideoFlags:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue