592 lines
13 KiB
C
592 lines
13 KiB
C
/*
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0
|
|
*
|
|
* Copyright (C) 2020 Amlogic or its affiliates
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; version 2.
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* for more details.
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
*/
|
|
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <getopt.h>
|
|
#include <errno.h>
|
|
#include <signal.h>
|
|
#include <linux/videodev2.h>
|
|
|
|
#include "camera.h"
|
|
#include "handler.h"
|
|
|
|
#define CAM_DEV_CNT 4
|
|
|
|
static struct camera_dev cameras[CAM_DEV_CNT];
|
|
|
|
static void cam_list_all_dev(void)
|
|
{
|
|
for (uint32_t i = 0; i < CAM_DEV_CNT; i++) {
|
|
if (cameras[i].name)
|
|
printf("%u: %s\n", i, cameras[i].name);
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
|
|
static int cam_get_all_dev(void)
|
|
{
|
|
char name[16] = { '\0' };
|
|
uint32_t index = 0;
|
|
uint32_t cid = 0;
|
|
int ret;
|
|
|
|
memset(cameras, 0, sizeof(cameras));
|
|
|
|
while (1) {
|
|
snprintf(name, sizeof(name), "/dev/media%u", index);
|
|
memset(&cameras[cid], 0, sizeof(cameras[cid]));
|
|
ret = media_parse_topo(name, &cameras[cid]);
|
|
if (ret == 0)
|
|
cid++;
|
|
else if (ret == -ENOENT)
|
|
break;
|
|
|
|
if (cid == CAM_DEV_CNT)
|
|
break;
|
|
|
|
index++;
|
|
}
|
|
|
|
if (cid == 0)
|
|
return -ENODEV;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int cam_match_dev(struct camera_dev **mcam0, struct camera_dev **mcam1)
|
|
{
|
|
if (cameras[0].status == STATUS_PLUG) {
|
|
*mcam0 = &cameras[0];
|
|
(*mcam0)->cam_id = 0;
|
|
}
|
|
if (cameras[1].status == STATUS_PLUG) {
|
|
*mcam1 = &cameras[1];
|
|
(*mcam1)->cam_id = 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static struct video_dev *cam_parse_vdev(char *param, struct camera_dev *cam)
|
|
{
|
|
char *ptr = NULL;
|
|
struct video_dev *vdev = NULL;
|
|
|
|
ptr = strstr(param, "view");
|
|
if (ptr)
|
|
vdev = &cam->view;
|
|
|
|
ptr = strstr(param, "still");
|
|
if (ptr)
|
|
vdev = &cam->cap;
|
|
|
|
ptr = strstr(param, "video");
|
|
if (ptr)
|
|
vdev = &cam->record;
|
|
|
|
ptr = strstr(param, "disp");
|
|
if (ptr)
|
|
vdev = &cam->disp;
|
|
|
|
ptr = strstr(param, "raw");
|
|
if (ptr)
|
|
vdev = &cam->raw;
|
|
|
|
ptr = strstr(param, "vc0");
|
|
if (ptr)
|
|
vdev = &cam->vc0;
|
|
|
|
ptr = strstr(param, "vc1");
|
|
if (ptr)
|
|
vdev = &cam->vc1;
|
|
|
|
ptr = strstr(param, "vc2");
|
|
if (ptr)
|
|
vdev = &cam->vc2;
|
|
|
|
ptr = strstr(param, "vc3");
|
|
if (ptr)
|
|
vdev = &cam->vc3;
|
|
|
|
return vdev;
|
|
}
|
|
|
|
static int cam_parse_size(char *param, struct format_info *fmt)
|
|
{
|
|
char *ptr = NULL;
|
|
char *width = "width=";
|
|
char *height = "height=";
|
|
|
|
ptr = strstr(param, width);
|
|
if (ptr) {
|
|
ptr += strlen(width);
|
|
fmt->width = atoi(ptr);
|
|
}
|
|
|
|
ptr = strstr(param, height);
|
|
if (ptr) {
|
|
ptr += strlen(height);
|
|
fmt->height = atoi(ptr);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int cam_parse_format(char *param, struct format_info *fmt)
|
|
{
|
|
char *ptr = NULL;
|
|
|
|
ptr = strstr(param, "nv12");
|
|
if (ptr)
|
|
fmt->fmt = V4L2_PIX_FMT_NV12M;
|
|
|
|
ptr = strstr(param, "nv21");
|
|
if (ptr)
|
|
fmt->fmt = V4L2_PIX_FMT_NV21M;
|
|
|
|
ptr = strstr(param, "nv16");
|
|
if (ptr)
|
|
fmt->fmt = V4L2_PIX_FMT_NV16M;
|
|
|
|
ptr = strstr(param, "nv61");
|
|
if (ptr)
|
|
fmt->fmt = V4L2_PIX_FMT_NV61M;
|
|
|
|
ptr = strstr(param, "grey");
|
|
if (ptr)
|
|
fmt->fmt = V4L2_PIX_FMT_GREY;
|
|
|
|
ptr = strstr(param, "rggb12");
|
|
if (ptr)
|
|
fmt->fmt = V4L2_PIX_FMT_SRGGB12;
|
|
|
|
ptr = strstr(param, "grbg12");
|
|
if (ptr)
|
|
fmt->fmt = V4L2_PIX_FMT_SGRBG12;
|
|
|
|
ptr = strstr(param, "bggr12");
|
|
if (ptr)
|
|
fmt->fmt = V4L2_PIX_FMT_SBGGR12;
|
|
|
|
ptr = strstr(param, "gbrg12");
|
|
if (ptr)
|
|
fmt->fmt = V4L2_PIX_FMT_SGBRG12;
|
|
|
|
ptr = strstr(param, "rggb10");
|
|
if (ptr)
|
|
fmt->fmt = V4L2_PIX_FMT_SRGGB10;
|
|
|
|
ptr = strstr(param, "grbg10");
|
|
if (ptr)
|
|
fmt->fmt = V4L2_PIX_FMT_SGRBG10;
|
|
|
|
ptr = strstr(param, "bggr10");
|
|
if (ptr)
|
|
fmt->fmt = V4L2_PIX_FMT_SBGGR10;
|
|
|
|
ptr = strstr(param, "gbrg10");
|
|
if (ptr)
|
|
fmt->fmt = V4L2_PIX_FMT_SGBRG10;
|
|
|
|
ptr = strstr(param, "yuyv");
|
|
if (ptr)
|
|
fmt->fmt = V4L2_PIX_FMT_YUYV;
|
|
|
|
ptr = strstr(param, "yvyu");
|
|
if (ptr)
|
|
fmt->fmt = V4L2_PIX_FMT_YVYU;
|
|
|
|
ptr = strstr(param, "uyvy");
|
|
if (ptr)
|
|
fmt->fmt = V4L2_PIX_FMT_UYVY;
|
|
|
|
ptr = strstr(param, "vyuy");
|
|
if (ptr)
|
|
fmt->fmt = V4L2_PIX_FMT_VYUY;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int cam_cfg_stream(char *param, struct camera_dev *cam)
|
|
{
|
|
struct video_dev *vdev = NULL;
|
|
|
|
if (!cam) {
|
|
printf("Error to get camera dev\n");
|
|
return -ENODEV;
|
|
}
|
|
|
|
vdev = cam_parse_vdev(param, cam);
|
|
if (!vdev) {
|
|
printf("Error to get video dev\n");
|
|
return -ENODEV;
|
|
}
|
|
|
|
vdev->used = 1;
|
|
cam->stats.used = 1;
|
|
cam->param.used = 1;
|
|
|
|
cam_parse_size(param, &vdev->format);
|
|
cam_parse_format(param, &vdev->format);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void cam_cfg_mode(char *param, struct camera_dev *cam)
|
|
{
|
|
if (!strcmp(param, "0")) {
|
|
cam->isp.work_mode = C4_ISP_RAW2DDR_MODE;
|
|
cam->ipp.work_mode = C4_IPP_SINGLE_VC_MODE;
|
|
} else if (!strcmp(param, "1")) {
|
|
cam->isp.work_mode = C4_ISP_ALLSCAN_MODE;
|
|
cam->ipp.work_mode = C4_IPP_SINGLE_VC_MODE;
|
|
} else if (!strcmp(param, "2")) {
|
|
cam->isp.work_mode = C4_ISP_SCANTILE_MODE;
|
|
cam->ipp.work_mode = C4_IPP_SINGLE_VC_MODE;
|
|
} else if (!strcmp(param, "3")) {
|
|
cam->isp.work_mode = C4_ISP_ALLTILE_MODE;
|
|
cam->ipp.work_mode = C4_IPP_SINGLE_VC_MODE;
|
|
} else if (!strcmp(param, "4")) {
|
|
cam->isp.work_mode = C4_ISP_SCANTILE_MODE;
|
|
cam->ipp.work_mode = C4_IPP_MULTI_VC_SYNC_MODE;
|
|
} else if (!strcmp(param, "5")) {
|
|
cam->isp.work_mode = C4_ISP_SCANTILE_MODE;
|
|
cam->ipp.work_mode = C4_IPP_MULTI_VC_SEP_MODE;
|
|
} else if (!strcmp(param, "6")) {
|
|
cam->isp.work_mode = C4_ISP_OFFTILE_MODE;
|
|
cam->ipp.work_mode = C4_IPP_MULTI_VC_SYNC_MODE;
|
|
} else {
|
|
cam->isp.work_mode = C4_ISP_OFFPOST_MODE;
|
|
cam->ipp.work_mode = C4_IPP_MULTI_VC_SYNC_MODE;
|
|
}
|
|
}
|
|
|
|
static void cam_cfg_hdr(char *param, struct camera_dev *cam)
|
|
{
|
|
if (!strcmp(param, "0")) {
|
|
cam->sensor.img_mode = SENSOR_IMAGE_SDR;
|
|
cam->adap.img_mode = C4_ADAP_IMAGE_SDR;
|
|
cam->ipp.img_mode = C4_IPP_IMAGE_SDR;
|
|
cam->isp.img_mode = C4_ISP_IMAGE_SDR;
|
|
} else if (!strcmp(param, "1")) {
|
|
cam->sensor.img_mode = SENSOR_IMAGE_HDR_VC_INFO;
|
|
cam->adap.img_mode = C4_ADAP_IMAGE_HDR_VC_INFO;
|
|
cam->ipp.img_mode = C4_IPP_IMAGE_HDR;
|
|
cam->isp.img_mode = C4_ISP_IMAGE_HDR;
|
|
} else if (!strcmp(param, "2")) {
|
|
cam->sensor.img_mode = SENSOR_IMAGE_HDR_LINE_INFO;
|
|
cam->adap.img_mode = C4_ADAP_IMAGE_HDR_LINE_INFO;
|
|
cam->ipp.img_mode = C4_IPP_IMAGE_HDR;
|
|
cam->isp.img_mode = C4_ISP_IMAGE_HDR;
|
|
} else {
|
|
cam->sensor.img_mode = SENSOR_IMAGE_SDR;
|
|
cam->adap.img_mode = C4_ADAP_IMAGE_SDR;
|
|
cam->ipp.img_mode = C4_IPP_IMAGE_SDR;
|
|
cam->isp.img_mode = C4_ISP_IMAGE_SDR;
|
|
}
|
|
}
|
|
|
|
static void cam_cfg_save_files(struct camera_dev *cam)
|
|
{
|
|
cam->view.need_save_files = 1;
|
|
cam->cap.need_save_files = 1;
|
|
cam->record.need_save_files = 1;
|
|
cam->raw.need_save_files = 1;
|
|
cam->disp.need_save_files = 1;
|
|
cam->vc0.need_save_files = 1;
|
|
cam->vc1.need_save_files = 1;
|
|
cam->vc2.need_save_files = 1;
|
|
cam->vc3.need_save_files = 1;
|
|
}
|
|
|
|
static void cam_cfg_patgen(struct camera_dev *cam)
|
|
{
|
|
cam->ipp.patgen = 1;
|
|
}
|
|
|
|
|
|
static void cam_cfg_allscan_mode(struct camera_dev *cam)
|
|
{
|
|
cam->vc0.used = 0;
|
|
cam->vc1.used = 0;
|
|
cam->vc2.used = 0;
|
|
cam->vc3.used = 0;
|
|
cam->stats.used = 1;
|
|
cam->param.used = 1;
|
|
cam->view.used = 1;
|
|
cam->isp_work_mode = C4_ISP_ALLSCAN_MODE;
|
|
}
|
|
|
|
static void cam_cfg_offtile_mode(struct camera_dev *cam)
|
|
{
|
|
if (cam->isp.img_mode == C4_ISP_IMAGE_SDR) {
|
|
cam->vc0.used = 1;
|
|
cam->vc1.used = 0;
|
|
cam->raw.used = 0;
|
|
cam->imp.used = 1;
|
|
cam->stats.used = 1;
|
|
cam->param.used = 1;
|
|
cam->view.used = 1;
|
|
cam->isp_work_mode = C4_ISP_ALLTILE_MODE;
|
|
} else {
|
|
cam->vc0.used = 1;
|
|
cam->vc1.used = 1;
|
|
cam->raw.used = 0;
|
|
cam->imp.used = 1;
|
|
cam->stats.used = 1;
|
|
cam->param.used = 1;
|
|
cam->view.used = 1;
|
|
cam->isp_work_mode = C4_ISP_ALLTILE_MODE;
|
|
}
|
|
}
|
|
|
|
static void cam_cfg_offpost_mode(struct camera_dev *cam)
|
|
{
|
|
if (cam->isp.img_mode != C4_ISP_IMAGE_SDR)
|
|
return;
|
|
|
|
cam->vc0.used = 1;
|
|
cam->vc1.used = 1;
|
|
cam->vc2.used = 1;
|
|
cam->vc3.used = 1;
|
|
|
|
cam->raw.used = 0;
|
|
cam->param.used = 0;
|
|
cam->stats.used = 0;
|
|
|
|
cam->imp.used = 1;
|
|
cam->isp_work_mode = C4_ISP_ALLTILE_MODE;
|
|
}
|
|
|
|
static void cam_cfg_pipeline_mode(struct camera_dev *cam)
|
|
{
|
|
switch (cam->isp.work_mode)
|
|
{
|
|
case C4_ISP_ALLSCAN_MODE:
|
|
cam_cfg_allscan_mode(cam);
|
|
break;
|
|
case C4_ISP_OFFTILE_MODE:
|
|
cam_cfg_offtile_mode(cam);
|
|
break;
|
|
case C4_ISP_OFFPOST_MODE:
|
|
cam_cfg_offpost_mode(cam);
|
|
break;
|
|
default:
|
|
cam_cfg_allscan_mode(cam);
|
|
printf("Error to get camera work mode, use allscan mode\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void cam_start(struct camera_dev *cam)
|
|
{
|
|
cam_cfg_pipeline_mode(cam);
|
|
|
|
camera_dev_init(cam);
|
|
|
|
camera_subdev_query_ctrls(cam);
|
|
|
|
/* Need configure mode firstly */
|
|
camera_subdev_cfg_ctrls(cam);
|
|
|
|
camera_subdev_cfg_format(cam);
|
|
|
|
if (cam->isp.work_mode == C4_ISP_OFFTILE_MODE)
|
|
camera_video_prep_offtile_format(cam);
|
|
|
|
if (cam->isp.work_mode == C4_ISP_OFFPOST_MODE)
|
|
camera_video_prep_offpost_format(cam);
|
|
|
|
camera_video_query_ctrls(cam);
|
|
camera_video_cfg_format(cam);
|
|
|
|
camera_data_cfg_format(cam);
|
|
|
|
camera_dev_create_links(cam);
|
|
pthread_mutex_init(&cam->lock, NULL);
|
|
pthread_mutex_lock(&cam->lock);
|
|
cam->status = STATUS_PAUSE;
|
|
pthread_mutex_unlock(&cam->lock);
|
|
camera_video_alloc_buffs(cam);
|
|
camera_video_queue_buffs(cam);
|
|
camera_video_stream_on(cam);
|
|
camera_video_create_thread(cam);
|
|
printf("Camera %s start end\n", cam->name);
|
|
}
|
|
|
|
static void cam_stop(struct camera_dev *cam)
|
|
{
|
|
pthread_mutex_lock(&cam->lock);
|
|
|
|
if (cam->status == STATUS_ON) {
|
|
cam->status = STATUS_PAUSE;
|
|
videos_dev_thread_destroy(cam);
|
|
camera_video_stream_off(cam);
|
|
camera_video_release_buffs(cam);
|
|
}
|
|
cam->status = STATUS_OFF;
|
|
camera_video_exit_thread(cam);
|
|
camera_dev_deinit(cam);
|
|
pthread_mutex_unlock(&cam->lock);
|
|
}
|
|
|
|
static void cam_exit(struct camera_dev *cam)
|
|
{
|
|
media_close_dev(cam);
|
|
}
|
|
|
|
static void cam_usage(void)
|
|
{
|
|
printf("Aml cam usage:\n");
|
|
printf("C: capture\n");
|
|
printf("c: camera name\n");
|
|
printf("mode: 0: raw2ddr, 1: allscan, 2: scantile, 3: alltile,\n");
|
|
printf(" 4: ipp multi vc sync, 5: ipp multi vc sep,\n");
|
|
printf(" 6: isp offline\n");
|
|
printf("hdr: 0: sdr, 1: hdr vc info, 2: hdr line info\n");
|
|
printf("file: save files\n");
|
|
printf("patgen: enable pattern generate\n");
|
|
printf("l: list all camera\n");
|
|
printf("s: stream param, role=view/still/video/disp/raw/vc0/vc1/vc2/vc3\n");
|
|
printf("example:\n");
|
|
printf("sdr and hdr:\n");
|
|
printf("./capp -C -c imx290-0-001a --mode 1 --hdr 0 -s role=view,width=1920,height=1080,pixelformat=nv12\n");
|
|
printf("./capp -C -c imx290-0-001a --mode 1 --hdr 2 -s role=view,width=1920,height=1080,pixelformat=nv12\n");
|
|
printf("./capp -C -c imx290-0-001a --mode 4 --hdr 0 -s role=vc0,width=1920,height=1080,pixelformat=rggb12\n");
|
|
printf("./capp -C -c imx290-0-001a --mode 4 --hdr 2 -s role=vc0,width=1920,height=1080,pixelformat=rggb10 \n");
|
|
printf(" -s role=vc1,width=1920,height=1080,pixelformat=rggb10\n");
|
|
printf("./capp -C -c imx290-0-001a --mode 6 --hdr 0 -s role=view,width=1920,height=1080,pixelformat=nv12\n");
|
|
printf("./capp -C -c imx290-0-001a --mode 6 --hdr 2 -s role=view,width=1920,height=1080,pixelformat=nv12\n");
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
int idx;
|
|
int crtn;
|
|
struct camera_dev *mcam0 = NULL;
|
|
struct camera_dev *mcam1 = NULL;
|
|
char *short_opt = "ls:";
|
|
struct option long_opt[] = {
|
|
{"mode", required_argument, NULL, 'M'},
|
|
{"hdr", required_argument, NULL, 'H'},
|
|
{"file", no_argument, NULL, 'F'},
|
|
{"patgen", no_argument, NULL, 'P'},
|
|
{NULL, 0, NULL, 0}
|
|
};
|
|
|
|
crtn = cam_get_all_dev();
|
|
if (crtn)
|
|
return crtn;
|
|
crtn = cam_match_dev(&mcam0, &mcam1);
|
|
if (!crtn) {
|
|
if (mcam0 != NULL)
|
|
camera_dev_disable_links(mcam0);
|
|
if (mcam1 != NULL)
|
|
camera_dev_disable_links(mcam1);
|
|
} else {
|
|
printf("Invalid camera %s\n", optarg);
|
|
return crtn;
|
|
}
|
|
while (1) {
|
|
crtn = getopt_long(argc, argv, short_opt, long_opt, &idx);
|
|
if (crtn == -1)
|
|
break;
|
|
switch (crtn) {
|
|
case 0:
|
|
printf("long opt name: %s\n", long_opt[idx].name);
|
|
break;
|
|
case 'l':
|
|
cam_list_all_dev();
|
|
return 0;
|
|
case 's':
|
|
if (mcam0 != NULL)
|
|
cam_cfg_stream(optarg, mcam0);
|
|
if (mcam1 != NULL)
|
|
cam_cfg_stream(optarg, mcam1);
|
|
break;
|
|
case 'M':
|
|
if (mcam0 != NULL)
|
|
cam_cfg_mode(optarg, mcam0);
|
|
if (mcam1 != NULL)
|
|
cam_cfg_mode(optarg, mcam1);
|
|
break;
|
|
case 'H':
|
|
if (mcam0 != NULL)
|
|
cam_cfg_hdr(optarg, mcam0);
|
|
if (mcam1 != NULL)
|
|
cam_cfg_hdr(optarg, mcam1);
|
|
break;
|
|
case 'F':
|
|
if (mcam0 != NULL)
|
|
cam_cfg_save_files(mcam0);
|
|
if (mcam1 != NULL)
|
|
cam_cfg_save_files(mcam1);
|
|
break;
|
|
case 'P':
|
|
if (mcam0 != NULL)
|
|
cam_cfg_patgen(mcam0);
|
|
if (mcam1 != NULL)
|
|
cam_cfg_patgen(mcam1);
|
|
break;
|
|
default:
|
|
cam_usage();
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if (!mcam0 && !mcam1) {
|
|
cam_usage();
|
|
return 0;
|
|
}
|
|
|
|
if (mcam0 != NULL) {
|
|
printf("camera %s start\n", mcam0->name);
|
|
cam_start(mcam0);
|
|
}
|
|
if (mcam1 != NULL) {
|
|
printf("camera %s start\n", mcam1->name);
|
|
cam_start(mcam1);
|
|
}
|
|
|
|
while (1) {
|
|
sleep(10);
|
|
}
|
|
|
|
if (mcam0 != NULL) {
|
|
cam_stop(mcam0);
|
|
cam_exit(mcam0);
|
|
}
|
|
|
|
if (mcam1 != NULL) {
|
|
cam_stop(mcam1);
|
|
cam_exit(mcam1);
|
|
}
|
|
|
|
if (mcam0 != NULL)
|
|
printf("camera %s exit over\n", mcam0->name);
|
|
if (mcam1 != NULL)
|
|
printf("camera %s exit over\n", mcam1->name);
|
|
|
|
return 0;
|
|
}
|