416 lines
12 KiB
C++
416 lines
12 KiB
C++
/*
|
||
* Copyright (C) 2013-2017 Intel Corporation
|
||
* Copyright (c) 2017, Fuzhou Rockchip Electronics Co., Ltd
|
||
*
|
||
* 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.
|
||
*/
|
||
|
||
#define LOG_TAG "V4L2Subdev"
|
||
#include "LogHelper.h"
|
||
#include "v4l2device.h"
|
||
#include "UtilityMacros.h"
|
||
|
||
////////////////////////////////////////////////////////////////////
|
||
// PUBLIC METHODS
|
||
////////////////////////////////////////////////////////////////////
|
||
|
||
NAMESPACE_DECLARATION {
|
||
|
||
V4L2Subdevice::V4L2Subdevice(const char *name):
|
||
V4L2DeviceBase(name),
|
||
mState(DEVICE_CLOSED)
|
||
{
|
||
LOGI("@%s: %s", __FUNCTION__, name);
|
||
CLEAR(mConfig);
|
||
}
|
||
|
||
V4L2Subdevice::~V4L2Subdevice()
|
||
{
|
||
LOGI("@%s", __FUNCTION__);
|
||
|
||
}
|
||
|
||
status_t V4L2Subdevice::open()
|
||
{
|
||
LOGI("@%s", __FUNCTION__);
|
||
status_t status = NO_ERROR;
|
||
|
||
status = V4L2DeviceBase::open();
|
||
if (status == NO_ERROR)
|
||
mState = DEVICE_OPEN;
|
||
codeIndex.clear();
|
||
return status;
|
||
}
|
||
|
||
status_t V4L2Subdevice::close()
|
||
{
|
||
LOGI("@%s", __FUNCTION__);
|
||
status_t status = NO_ERROR;
|
||
|
||
status = V4L2DeviceBase::close();
|
||
if (status == NO_ERROR)
|
||
mState = DEVICE_CLOSED;
|
||
|
||
return status;
|
||
}
|
||
|
||
status_t V4L2Subdevice::setFormat(int pad, int width, int height, int formatCode,
|
||
int field, int quantization)
|
||
{
|
||
LOGI("@%s device = %s", __FUNCTION__, mName.c_str());
|
||
struct v4l2_subdev_format format;
|
||
|
||
CLEAR(format);
|
||
format.pad = pad;
|
||
format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
|
||
format.format.code = formatCode;
|
||
format.format.width = width;
|
||
format.format.height = height;
|
||
format.format.field = field;
|
||
format.format.quantization = quantization;
|
||
return setFormat(format);
|
||
}
|
||
|
||
/**
|
||
* Update the current subdevice configuration
|
||
*
|
||
* This called is allowed in the following states:
|
||
* - OPEN
|
||
* - CONFIGURED
|
||
*
|
||
* \param aFormat:[IN] reference to the new v4l2_subdev_format
|
||
*
|
||
* \return NO_ERROR if everything went well
|
||
* INVALID_OPERATION if device is not in correct state (open)
|
||
* UNKNOW_ERROR if we get an error from the v4l2 ioctl
|
||
*/
|
||
status_t V4L2Subdevice::setFormat(struct v4l2_subdev_format &aFormat)
|
||
{
|
||
int ret = 0;
|
||
|
||
if ((mState != DEVICE_OPEN) &&
|
||
(mState != DEVICE_CONFIGURED)){
|
||
LOGE("%s invalid device state %d",__FUNCTION__, mState);
|
||
return INVALID_OPERATION;
|
||
}
|
||
|
||
LOGI("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 = pbxioctl(VIDIOC_SUBDEV_S_FMT, &aFormat);
|
||
if (ret < 0) {
|
||
LOGE("VIDIOC_SUBDEV_S_FMT failed: %s", strerror(errno));
|
||
return UNKNOWN_ERROR;
|
||
}
|
||
|
||
// TODO: Update current pad configuration with the new one
|
||
|
||
mState = DEVICE_CONFIGURED;
|
||
return NO_ERROR;
|
||
}
|
||
|
||
status_t V4L2Subdevice::getFormat(struct v4l2_subdev_format &aFormat)
|
||
{
|
||
LOGI("@%s device = %s", __FUNCTION__, mName.c_str());
|
||
int ret = 0;
|
||
|
||
if ((mState != DEVICE_OPEN) &&
|
||
(mState != DEVICE_CONFIGURED)){
|
||
LOGE("%s invalid device state %d",__FUNCTION__, mState);
|
||
return INVALID_OPERATION;
|
||
}
|
||
|
||
ret = pbxioctl(VIDIOC_SUBDEV_G_FMT, &aFormat);
|
||
if (ret < 0) {
|
||
LOGE("VIDIOC_SUBDEV_G_FMT failed: %s", strerror(errno));
|
||
return UNKNOWN_ERROR;
|
||
}
|
||
|
||
LOGI("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 NO_ERROR;
|
||
}
|
||
|
||
status_t V4L2Subdevice::getPadFormat(int padIndex, int &width, int &height, int &code)
|
||
{
|
||
LOGI("@%s pad: %d", __FUNCTION__, padIndex);
|
||
status_t status = NO_ERROR;
|
||
struct v4l2_subdev_format format;
|
||
|
||
CLEAR(format);
|
||
format.pad = padIndex;
|
||
format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
|
||
status = getFormat(format);
|
||
if (status == NO_ERROR) {
|
||
width = format.format.width;
|
||
height = format.format.height;
|
||
code = format.format.code;
|
||
}
|
||
return status;
|
||
}
|
||
|
||
status_t V4L2Subdevice::setSelection(int pad, int target, int top, int left, int width, int height)
|
||
{
|
||
LOGI("@%s device = %s", __FUNCTION__, mName.c_str());
|
||
struct v4l2_subdev_selection selection;
|
||
|
||
CLEAR(selection);
|
||
selection.pad = pad;
|
||
selection.which = V4L2_SUBDEV_FORMAT_ACTIVE;
|
||
selection.target = target;
|
||
selection.flags = 0;
|
||
selection.r.top = top;
|
||
selection.r.left = left;
|
||
selection.r.width = width;
|
||
selection.r.height = height;
|
||
|
||
return setSelection(selection);
|
||
}
|
||
|
||
status_t V4L2Subdevice::getSelection(struct v4l2_subdev_selection &aSelection)
|
||
{
|
||
LOGI("@%s device = %s", __FUNCTION__, mName.c_str());
|
||
int ret = 0;
|
||
|
||
if ((mState != DEVICE_OPEN) &&
|
||
(mState != DEVICE_CONFIGURED)){
|
||
LOGE("%s invalid device state %d",__FUNCTION__, mState);
|
||
return INVALID_OPERATION;
|
||
}
|
||
struct v4l2_subdev_selection sel;
|
||
memset(&sel, 0, sizeof(sel));
|
||
sel.pad = 0;
|
||
sel.which = V4L2_SUBDEV_FORMAT_ACTIVE;
|
||
sel.target = V4L2_SEL_TGT_CROP_BOUNDS;
|
||
|
||
ret = pbxioctl(VIDIOC_SUBDEV_G_SELECTION, &sel);
|
||
if (ret < 0) {
|
||
LOGE("VIDIOC_SUBDEV_G_SELECTION failed: %s", strerror(errno));
|
||
return UNKNOWN_ERROR;
|
||
}
|
||
|
||
aSelection = sel;
|
||
|
||
LOGI("@%s: pad%d: crop.bounds:(%d,%d)/%dx%d",
|
||
__FUNCTION__,
|
||
aSelection.pad,
|
||
aSelection.r.left,
|
||
aSelection.r.top,
|
||
aSelection.r.width,
|
||
aSelection.r.height);
|
||
|
||
return NO_ERROR;
|
||
}
|
||
|
||
status_t V4L2Subdevice::setSelection(struct v4l2_subdev_selection &aSelection)
|
||
{
|
||
LOGI("@%s device = %s", __FUNCTION__, mName.c_str());
|
||
int ret = 0;
|
||
|
||
if ((mState != DEVICE_OPEN) &&
|
||
(mState != DEVICE_CONFIGURED)){
|
||
LOGE("%s invalid device state %d",__FUNCTION__, mState);
|
||
return INVALID_OPERATION;
|
||
}
|
||
|
||
LOGI("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 = pbxioctl(VIDIOC_SUBDEV_S_SELECTION, &aSelection);
|
||
if (ret < 0) {
|
||
LOGE("VIDIOC_SUBDEV_S_SELECTION failed: %s", strerror(errno));
|
||
return UNKNOWN_ERROR;
|
||
}
|
||
|
||
// TODO: Update current pad configuration with the new one
|
||
|
||
return NO_ERROR;
|
||
}
|
||
|
||
status_t V4L2Subdevice::queryFormats(int pad, std::vector<uint32_t> &formats)
|
||
{
|
||
LOGI("@%s device = %s, pad: %d", __FUNCTION__, mName.c_str(), pad);
|
||
struct v4l2_subdev_mbus_code_enum aFormat;
|
||
|
||
if (mState == DEVICE_CLOSED) {
|
||
LOGE("%s invalid device state %d",__FUNCTION__, mState);
|
||
return INVALID_OPERATION;
|
||
}
|
||
|
||
formats.clear();
|
||
CLEAR(aFormat);
|
||
|
||
aFormat.pad = pad;
|
||
aFormat.index = 0;
|
||
|
||
while (pbxioctl(VIDIOC_SUBDEV_ENUM_MBUS_CODE, &aFormat) == 0) {
|
||
/*
|
||
* Since we are iterating through the index
|
||
* check if this code is already in format to avoid add
|
||
* the code twice
|
||
*/
|
||
if (std::find(formats.begin(), formats.end(), aFormat.code) != formats.end()) {
|
||
aFormat.index++;
|
||
continue;
|
||
}
|
||
formats.push_back(aFormat.code);
|
||
codeIndex[aFormat.code] = aFormat.index;
|
||
aFormat.index++;
|
||
};
|
||
|
||
LOGI("@%s device: %s, %zu formats retrieved", __FUNCTION__, mName.c_str(), formats.size());
|
||
return NO_ERROR;
|
||
}
|
||
|
||
status_t V4L2Subdevice::setFrameInterval(struct v4l2_subdev_frame_interval &finterval)
|
||
{
|
||
LOGI("@%s device = %s", __FUNCTION__, mName.c_str());
|
||
int ret = 0;
|
||
|
||
if (mState == DEVICE_CLOSED) {
|
||
LOGE("%s invalid device state %d",__FUNCTION__, mState);
|
||
return INVALID_OPERATION;
|
||
}
|
||
|
||
LOGI("VIDIOC_SUBDEV_S_FRAME_INTERVAL: pad: %d, numerator %d, denominator %d",
|
||
finterval.pad,
|
||
finterval.interval.numerator,
|
||
finterval.interval.denominator);
|
||
ret = pbxioctl(VIDIOC_SUBDEV_S_FRAME_INTERVAL, &finterval);
|
||
if (ret < 0) {
|
||
LOGW("VIDIOC_SUBDEV_S_FRAME_INTERVAL failed: %s", strerror(errno));
|
||
return UNKNOWN_ERROR;
|
||
}
|
||
|
||
return NO_ERROR;
|
||
}
|
||
|
||
status_t V4L2Subdevice::setFramerate(int pad, int fps)
|
||
{
|
||
struct v4l2_subdev_frame_interval finterval;
|
||
|
||
LOGI("@%s device = %s", __FUNCTION__, mName.c_str());
|
||
|
||
CLEAR(finterval);
|
||
finterval.pad = 0;
|
||
finterval.interval.numerator = 10000;
|
||
finterval.interval.denominator = fps * 10000;
|
||
|
||
return setFrameInterval(finterval);
|
||
}
|
||
|
||
status_t V4L2Subdevice::getSensorFrameDuration(int32_t &duration)
|
||
{
|
||
LOGI("@%s device = %s", __FUNCTION__, mName.c_str());
|
||
int ret = 0;
|
||
|
||
struct v4l2_subdev_frame_interval finterval;
|
||
CLEAR(finterval);
|
||
|
||
if (mState == DEVICE_CLOSED) {
|
||
LOGE("%s invalid device state %d",__FUNCTION__, mState);
|
||
return INVALID_OPERATION;
|
||
}
|
||
|
||
ret = pbxioctl(VIDIOC_SUBDEV_G_FRAME_INTERVAL, &finterval);
|
||
if (ret < 0) {
|
||
LOGW("VIDIOC_SUBDEV_G_FRAME_INTERVAL failed: %s", strerror(errno));
|
||
return UNKNOWN_ERROR;
|
||
}
|
||
duration = 1000 * finterval.interval.numerator / finterval.interval.denominator;
|
||
LOGI("VIDIOC_SUBDEV_G_FRAME_INTERVAL: numerator %d, denominator %d,duration %dms",
|
||
finterval.interval.numerator,
|
||
finterval.interval.denominator,
|
||
duration);
|
||
|
||
return NO_ERROR;
|
||
}
|
||
|
||
status_t V4L2Subdevice::getSensorFormats(int pad, uint32_t code, std::vector<struct v4l2_subdev_frame_size_enum> &fse)
|
||
{
|
||
int ret = 0;
|
||
struct v4l2_subdev_frame_size_enum frame_size;
|
||
|
||
CLEAR(frame_size);
|
||
frame_size.pad = pad;
|
||
frame_size.index = codeIndex[code];
|
||
frame_size.code = code;
|
||
|
||
if (mState == DEVICE_CLOSED) {
|
||
LOGE("%s %s in invalid state %d",__FUNCTION__, mName.c_str(), mState);
|
||
return INVALID_OPERATION;
|
||
}
|
||
|
||
LOGD("%s VIDIOC_SUBDEV_ENUM_FRAME_SIZE: pad: %d, index %d, code:0x%x",
|
||
mName.c_str(), frame_size.pad, frame_size.index, frame_size.code);
|
||
while (pbxioctl(VIDIOC_SUBDEV_ENUM_FRAME_SIZE, &frame_size) == 0) {
|
||
LOGI("@%s: Sensor frame size: Min(%dx%d), Max(%dx%d)", __FUNCTION__,
|
||
frame_size.min_width, frame_size.min_height, frame_size.max_width, frame_size.max_height);
|
||
fse.push_back(frame_size);
|
||
frame_size.index++;
|
||
};
|
||
LOGD("@%s device: %s, %zu frame size retrieved", __FUNCTION__, mName.c_str(), fse.size());
|
||
|
||
return OK;
|
||
}
|
||
|
||
status_t V4L2Subdevice::queryDvTimings(struct v4l2_dv_timings &timings)
|
||
{
|
||
LOGI("@%s device = %s", __FUNCTION__, mName.c_str());
|
||
int ret = 0;
|
||
|
||
if (mState == DEVICE_CLOSED) {
|
||
LOGE("%s invalid device state %d",__FUNCTION__, mState);
|
||
return INVALID_OPERATION;
|
||
}
|
||
|
||
ret = pbxioctl(VIDIOC_SUBDEV_QUERY_DV_TIMINGS, &timings);
|
||
LOGE("%s, ret:%d, I:%d, wxh:%dx%d", __func__, ret,
|
||
timings.bt.interlaced, timings.bt.width, timings.bt.height);
|
||
if (ret < 0) {
|
||
LOGE("VIDIOC_SUBDEV_QUERY_DV_TIMINGS failed: %s", strerror(errno));
|
||
return UNKNOWN_ERROR;
|
||
}
|
||
|
||
return NO_ERROR;
|
||
}
|
||
|
||
} NAMESPACE_DECLARATION_END
|
||
////////////////////////////////////////////////////////////////////
|
||
// PRIVATE METHODS
|
||
////////////////////////////////////////////////////////////////////
|
||
|