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.
This commit is contained in:
Wim Taymans 2016-08-03 21:33:57 +02:00
parent 98993c680b
commit 1169c2419b
19 changed files with 383 additions and 356 deletions

View file

@ -20,6 +20,7 @@
#include <gst/gst.h>
#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 ();
}
/**

View file

@ -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);
priv->buffer = bid->buf;
spa_debug_buffer (bid->buf);
}
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;
}
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) {

View file

@ -24,6 +24,7 @@
#include <server/daemon.h>
#include <modules/gst/gst-manager.h>
#include <modules/gst/gst-node-factory.h>
#include <spa/include/spa/memory.h>
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);

View file

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

View file

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

View file

@ -44,6 +44,7 @@
#include <gst/allocators/gstfdmemory.h>
#include <gst/video/video.h>
#include <spa/include/spa/memory.h>
#include <spa/include/spa/buffer.h>
@ -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:
{
mem = spa_memory_find (0, d->mem_id);
if (mem->fd) {
GstMemory *fdmem = NULL;
int fd = SPA_PTR_TO_INT (d->ptr);
fdmem = gst_fd_allocator_alloc (pinossrc->fd_allocator, dup (fd),
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);
break;
}
default:
break;
} else {
gst_buffer_append_memory (buf,
gst_memory_new_wrapped (0, mem->ptr, mem->size, d->offset,
d->size, NULL, NULL));
}
}

View file

@ -27,6 +27,7 @@
#include <gio/gio.h>
#include <spa/include/spa/node.h>
#include <spa/include/spa/memory.h>
#include <spa/include/spa/audio/format.h>
#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);

View file

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

View file

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

View file

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

View file

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

View file

@ -20,6 +20,7 @@
#include <stdio.h>
#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;
}

View file

@ -17,7 +17,16 @@
* Boston, MA 02110-1301, USA.
*/
#define _GNU_SOURCE
#include <string.h>
#include <stddef.h>
#include <stdio.h>
#include <sys/socket.h>
#include <errno.h>
#include <sys/mman.h>
#include <unistd.h>
#include <fcntl.h>
#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;
}

View file

@ -21,6 +21,7 @@
#include <stdio.h>
#include <spa/node.h>
#include <spa/memory.h>
#include <spa/audio/format.h>
#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;

View file

@ -17,8 +17,6 @@
* Boston, MA 02110-1301, USA.
*/
#define _GNU_SOURCE
#include <string.h>
#include <stddef.h>
#include <stdio.h>
@ -31,6 +29,7 @@
#include <spa/node.h>
#include <spa/memory.h>
#include <spa/control.h>
#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)
{

View file

@ -25,6 +25,7 @@
#include <linux/videodev2.h>
#include <spa/node.h>
#include <spa/memory.h>
#include <spa/video/format.h>
#include <spa/debug.h>
@ -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;

View file

@ -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,
mem->fd = -1;
mem->type = "sysmem";
mem->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) {
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;

View file

@ -21,6 +21,7 @@
#include <stddef.h>
#include <spa/node.h>
#include <spa/memory.h>
#include <spa/audio/format.h>
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);

View file

@ -30,6 +30,7 @@
#include <spa/node.h>
#include <spa/debug.h>
#include <spa/memory.h>
#include <spa/video/format.h>
#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;