stream: improve stream API

Simplify the stream API. make just 2 methods to queue and dequeue
buffers. Make just one callback when new buffers can be dequeued.
Add support for driver nodes such as the video-src.
Pass a pw_buffer structure to add/remove_buffer and make it possible
to attach metadata to it. This makes it a lot easier to implement
the gstreamer pipewire pool.
Call the stream process function from the main loop and use a lockfree
ringbuffer to pass buffers between the threads. Make it possible to
also call process from the RT thread.
unmap the buffer data when needed.
This commit is contained in:
Wim Taymans 2018-03-22 16:40:27 +01:00
parent 97547d726f
commit f9ceedb714
11 changed files with 451 additions and 508 deletions

View file

@ -89,18 +89,17 @@ static void fill_f32(struct data *d, void *dest, int avail)
}
}
static void on_need_buffer(void *userdata)
static void on_process(void *userdata)
{
struct data *data = userdata;
uint32_t id;
struct pw_buffer *b;
struct spa_buffer *buf;
uint8_t *p;
id = pw_stream_get_empty_buffer(data->stream);
if (id == SPA_ID_INVALID)
if ((b = pw_stream_dequeue_buffer(data->stream)) == NULL)
return;
buf = pw_stream_peek_buffer(data->stream, id);
buf = b->buffer;
if ((p = buf->datas[0].data) == NULL)
return;
@ -109,12 +108,12 @@ static void on_need_buffer(void *userdata)
buf->datas[0].chunk->size = buf->datas[0].maxsize;
pw_stream_send_buffer(data->stream, id);
pw_stream_queue_buffer(data->stream, b);
}
static const struct pw_stream_events stream_events = {
PW_VERSION_STREAM_EVENTS,
.need_buffer = on_need_buffer,
.process = on_process,
};
static void on_state_changed(void *_data, enum pw_remote_state old, enum pw_remote_state state, const char *error)
@ -159,7 +158,8 @@ static void on_state_changed(void *_data, enum pw_remote_state old, enum pw_remo
PW_DIRECTION_OUTPUT,
NULL,
PW_STREAM_FLAG_AUTOCONNECT |
PW_STREAM_FLAG_MAP_BUFFERS,
PW_STREAM_FLAG_MAP_BUFFERS |
PW_STREAM_FLAG_RT_PROCESS,
params, 1);
break;
}

View file

@ -87,25 +87,31 @@ static void handle_events(struct data *data)
}
}
static int
do_render(struct spa_loop *loop, bool async, uint32_t seq,
const void *_data, size_t size, void *user_data)
static void
on_process(void *_data)
{
struct data *data = user_data;
struct spa_buffer *buf = ((struct spa_buffer **) _data)[0];
struct data *data = _data;
struct pw_stream *stream = data->stream;
struct pw_buffer *b;
struct spa_buffer *buf;
void *sdata, *ddata;
int sstride, dstride, ostride;
uint32_t i;
uint8_t *src, *dst;
b = pw_stream_dequeue_buffer(stream);
buf = b->buffer;
pw_log_trace("new buffer %d", buf->id);
handle_events(data);
if ((sdata = buf->datas[0].data) == NULL)
return -EINVAL;
return;
if (SDL_LockTexture(data->texture, NULL, &ddata, &dstride) < 0) {
fprintf(stderr, "Couldn't lock texture: %s\n", SDL_GetError());
return -EIO;
return;
}
sstride = buf->datas[0].chunk->stride;
ostride = SPA_MIN(sstride, dstride);
@ -123,25 +129,8 @@ do_render(struct spa_loop *loop, bool async, uint32_t seq,
SDL_RenderCopy(data->renderer, data->texture, NULL, NULL);
SDL_RenderPresent(data->renderer);
return 0;
}
static void
on_stream_new_buffer(void *_data, uint32_t id)
{
struct data *data = _data;
struct pw_stream *stream = data->stream;
struct spa_buffer *buf;
buf = pw_stream_peek_buffer(stream, id);
pw_log_trace("new buffer %d", id);
pw_loop_invoke(pw_main_loop_get_loop(data->loop), do_render,
SPA_ID_INVALID, &buf, sizeof(struct spa_buffer *),
true, data);
pw_stream_recycle_buffer(stream, id);
pw_stream_queue_buffer(stream, b);
}
static void on_stream_state_changed(void *_data, enum pw_stream_state old,
@ -281,7 +270,7 @@ static const struct pw_stream_events stream_events = {
PW_VERSION_STREAM_EVENTS,
.state_changed = on_stream_state_changed,
.format_changed = on_stream_format_changed,
.new_buffer = on_stream_new_buffer,
.process = on_process,
};
static void on_state_changed(void *_data, enum pw_remote_state old, enum pw_remote_state state, const char *error)

View file

@ -71,7 +71,7 @@ struct data {
static void on_timeout(void *userdata, uint64_t expirations)
{
struct data *data = userdata;
uint32_t id;
struct pw_buffer *b;
struct spa_buffer *buf;
int i, j;
uint8_t *p, *map;
@ -79,13 +79,12 @@ static void on_timeout(void *userdata, uint64_t expirations)
pw_log_trace("timeout");
id = pw_stream_get_empty_buffer(data->stream);
if (id == SPA_ID_INVALID) {
b = pw_stream_dequeue_buffer(data->stream);
if (b == NULL) {
pw_log_warn("out of buffers");
return;
}
buf = pw_stream_peek_buffer(data->stream, id);
buf = b->buffer;
if (buf->datas[0].type == data->t->data.MemFd ||
buf->datas[0].type == data->t->data.DmaBuf) {
@ -129,7 +128,7 @@ static void on_timeout(void *userdata, uint64_t expirations)
buf->datas[0].chunk->size = buf->datas[0].maxsize;
pw_stream_send_buffer(data->stream, id);
pw_stream_queue_buffer(data->stream, b);
}
static void on_stream_state_changed(void *_data, enum pw_stream_state old, enum pw_stream_state state,
@ -240,7 +239,7 @@ static void on_state_changed(void *_data, enum pw_remote_state old, enum pw_remo
pw_stream_connect(data->stream,
PW_DIRECTION_OUTPUT,
NULL, PW_STREAM_FLAG_NONE,
NULL, PW_STREAM_FLAG_DRIVER,
params, 1);
break;
}