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:
Wim Taymans 2017-04-18 17:57:04 +02:00
parent c7333c46cc
commit db16de85bb
16 changed files with 466 additions and 93 deletions

View file

@ -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));
bid->used = false;
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;
}
return SPA_ID_INVALID;
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,10 +1198,12 @@ 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);
send_have_output (stream);
if (!impl->in_need_buffer)
send_have_output (stream);
} else {
pinos_log_debug ("stream %p: output %u was used", stream, id);
}

View file

@ -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);

View file

@ -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);

View file

@ -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;

View file

@ -0,0 +1,5 @@
executable('video-src',
'video-src.c',
install: false,
dependencies : [pinos_dep],
)

272
pinos/examples/video-src.c Normal file
View 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;
}

View file

@ -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;

View file

@ -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;

View file

@ -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:
{

View file

@ -6,3 +6,4 @@ subdir('daemon')
subdir('tools')
subdir('modules')
subdir('gst')
subdir('examples')

View file

@ -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,

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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);
}
}

View file

@ -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:

View file

@ -151,16 +151,16 @@ reset_videotestsrc_props (SpaVideoTestSrc *this, SpaVideoTestSrcProps *props)
props->pattern = this->type. DEFAULT_PATTERN;
}
#define PROP(f,key,type,...) \
#define PROP(f,key,type,...) \
SPA_POD_PROP (f,key,0,type,1,__VA_ARGS__)
#define PROP_MM(f,key,type,...) \
#define PROP_MM(f,key,type,...) \
SPA_POD_PROP (f,key,SPA_POD_PROP_RANGE_MIN_MAX,type,3,__VA_ARGS__)
#define PROP_U_MM(f,key,type,...) \
#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__)
#define PROP_EN(f,key,type,n,...) \
#define PROP_EN(f,key,type,n,...) \
SPA_POD_PROP (f,key, SPA_POD_PROP_RANGE_ENUM,type,n,__VA_ARGS__)
#define PROP_U_EN(f,key,type,n,...) \
#define PROP_U_EN(f,key,type,n,...) \
SPA_POD_PROP (f,key,SPA_POD_PROP_FLAG_UNSET | \
SPA_POD_PROP_RANGE_ENUM,type,n,__VA_ARGS__)