mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
v4l2: Add mmap fallback when USERPTR is not supported
When we don't support EXPBUF according to the probe, the host will allocate memory for us. We will then try to use USERPTR to import the memory into v4l2. If this is not supported, try to fall back to MMAP support, mmap the buffers and memcpy the MMAP buffer to the host allocated buffers.
This commit is contained in:
parent
c4df4a0371
commit
b2dd733520
2 changed files with 44 additions and 7 deletions
|
|
@ -58,6 +58,7 @@ struct buffer {
|
||||||
struct spa_meta_videotransform *vt;
|
struct spa_meta_videotransform *vt;
|
||||||
struct v4l2_buffer v4l2_buffer;
|
struct v4l2_buffer v4l2_buffer;
|
||||||
void *ptr;
|
void *ptr;
|
||||||
|
void *mmap_ptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MAX_CONTROLS 64
|
#define MAX_CONTROLS 64
|
||||||
|
|
|
||||||
|
|
@ -120,7 +120,6 @@ static int spa_v4l2_buffer_recycle(struct impl *this, uint32_t buffer_id)
|
||||||
spa_log_error(this->log, "'%s' VIDIOC_QBUF: %m", this->props.device);
|
spa_log_error(this->log, "'%s' VIDIOC_QBUF: %m", this->props.device);
|
||||||
return -err;
|
return -err;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -147,6 +146,8 @@ static int spa_v4l2_clear_buffers(struct impl *this)
|
||||||
if (SPA_FLAG_IS_SET(b->flags, BUFFER_FLAG_MAPPED)) {
|
if (SPA_FLAG_IS_SET(b->flags, BUFFER_FLAG_MAPPED)) {
|
||||||
munmap(b->ptr, d[0].maxsize);
|
munmap(b->ptr, d[0].maxsize);
|
||||||
}
|
}
|
||||||
|
if (b->mmap_ptr)
|
||||||
|
munmap(b->mmap_ptr, b->v4l2_buffer.length);
|
||||||
if (SPA_FLAG_IS_SET(b->flags, BUFFER_FLAG_ALLOCATED)) {
|
if (SPA_FLAG_IS_SET(b->flags, BUFFER_FLAG_ALLOCATED)) {
|
||||||
spa_log_debug(this->log, "close %d", (int) d[0].fd);
|
spa_log_debug(this->log, "close %d", (int) d[0].fd);
|
||||||
close(d[0].fd);
|
close(d[0].fd);
|
||||||
|
|
@ -1459,12 +1460,15 @@ static int mmap_read(struct impl *this)
|
||||||
|
|
||||||
d = b->outbuf->datas;
|
d = b->outbuf->datas;
|
||||||
d[0].chunk->offset = 0;
|
d[0].chunk->offset = 0;
|
||||||
d[0].chunk->size = buf.bytesused;
|
d[0].chunk->size = SPA_MIN(buf.bytesused, d[0].maxsize);
|
||||||
d[0].chunk->stride = port->fmt.fmt.pix.bytesperline;
|
d[0].chunk->stride = port->fmt.fmt.pix.bytesperline;
|
||||||
d[0].chunk->flags = 0;
|
d[0].chunk->flags = 0;
|
||||||
if (buf.flags & V4L2_BUF_FLAG_ERROR)
|
if (buf.flags & V4L2_BUF_FLAG_ERROR)
|
||||||
d[0].chunk->flags |= SPA_CHUNK_FLAG_CORRUPTED;
|
d[0].chunk->flags |= SPA_CHUNK_FLAG_CORRUPTED;
|
||||||
|
|
||||||
|
if (b->mmap_ptr && b->ptr)
|
||||||
|
memcpy(b->ptr, b->mmap_ptr, d[0].chunk->size);
|
||||||
|
|
||||||
spa_list_append(&port->queue, &b->link);
|
spa_list_append(&port->queue, &b->link);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -1549,8 +1553,22 @@ static int spa_v4l2_use_buffers(struct impl *this, struct spa_buffer **buffers,
|
||||||
reqbuf.count = n_buffers;
|
reqbuf.count = n_buffers;
|
||||||
|
|
||||||
if (xioctl(dev->fd, VIDIOC_REQBUFS, &reqbuf) < 0) {
|
if (xioctl(dev->fd, VIDIOC_REQBUFS, &reqbuf) < 0) {
|
||||||
spa_log_error(this->log, "'%s' VIDIOC_REQBUFS %m", this->props.device);
|
if (port->memtype != V4L2_MEMORY_USERPTR) {
|
||||||
return -errno;
|
spa_log_error(this->log, "'%s' VIDIOC_REQBUFS %m", this->props.device);
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
/* some drivers (v4l2loopback) don't support USERPTR
|
||||||
|
* and so we need to try again with MMAP and memcpy */
|
||||||
|
port->memtype = V4L2_MEMORY_MMAP;
|
||||||
|
spa_zero(reqbuf);
|
||||||
|
reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
reqbuf.memory = port->memtype;
|
||||||
|
reqbuf.count = n_buffers;
|
||||||
|
|
||||||
|
if (xioctl(dev->fd, VIDIOC_REQBUFS, &reqbuf) < 0) {
|
||||||
|
spa_log_error(this->log, "'%s' VIDIOC_REQBUFS %m", this->props.device);
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
spa_log_debug(this->log, "got %d buffers", reqbuf.count);
|
spa_log_debug(this->log, "got %d buffers", reqbuf.count);
|
||||||
if (reqbuf.count < n_buffers) {
|
if (reqbuf.count < n_buffers) {
|
||||||
|
|
@ -1583,7 +1601,8 @@ static int spa_v4l2_use_buffers(struct impl *this, struct spa_buffer **buffers,
|
||||||
b->v4l2_buffer.memory = port->memtype;
|
b->v4l2_buffer.memory = port->memtype;
|
||||||
b->v4l2_buffer.index = i;
|
b->v4l2_buffer.index = i;
|
||||||
|
|
||||||
if (port->memtype == V4L2_MEMORY_USERPTR) {
|
if (port->memtype == V4L2_MEMORY_USERPTR ||
|
||||||
|
port->memtype == V4L2_MEMORY_MMAP) {
|
||||||
if (d[0].data == NULL) {
|
if (d[0].data == NULL) {
|
||||||
void *data;
|
void *data;
|
||||||
|
|
||||||
|
|
@ -1601,8 +1620,24 @@ static int spa_v4l2_use_buffers(struct impl *this, struct spa_buffer **buffers,
|
||||||
else
|
else
|
||||||
b->ptr = d[0].data;
|
b->ptr = d[0].data;
|
||||||
|
|
||||||
b->v4l2_buffer.m.userptr = (unsigned long) b->ptr;
|
if (port->memtype == V4L2_MEMORY_USERPTR) {
|
||||||
b->v4l2_buffer.length = d[0].maxsize;
|
b->v4l2_buffer.m.userptr = (unsigned long) b->ptr;
|
||||||
|
b->v4l2_buffer.length = d[0].maxsize;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (xioctl(dev->fd, VIDIOC_QUERYBUF, &b->v4l2_buffer) < 0) {
|
||||||
|
spa_log_error(this->log, "'%s' VIDIOC_QUERYBUF: %m", this->props.device);
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
b->mmap_ptr = mmap(NULL,
|
||||||
|
b->v4l2_buffer.length,
|
||||||
|
PROT_READ, MAP_PRIVATE,
|
||||||
|
dev->fd, b->v4l2_buffer.m.offset);
|
||||||
|
if (b->mmap_ptr == MAP_FAILED) {
|
||||||
|
spa_log_error(this->log, "'%s' mmap: %m", this->props.device);
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (port->memtype == V4L2_MEMORY_DMABUF) {
|
else if (port->memtype == V4L2_MEMORY_DMABUF) {
|
||||||
b->v4l2_buffer.m.fd = d[0].fd;
|
b->v4l2_buffer.m.fd = d[0].fd;
|
||||||
|
|
@ -1814,6 +1849,7 @@ static int spa_v4l2_stream_on(struct impl *this)
|
||||||
spa_log_debug(this->log, "starting");
|
spa_log_debug(this->log, "starting");
|
||||||
|
|
||||||
port->first_buffer = true;
|
port->first_buffer = true;
|
||||||
|
mmap_read(this);
|
||||||
|
|
||||||
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
if (xioctl(dev->fd, VIDIOC_STREAMON, &type) < 0) {
|
if (xioctl(dev->fd, VIDIOC_STREAMON, &type) < 0) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue