1 /*
2 * Copyright 2015 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 "mpp_enc_ref"
18
19 #include <string.h>
20
21 #include "mpp_env.h"
22 #include "mpp_log.h"
23 #include "mpp_mem.h"
24 #include "mpp_time.h"
25
26 #include "mpp_rc_defs.h"
27 #include "mpp_enc_ref.h"
28 #include "mpp_enc_refs.h"
29
30 #define setup_mpp_enc_ref_cfg(ref) \
31 ((MppEncRefCfgImpl*)ref)->name = module_name;
32
33 static const char *module_name = MODULE_TAG;
34
_check_is_mpp_enc_ref_cfg(const char * func,void * ref)35 MPP_RET _check_is_mpp_enc_ref_cfg(const char *func, void *ref)
36 {
37 if (NULL == ref) {
38 mpp_err("%s input ref check NULL failed\n", func);
39 return MPP_NOK;
40 }
41
42 if (((MppEncRefCfgImpl*)(ref))->name != module_name) {
43 mpp_err("%s input ref check %p %p failed\n", func, ((MppEncRefCfgImpl*)(ref))->name);
44 return MPP_NOK;
45 }
46
47 return MPP_OK;
48 }
49
mpp_enc_ref_cfg_init(MppEncRefCfg * ref)50 MPP_RET mpp_enc_ref_cfg_init(MppEncRefCfg *ref)
51 {
52 if (NULL == ref) {
53 mpp_err_f("invalid NULL input ref_cfg\n");
54 return MPP_ERR_NULL_PTR;
55 }
56
57 MppEncRefCfgImpl *p = mpp_calloc(MppEncRefCfgImpl, 1);
58 *ref = p;
59 if (NULL == p) {
60 mpp_err_f("malloc failed\n");
61 return MPP_ERR_NULL_PTR;
62 }
63
64 mpp_env_get_u32("enc_ref_cfg_debug", &p->debug, 0);
65
66 setup_mpp_enc_ref_cfg(p);
67
68 return MPP_OK;
69 }
70
mpp_enc_ref_cfg_deinit(MppEncRefCfg * ref)71 MPP_RET mpp_enc_ref_cfg_deinit(MppEncRefCfg *ref)
72 {
73 if (!ref || check_is_mpp_enc_ref_cfg(*ref)) {
74 mpp_err_f("input %p check failed\n", ref);
75 return MPP_ERR_VALUE;
76 }
77
78 MppEncRefCfgImpl *p = (MppEncRefCfgImpl *)(*ref);
79 MPP_FREE(p->lt_cfg);
80 MPP_FREE(p->st_cfg);
81 MPP_FREE(p);
82
83 return MPP_OK;
84 }
85
mpp_enc_ref_cfg_reset(MppEncRefCfg ref)86 MPP_RET mpp_enc_ref_cfg_reset(MppEncRefCfg ref)
87 {
88 if (check_is_mpp_enc_ref_cfg(ref))
89 return MPP_ERR_VALUE;
90
91 MppEncRefCfgImpl *p = (MppEncRefCfgImpl *)ref;
92 MPP_FREE(p->lt_cfg);
93 MPP_FREE(p->st_cfg);
94 memset(p, 0, sizeof(*p));
95 setup_mpp_enc_ref_cfg(p);
96
97 return MPP_OK;
98 }
99
mpp_enc_ref_cfg_set_cfg_cnt(MppEncRefCfg ref,RK_S32 lt_cnt,RK_S32 st_cnt)100 MPP_RET mpp_enc_ref_cfg_set_cfg_cnt(MppEncRefCfg ref, RK_S32 lt_cnt, RK_S32 st_cnt)
101 {
102 if (check_is_mpp_enc_ref_cfg(ref))
103 return MPP_ERR_NULL_PTR;
104
105 MppEncRefCfgImpl *p = (MppEncRefCfgImpl *)ref;
106 MppEncRefLtFrmCfg *lt_cfg = p->lt_cfg;
107 MppEncRefStFrmCfg *st_cfg = p->st_cfg;;
108
109 if (lt_cfg || st_cfg) {
110 mpp_err_f("do call reset before setup new cnout\n");
111 MPP_FREE(lt_cfg);
112 MPP_FREE(st_cfg);
113 }
114
115 if (lt_cnt) {
116 lt_cfg = mpp_calloc(MppEncRefLtFrmCfg, lt_cnt);
117 if (NULL == lt_cfg)
118 mpp_log_f("failed to create %d lt ref cfg\n", lt_cnt);
119 }
120
121 if (st_cnt) {
122 st_cfg = mpp_calloc(MppEncRefStFrmCfg, st_cnt);
123 if (NULL == st_cfg)
124 mpp_log_f("failed to create %d st ref cfg\n", lt_cnt);
125 }
126
127 p->max_lt_cfg = lt_cnt;
128 p->max_st_cfg = st_cnt;
129 p->lt_cfg_cnt = 0;
130 p->st_cfg_cnt = 0;
131 p->lt_cfg = lt_cfg;
132 p->st_cfg = st_cfg;
133
134 return MPP_OK;
135 }
136
mpp_enc_ref_cfg_add_lt_cfg(MppEncRefCfg ref,RK_S32 cnt,MppEncRefLtFrmCfg * frm)137 MPP_RET mpp_enc_ref_cfg_add_lt_cfg(MppEncRefCfg ref, RK_S32 cnt, MppEncRefLtFrmCfg *frm)
138 {
139 if (check_is_mpp_enc_ref_cfg(ref))
140 return MPP_ERR_VALUE;
141
142 MppEncRefCfgImpl *p = (MppEncRefCfgImpl *)ref;
143
144 if (p->debug)
145 mpp_log("ref %p add lt %d cfg idx %d tid %d gap %d delay %d ref mode %x\n",
146 ref, p->lt_cfg_cnt, frm->lt_idx, frm->temporal_id,
147 frm->lt_gap, frm->lt_delay, frm->ref_mode);
148
149 memcpy(&p->lt_cfg[p->lt_cfg_cnt], frm, sizeof(*frm) * cnt);
150 p->lt_cfg_cnt += cnt;
151
152 return MPP_OK;
153 }
154
mpp_enc_ref_cfg_add_st_cfg(MppEncRefCfg ref,RK_S32 cnt,MppEncRefStFrmCfg * frm)155 MPP_RET mpp_enc_ref_cfg_add_st_cfg(MppEncRefCfg ref, RK_S32 cnt, MppEncRefStFrmCfg *frm)
156 {
157 if (check_is_mpp_enc_ref_cfg(ref)) {
158 mpp_err_f("input %p check failed\n", ref);
159 return MPP_ERR_VALUE;
160 }
161
162 MppEncRefCfgImpl *p = (MppEncRefCfgImpl *)ref;
163
164 if (p->debug)
165 mpp_log("ref %p add lt %d cfg non %d tid %d gap repeat %d ref mode %x arg %d\n",
166 ref, p->st_cfg_cnt, frm->is_non_ref, frm->temporal_id,
167 frm->repeat, frm->ref_mode, frm->ref_arg);
168
169 memcpy(&p->st_cfg[p->st_cfg_cnt], frm, sizeof(*frm) * cnt);
170 p->st_cfg_cnt += cnt;
171
172 return MPP_OK;
173 }
174
mpp_enc_ref_cfg_check(MppEncRefCfg ref)175 MPP_RET mpp_enc_ref_cfg_check(MppEncRefCfg ref)
176 {
177 if (check_is_mpp_enc_ref_cfg(ref))
178 return MPP_ERR_VALUE;
179
180 MppEncRefCfgImpl *p = (MppEncRefCfgImpl *)ref;
181 RK_S32 lt_cfg_cnt = p->lt_cfg_cnt;
182 RK_S32 st_cfg_cnt = p->st_cfg_cnt;
183 RK_S32 max_lt_ref_cnt = 0;
184 RK_S32 max_lt_ref_idx = 0;
185 RK_S32 lt_idx_used_mask = 0;
186 RK_S32 lt_dryrun_length = 0;
187 RK_S32 max_st_ref_cnt = 0;
188 RK_S32 max_st_tid = 0;
189 RK_S32 st_tid_used_mask = 0;
190 RK_S32 st_dryrun_length = 0;
191 RK_S32 ready = 1;
192
193 /* parse and check gop config for encoder */
194 if (lt_cfg_cnt) {
195 RK_S32 pos = 0;
196 MppEncRefLtFrmCfg *cfg = p->lt_cfg;
197
198 for (pos = 0; pos < lt_cfg_cnt; pos++, cfg++) {
199 MppEncRefMode ref_mode = cfg->ref_mode;
200 RK_S32 temporal_id = cfg->temporal_id;
201 RK_S32 lt_idx = cfg->lt_idx;
202 RK_U32 lt_idx_mask = 1 << lt_idx;
203
204 /* check lt idx */
205 if (lt_idx >= MPP_ENC_MAX_LT_REF_NUM) {
206 mpp_err_f("ref cfg %p lt cfg %d with invalid lt_idx %d larger than MPP_ENC_MAX_LT_REF_NUM\n",
207 ref, pos, lt_idx);
208 ready = 0;
209 }
210
211 if (lt_idx_used_mask & lt_idx_mask) {
212 mpp_err_f("ref cfg %p lt cfg %d with redefined lt_idx %d config\n",
213 ref, pos, lt_idx);
214 ready = 0;
215 }
216
217 if (!(lt_idx_used_mask & lt_idx_mask)) {
218 lt_idx_used_mask |= lt_idx_mask;
219 max_lt_ref_cnt++;
220 }
221
222 if (lt_idx > max_lt_ref_idx)
223 max_lt_ref_idx = lt_idx;
224
225 /* check temporal id */
226 if (temporal_id != 0) {
227 mpp_err_f("ref cfg %p lt cfg %d with invalid temporal_id %d is non-zero\n",
228 ref, pos, temporal_id);
229 ready = 0;
230 }
231
232 /* check gop mode */
233 if (!REF_MODE_IS_GLOBAL(ref_mode) && !REF_MODE_IS_LT_MODE(ref_mode)) {
234 mpp_err_f("ref cfg %p lt cfg %d with invalid ref mode %x\n",
235 ref, pos, ref_mode);
236 ready = 0;
237 }
238
239 /* if check failed just quit */
240 if (!ready)
241 break;
242
243 if (cfg->lt_gap && (cfg->lt_gap + cfg->lt_delay > lt_dryrun_length))
244 lt_dryrun_length = cfg->lt_gap + cfg->lt_delay;
245 }
246 }
247
248 /* check st-ref config */
249 if (ready && st_cfg_cnt) {
250 RK_S32 pos = 0;
251 MppEncRefStFrmCfg *cfg = p->st_cfg;
252
253 for (pos = 0; pos < st_cfg_cnt; pos++, cfg++) {
254 MppEncRefMode ref_mode = cfg->ref_mode;
255 RK_S32 temporal_id = cfg->temporal_id;
256 RK_U32 tid_mask = 1 << temporal_id;
257
258 /* check temporal_id */
259 if (temporal_id > MPP_ENC_MAX_TEMPORAL_LAYER_NUM - 1) {
260 mpp_err_f("ref cfg %p st cfg %d with invalid temporal_id %d larger than MPP_ENC_MAX_TEMPORAL_LAYER_NUM\n",
261 ref, pos, temporal_id);
262 ready = 0;
263 }
264
265 /* check gop mode */
266 if (!REF_MODE_IS_GLOBAL(ref_mode) && !REF_MODE_IS_ST_MODE(ref_mode)) {
267 mpp_err_f("ref cfg %p st cfg %d with invalid ref mode %x\n",
268 ref, pos, ref_mode);
269 ready = 0;
270 }
271
272 if (cfg->repeat < 0) {
273 mpp_err_f("ref cfg %p st cfg %d with negative repeat %d set to zero\n",
274 ref, pos, cfg->repeat);
275 cfg->repeat = 0;
276 }
277
278 /* constrain on head and tail frame */
279 if (pos == 0 || (pos == st_cfg_cnt - 1)) {
280 if (cfg->is_non_ref) {
281 mpp_err_f("ref cfg %p st cfg %d with invalid non-ref frame on head/tail frame\n",
282 ref, pos);
283 ready = 0;
284 }
285
286 if (temporal_id > 0) {
287 mpp_err_f("ref cfg %p st cfg %d with invalid non-zero temporal id %d on head/tail frame\n",
288 ref, pos, temporal_id);
289 ready = 0;
290 }
291 }
292
293 if (!ready)
294 break;
295
296 if (!cfg->is_non_ref && !(st_tid_used_mask & tid_mask)) {
297 max_st_ref_cnt++;
298 st_tid_used_mask |= tid_mask;
299 }
300
301 if (temporal_id > max_st_tid)
302 max_st_tid = temporal_id;
303
304 st_dryrun_length++;
305 st_dryrun_length += cfg->repeat;
306 }
307 }
308
309 if (ready) {
310 MppEncCpbInfo *cpb_info = &p->cpb_info;
311 MppEncRefs refs = NULL;
312 MPP_RET ret = MPP_OK;
313
314 cpb_info->dpb_size = 0;
315 cpb_info->max_lt_cnt = max_lt_ref_cnt;
316 cpb_info->max_st_cnt = max_st_ref_cnt;
317 cpb_info->max_lt_idx = max_lt_ref_idx;
318 cpb_info->max_st_tid = max_st_tid;
319 cpb_info->lt_gop = lt_dryrun_length;
320 cpb_info->st_gop = st_dryrun_length - 1;
321
322 ret = mpp_enc_refs_init(&refs);
323 ready = (ret) ? 0 : (ready);
324 ret = mpp_enc_refs_set_cfg(refs, ref);
325 ready = (ret) ? 0 : (ready);
326 ret = mpp_enc_refs_dryrun(refs);
327 ready = (ret) ? 0 : (ready);
328
329 /* update dpb size */
330 ret = mpp_enc_refs_get_cpb_info(refs, cpb_info);
331 ready = (ret) ? 0 : (ready);
332
333 ret = mpp_enc_refs_deinit(&refs);
334 ready = (ret) ? 0 : (ready);
335 } else {
336 mpp_err_f("check ref cfg %p failed\n", ref);
337 }
338 p->ready = ready;
339
340 return ready ? MPP_OK : MPP_NOK;
341 }
342
mpp_enc_ref_cfg_set_keep_cpb(MppEncRefCfg ref,RK_S32 keep)343 MPP_RET mpp_enc_ref_cfg_set_keep_cpb(MppEncRefCfg ref, RK_S32 keep)
344 {
345 if (check_is_mpp_enc_ref_cfg(ref))
346 return MPP_ERR_VALUE;
347
348 MppEncRefCfgImpl *p = (MppEncRefCfgImpl *)ref;
349 p->keep_cpb = keep;
350
351 return MPP_OK;
352 }
353
mpp_enc_ref_cfg_show(MppEncRefCfg ref)354 MPP_RET mpp_enc_ref_cfg_show(MppEncRefCfg ref)
355 {
356 if (check_is_mpp_enc_ref_cfg(ref))
357 return MPP_ERR_VALUE;
358
359 return MPP_OK;
360 }
361
mpp_enc_ref_cfg_copy(MppEncRefCfg dst,MppEncRefCfg src)362 MPP_RET mpp_enc_ref_cfg_copy(MppEncRefCfg dst, MppEncRefCfg src)
363 {
364 if (check_is_mpp_enc_ref_cfg(dst) || check_is_mpp_enc_ref_cfg(src))
365 return MPP_ERR_VALUE;
366
367 MPP_RET ret = MPP_OK;
368 MppEncRefCfgImpl *d = (MppEncRefCfgImpl *)dst;
369 MppEncRefCfgImpl *s = (MppEncRefCfgImpl *)src;
370 RK_S32 max_lt_cfg = s->max_lt_cfg;
371 RK_S32 max_st_cfg = s->max_st_cfg;
372
373 /* step 1 - free cfg in dst */
374 MPP_FREE(d->lt_cfg);
375 MPP_FREE(d->st_cfg);
376
377 /* step 2 - copy contex from src */
378 memcpy(d, s, sizeof(*d));
379
380 /* step 3 - create new storage and copy lt/st cfg */
381 if (max_lt_cfg) {
382 MppEncRefLtFrmCfg *lt_cfg = mpp_calloc(MppEncRefLtFrmCfg, max_lt_cfg);
383
384 if (NULL == lt_cfg) {
385 mpp_log_f("failed to create %d lt ref cfg\n", max_lt_cfg);
386 ret = MPP_NOK;
387 } else
388 memcpy(lt_cfg, s->lt_cfg, sizeof(lt_cfg[0]) * s->max_lt_cfg);
389
390 d->lt_cfg = lt_cfg;
391 }
392
393 if (max_st_cfg) {
394 MppEncRefStFrmCfg *st_cfg = mpp_calloc(MppEncRefStFrmCfg, max_st_cfg);
395
396 if (NULL == st_cfg) {
397 mpp_log_f("failed to create %d st ref cfg\n", max_st_cfg);
398 ret = MPP_NOK;
399 } else
400 memcpy(st_cfg, s->st_cfg, sizeof(st_cfg[0]) * s->max_st_cfg);
401
402 d->st_cfg = st_cfg;
403 }
404
405 if (ret)
406 mpp_enc_ref_cfg_reset(dst);
407
408 return ret;
409 }
410
mpp_enc_ref_cfg_get_cpb_info(MppEncRefCfg ref)411 MppEncCpbInfo *mpp_enc_ref_cfg_get_cpb_info(MppEncRefCfg ref)
412 {
413 if (check_is_mpp_enc_ref_cfg(ref))
414 return NULL;
415
416 MppEncRefCfgImpl *p = (MppEncRefCfgImpl *)ref;
417 return &p->cpb_info;
418 }
419
420 static MppEncRefStFrmCfg default_st_ref_cfg = {
421 .is_non_ref = 0,
422 .temporal_id = 0,
423 .ref_mode = REF_TO_PREV_REF_FRM,
424 .ref_arg = 0,
425 .repeat = 0,
426 };
427
428 static const MppEncRefCfgImpl default_ref_cfg = {
429 .name = module_name,
430 .ready = 1,
431 .debug = 0,
432 .keep_cpb = 0,
433 .max_lt_cfg = 0,
434 .max_st_cfg = 1,
435 .lt_cfg_cnt = 0,
436 .st_cfg_cnt = 1,
437 .lt_cfg = NULL,
438 .st_cfg = &default_st_ref_cfg,
439 .cpb_info = { 1, 0, 1, 0, 0, 0, 0 },
440 };
441
mpp_enc_ref_default(void)442 MppEncRefCfg mpp_enc_ref_default(void)
443 {
444 return (MppEncRefCfg)&default_ref_cfg;
445 }
446