mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-31 22:25:38 -04:00
improve node io
Unify input and output io areas. Add support for ranges in the io area. Automatically recycle buffers in the output areas in process_output Improve the mixer, add use_buffer support, use a queue of input buffers, fix mixing, add support for ranges. Fix mixer and v4l2 tests
This commit is contained in:
parent
29fbf2e841
commit
01c13adab5
28 changed files with 983 additions and 747 deletions
|
|
@ -576,9 +576,10 @@ spa_alsa_sink_node_port_alloc_buffers (SpaNode *node,
|
|||
}
|
||||
|
||||
static SpaResult
|
||||
spa_alsa_sink_node_port_set_input (SpaNode *node,
|
||||
uint32_t port_id,
|
||||
SpaPortInput *input)
|
||||
spa_alsa_sink_node_port_set_io (SpaNode *node,
|
||||
SpaDirection direction,
|
||||
uint32_t port_id,
|
||||
SpaPortIO *io)
|
||||
{
|
||||
SpaALSASink *this;
|
||||
|
||||
|
|
@ -587,22 +588,14 @@ spa_alsa_sink_node_port_set_input (SpaNode *node,
|
|||
|
||||
this = SPA_CONTAINER_OF (node, SpaALSASink, node);
|
||||
|
||||
if (!CHECK_PORT (this, SPA_DIRECTION_INPUT, port_id))
|
||||
if (!CHECK_PORT (this, direction, port_id))
|
||||
return SPA_RESULT_INVALID_PORT;
|
||||
|
||||
this->io = input;
|
||||
this->io = io;
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
spa_alsa_sink_node_port_set_output (SpaNode *node,
|
||||
uint32_t port_id,
|
||||
SpaPortOutput *output)
|
||||
{
|
||||
return SPA_RESULT_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
spa_alsa_sink_node_port_reuse_buffer (SpaNode *node,
|
||||
uint32_t port_id,
|
||||
|
|
@ -648,7 +641,7 @@ static SpaResult
|
|||
spa_alsa_sink_node_process_input (SpaNode *node)
|
||||
{
|
||||
SpaALSASink *this;
|
||||
SpaPortInput *input;
|
||||
SpaPortIO *input;
|
||||
SpaALSABuffer *b;
|
||||
|
||||
if (node == NULL)
|
||||
|
|
@ -680,8 +673,8 @@ spa_alsa_sink_node_process_input (SpaNode *node)
|
|||
this->ringbuffer = b;
|
||||
} else {
|
||||
spa_list_insert (this->ready.prev, &b->link);
|
||||
spa_log_trace (this->log, "alsa-sink %p: queue buffer %u", this, input->buffer_id);
|
||||
}
|
||||
//spa_log_debug (this->log, "alsa-source: got buffer %u", input->buffer_id);
|
||||
b->outstanding = false;
|
||||
input->buffer_id = SPA_ID_INVALID;
|
||||
input->status = SPA_RESULT_OK;
|
||||
|
|
@ -716,8 +709,7 @@ static const SpaNode alsasink_node = {
|
|||
spa_alsa_sink_node_port_set_props,
|
||||
spa_alsa_sink_node_port_use_buffers,
|
||||
spa_alsa_sink_node_port_alloc_buffers,
|
||||
spa_alsa_sink_node_port_set_input,
|
||||
spa_alsa_sink_node_port_set_output,
|
||||
spa_alsa_sink_node_port_set_io,
|
||||
spa_alsa_sink_node_port_reuse_buffer,
|
||||
spa_alsa_sink_node_port_send_command,
|
||||
spa_alsa_sink_node_process_input,
|
||||
|
|
@ -779,7 +771,15 @@ alsa_sink_init (const SpaHandleFactory *factory,
|
|||
this->main_loop = support[i].data;
|
||||
}
|
||||
if (this->map == NULL) {
|
||||
spa_log_error (this->log, "an id-map is needed");
|
||||
spa_log_error (this->log, "a type-map is needed");
|
||||
return SPA_RESULT_ERROR;
|
||||
}
|
||||
if (this->data_loop == NULL) {
|
||||
spa_log_error (this->log, "a data loop is needed");
|
||||
return SPA_RESULT_ERROR;
|
||||
}
|
||||
if (this->main_loop == NULL) {
|
||||
spa_log_error (this->log, "a main loop is needed");
|
||||
return SPA_RESULT_ERROR;
|
||||
}
|
||||
init_type (&this->type, this->map);
|
||||
|
|
|
|||
|
|
@ -369,8 +369,7 @@ recycle_buffer (SpaALSASource *this, uint32_t buffer_id)
|
|||
SpaALSABuffer *b;
|
||||
|
||||
b = &this->buffers[buffer_id];
|
||||
if (!b->outstanding)
|
||||
return;
|
||||
spa_return_if_fail (b->outstanding);
|
||||
|
||||
b->outstanding = false;
|
||||
spa_list_insert (this->free.prev, &b->link);
|
||||
|
|
@ -616,17 +615,10 @@ spa_alsa_source_node_port_alloc_buffers (SpaNode *node,
|
|||
}
|
||||
|
||||
static SpaResult
|
||||
spa_alsa_source_node_port_set_input (SpaNode *node,
|
||||
uint32_t port_id,
|
||||
SpaPortInput *input)
|
||||
{
|
||||
return SPA_RESULT_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
spa_alsa_source_node_port_set_output (SpaNode *node,
|
||||
uint32_t port_id,
|
||||
SpaPortOutput *output)
|
||||
spa_alsa_source_node_port_set_io (SpaNode *node,
|
||||
SpaDirection direction,
|
||||
uint32_t port_id,
|
||||
SpaPortIO *io)
|
||||
{
|
||||
SpaALSASource *this;
|
||||
|
||||
|
|
@ -635,10 +627,10 @@ spa_alsa_source_node_port_set_output (SpaNode *node,
|
|||
|
||||
this = SPA_CONTAINER_OF (node, SpaALSASource, node);
|
||||
|
||||
if (!CHECK_PORT (this, SPA_DIRECTION_OUTPUT, port_id))
|
||||
if (!CHECK_PORT (this, direction, port_id))
|
||||
return SPA_RESULT_INVALID_PORT;
|
||||
|
||||
this->io = output;
|
||||
this->io = io;
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
|
@ -710,6 +702,17 @@ spa_alsa_source_node_process_input (SpaNode *node)
|
|||
static SpaResult
|
||||
spa_alsa_source_node_process_output (SpaNode *node)
|
||||
{
|
||||
SpaALSASource *this;
|
||||
SpaPortIO *io;
|
||||
|
||||
spa_return_val_if_fail (node != NULL, SPA_RESULT_INVALID_ARGUMENTS);
|
||||
|
||||
this = SPA_CONTAINER_OF (node, SpaALSASource, node);
|
||||
|
||||
if ((io = this->io) && io->buffer_id != SPA_ID_INVALID) {
|
||||
recycle_buffer (this, io->buffer_id);
|
||||
io->buffer_id = SPA_ID_INVALID;
|
||||
}
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
|
|
@ -733,8 +736,7 @@ static const SpaNode alsasource_node = {
|
|||
spa_alsa_source_node_port_set_props,
|
||||
spa_alsa_source_node_port_use_buffers,
|
||||
spa_alsa_source_node_port_alloc_buffers,
|
||||
spa_alsa_source_node_port_set_input,
|
||||
spa_alsa_source_node_port_set_output,
|
||||
spa_alsa_source_node_port_set_io,
|
||||
spa_alsa_source_node_port_reuse_buffer,
|
||||
spa_alsa_source_node_port_send_command,
|
||||
spa_alsa_source_node_process_input,
|
||||
|
|
@ -847,6 +849,14 @@ alsa_source_init (const SpaHandleFactory *factory,
|
|||
spa_log_error (this->log, "an id-map is needed");
|
||||
return SPA_RESULT_ERROR;
|
||||
}
|
||||
if (this->data_loop == NULL) {
|
||||
spa_log_error (this->log, "a data loop is needed");
|
||||
return SPA_RESULT_ERROR;
|
||||
}
|
||||
if (this->main_loop == NULL) {
|
||||
spa_log_error (this->log, "a main loop is needed");
|
||||
return SPA_RESULT_ERROR;
|
||||
}
|
||||
init_type (&this->type, this->map);
|
||||
|
||||
this->node = alsasource_node;
|
||||
|
|
|
|||
|
|
@ -228,6 +228,15 @@ pull_frames_queue (SpaALSAState *state,
|
|||
|
||||
if (spa_list_is_empty (&state->ready)) {
|
||||
SpaEvent event = SPA_EVENT_INIT (state->type.event_node.NeedInput);
|
||||
SpaPortIO *io;
|
||||
|
||||
if ((io = state->io)) {
|
||||
io->flags = SPA_PORT_IO_FLAG_RANGE;
|
||||
io->status = SPA_RESULT_OK;
|
||||
io->range.offset = state->sample_count;
|
||||
io->range.min_size = state->threshold;
|
||||
io->range.max_size = frames;
|
||||
}
|
||||
state->event_cb (&state->node, &event, state->user_data);
|
||||
}
|
||||
while (!spa_list_is_empty (&state->ready) && to_write > 0) {
|
||||
|
|
@ -334,7 +343,7 @@ push_frames_queue (SpaALSAState *state,
|
|||
size_t n_bytes;
|
||||
SpaALSABuffer *b;
|
||||
SpaData *d;
|
||||
SpaPortOutput *output;
|
||||
SpaPortIO *io;
|
||||
|
||||
b = spa_list_first (&state->free, SpaALSABuffer, link);
|
||||
spa_list_remove (&b->link);
|
||||
|
|
@ -357,13 +366,13 @@ push_frames_queue (SpaALSAState *state,
|
|||
d[0].chunk->size = n_bytes;
|
||||
d[0].chunk->stride = 0;
|
||||
|
||||
if ((output = state->io)) {
|
||||
b->outstanding = true;
|
||||
output->buffer_id = b->outbuf->id;
|
||||
output->status = SPA_RESULT_OK;
|
||||
}
|
||||
{
|
||||
if ((io = state->io)) {
|
||||
SpaEvent event = SPA_EVENT_INIT (state->type.event_node.HaveOutput);
|
||||
|
||||
b->outstanding = true;
|
||||
io->buffer_id = b->outbuf->id;
|
||||
io->status = SPA_RESULT_OK;
|
||||
|
||||
state->event_cb (&state->node, &event, state->user_data);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ struct _SpaALSAState {
|
|||
SpaPortInfo info;
|
||||
SpaAllocParam *params[3];
|
||||
uint8_t params_buffer[1024];
|
||||
void *io;
|
||||
SpaPortIO *io;
|
||||
|
||||
SpaALSABuffer buffers[MAX_BUFFERS];
|
||||
unsigned int n_buffers;
|
||||
|
|
|
|||
|
|
@ -21,39 +21,38 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#include <spa/log.h>
|
||||
#include <spa/list.h>
|
||||
#include <spa/type-map.h>
|
||||
#include <spa/node.h>
|
||||
#include <spa/audio/format-utils.h>
|
||||
#include <lib/props.h>
|
||||
|
||||
#define MAX_BUFFERS 64
|
||||
#define MAX_PORTS 128
|
||||
|
||||
typedef struct _SpaAudioMixer SpaAudioMixer;
|
||||
|
||||
typedef struct _MixerBuffer MixerBuffer;
|
||||
|
||||
struct _MixerBuffer {
|
||||
SpaBuffer buffer;
|
||||
SpaMeta meta[1];
|
||||
SpaMetaHeader header;
|
||||
SpaData data[1];
|
||||
uint16_t samples[4096];
|
||||
};
|
||||
typedef struct {
|
||||
SpaBuffer *outbuf;
|
||||
bool outstanding;
|
||||
SpaMetaHeader *h;
|
||||
void *ptr;
|
||||
size_t size;
|
||||
SpaList link;
|
||||
} MixerBuffer;
|
||||
|
||||
typedef struct {
|
||||
bool valid;
|
||||
bool have_format;
|
||||
SpaAudioInfo format;
|
||||
SpaPortInfo info;
|
||||
size_t buffer_index;
|
||||
size_t buffer_offset;
|
||||
size_t buffer_queued;
|
||||
MixerBuffer mix;
|
||||
|
||||
SpaBuffer **buffers;
|
||||
uint32_t n_buffers;
|
||||
SpaBuffer *buffer;
|
||||
void *io;
|
||||
SpaPortIO *io;
|
||||
MixerBuffer buffers[MAX_BUFFERS];
|
||||
uint32_t n_buffers;
|
||||
SpaList queue;
|
||||
size_t queued_offset;
|
||||
size_t queued_bytes;
|
||||
} SpaAudioMixerPort;
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -89,6 +88,11 @@ struct _SpaAudioMixer {
|
|||
int port_queued;
|
||||
SpaAudioMixerPort in_ports[MAX_PORTS];
|
||||
SpaAudioMixerPort out_ports[1];
|
||||
|
||||
#define STATE_ERROR 0
|
||||
#define STATE_IN 1
|
||||
#define STATE_OUT 2
|
||||
int state;
|
||||
};
|
||||
|
||||
#define CHECK_FREE_IN_PORT(this,d,p) ((d) == SPA_DIRECTION_INPUT && (p) < MAX_PORTS && !this->in_ports[(p)].valid)
|
||||
|
|
@ -227,6 +231,7 @@ spa_audiomixer_node_add_port (SpaNode *node,
|
|||
|
||||
this->in_ports[port_id].valid = true;
|
||||
this->port_count++;
|
||||
spa_list_init (&this->in_ports[port_id].queue);
|
||||
|
||||
this->in_ports[port_id].info.flags = SPA_PORT_INFO_FLAG_CAN_USE_BUFFERS |
|
||||
SPA_PORT_INFO_FLAG_REMOVABLE |
|
||||
|
|
@ -241,7 +246,7 @@ spa_audiomixer_node_remove_port (SpaNode *node,
|
|||
uint32_t port_id)
|
||||
{
|
||||
SpaAudioMixer *this;
|
||||
SpaPortInput *input;
|
||||
SpaPortIO *io;
|
||||
|
||||
if (node == NULL)
|
||||
return SPA_RESULT_INVALID_ARGUMENTS;
|
||||
|
|
@ -254,8 +259,8 @@ spa_audiomixer_node_remove_port (SpaNode *node,
|
|||
this->in_ports[port_id].valid = false;
|
||||
this->port_count--;
|
||||
|
||||
input = this->in_ports[port_id].io;
|
||||
if (input && input->buffer_id) {
|
||||
io = this->in_ports[port_id].io;
|
||||
if (io && io->buffer_id) {
|
||||
this->port_queued--;
|
||||
}
|
||||
|
||||
|
|
@ -292,6 +297,17 @@ spa_audiomixer_node_port_enum_formats (SpaNode *node,
|
|||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
clear_buffers (SpaAudioMixer *this, SpaAudioMixerPort *port)
|
||||
{
|
||||
if (port->n_buffers > 0) {
|
||||
spa_log_info (this->log, "audio-mixer %p: clear buffers", this);
|
||||
port->n_buffers = 0;
|
||||
spa_list_init (&port->queue);
|
||||
}
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
spa_audiomixer_node_port_set_format (SpaNode *node,
|
||||
SpaDirection direction,
|
||||
|
|
@ -314,6 +330,7 @@ spa_audiomixer_node_port_set_format (SpaNode *node,
|
|||
|
||||
if (format == NULL) {
|
||||
port->have_format = false;
|
||||
clear_buffers (this, port);
|
||||
} else {
|
||||
SpaAudioInfo info = { SPA_FORMAT_MEDIA_TYPE (format),
|
||||
SPA_FORMAT_MEDIA_SUBTYPE (format), };
|
||||
|
|
@ -328,6 +345,13 @@ spa_audiomixer_node_port_set_format (SpaNode *node,
|
|||
port->format = info;
|
||||
port->have_format = true;
|
||||
}
|
||||
|
||||
if (port->have_format) {
|
||||
update_state (this, SPA_NODE_STATE_READY);
|
||||
}
|
||||
else
|
||||
update_state (this, SPA_NODE_STATE_CONFIGURE);
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
|
|
@ -406,7 +430,55 @@ spa_audiomixer_node_port_use_buffers (SpaNode *node,
|
|||
SpaBuffer **buffers,
|
||||
uint32_t n_buffers)
|
||||
{
|
||||
return SPA_RESULT_NOT_IMPLEMENTED;
|
||||
SpaAudioMixer *this;
|
||||
SpaAudioMixerPort *port;
|
||||
uint32_t i;
|
||||
|
||||
spa_return_val_if_fail (node != NULL, SPA_RESULT_INVALID_ARGUMENTS);
|
||||
|
||||
this = SPA_CONTAINER_OF (node, SpaAudioMixer, node);
|
||||
|
||||
spa_return_val_if_fail (CHECK_PORT (this, direction, port_id), SPA_RESULT_INVALID_PORT);
|
||||
|
||||
port = direction == SPA_DIRECTION_INPUT ? &this->in_ports[port_id] : &this->out_ports[port_id];
|
||||
|
||||
spa_return_val_if_fail (port->have_format, SPA_RESULT_NO_FORMAT);
|
||||
|
||||
clear_buffers (this, port);
|
||||
|
||||
for (i = 0; i < n_buffers; i++) {
|
||||
MixerBuffer *b;
|
||||
SpaData *d = buffers[i]->datas;
|
||||
|
||||
b = &port->buffers[i];
|
||||
b->outbuf = buffers[i];
|
||||
b->outstanding = true;
|
||||
b->h = spa_buffer_find_meta (buffers[i], SPA_META_TYPE_HEADER);
|
||||
|
||||
switch (d[0].type) {
|
||||
case SPA_DATA_TYPE_MEMPTR:
|
||||
case SPA_DATA_TYPE_MEMFD:
|
||||
case SPA_DATA_TYPE_DMABUF:
|
||||
if (d[0].data == NULL) {
|
||||
spa_log_error (this->log, "volume %p: invalid memory on buffer %p", this, buffers[i]);
|
||||
continue;
|
||||
}
|
||||
b->ptr = d[0].data;
|
||||
b->size = d[0].maxsize;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
spa_list_insert (port->queue.prev, &b->link);
|
||||
}
|
||||
port->n_buffers = n_buffers;
|
||||
|
||||
if (port->n_buffers > 0) {
|
||||
update_state (this, SPA_NODE_STATE_PAUSED);
|
||||
} else {
|
||||
update_state (this, SPA_NODE_STATE_READY);
|
||||
}
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
|
|
@ -422,41 +494,24 @@ spa_audiomixer_node_port_alloc_buffers (SpaNode *node,
|
|||
}
|
||||
|
||||
static SpaResult
|
||||
spa_audiomixer_node_port_set_input (SpaNode *node,
|
||||
uint32_t port_id,
|
||||
SpaPortInput *input)
|
||||
spa_audiomixer_node_port_set_io (SpaNode *node,
|
||||
SpaDirection direction,
|
||||
uint32_t port_id,
|
||||
SpaPortIO *io)
|
||||
{
|
||||
SpaAudioMixer *this;
|
||||
SpaAudioMixerPort *port;
|
||||
|
||||
if (node == NULL)
|
||||
return SPA_RESULT_INVALID_ARGUMENTS;
|
||||
|
||||
this = SPA_CONTAINER_OF (node, SpaAudioMixer, node);
|
||||
|
||||
if (!CHECK_PORT (this, SPA_DIRECTION_INPUT, port_id))
|
||||
if (!CHECK_PORT (this, direction, port_id))
|
||||
return SPA_RESULT_INVALID_PORT;
|
||||
|
||||
this->in_ports[port_id].io = input;
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
spa_audiomixer_node_port_set_output (SpaNode *node,
|
||||
uint32_t port_id,
|
||||
SpaPortOutput *output)
|
||||
{
|
||||
SpaAudioMixer *this;
|
||||
|
||||
if (node == NULL)
|
||||
return SPA_RESULT_INVALID_ARGUMENTS;
|
||||
|
||||
this = SPA_CONTAINER_OF (node, SpaAudioMixer, node);
|
||||
|
||||
if (!CHECK_PORT (this, SPA_DIRECTION_OUTPUT, port_id))
|
||||
return SPA_RESULT_INVALID_PORT;
|
||||
|
||||
this->out_ports[port_id].io = output;
|
||||
port = direction == SPA_DIRECTION_INPUT ? &this->in_ports[port_id] : &this->out_ports[port_id];
|
||||
port->io = io;
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
|
@ -478,131 +533,107 @@ spa_audiomixer_node_port_send_command (SpaNode *node,
|
|||
return SPA_RESULT_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static void
|
||||
add_port_data (SpaAudioMixer *this, MixerBuffer *out, SpaAudioMixerPort *port)
|
||||
{
|
||||
int i;
|
||||
uint8_t *op, *ip;
|
||||
size_t os, is, chunk;
|
||||
MixerBuffer *b = spa_list_first (&port->queue, MixerBuffer, link);
|
||||
|
||||
op = out->ptr;
|
||||
os = out->size;
|
||||
ip = SPA_MEMBER (b->ptr, port->queued_offset + b->outbuf->datas[0].chunk->offset, void);
|
||||
is = b->outbuf->datas[0].chunk->size - port->queued_offset;
|
||||
|
||||
chunk = SPA_MIN (os, is);
|
||||
|
||||
for (i = 0; i < chunk; i++)
|
||||
op[i] += ip[i];
|
||||
|
||||
port->queued_offset += chunk;
|
||||
port->queued_bytes -= chunk;
|
||||
|
||||
if (chunk == is) {
|
||||
spa_log_trace (this->log, "audiomixer %p: return buffer %d on port %p", this, b->outbuf->id, port);
|
||||
port->io->buffer_id = b->outbuf->id;
|
||||
spa_list_remove (&b->link);
|
||||
b->outstanding = true;
|
||||
port->queued_offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
spa_audiomixer_node_process_input (SpaNode *node)
|
||||
{
|
||||
SpaAudioMixer *this;
|
||||
uint32_t i;
|
||||
bool have_error = false;
|
||||
SpaPortOutput *output;
|
||||
SpaAudioMixerPort *outport;
|
||||
size_t min_queued = -1;
|
||||
|
||||
if (node == NULL)
|
||||
return SPA_RESULT_INVALID_ARGUMENTS;
|
||||
spa_return_val_if_fail (node != NULL, SPA_RESULT_INVALID_ARGUMENTS);
|
||||
|
||||
this = SPA_CONTAINER_OF (node, SpaAudioMixer, node);
|
||||
|
||||
if ((output = this->out_ports[0].io) == NULL)
|
||||
return SPA_RESULT_OK;
|
||||
if (this->state == STATE_OUT)
|
||||
return SPA_RESULT_HAVE_OUTPUT;
|
||||
|
||||
this->port_queued = 0;
|
||||
outport = &this->out_ports[0];
|
||||
spa_return_val_if_fail (outport->io != NULL, SPA_RESULT_ERROR);
|
||||
|
||||
for (i = 0; i < MAX_PORTS; i++) {
|
||||
SpaAudioMixerPort *port = &this->in_ports[i];
|
||||
SpaPortInput *input;
|
||||
SpaPortIO *input;
|
||||
|
||||
if ((input = port->io) == NULL)
|
||||
if (!port->valid || (input = port->io) == NULL)
|
||||
continue;
|
||||
|
||||
if (input->buffer_id >= port->n_buffers) {
|
||||
input->status = SPA_RESULT_INVALID_BUFFER_ID;
|
||||
have_error = true;
|
||||
continue;
|
||||
}
|
||||
if (port->buffer == NULL) {
|
||||
port->buffer = port->buffers[input->buffer_id];
|
||||
if (input->buffer_id != SPA_ID_INVALID) {
|
||||
MixerBuffer *b = &port->buffers[input->buffer_id];
|
||||
|
||||
if (spa_list_is_empty (&port->queue)) {
|
||||
port->queued_bytes = 0;
|
||||
port->queued_offset = 0;
|
||||
}
|
||||
spa_log_trace (this->log, "audiomixer %p: queue buffer %d on port %p", this, b->outbuf->id, port);
|
||||
spa_list_insert (port->queue.prev, &b->link);
|
||||
b->outstanding = false;
|
||||
port->queued_bytes += b->size;
|
||||
input->buffer_id = SPA_ID_INVALID;
|
||||
}
|
||||
if (min_queued == -1 || port->queued_bytes < min_queued)
|
||||
min_queued = port->queued_bytes;
|
||||
|
||||
input->status = SPA_RESULT_OK;
|
||||
this->port_queued++;
|
||||
}
|
||||
if (have_error)
|
||||
return SPA_RESULT_ERROR;
|
||||
|
||||
return this->port_queued == this->port_count ? SPA_RESULT_HAVE_OUTPUT : SPA_RESULT_OK;
|
||||
}
|
||||
if (min_queued != -1) {
|
||||
MixerBuffer *outbuf;
|
||||
SpaPortIO *output;
|
||||
|
||||
static void
|
||||
add_port_data (SpaAudioMixer *this, SpaBuffer *out, SpaAudioMixerPort *port)
|
||||
{
|
||||
int i, oi = 0;
|
||||
uint8_t *op, *ip;
|
||||
size_t os, is, chunk;
|
||||
SpaData *odatas = out->datas;
|
||||
SpaData *idatas = port->buffer->datas;
|
||||
if (spa_list_is_empty (&outport->queue))
|
||||
return SPA_RESULT_OUT_OF_BUFFERS;
|
||||
|
||||
op = ip = NULL;
|
||||
outbuf = spa_list_first (&outport->queue, MixerBuffer, link);
|
||||
spa_list_remove (&outbuf->link);
|
||||
spa_log_trace (this->log, "audiomixer %p: dequeue output buffer %d", this, outbuf->outbuf->id);
|
||||
outbuf->outstanding = true;
|
||||
|
||||
while (true) {
|
||||
if (op == NULL) {
|
||||
op = (uint8_t*)odatas[oi].data + odatas[oi].chunk->offset;
|
||||
os = odatas[oi].chunk->size;
|
||||
}
|
||||
if (ip == NULL) {
|
||||
ip = (uint8_t*)idatas[port->buffer_index].data + idatas[port->buffer_index].chunk->offset;
|
||||
is = idatas[port->buffer_index].chunk->size;
|
||||
ip += port->buffer_offset;
|
||||
is -= port->buffer_offset;
|
||||
}
|
||||
|
||||
chunk = os < is ? os : is;
|
||||
|
||||
for (i = 0; i < chunk; i++)
|
||||
op[i] += ip[i];
|
||||
|
||||
if ((is -= chunk) == 0) {
|
||||
if (++port->buffer_index == port->buffer->n_datas) {
|
||||
port->buffer = NULL;
|
||||
break;
|
||||
}
|
||||
port->buffer_offset = 0;
|
||||
ip = NULL;
|
||||
} else {
|
||||
port->buffer_offset += chunk;
|
||||
}
|
||||
port->buffer_queued -= chunk;
|
||||
|
||||
if ((os -= chunk) == 0) {
|
||||
if (++oi == out->n_datas)
|
||||
break;
|
||||
op = NULL;
|
||||
for (i = 0; i < MAX_PORTS; i++) {
|
||||
SpaAudioMixerPort *port = &this->in_ports[i];
|
||||
|
||||
if (!port->valid || port->io == NULL ||
|
||||
spa_list_is_empty (&port->queue))
|
||||
continue;
|
||||
|
||||
add_port_data (this, outbuf, port);
|
||||
}
|
||||
output = outport->io;
|
||||
output->buffer_id = outbuf->outbuf->id;
|
||||
output->state = SPA_RESULT_OK;
|
||||
this->state = STATE_OUT;
|
||||
}
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
mix_data (SpaAudioMixer *this, SpaPortOutput *output)
|
||||
{
|
||||
int i, min_size, min_port;
|
||||
SpaBuffer *buf;
|
||||
|
||||
min_size = 0;
|
||||
min_port = 0;
|
||||
for (i = 0; i < MAX_PORTS; i++) {
|
||||
if (!this->in_ports[i].valid)
|
||||
continue;
|
||||
|
||||
if (this->in_ports[i].buffer == NULL)
|
||||
return SPA_RESULT_NEED_INPUT;
|
||||
|
||||
if (min_size == 0 || this->in_ports[i].buffer_queued < min_size) {
|
||||
min_size = this->in_ports[i].buffer_queued;
|
||||
min_port = i;
|
||||
}
|
||||
}
|
||||
if (min_port == 0)
|
||||
return SPA_RESULT_NEED_INPUT;
|
||||
|
||||
buf = this->in_ports[min_port].buffer;
|
||||
output->buffer_id = buf->id;
|
||||
this->in_ports[min_port].buffer = NULL;
|
||||
|
||||
for (i = 0; i < MAX_PORTS; i++) {
|
||||
if (!this->in_ports[i].valid || this->in_ports[i].buffer == NULL)
|
||||
continue;
|
||||
|
||||
add_port_data (this, buf, &this->in_ports[i]);
|
||||
}
|
||||
return SPA_RESULT_OK;
|
||||
return this->state == STATE_IN ? SPA_RESULT_NEED_INPUT : SPA_RESULT_HAVE_OUTPUT;
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
|
|
@ -610,24 +641,39 @@ spa_audiomixer_node_process_output (SpaNode *node)
|
|||
{
|
||||
SpaAudioMixer *this;
|
||||
SpaAudioMixerPort *port;
|
||||
SpaPortOutput *output;
|
||||
SpaPortIO *output;
|
||||
int i;
|
||||
|
||||
if (node == NULL)
|
||||
return SPA_RESULT_INVALID_ARGUMENTS;
|
||||
spa_return_val_if_fail (node != NULL, SPA_RESULT_INVALID_ARGUMENTS);
|
||||
|
||||
this = SPA_CONTAINER_OF (node, SpaAudioMixer, node);
|
||||
|
||||
port = &this->out_ports[0];
|
||||
if ((output = port->io) == NULL)
|
||||
return SPA_RESULT_ERROR;
|
||||
spa_return_val_if_fail (port->io != NULL, SPA_RESULT_ERROR);
|
||||
output = port->io;
|
||||
|
||||
if (!port->have_format)
|
||||
return SPA_RESULT_NO_FORMAT;
|
||||
spa_return_val_if_fail (port->have_format, SPA_RESULT_NO_FORMAT);
|
||||
|
||||
if ((output->status = mix_data (this, output)) < 0)
|
||||
return SPA_RESULT_ERROR;
|
||||
for (i = 0; i < MAX_PORTS; i++) {
|
||||
SpaPortIO *input;
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
if (!this->in_ports[i].valid || (input = this->in_ports[i].io) == NULL)
|
||||
continue;
|
||||
|
||||
input->flags = output->flags;
|
||||
input->range = output->range;
|
||||
}
|
||||
if (output->buffer_id != SPA_ID_INVALID) {
|
||||
MixerBuffer *b = &port->buffers[output->buffer_id];
|
||||
if (b->outstanding) {
|
||||
spa_list_insert (port->queue.prev, &b->link);
|
||||
b->outstanding = false;
|
||||
spa_log_trace (this->log, "audiomixer %p: recycle buffer %d", this, b->outbuf->id);
|
||||
}
|
||||
output->buffer_id = SPA_ID_INVALID;
|
||||
}
|
||||
this->state = STATE_IN;
|
||||
return SPA_RESULT_NEED_INPUT;
|
||||
}
|
||||
|
||||
static const SpaNode audiomixer_node = {
|
||||
|
|
@ -650,8 +696,7 @@ static const SpaNode audiomixer_node = {
|
|||
spa_audiomixer_node_port_set_props,
|
||||
spa_audiomixer_node_port_use_buffers,
|
||||
spa_audiomixer_node_port_alloc_buffers,
|
||||
spa_audiomixer_node_port_set_input,
|
||||
spa_audiomixer_node_port_set_output,
|
||||
spa_audiomixer_node_port_set_io,
|
||||
spa_audiomixer_node_port_reuse_buffer,
|
||||
spa_audiomixer_node_port_send_command,
|
||||
spa_audiomixer_node_process_input,
|
||||
|
|
@ -717,9 +762,10 @@ spa_audiomixer_init (const SpaHandleFactory *factory,
|
|||
this->node = audiomixer_node;
|
||||
|
||||
this->out_ports[0].valid = true;
|
||||
this->out_ports[0].info.flags = SPA_PORT_INFO_FLAG_CAN_ALLOC_BUFFERS |
|
||||
SPA_PORT_INFO_FLAG_CAN_USE_BUFFERS |
|
||||
this->out_ports[0].info.flags = SPA_PORT_INFO_FLAG_CAN_USE_BUFFERS |
|
||||
SPA_PORT_INFO_FLAG_NO_REF;
|
||||
spa_list_init (&this->out_ports[0].queue);
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ struct _SpaAudioTestSrc {
|
|||
SpaPortInfo info;
|
||||
SpaAllocParam *params[2];
|
||||
uint8_t params_buffer[1024];
|
||||
SpaPortOutput *output;
|
||||
SpaPortIO *io;
|
||||
|
||||
bool have_format;
|
||||
SpaAudioInfo current_format;
|
||||
|
|
@ -275,23 +275,20 @@ set_timer (SpaAudioTestSrc *this, bool enabled)
|
|||
timerfd_settime (this->timer_source.fd, TFD_TIMER_ABSTIME, &this->timerspec, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
audiotestsrc_on_output (SpaSource *source)
|
||||
static SpaResult
|
||||
audiotestsrc_make_buffer (SpaAudioTestSrc *this)
|
||||
{
|
||||
SpaAudioTestSrc *this = source->data;
|
||||
ATSBuffer *b;
|
||||
SpaPortOutput *output;
|
||||
uint64_t expirations;
|
||||
|
||||
if (read (this->timer_source.fd, &expirations, sizeof (uint64_t)) < sizeof (uint64_t))
|
||||
perror ("read timerfd");
|
||||
SpaPortIO *io;
|
||||
|
||||
if (spa_list_is_empty (&this->empty)) {
|
||||
set_timer (this, false);
|
||||
return;
|
||||
return SPA_RESULT_OUT_OF_BUFFERS;
|
||||
}
|
||||
b = spa_list_first (&this->empty, ATSBuffer, link);
|
||||
spa_list_remove (&b->link);
|
||||
b->outstanding = true;
|
||||
spa_log_trace (this->log, "audiotestsrc %p: dequeue buffer %d", this, b->outbuf->id);
|
||||
|
||||
fill_buffer (this, b);
|
||||
|
||||
|
|
@ -305,12 +302,25 @@ audiotestsrc_on_output (SpaSource *source)
|
|||
this->elapsed_time = SAMPLES_TO_TIME (this, this->sample_count);
|
||||
set_timer (this, true);
|
||||
|
||||
if ((output = this->output)) {
|
||||
b->outstanding = true;
|
||||
output->buffer_id = b->outbuf->id;
|
||||
output->status = SPA_RESULT_OK;
|
||||
send_have_output (this);
|
||||
if ((io = this->io)) {
|
||||
io->buffer_id = b->outbuf->id;
|
||||
io->status = SPA_RESULT_OK;
|
||||
}
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
audiotestsrc_on_output (SpaSource *source)
|
||||
{
|
||||
SpaAudioTestSrc *this = source->data;
|
||||
uint64_t expirations;
|
||||
|
||||
if (read (this->timer_source.fd, &expirations, sizeof (uint64_t)) < sizeof (uint64_t))
|
||||
perror ("read timerfd");
|
||||
|
||||
audiotestsrc_make_buffer (this);
|
||||
|
||||
send_have_output (this);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -684,7 +694,7 @@ spa_audiotestsrc_node_port_use_buffers (SpaNode *node,
|
|||
|
||||
b = &this->buffers[i];
|
||||
b->outbuf = buffers[i];
|
||||
b->outstanding = true;
|
||||
b->outstanding = false;
|
||||
b->h = spa_buffer_find_meta (buffers[i], SPA_META_TYPE_HEADER);
|
||||
|
||||
switch (d[0].type) {
|
||||
|
|
@ -740,29 +750,20 @@ spa_audiotestsrc_node_port_alloc_buffers (SpaNode *node,
|
|||
}
|
||||
|
||||
static SpaResult
|
||||
spa_audiotestsrc_node_port_set_input (SpaNode *node,
|
||||
uint32_t port_id,
|
||||
SpaPortInput *input)
|
||||
{
|
||||
return SPA_RESULT_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
spa_audiotestsrc_node_port_set_output (SpaNode *node,
|
||||
uint32_t port_id,
|
||||
SpaPortOutput *output)
|
||||
spa_audiotestsrc_node_port_set_io (SpaNode *node,
|
||||
SpaDirection direction,
|
||||
uint32_t port_id,
|
||||
SpaPortIO *io)
|
||||
{
|
||||
SpaAudioTestSrc *this;
|
||||
|
||||
if (node == NULL || output == NULL)
|
||||
return SPA_RESULT_INVALID_ARGUMENTS;
|
||||
spa_return_val_if_fail (node != NULL, SPA_RESULT_INVALID_ARGUMENTS);
|
||||
|
||||
this = SPA_CONTAINER_OF (node, SpaAudioTestSrc, node);
|
||||
|
||||
if (!CHECK_PORT (this, SPA_DIRECTION_OUTPUT, port_id))
|
||||
return SPA_RESULT_INVALID_PORT;
|
||||
spa_return_val_if_fail (CHECK_PORT (this, direction, port_id), SPA_RESULT_INVALID_PORT);
|
||||
|
||||
this->output = output;
|
||||
this->io = io;
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
|
@ -775,23 +776,18 @@ spa_audiotestsrc_node_port_reuse_buffer (SpaNode *node,
|
|||
SpaAudioTestSrc *this;
|
||||
ATSBuffer *b;
|
||||
|
||||
if (node == NULL)
|
||||
return SPA_RESULT_INVALID_ARGUMENTS;
|
||||
spa_return_val_if_fail (node != NULL, SPA_RESULT_INVALID_ARGUMENTS);
|
||||
|
||||
this = SPA_CONTAINER_OF (node, SpaAudioTestSrc, node);
|
||||
|
||||
if (port_id != 0)
|
||||
return SPA_RESULT_INVALID_PORT;
|
||||
|
||||
if (this->n_buffers == 0)
|
||||
return SPA_RESULT_NO_BUFFERS;
|
||||
|
||||
if (buffer_id >= this->n_buffers)
|
||||
return SPA_RESULT_INVALID_BUFFER_ID;
|
||||
spa_return_val_if_fail (port_id == 0, SPA_RESULT_INVALID_PORT);
|
||||
spa_return_val_if_fail (this->n_buffers > 0, SPA_RESULT_NO_BUFFERS);
|
||||
spa_return_val_if_fail (buffer_id < this->n_buffers, SPA_RESULT_INVALID_BUFFER_ID);
|
||||
|
||||
b = &this->buffers[buffer_id];
|
||||
if (!b->outstanding)
|
||||
return SPA_RESULT_OK;
|
||||
spa_return_val_if_fail (b->outstanding, SPA_RESULT_INVALID_BUFFER_ID);
|
||||
|
||||
spa_log_trace (this->log, "audiotestsrc %p: reuse buffer %d", this, b->outbuf->id);
|
||||
|
||||
b->outstanding = false;
|
||||
spa_list_insert (this->empty.prev, &b->link);
|
||||
|
|
@ -820,7 +816,29 @@ spa_audiotestsrc_node_process_input (SpaNode *node)
|
|||
static SpaResult
|
||||
spa_audiotestsrc_node_process_output (SpaNode *node)
|
||||
{
|
||||
return SPA_RESULT_OK;
|
||||
SpaResult res;
|
||||
SpaAudioTestSrc *this;
|
||||
ATSBuffer *b;
|
||||
|
||||
spa_return_val_if_fail (node != NULL, SPA_RESULT_INVALID_ARGUMENTS);
|
||||
|
||||
this = SPA_CONTAINER_OF (node, SpaAudioTestSrc, node);
|
||||
|
||||
if (this->io && this->io->buffer_id != SPA_ID_INVALID) {
|
||||
b = &this->buffers[this->io->buffer_id];
|
||||
if (b->outstanding) {
|
||||
b->outstanding = false;
|
||||
spa_log_trace (this->log, "audiotestsrc %p: recycle buffer %d", this, b->outbuf->id);
|
||||
spa_list_insert (this->empty.prev, &b->link);
|
||||
if (!this->props.live)
|
||||
set_timer (this, true);
|
||||
}
|
||||
this->io->buffer_id = SPA_ID_INVALID;
|
||||
}
|
||||
if ((res = audiotestsrc_make_buffer (this)) < 0)
|
||||
return res;
|
||||
|
||||
return SPA_RESULT_HAVE_OUTPUT;
|
||||
}
|
||||
|
||||
static const SpaNode audiotestsrc_node = {
|
||||
|
|
@ -843,8 +861,7 @@ static const SpaNode audiotestsrc_node = {
|
|||
spa_audiotestsrc_node_port_set_props,
|
||||
spa_audiotestsrc_node_port_use_buffers,
|
||||
spa_audiotestsrc_node_port_alloc_buffers,
|
||||
spa_audiotestsrc_node_port_set_input,
|
||||
spa_audiotestsrc_node_port_set_output,
|
||||
spa_audiotestsrc_node_port_set_io,
|
||||
spa_audiotestsrc_node_port_reuse_buffer,
|
||||
spa_audiotestsrc_node_port_send_command,
|
||||
spa_audiotestsrc_node_process_input,
|
||||
|
|
|
|||
|
|
@ -373,41 +373,24 @@ spa_ffmpeg_dec_node_port_alloc_buffers (SpaNode *node,
|
|||
}
|
||||
|
||||
static SpaResult
|
||||
spa_ffmpeg_dec_node_port_set_input (SpaNode *node,
|
||||
uint32_t port_id,
|
||||
SpaPortInput *input)
|
||||
spa_ffmpeg_dec_node_port_set_io (SpaNode *node,
|
||||
SpaDirection direction,
|
||||
uint32_t port_id,
|
||||
SpaPortIO *io)
|
||||
{
|
||||
SpaFFMpegDec *this;
|
||||
SpaFFMpegPort *port;
|
||||
|
||||
if (node == NULL)
|
||||
return SPA_RESULT_INVALID_ARGUMENTS;
|
||||
|
||||
this = SPA_CONTAINER_OF (node, SpaFFMpegDec, node);
|
||||
|
||||
if (!IS_VALID_PORT (this, SPA_DIRECTION_INPUT, port_id))
|
||||
if (!IS_VALID_PORT (this, direction, port_id))
|
||||
return SPA_RESULT_INVALID_PORT;
|
||||
|
||||
this->in_ports[port_id].io = input;
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
spa_ffmpeg_dec_node_port_set_output (SpaNode *node,
|
||||
uint32_t port_id,
|
||||
SpaPortOutput *output)
|
||||
{
|
||||
SpaFFMpegDec *this;
|
||||
|
||||
if (node == NULL)
|
||||
return SPA_RESULT_INVALID_ARGUMENTS;
|
||||
|
||||
this = SPA_CONTAINER_OF (node, SpaFFMpegDec, node);
|
||||
|
||||
if (!IS_VALID_PORT (this, SPA_DIRECTION_OUTPUT, port_id))
|
||||
return SPA_RESULT_INVALID_PORT;
|
||||
|
||||
this->out_ports[port_id].io = output;
|
||||
port = direction == SPA_DIRECTION_INPUT ? &this->in_ports[port_id] : &this->out_ports[port_id];
|
||||
port->io = io;
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
|
@ -423,7 +406,7 @@ spa_ffmpeg_dec_node_process_output (SpaNode *node)
|
|||
{
|
||||
SpaFFMpegDec *this;
|
||||
SpaFFMpegPort *port;
|
||||
SpaPortOutput *output;
|
||||
SpaPortIO *output;
|
||||
|
||||
if (node == NULL)
|
||||
return SPA_RESULT_INVALID_ARGUMENTS;
|
||||
|
|
@ -488,8 +471,7 @@ static const SpaNode ffmpeg_dec_node = {
|
|||
spa_ffmpeg_dec_node_port_set_props,
|
||||
spa_ffmpeg_dec_node_port_use_buffers,
|
||||
spa_ffmpeg_dec_node_port_alloc_buffers,
|
||||
spa_ffmpeg_dec_node_port_set_input,
|
||||
spa_ffmpeg_dec_node_port_set_output,
|
||||
spa_ffmpeg_dec_node_port_set_io,
|
||||
spa_ffmpeg_dec_node_port_reuse_buffer,
|
||||
spa_ffmpeg_dec_node_port_send_command,
|
||||
spa_ffmpeg_dec_node_process_input,
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ typedef struct {
|
|||
bool have_buffers;
|
||||
FFMpegBuffer buffers[MAX_BUFFERS];
|
||||
SpaPortInfo info;
|
||||
void *io;
|
||||
SpaPortIO *io;
|
||||
} SpaFFMpegPort;
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -381,41 +381,24 @@ spa_ffmpeg_enc_node_port_alloc_buffers (SpaNode *node,
|
|||
}
|
||||
|
||||
static SpaResult
|
||||
spa_ffmpeg_enc_node_port_set_input (SpaNode *node,
|
||||
uint32_t port_id,
|
||||
SpaPortInput *input)
|
||||
spa_ffmpeg_enc_node_port_set_io (SpaNode *node,
|
||||
SpaDirection direction,
|
||||
uint32_t port_id,
|
||||
SpaPortIO *io)
|
||||
{
|
||||
SpaFFMpegEnc *this;
|
||||
SpaFFMpegPort *port;
|
||||
|
||||
if (node == NULL)
|
||||
return SPA_RESULT_INVALID_ARGUMENTS;
|
||||
|
||||
this = SPA_CONTAINER_OF (node, SpaFFMpegEnc, node);
|
||||
|
||||
if (!IS_VALID_PORT (this, SPA_DIRECTION_INPUT, port_id))
|
||||
if (!IS_VALID_PORT (this, direction, port_id))
|
||||
return SPA_RESULT_INVALID_PORT;
|
||||
|
||||
this->in_ports[port_id].io = input;
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
spa_ffmpeg_enc_node_port_set_output (SpaNode *node,
|
||||
uint32_t port_id,
|
||||
SpaPortOutput *output)
|
||||
{
|
||||
SpaFFMpegEnc *this;
|
||||
|
||||
if (node == NULL)
|
||||
return SPA_RESULT_INVALID_ARGUMENTS;
|
||||
|
||||
this = SPA_CONTAINER_OF (node, SpaFFMpegEnc, node);
|
||||
|
||||
if (!IS_VALID_PORT (this, SPA_DIRECTION_OUTPUT, port_id))
|
||||
return SPA_RESULT_INVALID_PORT;
|
||||
|
||||
this->out_ports[port_id].io = output;
|
||||
port = direction == SPA_DIRECTION_INPUT ? &this->in_ports[port_id] : &this->out_ports[port_id];
|
||||
port->io = io;
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
|
@ -454,7 +437,7 @@ spa_ffmpeg_enc_node_process_output (SpaNode *node)
|
|||
{
|
||||
SpaFFMpegEnc *this;
|
||||
SpaFFMpegPort *port;
|
||||
SpaPortOutput *output;
|
||||
SpaPortIO *output;
|
||||
|
||||
if (node == NULL)
|
||||
return SPA_RESULT_INVALID_ARGUMENTS;
|
||||
|
|
@ -495,8 +478,7 @@ static const SpaNode ffmpeg_enc_node = {
|
|||
spa_ffmpeg_enc_node_port_set_props,
|
||||
spa_ffmpeg_enc_node_port_use_buffers,
|
||||
spa_ffmpeg_enc_node_port_alloc_buffers,
|
||||
spa_ffmpeg_enc_node_port_set_input,
|
||||
spa_ffmpeg_enc_node_port_set_output,
|
||||
spa_ffmpeg_enc_node_port_set_io,
|
||||
spa_ffmpeg_enc_node_port_reuse_buffer,
|
||||
spa_ffmpeg_enc_node_port_send_command,
|
||||
spa_ffmpeg_enc_node_process_input,
|
||||
|
|
|
|||
|
|
@ -528,12 +528,16 @@ spa_v4l2_source_node_port_set_format (SpaNode *node,
|
|||
info.media_type = SPA_FORMAT_MEDIA_TYPE (format);
|
||||
info.media_subtype = SPA_FORMAT_MEDIA_SUBTYPE (format);
|
||||
|
||||
if (info.media_type != this->type.media_type.video)
|
||||
if (info.media_type != this->type.media_type.video) {
|
||||
spa_log_error (this->log, "media type must be video");
|
||||
return SPA_RESULT_INVALID_MEDIA_TYPE;
|
||||
}
|
||||
|
||||
if (info.media_subtype == this->type.media_subtype.raw) {
|
||||
if (!spa_format_video_raw_parse (format, &info.info.raw, &this->type.format_video))
|
||||
if (!spa_format_video_raw_parse (format, &info.info.raw, &this->type.format_video)) {
|
||||
spa_log_error (this->log, "can't parse video raw");
|
||||
return SPA_RESULT_INVALID_MEDIA_TYPE;
|
||||
}
|
||||
|
||||
if (state->have_format && info.media_type == state->current_format.media_type &&
|
||||
info.media_subtype == state->current_format.media_subtype &&
|
||||
|
|
@ -761,17 +765,10 @@ spa_v4l2_source_node_port_alloc_buffers (SpaNode *node,
|
|||
}
|
||||
|
||||
static SpaResult
|
||||
spa_v4l2_source_node_port_set_input (SpaNode *node,
|
||||
uint32_t port_id,
|
||||
SpaPortInput *input)
|
||||
{
|
||||
return SPA_RESULT_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
spa_v4l2_source_node_port_set_output (SpaNode *node,
|
||||
uint32_t port_id,
|
||||
SpaPortOutput *output)
|
||||
spa_v4l2_source_node_port_set_io (SpaNode *node,
|
||||
SpaDirection direction,
|
||||
uint32_t port_id,
|
||||
SpaPortIO *io)
|
||||
{
|
||||
SpaV4l2Source *this;
|
||||
|
||||
|
|
@ -780,15 +777,14 @@ spa_v4l2_source_node_port_set_output (SpaNode *node,
|
|||
|
||||
this = SPA_CONTAINER_OF (node, SpaV4l2Source, node);
|
||||
|
||||
if (!CHECK_PORT (this, SPA_DIRECTION_OUTPUT, port_id))
|
||||
if (!CHECK_PORT (this, direction, port_id))
|
||||
return SPA_RESULT_INVALID_PORT;
|
||||
|
||||
this->state[port_id].io = output;
|
||||
this->state[port_id].io = io;
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
|
||||
static SpaResult
|
||||
spa_v4l2_source_node_port_reuse_buffer (SpaNode *node,
|
||||
uint32_t port_id,
|
||||
|
|
@ -834,7 +830,8 @@ spa_v4l2_source_node_port_send_command (SpaNode *node,
|
|||
}
|
||||
else if (SPA_COMMAND_TYPE (command) == this->type.command_node.Start) {
|
||||
res = spa_v4l2_port_set_enabled (this, true);
|
||||
} else
|
||||
}
|
||||
else
|
||||
res = SPA_RESULT_NOT_IMPLEMENTED;
|
||||
|
||||
return res;
|
||||
|
|
@ -849,7 +846,22 @@ spa_v4l2_source_node_process_input (SpaNode *node)
|
|||
static SpaResult
|
||||
spa_v4l2_source_node_process_output (SpaNode *node)
|
||||
{
|
||||
return SPA_RESULT_OK;
|
||||
SpaV4l2Source *this;
|
||||
SpaResult res = SPA_RESULT_OK;
|
||||
SpaPortIO *io;
|
||||
|
||||
if (node == NULL)
|
||||
return SPA_RESULT_INVALID_ARGUMENTS;
|
||||
|
||||
this = SPA_CONTAINER_OF (node, SpaV4l2Source, node);
|
||||
|
||||
if ((io = this->state[0].io)) {
|
||||
if (io->buffer_id != SPA_ID_INVALID) {
|
||||
res = spa_v4l2_buffer_recycle (this, io->buffer_id);
|
||||
io->buffer_id = SPA_ID_INVALID;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static const SpaNode v4l2source_node = {
|
||||
|
|
@ -872,8 +884,7 @@ static const SpaNode v4l2source_node = {
|
|||
spa_v4l2_source_node_port_set_props,
|
||||
spa_v4l2_source_node_port_use_buffers,
|
||||
spa_v4l2_source_node_port_alloc_buffers,
|
||||
spa_v4l2_source_node_port_set_input,
|
||||
spa_v4l2_source_node_port_set_output,
|
||||
spa_v4l2_source_node_port_set_io,
|
||||
spa_v4l2_source_node_port_reuse_buffer,
|
||||
spa_v4l2_source_node_port_send_command,
|
||||
spa_v4l2_source_node_process_input,
|
||||
|
|
|
|||
|
|
@ -90,6 +90,7 @@ spa_v4l2_buffer_recycle (SpaV4l2Source *this, uint32_t buffer_id)
|
|||
return SPA_RESULT_OK;
|
||||
|
||||
b->outstanding = false;
|
||||
spa_log_trace (state->log, "v4l2 %p: recycle buffer %d", this, buffer_id);
|
||||
|
||||
if (xioctl (state->fd, VIDIOC_QBUF, &b->v4l2_buffer) < 0) {
|
||||
perror ("VIDIOC_QBUF");
|
||||
|
|
@ -916,7 +917,7 @@ mmap_read (SpaV4l2Source *this)
|
|||
V4l2Buffer *b;
|
||||
SpaData *d;
|
||||
int64_t pts;
|
||||
SpaPortOutput *output;
|
||||
SpaPortIO *io;
|
||||
|
||||
CLEAR(buf);
|
||||
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
|
|
@ -955,10 +956,14 @@ mmap_read (SpaV4l2Source *this)
|
|||
d[0].chunk->size = buf.bytesused;
|
||||
d[0].chunk->stride = state->fmt.fmt.pix.bytesperline;
|
||||
|
||||
if ((output = state->io)) {
|
||||
if ((io = state->io)) {
|
||||
SpaEvent event = SPA_EVENT_INIT (this->type.event_node.HaveOutput);
|
||||
|
||||
b->outstanding = true;
|
||||
output->buffer_id = b->outbuf->id;
|
||||
output->status = SPA_RESULT_OK;
|
||||
io->buffer_id = b->outbuf->id;
|
||||
io->status = SPA_RESULT_OK;
|
||||
|
||||
this->event_cb (&this->node, &event, this->user_data);
|
||||
}
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
|
@ -976,11 +981,6 @@ v4l2_on_fd_events (SpaSource *source)
|
|||
|
||||
if (mmap_read (this) < 0)
|
||||
return;
|
||||
|
||||
{
|
||||
SpaEvent event = SPA_EVENT_INIT (this->type.event_node.HaveOutput);
|
||||
this->event_cb (&this->node, &event, this->user_data);
|
||||
}
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ struct _SpaVideoTestSrc {
|
|||
SpaAllocParam *params[2];
|
||||
uint8_t params_buffer[1024];
|
||||
int stride;
|
||||
SpaPortOutput *output;
|
||||
SpaPortIO *io;
|
||||
|
||||
bool have_format;
|
||||
SpaVideoInfo current_format;
|
||||
|
|
@ -261,7 +261,7 @@ videotestsrc_on_output (SpaSource *source)
|
|||
{
|
||||
SpaVideoTestSrc *this = source->data;
|
||||
VTSBuffer *b;
|
||||
SpaPortOutput *output;
|
||||
SpaPortIO *io;
|
||||
uint64_t expirations;
|
||||
|
||||
if (read (this->timer_source.fd, &expirations, sizeof (uint64_t)) < sizeof (uint64_t))
|
||||
|
|
@ -286,10 +286,10 @@ videotestsrc_on_output (SpaSource *source)
|
|||
this->elapsed_time = FRAMES_TO_TIME (this, this->frame_count);
|
||||
set_timer (this, true);
|
||||
|
||||
if ((output = this->output)) {
|
||||
if ((io = this->io)) {
|
||||
b->outstanding = true;
|
||||
output->buffer_id = b->outbuf->id;
|
||||
output->status = SPA_RESULT_OK;
|
||||
io->buffer_id = b->outbuf->id;
|
||||
io->status = SPA_RESULT_OK;
|
||||
send_have_output (this);
|
||||
}
|
||||
}
|
||||
|
|
@ -684,7 +684,7 @@ spa_videotestsrc_node_port_use_buffers (SpaNode *node,
|
|||
|
||||
b = &this->buffers[i];
|
||||
b->outbuf = buffers[i];
|
||||
b->outstanding = true;
|
||||
b->outstanding = false;
|
||||
b->h = spa_buffer_find_meta (buffers[i], SPA_META_TYPE_HEADER);
|
||||
|
||||
switch (d[0].type) {
|
||||
|
|
@ -740,17 +740,10 @@ spa_videotestsrc_node_port_alloc_buffers (SpaNode *node,
|
|||
}
|
||||
|
||||
static SpaResult
|
||||
spa_videotestsrc_node_port_set_input (SpaNode *node,
|
||||
uint32_t port_id,
|
||||
SpaPortInput *input)
|
||||
{
|
||||
return SPA_RESULT_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
spa_videotestsrc_node_port_set_output (SpaNode *node,
|
||||
uint32_t port_id,
|
||||
SpaPortOutput *output)
|
||||
spa_videotestsrc_node_port_set_io (SpaNode *node,
|
||||
SpaDirection direction,
|
||||
uint32_t port_id,
|
||||
SpaPortIO *io)
|
||||
{
|
||||
SpaVideoTestSrc *this;
|
||||
|
||||
|
|
@ -759,10 +752,10 @@ spa_videotestsrc_node_port_set_output (SpaNode *node,
|
|||
|
||||
this = SPA_CONTAINER_OF (node, SpaVideoTestSrc, node);
|
||||
|
||||
if (!CHECK_PORT (this, SPA_DIRECTION_OUTPUT, port_id))
|
||||
if (!CHECK_PORT (this, direction, port_id))
|
||||
return SPA_RESULT_INVALID_PORT;
|
||||
|
||||
this->output = output;
|
||||
this->io = io;
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
|
@ -814,12 +807,30 @@ spa_videotestsrc_node_port_send_command (SpaNode *node,
|
|||
static SpaResult
|
||||
spa_videotestsrc_node_process_input (SpaNode *node)
|
||||
{
|
||||
return SPA_RESULT_INVALID_PORT;
|
||||
return SPA_RESULT_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
spa_videotestsrc_node_process_output (SpaNode *node)
|
||||
{
|
||||
SpaVideoTestSrc *this;
|
||||
VTSBuffer *b;
|
||||
|
||||
if (node == NULL)
|
||||
return SPA_RESULT_INVALID_ARGUMENTS;
|
||||
|
||||
this = SPA_CONTAINER_OF (node, SpaVideoTestSrc, node);
|
||||
|
||||
if (this->io && this->io->buffer_id != SPA_ID_INVALID) {
|
||||
b = &this->buffers[this->io->buffer_id];
|
||||
if (b->outstanding) {
|
||||
b->outstanding = false;
|
||||
spa_list_insert (this->empty.prev, &b->link);
|
||||
if (!this->props.live)
|
||||
set_timer (this, true);
|
||||
}
|
||||
this->io->buffer_id = SPA_ID_INVALID;
|
||||
}
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
|
|
@ -843,8 +854,7 @@ static const SpaNode videotestsrc_node = {
|
|||
spa_videotestsrc_node_port_set_props,
|
||||
spa_videotestsrc_node_port_use_buffers,
|
||||
spa_videotestsrc_node_port_alloc_buffers,
|
||||
spa_videotestsrc_node_port_set_input,
|
||||
spa_videotestsrc_node_port_set_output,
|
||||
spa_videotestsrc_node_port_set_io,
|
||||
spa_videotestsrc_node_port_reuse_buffer,
|
||||
spa_videotestsrc_node_port_send_command,
|
||||
spa_videotestsrc_node_process_input,
|
||||
|
|
|
|||
|
|
@ -55,7 +55,6 @@ typedef struct {
|
|||
|
||||
SpaVolumeBuffer buffers[MAX_BUFFERS];
|
||||
uint32_t n_buffers;
|
||||
|
||||
void *io;
|
||||
|
||||
SpaList empty;
|
||||
|
|
@ -565,41 +564,24 @@ spa_volume_node_port_alloc_buffers (SpaNode *node,
|
|||
}
|
||||
|
||||
static SpaResult
|
||||
spa_volume_node_port_set_input (SpaNode *node,
|
||||
uint32_t port_id,
|
||||
SpaPortInput *input)
|
||||
spa_volume_node_port_set_io (SpaNode *node,
|
||||
SpaDirection direction,
|
||||
uint32_t port_id,
|
||||
SpaPortIO *io)
|
||||
{
|
||||
SpaVolume *this;
|
||||
SpaVolumePort *port;
|
||||
|
||||
if (node == NULL)
|
||||
return SPA_RESULT_INVALID_ARGUMENTS;
|
||||
|
||||
this = SPA_CONTAINER_OF (node, SpaVolume, node);
|
||||
|
||||
if (!CHECK_PORT (this, SPA_DIRECTION_INPUT, port_id))
|
||||
if (!CHECK_PORT (this, direction, port_id))
|
||||
return SPA_RESULT_INVALID_PORT;
|
||||
|
||||
this->in_ports[port_id].io = input;
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
spa_volume_node_port_set_output (SpaNode *node,
|
||||
uint32_t port_id,
|
||||
SpaPortOutput *output)
|
||||
{
|
||||
SpaVolume *this;
|
||||
|
||||
if (node == NULL)
|
||||
return SPA_RESULT_INVALID_ARGUMENTS;
|
||||
|
||||
this = SPA_CONTAINER_OF (node, SpaVolume, node);
|
||||
|
||||
if (!CHECK_PORT (this, SPA_DIRECTION_OUTPUT, port_id))
|
||||
return SPA_RESULT_INVALID_PORT;
|
||||
|
||||
this->in_ports[port_id].io = output;
|
||||
port = direction == SPA_DIRECTION_INPUT ? &this->in_ports[port_id] : &this->out_ports[port_id];
|
||||
port->io = io;
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
|
@ -718,8 +700,8 @@ static SpaResult
|
|||
spa_volume_node_process_input (SpaNode *node)
|
||||
{
|
||||
SpaVolume *this;
|
||||
SpaPortInput *input;
|
||||
SpaPortOutput *output;
|
||||
SpaPortIO *input;
|
||||
SpaPortIO *output;
|
||||
SpaVolumePort *in_port, *out_port;
|
||||
SpaBuffer *dbuf, *sbuf;
|
||||
|
||||
|
|
@ -795,8 +777,7 @@ static const SpaNode volume_node = {
|
|||
spa_volume_node_port_set_props,
|
||||
spa_volume_node_port_use_buffers,
|
||||
spa_volume_node_port_alloc_buffers,
|
||||
spa_volume_node_port_set_input,
|
||||
spa_volume_node_port_set_output,
|
||||
spa_volume_node_port_set_io,
|
||||
spa_volume_node_port_reuse_buffer,
|
||||
spa_volume_node_port_send_command,
|
||||
spa_volume_node_process_input,
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ struct _SpaXvSink {
|
|||
SpaPortInfo info;
|
||||
SpaXvState state;
|
||||
|
||||
SpaPortInput *input;
|
||||
SpaPortIO *io;
|
||||
};
|
||||
|
||||
#define CHECK_PORT(this,d,p) ((d) == SPA_DIRECTION_OUTPUT && (p) == 0)
|
||||
|
|
@ -437,9 +437,10 @@ spa_xv_sink_node_port_alloc_buffers (SpaNode *node,
|
|||
}
|
||||
|
||||
static SpaResult
|
||||
spa_xv_sink_node_port_set_input (SpaNode *node,
|
||||
uint32_t port_id,
|
||||
SpaPortInput *input)
|
||||
spa_xv_sink_node_port_set_io (SpaNode *node,
|
||||
SpaDirection direction,
|
||||
uint32_t port_id,
|
||||
SpaPortIO *io)
|
||||
{
|
||||
SpaXvSink *this;
|
||||
|
||||
|
|
@ -448,22 +449,14 @@ spa_xv_sink_node_port_set_input (SpaNode *node,
|
|||
|
||||
this = SPA_CONTAINER_OF (node, SpaXvSink, node);
|
||||
|
||||
if (!CHECK_PORT (this, SPA_DIRECTION_INPUT, port_id))
|
||||
if (!CHECK_PORT (this, direction, port_id))
|
||||
return SPA_RESULT_INVALID_PORT;
|
||||
|
||||
this->input = input;
|
||||
this->io = io;
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
spa_xv_sink_node_port_set_output (SpaNode *node,
|
||||
uint32_t port_id,
|
||||
SpaPortOutput *output)
|
||||
{
|
||||
return SPA_RESULT_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
spa_xv_sink_node_port_reuse_buffer (SpaNode *node,
|
||||
uint32_t port_id,
|
||||
|
|
@ -513,8 +506,7 @@ static const SpaNode xvsink_node = {
|
|||
spa_xv_sink_node_port_set_props,
|
||||
spa_xv_sink_node_port_use_buffers,
|
||||
spa_xv_sink_node_port_alloc_buffers,
|
||||
spa_xv_sink_node_port_set_input,
|
||||
spa_xv_sink_node_port_set_output,
|
||||
spa_xv_sink_node_port_set_io,
|
||||
spa_xv_sink_node_port_reuse_buffer,
|
||||
spa_xv_sink_node_port_send_command,
|
||||
spa_xv_sink_node_process_input,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue