/* * Copyright (c) XMEDIA. All rights reserved. */ #include #include #include #include #include #include #include #include #include #include "sample_comm.h" #include "sample_comm_sys.h" #include "sample_comm_isp.h" #include "sample_comm_ircut.h" #define GAIN_MAX_COEF (280) #define GAIN_MIN_COEF (190) #define ISO_MAX_ARR_NUM 16 #define DIV_0_TO_1(a) ( ((a) == 0) ? 1 : (a) ) typedef enum{ SAMPLE_IRCUT_MANUAL_MODE = 0, SAMPLE_IRCUT_CALIBRATION_MODE = 1, SAMPLE_IRCUT_AUTO_MODE = 2, SAMPLE_IRCUT_MODE_BUTT, }sample_ircut_mode; typedef enum { SAMPLE_IRCUT_STATUS_NORMAL = 0, SAMPLE_IRCUT_STATUS_IR = 1, SAMPLE_IRCUT_STATUS_BUTT, } sample_ircut_status; typedef enum { SAMPLE_IRCUT_SWITCH_NONE = 0, SAMPLE_IRCUT_SWITCH_TO_NORMAL = 1, SAMPLE_IRCUT_SWITCH_TO_IR = 2, SAMPLE_IRCUT_SWITCH_BUTT, } sample_ircut_switch_status; typedef struct { xmedia_u32 normal_to_ir_iso_thr; xmedia_u32 ir_to_normal_iso_thr; xmedia_u32 rgmax; xmedia_u32 rgmin; xmedia_u32 bgmax; xmedia_u32 bgmin; sample_ircut_status status; sample_ircut_switch_status switch_status; }sample_ircut_attr; typedef struct { xmedia_u8 cnt; xmedia_u32 iso[ISO_MAX_ARR_NUM]; }sample_ircut_ctx; typedef struct { xmedia_s32 vi_dev; xmedia_s32 board_type; }sample_ircut_thread_param; static xmedia_bool g_force_exit = XMEDIA_FALSE; static sample_ircut_attr g_ircut_attr[VI_MAX_DEV_NUM] = {0}; static sample_ircut_ctx g_ircut_ctx[VI_MAX_DEV_NUM] = {0}; xmedia_void sample_ircut_usage(xmedia_char* args) { printf("Usage : %s mode board_type videv status normal2ir_iso_thr ir2normal_iso_thr rgmax rgmin bgmax bgmin\n", args); printf("mode:\n"); printf("\t 0: manul.\n"); printf("\t 1: calibration.\n"); printf("\t 2: auto.\n"); printf("board_type:\n"); printf("\t 0: xm7206v10rb.\n"); printf("\t 1: xm7206v10brba.\n"); printf("\t 2: xm7206v10bevb.\n"); printf("\t 3: xm7206v11arba.\n"); printf("\t 4: xm7206v11aevb.\n"); printf("videv:\n"); printf("\t 0: vi 0.\n"); printf("\t 1: vi 1.\n"); printf("status:\n"); printf("\t 0: ir --> normal (manual).\n"); printf("\t 1) normal --> ir (manual).\n"); printf("\t 0: current ir status: normal (auto).\n"); printf("\t 1) current ir status: ir (auto).\n"); printf("normal2ir_iso_thr:\n"); printf("\t iso threshold of switching from normal to ir mode.\n"); printf("ir2normal_iso_thr:\n"); printf("\t iso threshold of switching from ir to normal mode.\n"); printf("rgmax/rgmin/bgmax/bgmin:\n"); printf("\t maximum(minimum) value of r/g(b/g) in ir scene.\n"); printf("eg: manula:\n"); printf("\t %s 0 0 0 0\n", args); printf("eg: calibration:\n"); printf("\t %s 1 0 0\n", args); printf("eg: auto:\n"); printf("\t %s 2 0 0 0 16000 400 280 190 280 190\n", args); return; } static xmedia_s32 sample_ircut_switch_to_normal(sample_comm_board_type board_type, xmedia_s32 vi_dev) { xmedia_s32 ret = XMEDIA_SUCCESS; xmedia_awb_attr awb_attr = {0}; xmedia_awb_saturation_attr awb_saturation_attr = {0}; xmedia_awb_ccm_attr awb_ccm_attr = {0}; sample_comm_ircut_set_status_normal(board_type, vi_dev); ret = xmedia_awb_get_attr(vi_dev, &awb_attr); if (ret != XMEDIA_SUCCESS) { SAMPLE_PRT("vi dev:%d sample ircut get awb attr failed .\n", vi_dev); return ret; } awb_attr.op_type = XMEDIA_VIDEO_OPERATION_MODE_AUTO; ret = xmedia_awb_set_attr(vi_dev, &awb_attr); if (ret != XMEDIA_SUCCESS) { SAMPLE_PRT("vi dev:%d sample ircut set awb attr failed .\n", vi_dev); return ret; } ret = xmedia_awb_get_ccm_attr(vi_dev, &awb_ccm_attr); if (ret != XMEDIA_SUCCESS) { SAMPLE_PRT("vi dev:%d sample ircut get awb ccm attr failed .\n", vi_dev); return ret; } awb_ccm_attr.op_type = XMEDIA_VIDEO_OPERATION_MODE_AUTO; ret = xmedia_awb_set_ccm_attr(vi_dev, &awb_ccm_attr); if (ret != XMEDIA_SUCCESS) { SAMPLE_PRT("vi dev:%d sample ircut set awb ccm attr failed .\n", vi_dev); return ret; } usleep(1000000); ret = xmedia_awb_get_saturation_attr(vi_dev, &awb_saturation_attr); if (ret != XMEDIA_SUCCESS) { SAMPLE_PRT("vi dev:%d sample ircut get awb saturation attr failed .\n", vi_dev); return ret; } awb_saturation_attr.op_type = XMEDIA_VIDEO_OPERATION_MODE_AUTO; ret = xmedia_awb_set_saturation_attr(vi_dev, &awb_saturation_attr); if (ret != XMEDIA_SUCCESS) { SAMPLE_PRT("vi dev:%d sample ircut set awb saturation attr failed .\n", vi_dev); return ret; } return ret; } static xmedia_s32 sample_ircut_switch_to_ir(sample_comm_board_type board_type, xmedia_s32 vi_dev) { xmedia_s32 ret = XMEDIA_SUCCESS; xmedia_awb_attr awb_attr = {0}; xmedia_awb_saturation_attr awb_saturation_attr = {0}; xmedia_awb_ccm_attr awb_ccm_attr = {0}; ret = xmedia_awb_get_saturation_attr(vi_dev, &awb_saturation_attr); if (ret != XMEDIA_SUCCESS) { SAMPLE_PRT("vi dev:%d sample ircut get awb saturation attr failed .\n", vi_dev); return ret; } awb_saturation_attr.op_type = XMEDIA_VIDEO_OPERATION_MODE_MANUAL; awb_saturation_attr.manual_attr.saturation = 0; ret = xmedia_awb_set_saturation_attr(vi_dev, &awb_saturation_attr); if (ret != XMEDIA_SUCCESS) { SAMPLE_PRT("vi dev:%d sample ircut set awb saturation attr failed .\n", vi_dev); return ret; } usleep(1000000); ret = xmedia_awb_get_attr(vi_dev, &awb_attr); if (ret != XMEDIA_SUCCESS) { SAMPLE_PRT("vi dev:%d sample ircut get awb attr failed .\n", vi_dev); return ret; } awb_attr.op_type = XMEDIA_VIDEO_OPERATION_MODE_MANUAL; awb_attr.manual_attr.rgain = 0x100; awb_attr.manual_attr.bgain = 0x100; awb_attr.manual_attr.grgain = 0x100; awb_attr.manual_attr.gbgain = 0x100; ret = xmedia_awb_set_attr(vi_dev, &awb_attr); if (ret != XMEDIA_SUCCESS) { SAMPLE_PRT("vi dev:%d sample ircut set awb attr failed .\n", vi_dev); return ret; } ret = xmedia_awb_get_ccm_attr(vi_dev, &awb_ccm_attr); if (ret != XMEDIA_SUCCESS) { SAMPLE_PRT("vi dev:%d sample ircut get awb ccm attr failed .\n", vi_dev); return ret; } awb_ccm_attr.op_type = XMEDIA_VIDEO_OPERATION_MODE_MANUAL; awb_ccm_attr.manual_attr.ccm[0] = 0x100; awb_ccm_attr.manual_attr.ccm[1] = 0; awb_ccm_attr.manual_attr.ccm[2] = 0; awb_ccm_attr.manual_attr.ccm[3] = 0; awb_ccm_attr.manual_attr.ccm[4] = 0x100; awb_ccm_attr.manual_attr.ccm[5] = 0; awb_ccm_attr.manual_attr.ccm[6] = 0; awb_ccm_attr.manual_attr.ccm[7] = 0; awb_ccm_attr.manual_attr.ccm[8] = 0x100; ret = xmedia_awb_set_ccm_attr(vi_dev, &awb_ccm_attr); if (ret != XMEDIA_SUCCESS) { SAMPLE_PRT("vi dev:%d sample ircut set awb ccm attr failed .\n", vi_dev); return ret; } sample_comm_ircut_set_status_ir(board_type, vi_dev); return ret; } static xmedia_s32 sample_ircut_manual_mode(sample_comm_board_type board_type, xmedia_s32 vi_dev, xmedia_s32 status) { xmedia_s32 ret = XMEDIA_SUCCESS; if (status == SAMPLE_IRCUT_STATUS_NORMAL) { ret = sample_ircut_switch_to_normal(board_type, vi_dev); if (ret == XMEDIA_SUCCESS) { SAMPLE_PRT("vi dev:%d sample ircut switch to normal success .\n", vi_dev); } else { SAMPLE_PRT("vi dev:%d sample ircut switch to normal failed .\n", vi_dev); } } else { ret = sample_ircut_switch_to_ir(board_type, vi_dev); if (ret == XMEDIA_SUCCESS) { SAMPLE_PRT("vi dev:%d sample ircut switch to ir success .\n", vi_dev); } else { SAMPLE_PRT("vi dev:%d sample ircut switch to ir failed .\n", vi_dev); } } return ret; } static xmedia_s32 sample_ircut_calibration_mode(sample_comm_board_type board_type, xmedia_s32 vi_dev) { xmedia_s32 ret = XMEDIA_SUCCESS; xmedia_u32 rg = 0; xmedia_u32 bg = 0; xmedia_isp_awb_statistics awb_stat = {0}; ret = sample_ircut_switch_to_ir(board_type, vi_dev); if (ret != XMEDIA_SUCCESS) { SAMPLE_PRT("vi dev:%d sample ircut switch to ir failed .\n", vi_dev); return ret; } //waiting for ae to stabilize */ usleep(1000000); ret = xmedia_isp_get_awb_statistics(vi_dev, &awb_stat); if (ret != XMEDIA_SUCCESS) { SAMPLE_PRT("vi dev:%d sample ircut get awb stat failed .\n", vi_dev); return ret; } rg = ((xmedia_u32)awb_stat.global_r << 8) / DIV_0_TO_1(awb_stat.global_g); bg = ((xmedia_u32)awb_stat.global_b << 8) / DIV_0_TO_1(awb_stat.global_g); SAMPLE_PRT("rgmax:%d, rgmin:%d, bgmax:%d, bgmin:%d\n", rg * GAIN_MAX_COEF >> 8, rg * GAIN_MIN_COEF >> 8, bg * GAIN_MAX_COEF >> 8, bg * GAIN_MIN_COEF >> 8); sample_ircut_switch_to_normal(board_type, vi_dev); return ret; } static xmedia_bool sample_ircut_check_ae_stable(xmedia_u32 now_iso, sample_ircut_ctx *ircut_ctx) { xmedia_s32 i = 0; xmedia_u32 iso_mean = 0; xmedia_u64 iso_sum = 0; xmedia_u64 iso_diff_sum = 0; CHECK_NULL_PTR(ircut_ctx); for (i = 0; i < ISO_MAX_ARR_NUM - 1; i++) { ircut_ctx->iso[i] = ircut_ctx->iso[i + 1]; } ircut_ctx->iso[ISO_MAX_ARR_NUM - 1] = now_iso; for (i = 0; i < ISO_MAX_ARR_NUM; i++) { iso_sum += ircut_ctx->iso[i]; } iso_mean = iso_sum / ISO_MAX_ARR_NUM; for (i = 0; i < ISO_MAX_ARR_NUM; i++) { iso_diff_sum += (abs(ircut_ctx->iso[i] - iso_mean) * (i + 1)); } for (i = 0; i < ISO_MAX_ARR_NUM; i++) { if (!ircut_ctx->iso[i]) { break; } if (i == (ISO_MAX_ARR_NUM - 1)) { return (iso_diff_sum <= (iso_mean << 3)); } } return XMEDIA_FALSE; } static xmedia_s32 sample_ircut_auto_run_once(xmedia_s32 vi_dev, sample_ircut_attr *ircut_attr) { xmedia_s32 ret = XMEDIA_SUCCESS; xmedia_bool ae_stable = XMEDIA_FALSE; xmedia_u32 now_iso = 0; xmedia_u32 now_rg = 0; xmedia_u32 now_bg = 0; xmedia_isp_awb_statistics awb_stat = {0}; xmedia_ae_exp_info exp_info = {0}; sample_ircut_ctx *ctx = &g_ircut_ctx[vi_dev]; CHECK_NULL_PTR(ircut_attr); ret = xmedia_isp_get_awb_statistics(vi_dev, &awb_stat); if (ret != XMEDIA_SUCCESS) { SAMPLE_PRT("vi dev:%d sample ircut get awb stat failed .\n", vi_dev); return ret; } now_rg = ((xmedia_u32)awb_stat.global_r << 8) / DIV_0_TO_1(awb_stat.global_g); now_bg = ((xmedia_u32)awb_stat.global_b << 8) / DIV_0_TO_1(awb_stat.global_g); ret = xmedia_ae_query_exposure_info(vi_dev, &exp_info); if (ret != XMEDIA_SUCCESS) { SAMPLE_PRT("vi dev:%d sample ircut get ae info failed .\n", vi_dev); return ret; } now_iso = exp_info.iso; if (ctx->cnt > 15) { ctx->cnt = 16; ae_stable = sample_ircut_check_ae_stable(now_iso, ctx); if (ae_stable) { if (ircut_attr->status == SAMPLE_IRCUT_STATUS_IR) { if (now_iso < ircut_attr->ir_to_normal_iso_thr || now_rg > ircut_attr->rgmax || \ now_rg < ircut_attr->rgmin || now_bg > ircut_attr->bgmax || now_bg < ircut_attr->bgmin) { ircut_attr->switch_status = SAMPLE_IRCUT_SWITCH_TO_NORMAL; ctx->cnt = 0; return XMEDIA_SUCCESS; } } else if (now_iso > ircut_attr->normal_to_ir_iso_thr) { ircut_attr->switch_status = SAMPLE_IRCUT_SWITCH_TO_IR; ctx->cnt = 0; return XMEDIA_SUCCESS; } } } else { ctx->cnt++; } ircut_attr->switch_status = SAMPLE_IRCUT_SWITCH_NONE; return XMEDIA_SUCCESS; } static xmedia_void *sample_ircut_auto_thread(void *param) { xmedia_s32 ret = XMEDIA_SUCCESS; sample_comm_board_type board_type = 0; xmedia_s32 vi_dev = 0; sample_ircut_thread_param *thread_param = (sample_ircut_thread_param *)param; sample_ircut_attr ircut_attr = {0}; if (!thread_param) { SAMPLE_PRT("sample ircut thread_param is null .\n"); return XMEDIA_NULL; } vi_dev = thread_param->vi_dev; board_type = thread_param->board_type; memcpy(&ircut_attr, &g_ircut_attr[vi_dev], sizeof(sample_ircut_attr)); while (!g_force_exit) { usleep(40 * 1000 * 4); ret = sample_ircut_auto_run_once(vi_dev, &ircut_attr); if (ret != XMEDIA_SUCCESS) { SAMPLE_PRT("vi dev:%d sample ircut atou run once failed .\n", vi_dev); return XMEDIA_NULL; } if (ircut_attr.switch_status == SAMPLE_IRCUT_SWITCH_TO_NORMAL) { SAMPLE_PRT("\nir -> normal \n"); ret = sample_ircut_switch_to_normal(board_type, vi_dev); if (ret != XMEDIA_SUCCESS) { SAMPLE_PRT("vi dev:%d sample ircut switch to normal failed .\n", vi_dev); } ircut_attr.status = SAMPLE_IRCUT_STATUS_NORMAL; } else if (ircut_attr.switch_status == SAMPLE_IRCUT_SWITCH_TO_IR) { SAMPLE_PRT("\nnormal -> ir \n"); ret = sample_ircut_switch_to_ir(board_type, vi_dev); if (ret != XMEDIA_SUCCESS) { SAMPLE_PRT("vi dev:%d sample ircut switch to ir failed .\n", vi_dev); } ircut_attr.status = SAMPLE_IRCUT_STATUS_IR; } } return XMEDIA_NULL; } static xmedia_s32 sample_ircut_auto_mode(sample_comm_board_type board_type, xmedia_s32 vi_dev) { xmedia_s32 ret = XMEDIA_SUCCESS; pthread_t thread_tid; sample_ircut_thread_param thread_param = {0}; g_force_exit = XMEDIA_FALSE; thread_param.board_type = board_type; thread_param.vi_dev = vi_dev; ret = pthread_create(&thread_tid, 0, sample_ircut_auto_thread, &thread_param); if (ret) { SAMPLE_PRT("sample ircut create pthread failed .\n"); return XMEDIA_FAILURE; } PAUSE(g_force_exit); g_force_exit = XMEDIA_TRUE; pthread_join(thread_tid, XMEDIA_NULL); return ret; } xmedia_void sample_ircut_handle_sig(xmedia_s32 signo) { if (SIGINT == signo || SIGTSTP == signo || SIGTERM == signo) { g_force_exit = XMEDIA_TRUE; } } int main(int argc,char **argv) { xmedia_s32 mode = 0; sample_comm_board_type board_type = 0; xmedia_s32 vi_dev = 0; xmedia_s32 status = 0; signal(SIGINT, sample_ircut_handle_sig); signal(SIGTERM, sample_ircut_handle_sig); if (argc < 4) { sample_ircut_usage(argv[0]); return 0; } mode = atoi(argv[1]); board_type = (sample_comm_board_type)atoi(argv[2]); vi_dev = atoi(argv[3]); if (vi_dev > VI_MAX_DEV_NUM) { SAMPLE_PRT("input vi dev num(%d) > vi max dev num(%d) .\n", vi_dev, VI_MAX_DEV_NUM); return 0; } if (argc == 5 && mode == SAMPLE_IRCUT_MANUAL_MODE) { status = !!atoi(argv[4]); sample_ircut_manual_mode(board_type, vi_dev, status); } else if (argc == 4 && mode == SAMPLE_IRCUT_CALIBRATION_MODE) { sample_ircut_calibration_mode(board_type, vi_dev); } else if (argc == 11 && mode == SAMPLE_IRCUT_AUTO_MODE) { g_ircut_attr[vi_dev].status = !!atoi(argv[4]); g_ircut_attr[vi_dev].normal_to_ir_iso_thr = atoi(argv[5]); g_ircut_attr[vi_dev].ir_to_normal_iso_thr = atoi(argv[6]); g_ircut_attr[vi_dev].rgmax = atoi(argv[7]); g_ircut_attr[vi_dev].rgmin = atoi(argv[8]); g_ircut_attr[vi_dev].bgmax = atoi(argv[9]); g_ircut_attr[vi_dev].bgmin = atoi(argv[10]); sample_ircut_auto_mode(board_type, vi_dev); } else { sample_ircut_usage(argv[0]); } return 0; }