xref: /aosp_15_r20/external/libopenapv/src/oapv_rc.c (revision abb65b4b03b69e1d508d4d9a44dcf199df16e7c3)
1*abb65b4bSAndroid Build Coastguard Worker /*
2*abb65b4bSAndroid Build Coastguard Worker  * Copyright (c) 2022 Samsung Electronics Co., Ltd.
3*abb65b4bSAndroid Build Coastguard Worker  * All Rights Reserved.
4*abb65b4bSAndroid Build Coastguard Worker  *
5*abb65b4bSAndroid Build Coastguard Worker  * Redistribution and use in source and binary forms, with or without
6*abb65b4bSAndroid Build Coastguard Worker  * modification, are permitted provided that the following conditions are met:
7*abb65b4bSAndroid Build Coastguard Worker  *
8*abb65b4bSAndroid Build Coastguard Worker  * - Redistributions of source code must retain the above copyright notice,
9*abb65b4bSAndroid Build Coastguard Worker  *   this list of conditions and the following disclaimer.
10*abb65b4bSAndroid Build Coastguard Worker  *
11*abb65b4bSAndroid Build Coastguard Worker  * - Redistributions in binary form must reproduce the above copyright notice,
12*abb65b4bSAndroid Build Coastguard Worker  *   this list of conditions and the following disclaimer in the documentation
13*abb65b4bSAndroid Build Coastguard Worker  *   and/or other materials provided with the distribution.
14*abb65b4bSAndroid Build Coastguard Worker  *
15*abb65b4bSAndroid Build Coastguard Worker  * - Neither the name of the copyright owner, nor the names of its contributors
16*abb65b4bSAndroid Build Coastguard Worker  *   may be used to endorse or promote products derived from this software
17*abb65b4bSAndroid Build Coastguard Worker  *   without specific prior written permission.
18*abb65b4bSAndroid Build Coastguard Worker  *
19*abb65b4bSAndroid Build Coastguard Worker  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20*abb65b4bSAndroid Build Coastguard Worker  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21*abb65b4bSAndroid Build Coastguard Worker  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22*abb65b4bSAndroid Build Coastguard Worker  * ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23*abb65b4bSAndroid Build Coastguard Worker  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24*abb65b4bSAndroid Build Coastguard Worker  * CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25*abb65b4bSAndroid Build Coastguard Worker  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26*abb65b4bSAndroid Build Coastguard Worker  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27*abb65b4bSAndroid Build Coastguard Worker  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28*abb65b4bSAndroid Build Coastguard Worker  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29*abb65b4bSAndroid Build Coastguard Worker  * POSSIBILITY OF SUCH DAMAGE.
30*abb65b4bSAndroid Build Coastguard Worker  */
31*abb65b4bSAndroid Build Coastguard Worker 
32*abb65b4bSAndroid Build Coastguard Worker #include "oapv_rc.h"
33*abb65b4bSAndroid Build Coastguard Worker 
oapve_rc_get_tile_cost(oapve_ctx_t * ctx,oapve_core_t * core,oapve_tile_t * tile)34*abb65b4bSAndroid Build Coastguard Worker int oapve_rc_get_tile_cost(oapve_ctx_t* ctx, oapve_core_t* core, oapve_tile_t* tile)
35*abb65b4bSAndroid Build Coastguard Worker {
36*abb65b4bSAndroid Build Coastguard Worker     int sum = 0;
37*abb65b4bSAndroid Build Coastguard Worker     tile->rc.number_pixel = 0;
38*abb65b4bSAndroid Build Coastguard Worker     for (int c = Y_C; c < ctx->num_comp; c++)
39*abb65b4bSAndroid Build Coastguard Worker     {
40*abb65b4bSAndroid Build Coastguard Worker         int step_w = 8 << ctx->comp_sft[c][0];
41*abb65b4bSAndroid Build Coastguard Worker         int step_h = 8 << ctx->comp_sft[c][1];
42*abb65b4bSAndroid Build Coastguard Worker         for (int y = 0; y < tile->h; y += step_h)
43*abb65b4bSAndroid Build Coastguard Worker         {
44*abb65b4bSAndroid Build Coastguard Worker             for (int x = 0; x < tile->w; x += step_w)
45*abb65b4bSAndroid Build Coastguard Worker             {
46*abb65b4bSAndroid Build Coastguard Worker                 int tx = tile->x + x;
47*abb65b4bSAndroid Build Coastguard Worker                 int ty = tile->y + y;
48*abb65b4bSAndroid Build Coastguard Worker 
49*abb65b4bSAndroid Build Coastguard Worker                 ctx->fn_imgb_to_block_rc(ctx->imgb, c, tx, ty, 8, 8, core->coef);
50*abb65b4bSAndroid Build Coastguard Worker                 sum += ctx->fn_had8x8(core->coef, 8);
51*abb65b4bSAndroid Build Coastguard Worker                 tile->rc.number_pixel += 64;
52*abb65b4bSAndroid Build Coastguard Worker             }
53*abb65b4bSAndroid Build Coastguard Worker         }
54*abb65b4bSAndroid Build Coastguard Worker     }
55*abb65b4bSAndroid Build Coastguard Worker 
56*abb65b4bSAndroid Build Coastguard Worker     tile->rc.cost = sum;
57*abb65b4bSAndroid Build Coastguard Worker 
58*abb65b4bSAndroid Build Coastguard Worker     return OAPV_OK;
59*abb65b4bSAndroid Build Coastguard Worker }
60*abb65b4bSAndroid Build Coastguard Worker 
get_tile_cost_thread(void * arg)61*abb65b4bSAndroid Build Coastguard Worker int get_tile_cost_thread(void* arg)
62*abb65b4bSAndroid Build Coastguard Worker {
63*abb65b4bSAndroid Build Coastguard Worker     oapve_core_t* core = (oapve_core_t*)arg;
64*abb65b4bSAndroid Build Coastguard Worker     oapve_ctx_t* ctx = core->ctx;
65*abb65b4bSAndroid Build Coastguard Worker     oapve_tile_t* tile = ctx->tile;
66*abb65b4bSAndroid Build Coastguard Worker     int tidx = 0, ret = OAPV_OK, i;
67*abb65b4bSAndroid Build Coastguard Worker 
68*abb65b4bSAndroid Build Coastguard Worker     while (1) {
69*abb65b4bSAndroid Build Coastguard Worker         // find not processed tile
70*abb65b4bSAndroid Build Coastguard Worker         oapv_tpool_enter_cs(ctx->sync_obj);
71*abb65b4bSAndroid Build Coastguard Worker         for (i = 0; i < ctx->num_tiles; i++)
72*abb65b4bSAndroid Build Coastguard Worker         {
73*abb65b4bSAndroid Build Coastguard Worker             if (tile[i].stat == ENC_TILE_STAT_NOT_ENCODED)
74*abb65b4bSAndroid Build Coastguard Worker             {
75*abb65b4bSAndroid Build Coastguard Worker                 tile[i].stat = ENC_TILE_STAT_ON_ENCODING;
76*abb65b4bSAndroid Build Coastguard Worker                 tidx = i;
77*abb65b4bSAndroid Build Coastguard Worker                 break;
78*abb65b4bSAndroid Build Coastguard Worker             }
79*abb65b4bSAndroid Build Coastguard Worker         }
80*abb65b4bSAndroid Build Coastguard Worker         oapv_tpool_leave_cs(ctx->sync_obj);
81*abb65b4bSAndroid Build Coastguard Worker         if (i == ctx->num_tiles)
82*abb65b4bSAndroid Build Coastguard Worker         {
83*abb65b4bSAndroid Build Coastguard Worker             break;
84*abb65b4bSAndroid Build Coastguard Worker         }
85*abb65b4bSAndroid Build Coastguard Worker 
86*abb65b4bSAndroid Build Coastguard Worker         ret = oapve_rc_get_tile_cost(ctx, core, &tile[tidx]);
87*abb65b4bSAndroid Build Coastguard Worker         oapv_assert_g(OAPV_SUCCEEDED(ret), ERR);
88*abb65b4bSAndroid Build Coastguard Worker 
89*abb65b4bSAndroid Build Coastguard Worker         oapv_tpool_enter_cs(ctx->sync_obj);
90*abb65b4bSAndroid Build Coastguard Worker         tile[tidx].stat = ENC_TILE_STAT_ENCODED;
91*abb65b4bSAndroid Build Coastguard Worker         oapv_tpool_leave_cs(ctx->sync_obj);
92*abb65b4bSAndroid Build Coastguard Worker     }
93*abb65b4bSAndroid Build Coastguard Worker ERR:
94*abb65b4bSAndroid Build Coastguard Worker     return ret;
95*abb65b4bSAndroid Build Coastguard Worker }
96*abb65b4bSAndroid Build Coastguard Worker 
oapve_rc_get_tile_cost_thread(oapve_ctx_t * ctx,u64 * sum)97*abb65b4bSAndroid Build Coastguard Worker int oapve_rc_get_tile_cost_thread(oapve_ctx_t* ctx, u64* sum)
98*abb65b4bSAndroid Build Coastguard Worker {
99*abb65b4bSAndroid Build Coastguard Worker     for (int i = 0; i < ctx->num_tiles; i++) {
100*abb65b4bSAndroid Build Coastguard Worker         ctx->tile[i].stat = ENC_TILE_STAT_NOT_ENCODED;
101*abb65b4bSAndroid Build Coastguard Worker     }
102*abb65b4bSAndroid Build Coastguard Worker 
103*abb65b4bSAndroid Build Coastguard Worker     oapv_tpool_t* tpool = ctx->tpool;
104*abb65b4bSAndroid Build Coastguard Worker     int parallel_task = (ctx->cdesc.threads > ctx->num_tiles) ? ctx->num_tiles : ctx->cdesc.threads;
105*abb65b4bSAndroid Build Coastguard Worker 
106*abb65b4bSAndroid Build Coastguard Worker     // run new threads
107*abb65b4bSAndroid Build Coastguard Worker     int tidx = 0;
108*abb65b4bSAndroid Build Coastguard Worker     for (tidx = 0; tidx < (parallel_task - 1); tidx++) {
109*abb65b4bSAndroid Build Coastguard Worker         tpool->run(ctx->thread_id[tidx], get_tile_cost_thread, (void*)ctx->core[tidx]);
110*abb65b4bSAndroid Build Coastguard Worker     }
111*abb65b4bSAndroid Build Coastguard Worker     // use main thread
112*abb65b4bSAndroid Build Coastguard Worker     int ret = get_tile_cost_thread((void*)ctx->core[tidx]);
113*abb65b4bSAndroid Build Coastguard Worker     oapv_assert_rv(OAPV_SUCCEEDED(ret), ret);
114*abb65b4bSAndroid Build Coastguard Worker 
115*abb65b4bSAndroid Build Coastguard Worker     for (int thread_num1 = 0; thread_num1 < parallel_task - 1; thread_num1++) {
116*abb65b4bSAndroid Build Coastguard Worker         int res = tpool->join(ctx->thread_id[thread_num1], &ret);
117*abb65b4bSAndroid Build Coastguard Worker         oapv_assert_rv(res == TPOOL_SUCCESS, ret);
118*abb65b4bSAndroid Build Coastguard Worker         oapv_assert_rv(OAPV_SUCCEEDED(ret), ret);
119*abb65b4bSAndroid Build Coastguard Worker     }
120*abb65b4bSAndroid Build Coastguard Worker 
121*abb65b4bSAndroid Build Coastguard Worker     *sum = 0;
122*abb65b4bSAndroid Build Coastguard Worker     for (int i = 0; i < ctx->num_tiles; i++)
123*abb65b4bSAndroid Build Coastguard Worker     {
124*abb65b4bSAndroid Build Coastguard Worker         *sum += ctx->tile[i].rc.cost;
125*abb65b4bSAndroid Build Coastguard Worker         ctx->tile[i].stat = ENC_TILE_STAT_NOT_ENCODED;
126*abb65b4bSAndroid Build Coastguard Worker     }
127*abb65b4bSAndroid Build Coastguard Worker 
128*abb65b4bSAndroid Build Coastguard Worker     return ret;
129*abb65b4bSAndroid Build Coastguard Worker }
130*abb65b4bSAndroid Build Coastguard Worker 
rc_calculate_lambda(double alpha,double beta,double cost_pixel,double bits_pixel)131*abb65b4bSAndroid Build Coastguard Worker static double rc_calculate_lambda(double alpha, double beta, double cost_pixel, double bits_pixel)
132*abb65b4bSAndroid Build Coastguard Worker {
133*abb65b4bSAndroid Build Coastguard Worker     return ((alpha / 256.0) * pow(cost_pixel / bits_pixel, beta));
134*abb65b4bSAndroid Build Coastguard Worker }
135*abb65b4bSAndroid Build Coastguard Worker 
oapve_rc_estimate_pic_lambda(oapve_ctx_t * ctx,double cost)136*abb65b4bSAndroid Build Coastguard Worker double oapve_rc_estimate_pic_lambda(oapve_ctx_t* ctx, double cost)
137*abb65b4bSAndroid Build Coastguard Worker {
138*abb65b4bSAndroid Build Coastguard Worker     int num_pixel = ctx->w * ctx->h;
139*abb65b4bSAndroid Build Coastguard Worker     for (int c = 1; c < ctx->num_comp; c++)
140*abb65b4bSAndroid Build Coastguard Worker     {
141*abb65b4bSAndroid Build Coastguard Worker         num_pixel += (ctx->w * ctx->h) >> (ctx->comp_sft[c][0] + ctx->comp_sft[c][1]);
142*abb65b4bSAndroid Build Coastguard Worker     }
143*abb65b4bSAndroid Build Coastguard Worker 
144*abb65b4bSAndroid Build Coastguard Worker     double alpha = ctx->rc_param.alpha;
145*abb65b4bSAndroid Build Coastguard Worker     double beta = ctx->rc_param.beta;
146*abb65b4bSAndroid Build Coastguard Worker     double bpp = ((double)ctx->param->bitrate * 1000) / ((double)num_pixel * ((double)ctx->param->fps_num / ctx->param->fps_den));
147*abb65b4bSAndroid Build Coastguard Worker 
148*abb65b4bSAndroid Build Coastguard Worker     double est_lambda = rc_calculate_lambda(alpha, beta, pow(cost / (double)num_pixel, OAPV_RC_BETA), bpp);
149*abb65b4bSAndroid Build Coastguard Worker     est_lambda = oapv_clip3(0.1, 10000.0, est_lambda);
150*abb65b4bSAndroid Build Coastguard Worker     const int lambda_prec = 1000000;
151*abb65b4bSAndroid Build Coastguard Worker 
152*abb65b4bSAndroid Build Coastguard Worker     est_lambda = (double)((s64)(est_lambda * (double)lambda_prec + 0.5)) / (double)lambda_prec;
153*abb65b4bSAndroid Build Coastguard Worker 
154*abb65b4bSAndroid Build Coastguard Worker     return est_lambda;
155*abb65b4bSAndroid Build Coastguard Worker }
156*abb65b4bSAndroid Build Coastguard Worker 
oapve_rc_estimate_pic_qp(double lambda)157*abb65b4bSAndroid Build Coastguard Worker int oapve_rc_estimate_pic_qp(double lambda)
158*abb65b4bSAndroid Build Coastguard Worker {
159*abb65b4bSAndroid Build Coastguard Worker     int qp = (int)(4.2005 * log(lambda) + 13.7122 + 0.5) + OAPV_RC_QP_OFFSET;
160*abb65b4bSAndroid Build Coastguard Worker     qp = oapv_clip3(MIN_QUANT, MAX_QUANT, qp);
161*abb65b4bSAndroid Build Coastguard Worker     return qp;
162*abb65b4bSAndroid Build Coastguard Worker }
163*abb65b4bSAndroid Build Coastguard Worker 
oapve_rc_get_qp(oapve_ctx_t * ctx,oapve_tile_t * tile,int frame_qp,int * qp)164*abb65b4bSAndroid Build Coastguard Worker void oapve_rc_get_qp(oapve_ctx_t* ctx, oapve_tile_t* tile, int frame_qp, int* qp)
165*abb65b4bSAndroid Build Coastguard Worker {
166*abb65b4bSAndroid Build Coastguard Worker     double   alpha = ctx->rc_param.alpha;
167*abb65b4bSAndroid Build Coastguard Worker     double   beta = ctx->rc_param.beta;
168*abb65b4bSAndroid Build Coastguard Worker 
169*abb65b4bSAndroid Build Coastguard Worker     double cost_pixel = tile->rc.cost / (double)tile->rc.number_pixel;
170*abb65b4bSAndroid Build Coastguard Worker     cost_pixel = pow(cost_pixel, OAPV_RC_BETA);
171*abb65b4bSAndroid Build Coastguard Worker 
172*abb65b4bSAndroid Build Coastguard Worker     double bit_pixel =  (double)tile->rc.target_bits / (double)tile->rc.number_pixel;
173*abb65b4bSAndroid Build Coastguard Worker     double est_lambda = rc_calculate_lambda(alpha, beta, cost_pixel, bit_pixel);
174*abb65b4bSAndroid Build Coastguard Worker 
175*abb65b4bSAndroid Build Coastguard Worker     int min_qp = frame_qp - 2 - OAPV_RC_QP_OFFSET;
176*abb65b4bSAndroid Build Coastguard Worker     int max_qp = frame_qp + 2 - OAPV_RC_QP_OFFSET;
177*abb65b4bSAndroid Build Coastguard Worker 
178*abb65b4bSAndroid Build Coastguard Worker     double max_lambda = exp(((double)(max_qp + 0.49) - 13.7122) / 4.2005);
179*abb65b4bSAndroid Build Coastguard Worker     double min_lambda = exp(((double)(min_qp - 0.49) - 13.7122) / 4.2005);
180*abb65b4bSAndroid Build Coastguard Worker 
181*abb65b4bSAndroid Build Coastguard Worker     const int LAMBDA_PREC = 1000000;
182*abb65b4bSAndroid Build Coastguard Worker     est_lambda = oapv_clip3(min_lambda, max_lambda, est_lambda);
183*abb65b4bSAndroid Build Coastguard Worker     est_lambda = (double)((s64)(est_lambda * (double)LAMBDA_PREC + 0.5)) / (double)LAMBDA_PREC;
184*abb65b4bSAndroid Build Coastguard Worker     *qp = (int)(4.2005 * log(est_lambda) + 13.7122 + 0.5);
185*abb65b4bSAndroid Build Coastguard Worker     *qp = oapv_clip3(min_qp, max_qp, *qp);
186*abb65b4bSAndroid Build Coastguard Worker     *qp += OAPV_RC_QP_OFFSET;
187*abb65b4bSAndroid Build Coastguard Worker 
188*abb65b4bSAndroid Build Coastguard Worker }
189*abb65b4bSAndroid Build Coastguard Worker 
oapve_rc_update_after_pic(oapve_ctx_t * ctx,double cost)190*abb65b4bSAndroid Build Coastguard Worker void oapve_rc_update_after_pic(oapve_ctx_t* ctx, double cost)
191*abb65b4bSAndroid Build Coastguard Worker {
192*abb65b4bSAndroid Build Coastguard Worker     int num_pixel = ctx->w * ctx->h;
193*abb65b4bSAndroid Build Coastguard Worker     for (int c = 1; c < ctx->num_comp; c++)
194*abb65b4bSAndroid Build Coastguard Worker     {
195*abb65b4bSAndroid Build Coastguard Worker         num_pixel += (ctx->w * ctx->h) >> (ctx->comp_sft[c][0] + ctx->comp_sft[c][1]);
196*abb65b4bSAndroid Build Coastguard Worker     }
197*abb65b4bSAndroid Build Coastguard Worker 
198*abb65b4bSAndroid Build Coastguard Worker     int total_bits = 0;
199*abb65b4bSAndroid Build Coastguard Worker     for (int i = 0; i < ctx->num_tiles; i++)
200*abb65b4bSAndroid Build Coastguard Worker     {
201*abb65b4bSAndroid Build Coastguard Worker         total_bits += ctx->fh.tile_size[i] * 8;
202*abb65b4bSAndroid Build Coastguard Worker     }
203*abb65b4bSAndroid Build Coastguard Worker 
204*abb65b4bSAndroid Build Coastguard Worker     double ln_bpp = log(pow(cost / (double)num_pixel, OAPV_RC_BETA));
205*abb65b4bSAndroid Build Coastguard Worker     double diff_lambda = (ctx->rc_param.beta) * (log((double)total_bits) - log(((double)ctx->param->bitrate * 1000 / ((double)ctx->param->fps_num / ctx->param->fps_den))));
206*abb65b4bSAndroid Build Coastguard Worker 
207*abb65b4bSAndroid Build Coastguard Worker     diff_lambda = oapv_clip3(-0.125, 0.125, 0.25 * diff_lambda);
208*abb65b4bSAndroid Build Coastguard Worker     ctx->rc_param.alpha = (ctx->rc_param.alpha) * exp(diff_lambda);
209*abb65b4bSAndroid Build Coastguard Worker     ctx->rc_param.beta = (ctx->rc_param.beta) + diff_lambda / ln_bpp;
210*abb65b4bSAndroid Build Coastguard Worker }
211