blob: 7e0a961dea36b8861f2e023041d978c50d164bce [file] [log] [blame]
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
*/
#include "vpp_pq.h"
#include <linux/types.h>
#include <linux/amlogic/media/amvecm/amvecm.h>
/*BLUE_SCENE default 0*/
/*GREEN_SCENE default 0*/
/*SKIN_TONE_SCENE default 0*/
/*PEAKING_SCENE default 100*/
/*SATURATION_SCENE default 30*/
/*DYNAMIC_CONTRAST_SCENE default 0*/
/*NOISE_SCENE default 0*/
/*
* vpp_pq
* 0 faceskin
* 1 bluesky
* 2 food
* 3 architecture
* 4 grass
* 5 nightscop
* 6 waterside
* 7 flowers
* 8 breads
* 9 fruits
* 10 meats
* 11 document
* 12 ocean
* 13 pattern
* 14 group
* 15 animals
* 16 iceskate
* 17 leaves
* 18 racetrack
* 19 fireworks
* 20 waterfall
* 21 beach
* 22 snows
* 23 sunset
* 24 default setting
*/
int vpp_pq_data[AI_SCENES_MAX][SCENES_VALUE] = {
{0, 0, 25, 15, 15, 0, 0, 0, 0, 0},/*faceskin*/
{30, 0, 0, 0, 10, 0, 0, 0, 0, 0},/*bluesky*/
{0, 0, 0, 15, 20, 0, 0, 0, 0, 0},/*foods*/
{0, 0, 0, 25, 0, 2, 0, 0, 0, 0},/*architecture*/
{0, 30, 0, 15, 10, 0, 0, 0, 0, 0},/*grass*/
{0, 0, 0, 0, 0, 3, 0, 0, 0, 0},/*nightscop*/
{0, 0, 0, 20, 0, 2, 0, 0, 0, 0},/*document*/
{0, 0, 0, 100, 30, 0, 0, 0, 0, 0},
{0, 0, 0, 100, 70, 0, 0, 0, 0, 0},
{0, 0, 0, 100, 70, 0, 0, 0, 0, 0},
{0, 0, 0, 100, 30, 0, 0, 0, 0, 0},
{0, 0, 0, 100, 30, 0, 0, 0, 0, 0},
{0, 80, 0, 100, 30, 0, 0, 0, 0, 0},
{0, 0, 0, 100, 30, 0, 0, 0, 0, 0},
{0, 80, 0, 100, 30, 0, 0, 0, 0, 0},
{0, 0, 0, 100, 30, 0, 0, 0, 0, 0},
{0, 0, 0, 100, 30, 0, 0, 0, 0, 0},
{0, 0, 0, 100, 30, 0, 0, 0, 0, 0},
{0, 0, 0, 100, 30, 0, 0, 0, 0, 0},
{0, 0, 0, 100, 30, 0, 0, 0, 0, 0},
{0, 0, 0, 100, 30, 0, 0, 0, 0, 0},
{0, 0, 0, 100, 30, 0, 0, 0, 0, 0},
{0, 0, 0, 100, 30, 0, 0, 0, 0, 0},
{0, 0, 0, 100, 30, 0, 0, 0, 0, 0},
{0, 0, 0, 100, 30, 0, 0, 0, 0, 0}
};
static unsigned int det_stb_cnt = 30;
static unsigned int det_unstb_cnt = 20;
static unsigned int tolrnc_cnt = 6;
static unsigned int timer_filter_en;
/*aipq policy:
* 0 default policy from algorithm, owner gumin
* 1: use top 3 blend offset, with timer filter which can select as policy
*/
static unsigned int aipq_set_policy;
static unsigned int color_th = 100;
/*scene_prob[0]: scene, scene_prob[1]: prob*/
int scene_prob[2] = {0, 0};
struct ai_pq_hist_data aipq_hist_data = {
.pre_skin_pct = 0,
.pre_green_pct = 0,
.pre_blue_pct = 0,
.cur_skin_pct = 0,
.cur_green_pct = 0,
.cur_blue_pct = 0
};
enum iir_policy_e aipq_tiir_policy_proc(int (*prob)[2], int sc_chg,
int *pq_debug, int *kp_flag)
{
static int stable_cnt, unstb_cnt;
static int pre_det_sc = -1, pre_det_sec = -1, pre_det_thd = -1;
enum iir_policy_e policy, ret_plcy;
int prob_sum_2 = 0, prob_sum_3 = 0;
static enum aipq_state_mach state_mach = AIPQ_IDLE;
int i;
for (i = 0; i < 3; i++) {
prob_sum_3 += prob[i][1];
if (i < 2)
prob_sum_2 += prob[i][1];
}
if ((pre_det_sc == prob[0][0] && prob[0][1] >= 5000) ||
(pre_det_sc == prob[0][0] && pre_det_sec == prob[1][0] &&
prob_sum_2 >= 7000) ||
(pre_det_sc == prob[0][0] && pre_det_sec == prob[1][0] &&
pre_det_thd == prob[2][0] && prob_sum_3 >= 8000)) {
policy = SC_DETECTED;
} else {
policy = SC_INVALID;
}
switch (state_mach) {
case AIPQ_IDLE:
if (policy == SC_DETECTED) {
stable_cnt++;
unstb_cnt = 0;
state_mach++;
}
/*set pre detected scene*/
pre_det_sc = prob[0][0];
pre_det_sec = prob[1][0];
pre_det_thd = prob[2][0];
ret_plcy = SC_INVALID;
break;
case AIPQ_DET_UNSTABLE:
if (policy == SC_DETECTED)
stable_cnt++;
else
unstb_cnt++;
det_stb_cnt = get_stb_cnt();
tolrnc_cnt = get_tolrnc_cnt();
if (unstb_cnt >= tolrnc_cnt) {
state_mach--;
unstb_cnt = 0;
stable_cnt = 0;
} else if (stable_cnt >= det_stb_cnt) {
state_mach++;
unstb_cnt = 0;
}
ret_plcy = SC_INVALID;
break;
case AIPQ_DET_STATBLE:
if (policy == SC_INVALID) {
unstb_cnt++;
*kp_flag = 1;
} else {
if (unstb_cnt > 0)
unstb_cnt--;
}
det_unstb_cnt = get_unstb_cnt();
if (unstb_cnt >= det_unstb_cnt) {
state_mach = AIPQ_IDLE;
stable_cnt = 0;
unstb_cnt = 0;
}
ret_plcy = SC_DETECTED;
break;
default:
ret_plcy = SC_INVALID;
break;
}
if (pq_debug[2] > 0x10)
pr_info("%s: cur policy = %d, stable_cnt = %d, unstable_cnt = %d, iir policy = %d\n",
__func__, policy, stable_cnt, unstb_cnt, ret_plcy);
return ret_plcy;
}
int aipq_scs_bld_proc(int (*cfg)[SCENES_VALUE], int (*prob)[2],
int *out, int *pq_debug)
{
int i, j;
int a = 0;
int m;
int sc[3];
int sc_pr[3];
enum iir_policy_e policy;
static int pre_out[SCENES_VALUE];
int kp_flag = 0;
memset(out, 0, sizeof(int) * SCENES_VALUE);
timer_filter_en = get_timer_filter_en();
if (!timer_filter_en) {
/*prob 10000 as 1.0*/
if (prob[0][1] >= 8000) {
m = prob[0][0];
memcpy(out, cfg[m], sizeof(int) * SCENES_VALUE);
} else {
for (i = 0; i < 3; i++)
a += prob[i][1];
if (a >= 4500 && prob[0][1] >= 3000) {
for (i = 0; i < 3; i++) {
sc[i] = prob[i][0];
sc_pr[i] = prob[i][1] << 10;
sc_pr[i] = div64_s64(sc_pr[i], a);
}
for (i = 0; i < 3; i++) {
for (j = 0; j < SCENE_MAX; j++)
out[j] +=
(*(cfg + sc[i]))[j] * sc_pr[i] >> 10;
}
} else {
if (pq_debug[2] > 0x10)
pr_info("sum of top3 prob < 50 percent or top1 prob < 30 per\n");
}
}
return 0;
}
policy = aipq_tiir_policy_proc(prob, 0, pq_debug, &kp_flag);
switch (policy) {
case SC_DETECTED:
if (kp_flag) {
memcpy(out, pre_out, sizeof(int) * SCENES_VALUE);
if (pq_debug[2] > 0x10)
pr_info("same policy, keep setting\n");
break;
}
/*prob 10000 as 1.0*/
if (prob[0][1] >= 8000) {
m = prob[0][0];
memcpy(out, cfg[m], sizeof(int) * SCENES_VALUE);
} else {
for (i = 0; i < 3; i++)
a += prob[i][1];
for (i = 0; i < 3; i++) {
sc[i] = prob[i][0];
sc_pr[i] = prob[i][1] << 10;
sc_pr[i] = div64_s64(sc_pr[i], a);
}
for (i = 0; i < 3; i++) {
for (j = 0; j < SCENE_MAX; j++)
out[j] +=
(*(cfg + sc[i]))[j] * sc_pr[i] >> 10;
}
}
memcpy(pre_out, out, sizeof(int) * SCENES_VALUE);
if (pq_debug[2] > 0x10) {
pr_info("top1 prob = %d: bld value: %d, %d, %d, %d, %d, %d, %d\n",
prob[0][1], out[0], out[1], out[2], out[3],
out[4], out[5], out[6]);
}
break;
case SC_INVALID:
if (pq_debug[2] > 0x10)
pr_info("detected unstable: skip aipq seeting\n");
break;
default:
break;
}
return 0;
}
void aipq_scs_proc(struct vframe_s *vf,
int (*cfg)[SCENES_VALUE],
int (*prob)[2],
int *out,
int *pq_debug)
{
static int pre_top_one = -1;
int top_one, top_one_prob;
int top_two, top_two_prob;
int top_three, top_three_prob;
/*select color: skin/ green/ blue, percent : 1000 as 1.0*/
static unsigned int pre_skin_pct;
static unsigned int pre_green_pct;
static unsigned int pre_blue_pct;
unsigned int cur_total_hist = 1, cur_skin_pct, cur_green_pct, cur_blue_pct;
u64 cur_skin_hist = 0, cur_green_hist = 0, cur_blue_hist = 0;
unsigned int diff_skin_pct, diff_green_pct, diff_blue_pct;
int i;
static int pre_hist[32];
memset(out, 0, sizeof(int) * SCENES_VALUE);
top_one = prob[0][0];
top_one_prob = prob[0][1];
top_two = prob[1][0];
top_two_prob = prob[1][1];
top_three = prob[2][0];
top_three_prob = prob[2][1];
for (i = 0; i < 3; i++)
cur_skin_hist += vf->prop.hist.vpp_hue_gamma[11 + i];
for (i = 0; i < 5; i++)
cur_green_hist += vf->prop.hist.vpp_hue_gamma[18 + i];
for (i = 0; i < 5; i++)
cur_blue_hist += vf->prop.hist.vpp_hue_gamma[27 + i];
for (i = 0; i < 32; i++)
cur_total_hist += vf->prop.hist.vpp_hue_gamma[i];
cur_skin_pct = div64_u64(cur_skin_hist * 1000, cur_total_hist);
cur_green_pct = div64_u64(cur_green_hist * 1000, cur_total_hist);
cur_blue_pct = div64_u64(cur_blue_hist * 1000, cur_total_hist);
aipq_hist_data.cur_skin_pct = cur_skin_pct;
aipq_hist_data.cur_blue_pct = cur_blue_pct;
aipq_hist_data.cur_green_pct = cur_green_pct;
diff_skin_pct = (cur_skin_pct > pre_skin_pct) ?
(cur_skin_pct - pre_skin_pct) :
(pre_skin_pct - cur_skin_pct);
diff_green_pct = (cur_green_pct > pre_green_pct) ?
(cur_green_pct - pre_green_pct) :
(pre_green_pct - cur_green_pct);
diff_blue_pct = (cur_blue_pct > pre_blue_pct) ?
(cur_blue_pct - pre_blue_pct) :
(pre_blue_pct - cur_blue_pct);
color_th = get_color_th();
if (pre_top_one == top_one) {
memcpy(out, cfg[pre_top_one], sizeof(int) * SCENES_VALUE);
scene_prob[0] = top_one;
scene_prob[1] = top_one_prob;
} else if (((pre_top_one == top_two) && (top_two_prob > 1000)) ||
((pre_top_one == top_three) && (top_three_prob > 1000))) {
memcpy(out, cfg[pre_top_one], sizeof(int) * SCENES_VALUE);
if (pre_top_one == top_two) {
scene_prob[0] = top_two;
scene_prob[1] = top_two_prob;
} else {
scene_prob[0] = top_three;
scene_prob[1] = top_three_prob;
}
} else if ((diff_skin_pct + diff_green_pct + diff_blue_pct < color_th) &&
(pre_top_one >= 0)) {
memcpy(out, cfg[pre_top_one], sizeof(int) * SCENES_VALUE);
} else if ((top_one == 1) && (pre_top_one == 3) && (pre_blue_pct > 500) &&
(pre_blue_pct < cur_blue_pct)) {
memcpy(out, cfg[pre_top_one], sizeof(int) * SCENES_VALUE);
} else {
if (pq_debug[2] == 0x8) {
pr_info("pre_top_one = %d, top_one = %d, top_one_prob = %d, diff_skin_pct = %d, diff_green_pct = %d, diff_blue_pct = %d\n",
pre_top_one, top_one, top_one_prob,
diff_skin_pct, diff_green_pct, diff_blue_pct);
for (i = 0; i < 4; i++)
pr_info("pre: %d, %d, %d, %d, %d, %d, %d, %d\n",
pre_hist[i * 8],
pre_hist[i * 8 + 1],
pre_hist[i * 8 + 2],
pre_hist[i * 8 + 3],
pre_hist[i * 8 + 4],
pre_hist[i * 8 + 5],
pre_hist[i * 8 + 6],
pre_hist[i * 8 + 7]);
for (i = 0; i < 4; i++)
pr_info("cur: %d, %d, %d, %d, %d, %d, %d, %d\n",
vf->prop.hist.vpp_hue_gamma[i * 8],
vf->prop.hist.vpp_hue_gamma[i * 8 + 1],
vf->prop.hist.vpp_hue_gamma[i * 8 + 2],
vf->prop.hist.vpp_hue_gamma[i * 8 + 3],
vf->prop.hist.vpp_hue_gamma[i * 8 + 4],
vf->prop.hist.vpp_hue_gamma[i * 8 + 5],
vf->prop.hist.vpp_hue_gamma[i * 8 + 6],
vf->prop.hist.vpp_hue_gamma[i * 8 + 7]);
}
memcpy(out, cfg[top_one], sizeof(int) * SCENES_VALUE);
pre_top_one = top_one;
scene_prob[0] = top_one;
scene_prob[1] = top_one_prob;
}
for (i = 0; i < 32; i++)
pre_hist[i] = vf->prop.hist.vpp_hue_gamma[i];
if (pq_debug[2] > 0x10)
pr_info("pre_top_one = %d, diff_skin_pct = %d, diff_green_pct = %d, diff_blue_pct = %d\n",
pre_top_one, diff_skin_pct,
diff_green_pct, diff_blue_pct);
pre_skin_pct = cur_skin_pct;
pre_green_pct = cur_green_pct;
pre_blue_pct = cur_blue_pct;
aipq_hist_data.pre_skin_pct = pre_skin_pct;
aipq_hist_data.pre_green_pct = pre_green_pct;
aipq_hist_data.pre_blue_pct = pre_blue_pct;
}
void vf_pq_process(struct vframe_s *vf,
struct ai_scenes_pq *vpp_scenes,
int *pq_debug)
{
int pq_value;
int value;
int i = 0;
int prob[3][2];
int bld_ofst[SCENES_VALUE];
static int en_flag;
if (vf->ai_pq_enable && !en_flag)
en_flag = 1;
if (!en_flag) {
if (pq_debug[2] == 0x1)
pr_info("vf->ai_pq_enable = %d\n", vf->ai_pq_enable);
return;
}
if (en_flag) {
if (!vf->ai_pq_enable) {
i = 0;
while (i < SCENE_MAX) {
detected_scenes[i].func(0, 0);
i++;
}
en_flag = 0;
scene_prob[0] = 0;
scene_prob[1] = 0;
if (pq_debug[2] == 0x1)
pr_info("disable nn detect\n");
}
}
pq_value = vf->nn_value[0].maxclass;
for (i = 0; i < 3; i++) {
prob[i][0] = vf->nn_value[i].maxclass;
prob[i][1] = vf->nn_value[i].maxprob;
if (pq_debug[2] > 0x10)
pr_info("classi top%d= %d: prob = %d\n",
i + 1, prob[i][0], prob[i][1]);
}
if (pq_debug[0] != -1)
pq_value = pq_debug[0];
if (vf->nn_value[0].maxprob == 0 && pq_debug[0] == -1)
return;
if (pq_debug[1])
pq_value = 23;
aipq_set_policy = get_aipq_set_policy();
if (aipq_set_policy)
aipq_scs_bld_proc(vpp_pq_data, prob, bld_ofst, pq_debug);
else
aipq_scs_proc(vf, vpp_pq_data, prob, bld_ofst, pq_debug);
if (pq_debug[2] == 0x1)
pr_info("top5:%d,%d; %d,%d; %d,%d; %d,%d; %d,%d;\n",
vf->nn_value[0].maxclass, vf->nn_value[0].maxprob,
vf->nn_value[1].maxclass, vf->nn_value[1].maxprob,
vf->nn_value[2].maxclass, vf->nn_value[2].maxprob,
vf->nn_value[3].maxclass, vf->nn_value[3].maxprob,
vf->nn_value[4].maxclass, vf->nn_value[4].maxprob);
i = 0;
while (i < SCENE_MAX) {
vpp_scenes[pq_value].pq_scenes = pq_value;
if (pq_debug[3]) {
detected_scenes[i].func(bld_ofst[i], 1);
} else {
value = vpp_scenes[pq_value].pq_values[i];
detected_scenes[i].func(value, 1);
}
i++;
}
}