diff --git a/pinos/modules/spa/spa-v4l2-source.c b/pinos/modules/spa/spa-v4l2-source.c index 19cd7f773..f04546d12 100644 --- a/pinos/modules/spa/spa-v4l2-source.c +++ b/pinos/modules/spa/spa-v4l2-source.c @@ -199,11 +199,15 @@ on_source_event (SpaHandle *handle, SpaEvent *event, void *user_data) pinos_buffer_builder_init_into (&builder, buf, 1024, fdbuf, 8); pinos_buffer_builder_add_header (&builder, &hdr); - fd = tmpfile_create (source, b->datas[0].data, b->size); + if (b->datas[0].type == SPA_DATA_TYPE_FD) { + fd = *((int *)b->datas[0].data); + } else { + fd = tmpfile_create (source, b->datas[0].data, b->size); + } p.fd_index = pinos_buffer_builder_add_fd (&builder, fd); p.id = pinos_fd_manager_get_id (priv->fdmanager); - p.offset = 0; - p.size = b->size; + p.offset = b->datas[0].offset; + p.size = b->datas[0].size; pinos_buffer_builder_add_fd_payload (&builder, &p); pinos_buffer_builder_end (&builder, &pbuf); @@ -219,6 +223,7 @@ on_source_event (SpaHandle *handle, SpaEvent *event, void *user_data) g_clear_error (&error); } } + pinos_buffer_steal_fds (&pbuf, NULL); pinos_buffer_unref (&pbuf); spa_buffer_unref (b); diff --git a/spa/plugins/v4l2/v4l2-source.c b/spa/plugins/v4l2/v4l2-source.c index 06a11d4ac..1eb016fa7 100644 --- a/spa/plugins/v4l2/v4l2-source.c +++ b/spa/plugins/v4l2/v4l2-source.c @@ -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; } diff --git a/spa/plugins/v4l2/v4l2-utils.c b/spa/plugins/v4l2/v4l2-utils.c index d730aac99..11a8469c5 100644 --- a/spa/plugins/v4l2/v4l2-utils.c +++ b/spa/plugins/v4l2/v4l2-utils.c @@ -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;