/* 
 | 
 * 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 <feng.yuan@intel.com> 
 | 
 * Author: John Ye <john.ye@intel.com> 
 | 
 */ 
 | 
  
 | 
#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  4 
 | 
  
 | 
V4l2Device::V4l2Device (const char *name) 
 | 
    : _name (NULL) 
 | 
    , _fd (-1) 
 | 
    , _sensor_id (0) 
 | 
    , _capture_mode (0) 
 | 
    , _buf_type (V4L2_BUF_TYPE_VIDEO_CAPTURE) 
 | 
    , _buf_sync (false) 
 | 
    , _memory_type (V4L2_MEMORY_MMAP) 
 | 
    , _planes (NULL) 
 | 
    , _fps_n (0) 
 | 
    , _fps_d (0) 
 | 
    , _active (false) 
 | 
    , _buf_count (XCAM_V4L2_DEFAULT_BUFFER_COUNT) 
 | 
    , _queued_bufcnt(0) 
 | 
    ,_mplanes_count(FMT_NUM_PLANES) 
 | 
{ 
 | 
    if (name) 
 | 
        _name = strndup (name, XCAM_MAX_STR_SIZE); 
 | 
    xcam_mem_clear (_format); 
 | 
} 
 | 
  
 | 
V4l2Device::~V4l2Device () 
 | 
{ 
 | 
    close(); 
 | 
    if (_name) 
 | 
        xcam_free (_name); 
 | 
    if (_planes) 
 | 
        xcam_free (_planes); 
 | 
} 
 | 
  
 | 
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_mplanes_count (uint32_t planes_count) 
 | 
{ 
 | 
    if (is_activated ()) { 
 | 
        XCAM_LOG_WARNING ("device(%s) set mplanes count failed", XCAM_STR (_name)); 
 | 
        return false; 
 | 
    } 
 | 
    _mplanes_count = planes_count; 
 | 
    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_buf_type (enum v4l2_buf_type type) { 
 | 
    if (is_activated ()) { 
 | 
        XCAM_LOG_WARNING ("device(%s) set buf type failed", XCAM_STR (_name)); 
 | 
        return false; 
 | 
    } 
 | 
    _buf_type = type; 
 | 
    return true; 
 | 
} 
 | 
  
 | 
bool 
 | 
V4l2Device::set_buf_sync (bool sync) { 
 | 
    if (is_activated ()) { 
 | 
        XCAM_LOG_WARNING ("device(%s) set buf sync failed", XCAM_STR (_name)); 
 | 
        return false; 
 | 
    } 
 | 
    _buf_sync = sync; 
 | 
    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_ERROR ("open device(%s) failed", _name); 
 | 
        return XCAM_RETURN_ERROR_IOCTL; 
 | 
    } else { 
 | 
        XCAM_LOG_DEBUG ("open device(%s) successed, fd: %d", _name, _fd); 
 | 
    } 
 | 
#if 0 
 | 
    // 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 = _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); 
 | 
    } 
 | 
#endif 
 | 
    struct v4l2_capability cap; 
 | 
    // only video node cay query cap 
 | 
    if (_name && strstr(_name, "video")) { 
 | 
        query_cap(cap); 
 | 
        // get default foramt 
 | 
        get_format (_format); 
 | 
    } 
 | 
  
 | 
    return XCAM_RETURN_NO_ERROR; 
 | 
} 
 | 
  
 | 
XCamReturn 
 | 
V4l2Device::close () 
 | 
{ 
 | 
    if (!is_opened()) 
 | 
        return XCAM_RETURN_NO_ERROR; 
 | 
    ::close (_fd); 
 | 
    _fd = -1; 
 | 
  
 | 
    XCAM_LOG_INFO ("device(%s) closed", XCAM_STR (_name)); 
 | 
    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, int stop_fd) 
 | 
{ 
 | 
    int num_fds = stop_fd == -1 ? 1 : 2; 
 | 
    struct pollfd poll_fds[num_fds]; 
 | 
    int ret = 0; 
 | 
  
 | 
    XCAM_ASSERT (_fd > 0); 
 | 
  
 | 
    memset(poll_fds, 0, sizeof(poll_fds)); 
 | 
    poll_fds[0].fd = _fd; 
 | 
    poll_fds[0].events = (POLLPRI | POLLIN | POLLOUT | POLLERR | POLLNVAL | POLLHUP); 
 | 
  
 | 
    if (stop_fd != -1) { 
 | 
        poll_fds[1].fd = stop_fd; 
 | 
        poll_fds[1].events = POLLPRI | POLLIN | POLLOUT; 
 | 
        poll_fds[1].revents = 0; 
 | 
    } 
 | 
  
 | 
    ret = poll (poll_fds, num_fds, timeout_msec); 
 | 
    if (stop_fd != -1) { 
 | 
        if ((poll_fds[1].revents & POLLIN) || (poll_fds[1].revents & POLLPRI)) { 
 | 
            XCAM_LOG_DEBUG ("%s: Poll returning from flush", __FUNCTION__); 
 | 
            return POLL_STOP_RET; 
 | 
        } 
 | 
    } 
 | 
  
 | 
    if (ret > 0 && (poll_fds[0].revents & (POLLERR | POLLNVAL | POLLHUP))) { 
 | 
        XCAM_LOG_DEBUG ("v4l2 subdev(%s) polled error", XCAM_STR(_name)); 
 | 
        return -1; 
 | 
    } 
 | 
  
 | 
    return ret; 
 | 
  
 | 
} 
 | 
  
 | 
XCamReturn 
 | 
V4l2Device::query_cap (struct v4l2_capability &cap) 
 | 
{ 
 | 
    int ret = 0; 
 | 
  
 | 
    XCAM_FAIL_RETURN (ERROR, is_opened (), XCAM_RETURN_ERROR_FILE, 
 | 
                      "Cannot query cap from v4l2 device while it is closed."); 
 | 
  
 | 
    ret = io_control(VIDIOC_QUERYCAP, &cap); 
 | 
  
 | 
    if (ret < 0) { 
 | 
        XCAM_LOG_ERROR("VIDIOC_QUERYCAP returned: %d (%s)", ret, strerror(errno)); 
 | 
        return XCAM_RETURN_ERROR_UNKNOWN; 
 | 
    } 
 | 
  
 | 
    if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) 
 | 
        _buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 
 | 
    else if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE_MPLANE) 
 | 
        _buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; 
 | 
    else if (cap.capabilities & V4L2_CAP_VIDEO_OUTPUT) 
 | 
        _buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT; 
 | 
    else if (cap.capabilities & V4L2_CAP_VIDEO_OUTPUT_MPLANE) 
 | 
        _buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; 
 | 
    else if (cap.capabilities & V4L2_CAP_META_CAPTURE) 
 | 
        _buf_type = V4L2_BUF_TYPE_META_CAPTURE; 
 | 
    else if (cap.capabilities & V4L2_CAP_META_OUTPUT) 
 | 
        _buf_type = V4L2_BUF_TYPE_META_OUTPUT; 
 | 
    else { 
 | 
        XCAM_LOG_ERROR("@%s: unsupported buffer type.", __FUNCTION__); 
 | 
        return XCAM_RETURN_ERROR_UNKNOWN; 
 | 
    } 
 | 
  
 | 
    XCAM_LOG_INFO("------------------------------"); 
 | 
    XCAM_LOG_INFO("driver:       '%s'", cap.driver); 
 | 
    XCAM_LOG_INFO("card:         '%s'", cap.card); 
 | 
    XCAM_LOG_INFO("bus_info:     '%s'", cap.bus_info); 
 | 
    XCAM_LOG_INFO("version:      %x", cap.version); 
 | 
    XCAM_LOG_INFO("capabilities: %x", cap.capabilities); 
 | 
    XCAM_LOG_INFO("device caps:  %x", cap.device_caps); 
 | 
    XCAM_LOG_INFO("buffer type   %d", _buf_type); 
 | 
    XCAM_LOG_INFO("------------------------------"); 
 | 
  
 | 
    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)); 
 | 
        //RKTODO::rkisp no need to do set format op for subdev. 
 | 
        //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 = _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) 
 | 
{ 
 | 
    XCAM_LOG_INFO ( 
 | 
        "device(%s) set format(w:%d, h:%d, pixelformat:%s, bytesperline:%d)", 
 | 
        XCAM_STR (_name), 
 | 
        width, height, 
 | 
        xcam_fourcc_to_string (pixelformat), 
 | 
        bytes_perline); 
 | 
  
 | 
    struct v4l2_format format; 
 | 
    xcam_mem_clear (format); 
 | 
  
 | 
    format.type = _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 = _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 = _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::prepare () 
 | 
{ 
 | 
    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)); 
 | 
    _queued_bufcnt = 0; 
 | 
    //alloc buffers 
 | 
    ret = init_buffer_pool (); 
 | 
    XCAM_FAIL_RETURN ( 
 | 
        ERROR, ret == XCAM_RETURN_NO_ERROR, ret, 
 | 
        "device(%s) start failed", XCAM_STR (_name)); 
 | 
    if (!V4L2_TYPE_IS_OUTPUT(_buf_type) && 
 | 
            (_buf_type != V4L2_BUF_TYPE_META_OUTPUT)) { 
 | 
        //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; 
 | 
            } 
 | 
        } 
 | 
    } 
 | 
    return ret; 
 | 
} 
 | 
  
 | 
XCamReturn 
 | 
V4l2Device::get_crop (struct v4l2_crop &crop) 
 | 
{ 
 | 
    int ret = 0; 
 | 
    XCAM_ASSERT (is_opened()); 
 | 
    ret = this->io_control (VIDIOC_G_CROP, &crop); 
 | 
    if (ret < 0) { 
 | 
        XCAM_LOG_ERROR("subdev(%s) VIDIOC_G_CROP failed", XCAM_STR(_name)); 
 | 
        return XCAM_RETURN_ERROR_IOCTL; 
 | 
    } 
 | 
    return XCAM_RETURN_NO_ERROR; 
 | 
} 
 | 
  
 | 
XCamReturn 
 | 
V4l2Device::set_crop (struct v4l2_crop &crop) 
 | 
{ 
 | 
    int ret = 0; 
 | 
    XCAM_ASSERT (is_opened()); 
 | 
    ret = this->io_control (VIDIOC_S_CROP, &crop); 
 | 
    if (ret < 0) { 
 | 
        XCAM_LOG_ERROR("subdev(%s) VIDIOC_S_CROP failed", XCAM_STR(_name)); 
 | 
        return XCAM_RETURN_ERROR_IOCTL; 
 | 
    } 
 | 
    return XCAM_RETURN_NO_ERROR; 
 | 
} 
 | 
  
 | 
XCamReturn 
 | 
V4l2SubDevice::set_selection (struct v4l2_subdev_selection &aSelection) 
 | 
{ 
 | 
    int ret = 0; 
 | 
    XCAM_ASSERT (is_opened()); 
 | 
  
 | 
    XCAM_LOG_DEBUG ("VIDIOC_SUBDEV_S_SELECTION: which: %d, pad: %d, target: 0x%x, " 
 | 
         "flags: 0x%x, rect left: %d, rect top: %d, width: %d, height: %d", 
 | 
        aSelection.which, 
 | 
        aSelection.pad, 
 | 
        aSelection.target, 
 | 
        aSelection.flags, 
 | 
        aSelection.r.left, 
 | 
        aSelection.r.top, 
 | 
        aSelection.r.width, 
 | 
        aSelection.r.height); 
 | 
  
 | 
    ret = this->io_control (VIDIOC_SUBDEV_S_SELECTION, &aSelection); 
 | 
    if (ret < 0) { 
 | 
        XCAM_LOG_ERROR("subdev(%s) VIDIOC_SUBDEV_S_SELECTION failed", XCAM_STR(_name)); 
 | 
        return XCAM_RETURN_ERROR_IOCTL; 
 | 
    } 
 | 
  
 | 
    return XCAM_RETURN_NO_ERROR; 
 | 
} 
 | 
  
 | 
XCamReturn 
 | 
V4l2SubDevice::getFormat(struct v4l2_subdev_format &aFormat) 
 | 
{ 
 | 
    int ret = 0; 
 | 
    XCAM_ASSERT (is_opened()); 
 | 
  
 | 
    ret = this->io_control(VIDIOC_SUBDEV_G_FMT, &aFormat); 
 | 
    if (ret < 0) { 
 | 
        XCAM_LOG_ERROR("subdev(%s) VIDIOC_SUBDEV_G_FMT failed: %s", XCAM_STR(_name)); 
 | 
        return XCAM_RETURN_ERROR_IOCTL; 
 | 
    } 
 | 
  
 | 
    XCAM_LOG_DEBUG ("VIDIOC_SUBDEV_G_FMT: pad: %d, which: %d, width: %d, " 
 | 
         "height: %d, format: 0x%x, field: %d, color space: %d", 
 | 
         aFormat.pad, 
 | 
         aFormat.which, 
 | 
         aFormat.format.width, 
 | 
         aFormat.format.height, 
 | 
         aFormat.format.code, 
 | 
         aFormat.format.field, 
 | 
         aFormat.format.colorspace); 
 | 
  
 | 
    return XCAM_RETURN_NO_ERROR; 
 | 
} 
 | 
  
 | 
XCamReturn 
 | 
V4l2SubDevice::setFormat(struct v4l2_subdev_format &aFormat) 
 | 
{ 
 | 
    int ret = 0; 
 | 
    XCAM_ASSERT (is_opened()); 
 | 
  
 | 
    XCAM_LOG_DEBUG ("VIDIOC_SUBDEV_S_FMT: pad: %d, which: %d, width: %d, " 
 | 
         "height: %d, format: 0x%x, field: %d, color space: %d", 
 | 
         aFormat.pad, 
 | 
         aFormat.which, 
 | 
         aFormat.format.width, 
 | 
         aFormat.format.height, 
 | 
         aFormat.format.code, 
 | 
         aFormat.format.field, 
 | 
         aFormat.format.colorspace); 
 | 
  
 | 
    ret = this->io_control(VIDIOC_SUBDEV_S_FMT, &aFormat); 
 | 
    if (ret < 0) { 
 | 
        XCAM_LOG_ERROR("subdev(%s) VIDIOC_SUBDEV_S_FMT failed: %s", XCAM_STR(_name)); 
 | 
        return XCAM_RETURN_ERROR_IOCTL; 
 | 
    } 
 | 
  
 | 
    return XCAM_RETURN_NO_ERROR; 
 | 
} 
 | 
  
 | 
XCamReturn 
 | 
V4l2Device::start (bool prepared) 
 | 
{ 
 | 
    XCamReturn ret = XCAM_RETURN_NO_ERROR; 
 | 
    if (!prepared) { 
 | 
        // request buffer first 
 | 
        ret = request_buffer (); 
 | 
        XCAM_FAIL_RETURN ( 
 | 
            ERROR, ret == XCAM_RETURN_NO_ERROR, ret, 
 | 
            "device(%s) start failed", XCAM_STR (_name)); 
 | 
        _queued_bufcnt = 0; 
 | 
        //alloc buffers 
 | 
        ret = init_buffer_pool (); 
 | 
        XCAM_FAIL_RETURN ( 
 | 
            ERROR, ret == XCAM_RETURN_NO_ERROR, ret, 
 | 
            "device(%s) start failed", XCAM_STR (_name)); 
 | 
        if (!V4L2_TYPE_IS_OUTPUT(_buf_type) && 
 | 
                (_buf_type != V4L2_BUF_TYPE_META_OUTPUT)) { 
 | 
            //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, &_buf_type) < 0) { 
 | 
        XCAM_LOG_ERROR ( 
 | 
            "device(%s) start failed on VIDIOC_STREAMON, fd=%d", 
 | 
            XCAM_STR (_name), _fd); 
 | 
        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 () 
 | 
{ 
 | 
    SmartLock auto_lock(_buf_mutex); 
 | 
    XCAM_LOG_INFO ("device(%s) stop, already start: %d", XCAM_STR (_name), _active); 
 | 
  
 | 
    // stream off 
 | 
    if (_active) { 
 | 
        if (io_control (VIDIOC_STREAMOFF, &_buf_type) < 0) { 
 | 
            XCAM_LOG_WARNING ("device(%s) steamoff failed", XCAM_STR (_name)); 
 | 
        } 
 | 
        _active = false; 
 | 
        /* while (_queued_bufcnt > 0) { */ 
 | 
        /*     struct v4l2_buffer v4l2_buf; */ 
 | 
        /*     struct v4l2_plane planes[_mplanes_count]; */ 
 | 
  
 | 
        /*     xcam_mem_clear (v4l2_buf); */ 
 | 
        /*     v4l2_buf.type = _buf_type; */ 
 | 
        /*     v4l2_buf.memory = _memory_type; */ 
 | 
  
 | 
        /*     if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == _buf_type || */ 
 | 
        /*             V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE == _buf_type) { */ 
 | 
        /*         memset(planes, 0, sizeof(struct v4l2_plane) * _mplanes_count); */ 
 | 
        /*         v4l2_buf.m.planes = planes; */ 
 | 
        /*         v4l2_buf.length = _mplanes_count; */ 
 | 
        /*     } */ 
 | 
  
 | 
        /*     if (this->io_control (VIDIOC_DQBUF, &v4l2_buf) < 0) { */ 
 | 
        /*         XCAM_LOG_WARNING ("device(%s) fail to dequeue buffer.", XCAM_STR (_name)); */ 
 | 
        /*     } */ 
 | 
        /*     _queued_bufcnt--; */ 
 | 
        /* } */ 
 | 
        /* fini_buffer_pool (); */ 
 | 
        /* release the shared buf between mipi tx and rx */ 
 | 
        if (_memory_type == V4L2_MEMORY_DMABUF) { 
 | 
            struct v4l2_requestbuffers request_buf; 
 | 
            xcam_mem_clear (request_buf); 
 | 
            request_buf.type = _buf_type; 
 | 
            request_buf.count = 0; 
 | 
            request_buf.memory = _memory_type; 
 | 
            if (io_control (VIDIOC_REQBUFS, &request_buf) < 0) { 
 | 
                XCAM_LOG_ERROR ("device(%s) starts failed on VIDIOC_REQBUFS", XCAM_STR (_name)); 
 | 
                //return XCAM_RETURN_ERROR_IOCTL; 
 | 
            } 
 | 
        } 
 | 
    } 
 | 
  
 | 
    if (_buf_pool.size() > 0) 
 | 
        fini_buffer_pool (); 
 | 
    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 = _buf_type; 
 | 
    request_buf.count = _buf_count; 
 | 
    request_buf.memory = _memory_type; 
 | 
  
 | 
    XCAM_LOG_INFO ("request buffers in device(%s): type: %d, count: %d, mem_type: %d", 
 | 
                   XCAM_STR (_name), 
 | 
                   request_buf.type, 
 | 
                   request_buf.count, 
 | 
                   request_buf.memory); 
 | 
  
 | 
    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; 
 | 
    } 
 | 
  
 | 
    XCAM_LOG_INFO ("device(%s) request buffer count: %d", 
 | 
                   XCAM_STR (_name), request_buf.count); 
 | 
  
 | 
    if (request_buf.count != _buf_count) { 
 | 
        XCAM_LOG_INFO ( 
 | 
            "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; 
 | 
    } 
 | 
  
 | 
    if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == _buf_type || 
 | 
            V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE == _buf_type) 
 | 
        _planes = (struct v4l2_plane *)xcam_malloc0 
 | 
                  (_buf_count * _mplanes_count * sizeof(struct v4l2_plane)); 
 | 
  
 | 
    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; 
 | 
    int expbuf_fd = -1; 
 | 
    uintptr_t expbuf_ptr = 0; 
 | 
  
 | 
    xcam_mem_clear (v4l2_buf); 
 | 
    v4l2_buf.index = index; 
 | 
    v4l2_buf.type = _buf_type; 
 | 
    v4l2_buf.memory = _memory_type; 
 | 
    if (_buf_sync) { 
 | 
        v4l2_buf.flags = V4L2_BUF_FLAG_NO_CACHE_INVALIDATE | 
 | 
            V4L2_BUF_FLAG_NO_CACHE_CLEAN; 
 | 
    } 
 | 
  
 | 
    if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == _buf_type || 
 | 
            V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE == _buf_type) { 
 | 
        v4l2_buf.m.planes = &_planes[index * _mplanes_count]; 
 | 
        v4l2_buf.length = _mplanes_count; 
 | 
    } 
 | 
  
 | 
    switch (_memory_type) { 
 | 
    case V4L2_MEMORY_DMABUF: 
 | 
    { 
 | 
        v4l2_buf.length = format.fmt.pix.sizeimage; 
 | 
        if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == _buf_type || 
 | 
                V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE == _buf_type) { 
 | 
            v4l2_buf.length = _mplanes_count; 
 | 
            for (int i=0; i<_mplanes_count; i++) { 
 | 
                v4l2_buf.m.planes[i].length = format.fmt.pix.sizeimage; 
 | 
                v4l2_buf.m.planes[i].bytesused = format.fmt.pix.sizeimage; 
 | 
            } 
 | 
        } 
 | 
    } 
 | 
    break; 
 | 
    case V4L2_MEMORY_MMAP: 
 | 
    { 
 | 
        void *pointer = MAP_FAILED; 
 | 
        int map_flags = MAP_SHARED; 
 | 
#ifdef NEED_MAP_32BIT 
 | 
        map_flags |= MAP_32BIT; 
 | 
#endif 
 | 
        if (io_control (VIDIOC_QUERYBUF, &v4l2_buf) < 0) { 
 | 
            XCAM_LOG_ERROR("device(%s) query MMAP buf(%d) failed", XCAM_STR(_name), index); 
 | 
            return XCAM_RETURN_ERROR_MEM; 
 | 
        } 
 | 
  
 | 
        if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == _buf_type || 
 | 
                V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE == _buf_type) { 
 | 
            for (int i=0; i<_mplanes_count; i++) { 
 | 
                XCAM_LOG_DEBUG ("device(%s) get planar(%d) of buf(%d) length: %d", XCAM_STR (_name), i, index, v4l2_buf.m.planes[i].length); 
 | 
                pointer = mmap (0, v4l2_buf.m.planes[i].length, PROT_READ | PROT_WRITE, map_flags, _fd, v4l2_buf.m.planes[i].m.mem_offset); 
 | 
                v4l2_buf.m.planes[i].m.userptr = (uintptr_t) pointer; 
 | 
                if (pointer == MAP_FAILED) { 
 | 
                    XCAM_LOG_ERROR("device(%s) mmap planar(%d) of buf(%d) failed", XCAM_STR(_name), i, index); 
 | 
                    return XCAM_RETURN_ERROR_MEM; 
 | 
                } 
 | 
            } 
 | 
            expbuf_ptr = v4l2_buf.m.planes[0].m.userptr; 
 | 
        } else { 
 | 
            XCAM_LOG_DEBUG ("device(%s) get buf(%d) length: %d", XCAM_STR (_name), index, v4l2_buf.length); 
 | 
            pointer = mmap (0, v4l2_buf.length, PROT_READ | PROT_WRITE, map_flags, _fd, v4l2_buf.m.offset); 
 | 
            if (pointer == MAP_FAILED) { 
 | 
                XCAM_LOG_ERROR("device(%s) mmap buf(%d) failed", XCAM_STR(_name), index); 
 | 
                return XCAM_RETURN_ERROR_MEM; 
 | 
            } 
 | 
            expbuf_ptr = v4l2_buf.m.userptr = (uintptr_t) pointer; 
 | 
        } 
 | 
  
 | 
        // export buf dma fd 
 | 
        struct v4l2_exportbuffer expbuf; 
 | 
        xcam_mem_clear (expbuf); 
 | 
        expbuf.type = _buf_type; 
 | 
        expbuf.index = index; 
 | 
        expbuf.flags = O_CLOEXEC; 
 | 
        if (io_control (VIDIOC_EXPBUF, &expbuf) < 0) { 
 | 
            XCAM_LOG_ERROR ("device(%s) get dma buf(%d) failed", XCAM_STR (_name), index); 
 | 
            return XCAM_RETURN_ERROR_MEM; 
 | 
        } else { 
 | 
            XCAM_LOG_INFO ("device(%s) get dma buf(%d)-fd: %d", XCAM_STR (_name), index, expbuf.fd); 
 | 
        } 
 | 
        expbuf_fd = expbuf.fd; 
 | 
    } 
 | 
    break; 
 | 
    case V4L2_MEMORY_USERPTR: 
 | 
    { 
 | 
       v4l2_buf.length = format.fmt.pix.sizeimage; 
 | 
      if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == _buf_type || 
 | 
          V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE == _buf_type) { 
 | 
            v4l2_buf.length = _mplanes_count; 
 | 
            for (int i=0; i<_mplanes_count; i++) { 
 | 
                v4l2_buf.m.planes[i].length = format.fmt.pix.sizeimage; 
 | 
                v4l2_buf.m.planes[i].bytesused = format.fmt.pix.sizeimage; 
 | 
            } 
 | 
      } 
 | 
    } 
 | 
    break; 
 | 
    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); 
 | 
    if (expbuf_fd != -1) 
 | 
        buf->set_expbuf_fd (expbuf_fd); 
 | 
    if (expbuf_ptr != 0) 
 | 
        buf->set_expbuf_usrptr(expbuf_ptr); 
 | 
    return XCAM_RETURN_NO_ERROR; 
 | 
} 
 | 
  
 | 
XCamReturn 
 | 
V4l2Device::release_buffer (SmartPtr<V4l2Buffer> &buf) 
 | 
{ 
 | 
    int ret = 0; 
 | 
    switch (_memory_type) { 
 | 
    case V4L2_MEMORY_DMABUF: 
 | 
    { 
 | 
    } 
 | 
    break; 
 | 
    case V4L2_MEMORY_MMAP: 
 | 
    { 
 | 
        if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == _buf_type || 
 | 
                V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE == _buf_type) { 
 | 
            for (int i=0; i<_mplanes_count; i++) { 
 | 
                XCAM_LOG_DEBUG("release multi planar(%d) of buffer length: %d", i, buf->get_buf().m.planes[i].length); 
 | 
                ret = munmap((void*)buf->get_buf().m.planes[i].m.userptr, buf->get_buf().m.planes[i].length); 
 | 
            } 
 | 
            ::close(buf->get_expbuf_fd()); 
 | 
        } else { 
 | 
            XCAM_LOG_DEBUG("release buffer length: %d", buf->get_buf().length); 
 | 
            ret = munmap((void*)buf->get_buf().m.userptr, buf->get_buf().length); 
 | 
            ::close(buf->get_expbuf_fd()); 
 | 
        } 
 | 
        if (ret != 0) { 
 | 
            XCAM_LOG_ERROR ( 
 | 
                "release buffer: munmap failed"); 
 | 
        } 
 | 
    } 
 | 
    break; 
 | 
    case V4L2_MEMORY_USERPTR: 
 | 
    break; 
 | 
    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; 
 | 
    } 
 | 
    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; 
 | 
        XCAM_LOG_DEBUG("allocate_buffer index: %d", i); 
 | 
        ret = allocate_buffer (new_buf, _format, i); 
 | 
        if (ret != XCAM_RETURN_NO_ERROR) { 
 | 
            break; 
 | 
        } 
 | 
        _buf_pool.push_back (new_buf); 
 | 
    } 
 | 
  
 | 
    for (i = 0; i < _buf_count; i++) { 
 | 
        SmartPtr<V4l2Buffer> &buf = _buf_pool [i]; 
 | 
        struct v4l2_buffer v4l2_buf = buf->get_buf (); 
 | 
        XCAM_LOG_DEBUG ("init_buffer_pool device(%s) index:%d, memory:%d, type:%d, length:%d, fd:%d, ptr:%p", 
 | 
                        XCAM_STR (_name), v4l2_buf.index, v4l2_buf.memory, 
 | 
                        v4l2_buf.type, v4l2_buf.length, buf->get_expbuf_fd(), buf->get_expbuf_usrptr()); 
 | 
    } 
 | 
    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() 
 | 
{ 
 | 
    uint32_t i = 0; 
 | 
  
 | 
    for (; i < _buf_pool.size(); i++) { 
 | 
        release_buffer(_buf_pool [i]); 
 | 
    } 
 | 
  
 | 
    _buf_pool.clear (); 
 | 
    if (_planes) { 
 | 
        xcam_free (_planes); 
 | 
        _planes = NULL; 
 | 
    } 
 | 
  
 | 
    return XCAM_RETURN_NO_ERROR; 
 | 
} 
 | 
  
 | 
SmartPtr<V4l2Buffer> 
 | 
V4l2Device::get_buffer_by_index (int index) { 
 | 
    SmartLock auto_lock(_buf_mutex); 
 | 
    SmartPtr<V4l2Buffer> &buf = _buf_pool [index]; 
 | 
  
 | 
    return buf; 
 | 
} 
 | 
  
 | 
XCamReturn 
 | 
V4l2Device::dequeue_buffer(SmartPtr<V4l2Buffer> &buf) 
 | 
{ 
 | 
    struct v4l2_buffer v4l2_buf; 
 | 
    struct v4l2_plane planes[_mplanes_count]; 
 | 
  
 | 
    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 = _buf_type; 
 | 
    v4l2_buf.memory = _memory_type; 
 | 
  
 | 
    if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == _buf_type || 
 | 
            V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE == _buf_type) { 
 | 
        memset(planes, 0, sizeof(struct v4l2_plane) * _mplanes_count); 
 | 
        v4l2_buf.m.planes = planes; 
 | 
        v4l2_buf.length = _mplanes_count; 
 | 
    } 
 | 
  
 | 
    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; 
 | 
    } 
 | 
  
 | 
    if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == _buf_type || 
 | 
            V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE == _buf_type) { 
 | 
        XCAM_LOG_DEBUG ("device(%s) multi planar dequeue buffer index:%d, length: %dn", 
 | 
                        XCAM_STR (_name), v4l2_buf.index, 
 | 
                        v4l2_buf.m.planes[0].length); 
 | 
        if (V4L2_MEMORY_DMABUF == _memory_type) { 
 | 
            XCAM_LOG_DEBUG ("device(%s) multi planar index:%d, fd: %d", 
 | 
                            XCAM_STR (_name), v4l2_buf.index, v4l2_buf.m.planes[0].m.fd); 
 | 
        } 
 | 
    } else { 
 | 
        XCAM_LOG_DEBUG ("device(%s) dequeue buffer index:%d, length: %d", 
 | 
                        XCAM_STR (_name), v4l2_buf.index, v4l2_buf.length); 
 | 
    } 
 | 
  
 | 
    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; 
 | 
    } 
 | 
  
 | 
    SmartLock auto_lock(_buf_mutex); 
 | 
  
 | 
    buf = _buf_pool [v4l2_buf.index]; 
 | 
    buf->set_timestamp (v4l2_buf.timestamp); 
 | 
    buf->set_timecode (v4l2_buf.timecode); 
 | 
    buf->set_sequence (v4l2_buf.sequence); 
 | 
    if (!V4L2_TYPE_IS_OUTPUT(buf->get_buf ().type)) 
 | 
        buf->set_queued(false); 
 | 
    if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == _buf_type || 
 | 
            V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE == _buf_type) { 
 | 
        buf->set_length (v4l2_buf.m.planes[0].length); 
 | 
    } else { 
 | 
        buf->set_length (v4l2_buf.length); 
 | 
    } 
 | 
    _queued_bufcnt--; 
 | 
  
 | 
    return XCAM_RETURN_NO_ERROR; 
 | 
} 
 | 
  
 | 
XCamReturn 
 | 
V4l2Device::get_buffer (SmartPtr<V4l2Buffer> &buf, int index) const 
 | 
{ 
 | 
    SmartLock auto_lock(_buf_mutex); 
 | 
  
 | 
    if (_buf_pool.size() <= 0) 
 | 
        return XCAM_RETURN_ERROR_MEM; 
 | 
  
 | 
    if (index != -1 && !(_buf_pool[index]->get_queued())) { 
 | 
        buf = _buf_pool[index]; 
 | 
        return XCAM_RETURN_NO_ERROR; 
 | 
    } 
 | 
  
 | 
    uint32_t i; 
 | 
  
 | 
    for (i = 0; i < _buf_pool.size(); i++) { 
 | 
        if (!(_buf_pool[i]->get_queued())) { 
 | 
            buf = _buf_pool[i]; 
 | 
            break; 
 | 
        } 
 | 
    } 
 | 
  
 | 
    if (i == _buf_count) 
 | 
        return XCAM_RETURN_ERROR_MEM; 
 | 
    else 
 | 
        return XCAM_RETURN_NO_ERROR; 
 | 
} 
 | 
  
 | 
XCamReturn 
 | 
V4l2Device::return_buffer_to_pool (SmartPtr<V4l2Buffer> &buf) 
 | 
{ 
 | 
    SmartLock auto_lock(_buf_mutex); 
 | 
  
 | 
    XCAM_ASSERT (buf.ptr()); 
 | 
    buf->reset (); 
 | 
    return XCAM_RETURN_NO_ERROR; 
 | 
} 
 | 
  
 | 
XCamReturn 
 | 
V4l2Device::return_buffer (SmartPtr<V4l2Buffer> &buf) 
 | 
{ 
 | 
    SmartLock auto_lock(_buf_mutex); 
 | 
  
 | 
   if (V4L2_TYPE_IS_OUTPUT(buf->get_buf ().type) || 
 | 
            (buf->get_buf ().type == V4L2_BUF_TYPE_META_OUTPUT)) { 
 | 
        XCAM_ASSERT (buf.ptr()); 
 | 
        buf->reset (); 
 | 
        return XCAM_RETURN_NO_ERROR; 
 | 
   } else { 
 | 
        if (!_active) 
 | 
            buf->reset(); 
 | 
        else 
 | 
            return queue_buffer (buf, true); 
 | 
   } 
 | 
  
 | 
   return XCAM_RETURN_NO_ERROR; 
 | 
} 
 | 
  
 | 
XCamReturn 
 | 
V4l2Device::queue_buffer (SmartPtr<V4l2Buffer> &buf, bool locked) 
 | 
{ 
 | 
    if (!locked) 
 | 
        _buf_mutex.lock(); 
 | 
  
 | 
    XCAM_ASSERT (buf.ptr()); 
 | 
    buf->reset (); 
 | 
  
 | 
    struct v4l2_buffer v4l2_buf = buf->get_buf (); 
 | 
    struct v4l2_plane planes[_mplanes_count]; 
 | 
  
 | 
    XCAM_ASSERT (v4l2_buf.index < _buf_count); 
 | 
  
 | 
    if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == _buf_type || 
 | 
            V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE == _buf_type) { 
 | 
        XCAM_LOG_DEBUG ("device(%s) queue buffer index:%d, memory:%d, type:%d, multiply planar:%d, length:%d, fd:%d, ptr:%p", 
 | 
                        XCAM_STR (_name), v4l2_buf.index, v4l2_buf.memory, 
 | 
                        v4l2_buf.type, v4l2_buf.length, v4l2_buf.m.planes[0].length, buf->get_expbuf_fd(), buf->get_expbuf_usrptr()); 
 | 
        memset(planes, 0, sizeof(struct v4l2_plane) * _mplanes_count); 
 | 
        v4l2_buf.m.planes = planes; 
 | 
        planes[0] = buf->get_buf ().m.planes[0]; 
 | 
    } else { 
 | 
        XCAM_LOG_DEBUG ("device(%s) queue buffer index:%d, memory:%d, type:%d, length:%d, fd:%d", 
 | 
                        XCAM_STR (_name), v4l2_buf.index, v4l2_buf.memory, 
 | 
                        v4l2_buf.type, v4l2_buf.length, buf->get_expbuf_fd()); 
 | 
    } 
 | 
  
 | 
    if (v4l2_buf.type == V4L2_BUF_TYPE_META_OUTPUT) 
 | 
        v4l2_buf.bytesused = v4l2_buf.length; 
 | 
    if (v4l2_buf.type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { 
 | 
        v4l2_buf.m.planes[0].bytesused = v4l2_buf.m.planes[0].length; 
 | 
        if (V4L2_MEMORY_DMABUF == _memory_type) 
 | 
            v4l2_buf.m.planes[0].m.fd = buf->get_expbuf_fd(); 
 | 
        else if (V4L2_MEMORY_USERPTR == _memory_type) 
 | 
            v4l2_buf.m.planes[0].m.userptr = buf->get_expbuf_usrptr(); 
 | 
    } 
 | 
  
 | 
    _queued_bufcnt++; 
 | 
    buf->set_queued(true); 
 | 
    if (!locked) 
 | 
        _buf_mutex.unlock(); 
 | 
  
 | 
    if (io_control (VIDIOC_QBUF, &v4l2_buf) < 0) { 
 | 
        XCAM_LOG_ERROR("%s fail to enqueue buffer index:%d.", 
 | 
                       XCAM_STR(_name), v4l2_buf.index); 
 | 
        // restore buf status 
 | 
        { 
 | 
            if (!locked) 
 | 
                _buf_mutex.lock(); 
 | 
            /* SmartLock auto_lock(_buf_mutex); */ 
 | 
            buf->set_queued(false); 
 | 
            _queued_bufcnt--; 
 | 
            if (!locked) 
 | 
                _buf_mutex.unlock(); 
 | 
        } 
 | 
  
 | 
        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::get_selection (int pad, uint32_t target, struct v4l2_subdev_selection &select) 
 | 
{ 
 | 
    int ret = 0; 
 | 
    XCAM_ASSERT (is_opened()); 
 | 
  
 | 
    select.pad = pad; 
 | 
    select.which = V4L2_SUBDEV_FORMAT_ACTIVE; 
 | 
    select.target = target; 
 | 
  
 | 
    ret = this->io_control (VIDIOC_SUBDEV_G_SELECTION, &select); 
 | 
    if (ret < 0) { 
 | 
        XCAM_LOG_DEBUG ("subdev(%s) get selection failed", XCAM_STR(_name)); 
 | 
        return XCAM_RETURN_ERROR_IOCTL; 
 | 
    } 
 | 
  
 | 
    return XCAM_RETURN_NO_ERROR; 
 | 
} 
 | 
  
 | 
XCamReturn V4l2SubDevice::start (bool prepared) 
 | 
{ 
 | 
    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; 
 | 
} 
 | 
  
 | 
}; 
 |