1 /*
2 * Copyright 2021 Rockchip Electronics Co. LTD
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define MODULE_TAG "enc_roi_utils"
18
19 #include <string.h>
20
21 #include "rk_type.h"
22
23 #include "mpp_env.h"
24 #include "mpp_mem.h"
25 #include "mpp_soc.h"
26 #include "mpp_common.h"
27 #include "mpp_debug.h"
28
29 #include "mpp_enc_roi_utils.h"
30
31 #define VEPU541_MAX_ROI_NUM 8
32 #define CU_BASE_CFG_BYTE 64
33 #define CU_QP_CFG_BYTE 192
34
35 typedef enum RoiType_e {
36 ROI_TYPE_AUTO = -2,
37 ROI_TYPE_NONE = -1,
38 ROI_TYPE_0 = 0, /* vepu roi, not support yet */
39 ROI_TYPE_1 = 1, /* rv1109/rk3566/rk3568 roi */
40 ROI_TYPE_2 = 2, /* rk3588 roi */
41
42 /* legacy */
43 ROI_TYPE_LEGACY = 0x10, /* legacy region config way */
44 ROI_TYPE_BUTT,
45 } RoiType;
46
47 typedef struct Vepu541RoiCfg_t {
48 /*
49 * Force_intra
50 * 1 - The corresponding 16x16cu is forced to be intra
51 * 0 - Not force to intra
52 */
53 RK_U16 force_intra : 1;
54 RK_U16 reserved : 3;
55 /*
56 * Qp area index
57 * The choosed qp area index.
58 */
59 RK_U16 qp_area_idx : 3;
60 /*
61 * Area qp limit function enable flag
62 * Force to be true in vepu541
63 */
64 RK_U16 qp_area_en : 1;
65 /*
66 * Qp_adj
67 * Qp_adj
68 * in absolute qp mode qp_adj is the final qp used by encoder
69 * in relative qp mode qp_adj is a adjustment to final qp
70 */
71 RK_S16 qp_adj : 7;
72 /*
73 * Qp_adj_mode
74 * Qp adjustment mode
75 * 1 - absolute qp mode:
76 * the 16x16 MB qp is set to the qp_adj value
77 * 0 - relative qp mode
78 * the 16x16 MB qp is adjusted by qp_adj value
79 */
80 RK_U16 qp_adj_mode : 1;
81 } Vepu541RoiCfg;
82
83 typedef struct Vepu580RoiH264BsCfg_t {
84 RK_U64 force_inter : 42;
85 RK_U64 mode_mask : 9;
86 RK_U64 reserved : 10;
87 RK_U64 force_intra : 1;
88 RK_U64 qp_adj_en : 1;
89 RK_U64 amv_en : 1;
90 } Vepu580RoiH264BsCfg;
91
92 typedef struct Vepu580RoiH265BsCfg_t {
93 RK_U8 amv_en : 1;
94 RK_U8 qp_adj : 1;
95 RK_U8 force_split : 1;
96 RK_U8 force_intra : 2;
97 RK_U8 force_inter : 2;
98 } Vepu580RoiH265BsCfg;
99
100 typedef struct Vepu580RoiQpCfg_t {
101 RK_U16 reserved : 4;
102 /*
103 * Qp area index
104 * The choosed qp area index.
105 */
106 RK_U16 qp_area_idx : 4;
107 /*
108 * Qp_adj
109 * Qp_adj
110 * in absolute qp mode qp_adj is the final qp used by encoder
111 * in relative qp mode qp_adj is a adjustment to final qp
112 */
113 RK_S16 qp_adj : 7;
114 /*
115 * Qp_adj_mode
116 * Qp adjustment mode
117 * 1 - absolute qp mode:
118 * the 16x16 MB qp is set to the qp_adj value
119 * 0 - relative qp mode
120 * the 16x16 MB qp is adjusted by qp_adj value
121 */
122 RK_U16 qp_adj_mode : 1;
123 } Vepu580RoiQpCfg;
124
125 typedef struct MppEncRoiImpl_t {
126 /* common parameters */
127 RK_S32 w;
128 RK_S32 h;
129 MppCodingType type;
130
131 /* region config set */
132 RoiRegionCfg *regions;
133 RK_S32 max_count;
134 RK_S32 count;
135
136 /*
137 * roi_type is for the different encoder roi config
138 *
139 * 0 - rv1109/rk3566/rk3568 roi
140 * 1 - rk3588 roi
141 *
142 * others - legacy roi config
143 */
144 RoiType roi_type;
145
146 /* For roi type legacy config */
147 MppEncROICfg legacy_roi_cfg;
148 MppEncROIRegion *legacy_roi_region;
149
150 /* For roi type 1&2 config */
151 MppBufferGroup roi_grp;
152 MppEncROICfg2 roi_cfg;
153
154 /* buffer address and size of MppBuffer in MppEncROICfg2 */
155 void *dst_base;
156 void *dst_qp;
157 void *dst_amv;
158 void *dst_mv;
159 RK_U32 base_cfg_size;
160 RK_U32 qp_cfg_size;
161 RK_U32 amv_cfg_size;
162 RK_U32 mv_cfg_size;
163
164 RK_U8 *cu_map;
165 RK_U32 cu_size;
166
167 /* tmp buffer for convert vepu54x roi cfg to vepu58x roi cfg */
168 Vepu541RoiCfg *tmp;
169 } MppEncRoiImpl;
170
171 static RK_U32 raster2scan8[64] = {
172 0, 1, 4, 5, 16, 17, 20, 21,
173 2, 3, 6, 7, 18, 19, 22, 23,
174 8, 9, 12, 13, 24, 25, 28, 29,
175 10, 11, 14, 15, 26, 27, 30, 31,
176 32, 33, 36, 37, 48, 49, 52, 53,
177 34, 35, 38, 39, 50, 51, 54, 55,
178 40, 41, 44, 45, 56, 57, 60, 61,
179 42, 43, 46, 47, 58, 59, 62, 63
180 };
181
182 static RK_U32 raster2zscan16[16] = {
183 0, 1, 4, 5,
184 2, 3, 6, 7,
185 8, 9, 12, 13,
186 10, 11, 14, 15
187 };
188
vepu54x_h265_set_roi(void * dst_buf,void * src_buf,RK_S32 w,RK_S32 h)189 static MPP_RET vepu54x_h265_set_roi(void *dst_buf, void *src_buf, RK_S32 w, RK_S32 h)
190 {
191 Vepu541RoiCfg *src = (Vepu541RoiCfg *)src_buf;
192 Vepu541RoiCfg *dst = (Vepu541RoiCfg *)dst_buf;
193 RK_S32 mb_w = MPP_ALIGN(w, 64) / 64;
194 RK_S32 mb_h = MPP_ALIGN(h, 64) / 64;
195 RK_S32 ctu_line = mb_w;
196 RK_S32 j;
197
198 for (j = 0; j < mb_h; j++) {
199 RK_S32 i;
200
201 for (i = 0; i < mb_w; i++) {
202 RK_S32 ctu_addr = j * ctu_line + i;
203 RK_S32 cu16_num_line = ctu_line * 4;
204 RK_S32 cu16cnt;
205
206 for (cu16cnt = 0; cu16cnt < 16; cu16cnt++) {
207 RK_S32 cu16_addr_in_frame;
208 RK_S32 cu16_x = cu16cnt % 4;
209 RK_S32 cu16_y = cu16cnt / 4;
210
211 cu16_x += i * 4;
212 cu16_y += j * 4;
213 cu16_addr_in_frame = cu16_x + cu16_y * cu16_num_line;
214
215 dst[ctu_addr * 16 + cu16cnt] = src[cu16_addr_in_frame];
216 }
217 }
218 }
219
220 return MPP_OK;
221 }
222
gen_vepu54x_roi(MppEncRoiImpl * ctx,Vepu541RoiCfg * dst)223 static MPP_RET gen_vepu54x_roi(MppEncRoiImpl *ctx, Vepu541RoiCfg *dst)
224 {
225 RoiRegionCfg *region = ctx->regions;
226 RK_S32 mb_w = MPP_ALIGN(ctx->w, 16) / 16;
227 RK_S32 mb_h = MPP_ALIGN(ctx->h, 16) / 16;
228 RK_S32 stride_h = MPP_ALIGN(mb_w, 4);
229 RK_S32 stride_v = MPP_ALIGN(mb_h, 4);
230 Vepu541RoiCfg cfg;
231 MPP_RET ret = MPP_NOK;
232 RK_S32 i;
233
234 memset(ctx->cu_map, 0, ctx->cu_size);
235
236 cfg.force_intra = 0;
237 cfg.reserved = 0;
238 cfg.qp_area_idx = 0;
239 cfg.qp_area_en = 1;
240 cfg.qp_adj = 0;
241 cfg.qp_adj_mode = 0;
242
243 /* step 1. reset all the config */
244 for (i = 0; i < stride_h * stride_v; i++)
245 memcpy(dst + i, &cfg, sizeof(cfg));
246
247 if (ctx->w <= 0 || ctx->h <= 0) {
248 mpp_err_f("invalid size [%d:%d]\n", ctx->w, ctx->h);
249 goto DONE;
250 }
251
252 /* check region config */
253 ret = MPP_OK;
254 for (i = 0; i < ctx->count; i++, region++) {
255 if (region->x + region->w > ctx->w || region->y + region->h > ctx->h)
256 ret = MPP_NOK;
257
258 if (region->force_intra > 1 || region->qp_mode > 1)
259 ret = MPP_NOK;
260
261 if ((region->qp_mode && region->qp_val > 51) ||
262 (!region->qp_mode && (region->qp_val > 51 || region->qp_val < -51)))
263 ret = MPP_NOK;
264
265 if (ret) {
266 mpp_err_f("region %d invalid param:\n", i);
267 mpp_err_f("position [%d:%d:%d:%d] vs [%d:%d]\n",
268 region->x, region->y, region->w, region->h, ctx->w, ctx->h);
269 mpp_err_f("force intra %d qp mode %d val %d\n",
270 region->force_intra, region->qp_mode, region->qp_val);
271 goto DONE;
272 }
273 }
274
275 region = ctx->regions;
276 /* step 2. setup region for top to bottom */
277 for (i = 0; i < ctx->count; i++, region++) {
278 Vepu541RoiCfg *p = dst;
279 RK_U8 *map = ctx->cu_map;
280 RK_S32 roi_width = (region->w + 15) / 16;
281 RK_S32 roi_height = (region->h + 15) / 16;
282 RK_S32 pos_x_init = (region->x + 15) / 16;
283 RK_S32 pos_y_init = (region->y + 15) / 16;
284 RK_S32 pos_x_end = pos_x_init + roi_width;
285 RK_S32 pos_y_end = pos_y_init + roi_height;
286 RK_S32 x, y;
287
288 mpp_assert(pos_x_init >= 0 && pos_x_init < mb_w);
289 mpp_assert(pos_x_end >= 0 && pos_x_end <= mb_w);
290 mpp_assert(pos_y_init >= 0 && pos_y_init < mb_h);
291 mpp_assert(pos_y_end >= 0 && pos_y_end <= mb_h);
292
293 cfg.force_intra = region->force_intra;
294 cfg.reserved = 0;
295 cfg.qp_area_idx = 0;
296 // NOTE: When roi is enabled the qp_area_en should be one.
297 cfg.qp_area_en = 1; // region->area_map_en;
298 cfg.qp_adj = region->qp_val;
299 cfg.qp_adj_mode = region->qp_mode;
300
301 p += pos_y_init * stride_h + pos_x_init;
302 map += pos_y_init * stride_h + pos_x_init;
303 for (y = 0; y < roi_height; y++) {
304 for (x = 0; x < roi_width; x++) {
305 memcpy(p + x, &cfg, sizeof(cfg));
306 if (ctx->type == MPP_VIDEO_CodingAVC) {
307 *(map + x) = 1;
308 }
309
310 }
311 p += stride_h;
312 map += stride_h;
313 }
314
315 if (ctx->type == MPP_VIDEO_CodingHEVC) {
316 map = ctx->cu_map;
317 RK_U32 stride_cu64_h = stride_h * 16 / 64;
318
319 roi_width = (region->w + 64) / 64;
320 roi_height = (region->h + 64) / 64;
321
322 if (region->x < 64) {
323 pos_x_init = 0;
324 roi_width += 2;
325 } else if (region->x % 64) {
326 pos_x_init = (region->x - 64) / 64;
327 roi_width += 2;
328 } else
329 pos_x_init = region->x / 64;
330
331 if (region->y < 64) {
332 pos_y_init = 0;
333 roi_height += 2;
334 } else if (region->y % 64) {
335 pos_y_init = (region->y - 64) / 64;
336 roi_height += 2;
337 } else
338 pos_y_init = region->y / 64;
339
340 map += pos_y_init * stride_cu64_h + pos_x_init;
341 for (y = 0; y < roi_height; y++) {
342 for (x = 0; x < roi_width; x++) {
343 *(map + x) = 1;
344 }
345 map += stride_cu64_h;
346 }
347 }
348 }
349
350 DONE:
351 return ret;
352 }
353
354
set_roi_pos_val(RK_U32 * buf,RK_U32 pos,RK_U32 value)355 static MPP_RET set_roi_pos_val(RK_U32 *buf, RK_U32 pos, RK_U32 value)
356 {
357 RK_U32 index = pos / 32;
358 RK_U32 bits = pos % 32;
359
360 buf[index] = buf[index] | (value << bits);
361 return MPP_OK;
362 }
363
364 #define set_roi_qpadj(buf, index, val) \
365 do { \
366 RK_U32 offset = 425 + index; \
367 set_roi_pos_val(buf, offset, val); \
368 } while(0)
369
370 #define set_roi_force_split(buf, index, val) \
371 do { \
372 RK_U32 offset = 340 + index; \
373 set_roi_pos_val(buf, offset, val); \
374 } while(0)
375
376 #define set_roi_force_intra(buf, index, val) \
377 do { \
378 RK_U32 offset = 170 + index * 2; \
379 set_roi_pos_val(buf, offset, val); \
380 } while(0)
381
382 #define set_roi_force_inter(buf, index, val) \
383 do { \
384 RK_U32 offset = index * 2; \
385 set_roi_pos_val(buf, offset, val); \
386 } while(0)
387
set_roi_cu8_base_cfg(RK_U32 * buf,RK_U32 index,Vepu580RoiH265BsCfg val)388 static void set_roi_cu8_base_cfg(RK_U32 *buf, RK_U32 index, Vepu580RoiH265BsCfg val)
389 {
390 set_roi_qpadj(buf, index, val.qp_adj);
391 set_roi_force_split(buf, index, val.force_split);
392 set_roi_force_intra(buf, index, val.force_intra);
393 set_roi_force_inter(buf, index, val.force_inter);
394 }
395
set_roi_cu16_base_cfg(RK_U32 * buf,RK_U32 index,Vepu580RoiH265BsCfg val)396 static void set_roi_cu16_base_cfg(RK_U32 *buf, RK_U32 index, Vepu580RoiH265BsCfg val)
397 {
398 index += 64;
399 set_roi_qpadj(buf, index, val.qp_adj);
400 set_roi_force_split(buf, index, val.force_split);
401 set_roi_force_intra(buf, index, val.force_intra);
402 set_roi_force_inter(buf, index, val.force_inter);
403 }
404
set_roi_cu32_base_cfg(RK_U32 * buf,RK_U32 index,Vepu580RoiH265BsCfg val)405 static void set_roi_cu32_base_cfg(RK_U32 *buf, RK_U32 index, Vepu580RoiH265BsCfg val)
406 {
407 index += 80;
408 set_roi_qpadj(buf, index, val.qp_adj);
409 set_roi_force_split(buf, index, val.force_split);
410 set_roi_force_intra(buf, index, val.force_intra);
411 set_roi_force_inter(buf, index, val.force_inter);
412 }
413
set_roi_cu64_base_cfg(RK_U32 * buf,Vepu580RoiH265BsCfg val)414 static void set_roi_cu64_base_cfg(RK_U32 *buf, Vepu580RoiH265BsCfg val)
415 {
416 set_roi_qpadj(buf, 84, val.qp_adj);
417 set_roi_force_split(buf, 84, val.force_split);
418 set_roi_force_intra(buf, 84, val.force_intra);
419 set_roi_force_inter(buf, 84, val.force_inter);
420 }
421
set_roi_qp_cfg(void * buf,RK_U32 index,Vepu541RoiCfg * cfg)422 static void set_roi_qp_cfg(void *buf, RK_U32 index, Vepu541RoiCfg *cfg)
423 {
424 Vepu580RoiQpCfg *qp_cfg_base = (Vepu580RoiQpCfg *)buf;
425 Vepu580RoiQpCfg *qp_cfg = &qp_cfg_base[index];
426
427 qp_cfg->qp_adj = cfg->qp_adj;
428 qp_cfg->qp_adj_mode = cfg->qp_adj_mode;
429 qp_cfg->qp_area_idx = cfg->qp_area_idx;
430 }
431
432 #define set_roi_cu8_qp_cfg(buf, index, cfg) \
433 do { \
434 RK_U32 offset = index; \
435 set_roi_qp_cfg(buf, offset, cfg); \
436 } while(0)
437
438 #define set_roi_cu16_qp_cfg(buf, index, cfg) \
439 do { \
440 RK_U32 offset = 64 + index; \
441 set_roi_qp_cfg(buf, offset, cfg); \
442 } while(0)
443
444 #define set_roi_cu32_qp_cfg(buf, index, cfg) \
445 do { \
446 RK_U32 offset = 80 + index; \
447 set_roi_qp_cfg(buf, offset, cfg); \
448 } while(0)
449
450 #define set_roi_cu64_qp_cfg(buf, cfg) \
451 do { \
452 RK_U32 offset = 84; \
453 set_roi_qp_cfg(buf, offset, cfg); \
454 } while(0)
455
set_roi_amv(RK_U32 * buf,Vepu580RoiH265BsCfg val)456 void set_roi_amv(RK_U32 *buf, Vepu580RoiH265BsCfg val)
457 {
458 set_roi_pos_val(buf, 511, val.amv_en);
459 }
460
gen_vepu580_roi_h264(MppEncRoiImpl * ctx)461 static MPP_RET gen_vepu580_roi_h264(MppEncRoiImpl *ctx)
462 {
463 RK_S32 mb_w = MPP_ALIGN(ctx->w, 16) / 16;
464 RK_S32 mb_h = MPP_ALIGN(ctx->h, 16) / 16;
465 RK_S32 stride_h = MPP_ALIGN(mb_w, 4);
466 RK_S32 stride_v = MPP_ALIGN(mb_h, 4);
467 RK_S32 roi_buf_size = stride_h * stride_v * 8;
468 RK_S32 roi_qp_size = stride_h * stride_v * 2;
469
470 Vepu541RoiCfg *src = (Vepu541RoiCfg *)ctx->tmp;
471 Vepu580RoiQpCfg *dst_qp = ctx->dst_qp;
472 Vepu580RoiH264BsCfg *dst_base = ctx->dst_base;
473 RK_S32 j, k;
474
475 if (!src || !dst_qp || !dst_base)
476 return MPP_NOK;
477
478 memset(dst_base, 0, roi_buf_size);
479 memset(dst_qp, 0, roi_qp_size);
480
481 for (j = 0; j < mb_h; j++) {
482 for (k = 0; k < stride_h; k++) {
483 if (ctx->cu_map[j * stride_h + k]) {
484 Vepu541RoiCfg *cu_cfg = &src[j * stride_h + k];
485 Vepu580RoiQpCfg *qp_cfg = &dst_qp[j * stride_h + k];
486 Vepu580RoiH264BsCfg *base_cfg = &dst_base[j * stride_h + k];
487
488 qp_cfg->qp_adj = cu_cfg->qp_adj;
489 qp_cfg->qp_adj_mode = cu_cfg->qp_adj_mode;
490 qp_cfg->qp_area_idx = cu_cfg->qp_area_idx;
491 base_cfg->force_intra = cu_cfg->force_intra;
492 base_cfg->qp_adj_en = !!cu_cfg->qp_adj;
493 #if 0
494 if (j < 8 && k < 8) {
495 RK_U64 *tmp = (RK_U64 *)base_cfg;
496 RK_U16 *qp = (RK_U16 *)qp_cfg;
497
498 mpp_log("force_intra %d, qp_adj_en %d qp_adj %d, qp_adj_mode %d",
499 base_cfg->force_intra, base_cfg->qp_adj_en, qp_cfg->qp_adj, qp_cfg->qp_adj_mode);
500 mpp_log("val low %8x hight %8x", *tmp & 0xffffffff, ((*tmp >> 32) & 0xffffffff));
501
502 mpp_log("qp cfg %4x", *qp);
503 }
504 #endif
505 }
506 }
507 }
508
509 return MPP_OK;
510 }
511
set_roi_cu16_split_cu8(RK_U32 * buf,RK_U32 cu16index,Vepu580RoiH265BsCfg val)512 void set_roi_cu16_split_cu8(RK_U32 *buf, RK_U32 cu16index, Vepu580RoiH265BsCfg val)
513 {
514 RK_S32 cu16_x = cu16index % 4;
515 RK_S32 cu16_y = cu16index / 4;
516 RK_U32 cu8cnt;
517
518 // mpp_log("cu16index = %d, force intra = %d, cu16_y= %d", cu16index, val.force_intra, cu16_y);
519 for (cu8cnt = 0; cu8cnt < 4; cu8cnt++) {
520 RK_U32 zindex = 0;
521 RK_U32 cu8_x = cu8cnt % 2;
522 RK_U32 cu8_y = cu8cnt / 2;
523 RK_U32 cu8raster_index = (cu16_y * 2 + cu8_y) * 8 + cu16_x * 2 + cu8_x;
524
525 // mpp_log("cu8raster_index = %d", cu8raster_index);
526 zindex = raster2scan8[cu8raster_index];
527 // mpp_log("cu8raster_index = %d zindex = %d x %d, y %d, cu8_x %d cu8_y %d",
528 // cu8raster_index,zindex, x, y, cu8_x, cu8_y);
529 set_roi_cu8_base_cfg(buf, zindex, val);
530 }
531 }
532
gen_vepu580_roi_h265(MppEncRoiImpl * ctx)533 static MPP_RET gen_vepu580_roi_h265(MppEncRoiImpl *ctx)
534 {
535 RK_S32 ctu_w = MPP_ALIGN(ctx->w, 64) / 64;
536 RK_S32 ctu_h = MPP_ALIGN(ctx->h, 64) / 64;
537 RK_S32 roi_buf_size = ctu_w * ctu_h * 64;
538 RK_S32 roi_qp_size = ctu_w * ctu_h * 256;
539 RK_S32 ctu_line = ctu_w;
540
541 Vepu541RoiCfg *src = (Vepu541RoiCfg *)ctx->tmp;
542 void *dst_qp = ctx->dst_qp;
543 RK_U32 *dst_base = ctx->dst_base;
544 RK_S32 i, j, k, cu16cnt;
545
546 if (!src || !dst_qp || !dst_base)
547 return MPP_NOK;
548
549 // mpp_log("roi_qp_size = %d, roi_buf_size %d", roi_qp_size, roi_buf_size);
550 memset(dst_qp, 0, roi_qp_size);
551 memset(dst_base, 0, roi_buf_size);
552
553 for (j = 0; j < ctu_h; j++) {
554 for (k = 0; k < ctu_w; k++) {
555 RK_S32 cu16_num_line = ctu_line * 4;
556 RK_U32 adjust_cnt = 0;
557
558 if (ctx->cu_map[j * ctu_w + k]) {
559 for (cu16cnt = 0; cu16cnt < 16; cu16cnt++) {
560 RK_S32 cu16_x;
561 RK_S32 cu16_y;
562 RK_S32 cu16_addr_in_frame;
563 RK_U32 zindex = 0;
564 Vepu541RoiCfg *cu16_cfg = NULL;
565 Vepu580RoiH265BsCfg val;
566
567 memset(&val, 0, sizeof(val));
568 cu16_x = cu16cnt & 3;
569 cu16_y = cu16cnt / 4;
570 cu16_x += k * 4;
571 cu16_y += j * 4;
572 cu16_addr_in_frame = cu16_x + cu16_y * cu16_num_line;
573 cu16_cfg = &src[cu16_addr_in_frame];
574 zindex = raster2zscan16[cu16cnt];
575
576 val.force_intra = cu16_cfg->force_intra;
577 val.qp_adj = !!cu16_cfg->qp_adj;
578 if (val.force_intra || val.qp_adj) {
579 adjust_cnt++;
580 }
581
582 set_roi_cu16_split_cu8(dst_base, cu16cnt, val);
583 set_roi_cu16_base_cfg(dst_base, zindex, val);
584 set_roi_cu16_qp_cfg(dst_qp, zindex, cu16_cfg);
585 /*
586 * if all cu16 adjust c64 and cu32 must adjust
587 * or we will force split to cu 16
588 */
589 if (adjust_cnt == 16 && cu16cnt == 15) {
590 // cu64
591 set_roi_cu64_base_cfg(dst_base, val);
592 set_roi_cu64_qp_cfg(dst_qp, cu16_cfg);
593 // cu32
594 for (i = 0; i < 4; i++) {
595 set_roi_cu32_base_cfg(dst_base, i, val);
596 set_roi_cu32_qp_cfg(dst_qp, i, cu16_cfg);
597 }
598
599 for (i = 0; i < 64; i ++) {
600 set_roi_cu8_base_cfg(dst_base, i, val);
601 set_roi_qp_cfg(dst_qp, i, cu16_cfg);
602 }
603 } else if (cu16cnt == 15 && adjust_cnt > 0) {
604 val.force_split = 1;
605 set_roi_force_split(dst_base, 84, val.force_split);
606 for (i = 0; i < 4; i++) {
607 set_roi_force_split(dst_base, 80 + i, val.force_split);
608 }
609 for (i = 0; i < 16; i++) {
610 set_roi_force_split(dst_base, 64 + i, val.force_split);
611 }
612 }
613 }
614 }
615 #if 0
616 if (j < 3 && (k < 3 )) {
617 mpp_log("j %d, k %d need_update = %d", j, k, need_update);
618 RK_U16 *qp_val = (RK_U16 *)dst_qp;
619 for (i = 0; i < CU_BASE_CFG_BYTE / 4; i++) {
620 mpp_log("cfg[%d] = %08x", i, dst_base[i]);
621 }
622 for (i = 0; i < CU_QP_CFG_BYTE / 2; i++) {
623 mpp_log("qp[%d] = %04x", i, qp_val[i]);
624 }
625 }
626 #endif
627 dst_base += CU_BASE_CFG_BYTE / 4;
628 dst_qp += CU_QP_CFG_BYTE;
629 }
630 }
631 return MPP_OK;
632 }
633
mpp_enc_roi_init(MppEncRoiCtx * ctx,RK_U32 w,RK_U32 h,MppCodingType type,RK_S32 count)634 MPP_RET mpp_enc_roi_init(MppEncRoiCtx *ctx, RK_U32 w, RK_U32 h, MppCodingType type, RK_S32 count)
635 {
636 RockchipSocType soc_type = mpp_get_soc_type();
637 RoiType roi_type = ROI_TYPE_AUTO;
638 MppEncRoiImpl *impl = NULL;
639 MPP_RET ret = MPP_NOK;
640
641 switch (soc_type) {
642 case ROCKCHIP_SOC_RV1109 :
643 case ROCKCHIP_SOC_RV1126 :
644 case ROCKCHIP_SOC_RK3566 :
645 case ROCKCHIP_SOC_RK3568 : {
646 roi_type = ROI_TYPE_1;
647 } break;
648 case ROCKCHIP_SOC_RK3588 : {
649 roi_type = ROI_TYPE_2;
650 } break;
651 default : {
652 roi_type = ROI_TYPE_LEGACY;
653 mpp_log("soc %s run with legacy roi config\n", mpp_get_soc_name());
654 } break;
655 }
656
657 mpp_env_get_u32("roi_type", (RK_U32 *)&roi_type, roi_type);
658
659 impl = mpp_calloc(MppEncRoiImpl, 1);
660 if (!impl) {
661 mpp_log("can't create roi context\n");
662 goto done;
663 }
664
665 impl->w = w;
666 impl->h = h;
667 impl->type = type;
668 impl->roi_type = roi_type;
669 impl->max_count = count;
670 impl->regions = mpp_calloc(RoiRegionCfg, count);
671
672 switch (roi_type) {
673 case ROI_TYPE_1 : {
674 RK_S32 mb_w = MPP_ALIGN(impl->w, 16) / 16;
675 RK_S32 mb_h = MPP_ALIGN(impl->h, 16) / 16;
676 RK_U32 ctu_w = MPP_ALIGN(impl->w, 64) / 64;
677 RK_U32 ctu_h = MPP_ALIGN(impl->w, 64) / 64;
678 RK_S32 stride_h = MPP_ALIGN(mb_w, 4);
679 RK_S32 stride_v = MPP_ALIGN(mb_h, 4);
680
681 mpp_log("set to vepu54x roi generation\n");
682
683 impl->base_cfg_size = stride_h * stride_v * sizeof(Vepu541RoiCfg);
684 mpp_buffer_group_get_internal(&impl->roi_grp, MPP_BUFFER_TYPE_ION | MPP_BUFFER_FLAGS_CACHABLE);
685
686 mpp_buffer_get(impl->roi_grp, &impl->roi_cfg.base_cfg_buf, impl->base_cfg_size);
687 if (!impl->roi_cfg.base_cfg_buf) {
688 goto done;
689 }
690 impl->dst_base = mpp_buffer_get_ptr(impl->roi_cfg.base_cfg_buf);
691
692 /* create tmp buffer for hevc */
693 if (type == MPP_VIDEO_CodingHEVC) {
694 impl->tmp = mpp_malloc(Vepu541RoiCfg, stride_h * stride_v);
695 impl->cu_map = mpp_calloc(RK_U8, ctu_w * ctu_h);
696 impl->cu_size = ctu_w * ctu_h;
697 if (!impl->tmp || !impl->cu_map)
698 goto done;
699 } else {
700 impl->cu_map = mpp_calloc(RK_U8, mb_w * mb_h);
701 impl->cu_size = mb_w * mb_h;
702 if (!impl->cu_map)
703 goto done;
704 }
705
706 ret = MPP_OK;
707 } break;
708 case ROI_TYPE_2 : {
709 if (type == MPP_VIDEO_CodingHEVC) {
710 RK_U32 ctu_w = MPP_ALIGN(w, 64) / 64;
711 RK_U32 ctu_h = MPP_ALIGN(h, 64) / 64;
712
713 impl->base_cfg_size = ctu_w * ctu_h * 64;
714 impl->qp_cfg_size = ctu_w * ctu_h * 256;
715 impl->amv_cfg_size = ctu_w * ctu_h * 512;
716 impl->mv_cfg_size = ctu_w * ctu_h * 4;
717 impl->cu_map = mpp_calloc(RK_U8, ctu_w * ctu_h);
718 impl->cu_size = ctu_w * ctu_h;
719 } else {
720 RK_U32 mb_w = MPP_ALIGN(w, 64) / 16;
721 RK_U32 mb_h = MPP_ALIGN(h, 64) / 16;
722
723 impl->base_cfg_size = mb_w * mb_h * 8;
724 impl->qp_cfg_size = mb_w * mb_h * 2;
725 impl->amv_cfg_size = mb_w * mb_h / 4;
726 impl->mv_cfg_size = mb_w * mb_h * 96 / 4;
727 impl->cu_map = mpp_calloc(RK_U8, mb_w * mb_h);
728 impl->cu_size = mb_w * mb_h;
729 }
730
731 mpp_log("set to vepu58x roi generation\n");
732
733 impl->roi_cfg.roi_qp_en = 1;
734 mpp_buffer_group_get_internal(&impl->roi_grp, MPP_BUFFER_TYPE_ION | MPP_BUFFER_FLAGS_CACHABLE);
735 mpp_buffer_get(impl->roi_grp, &impl->roi_cfg.base_cfg_buf, impl->base_cfg_size);
736 if (!impl->roi_cfg.base_cfg_buf) {
737 goto done;
738 }
739 impl->dst_base = mpp_buffer_get_ptr(impl->roi_cfg.base_cfg_buf);
740 mpp_buffer_get(impl->roi_grp, &impl->roi_cfg.qp_cfg_buf, impl->qp_cfg_size);
741 if (!impl->roi_cfg.qp_cfg_buf) {
742 goto done;
743 }
744 impl->dst_qp = mpp_buffer_get_ptr(impl->roi_cfg.qp_cfg_buf);
745 mpp_buffer_get(impl->roi_grp, &impl->roi_cfg.amv_cfg_buf, impl->amv_cfg_size);
746 if (!impl->roi_cfg.amv_cfg_buf) {
747 goto done;
748 }
749 impl->dst_amv = mpp_buffer_get_ptr(impl->roi_cfg.amv_cfg_buf);
750 mpp_buffer_get(impl->roi_grp, &impl->roi_cfg.mv_cfg_buf, impl->mv_cfg_size);
751 if (!impl->roi_cfg.mv_cfg_buf) {
752 goto done;
753 }
754 impl->dst_mv = mpp_buffer_get_ptr(impl->roi_cfg.mv_cfg_buf);
755
756 {
757 // create tmp buffer for vepu54x H.264 config first
758 RK_S32 mb_w = MPP_ALIGN(impl->w, 16) / 16;
759 RK_S32 mb_h = MPP_ALIGN(impl->h, 16) / 16;
760 RK_S32 stride_h = MPP_ALIGN(mb_w, 4);
761 RK_S32 stride_v = MPP_ALIGN(mb_h, 4);
762
763 impl->tmp = mpp_malloc(Vepu541RoiCfg, stride_h * stride_v);
764 if (!impl->tmp)
765 goto done;
766 }
767 ret = MPP_OK;
768 } break;
769 case ROI_TYPE_LEGACY : {
770 impl->legacy_roi_region = mpp_calloc(MppEncROIRegion, count);
771
772 mpp_assert(impl->legacy_roi_region);
773 impl->legacy_roi_cfg.regions = impl->legacy_roi_region;
774 ret = MPP_OK;
775 } break;
776 default : {
777 } break;
778 }
779
780 done:
781 if (ret) {
782 if (impl) {
783 mpp_enc_roi_deinit(impl);
784 impl = NULL;
785 }
786 }
787
788 *ctx = impl;
789 return ret;
790 }
791
mpp_enc_roi_deinit(MppEncRoiCtx ctx)792 MPP_RET mpp_enc_roi_deinit(MppEncRoiCtx ctx)
793 {
794 MppEncRoiImpl *impl = (MppEncRoiImpl *)ctx;
795
796 if (!impl)
797 return MPP_OK;
798
799 if (impl->roi_cfg.base_cfg_buf) {
800 mpp_buffer_put(impl->roi_cfg.base_cfg_buf);
801 impl->roi_cfg.base_cfg_buf = NULL;
802 }
803
804 if (impl->roi_cfg.qp_cfg_buf) {
805 mpp_buffer_put(impl->roi_cfg.qp_cfg_buf);
806 impl->roi_cfg.qp_cfg_buf = NULL;
807 }
808 if (impl->roi_cfg.amv_cfg_buf) {
809 mpp_buffer_put(impl->roi_cfg.amv_cfg_buf);
810 impl->roi_cfg.amv_cfg_buf = NULL;
811 }
812 if (impl->roi_cfg.mv_cfg_buf) {
813 mpp_buffer_put(impl->roi_cfg.mv_cfg_buf);
814 impl->roi_cfg.mv_cfg_buf = NULL;
815 }
816
817 if (impl->roi_grp) {
818 mpp_buffer_group_put(impl->roi_grp);
819 impl->roi_grp = NULL;
820 }
821 MPP_FREE(impl->cu_map);
822 MPP_FREE(impl->legacy_roi_region);
823 MPP_FREE(impl->regions);
824 MPP_FREE(impl->tmp);
825
826 MPP_FREE(impl);
827 return MPP_OK;
828 }
829
mpp_enc_roi_add_region(MppEncRoiCtx ctx,RoiRegionCfg * region)830 MPP_RET mpp_enc_roi_add_region(MppEncRoiCtx ctx, RoiRegionCfg *region)
831 {
832 MppEncRoiImpl *impl = (MppEncRoiImpl *)ctx;
833
834 if (impl->count >= impl->max_count) {
835 mpp_err("can not add more region with max %d\n", impl->max_count);
836 return MPP_NOK;
837 }
838
839 memcpy(impl->regions + impl->count, region, sizeof(*impl->regions));
840 impl->count++;
841
842 return MPP_OK;
843 }
844
mpp_enc_roi_setup_meta(MppEncRoiCtx ctx,MppMeta meta)845 MPP_RET mpp_enc_roi_setup_meta(MppEncRoiCtx ctx, MppMeta meta)
846 {
847 MppEncRoiImpl *impl = (MppEncRoiImpl *)ctx;
848
849 switch (impl->roi_type) {
850 case ROI_TYPE_1 : {
851 switch (impl->type) {
852 case MPP_VIDEO_CodingAVC : {
853 gen_vepu54x_roi(impl, impl->dst_base);
854 } break;
855 case MPP_VIDEO_CodingHEVC : {
856 gen_vepu54x_roi(impl, impl->tmp);
857 vepu54x_h265_set_roi(impl->dst_base, impl->tmp, impl->w, impl->h);
858 } break;
859 default : {
860 } break;
861 }
862
863 mpp_meta_set_ptr(meta, KEY_ROI_DATA2, (void*)&impl->roi_cfg);
864 mpp_buffer_sync_ro_end(impl->roi_cfg.base_cfg_buf);
865 } break;
866 case ROI_TYPE_2 : {
867 gen_vepu54x_roi(impl, impl->tmp);
868
869 switch (impl->type) {
870 case MPP_VIDEO_CodingAVC : {
871 gen_vepu580_roi_h264(impl);
872 } break;
873 case MPP_VIDEO_CodingHEVC : {
874 gen_vepu580_roi_h265(impl);
875 } break;
876 default : {
877 } break;
878 }
879
880 mpp_meta_set_ptr(meta, KEY_ROI_DATA2, (void*)&impl->roi_cfg);
881 mpp_buffer_sync_ro_end(impl->roi_cfg.base_cfg_buf);
882 mpp_buffer_sync_ro_end(impl->roi_cfg.qp_cfg_buf);
883 } break;
884 case ROI_TYPE_LEGACY : {
885 MppEncROIRegion *region = impl->legacy_roi_region;
886 MppEncROICfg *roi_cfg = &impl->legacy_roi_cfg;
887 RoiRegionCfg *regions = impl->regions;
888 RK_S32 i;
889
890 for (i = 0; i < impl->count; i++) {
891 region[i].x = regions[i].x;
892 region[i].y = regions[i].y;
893 region[i].w = regions[i].w;
894 region[i].h = regions[i].h;
895
896 region[i].intra = regions[i].force_intra;
897 region[i].abs_qp_en = regions[i].qp_mode;
898 region[i].quality = regions[i].qp_val;
899 region[i].area_map_en = 1;
900 region[i].qp_area_idx = 0;
901 }
902
903 roi_cfg->number = impl->count;
904 roi_cfg->regions = region;
905
906 mpp_meta_set_ptr(meta, KEY_ROI_DATA, (void*)roi_cfg);
907 } break;
908 default : {
909 } break;
910 }
911
912 impl->count = 0;
913
914 return MPP_OK;
915 }
916