link: don't allocate shared meta in shared mem

We can't allocate the shared meta in shared mem because then clients can
damage it for other clients. Place it instead right after the buffer
metadata array. Filter out the shared metadata for a client, we send it
as part of the client_buffer structure.
Remove pointer metadata, it's not so useful.
Document the layout of the allocated buffers and the shared memory.
Work on metadata to define control parameters
This commit is contained in:
Wim Taymans 2017-11-17 13:34:42 +01:00
parent e774339ffe
commit 4d0bab799c
5 changed files with 158 additions and 69 deletions

View file

@ -36,28 +36,26 @@ extern "C" {
#define SPA_TYPE_META_BASE SPA_TYPE__Meta ":"
#define SPA_TYPE_META__Header SPA_TYPE_META_BASE "Header"
#define SPA_TYPE_META__Pointer SPA_TYPE_META_BASE "Pointer"
#define SPA_TYPE_META__VideoCrop SPA_TYPE_META_BASE "VideoCrop"
#define SPA_TYPE_META__Shared SPA_TYPE_META_BASE "Shared"
struct spa_type_meta {
uint32_t Header;
uint32_t Pointer;
uint32_t VideoCrop;
uint32_t Shared;
/**
* A metadata element.
*
* This structure is available on the buffer structure and contains
* the type of the metadata and a pointer/size to the actual metadata
* itself.
*/
struct spa_meta {
uint32_t type; /**< metadata type */
void *data; /**< pointer to metadata */
uint32_t size; /**< size of metadata */
};
static inline void spa_type_meta_map(struct spa_type_map *map, struct spa_type_meta *type)
{
if (type->Header == 0) {
type->Header = spa_type_map_get_id(map, SPA_TYPE_META__Header);
type->Pointer = spa_type_map_get_id(map, SPA_TYPE_META__Pointer);
type->VideoCrop = spa_type_map_get_id(map, SPA_TYPE_META__VideoCrop);
type->Shared = spa_type_map_get_id(map, SPA_TYPE_META__Shared);
}
}
/** Describes essential buffer header metadata */
/**
* Describes essential buffer header metadata such as flags and
* timestamps.
*/
struct spa_meta_header {
#define SPA_META_HEADER_FLAG_DISCONT (1 << 0) /**< data is not continous with previous buffer */
#define SPA_META_HEADER_FLAG_CORRUPTED (1 << 1) /**< data might be corrupted */
@ -72,33 +70,47 @@ struct spa_meta_header {
int64_t dts_offset; /**< decoding timestamp and a difference with pts */
};
/** Pointer metadata */
struct spa_meta_pointer {
uint32_t type; /**< the pointer type */
void *ptr; /**< the pointer */
};
/** Video cropping metadata */
/**
* Video cropping metadata
* a */
struct spa_meta_video_crop {
int32_t x, y; /**< x and y offsets */
int32_t width, height; /**< width and height */
};
/** Describes the shared memory of a buffer is stored */
/**
* Describes the shared memory that holds buffer meta/chunk/data
*/
struct spa_meta_shared {
int32_t flags; /**< flags */
uint32_t flags; /**< flags */
int fd; /**< file descriptor of memory */
int32_t offset; /**< offset in memory */
uint32_t offset; /**< offset in memory */
uint32_t size; /**< size of memory */
};
/** A metadata element */
struct spa_meta {
uint32_t type; /**< metadata type */
void *data; /**< pointer to metadata */
uint32_t size; /**< size of metadata */
/**
* Describes a control location in the buffer.
*/
struct spa_meta_control {
uint32_t id; /**< control id */
uint32_t offset; /**< offset in buffer memory */
};
struct spa_type_meta {
uint32_t Header;
uint32_t VideoCrop;
uint32_t Shared;
};
static inline void spa_type_meta_map(struct spa_type_map *map, struct spa_type_meta *type)
{
if (type->Header == 0) {
type->Header = spa_type_map_get_id(map, SPA_TYPE_META__Header);
type->VideoCrop = spa_type_map_get_id(map, SPA_TYPE_META__VideoCrop);
type->Shared = spa_type_map_get_id(map, SPA_TYPE_META__Shared);
}
}
#ifdef __cplusplus
} /* extern "C" */
#endif

View file

@ -405,8 +405,8 @@ struct spa_node {
* Tell the port to allocate memory for \a buffers.
*
* \a buffers should contain an array of pointers to buffers. The data
* in the buffers should point to an array of at least 1 SPA_DATA_TYPE_INVALID
* data pointers that will be filled by this function.
* in the buffers should point to an array of at least 1 data entry
* with a 0 type that will be filled by this function.
*
* For input ports, the buffers will be dequeued and ready to be filled
* and pushed into the port. A notify should be configured so that you can

View file

@ -72,12 +72,6 @@ int spa_debug_buffer(const struct spa_buffer *buffer)
fprintf(stderr, " seq: %u\n", h->seq);
fprintf(stderr, " pts: %" PRIi64 "\n", h->pts);
fprintf(stderr, " dts_offset: %" PRIi64 "\n", h->dts_offset);
} else if (!strcmp(type_name, SPA_TYPE_META__Pointer)) {
struct spa_meta_pointer *h = m->data;
fprintf(stderr, " struct spa_meta_pointer:\n");
fprintf(stderr, " type: %s\n",
spa_type_map_get_type(map, h->type));
fprintf(stderr, " ptr: %p\n", h->ptr);
} else if (!strcmp(type_name, SPA_TYPE_META__VideoCrop)) {
struct spa_meta_video_crop *h = m->data;
fprintf(stderr, " struct spa_meta_video_crop:\n");

View file

@ -540,7 +540,7 @@ spa_proxy_node_port_use_buffers(struct spa_node *node,
struct proxy *this;
struct impl *impl;
struct proxy_port *port;
uint32_t i, j;
uint32_t i, j, k;
size_t n_mem;
struct pw_client_node_buffer *mb;
struct spa_meta_shared *msh;
@ -600,9 +600,11 @@ spa_proxy_node_port_use_buffers(struct spa_node *node,
t->data.MemFd,
msh->fd, msh->flags, msh->offset, msh->size);
for (j = 0; j < buffers[i]->n_metas; j++) {
memcpy(&b->buffer.metas[j], &buffers[i]->metas[j], sizeof(struct spa_meta));
for (j = 0, k = 0; j < buffers[i]->n_metas; j++) {
if (buffers[i]->metas[j].type != t->meta.Shared)
memcpy(&b->buffer.metas[k++], &buffers[i]->metas[j], sizeof(struct spa_meta));
}
b->buffer.n_metas = k;
for (j = 0; j < buffers[i]->n_datas; j++) {
struct spa_data *d = &buffers[i]->datas[j];

View file

@ -246,6 +246,78 @@ static struct spa_pod *find_param(struct spa_pod **params, int n_params, uint32_
return NULL;
}
/* Allocate an array of buffers that can be shared.
*
* All information will be allocated in \a mem. A pointer to a
* newly allocated memory with an array of buffer pointers is
* returned.
*
* \return an array of freshly allocated buffer pointers. free()
* after usage.
*
* Array of allocated buffers:
*
* +==============================+
* +-| struct spa_buffer * | array of n_buffers of pointers
* | | ... <n_buffers> |
* | +==============================+
* +>| struct spa_buffer |
* | uint32_t id | id of buffer
* | uint32_t n_metas | number of metas
* +-| struct spa_meta *metas | pointer to array of metas
* | | uint32_t n_datas | number of datas
* +|-| struct spa_data *datas | pointer to array of datas
* || +------------------------------+
* |+>| struct spa_meta |
* | | uint32_t type | Shared meta type, first one always shared
* |+-| void *data | pointer to inlined shared metadata
* || | uint32_t size | sizeof(struct spa_meta_shared)
* || | struct spa_meta |
* || | uint32_t type | more metadata
* +||-| void *data | pointer to mmaped metadata in shared memory
* ||| | uint32_t size | size of metadata
* ||| | ... <n_metas> | more metas follow
* ||| +------------------------------+
* ||+>| struct spa_meta_shared | inlined shared metadata
* || | uint32_t flags |
* || | int fd | fd of the shared memory block
* || | uint32_t offset | offset of meta/chunk/data for this buffer
* || | uint32_t size | size of meta/chunk/data for this buffer
* || +------------------------------+
* |+->| struct spa_data |
* | | uint32_t type | memory type, either MemFd or INVALID
* | | uint32_t flags |
* | | int fd | fd of shared memory block
* | | uint32_t mapoffset | offset in shared memory of data
* | | uint32_t maxsize | size of data block
* | +-| void *data | pointer to mmaped data in shared memory
* |+|-| struct spa_chunk *chunk | pointer to mmaped chunk in shared memory
* ||| | ... <n_datas> | more datas follow
* ||| +==============================+
* ||| | ... <n_buffers> | more buffer/meta/data definitions follow
* ||| +==============================+
* |||
* |||
* ||| shared memory block:
* |||
* ||| +==============================+
* +-->| meta data memory | metadata memory
* || | ... <n_metas> |
* || +------------------------------+
* +->| struct spa_chunk | memory for n_datas chunks
* | | struct spa_ringbuffer area |
* | | int32_t stride |
* | | ... <n_datas> chunks |
* | +------------------------------+
* +>| data | memory for n_datas data
* | ... <n_datas> blocks |
* +==============================+
* | ... <n_buffers> | repeated for each buffer
* +==============================+
*
* The shared memory block should not contain any types or structure,
* just the actual metadata contents.
*/
static struct spa_buffer **alloc_buffers(struct pw_link *this,
uint32_t n_buffers,
uint32_t n_params,
@ -265,17 +337,19 @@ static struct spa_buffer **alloc_buffers(struct pw_link *this,
n_metas = data_size = meta_size = 0;
/* each buffer */
/* each buffer has 1 meta shared */
skel_size = sizeof(struct spa_buffer);
skel_size += sizeof(struct spa_meta);
skel_size += sizeof(struct spa_meta_shared);
metas = alloca(sizeof(struct spa_meta) * (n_params + 1));
/* add shared metadata */
/* add shared metadata this should not go into shared
* memory or else a client can damage it so we inline it after
* the array of spa_meta. */
metas[n_metas].type = this->core->type.meta.Shared;
metas[n_metas].size = sizeof(struct spa_meta_shared);
meta_size += metas[n_metas].size;
n_metas++;
skel_size += sizeof(struct spa_meta);
/* collect metadata */
for (i = 0; i < n_params; i++) {
@ -316,32 +390,36 @@ static struct spa_buffer **alloc_buffers(struct pw_link *this,
for (i = 0; i < n_buffers; i++) {
int j;
struct spa_buffer *b;
struct spa_meta_shared *msh;
void *p;
buffers[i] = b = SPA_MEMBER(bp, skel_size * i, struct spa_buffer);
p = SPA_MEMBER(mem->ptr, data_size * i, void);
b->id = i;
b->n_metas = n_metas;
b->metas = SPA_MEMBER(b, sizeof(struct spa_buffer), struct spa_meta);
for (j = 0; j < n_metas; j++) {
struct spa_meta *m = &b->metas[j];
m->type = metas[j].type;
m->data = p;
m->size = metas[j].size;
if (m->type == this->core->type.meta.Shared) {
struct spa_meta_shared *msh = p;
msh = SPA_MEMBER(b, sizeof(struct spa_buffer), struct spa_meta_shared);
msh->flags = 0;
msh->fd = mem->fd;
msh->offset = data_size * i;
msh->size = data_size;
b->id = i;
b->n_metas = n_metas;
b->metas = SPA_MEMBER(msh, sizeof(struct spa_meta_shared), struct spa_meta);
for (j = 0; j < n_metas; j++) {
struct spa_meta *m = &b->metas[j];
m->type = metas[j].type;
m->size = metas[j].size;
if (m->type == this->core->type.meta.Shared) {
m->data = msh;
}
else {
m->data = p;
p += m->size;
}
}
/* pointer to data structure */
b->n_datas = n_datas;
b->datas = SPA_MEMBER(b->metas, n_metas * sizeof(struct spa_meta), struct spa_data);
@ -364,6 +442,7 @@ static struct spa_buffer **alloc_buffers(struct pw_link *this,
d->chunk->stride = data_strides[j];
ddp += data_sizes[j];
} else {
/* needs to be allocated by a node */
d->type = SPA_ID_INVALID;
d->data = NULL;
}
@ -535,6 +614,8 @@ static int do_allocation(struct pw_link *this, uint32_t in_state, uint32_t out_s
minsize = 1024;
}
/* when one of the ports can allocate buffer memory, set the minsize to
* 0 to make sure we don't allocate memory in the shared memory */
if ((in_flags & SPA_PORT_INFO_FLAG_CAN_ALLOC_BUFFERS) ||
(out_flags & SPA_PORT_INFO_FLAG_CAN_ALLOC_BUFFERS))
minsize = 0;