v4l2: add support for DMABUF

Export dmafd on buffers and use those directly to send to the client.
Do some v4l2 cleanup.
This commit is contained in:
Wim Taymans 2016-07-13 19:56:39 +02:00
parent 17ef36c9c1
commit 16d2a3a69c
3 changed files with 61 additions and 18 deletions

View file

@ -58,6 +58,7 @@ struct _V4l2Buffer {
bool outstanding;
struct v4l2_buffer v4l2_buffer;
V4l2Buffer *next;
int dmafd;
};
typedef struct {
@ -79,6 +80,7 @@ typedef struct {
SpaPortInfo info;
SpaAllocParam *params[1];
SpaAllocParamBuffers param_buffers;
bool export_buf;
SpaPortStatus status;
} SpaV4l2State;
@ -598,6 +600,8 @@ v4l2_source_init (const SpaHandleFactory *factory,
this->state[0].info.flags = SPA_PORT_INFO_FLAG_NONE;
this->state[0].status.flags = SPA_PORT_STATUS_FLAG_NONE;
this->state[0].export_buf = true;
return SPA_RESULT_OK;
}

View file

@ -346,7 +346,6 @@ spa_v4l2_close (SpaV4l2Source *this)
state->fd = -1;
state->opened = false;
state->have_buffers = false;
return 0;
}
@ -530,22 +529,40 @@ mmap_init (SpaV4l2Source *this)
b->metas[0].data = &b->header;
b->metas[0].size = sizeof (b->header);
b->datas[0].type = SPA_DATA_TYPE_MEMPTR;
b->datas[0].data = 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;
b->datas[0].stride = state->fmt.fmt.pix.bytesperline;
b->outstanding = true;
if (state->export_buf) {
struct v4l2_exportbuffer expbuf;
if (b->datas[0].data == MAP_FAILED) {
perror ("mmap");
continue;
CLEAR (expbuf);
expbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
expbuf.index = i;
if (xioctl (state->fd, VIDIOC_EXPBUF, &expbuf) < 0) {
perror("VIDIOC_EXPBUF");
continue;
}
b->dmafd = expbuf.fd;
b->datas[0].type = SPA_DATA_TYPE_FD;
b->datas[0].data = &b->dmafd;
b->datas[0].offset = 0;
b->datas[0].size = buf.length;
b->datas[0].stride = state->fmt.fmt.pix.bytesperline;
} else {
b->datas[0].type = SPA_DATA_TYPE_MEMPTR;
b->datas[0].data = 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;
b->datas[0].stride = state->fmt.fmt.pix.bytesperline;
if (b->datas[0].data == MAP_FAILED) {
perror ("mmap");
continue;
}
}
b->outstanding = true;
CLEAR (b->v4l2_buffer);
b->v4l2_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
@ -626,6 +643,7 @@ spa_v4l2_stop (SpaV4l2Source *this)
SpaV4l2State *state = &this->state[0];
enum v4l2_buf_type type;
SpaEvent event;
int i;
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (xioctl (state->fd, VIDIOC_STREAMOFF, &type) < 0) {
@ -633,6 +651,22 @@ spa_v4l2_stop (SpaV4l2Source *this)
return -1;
}
for (i = 0; i < state->reqbuf.count; i++) {
V4l2Buffer *b;
b = &state->buffers[i];
if (b->outstanding) {
fprintf (stderr, "queueing outstanding buffer %p\n", b);
v4l2_buffer_free (b);
}
if (state->export_buf) {
close (b->dmafd);
} else {
munmap (b->datas[0].data, b->datas[0].size);
}
}
state->have_buffers = false;
event.refcount = 1;
event.notify = NULL;
event.type = SPA_EVENT_TYPE_REMOVE_POLL;