diff --git a/spa/plugins/v4l2/v4l2-source.c b/spa/plugins/v4l2/v4l2-source.c index b79015a28..c532ea185 100644 --- a/spa/plugins/v4l2/v4l2-source.c +++ b/spa/plugins/v4l2/v4l2-source.c @@ -71,6 +71,7 @@ struct port { struct impl *impl; bool alloc_buffers; + bool probed_expbuf; bool have_expbuf; bool next_fmtdesc; @@ -1020,8 +1021,7 @@ impl_init(const struct spa_handle_factory *factory, port->info.params = port->params; port->info.n_params = N_PORT_PARAMS; - port->alloc_buffers = true; - port->have_expbuf = true; + port->probed_expbuf = false; port->have_query_ext_ctrl = true; port->dev.log = this->log; port->dev.fd = -1; diff --git a/spa/plugins/v4l2/v4l2-utils.c b/spa/plugins/v4l2/v4l2-utils.c index 0c7626eb3..1ed46d62c 100644 --- a/spa/plugins/v4l2/v4l2-utils.c +++ b/spa/plugins/v4l2/v4l2-utils.c @@ -867,6 +867,48 @@ do_enum_fmt: return res; } +static int probe_expbuf(struct impl *this) +{ + struct port *port = &this->out_ports[0]; + struct spa_v4l2_device *dev = &port->dev; + struct v4l2_requestbuffers reqbuf; + struct v4l2_exportbuffer expbuf; + + if (port->probed_expbuf) + return 0; + port->probed_expbuf = true; + + spa_zero(reqbuf); + reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + reqbuf.memory = V4L2_MEMORY_MMAP; + reqbuf.count = 2; + + if (xioctl(dev->fd, VIDIOC_REQBUFS, &reqbuf) < 0) { + spa_log_error(this->log, "'%s' VIDIOC_REQBUFS: %m", this->props.device); + return -errno; + } + + spa_zero(expbuf); + expbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + expbuf.index = 0; + expbuf.flags = O_CLOEXEC | O_RDONLY; + if (xioctl(dev->fd, VIDIOC_EXPBUF, &expbuf) < 0) { + spa_log_info(this->log, "'%s' EXPBUF not supported: %m", this->props.device); + port->have_expbuf = false; + port->alloc_buffers = false; + } else { + port->have_expbuf = true; + port->alloc_buffers = true; + } + + reqbuf.count = 0; + if (xioctl(dev->fd, VIDIOC_REQBUFS, &reqbuf) < 0) { + spa_log_error(this->log, "'%s' VIDIOC_REQBUFS: %m", this->props.device); + return -errno; + } + return 0; +} + static int spa_v4l2_set_format(struct impl *this, struct spa_video_info *format, uint32_t flags) { struct port *port = &this->out_ports[0]; @@ -973,6 +1015,8 @@ static int spa_v4l2_set_format(struct impl *this, struct spa_video_info *format, port->rate.denom = framerate->num = streamparm.parm.capture.timeperframe.denominator; port->rate.num = framerate->denom = streamparm.parm.capture.timeperframe.numerator; + probe_expbuf(this); + port->fmt = fmt; port->info.change_mask |= SPA_PORT_CHANGE_MASK_FLAGS | SPA_PORT_CHANGE_MASK_RATE; port->info.flags = (port->alloc_buffers ? SPA_PORT_FLAG_CAN_ALLOC_BUFFERS : 0) |