| /* |
| * v4l2_device.cpp - v4l2 device |
| * |
| * Copyright (c) 2014-2015 Intel Corporation |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| * Author: Wind Yuan <[email protected]> |
| * Author: John Ye <[email protected]> |
| */ |
| |
| #include "v4l2_device.h" |
| #include <sys/ioctl.h> |
| #include <stdlib.h> |
| #include <unistd.h> |
| #include <fcntl.h> |
| #include <poll.h> |
| #include <errno.h> |
| #include <sys/mman.h> |
| |
| #include "v4l2_buffer_proxy.h" |
| |
| namespace XCam { |
| |
| #define XCAM_V4L2_DEFAULT_BUFFER_COUNT 6 |
| |
| V4l2Device::V4l2Device (const char *name) |
| : _name (NULL) |
| , _fd (-1) |
| , _sensor_id (0) |
| , _capture_mode (0) |
| , _capture_buf_type (V4L2_BUF_TYPE_VIDEO_CAPTURE) |
| , _memory_type (V4L2_MEMORY_MMAP) |
| , _fps_n (0) |
| , _fps_d (0) |
| , _active (false) |
| , _buf_count (XCAM_V4L2_DEFAULT_BUFFER_COUNT) |
| { |
| if (name) |
| _name = strndup (name, XCAM_MAX_STR_SIZE); |
| xcam_mem_clear (_format); |
| } |
| |
| V4l2Device::~V4l2Device () |
| { |
| close(); |
| if (_name) |
| xcam_free (_name); |
| } |
| |
| bool |
| V4l2Device::set_device_name (const char *name) |
| { |
| XCAM_ASSERT (name); |
| |
| if (is_opened()) { |
| XCAM_LOG_WARNING ("can't set device name since device opened"); |
| return false; |
| } |
| if (_name) |
| xcam_free (_name); |
| _name = strndup (name, XCAM_MAX_STR_SIZE); |
| return true; |
| } |
| |
| bool |
| V4l2Device::set_sensor_id (int id) |
| { |
| if (is_opened()) { |
| XCAM_LOG_WARNING ("can't set sensor id since device opened"); |
| return false; |
| } |
| _sensor_id = id; |
| return true; |
| } |
| |
| bool |
| V4l2Device::set_capture_mode (uint32_t capture_mode) |
| { |
| if (is_opened()) { |
| XCAM_LOG_WARNING ("can't set sensor id since device opened"); |
| return false; |
| } |
| _capture_mode = capture_mode; |
| return true; |
| } |
| |
| bool |
| V4l2Device::set_framerate (uint32_t n, uint32_t d) |
| { |
| if (_format.fmt.pix.pixelformat) { |
| XCAM_LOG_WARNING ("device(%s) set framerate failed since formatted was already set.", XCAM_STR(_name)); |
| return false; |
| } |
| |
| _fps_n = n; |
| _fps_d = d; |
| |
| return true; |
| } |
| |
| void |
| V4l2Device::get_framerate (uint32_t &n, uint32_t &d) |
| { |
| n = _fps_n; |
| d = _fps_d; |
| } |
| |
| bool |
| V4l2Device::set_mem_type (enum v4l2_memory type) { |
| if (is_activated ()) { |
| XCAM_LOG_WARNING ("device(%s) set mem type failed", XCAM_STR (_name)); |
| return false; |
| } |
| _memory_type = type; |
| return true; |
| } |
| |
| bool |
| V4l2Device::set_buffer_count (uint32_t buf_count) |
| { |
| if (is_activated ()) { |
| XCAM_LOG_WARNING ("device(%s) set buffer count failed", XCAM_STR (_name)); |
| return false; |
| } |
| _buf_count = buf_count; |
| return true; |
| } |
| |
| |
| 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::close () |
| { |
| if (!is_opened()) |
| return XCAM_RETURN_NO_ERROR; |
| ::close (_fd); |
| _fd = -1; |
| return XCAM_RETURN_NO_ERROR; |
| } |
| |
| int |
| V4l2Device::io_control (int cmd, void *arg) |
| |
| { |
| if (_fd <= 0) |
| return -1; |
| |
| return xcam_device_ioctl (_fd, cmd, arg); |
| } |
| |
| int |
| V4l2Device::poll_event (int timeout_msec) |
| { |
| struct pollfd poll_fd; |
| int ret = 0; |
| |
| XCAM_ASSERT (_fd > 0); |
| |
| xcam_mem_clear (poll_fd); |
| poll_fd.fd = _fd; |
| poll_fd.events = (POLLPRI | POLLIN | POLLERR | POLLNVAL | POLLHUP); |
| |
| ret = poll (&poll_fd, 1, timeout_msec); |
| if (ret > 0 && (poll_fd.revents & (POLLERR | POLLNVAL | POLLHUP))) { |
| XCAM_LOG_DEBUG ("v4l2 subdev(%s) polled error", XCAM_STR(_name)); |
| return -1; |
| } |
| return ret; |
| |
| } |
| |
| 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; |
| } |
| |
| /*! \brief v4l2 set format |
| * |
| * \param[in] width format width |
| * \param[in] height format height |
| * \param[in] pixelformat fourcc |
| * \param[in] field V4L2_FIELD_INTERLACED or V4L2_FIELD_NONE |
| */ |
| XCamReturn |
| V4l2Device::set_format ( |
| uint32_t width, uint32_t height, |
| uint32_t pixelformat, enum v4l2_field field, uint32_t bytes_perline) |
| { |
| |
| struct v4l2_format format; |
| xcam_mem_clear (format); |
| |
| format.type = _capture_buf_type; |
| format.fmt.pix.width = width; |
| format.fmt.pix.height = height; |
| format.fmt.pix.pixelformat = pixelformat; |
| format.fmt.pix.field = field; |
| |
| if (bytes_perline != 0) |
| format.fmt.pix.bytesperline = bytes_perline; |
| return set_format (format); |
| } |
| |
| XCamReturn |
| V4l2Device::pre_set_format (struct v4l2_format &format) |
| { |
| XCAM_UNUSED (format); |
| return XCAM_RETURN_NO_ERROR; |
| } |
| |
| XCamReturn |
| V4l2Device::post_set_format (struct v4l2_format &format) |
| { |
| XCAM_UNUSED (format); |
| return XCAM_RETURN_NO_ERROR; |
| } |
| |
| std::list<struct v4l2_fmtdesc> |
| V4l2Device::enum_formats () |
| { |
| std::list<struct v4l2_fmtdesc> formats; |
| struct v4l2_fmtdesc format; |
| uint32_t i = 0; |
| |
| while (1) { |
| xcam_mem_clear (format); |
| format.index = i++; |
| format.type = _capture_buf_type; |
| if (this->io_control (VIDIOC_ENUM_FMT, &format) < 0) { |
| if (errno == EINVAL) |
| break; |
| else { // error |
| XCAM_LOG_DEBUG ("enum formats failed"); |
| return formats; |
| } |
| } |
| formats.push_back (format); |
| } |
| |
| return formats; |
| } |
| |
| XCamReturn |
| V4l2Device::get_format (struct v4l2_format &format) |
| { |
| if (is_activated ()) { |
| format = _format; |
| return XCAM_RETURN_NO_ERROR; |
| } |
| |
| if (!is_opened ()) |
| return XCAM_RETURN_ERROR_IOCTL; |
| |
| xcam_mem_clear (format); |
| format.type = _capture_buf_type; |
| |
| if (this->io_control (VIDIOC_G_FMT, &format) < 0) { |
| // FIXME: also log the device name? |
| XCAM_LOG_ERROR("Fail to get format via ioctl VIDVIO_G_FMT."); |
| return XCAM_RETURN_ERROR_IOCTL; |
| } |
| |
| 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::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::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::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::init_buffer_pool () |
| { |
| XCamReturn ret = XCAM_RETURN_NO_ERROR; |
| uint32_t i = 0; |
| |
| _buf_pool.clear (); |
| _buf_pool.reserve (_buf_count); |
| |
| for (; i < _buf_count; i++) { |
| SmartPtr<V4l2Buffer> new_buf; |
| ret = allocate_buffer (new_buf, _format, i); |
| if (ret != XCAM_RETURN_NO_ERROR) { |
| break; |
| } |
| _buf_pool.push_back (new_buf); |
| } |
| |
| if (_buf_pool.empty()) { |
| XCAM_LOG_ERROR ("No bufer allocated in device(%s)", XCAM_STR (_name)); |
| return XCAM_RETURN_ERROR_MEM; |
| } |
| |
| if (i != _buf_count) { |
| XCAM_LOG_WARNING ( |
| "device(%s) allocate buffer count:%d failback to %d", |
| XCAM_STR (_name), _buf_count, i); |
| _buf_count = i; |
| } |
| |
| return XCAM_RETURN_NO_ERROR; |
| } |
| |
| XCamReturn |
| V4l2Device::fini_buffer_pool() |
| { |
| _buf_pool.clear (); |
| return XCAM_RETURN_NO_ERROR; |
| } |
| |
| XCamReturn |
| V4l2Device::dequeue_buffer(SmartPtr<V4l2Buffer> &buf) |
| { |
| struct v4l2_buffer v4l2_buf; |
| |
| if (!is_activated()) { |
| XCAM_LOG_DEBUG ( |
| "device(%s) dequeue buffer failed since not activated", XCAM_STR (_name)); |
| return XCAM_RETURN_ERROR_PARAM; |
| } |
| |
| xcam_mem_clear (v4l2_buf); |
| v4l2_buf.type = _capture_buf_type; |
| v4l2_buf.memory = _memory_type; |
| |
| if (this->io_control (VIDIOC_DQBUF, &v4l2_buf) < 0) { |
| XCAM_LOG_ERROR ("device(%s) fail to dequeue buffer.", XCAM_STR (_name)); |
| return XCAM_RETURN_ERROR_IOCTL; |
| } |
| |
| XCAM_LOG_DEBUG ("device(%s) dequeue buffer index:%d", XCAM_STR (_name), v4l2_buf.index); |
| |
| if (v4l2_buf.index > _buf_count) { |
| XCAM_LOG_ERROR ( |
| "device(%s) dequeue wrong buffer index:%d", |
| XCAM_STR (_name), v4l2_buf.index); |
| return XCAM_RETURN_ERROR_ISP; |
| } |
| buf = _buf_pool [v4l2_buf.index]; |
| buf->set_timestamp (v4l2_buf.timestamp); |
| buf->set_timecode (v4l2_buf.timecode); |
| buf->set_sequence (v4l2_buf.sequence); |
| //buf.set_length (v4l2_buf.length); // not necessary to set length |
| 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; |
| } |
| |
| V4l2SubDevice::V4l2SubDevice (const char *name) |
| : V4l2Device (name) |
| { |
| } |
| |
| XCamReturn |
| V4l2SubDevice::subscribe_event (int event) |
| { |
| struct v4l2_event_subscription sub; |
| int ret = 0; |
| |
| XCAM_ASSERT (is_opened()); |
| |
| xcam_mem_clear (sub); |
| sub.type = event; |
| |
| ret = this->io_control (VIDIOC_SUBSCRIBE_EVENT, &sub); |
| if (ret < 0) { |
| XCAM_LOG_DEBUG ("subdev(%s) subscribe event(%d) failed", XCAM_STR(_name), event); |
| return XCAM_RETURN_ERROR_IOCTL; |
| } |
| return XCAM_RETURN_NO_ERROR; |
| } |
| |
| XCamReturn |
| V4l2SubDevice::unsubscribe_event (int event) |
| { |
| struct v4l2_event_subscription sub; |
| int ret = 0; |
| |
| XCAM_ASSERT (is_opened()); |
| |
| xcam_mem_clear (sub); |
| sub.type = event; |
| |
| ret = this->io_control (VIDIOC_UNSUBSCRIBE_EVENT, &sub); |
| if (ret < 0) { |
| XCAM_LOG_DEBUG ("subdev(%s) unsubscribe event(%d) failed", XCAM_STR(_name), event); |
| return XCAM_RETURN_ERROR_IOCTL; |
| } |
| return XCAM_RETURN_NO_ERROR; |
| } |
| |
| XCamReturn |
| V4l2SubDevice::dequeue_event (struct v4l2_event &event) |
| { |
| int ret = 0; |
| XCAM_ASSERT (is_opened()); |
| |
| ret = this->io_control (VIDIOC_DQEVENT, &event); |
| if (ret < 0) { |
| XCAM_LOG_DEBUG ("subdev(%s) dequeue event failed", XCAM_STR(_name)); |
| return XCAM_RETURN_ERROR_IOCTL; |
| } |
| |
| return XCAM_RETURN_NO_ERROR; |
| } |
| |
| XCamReturn V4l2SubDevice::start () |
| { |
| if (!is_opened()) |
| return XCAM_RETURN_ERROR_PARAM; |
| |
| _active = true; |
| return XCAM_RETURN_NO_ERROR; |
| } |
| |
| XCamReturn V4l2SubDevice::stop () |
| { |
| if (_active) |
| _active = false; |
| |
| return XCAM_RETURN_NO_ERROR; |
| } |
| |
| }; |