rk3568_ubuntu_r60_v1.3.2/external/rkfacial/aiq_control.cpp
2023-11-03 06:12:44 +00:00

332 lines
9.7 KiB
C++

/*
* Copyright (C) 2019 Rockchip Electronics Co., Ltd.
* author: Zhihua Wang, hogan.wang@rock-chips.com
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL), available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <linux/videodev2.h>
#include <sys/ioctl.h>
#include <list>
#include "aiq_control.h"
#include <mediactl/mediactl.h>
#include <mediactl/v4l2subdev.h>
#define IQFILES_PATH "/etc/iqfiles"
#define AIQ_FILE_PATH_LEN 64
#define AIQ_WIDTH 2688
#define AIQ_HEIGHT 1520
#define IR_SENSOR_MEDIA_MODEL "rkcif_mipi_lvds"
#define RGB_SENSOR_MEDIA_MODEL "rkisp0"
#define RGB_ISPP_MEDIA_MODEL "rkispp0"
#define IR_ISPP_MEDIA_MODEL "rkispp1"
#define CLEAR(x) memset(&(x), 0, sizeof(x))
/* Private v4l2 event */
#define CIFISP_V4L2_EVENT_STREAM_START (V4L2_EVENT_PRIVATE_START + 1)
#define CIFISP_V4L2_EVENT_STREAM_STOP (V4L2_EVENT_PRIVATE_START + 2)
struct aiq_control {
rk_aiq_working_mode_t mode;
rk_aiq_sys_ctx_t *ctx;
aiq_control_type type;
char sensor[AIQ_FILE_PATH_LEN];
char ispp[AIQ_FILE_PATH_LEN];
bool ok;
};
static std::list<struct aiq_control *> g_aiq;
static int xioctl(int fh, int request, void *arg)
{
int r;
do {
r = ioctl(fh, request, arg);
} while (-1 == r && EINTR == errno);
return r;
}
static int get_devname(struct media_device *device, const char *name, char *dev_name)
{
const char *devname;
struct media_entity *entity = NULL;
entity = media_get_entity_by_name(device, name, strlen(name));
if (!entity)
return -1;
devname = media_entity_get_devname(entity);
if (!devname)
return -1;
strncpy(dev_name, devname, AIQ_FILE_PATH_LEN);
printf("get %s devname: %s\n", name, dev_name);
return 0;
}
static int enumrate_modules(struct media_device *device, char *name, size_t size)
{
uint32_t nents, i;
const char *dev_name = NULL;
int active_sensor = -1;
nents = media_get_entities_count(device);
for (i = 0; i < nents; ++i) {
struct media_entity *e;
const struct media_entity_desc *ef;
const struct media_link *link;
e = media_get_entity(device, i);
ef = media_entity_get_info(e);
if (ef->type != MEDIA_ENT_T_V4L2_SUBDEV_SENSOR)
continue;
if (ef->name[0] != 'm' && ef->name[3] != '_') {
fprintf(stderr, "sensor entity name format is incorrect\n");
return -1;
}
dev_name = media_entity_get_devname(e);
switch (ef->type) {
case MEDIA_ENT_T_V4L2_SUBDEV_SENSOR:
link = media_entity_get_link(e, 0);
if (link && (link->flags & MEDIA_LNK_FL_ENABLED)) {
active_sensor = 1;
strncpy(name, ef->name, size);
}
break;
default:
break;
}
}
if (active_sensor < 0) {
fprintf(stderr, "Not sensor link is enabled, does sensor probe correctly?\n");
return -1;
}
return 0;
}
static int aiq_control_get_sensor_entity_name(aiq_control_type type, char *name, size_t size, char *ispp)
{
char mdev_path[AIQ_FILE_PATH_LEN];
int ret = -1;
struct media_device *device = NULL;
for (int i = 0;; i++) {
sprintf(mdev_path, "/dev/media%d", i);
if (access(mdev_path, F_OK))
break;
device = media_device_new(mdev_path);
if (device == NULL) {
printf("Failed to create media %s\n", mdev_path);
continue;
}
if (media_device_enumerate(device) < 0) {
printf("Failed to enumerate %s (%d)\n", mdev_path, ret);
media_device_unref(device);
continue;
}
const struct media_device_info *info = media_get_info(device);
if (AIQ_CONTROL_IR == type && !strcmp(info->model, IR_SENSOR_MEDIA_MODEL) ||
AIQ_CONTROL_RGB == type && !strcmp(info->model, RGB_SENSOR_MEDIA_MODEL))
ret = enumrate_modules(device, name, size);
if (AIQ_CONTROL_IR == type && !strcmp(info->model, IR_ISPP_MEDIA_MODEL) ||
AIQ_CONTROL_RGB == type && !strcmp(info->model, RGB_ISPP_MEDIA_MODEL))
get_devname(device, "rkispp_input_params", ispp);
media_device_unref(device);
}
return ret;
}
static int wait_stream_event(int fd, unsigned int event_type, int time_out_ms)
{
int ret;
struct v4l2_event event;
CLEAR(event);
do {
/*
* xioctl instead of poll.
* Since poll() cannot wait for input before stream on,
* it will return an error directly. So, use ioctl to
* dequeue event and block until sucess.
*/
ret = xioctl(fd, VIDIOC_DQEVENT, &event);
if (ret == 0 && event.type == event_type) {
return 0;
}
} while (true);
return -1;
}
static int subscrible_stream_event(char *ispp, int fd, bool subs) {
struct v4l2_event_subscription sub;
int ret = 0;
CLEAR(sub);
sub.type = CIFISP_V4L2_EVENT_STREAM_START;
ret = xioctl(fd, subs ? VIDIOC_SUBSCRIBE_EVENT : VIDIOC_UNSUBSCRIBE_EVENT, &sub);
if (ret) {
printf("can't subscribe %s start event!\n", ispp);
exit(EXIT_FAILURE);
}
CLEAR(sub);
sub.type = CIFISP_V4L2_EVENT_STREAM_STOP;
ret = xioctl(fd, subs ? VIDIOC_SUBSCRIBE_EVENT : VIDIOC_UNSUBSCRIBE_EVENT, &sub);
if (ret) {
printf("can't subscribe %s stop event!\n", ispp);
}
printf("subscribe events from %s success !\n", ispp);
return 0;
}
static void *aiq_thread(void *arg)
{
struct aiq_control *aiq = (struct aiq_control *)arg;
while (1) {
int isp_fd = open(aiq->ispp, O_RDWR);
if (isp_fd < 0) {
printf("open %s failed %s\n", aiq->ispp, strerror(errno));
pthread_exit(NULL);
}
subscrible_stream_event(aiq->ispp, isp_fd, true);
rk_aiq_sys_ctx_t *ctx = rk_aiq_uapi_sysctl_init(aiq->sensor, IQFILES_PATH, NULL, NULL);
if (!ctx) {
printf("%s: rk_aiq_uapi_sysctl_init fail!\n", __func__);
pthread_exit(NULL);
}
rk_aiq_uapi_sysctl_setMulCamConc(ctx, true);
if (rk_aiq_uapi_sysctl_prepare(ctx, AIQ_WIDTH, AIQ_HEIGHT, aiq->mode)) {
printf("%s: rk_aiq_uapi_sysctl_prepare fail!\n", __func__);
rk_aiq_uapi_sysctl_deinit(ctx);
pthread_exit(NULL);
}
aiq->ok = true;
wait_stream_event(isp_fd, CIFISP_V4L2_EVENT_STREAM_START, -1);
aiq->ctx = ctx;
if (rk_aiq_uapi_sysctl_start(ctx) < 0) {
printf("%s: rk_aiq_uapi_sysctl_start fail!\n", __func__);
rk_aiq_uapi_sysctl_deinit(ctx);
pthread_exit(NULL);
}
wait_stream_event(isp_fd, CIFISP_V4L2_EVENT_STREAM_STOP, -1);
aiq->ctx = NULL;
aiq->ok = false;
rk_aiq_uapi_sysctl_stop(ctx, false);
rk_aiq_uapi_sysctl_deinit(ctx);
subscrible_stream_event(aiq->ispp, isp_fd, false);
close(isp_fd);
}
pthread_detach(pthread_self());
pthread_exit(NULL);
}
static void aiq_alloc(aiq_control_type type)
{
char name[AIQ_FILE_PATH_LEN] = "";
char ispp[AIQ_FILE_PATH_LEN] = "";
if (!aiq_control_get_sensor_entity_name(type, name, sizeof(name), ispp) && strlen(ispp)) {
struct aiq_control *aiq = (struct aiq_control *)calloc(1, sizeof(struct aiq_control));
if (!aiq) {
printf("%s alloc fail!\n", __func__);
return;
}
if (type == AIQ_CONTROL_RGB)
aiq->mode = RK_AIQ_WORKING_MODE_ISP_HDR2;
else
aiq->mode = RK_AIQ_WORKING_MODE_NORMAL;
aiq->type = type;
strncpy(aiq->ispp, ispp, sizeof(aiq->ispp));
strncpy(aiq->sensor, name, sizeof(aiq->sensor));
g_aiq.push_back(aiq);
pthread_t tid;
if (pthread_create(&tid, NULL, aiq_thread, aiq))
printf("create aiq_thread fail!\n");
}
}
int aiq_control_alloc(void)
{
aiq_alloc(AIQ_CONTROL_RGB);
aiq_alloc(AIQ_CONTROL_IR);
return 0;
}
void aiq_control_setExpGainRange(enum aiq_control_type type, paRange_t range)
{
for (auto &aiq : g_aiq) {
if (aiq->type == type) {
rk_aiq_uapi_getExpGainRange(aiq->ctx, &range);
rk_aiq_uapi_setExpGainRange(aiq->ctx, &range);
break;
}
}
}
bool aiq_control_get_status(enum aiq_control_type type)
{
bool ok = false;
for (auto &aiq : g_aiq) {
if (aiq->type == type) {
ok = aiq->ok;
break;
}
}
return ok;
}