Enable header metadata

Enable the header metadata so that we have timestamps again.
Rework allocation in the link a little. Reuse previously allocated
buffers when possible. Keep track of where the buffers was allocated.
Make some more convenience functions to initialize buffer headers. Make
it so that we move allocations to the app.
Make some helpers to make memfd memory in pinos now that we will be able
to do all allocation there.
This commit is contained in:
Wim Taymans 2016-09-30 17:07:38 +02:00
parent 24108e01c1
commit 9d4048e73a
15 changed files with 504 additions and 157 deletions

View file

@ -1048,7 +1048,7 @@ parse_control (PinosStream *stream,
mid.ptr = NULL; mid.ptr = NULL;
mid.size = p.size; mid.size = p.size;
g_debug ("add mem %u, fd %d, flags %d", p.mem_id, fd, p.flags); g_debug ("add mem %u, fd %d, flags %d, size %zd", p.mem_id, fd, p.flags, p.size);
g_array_append_val (priv->mem_ids, mid); g_array_append_val (priv->mem_ids, mid);
break; break;
} }
@ -1098,9 +1098,7 @@ parse_control (PinosStream *stream,
bid.buf = spa_buffer_deserialize (mid->ptr, p.buffers[i].offset); bid.buf = spa_buffer_deserialize (mid->ptr, p.buffers[i].offset);
bid.id = bid.buf->id; bid.id = bid.buf->id;
spa_debug_dump_mem (mid->ptr, 256); g_debug ("add buffer %d %d %zd", mid->id, bid.id, p.buffers[i].offset);
g_debug ("add buffer %d %zd", bid.id, p.buffers[i].offset);
for (j = 0; j < bid.buf->n_datas; j++) { for (j = 0; j < bid.buf->n_datas; j++) {
SpaData *d = &bid.buf->datas[j]; SpaData *d = &bid.buf->datas[j];

View file

@ -721,7 +721,15 @@ on_format_notify (GObject *gobject,
gst_caps_unref (caps); gst_caps_unref (caps);
if (res) { if (res) {
pinos_stream_finish_format (pinossrc->stream, SPA_RESULT_OK, NULL, 0); SpaAllocParam *params[1];
SpaAllocParamMetaEnable param_meta;
params[0] = &param_meta.param;
param_meta.param.type = SPA_ALLOC_PARAM_TYPE_META_ENABLE;
param_meta.param.size = sizeof (param_meta);
param_meta.type = SPA_META_TYPE_HEADER;
pinos_stream_finish_format (pinossrc->stream, SPA_RESULT_OK, params, 1);
} else { } else {
pinos_stream_finish_format (pinossrc->stream, SPA_RESULT_INVALID_MEDIA_TYPE, NULL, 0); pinos_stream_finish_format (pinossrc->stream, SPA_RESULT_INVALID_MEDIA_TYPE, NULL, 0);
} }

View file

@ -28,6 +28,7 @@
#include "pinos/client/enumtypes.h" #include "pinos/client/enumtypes.h"
#include "pinos/server/link.h" #include "pinos/server/link.h"
#include "pinos/server/utils.h"
#include "pinos/dbus/org-pinos.h" #include "pinos/dbus/org-pinos.h"
@ -51,7 +52,8 @@ struct _PinosLinkPrivate
uint32_t async_busy; uint32_t async_busy;
gboolean allocated; gboolean allocated;
SpaBuffer *buffers[MAX_BUFFERS]; PinosMemblock buffer_mem;
SpaBuffer **buffers;
unsigned int n_buffers; unsigned int n_buffers;
}; };
@ -417,10 +419,10 @@ do_allocation (PinosLink *this, SpaNodeState in_state, SpaNodeState out_state)
spa_debug_port_info (oinfo); spa_debug_port_info (oinfo);
spa_debug_port_info (iinfo); spa_debug_port_info (iinfo);
if (!priv->allocated) { if (priv->buffers == NULL) {
SpaAllocParamBuffers *in_alloc, *out_alloc; SpaAllocParamBuffers *in_alloc, *out_alloc;
guint max_buffers = MAX_BUFFERS; guint max_buffers = MAX_BUFFERS;
SpaBufferAllocFlags flags = 0; gboolean alloc_data = TRUE;
max_buffers = MAX_BUFFERS; max_buffers = MAX_BUFFERS;
in_alloc = find_param (iinfo, SPA_ALLOC_PARAM_TYPE_BUFFERS); in_alloc = find_param (iinfo, SPA_ALLOC_PARAM_TYPE_BUFFERS);
@ -432,21 +434,49 @@ do_allocation (PinosLink *this, SpaNodeState in_state, SpaNodeState out_state)
if ((in_flags & SPA_PORT_INFO_FLAG_CAN_ALLOC_BUFFERS) || if ((in_flags & SPA_PORT_INFO_FLAG_CAN_ALLOC_BUFFERS) ||
(out_flags & SPA_PORT_INFO_FLAG_CAN_ALLOC_BUFFERS)) (out_flags & SPA_PORT_INFO_FLAG_CAN_ALLOC_BUFFERS))
flags |= SPA_BUFFER_ALLOC_FLAG_NO_MEM; alloc_data = FALSE;
priv->n_buffers = max_buffers; if (this->output->allocated) {
if ((res = spa_buffer_alloc (flags, out_flags = 0;
oinfo->params, oinfo->n_params, in_flags = SPA_PORT_INFO_FLAG_CAN_USE_BUFFERS;
priv->buffers, priv->n_buffers = this->output->n_buffers;
&priv->n_buffers)) < 0) { priv->buffers = this->output->buffers;
g_set_error (&error, priv->allocated = FALSE;
PINOS_ERROR, g_debug ("reusing %d output buffers %p", priv->n_buffers, priv->buffers);
PINOS_ERROR_BUFFER_ALLOCATION, } else {
"error buffer alloc: %d", res); guint i;
goto error; size_t hdr_size;
void *p;
spa_alloc_params_get_header_size (oinfo->params, oinfo->n_params, 1, &hdr_size);
priv->n_buffers = max_buffers;
pinos_memblock_alloc (PINOS_MEMBLOCK_FLAG_WITH_FD |
PINOS_MEMBLOCK_FLAG_MAP_READWRITE |
PINOS_MEMBLOCK_FLAG_SEAL,
priv->n_buffers * (sizeof (SpaBuffer*) + hdr_size),
&priv->buffer_mem);
priv->buffers = p = priv->buffer_mem.ptr;
p = SPA_MEMBER (p, priv->n_buffers * sizeof (SpaBuffer*), void);
for (i = 0; i < priv->n_buffers; i++)
priv->buffers[i] = SPA_MEMBER (p, hdr_size * i, SpaBuffer);
if ((res = spa_buffer_init_headers (oinfo->params,
oinfo->n_params,
1,
priv->buffers,
priv->n_buffers)) < 0) {
g_set_error (&error,
PINOS_ERROR,
PINOS_ERROR_BUFFER_ALLOCATION,
"error buffer alloc: %d", res);
goto error;
}
g_debug ("allocated %d buffers %p", priv->n_buffers, priv->buffers);
priv->allocated = TRUE;
} }
g_debug ("allocated %d buffers %p", priv->n_buffers, priv->buffers);
priv->allocated = TRUE;
if (in_flags & SPA_PORT_INFO_FLAG_CAN_ALLOC_BUFFERS) { if (in_flags & SPA_PORT_INFO_FLAG_CAN_ALLOC_BUFFERS) {
if ((res = spa_node_port_alloc_buffers (this->input->node->node, this->input->port, if ((res = spa_node_port_alloc_buffers (this->input->node->node, this->input->port,
@ -458,7 +488,10 @@ do_allocation (PinosLink *this, SpaNodeState in_state, SpaNodeState out_state)
"error alloc input buffers: %d", res); "error alloc input buffers: %d", res);
goto error; goto error;
} }
this->input->buffers = priv->buffers;
this->input->n_buffers = priv->n_buffers;
this->input->allocated = TRUE; this->input->allocated = TRUE;
priv->allocated = FALSE;
g_debug ("allocated %d buffers %p from input port", priv->n_buffers, priv->buffers); g_debug ("allocated %d buffers %p from input port", priv->n_buffers, priv->buffers);
} }
else if (out_flags & SPA_PORT_INFO_FLAG_CAN_ALLOC_BUFFERS) { else if (out_flags & SPA_PORT_INFO_FLAG_CAN_ALLOC_BUFFERS) {
@ -471,10 +504,14 @@ do_allocation (PinosLink *this, SpaNodeState in_state, SpaNodeState out_state)
"error alloc output buffers: %d", res); "error alloc output buffers: %d", res);
goto error; goto error;
} }
this->output->buffers = priv->buffers;
this->output->n_buffers = priv->n_buffers;
this->output->allocated = TRUE; this->output->allocated = TRUE;
priv->allocated = FALSE;
g_debug ("allocated %d buffers %p from output port", priv->n_buffers, priv->buffers); g_debug ("allocated %d buffers %p from output port", priv->n_buffers, priv->buffers);
} }
} }
if (in_flags & SPA_PORT_INFO_FLAG_CAN_USE_BUFFERS) { if (in_flags & SPA_PORT_INFO_FLAG_CAN_USE_BUFFERS) {
g_debug ("using %d buffers %p on input port", priv->n_buffers, priv->buffers); g_debug ("using %d buffers %p on input port", priv->n_buffers, priv->buffers);
if ((res = spa_node_port_use_buffers (this->input->node->node, this->input->port, if ((res = spa_node_port_use_buffers (this->input->node->node, this->input->port,
@ -485,6 +522,8 @@ do_allocation (PinosLink *this, SpaNodeState in_state, SpaNodeState out_state)
"error use input buffers: %d", res); "error use input buffers: %d", res);
goto error; goto error;
} }
this->input->buffers = priv->buffers;
this->input->n_buffers = priv->n_buffers;
this->input->allocated = FALSE; this->input->allocated = FALSE;
} }
else if (out_flags & SPA_PORT_INFO_FLAG_CAN_USE_BUFFERS) { else if (out_flags & SPA_PORT_INFO_FLAG_CAN_USE_BUFFERS) {
@ -497,21 +536,27 @@ do_allocation (PinosLink *this, SpaNodeState in_state, SpaNodeState out_state)
"error use output buffers: %d", res); "error use output buffers: %d", res);
goto error; goto error;
} }
this->output->buffers = priv->buffers;
this->output->n_buffers = priv->n_buffers;
this->output->allocated = FALSE; this->output->allocated = FALSE;
} else { } else {
g_set_error (&error, g_set_error (&error,
PINOS_ERROR, PINOS_ERROR,
PINOS_ERROR_BUFFER_ALLOCATION, PINOS_ERROR_BUFFER_ALLOCATION,
"no common buffer alloc found"); "no common buffer alloc found");
goto error; goto error;
this->input->allocated = FALSE;
this->output->allocated = FALSE;
} }
return res; return res;
error: error:
{ {
this->output->buffers = NULL;
this->output->n_buffers = 0;
this->output->allocated = FALSE;
this->input->buffers = NULL;
this->input->n_buffers = 0;
this->input->allocated = FALSE;
pinos_link_report_error (this, error); pinos_link_report_error (this, error);
return res; return res;
} }
@ -624,11 +669,22 @@ on_property_notify (GObject *obj,
static void static void
on_node_remove (PinosNode *node, PinosLink *this) on_node_remove (PinosNode *node, PinosLink *this)
{ {
PinosLinkPrivate *priv = this->priv;
g_signal_handlers_disconnect_by_data (node, this); g_signal_handlers_disconnect_by_data (node, this);
if (node == this->input->node) if (node == this->input->node) {
if (this->input->allocated) {
priv->buffers = NULL;
priv->n_buffers = 0;
}
this->input = NULL; this->input = NULL;
else } else {
if (this->output->allocated) {
priv->buffers = NULL;
priv->n_buffers = 0;
}
this->output = NULL; this->output = NULL;
}
pinos_link_update_state (this, PINOS_LINK_STATE_UNLINKED); pinos_link_update_state (this, PINOS_LINK_STATE_UNLINKED);
} }
@ -688,6 +744,9 @@ pinos_link_finalize (GObject * object)
g_clear_object (&priv->iface); g_clear_object (&priv->iface);
g_free (priv->object_path); g_free (priv->object_path);
if (priv->allocated)
pinos_memblock_free (&priv->buffer_mem);
G_OBJECT_CLASS (pinos_link_parent_class)->finalize (object); G_OBJECT_CLASS (pinos_link_parent_class)->finalize (object);
} }

View file

@ -44,6 +44,8 @@ typedef struct {
PinosNode *node; PinosNode *node;
uint32_t port; uint32_t port;
gboolean allocated; gboolean allocated;
SpaBuffer **buffers;
guint n_buffers;
} PinosPort; } PinosPort;
/** /**

View file

@ -0,0 +1,59 @@
/* Simple Plugin API
* Copyright (C) 2016 Wim Taymans <wim.taymans@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include <sys/syscall.h>
#include <fcntl.h>
/*
* No glibc wrappers exist for memfd_create(2), so provide our own.
*
* Also define memfd fcntl sealing macros. While they are already
* defined in the kernel header file <linux/fcntl.h>, that file as
* a whole conflicts with the original glibc header <fnctl.h>.
*/
static inline int memfd_create(const char *name, unsigned int flags) {
return syscall(SYS_memfd_create, name, flags);
}
/* memfd_create(2) flags */
#ifndef MFD_CLOEXEC
#define MFD_CLOEXEC 0x0001U
#endif
#ifndef MFD_ALLOW_SEALING
#define MFD_ALLOW_SEALING 0x0002U
#endif
/* fcntl() seals-related flags */
#ifndef F_LINUX_SPECIFIC_BASE
#define F_LINUX_SPECIFIC_BASE 1024
#endif
#ifndef F_ADD_SEALS
#define F_ADD_SEALS (F_LINUX_SPECIFIC_BASE + 9)
#define F_GET_SEALS (F_LINUX_SPECIFIC_BASE + 10)
#define F_SEAL_SEAL 0x0001 /* prevent further seals from being set */
#define F_SEAL_SHRINK 0x0002 /* prevent file from shrinking */
#define F_SEAL_GROW 0x0004 /* prevent file from growing */
#define F_SEAL_WRITE 0x0008 /* prevent writes */
#endif

View file

@ -8,6 +8,7 @@ pinoscore_headers = [
'node.h', 'node.h',
'node-factory.h', 'node-factory.h',
'rt-loop.h', 'rt-loop.h',
'utils.h',
] ]
pinoscore_sources = [ pinoscore_sources = [
@ -20,6 +21,7 @@ pinoscore_sources = [
'node.c', 'node.c',
'node-factory.c', 'node-factory.c',
'rt-loop.c', 'rt-loop.c',
'utils.c',
] ]
libpinoscore_c_args = [ libpinoscore_c_args = [

View file

@ -283,12 +283,16 @@ suspend_node (PinosNode *this)
NodePort *p = walk->data; NodePort *p = walk->data;
if ((res = spa_node_port_set_format (this->node, p->port.port, 0, NULL)) < 0) if ((res = spa_node_port_set_format (this->node, p->port.port, 0, NULL)) < 0)
g_warning ("error unset format output: %d", res); g_warning ("error unset format output: %d", res);
p->port.buffers = NULL;
p->port.n_buffers = 0;
p->port.allocated = FALSE; p->port.allocated = FALSE;
} }
for (walk = priv->output_ports; walk; walk = g_list_next (walk)) { for (walk = priv->output_ports; walk; walk = g_list_next (walk)) {
NodePort *p = walk->data; NodePort *p = walk->data;
if ((res = spa_node_port_set_format (this->node, p->port.port, 0, NULL)) < 0) if ((res = spa_node_port_set_format (this->node, p->port.port, 0, NULL)) < 0)
g_warning ("error unset format output: %d", res); g_warning ("error unset format output: %d", res);
p->port.buffers = NULL;
p->port.n_buffers = 0;
p->port.allocated = FALSE; p->port.allocated = FALSE;
} }
return res; return res;

91
pinos/server/utils.c Normal file
View file

@ -0,0 +1,91 @@
/* Pinos
* Copyright (C) 2016 Wim Taymans <wim.taymans@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include <string.h>
#include <stddef.h>
#include <stdio.h>
#include <errno.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include "memfd-wrappers.h"
#include <pinos/server/utils.h>
gboolean
pinos_memblock_alloc (PinosMemblockFlags flags,
gsize size,
PinosMemblock *mem)
{
g_return_val_if_fail (mem != NULL, FALSE);
g_return_val_if_fail (size > 0, FALSE);
mem->flags = flags;
mem->size = size;
if (flags & PINOS_MEMBLOCK_FLAG_WITH_FD) {
mem->fd = memfd_create ("pinos-memfd", MFD_CLOEXEC | MFD_ALLOW_SEALING);
if (ftruncate (mem->fd, size) < 0) {
g_warning ("Failed to truncate temporary file: %s", strerror (errno));
close (mem->fd);
return FALSE;
}
if (flags & PINOS_MEMBLOCK_FLAG_SEAL) {
unsigned int seals = F_SEAL_GROW | F_SEAL_SHRINK | F_SEAL_SEAL;
if (fcntl (mem->fd, F_ADD_SEALS, seals) == -1) {
g_warning ("Failed to add seals: %s", strerror (errno));
}
}
if (flags & PINOS_MEMBLOCK_FLAG_MAP_READWRITE) {
int prot = 0;
if (flags & PINOS_MEMBLOCK_FLAG_MAP_READ)
prot |= PROT_READ;
if (flags & PINOS_MEMBLOCK_FLAG_MAP_WRITE)
prot |= PROT_WRITE;
mem->ptr = mmap (NULL, size, prot, MAP_SHARED, mem->fd, 0);
} else {
mem->ptr = NULL;
}
} else {
mem->ptr = g_malloc (size);
mem->fd = -1;
}
return TRUE;
}
void
pinos_memblock_free (PinosMemblock *mem)
{
g_return_if_fail (mem != NULL);
if (mem->flags & PINOS_MEMBLOCK_FLAG_WITH_FD) {
if (mem->ptr)
munmap (mem->ptr, mem->size);
if (mem->fd != -1)
close (mem->fd);
} else {
g_free (mem->ptr);
}
mem->ptr = NULL;
mem->fd = -1;
}

55
pinos/server/utils.h Normal file
View file

@ -0,0 +1,55 @@
/* Pinos
* Copyright (C) 2016 Wim Taymans <wim.taymans@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __PINOS_UTILS_H__
#define __PINOS_UTILS_H__
#include <glib-object.h>
G_BEGIN_DECLS
typedef struct _PinosMemblock PinosMemblock;
#include <pinos/server/daemon.h>
typedef enum {
PINOS_MEMBLOCK_FLAG_NONE = 0,
PINOS_MEMBLOCK_FLAG_WITH_FD = (1 << 0),
PINOS_MEMBLOCK_FLAG_MAP_READ = (1 << 1),
PINOS_MEMBLOCK_FLAG_MAP_WRITE = (1 << 2),
PINOS_MEMBLOCK_FLAG_SEAL = (1 << 3),
} PinosMemblockFlags;
#define PINOS_MEMBLOCK_FLAG_MAP_READWRITE (PINOS_MEMBLOCK_FLAG_MAP_READ | PINOS_MEMBLOCK_FLAG_MAP_WRITE)
struct _PinosMemblock {
PinosMemblockFlags flags;
int fd;
gpointer *ptr;
gsize size;
};
gboolean pinos_memblock_alloc (PinosMemblockFlags flags,
gsize size,
PinosMemblock *mem);
void pinos_memblock_free (PinosMemblock *mem);
G_END_DECLS
#endif /* __PINOS_UTILS_H__ */

View file

@ -164,21 +164,18 @@ size_t spa_buffer_get_size (const SpaBuffer *buffer);
size_t spa_buffer_serialize (void *dest, const SpaBuffer *buffer); size_t spa_buffer_serialize (void *dest, const SpaBuffer *buffer);
SpaBuffer * spa_buffer_deserialize (void *src, off_t offset); SpaBuffer * spa_buffer_deserialize (void *src, off_t offset);
/**
* SpaBufferAllocFlags:
* @SPA_BUFFER_ALLOC_FLAG_NONE: no flags
* @SPA_BUFFER_ALLOC_FLAG_NO_MEM: don't allocate memory
*/
typedef enum {
SPA_BUFFER_ALLOC_FLAG_NONE = 0,
SPA_BUFFER_ALLOC_FLAG_NO_MEM,
} SpaBufferAllocFlags;
SpaResult spa_buffer_alloc (SpaBufferAllocFlags flags,
SpaAllocParam **params, SpaResult spa_alloc_params_get_header_size (SpaAllocParam **params,
unsigned int n_params, unsigned int n_params,
SpaBuffer **buffers, unsigned int n_datas,
unsigned int *n_buffers); size_t *size);
SpaResult spa_buffer_init_headers (SpaAllocParam **params,
unsigned int n_params,
unsigned int n_datas,
SpaBuffer **buffers,
unsigned int n_buffers);
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ } /* extern "C" */

View file

@ -346,7 +346,9 @@ struct _SpaNode {
* the READY state or to CONFIGURE when @format is NULL. * the READY state or to CONFIGURE when @format is NULL.
* *
* Returns: #SPA_RESULT_OK on success * Returns: #SPA_RESULT_OK on success
* #SPA_RESULT_OK_RECHECK on success * #SPA_RESULT_OK_RECHECK on success, the value of @format might have been
* changed depending on @flags and the final value can be found by
* doing SpaNode::get_format.
* #SPA_RESULT_INVALID_ARGUMENTS when node is %NULL * #SPA_RESULT_INVALID_ARGUMENTS when node is %NULL
* #SPA_RESULT_INVALID_PORT when port_id is not valid * #SPA_RESULT_INVALID_PORT when port_id is not valid
* #SPA_RESULT_INVALID_MEDIA_TYPE when the media type is not valid * #SPA_RESULT_INVALID_MEDIA_TYPE when the media type is not valid
@ -411,8 +413,8 @@ struct _SpaNode {
* on the buffers. * on the buffers.
* *
* Upon completion, this function might change the state of the * Upon completion, this function might change the state of the
* node to PAUSED, when the node has enough buffers, or READY when * node to PAUSED, when the node has enough buffers on all ports, or READY
* @buffers are %NULL. * when @buffers are %NULL.
* *
* Returns: #SPA_RESULT_OK on success * Returns: #SPA_RESULT_OK on success
* #SPA_RESULT_ASYNC the function is executed asynchronously * #SPA_RESULT_ASYNC the function is executed asynchronously
@ -432,6 +434,10 @@ struct _SpaNode {
* *
* Tell the port to allocate memory for @buffers. * Tell the port to allocate memory for @buffers.
* *
* @params 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.
*
* For input ports, the buffers will be dequeued and ready to be filled * 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 * and pushed into the port. A notify should be configured so that you can
* know when a buffer can be reused. * know when a buffer can be reused.
@ -439,7 +445,15 @@ struct _SpaNode {
* For output ports, the buffers remain queued. port_reuse_buffer() should * For output ports, the buffers remain queued. port_reuse_buffer() should
* be called when a buffer can be reused. * be called when a buffer can be reused.
* *
* Upon completion, this function might change the state of the
* node to PAUSED, when the node has enough buffers on all ports.
*
* Once the port has allocated buffers, the memory of the buffers can be
* released again by calling SpaNode::port_use_buffers with %NULL.
*
* Returns: #SPA_RESULT_OK on success * Returns: #SPA_RESULT_OK on success
* #SPA_RESULT_ERROR when the node already has allocated buffers.
* #SPA_RESULT_ASYNC the function is executed asynchronously
*/ */
SpaResult (*port_alloc_buffers) (SpaNode *node, SpaResult (*port_alloc_buffers) (SpaNode *node,
uint32_t port_id, uint32_t port_id,

View file

@ -25,62 +25,35 @@
#include <spa/buffer.h> #include <spa/buffer.h>
#include <spa/port.h> #include <spa/port.h>
typedef struct { static const size_t header_sizes[] = {
SpaBuffer buffer; 0,
SpaMeta metas[3]; sizeof (SpaMetaHeader),
SpaMetaHeader header; sizeof (SpaMetaPointer),
SpaMetaRingbuffer ringbuffer; sizeof (SpaMetaVideoCrop),
SpaMetaVideoCrop crop; sizeof (SpaMetaRingbuffer),
SpaData datas[4]; };
} Buffer;
SpaResult SpaResult
spa_buffer_alloc (SpaBufferAllocFlags flags, spa_alloc_params_get_header_size (SpaAllocParam **params,
SpaAllocParam **params, unsigned int n_params,
unsigned int n_params, unsigned int n_datas,
SpaBuffer **buffers, size_t *size)
unsigned int *n_buffers)
{ {
unsigned int i, nbufs; unsigned int i, n_metas = 0;
size_t size = 0, stride = 0;
void *mem;
Buffer *bufs;
bool add_header = false;
int n_metas = 0;
nbufs = *n_buffers; *size = sizeof (SpaBuffer);
if (nbufs == 0)
return SPA_RESULT_ERROR;
for (i = 0; i < n_params; i++) { for (i = 0; i < n_params; i++) {
SpaAllocParam *p = params[i]; SpaAllocParam *p = params[i];
switch (p->type) { switch (p->type) {
case SPA_ALLOC_PARAM_TYPE_BUFFERS:
{
SpaAllocParamBuffers *b = (SpaAllocParamBuffers *) p;
size = SPA_MAX (size, b->minsize);
break;
}
case SPA_ALLOC_PARAM_TYPE_META_ENABLE: case SPA_ALLOC_PARAM_TYPE_META_ENABLE:
{ {
SpaAllocParamMetaEnable *b = (SpaAllocParamMetaEnable *) p; SpaAllocParamMetaEnable *b = (SpaAllocParamMetaEnable *) p;
switch (b->type) { if (b->type > 0 && b->type < SPA_N_ELEMENTS (header_sizes)) {
case SPA_META_TYPE_HEADER: n_metas++;
if (!add_header) *size += header_sizes[b->type];
n_metas++;
add_header = true;
break;
case SPA_META_TYPE_POINTER:
break;
case SPA_META_TYPE_VIDEO_CROP:
break;
case SPA_META_TYPE_RINGBUFFER:
break;
default:
break;
} }
break; break;
} }
@ -88,52 +61,71 @@ spa_buffer_alloc (SpaBufferAllocFlags flags,
break; break;
} }
} }
*size += n_metas * sizeof (SpaMeta);
*size += n_datas * sizeof (SpaData);
*n_buffers = nbufs; return SPA_RESULT_OK;
}
if (flags & SPA_BUFFER_ALLOC_FLAG_NO_MEM) SpaResult
size = 0; spa_buffer_init_headers (SpaAllocParam **params,
unsigned int n_params,
unsigned int n_datas,
SpaBuffer **buffers,
unsigned int n_buffers)
{
unsigned int i;
int n_metas = 0;
mem = calloc (nbufs, sizeof (Buffer) + size); for (i = 0; i < n_params; i++) {
SpaAllocParam *p = params[i];
bufs = mem; switch (p->type) {
case SPA_ALLOC_PARAM_TYPE_META_ENABLE:
for (i = 0; i < nbufs; i++) { {
int mi = 0; SpaAllocParamMetaEnable *b = (SpaAllocParamMetaEnable *) p;
Buffer *b; if (b->type > 0 && b->type <= SPA_N_ELEMENTS (header_sizes))
n_metas++;
b = &bufs[i]; }
b->buffer.id = i; default:
break;
buffers[i] = &b->buffer;
b->buffer.n_metas = n_metas;
b->buffer.metas = b->metas;
b->buffer.n_datas = 1;
b->buffer.datas = b->datas;
if (add_header) {
b->header.flags = 0;
b->header.seq = 0;
b->header.pts = 0;
b->header.dts_offset = 0;
b->metas[mi].type = SPA_META_TYPE_HEADER;
b->metas[mi].data = &b->header;
b->metas[mi].size = sizeof (b->header);
mi++;
} }
}
if (size == 0) { for (i = 0; i < n_buffers; i++) {
b->datas[0].type = SPA_DATA_TYPE_INVALID; int mi = 0, j;
b->datas[0].data = NULL; SpaBuffer *b;
} else { void *p;
b->datas[0].type = SPA_DATA_TYPE_MEMPTR;
b->datas[0].data = mem + sizeof (Buffer); b = buffers[i];
b->id = i;
b->n_metas = n_metas;
b->metas = SPA_MEMBER (b, sizeof (SpaBuffer), SpaMeta);
b->n_datas = n_datas;
b->datas = SPA_MEMBER (b->metas, sizeof (SpaMeta) * n_metas, SpaData);
p = SPA_MEMBER (b->datas, sizeof (SpaData) * n_datas, void);
for (j = 0, mi = 0; j < n_params; j++) {
SpaAllocParam *prm = params[j];
switch (prm->type) {
case SPA_ALLOC_PARAM_TYPE_META_ENABLE:
{
SpaAllocParamMetaEnable *pme = (SpaAllocParamMetaEnable *) prm;
if (pme->type > 0 && pme->type <= SPA_N_ELEMENTS (header_sizes)) {
b->metas[mi].type = pme->type;
b->metas[mi].data = p;
b->metas[mi].size = header_sizes[pme->type];
p = SPA_MEMBER (p, header_sizes[pme->type], void);
mi++;
}
break;
}
default:
break;
}
} }
b->datas[0].offset = size * i;
b->datas[0].size = size;
b->datas[0].stride = stride;
} }
return SPA_RESULT_OK; return SPA_RESULT_OK;
} }
@ -150,7 +142,7 @@ spa_buffer_get_size (const SpaBuffer *buffer)
size = sizeof (SpaBuffer); size = sizeof (SpaBuffer);
for (i = 0; i < buffer->n_metas; i++) for (i = 0; i < buffer->n_metas; i++)
size += buffer->metas[i].size * sizeof (SpaMeta); size += sizeof (SpaMeta) + buffer->metas[i].size;
for (i = 0; i < buffer->n_datas; i++) for (i = 0; i < buffer->n_datas; i++)
size += sizeof (SpaData); size += sizeof (SpaData);
return size; return size;

View file

@ -51,8 +51,8 @@ typedef struct _ProxyBuffer ProxyBuffer;
struct _ProxyBuffer { struct _ProxyBuffer {
SpaBuffer *outbuf; SpaBuffer *outbuf;
SpaBuffer buffer; SpaBuffer buffer;
SpaMeta metas[4];
SpaData datas[4]; SpaData datas[4];
off_t offset; off_t offset;
size_t size; size_t size;
@ -172,6 +172,8 @@ clear_buffers (SpaProxy *this, SpaProxyPort *port)
if (port->n_buffers) { if (port->n_buffers) {
fprintf (stderr, "proxy %p: clear buffers\n", this); fprintf (stderr, "proxy %p: clear buffers\n", this);
munmap (port->buffer_mem_ptr, port->buffer_mem_size);
close (port->buffer_mem_fd);
port->n_buffers = 0; port->n_buffers = 0;
SPA_QUEUE_INIT (&port->ready); SPA_QUEUE_INIT (&port->ready);
@ -400,7 +402,7 @@ do_update_port (SpaProxy *this,
if (pu->change_mask & SPA_CONTROL_CMD_PORT_UPDATE_PROPS) { if (pu->change_mask & SPA_CONTROL_CMD_PORT_UPDATE_PROPS) {
} }
if (pu->change_mask & SPA_CONTROL_CMD_PORT_UPDATE_INFO) { if (pu->change_mask & SPA_CONTROL_CMD_PORT_UPDATE_INFO && pu->info) {
port->info = *pu->info; port->info = *pu->info;
} }
@ -691,12 +693,17 @@ spa_proxy_node_port_use_buffers (SpaNode *node,
b->outbuf = buffers[i]; b->outbuf = buffers[i];
memcpy (&b->buffer, buffers[i], sizeof (SpaBuffer)); memcpy (&b->buffer, buffers[i], sizeof (SpaBuffer));
b->buffer.datas = b->datas; b->buffer.datas = b->datas;
b->buffer.metas = b->metas;
b->size = spa_buffer_get_size (buffers[i]); b->size = spa_buffer_get_size (buffers[i]);
b->offset = size; b->offset = size;
size += b->size; size += b->size;
for (j = 0; j < buffers[i]->n_datas; j++) {
memcpy (&b->buffer.metas[j], &buffers[i]->metas[j], sizeof (SpaMeta));
}
for (j = 0; j < buffers[i]->n_datas; j++) { for (j = 0; j < buffers[i]->n_datas; j++) {
SpaData *d = &buffers[i]->datas[j]; SpaData *d = &buffers[i]->datas[j];
@ -723,18 +730,32 @@ spa_proxy_node_port_use_buffers (SpaNode *node,
if (ftruncate (port->buffer_mem_fd, size) < 0) { if (ftruncate (port->buffer_mem_fd, size) < 0) {
fprintf (stderr, "Failed to truncate temporary file: %s\n", strerror (errno)); fprintf (stderr, "Failed to truncate temporary file: %s\n", strerror (errno));
close (port->buffer_mem_fd); close (port->buffer_mem_fd);
return SPA_RESULT_ERROR;
} }
{ {
unsigned int seals = F_SEAL_GROW | F_SEAL_SHRINK | F_SEAL_SEAL; unsigned int seals = F_SEAL_GROW | F_SEAL_SHRINK | F_SEAL_SEAL;
if (fcntl (port->buffer_mem_fd, F_ADD_SEALS, seals) == -1) { if (fcntl (port->buffer_mem_fd, F_ADD_SEALS, seals) == -1) {
fprintf (stderr, "Failed to add seals: %s\n", strerror (errno)); fprintf (stderr, "Failed to add seals: %s\n", strerror (errno));
close (port->buffer_mem_fd);
} }
} }
p = port->buffer_mem_ptr = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, port->buffer_mem_fd, 0); p = port->buffer_mem_ptr = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, port->buffer_mem_fd, 0);
for (i = 0; i < n_buffers; i++) for (i = 0; i < n_buffers; i++) {
p += spa_buffer_serialize (p, &port->buffers[i].buffer); ProxyBuffer *b = &port->buffers[i];
size_t len;
SpaBuffer *sb;
SpaMeta *sbm;
len = spa_buffer_serialize (p, &b->buffer);
sb = p;
sbm = SPA_MEMBER (sb, SPA_PTR_TO_INT (sb->metas), SpaMeta);
for (j = 0; j < b->buffer.n_metas; j++)
b->metas[j].data = SPA_MEMBER (sb, SPA_PTR_TO_INT (sbm[j].data), void);
p += len;
}
am.port_id = port_id; am.port_id = port_id;
am.mem_id = port->buffer_mem_id; am.mem_id = port->buffer_mem_id;
@ -837,6 +858,19 @@ spa_proxy_node_port_reuse_buffer (SpaNode *node,
return res; return res;
} }
static void
copy_meta (SpaProxy *this, SpaProxyPort *port, uint32_t buffer_id)
{
ProxyBuffer *b = &port->buffers[buffer_id];
unsigned int i;
for (i = 0; i < b->outbuf->n_metas; i++) {
SpaMeta *sm = &b->outbuf->metas[i];
SpaMeta *dm = &b->buffer.metas[i];
memcpy (dm->data, sm->data, dm->size);
}
}
static SpaResult static SpaResult
spa_proxy_node_port_push_input (SpaNode *node, spa_proxy_node_port_push_input (SpaNode *node,
unsigned int n_info, unsigned int n_info,
@ -883,6 +917,8 @@ spa_proxy_node_port_push_input (SpaNode *node,
continue; continue;
} }
copy_meta (this, port, info[i].buffer_id);
pb.port_id = info[i].port_id; pb.port_id = info[i].port_id;
pb.buffer_id = info[i].buffer_id; pb.buffer_id = info[i].buffer_id;
spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_PROCESS_BUFFER, &pb); spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_PROCESS_BUFFER, &pb);

View file

@ -78,7 +78,6 @@ struct _V4l2Format {
typedef struct { typedef struct {
bool export_buf; bool export_buf;
bool have_buffers;
bool started; bool started;
bool next_fmtdesc; bool next_fmtdesc;
@ -98,16 +97,17 @@ typedef struct {
enum v4l2_buf_type type; enum v4l2_buf_type type;
enum v4l2_memory memtype; enum v4l2_memory memtype;
struct v4l2_requestbuffers reqbuf; V4l2Buffer buffers[MAX_BUFFERS];
V4l2Buffer buffers[MAX_BUFFERS]; unsigned int n_buffers;
SpaQueue ready; SpaQueue ready;
SpaPollFd fds[1]; SpaPollFd fds[1];
SpaPollItem poll; SpaPollItem poll;
SpaPortInfo info; SpaPortInfo info;
SpaAllocParam *params[1]; SpaAllocParam *params[2];
SpaAllocParamBuffers param_buffers; SpaAllocParamBuffers param_buffers;
SpaAllocParamMetaEnable param_meta;
SpaPortStatus status; SpaPortStatus status;
int64_t last_ticks; int64_t last_ticks;
@ -228,7 +228,7 @@ spa_v4l2_source_node_send_command (SpaNode *node,
if (state->current_format == NULL) if (state->current_format == NULL)
return SPA_RESULT_NO_FORMAT; return SPA_RESULT_NO_FORMAT;
if (!state->have_buffers) if (state->n_buffers == 0)
return SPA_RESULT_NO_BUFFERS; return SPA_RESULT_NO_BUFFERS;
if ((res = spa_v4l2_start (this)) < 0) if ((res = spa_v4l2_start (this)) < 0)
@ -243,7 +243,7 @@ spa_v4l2_source_node_send_command (SpaNode *node,
if (state->current_format == NULL) if (state->current_format == NULL)
return SPA_RESULT_NO_FORMAT; return SPA_RESULT_NO_FORMAT;
if (!state->have_buffers) if (state->n_buffers == 0)
return SPA_RESULT_NO_BUFFERS; return SPA_RESULT_NO_BUFFERS;
if ((res = spa_v4l2_pause (this)) < 0) if ((res = spa_v4l2_pause (this)) < 0)
@ -533,7 +533,7 @@ spa_v4l2_source_node_port_use_buffers (SpaNode *node,
if (state->current_format == NULL) if (state->current_format == NULL)
return SPA_RESULT_NO_FORMAT; return SPA_RESULT_NO_FORMAT;
if (state->have_buffers) { if (state->n_buffers) {
if ((res = spa_v4l2_clear_buffers (this)) < 0) if ((res = spa_v4l2_clear_buffers (this)) < 0)
return res; return res;
} }
@ -542,12 +542,12 @@ spa_v4l2_source_node_port_use_buffers (SpaNode *node,
return res; return res;
} }
if (state->have_buffers) if (state->n_buffers)
update_state (this, SPA_NODE_STATE_PAUSED); update_state (this, SPA_NODE_STATE_PAUSED);
else else
update_state (this, SPA_NODE_STATE_READY); update_state (this, SPA_NODE_STATE_READY);
return res; return SPA_RESULT_OK;
} }
static SpaResult static SpaResult
@ -577,7 +577,7 @@ spa_v4l2_source_node_port_alloc_buffers (SpaNode *node,
res = spa_v4l2_alloc_buffers (this, params, n_params, buffers, n_buffers); res = spa_v4l2_alloc_buffers (this, params, n_params, buffers, n_buffers);
if (state->have_buffers) { if (state->n_buffers) {
if (state->started) if (state->started)
update_state (this, SPA_NODE_STATE_STREAMING); update_state (this, SPA_NODE_STATE_STREAMING);
else else
@ -606,10 +606,10 @@ spa_v4l2_source_node_port_reuse_buffer (SpaNode *node,
state = &this->state[port_id]; state = &this->state[port_id];
if (!state->have_buffers) if (state->n_buffers == 0)
return SPA_RESULT_NO_BUFFERS; return SPA_RESULT_NO_BUFFERS;
if (buffer_id >= state->reqbuf.count) if (buffer_id >= state->n_buffers)
return SPA_RESULT_INVALID_BUFFER_ID; return SPA_RESULT_INVALID_BUFFER_ID;
res = spa_v4l2_buffer_recycle (this, buffer_id); res = spa_v4l2_buffer_recycle (this, buffer_id);

View file

@ -92,12 +92,13 @@ static SpaResult
spa_v4l2_clear_buffers (SpaV4l2Source *this) spa_v4l2_clear_buffers (SpaV4l2Source *this)
{ {
SpaV4l2State *state = &this->state[0]; SpaV4l2State *state = &this->state[0];
struct v4l2_requestbuffers reqbuf;
int i; int i;
if (!state->have_buffers) if (state->n_buffers == 0)
return SPA_RESULT_OK; return SPA_RESULT_OK;
for (i = 0; i < state->reqbuf.count; i++) { for (i = 0; i < state->n_buffers; i++) {
V4l2Buffer *b; V4l2Buffer *b;
b = &state->buffers[i]; b = &state->buffers[i];
@ -105,9 +106,20 @@ spa_v4l2_clear_buffers (SpaV4l2Source *this)
fprintf (stderr, "queueing outstanding buffer %p\n", b); fprintf (stderr, "queueing outstanding buffer %p\n", b);
spa_v4l2_buffer_recycle (this, i); spa_v4l2_buffer_recycle (this, i);
} }
if (state->export_buf) {
close (SPA_PTR_TO_INT (b->outbuf->datas[0].data));
}
} }
state->have_buffers = false; CLEAR(reqbuf);
reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
reqbuf.memory = state->memtype;
reqbuf.count = 0;
if (xioctl (state->fd, VIDIOC_REQBUFS, &reqbuf) < 0) {
perror ("VIDIOC_REQBUFS");
}
state->n_buffers = 0;
return SPA_RESULT_OK; return SPA_RESULT_OK;
} }
@ -120,7 +132,7 @@ spa_v4l2_close (SpaV4l2Source *this)
if (!state->opened) if (!state->opened)
return 0; return 0;
if (state->have_buffers) if (state->n_buffers > 0)
return 0; return 0;
fprintf (stderr, "close\n"); fprintf (stderr, "close\n");
@ -786,7 +798,7 @@ spa_v4l2_set_format (SpaV4l2Source *this, V4l2Format *f, bool try_only)
state->info.latency = (streamparm.parm.capture.timeperframe.numerator * SPA_NSEC_PER_SEC) / state->info.latency = (streamparm.parm.capture.timeperframe.numerator * SPA_NSEC_PER_SEC) /
streamparm.parm.capture.timeperframe.denominator; streamparm.parm.capture.timeperframe.denominator;
state->info.n_params = 1; state->info.n_params = 2;
state->info.params = state->params; state->info.params = state->params;
state->params[0] = &state->param_buffers.param; state->params[0] = &state->param_buffers.param;
state->param_buffers.param.type = SPA_ALLOC_PARAM_TYPE_BUFFERS; state->param_buffers.param.type = SPA_ALLOC_PARAM_TYPE_BUFFERS;
@ -796,6 +808,11 @@ spa_v4l2_set_format (SpaV4l2Source *this, V4l2Format *f, bool try_only)
state->param_buffers.min_buffers = 2; state->param_buffers.min_buffers = 2;
state->param_buffers.max_buffers = MAX_BUFFERS; state->param_buffers.max_buffers = MAX_BUFFERS;
state->param_buffers.align = 16; state->param_buffers.align = 16;
state->params[1] = &state->param_meta.param;
state->param_meta.param.type = SPA_ALLOC_PARAM_TYPE_META_ENABLE;
state->param_meta.param.size = sizeof (state->param_meta);
state->param_meta.type = SPA_META_TYPE_HEADER;
state->info.features = NULL; state->info.features = NULL;
return 0; return 0;
@ -873,6 +890,18 @@ v4l2_on_fd_events (SpaPollNotifyData *data)
return 0; return 0;
} }
static void *
find_meta_data (SpaBuffer *b, SpaMetaType type)
{
unsigned int i;
for (i = 0; i < b->n_metas; i++)
if (b->metas[i].type == type)
return b->metas[i].data;
return NULL;
}
static SpaResult static SpaResult
spa_v4l2_use_buffers (SpaV4l2Source *this, SpaBuffer **buffers, uint32_t n_buffers) spa_v4l2_use_buffers (SpaV4l2Source *this, SpaBuffer **buffers, uint32_t n_buffers)
{ {
@ -896,7 +925,6 @@ spa_v4l2_use_buffers (SpaV4l2Source *this, SpaBuffer **buffers, uint32_t n_buffe
fprintf (stderr, "can't allocate enough buffers\n"); fprintf (stderr, "can't allocate enough buffers\n");
return SPA_RESULT_ERROR; return SPA_RESULT_ERROR;
} }
state->reqbuf = reqbuf;
for (i = 0; i < reqbuf.count; i++) { for (i = 0; i < reqbuf.count; i++) {
V4l2Buffer *b; V4l2Buffer *b;
@ -905,6 +933,7 @@ spa_v4l2_use_buffers (SpaV4l2Source *this, SpaBuffer **buffers, uint32_t n_buffe
b = &state->buffers[i]; b = &state->buffers[i];
b->outbuf = buffers[i]; b->outbuf = buffers[i];
b->outstanding = true; b->outstanding = true;
b->h = find_meta_data (b->outbuf, SPA_META_TYPE_HEADER);
fprintf (stderr, "import buffer %p\n", buffers[i]); fprintf (stderr, "import buffer %p\n", buffers[i]);
@ -923,7 +952,7 @@ spa_v4l2_use_buffers (SpaV4l2Source *this, SpaBuffer **buffers, uint32_t n_buffe
spa_v4l2_buffer_recycle (this, buffers[i]->id); spa_v4l2_buffer_recycle (this, buffers[i]->id);
} }
state->have_buffers = true; state->n_buffers = reqbuf.count;
return SPA_RESULT_OK; return SPA_RESULT_OK;
} }
@ -961,8 +990,6 @@ mmap_init (SpaV4l2Source *this,
if (state->export_buf) if (state->export_buf)
fprintf (stderr, "using EXPBUF\n"); fprintf (stderr, "using EXPBUF\n");
state->reqbuf = reqbuf;
for (i = 0; i < reqbuf.count; i++) { for (i = 0; i < reqbuf.count; i++) {
V4l2Buffer *b; V4l2Buffer *b;
SpaData *d; SpaData *d;
@ -975,6 +1002,7 @@ mmap_init (SpaV4l2Source *this,
b = &state->buffers[i]; b = &state->buffers[i];
b->outbuf = buffers[i]; b->outbuf = buffers[i];
b->outstanding = true; b->outstanding = true;
b->h = find_meta_data (b->outbuf, SPA_META_TYPE_HEADER);
CLEAR (b->v4l2_buffer); CLEAR (b->v4l2_buffer);
b->v4l2_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; b->v4l2_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
@ -997,17 +1025,19 @@ mmap_init (SpaV4l2Source *this,
CLEAR (expbuf); CLEAR (expbuf);
expbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; expbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
expbuf.index = i; expbuf.index = i;
expbuf.flags = O_CLOEXEC | O_RDONLY;
if (xioctl (state->fd, VIDIOC_EXPBUF, &expbuf) < 0) { if (xioctl (state->fd, VIDIOC_EXPBUF, &expbuf) < 0) {
perror("VIDIOC_EXPBUF"); perror("VIDIOC_EXPBUF");
continue; continue;
} }
fprintf (stderr, "expbuf %d\n", expbuf.fd);
d[0].type = SPA_DATA_TYPE_FD; d[0].type = SPA_DATA_TYPE_FD;
d[0].data = SPA_INT_TO_PTR (expbuf.fd); d[0].data = SPA_INT_TO_PTR (expbuf.fd);
} else { } else {
d[0].type = SPA_DATA_TYPE_MEMPTR; d[0].type = SPA_DATA_TYPE_MEMPTR;
d[0].data = mmap (NULL, d[0].data = mmap (NULL,
b->v4l2_buffer.length, b->v4l2_buffer.length,
PROT_READ | PROT_WRITE, PROT_READ,
MAP_SHARED, MAP_SHARED,
state->fd, state->fd,
b->v4l2_buffer.m.offset); b->v4l2_buffer.m.offset);
@ -1018,7 +1048,7 @@ mmap_init (SpaV4l2Source *this,
} }
spa_v4l2_buffer_recycle (this, i); spa_v4l2_buffer_recycle (this, i);
} }
state->have_buffers = true; state->n_buffers = reqbuf.count;
return SPA_RESULT_OK; return SPA_RESULT_OK;
} }
@ -1045,7 +1075,7 @@ spa_v4l2_alloc_buffers (SpaV4l2Source *this,
SpaResult res; SpaResult res;
SpaV4l2State *state = &this->state[0]; SpaV4l2State *state = &this->state[0];
if (state->have_buffers) if (state->n_buffers > 0)
return SPA_RESULT_ERROR; return SPA_RESULT_ERROR;
if (state->cap.capabilities & V4L2_CAP_STREAMING) { if (state->cap.capabilities & V4L2_CAP_STREAMING) {
@ -1123,7 +1153,7 @@ spa_v4l2_pause (SpaV4l2Source *this)
perror ("VIDIOC_STREAMOFF"); perror ("VIDIOC_STREAMOFF");
return SPA_RESULT_ERROR; return SPA_RESULT_ERROR;
} }
for (i = 0; i < state->reqbuf.count; i++) { for (i = 0; i < state->n_buffers; i++) {
V4l2Buffer *b; V4l2Buffer *b;
b = &state->buffers[i]; b = &state->buffers[i];