From 1169c2419bdc25a2e6e061e8dc4926d436debc54 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 3 Aug 2016 21:33:57 +0200 Subject: [PATCH] Make buffer data point to memory blocks Make buffer data point to a registered memory block by its mem_id. Add some more helpers to allocate memfd backed memory. Allocate buffers in memfd so that we easily share them between client and server. Update pts and seq in v4l2 now that this change will actually be visible at the client. --- pinos/client/pinos.c | 2 + pinos/client/stream.c | 85 ++++------------- pinos/daemon/main.c | 2 + pinos/gst/gstpinos.c | 2 + pinos/gst/gstpinossink.c | 5 +- pinos/gst/gstpinossrc.c | 34 +++---- pinos/modules/spa/spa-alsa-sink.c | 7 +- spa/include/spa/buffer.h | 38 ++------ spa/include/spa/control.h | 4 +- spa/include/spa/memory.h | 8 ++ spa/lib/control.c | 102 -------------------- spa/lib/debug.c | 45 ++++----- spa/lib/memory.c | 106 +++++++++++++++++++++ spa/plugins/audiomixer/audiomixer.c | 8 +- spa/plugins/remote/proxy.c | 143 +++++++++++++++++++--------- spa/plugins/v4l2/v4l2-source.c | 7 +- spa/plugins/v4l2/v4l2-utils.c | 109 ++++++++++++--------- spa/plugins/volume/volume.c | 17 ++-- spa/tests/test-v4l2.c | 15 ++- 19 files changed, 383 insertions(+), 356 deletions(-) diff --git a/pinos/client/pinos.c b/pinos/client/pinos.c index a169a1e78..c12e47aa7 100644 --- a/pinos/client/pinos.c +++ b/pinos/client/pinos.c @@ -20,6 +20,7 @@ #include #include "pinos/client/pinos.h" +#include "spa/include/spa/memory.h" /** * pinos_init: @@ -33,6 +34,7 @@ void pinos_init (int *argc, char **argv[]) { gst_init (argc, argv); + spa_memory_init (); } /** diff --git a/pinos/client/stream.c b/pinos/client/stream.c index 6c96aa133..cc835abeb 100644 --- a/pinos/client/stream.c +++ b/pinos/client/stream.c @@ -33,23 +33,12 @@ #include "pinos/client/private.h" #include "spa/include/spa/control.h" +#include "spa/include/spa/debug.h" +#include "spa/include/spa/memory.h" #define MAX_BUFFER_SIZE 1024 #define MAX_FDS 16 -typedef struct { - bool cleanup; - uint32_t id; - int fd; -} MemId; - -static void -clear_mem_id (MemId *id) -{ - close (id->fd); - id->fd = -1; -} - typedef struct { bool cleanup; uint32_t id; @@ -104,7 +93,6 @@ struct _PinosStreamPrivate guint8 send_data[MAX_BUFFER_SIZE]; int send_fds[MAX_FDS]; - GArray *mem_ids; GArray *buffer_ids; }; @@ -430,8 +418,6 @@ pinos_stream_init (PinosStream * stream) g_debug ("new stream %p", stream); priv->state = PINOS_STREAM_STATE_UNCONNECTED; - priv->mem_ids = g_array_sized_new (FALSE, FALSE, sizeof (MemId), 64); - g_array_set_clear_func (priv->mem_ids, (GDestroyNotify) clear_mem_id); priv->buffer_ids = g_array_sized_new (FALSE, FALSE, sizeof (BufferId), 64); g_array_set_clear_func (priv->buffer_ids, (GDestroyNotify) clear_buffer_id); } @@ -565,19 +551,6 @@ find_buffer (PinosStream *stream, uint32_t id) return NULL; } -static MemId * -find_mem (PinosStream *stream, uint32_t id) -{ - PinosStreamPrivate *priv = stream->priv; - guint i; - for (i = 0; i < priv->mem_ids->len; i++) { - MemId *mid = &g_array_index (priv->mem_ids, MemId, i); - if (mid->id == id) - return mid; - } - return NULL; -} - static gboolean parse_control (PinosStream *stream, SpaControl *ctrl) @@ -664,7 +637,7 @@ parse_control (PinosStream *stream, case SPA_CONTROL_CMD_ADD_MEM: { SpaControlCmdAddMem p; - MemId mid; + SpaMemory *mem; int fd; if (spa_control_iter_parse_cmd (&it, &p) < 0) @@ -674,44 +647,44 @@ parse_control (PinosStream *stream, if (fd == -1) break; - g_debug ("add mem %d, %d", p.mem_id, fd); - mid.cleanup = false; - mid.id = p.mem_id; - mid.fd = fd; - g_array_append_val (priv->mem_ids, mid); + g_debug ("add mem %d, %d, %d", p.mem_id, fd, p.flags); + mem = spa_memory_import (0, p.mem_id); + mem->flags = p.flags; + mem->fd = fd; + mem->ptr = NULL; + mem->size = p.size; break; } case SPA_CONTROL_CMD_REMOVE_MEM: { SpaControlCmdRemoveMem p; - MemId *mid; + SpaMemory *mem; if (spa_control_iter_parse_cmd (&it, &p) < 0) break; g_debug ("stream %p: stop", stream); - if ((mid = find_mem (stream, p.mem_id))) - mid->cleanup = true; + mem = spa_memory_find (0, p.mem_id); + if (--mem->refcount == 0) + mem->notify (mem); break; } case SPA_CONTROL_CMD_ADD_BUFFER: { SpaControlCmdAddBuffer p; BufferId bid; + SpaMemory *mem; if (spa_control_iter_parse_cmd (&it, &p) < 0) break; - bid.fd = spa_control_get_fd (ctrl, p.fd_index, false); - if (bid.fd == -1) - break; - g_debug ("add buffer %d", p.buffer_id); + mem = spa_memory_find (0, p.mem_id); bid.cleanup = false; bid.id = p.buffer_id; bid.offset = p.offset; bid.size = p.size; - bid.buf = mmap (NULL, p.size, PROT_READ | PROT_WRITE, MAP_SHARED, bid.fd, p.offset); + bid.buf = (SpaBuffer *)((uint8_t*) spa_memory_ensure_ptr (mem) + p.offset); spa_debug_buffer (bid.buf); g_array_append_val (priv->buffer_ids, bid); @@ -733,29 +706,16 @@ parse_control (PinosStream *stream, case SPA_CONTROL_CMD_PROCESS_BUFFER: { SpaControlCmdProcessBuffer p; - unsigned int i; BufferId *bid; if (spa_control_iter_parse_cmd (&it, &p) < 0) break; if ((bid = find_buffer (stream, p.buffer_id))) { - SpaBuffer *b = bid->buf; - SpaData *d = SPA_BUFFER_DATAS (b); - - for (i = 0; i < b->n_datas; i++) { - if (d[i].type == SPA_DATA_TYPE_MEMID) { - uint32_t id = SPA_PTR_TO_UINT32 (d[i].ptr); - MemId *mid; - - if ((mid = find_mem (stream, id))) { - d[i].type = SPA_DATA_TYPE_FD; - d[i].ptr = SPA_INT_TO_PTR (mid->fd); - } - } - } - priv->buffer = b; + priv->buffer = bid->buf; + spa_debug_buffer (bid->buf); } + break; } case SPA_CONTROL_CMD_REUSE_BUFFER: @@ -810,13 +770,6 @@ on_socket_condition (GSocket *socket, send_need_input (stream, 0, priv->buffer->id); priv->buffer = NULL; } - for (i = 0; i < priv->mem_ids->len; i++) { - MemId *mid = &g_array_index (priv->mem_ids, MemId, i); - if (mid->cleanup) { - g_array_remove_index_fast (priv->mem_ids, i); - i--; - } - } for (i = 0; i < priv->buffer_ids->len; i++) { BufferId *bid = &g_array_index (priv->buffer_ids, BufferId, i); if (bid->cleanup) { diff --git a/pinos/daemon/main.c b/pinos/daemon/main.c index 71f3b823c..10c8bf5e9 100644 --- a/pinos/daemon/main.c +++ b/pinos/daemon/main.c @@ -24,6 +24,7 @@ #include #include #include +#include gint main (gint argc, gchar *argv[]) @@ -34,6 +35,7 @@ main (gint argc, gchar *argv[]) PinosNodeFactory *factory; pinos_init (&argc, &argv); + spa_memory_init (); loop = g_main_loop_new (NULL, FALSE); diff --git a/pinos/gst/gstpinos.c b/pinos/gst/gstpinos.c index db4ef2f74..4c1f4a66c 100644 --- a/pinos/gst/gstpinos.c +++ b/pinos/gst/gstpinos.c @@ -46,6 +46,8 @@ GST_DEBUG_CATEGORY (pinos_debug); static gboolean plugin_init (GstPlugin * plugin) { + pinos_init (NULL, NULL); + // gst_element_register (plugin, "pinospay", GST_RANK_NONE, // GST_TYPE_PINOS_PAY); // gst_element_register (plugin, "pinosdepay", GST_RANK_NONE, diff --git a/pinos/gst/gstpinossink.c b/pinos/gst/gstpinossink.c index b5cd19b33..6b27b6d0e 100644 --- a/pinos/gst/gstpinossink.c +++ b/pinos/gst/gstpinossink.c @@ -562,9 +562,8 @@ gst_pinos_sink_render (GstBaseSink * bsink, GstBuffer * buffer) b->mem = mem; b->fd = gst_fd_memory_get_fd (mem); - b->datas[0].type = SPA_DATA_TYPE_FD; - b->datas[0].ptr = &b->fd; - b->datas[0].ptr_type = mem->allocator->mem_type; + + b->datas[0].mem_id = 0; b->datas[0].offset = mem->offset; b->datas[0].size = mem->size; b->datas[0].stride = 0; diff --git a/pinos/gst/gstpinossrc.c b/pinos/gst/gstpinossrc.c index 016776772..39b92fed7 100644 --- a/pinos/gst/gstpinossrc.c +++ b/pinos/gst/gstpinossrc.c @@ -44,6 +44,7 @@ #include #include +#include #include @@ -385,28 +386,21 @@ on_new_buffer (GObject *gobject, } for (i = 0; i < b->n_datas; i++) { SpaData *d = &SPA_BUFFER_DATAS (b)[i]; + SpaMemory *mem; - switch (d->type) { - case SPA_DATA_TYPE_MEMPTR: - { - gst_buffer_append_memory (buf, - gst_memory_new_wrapped (0, d->ptr, d->offset + d->size, d->offset, - d->size, NULL, NULL)); - break; - } - case SPA_DATA_TYPE_FD: - { - GstMemory *fdmem = NULL; - int fd = SPA_PTR_TO_INT (d->ptr); + mem = spa_memory_find (0, d->mem_id); - fdmem = gst_fd_allocator_alloc (pinossrc->fd_allocator, dup (fd), - d->offset + d->size, GST_FD_MEMORY_FLAG_NONE); - gst_memory_resize (fdmem, d->offset, d->size); - gst_buffer_append_memory (buf, fdmem); - break; - } - default: - break; + if (mem->fd) { + GstMemory *fdmem = NULL; + + fdmem = gst_fd_allocator_alloc (pinossrc->fd_allocator, dup (mem->fd), + d->offset + d->size, GST_FD_MEMORY_FLAG_NONE); + gst_memory_resize (fdmem, d->offset, d->size); + gst_buffer_append_memory (buf, fdmem); + } else { + gst_buffer_append_memory (buf, + gst_memory_new_wrapped (0, mem->ptr, mem->size, d->offset, + d->size, NULL, NULL)); } } diff --git a/pinos/modules/spa/spa-alsa-sink.c b/pinos/modules/spa/spa-alsa-sink.c index 34687add4..8990bd90d 100644 --- a/pinos/modules/spa/spa-alsa-sink.c +++ b/pinos/modules/spa/spa-alsa-sink.c @@ -27,6 +27,7 @@ #include #include +#include #include #include "spa-alsa-sink.h" @@ -438,15 +439,15 @@ on_received_buffer (PinosPort *port, for (i = 0; i < buffer->n_datas; i++) { SpaData *d = SPA_BUFFER_DATAS (buffer); + SpaMemory *mem; PinosRingbufferArea areas[2]; uint8_t *data; size_t size, towrite, total; - if (d[i].type != SPA_DATA_TYPE_MEMPTR) - continue; + mem = spa_memory_find (0, d[i].mem_id); size = d[i].size; - data = (guint8*)d[i].ptr + d[i].offset; + data = (guint8*)mem->ptr + d[i].offset; pinos_ringbuffer_get_write_areas (priv->ringbuffer, areas); diff --git a/spa/include/spa/buffer.h b/spa/include/spa/buffer.h index b02cd1085..59be11415 100644 --- a/spa/include/spa/buffer.h +++ b/spa/include/spa/buffer.h @@ -98,39 +98,15 @@ typedef struct { size_t size; } SpaMeta; -/** - * SpaDataType: - * @SPA_DATA_TYPE_INVALID: invalid data type, is ignored - * @SPA_DATA_TYPE_MEMPTR: data and size point to memory accessible by the - * CPU. - * @SPA_DATA_TYPE_FD: data points to an int file descriptor that can be - * mmapped. - * @SPA_DATA_TYPE_MEMID: data points to the id of the memory block to use - * @SPA_DATA_TYPE_POINTER: data points to some other datastructure, the - * type can be found in ptr_type - */ -typedef enum { - SPA_DATA_TYPE_INVALID = 0, - SPA_DATA_TYPE_MEMPTR, - SPA_DATA_TYPE_FD, - SPA_DATA_TYPE_MEMID, - SPA_DATA_TYPE_POINTER, -} SpaDataType; - /** * SpaData: - * @id: user id - * @type: the type of data - * @ptr_type: more info about the type of @ptr - * @ptr: pointer to data or fd - * @offset: offset of data - * @size: size of data - * @stride: stride of data if applicable + * @mem_id: the memory id to use + * @offset: offset of memory + * @size: size of memory + * @stride: stride of memory if applicable */ typedef struct { - SpaDataType type; - const char *ptr_type; - void *ptr; + uint32_t mem_id; off_t offset; size_t size; size_t stride; @@ -139,6 +115,8 @@ typedef struct { /** * SpaBuffer: * @id: buffer id + * @mem_id: memory id of the buffer + * @offset: offset into the memory * @size: total size of the buffer structure * @n_metas: number of metadata * @metas: offset of array of @n_metas metadata @@ -147,6 +125,8 @@ typedef struct { */ struct _SpaBuffer { uint32_t id; + uint32_t mem_id; + off_t offset; size_t size; unsigned int n_metas; off_t metas; diff --git a/spa/include/spa/control.h b/spa/include/spa/control.h index fcf061e6f..1244320df 100644 --- a/spa/include/spa/control.h +++ b/spa/include/spa/control.h @@ -165,7 +165,7 @@ typedef struct { uint32_t mem_id; uint32_t mem_type; uint32_t fd_index; - uint64_t offset; + uint32_t flags; uint64_t size; } SpaControlCmdAddMem; @@ -179,7 +179,7 @@ typedef struct { typedef struct { uint32_t port_id; uint32_t buffer_id; - int fd_index; + uint32_t mem_id; uint64_t offset; uint64_t size; } SpaControlCmdAddBuffer; diff --git a/spa/include/spa/memory.h b/spa/include/spa/memory.h index a8305e1da..f9ea8fa69 100644 --- a/spa/include/spa/memory.h +++ b/spa/include/spa/memory.h @@ -41,6 +41,8 @@ typedef enum { SPA_MEMORY_FLAG_WRITABLE = (1 << 1), } SpaMemoryFlags; +#define SPA_MEMORY_FLAG_READWRITE (SPA_MEMORY_FLAG_READABLE|SPA_MEMORY_FLAG_WRITABLE) + /** * SpaMemory: * @refcount: a refcount @@ -65,15 +67,21 @@ struct _SpaMemory { size_t size; }; +void spa_memory_init (void); + uint32_t spa_memory_pool_get (uint32_t type); uint32_t spa_memory_pool_new (void); void spa_memory_pool_free (uint32_t); SpaMemory * spa_memory_alloc (uint32_t pool_id); +SpaMemory * spa_memory_alloc_with_fd (uint32_t pool_id, void *data, size_t size); SpaResult spa_memory_free (uint32_t pool_id, uint32_t id); +SpaMemory * spa_memory_import (uint32_t pool_id, uint32_t id); SpaMemory * spa_memory_find (uint32_t pool_id, uint32_t id); +void * spa_memory_ensure_ptr (SpaMemory *mem); + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/spa/lib/control.c b/spa/lib/control.c index cac534d3e..d4556e2b9 100644 --- a/spa/lib/control.c +++ b/spa/lib/control.c @@ -339,54 +339,6 @@ spa_control_iter_get_data (SpaControlIter *iter, size_t *size) return si->data; } -#if 0 -typedef struct { - SpaBuffer buffer; - SpaMeta metas[16]; - SpaData datas[16]; - int memid[16]; -} MyBuffer; - -static SpaResult -parse_add_buffer (struct stack_iter *si, - SpaControlCmdAddBuffer *command) -{ - MyBuffer *b; - uint32_t *p = si->data; - unsigned int i; - - command->port_id = *p++; - b = malloc (sizeof (MyBuffer)); - b->buffer.id = *(uint32_t *)p++; - b->buffer.size = *(uint32_t *)p++; - b->buffer.n_metas = *(uint32_t *)p++; - b->buffer.metas = offsetof (MyBuffer, metas); - b->buffer.n_datas = *(uint32_t *)p++; - b->buffer.datas = offsetof (MyBuffer, datas); - - for (i = 0; i < b->buffer.n_metas; i++) { - SpaMeta *m = &b->metas[i]; - m->type = *p++; - m->size = *p++; - m->offset = 0; - p = p + (m->size + 3) / 4; - } - for (i = 0; i < b->buffer.n_datas; i++) { - SpaData *d = &b->datas[i]; - d->type = SPA_DATA_TYPE_MEMID; - d->ptr_type = NULL; - b->memid[i] = *p++; - d->ptr = &b->memid[i]; - d->offset = *p++; - d->size = *p++; - d->stride = *p++; - } - command->buffer = &b->buffer; - - return SPA_RESULT_OK; -} -#endif - SpaResult spa_control_iter_parse_cmd (SpaControlIter *iter, void *command) @@ -719,60 +671,6 @@ builder_add_cmd (struct stack_builder *sb, SpaControlCmd cmd, size_t size) return p; } -#if 0 -static SpaResult -build_add_buffer (struct stack_builder *sb, - SpaControlCmdAddBuffer *command) -{ - unsigned int i; - size_t size; - SpaBuffer *b = command->buffer; - uint32_t *p; - - /* port + id + size + n_metas + n_datas */ - size = 4 + 4 + 4 + 4 + 4; - - for (i = 0; i < b->n_metas; i++) { - SpaMeta *m = &b->metas[i]; - /* type + size + data */ - size += 4 + 4 + m->size; - } - for (i = 0; i < b->n_datas; i++) { - SpaData *d = &b->datas[i]; - if (d->type != SPA_DATA_TYPE_MEMID) - continue; - /* memidx + offset + size + stride */ - size += 4 + 4 + 4 + 4; - } - p = builder_add_cmd (sb, SPA_CONTROL_CMD_ADD_BUFFER, size); - - *p++ = command->port_id; - *p++ = b->id; - *p++ = b->size; - *p++ = b->n_metas; - *p++ = b->n_datas; - - for (i = 0; i < b->n_metas; i++) { - SpaMeta *m = &b->metas[i]; - - *p++ = m->type; - *p++ = m->size; - memcpy (p, m->data, m->size); - p = p + m->size / 4; - } - for (i = 0; i < b->n_datas; i++) { - SpaData *d = &b->datas[i]; - if (d->type != SPA_DATA_TYPE_MEMID) - continue; - *p++ = *((uint32_t*)(d->ptr)); - *p++ = d->offset; - *p++ = d->size; - *p++ = d->stride; - } - return SPA_RESULT_OK; -} -#endif - /** * spa_control_builder_add_cmd: * @builder: a #SpaControlBuilder diff --git a/spa/lib/debug.c b/spa/lib/debug.c index 4efce1285..d80ac8d83 100644 --- a/spa/lib/debug.c +++ b/spa/lib/debug.c @@ -20,6 +20,7 @@ #include #include "spa/debug.h" +#include "spa/memory.h" SpaResult spa_debug_port_info (const SpaPortInfo *info) @@ -88,9 +89,11 @@ spa_debug_buffer (const SpaBuffer *buffer) return SPA_RESULT_INVALID_ARGUMENTS; fprintf (stderr, "SpaBuffer %p:\n", buffer); - fprintf (stderr, " id: \t%08x\n", buffer->id); - fprintf (stderr, " size: \t%zd\n", buffer->size); - fprintf (stderr, " n_metas: \t%u (offset %zd)\n", buffer->n_metas, buffer->metas); + fprintf (stderr, " id: %08X\n", buffer->id); + fprintf (stderr, " mem_id: %08X\n", buffer->mem_id); + fprintf (stderr, " offset: %zd\n", buffer->offset); + fprintf (stderr, " size: %zd\n", buffer->size); + fprintf (stderr, " n_metas: %u (offset %zd)\n", buffer->n_metas, buffer->metas); for (i = 0; i < buffer->n_metas; i++) { SpaMeta *m = &SPA_BUFFER_METAS (buffer)[i]; fprintf (stderr, " meta %d: type %d, offset %zd, size %zd:\n", i, m->type, m->offset, m->size); @@ -121,26 +124,24 @@ spa_debug_buffer (const SpaBuffer *buffer) fprintf (stderr, " n_datas: \t%u (offset %zd)\n", buffer->n_datas, buffer->datas); for (i = 0; i < buffer->n_datas; i++) { SpaData *d = &SPA_BUFFER_DATAS (buffer)[i]; - fprintf (stderr, " data %d: type %d\n", i, d->type); - switch (d->type) { - case SPA_DATA_TYPE_MEMPTR: - fprintf (stderr, " memptr %p\n", d->ptr); - break; - case SPA_DATA_TYPE_FD: - fprintf (stderr, " fd %d\n", SPA_PTR_TO_INT (d->ptr)); - break; - case SPA_DATA_TYPE_MEMID: - fprintf (stderr, " memid %d\n", SPA_PTR_TO_UINT32 (d->ptr)); - break; - case SPA_DATA_TYPE_POINTER: - fprintf (stderr, " pointer %p\n", d->ptr); - break; - default: - break; + SpaMemory *mem; + + mem = spa_memory_find (0, d->mem_id); + fprintf (stderr, " data %d: (memory %p)\n", i, mem); + if (mem) { + fprintf (stderr, " pool_id: %u\n", mem->pool_id); + fprintf (stderr, " id: %u\n", mem->id); + fprintf (stderr, " flags: %08x\n", mem->flags); + fprintf (stderr, " type: %s\n", mem->type ? mem->type : "*unknown*"); + fprintf (stderr, " fd: %d\n", mem->fd); + fprintf (stderr, " ptr: %p\n", mem->ptr); + fprintf (stderr, " size: %zd\n", mem->size); + } else { + fprintf (stderr, " invalid memory reference\n"); } - fprintf (stderr, " offset %zd:\n", d->offset); - fprintf (stderr, " size %zd:\n", d->size); - fprintf (stderr, " stride %zd:\n", d->stride); + fprintf (stderr, " offset: %zd\n", d->offset); + fprintf (stderr, " size: %zd\n", d->size); + fprintf (stderr, " stride: %zd\n", d->stride); } return SPA_RESULT_OK; } diff --git a/spa/lib/memory.c b/spa/lib/memory.c index c202ef54d..cc79dffdb 100644 --- a/spa/lib/memory.c +++ b/spa/lib/memory.c @@ -17,7 +17,16 @@ * Boston, MA 02110-1301, USA. */ +#define _GNU_SOURCE + +#include +#include #include +#include +#include +#include +#include +#include #include "spa/memory.h" @@ -39,6 +48,7 @@ spa_memory_pool_init (SpaMemoryPool *pool, uint32_t id) { int i; + memset (pool, 0, sizeof (SpaMemoryPool)); for (i = 0; i < MAX_MEMORIES; i++) pool->free_mem[i] = MAX_MEMORIES - 1 - i; pool->n_free = MAX_MEMORIES; @@ -103,12 +113,84 @@ spa_memory_alloc (uint32_t pool_id) mem = &pool->memories[id]; mem->refcount = 1; + mem->notify = NULL; mem->pool_id = pool_id; mem->id = id; return mem; } +SpaMemory * +spa_memory_alloc_with_fd (uint32_t pool_id, void *data, size_t size) +{ + SpaMemory *mem; + char filename[] = "/dev/shm/spa-tmpfile.XXXXXX"; + + if (!(mem = spa_memory_alloc (pool_id))) + return NULL; + + mem->fd = mkostemp (filename, O_CLOEXEC); + if (mem->fd == -1) { + fprintf (stderr, "Failed to create temporary file: %s\n", strerror (errno)); + return NULL; + } + unlink (filename); + + if (data) { + if (write (mem->fd, data, size) != (ssize_t) size) { + fprintf (stderr, "Failed to write data: %s\n", strerror (errno)); + close (mem->fd); + return NULL; + } + } else { + if (ftruncate (mem->fd, size) < 0) { + fprintf (stderr, "Failed to truncate temporary file: %s\n", strerror (errno)); + close (mem->fd); + return NULL; + } + } + + mem->flags = SPA_MEMORY_FLAG_READWRITE; + mem->ptr = NULL; + mem->size = size; + + return mem; +} + + +SpaMemory * +spa_memory_import (uint32_t pool_id, uint32_t id) +{ + SpaMemory *mem = NULL; + SpaMemoryPool *pool; + int i; + bool init = false; + + if (pool_id >= MAX_POOLS || !pools[pool_id].valid) + return NULL; + + pool = &pools[pool_id]; + + for (i = 0; i < pool->n_free; i++) { + if (pool->free_mem[i] == id) { + pool->free_mem[i] = pool->free_mem[pool->n_free - 1]; + pool->n_free--; + init = true; + break; + } + } + + mem = &pool->memories[id]; + if (init) { + mem->refcount = 1; + mem->notify = NULL; + mem->pool_id = pool_id; + mem->id = id; + } + + return mem; +} + SpaResult spa_memory_free (uint32_t pool_id, uint32_t id) { @@ -139,3 +221,27 @@ spa_memory_find (uint32_t pool_id, uint32_t id) return &pool->memories[id]; } + +void * +spa_memory_ensure_ptr (SpaMemory *mem) +{ + int prot = 0; + + if (mem == NULL) + return NULL; + + if (mem->ptr) + return mem->ptr; + + if (mem->flags & SPA_MEMORY_FLAG_READABLE) + prot |= PROT_READ; + if (mem->flags & SPA_MEMORY_FLAG_WRITABLE) + prot |= PROT_WRITE; + + mem->ptr = mmap (NULL, mem->size, prot, MAP_SHARED, mem->fd, 0); + if (mem->ptr == MAP_FAILED) { + mem->ptr = NULL; + fprintf (stderr, "Failed to mmap memory %p: %s\n", mem, strerror (errno)); + } + return mem->ptr; +} diff --git a/spa/plugins/audiomixer/audiomixer.c b/spa/plugins/audiomixer/audiomixer.c index cb17f9974..1aa03666c 100644 --- a/spa/plugins/audiomixer/audiomixer.c +++ b/spa/plugins/audiomixer/audiomixer.c @@ -21,6 +21,7 @@ #include #include +#include #include #define MAX_PORTS 128 @@ -590,16 +591,19 @@ add_port_data (SpaAudioMixer *this, SpaBuffer *out, SpaAudioMixerPort *port) size_t os, is, chunk; SpaData *odatas = SPA_BUFFER_DATAS (out); SpaData *idatas = SPA_BUFFER_DATAS (port->buffer); + SpaMemory *mem; op = ip = NULL; while (true) { if (op == NULL) { - op = odatas[oi].ptr; + mem = spa_memory_find (0, odatas[oi].mem_id); + op = (uint8_t*)mem->ptr + odatas[oi].offset; os = odatas[oi].size; } if (ip == NULL) { - ip = idatas[port->buffer_index].ptr; + mem = spa_memory_find (0, idatas[port->buffer_index].mem_id); + ip = (uint8_t*)mem->ptr + odatas[oi].offset; is = idatas[port->buffer_index].size; ip += port->buffer_offset; is -= port->buffer_offset; diff --git a/spa/plugins/remote/proxy.c b/spa/plugins/remote/proxy.c index f5bdbdd6b..9673812ba 100644 --- a/spa/plugins/remote/proxy.c +++ b/spa/plugins/remote/proxy.c @@ -17,8 +17,6 @@ * Boston, MA 02110-1301, USA. */ -#define _GNU_SOURCE - #include #include #include @@ -31,6 +29,7 @@ #include +#include #include #define MAX_INPUTS 64 @@ -548,25 +547,6 @@ spa_proxy_node_port_get_status (SpaNode *node, return SPA_RESULT_OK; } -static int -tmpfile_create (void *data, size_t size) -{ - char filename[] = "/dev/shm/tmpfilepay.XXXXXX"; - int fd; - - fd = mkostemp (filename, O_CLOEXEC); - if (fd == -1) { - fprintf (stderr, "Failed to create temporary file: %s\n", strerror (errno)); - return -1; - } - unlink (filename); - - if (write (fd, data, size) != (ssize_t) size) - fprintf (stderr, "Failed to write data: %s\n", strerror (errno)); - - return fd; -} - static SpaResult add_buffer (SpaProxy *this, uint32_t port_id, SpaBuffer *buffer) { @@ -574,53 +554,57 @@ add_buffer (SpaProxy *this, uint32_t port_id, SpaBuffer *buffer) SpaControlBuilder builder; uint8_t buf[1024]; int fds[16]; + SpaControlCmdAddMem am; SpaControlCmdAddBuffer ab; - int fd, i; + int i; SpaResult res; SpaBuffer *b; + SpaMemory *bmem; spa_control_builder_init_into (&builder, buf, sizeof (buf), fds, sizeof (fds)); - fd = tmpfile_create (buffer, buffer->size); + if (buffer->mem_id == SPA_ID_INVALID) { + fprintf (stderr, "proxy %p: alloc buffer space\n", this); + bmem = spa_memory_alloc_with_fd (0, buffer, buffer->size); + b = spa_memory_ensure_ptr (bmem); + b->mem_id = bmem->id; + b->offset = 0; + } else { + bmem = spa_memory_find (0, buffer->mem_id); + b = buffer; + } + + am.port_id = port_id; + am.mem_id = bmem->id; + am.mem_type = 0; + am.fd_index = spa_control_builder_add_fd (&builder, bmem->fd, false); + am.flags = bmem->flags; + am.size = bmem->size; + spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_ADD_MEM, &am); - b = mmap (NULL, buffer->size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); for (i = 0; i < b->n_datas; i++) { SpaData *d = &SPA_BUFFER_DATAS (b)[i]; - int fd; - SpaControlCmdAddMem am; - bool tmpfile; + SpaMemory *mem; - if (d->type == SPA_DATA_TYPE_FD) { - fd = SPA_PTR_TO_INT (d->ptr); - tmpfile = false; - } else if (d->type == SPA_DATA_TYPE_MEMPTR) { - fd = tmpfile_create (d->ptr, d->size + d->offset); - tmpfile = true; - } else { - fprintf (stderr, "proxy %p: invalid mem type received %d\n", this, d->type); + if (!(mem = spa_memory_find (0, d->mem_id))) { + fprintf (stderr, "proxy %p: error invalid memory\n", this); continue; } am.port_id = port_id; - am.mem_id = b->id * 64 + i; + am.mem_id = mem->id; am.mem_type = 0; - am.fd_index = spa_control_builder_add_fd (&builder, fd, tmpfile ? true : false); - am.offset = d->offset; - am.size = d->size; + am.fd_index = spa_control_builder_add_fd (&builder, mem->fd, false); + am.flags = mem->flags; + am.size = mem->size; spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_ADD_MEM, &am); - - d->type = SPA_DATA_TYPE_MEMID; - d->ptr_type = NULL; - d->ptr = SPA_UINT32_TO_PTR (am.mem_id); - d->offset = 0; } ab.port_id = port_id; ab.buffer_id = b->id; - ab.fd_index = spa_control_builder_add_fd (&builder, fd, true); - ab.offset = 0; + ab.mem_id = bmem->id; + ab.offset = b->offset; ab.size = b->size; spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_ADD_BUFFER, &ab); - munmap (b, buffer->size); spa_control_builder_end (&builder, &control); @@ -632,6 +616,71 @@ add_buffer (SpaProxy *this, uint32_t port_id, SpaBuffer *buffer) return SPA_RESULT_OK; } +#if 0 +static SpaResult +add_buffer (SpaProxy *this, uint32_t port_id, SpaBuffer *buffer) +{ + SpaControl control; + SpaControlBuilder builder; + uint8_t buf[1024]; + int fds[16]; + SpaControlCmdAddMem am; + SpaControlCmdAddBuffer ab; + int i; + SpaResult res; + SpaBuffer *b; + SpaMemory *bmem; + + spa_control_builder_init_into (&builder, buf, sizeof (buf), fds, sizeof (fds)); + + bmem = spa_memory_alloc_with_fd (0, buffer, buffer->size); + b = spa_memory_ensure_ptr (bmem); + b->mem_id = bmem->id; + b->offset = 0; + + am.port_id = port_id; + am.mem_id = bmem->id; + am.mem_type = 0; + am.fd_index = spa_control_builder_add_fd (&builder, bmem->fd, false); + am.offset = 0; + am.size = buffer->size; + spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_ADD_MEM, &am); + + for (i = 0; i < b->n_datas; i++) { + SpaData *d = &SPA_BUFFER_DATAS (b)[i]; + SpaMemory *mem; + + if (!(mem = spa_memory_find (0, d->mem_id))) { + fprintf (stderr, "proxy %p: error invalid memory\n", this); + continue; + } + + am.port_id = port_id; + am.mem_id = mem->id; + am.mem_type = 0; + am.fd_index = spa_control_builder_add_fd (&builder, mem->fd, false); + am.offset = d->offset; + am.size = d->size; + spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_ADD_MEM, &am); + } + ab.port_id = port_id; + ab.buffer_id = b->id; + ab.mem_id = bmem->id; + ab.offset = 0; + ab.size = b->size; + spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_ADD_BUFFER, &ab); + + spa_control_builder_end (&builder, &control); + + if ((res = spa_control_write (&control, this->fds[0].fd)) < 0) + fprintf (stderr, "proxy %p: error writing control\n", this); + + spa_control_clear (&control); + + return SPA_RESULT_OK; +} +#endif + static SpaResult remove_buffer (SpaProxy *this, uint32_t port_id, SpaBuffer *buffer) { diff --git a/spa/plugins/v4l2/v4l2-source.c b/spa/plugins/v4l2/v4l2-source.c index 57db19114..fc0cbda5c 100644 --- a/spa/plugins/v4l2/v4l2-source.c +++ b/spa/plugins/v4l2/v4l2-source.c @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -54,8 +55,7 @@ struct _V4l2Buffer { SpaMeta metas[1]; SpaMetaHeader header; SpaData datas[1]; - SpaV4l2Source *source; - SpaBuffer *imported; + SpaBuffer *outbuf; bool outstanding; struct v4l2_buffer v4l2_buffer; V4l2Buffer *next; @@ -102,7 +102,8 @@ typedef struct { enum v4l2_memory memtype; struct v4l2_requestbuffers reqbuf; - V4l2Buffer buffers[MAX_BUFFERS]; + SpaMemory *alloc_mem; + V4l2Buffer *alloc_buffers; V4l2Buffer *ready; uint32_t ready_count; diff --git a/spa/plugins/v4l2/v4l2-utils.c b/spa/plugins/v4l2/v4l2-utils.c index 5aee58174..b7c96a235 100644 --- a/spa/plugins/v4l2/v4l2-utils.c +++ b/spa/plugins/v4l2/v4l2-utils.c @@ -408,7 +408,7 @@ spa_v4l2_set_format (SpaV4l2Source *this, V4l2Format *f, bool try_only) state->info.params = state->params; state->params[0] = &state->param_buffers.param; state->param_buffers.param.type = SPA_ALLOC_PARAM_TYPE_BUFFERS; - state->param_buffers.param.size = sizeof (&state->buffers); + state->param_buffers.param.size = sizeof (state->param_buffers); state->param_buffers.minsize = fmt.fmt.pix.sizeimage; state->param_buffers.stride = fmt.fmt.pix.bytesperline; state->param_buffers.min_buffers = 2; @@ -459,7 +459,9 @@ mmap_read (SpaV4l2Source *this) } } - b = &state->buffers[buf.index]; + b = &state->alloc_buffers[buf.index]; + b->header.seq = buf.sequence; + b->header.pts = (uint64_t)buf.timestamp.tv_sec * 1000000000lu + (uint64_t)buf.timestamp.tv_usec * 1000lu; b->next = state->ready; state->ready = b; state->ready_count++; @@ -489,7 +491,7 @@ static void spa_v4l2_buffer_recycle (SpaV4l2Source *this, uint32_t buffer_id) { SpaV4l2State *state = &this->state[0]; - V4l2Buffer *b = &state->buffers[buffer_id]; + V4l2Buffer *b = &state->alloc_buffers[buffer_id]; b->outstanding = false; @@ -523,24 +525,39 @@ spa_v4l2_import_buffers (SpaV4l2Source *this, SpaBuffer **buffers, uint32_t n_bu } state->reqbuf = reqbuf; + if (state->alloc_mem) + spa_memory_free (state->alloc_mem->pool_id, state->alloc_mem->id); + state->alloc_mem = spa_memory_alloc_with_fd (0, NULL, sizeof (V4l2Buffer) * reqbuf.count); + state->alloc_buffers = spa_memory_ensure_ptr (state->alloc_mem); + for (i = 0; i < reqbuf.count; i++) { V4l2Buffer *b; + uint32_t mem_id; + SpaMemory *mem; + SpaData *d = SPA_BUFFER_DATAS (buffers[i]); - b = &state->buffers[i]; + b = &state->alloc_buffers[i]; + b->buffer.mem_id = state->alloc_mem->id; + b->buffer.offset = sizeof (V4l2Buffer) * i; + b->buffer.size = sizeof (V4l2Buffer); + b->buffer.id = SPA_ID_INVALID; + b->outbuf = buffers[i]; + b->outstanding = true; fprintf (stderr, "import buffer %p\n", buffers[i]); - b->source = this; - b->buffer.id = SPA_ID_INVALID; - b->imported = buffers[i]; - b->outstanding = true; + mem_id = SPA_BUFFER_DATAS (buffers[i])[0].mem_id; + if (!(mem = spa_memory_find (0, mem_id))) { + fprintf (stderr, "invalid memory on buffer %p\n", buffers[i]); + continue; + } CLEAR (b->v4l2_buffer); b->v4l2_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; b->v4l2_buffer.memory = state->memtype; b->v4l2_buffer.index = i; - b->v4l2_buffer.m.userptr = (unsigned long) SPA_BUFFER_DATAS (buffers[i])[0].ptr; - b->v4l2_buffer.length = SPA_BUFFER_DATAS (buffers[i])[0].size; + b->v4l2_buffer.m.userptr = (unsigned long) ((uint8_t*)mem->ptr + d[0].offset); + b->v4l2_buffer.length = d[0].size; spa_v4l2_buffer_recycle (this, buffers[i]->id); } @@ -584,9 +601,15 @@ mmap_init (SpaV4l2Source *this, state->reqbuf = reqbuf; + if (state->alloc_mem) + spa_memory_free (state->alloc_mem->pool_id, state->alloc_mem->id); + state->alloc_mem = spa_memory_alloc_with_fd (0, NULL, sizeof (V4l2Buffer) * reqbuf.count); + state->alloc_buffers = spa_memory_ensure_ptr (state->alloc_mem); + for (i = 0; i < reqbuf.count; i++) { struct v4l2_buffer buf; V4l2Buffer *b; + SpaMemory *mem; CLEAR (buf); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; @@ -598,13 +621,14 @@ mmap_init (SpaV4l2Source *this, return SPA_RESULT_ERROR; } - b = &state->buffers[i]; + b = &state->alloc_buffers[i]; + b->buffer.id = i; + b->buffer.mem_id = state->alloc_mem->id; + b->buffer.offset = sizeof (V4l2Buffer) * i; + b->buffer.size = sizeof (V4l2Buffer); buffers[i] = &b->buffer; - b->source = this; - b->buffer.id = i; - b->buffer.size = sizeof (V4l2Buffer); b->buffer.n_metas = 1; b->buffer.metas = offsetof (V4l2Buffer, metas); b->buffer.n_datas = 1; @@ -619,6 +643,14 @@ mmap_init (SpaV4l2Source *this, b->metas[0].offset = offsetof (V4l2Buffer, header); b->metas[0].size = sizeof (b->header); + mem = spa_memory_alloc (0); + mem->flags = SPA_MEMORY_FLAG_READABLE; + mem->size = buf.length; + b->datas[0].mem_id = mem->id; + b->datas[0].offset = 0; + b->datas[0].size = buf.length; + b->datas[0].stride = state->fmt.fmt.pix.bytesperline; + if (state->export_buf) { struct v4l2_exportbuffer expbuf; @@ -630,39 +662,25 @@ mmap_init (SpaV4l2Source *this, continue; } + mem->fd = expbuf.fd; + mem->type = "dmabuf"; + mem->ptr = NULL; b->dmafd = expbuf.fd; - b->datas[0].type = SPA_DATA_TYPE_FD; - b->datas[0].ptr = SPA_INT_TO_PTR (b->dmafd); - b->datas[0].ptr_type = "dmabuf"; - b->datas[0].offset = 0; - b->datas[0].size = buf.length; - b->datas[0].stride = state->fmt.fmt.pix.bytesperline; } else { -#if 1 - b->datas[0].type = SPA_DATA_TYPE_MEMPTR; - b->datas[0].ptr_type = "sysmem"; - b->datas[0].ptr = mmap (NULL, - buf.length, - PROT_READ | PROT_WRITE, - MAP_SHARED, - state->fd, - buf.m.offset); - b->datas[0].offset = 0; - b->datas[0].size = buf.length; - if (b->datas[0].ptr == MAP_FAILED) { + mem->fd = -1; + mem->type = "sysmem"; + mem->ptr = mmap (NULL, + buf.length, + PROT_READ | PROT_WRITE, + MAP_SHARED, + state->fd, + buf.m.offset); + if (mem->ptr == MAP_FAILED) { perror ("mmap"); continue; } -#else - b->datas[0].type = SPA_DATA_TYPE_FD; - b->datas[0].ptr = &state->fd; - b->datas[0].ptr_type = "dmabuf"; - b->datas[0].offset = buf.m.offset; - b->datas[0].size = buf.length; - b->datas[0].stride = state->fmt.fmt.pix.bytesperline; -#endif } - b->imported = &b->buffer; + b->outbuf = &b->buffer; b->outstanding = true; CLEAR (b->v4l2_buffer); @@ -772,17 +790,20 @@ spa_v4l2_stop (SpaV4l2Source *this) for (i = 0; i < state->reqbuf.count; i++) { V4l2Buffer *b; + SpaMemory *mem; - b = &state->buffers[i]; + b = &state->alloc_buffers[i]; if (b->outstanding) { fprintf (stderr, "queueing outstanding buffer %p\n", b); spa_v4l2_buffer_recycle (this, i); } + mem = spa_memory_find (0, b->datas[0].mem_id); if (state->export_buf) { - close (b->dmafd); + close (mem->fd); } else { - munmap (b->datas[0].ptr, b->datas[0].size); + munmap (mem->ptr, mem->size); } + spa_memory_free (0, mem->id); } state->have_buffers = false; diff --git a/spa/plugins/volume/volume.c b/spa/plugins/volume/volume.c index 46f060e21..6548b6cc9 100644 --- a/spa/plugins/volume/volume.c +++ b/spa/plugins/volume/volume.c @@ -21,6 +21,7 @@ #include #include +#include #include typedef struct _SpaVolume SpaVolume; @@ -550,6 +551,7 @@ spa_volume_node_port_pull_output (SpaNode *node, SpaData *sd, *dd; uint16_t *src, *dst; double volume; + SpaMemory *sm, *dm; if (node == NULL || node->handle == NULL || n_info == 0 || info == NULL) return SPA_RESULT_INVALID_ARGUMENTS; @@ -581,16 +583,11 @@ spa_volume_node_port_pull_output (SpaNode *node, sd = &SPA_BUFFER_DATAS (sbuf)[si]; dd = &SPA_BUFFER_DATAS (dbuf)[di]; - if (sd->type != SPA_DATA_TYPE_MEMPTR) { - si++; - continue; - } - if (dd->type != SPA_DATA_TYPE_MEMPTR) { - di++; - continue; - } - src = (uint16_t*) ((uint8_t*)sd->ptr + soff); - dst = (uint16_t*) ((uint8_t*)dd->ptr + doff); + sm = spa_memory_find (0, sd->mem_id); + dm = spa_memory_find (0, dd->mem_id); + + src = (uint16_t*) ((uint8_t*)sm->ptr + sd->offset + soff); + dst = (uint16_t*) ((uint8_t*)dm->ptr + dd->offset + doff); n_bytes = SPA_MIN (sd->size - soff, dd->size - doff); n_samples = n_bytes / sizeof (uint16_t); diff --git a/spa/tests/test-v4l2.c b/spa/tests/test-v4l2.c index d98d30a0a..0ff3b3676 100644 --- a/spa/tests/test-v4l2.c +++ b/spa/tests/test-v4l2.c @@ -30,6 +30,7 @@ #include #include +#include #include #undef USE_BUFFER @@ -123,6 +124,7 @@ on_source_event (SpaNode *node, SpaEvent *event, void *user_data) uint8_t *src, *dst; SpaMeta *metas; SpaData *datas; + SpaMemory *mem; if ((res = spa_node_port_pull_output (data->source, 1, info)) < 0) printf ("got pull error %d\n", res); @@ -146,8 +148,11 @@ on_source_event (SpaNode *node, SpaEvent *event, void *user_data) fprintf (stderr, "Couldn't lock texture: %s\n", SDL_GetError()); return; } - datas[0].ptr = sdata; - datas[0].ptr_type = "sysmem"; + mem = spa_memory_find (0, datas[0].mem_id); + mem->ptr = sdata; + mem->type = "sysmem"; + mem->size = sstride * 240; + datas[0].size = sstride * 240; datas[0].stride = sstride; } else { @@ -155,7 +160,9 @@ on_source_event (SpaNode *node, SpaEvent *event, void *user_data) fprintf (stderr, "Couldn't lock texture: %s\n", SDL_GetError()); return; } - sdata = datas[0].ptr; + mem = spa_memory_find (0, datas[0].mem_id); + + sdata = spa_memory_ensure_ptr (mem); sstride = datas[0].stride; for (i = 0; i < 240; i++) { @@ -438,6 +445,8 @@ main (int argc, char *argv[]) AppData data; SpaResult res; + spa_memory_init (); + if (SDL_Init (SDL_INIT_VIDEO) < 0) { printf ("can't initialize SDL: %s\n", SDL_GetError ()); return -1;