XCamReturn V4l2Device::open () { struct v4l2_streamparm param; if (is_opened()) { XCAM_LOG_DEBUG ("device(%s) was already opened", XCAM_STR(_name)); return XCAM_RETURN_NO_ERROR; } if (!_name) { XCAM_LOG_DEBUG ("v4l2 device open failed, there's no device name"); return XCAM_RETURN_ERROR_PARAM; } _fd = ::open (_name, O_RDWR); if (_fd == -1) { XCAM_LOG_DEBUG ("open device(%s) failed", _name); return XCAM_RETURN_ERROR_IOCTL; } // set sensor id if (io_control (VIDIOC_S_INPUT, &_sensor_id) < 0) { XCAM_LOG_WARNING ("set sensor id(%d) failed but continue", _sensor_id); } // set capture mode xcam_mem_clear (param); param.type = _capture_buf_type; param.parm.capture.capturemode = _capture_mode; if (io_control (VIDIOC_S_PARM, ¶m) < 0) { XCAM_LOG_WARNING ("set capture mode(0x%08x) failed but continue", _capture_mode); } return XCAM_RETURN_NO_ERROR; }
XCamReturn V4l2Device::request_buffer () { struct v4l2_requestbuffers request_buf; XCAM_ASSERT (!is_activated()); xcam_mem_clear (request_buf); request_buf.type = _capture_buf_type; request_buf.count = _buf_count; request_buf.memory = _memory_type; if (io_control (VIDIOC_REQBUFS, &request_buf) < 0) { XCAM_LOG_INFO ("device(%s) starts failed on VIDIOC_REQBUFS", XCAM_STR (_name)); return XCAM_RETURN_ERROR_IOCTL; } if (request_buf.count != _buf_count) { XCAM_LOG_DEBUG ( "device(%s) request buffer count doesn't match user settings, reset buffer count to %d", XCAM_STR (_name), request_buf.count); _buf_count = request_buf.count; } return XCAM_RETURN_NO_ERROR; }
XCamReturn V4l2Device::queue_buffer (SmartPtr<V4l2Buffer> &buf) { XCAM_ASSERT (buf.ptr()); buf->reset (); struct v4l2_buffer v4l2_buf = buf->get_buf (); XCAM_ASSERT (v4l2_buf.index < _buf_count); XCAM_LOG_DEBUG ("device(%s) queue buffer index:%d", XCAM_STR (_name), v4l2_buf.index); if (io_control (VIDIOC_QBUF, &v4l2_buf) < 0) { XCAM_LOG_ERROR("fail to enqueue buffer index:%d.", v4l2_buf.index); return XCAM_RETURN_ERROR_IOCTL; } return XCAM_RETURN_NO_ERROR; }
XCamReturn V4l2Device::stop () { // stream off if (_active) { if (io_control (VIDIOC_STREAMOFF, &_capture_buf_type) < 0) { XCAM_LOG_WARNING ("device(%s) steamoff failed", XCAM_STR (_name)); } _active = false; } fini_buffer_pool (); XCAM_LOG_INFO ("device(%s) stopped", XCAM_STR (_name)); return XCAM_RETURN_NO_ERROR; }
XCamReturn V4l2Device::start () { XCamReturn ret = XCAM_RETURN_NO_ERROR; // request buffer first ret = request_buffer (); XCAM_FAIL_RETURN ( ERROR, ret == XCAM_RETURN_NO_ERROR, ret, "device(%s) start failed", XCAM_STR (_name)); //alloc buffers ret = init_buffer_pool (); XCAM_FAIL_RETURN ( ERROR, ret == XCAM_RETURN_NO_ERROR, ret, "device(%s) start failed", XCAM_STR (_name)); //queue all buffers for (uint32_t i = 0; i < _buf_count; ++i) { SmartPtr<V4l2Buffer> &buf = _buf_pool [i]; XCAM_ASSERT (buf.ptr()); XCAM_ASSERT (buf->get_buf().index == i); ret = queue_buffer (buf); if (ret != XCAM_RETURN_NO_ERROR) { XCAM_LOG_ERROR ( "device(%s) start failed on queue index:%d", XCAM_STR (_name), i); stop (); return ret; } } // stream on if (io_control (VIDIOC_STREAMON, &_capture_buf_type) < 0) { XCAM_LOG_ERROR ( "device(%s) start failed on VIDIOC_STREAMON", XCAM_STR (_name)); stop (); return XCAM_RETURN_ERROR_IOCTL; } _active = true; XCAM_LOG_INFO ("device(%s) started successfully", XCAM_STR (_name)); return XCAM_RETURN_NO_ERROR; }
XCamReturn V4l2Device::allocate_buffer ( SmartPtr<V4l2Buffer> &buf, const struct v4l2_format &format, const uint32_t index) { struct v4l2_buffer v4l2_buf; xcam_mem_clear (v4l2_buf); v4l2_buf.index = index; v4l2_buf.type = _capture_buf_type; v4l2_buf.memory = _memory_type; switch (_memory_type) { case V4L2_MEMORY_DMABUF: { struct v4l2_exportbuffer expbuf; xcam_mem_clear (expbuf); expbuf.type = _capture_buf_type; expbuf.index = index; expbuf.flags = O_CLOEXEC; if (io_control (VIDIOC_EXPBUF, &expbuf) < 0) { XCAM_LOG_WARNING ("device(%s) get dma buf(%d) failed", XCAM_STR (_name), index); return XCAM_RETURN_ERROR_MEM; } v4l2_buf.m.fd = expbuf.fd; v4l2_buf.length = format.fmt.pix.sizeimage; } break; case V4L2_MEMORY_MMAP: { void *pointer; int map_flags = MAP_SHARED; #ifdef NEED_MAP_32BIT map_flags |= MAP_32BIT; #endif if (io_control (VIDIOC_QUERYBUF, &v4l2_buf) < 0) { XCAM_LOG_WARNING("device(%s) query MMAP buf(%d) failed", XCAM_STR(_name), index); return XCAM_RETURN_ERROR_MEM; } pointer = mmap (0, v4l2_buf.length, PROT_READ | PROT_WRITE, map_flags, _fd, v4l2_buf.m.offset); if (pointer == MAP_FAILED) { XCAM_LOG_WARNING("device(%s) mmap buf(%d) failed", XCAM_STR(_name), index); return XCAM_RETURN_ERROR_MEM; } v4l2_buf.m.userptr = (uintptr_t) pointer; } break; case V4L2_MEMORY_USERPTR: default: XCAM_ASSERT (false); XCAM_LOG_WARNING ( "device(%s) allocated buffer mem_type(%d) doesn't support", XCAM_STR (_name), _memory_type); return XCAM_RETURN_ERROR_MEM; } buf = new V4l2Buffer (v4l2_buf, _format); return XCAM_RETURN_NO_ERROR; }
XCamReturn V4l2Device::set_format (struct v4l2_format &format) { XCamReturn ret = XCAM_RETURN_NO_ERROR; XCAM_FAIL_RETURN (ERROR, !is_activated (), XCAM_RETURN_ERROR_PARAM, "Cannot set format to v4l2 device while it is active."); XCAM_FAIL_RETURN (ERROR, is_opened (), XCAM_RETURN_ERROR_FILE, "Cannot set format to v4l2 device while it is closed."); struct v4l2_format tmp_format = format; ret = pre_set_format (format); if (ret != XCAM_RETURN_NO_ERROR) { XCAM_LOG_WARNING ("device(%s) pre_set_format failed", XCAM_STR (_name)); return ret; } if (io_control (VIDIOC_S_FMT, &format) < 0) { if (errno == EBUSY) { // TODO log device name XCAM_LOG_ERROR("Video device is busy, fail to set format."); } else { // TODO log format details and errno XCAM_LOG_ERROR("Fail to set format: %s", strerror(errno)); } return XCAM_RETURN_ERROR_IOCTL; } if (tmp_format.fmt.pix.width != format.fmt.pix.width || tmp_format.fmt.pix.height != format.fmt.pix.height) { XCAM_LOG_ERROR ( "device(%s) set v4l2 format failed, supported format: width:%d, height:%d", XCAM_STR (_name), format.fmt.pix.width, format.fmt.pix.height); return XCAM_RETURN_ERROR_PARAM; } while (_fps_n && _fps_d) { struct v4l2_streamparm param; xcam_mem_clear (param); param.type = _capture_buf_type; if (io_control (VIDIOC_G_PARM, ¶m) < 0) { XCAM_LOG_WARNING ("device(%s) set framerate failed on VIDIOC_G_PARM but continue", XCAM_STR (_name)); break; } if (!(param.parm.capture.capability & V4L2_CAP_TIMEPERFRAME)) break; param.parm.capture.timeperframe.numerator = _fps_d; param.parm.capture.timeperframe.denominator = _fps_n; if (io_control (VIDIOC_S_PARM, ¶m) < 0) { XCAM_LOG_WARNING ("device(%s) set framerate failed on VIDIOC_S_PARM but continue", XCAM_STR (_name)); break; } _fps_n = param.parm.capture.timeperframe.denominator; _fps_d = param.parm.capture.timeperframe.numerator; XCAM_LOG_INFO ("device(%s) set framerate(%d/%d)", XCAM_STR (_name), _fps_n, _fps_d); // exit here, otherwise it is an infinite loop break; } ret = post_set_format (format); if (ret != XCAM_RETURN_NO_ERROR) { XCAM_LOG_WARNING ("device(%s) post_set_format failed", XCAM_STR (_name)); return ret; } _format = format; XCAM_LOG_INFO ( "device(%s) set format(w:%d, h:%d, pixelformat:%s, bytesperline:%d,image_size:%d)", XCAM_STR (_name), format.fmt.pix.width, format.fmt.pix.height, xcam_fourcc_to_string (format.fmt.pix.pixelformat), format.fmt.pix.bytesperline, format.fmt.pix.sizeimage); return XCAM_RETURN_NO_ERROR; }
template <class Const_Buffers> std::size_t write_some(Const_Buffers const& buffers, error_code& ec) { TORRENT_SOCKTYPE_FORWARD_RET(write_some(buffers, ec), 0) } template <class Const_Buffers, class Handler> void async_write_some(Const_Buffers const& buffers, Handler const& handler) { TORRENT_SOCKTYPE_FORWARD(async_write_some(buffers, handler)) } template <class Handler> void async_connect(endpoint_type const& endpoint, Handler const& handler) { TORRENT_SOCKTYPE_FORWARD(async_connect(endpoint, handler)) } #ifndef BOOST_NO_EXCEPTIONS template <class IO_Control_Command> void io_control(IO_Control_Command& ioc) { TORRENT_SOCKTYPE_FORWARD(io_control(ioc)) } template <class Mutable_Buffers> std::size_t read_some(Mutable_Buffers const& buffers) { TORRENT_SOCKTYPE_FORWARD_RET(read_some(buffers), 0) } #endif template <class IO_Control_Command> void io_control(IO_Control_Command& ioc, error_code& ec) { TORRENT_SOCKTYPE_FORWARD(io_control(ioc, ec)) } #ifndef BOOST_NO_EXCEPTIONS template <class SettableSocketOption> void set_option(SettableSocketOption const& opt) { TORRENT_SOCKTYPE_FORWARD(set_option(opt)) } #endif