1 /* SPDX-License-Identifier: Apache-2.0 OR MIT */
2 /*
3 * Copyright (c) 2015 Rockchip Electronics Co., Ltd.
4 */
5
6 #define MODULE_TAG "mpp_enc"
7
8 #include <string.h>
9
10 #include "mpp_env.h"
11 #include "mpp_mem.h"
12 #include "mpp_info.h"
13 #include "mpp_common.h"
14 #include "mpp_2str.h"
15
16 #include "mpp.h"
17 #include "mpp_enc_debug.h"
18 #include "mpp_enc_cfg.h"
19 #include "mpp_enc_impl.h"
20 #include "mpp_enc_cb_param.h"
21
22 #include "kmpp_obj.h"
23
24 RK_U32 mpp_enc_debug = 0;
25
copy_enc_cfg(KmppObj dst,KmppObj src)26 static void copy_enc_cfg(KmppObj dst, KmppObj src)
27 {
28 MppEncCfgSet *_dst = (MppEncCfgSet *)kmpp_obj_to_entry(dst);
29 MppEncCfgSet *_src = (MppEncCfgSet *)kmpp_obj_to_entry(src);
30
31 memcpy(_dst, _src, sizeof(*_dst));
32
33 /* cleanup output change flag to avoid extra change flag bit when user resend the cfg */
34 {
35 void *p = kmpp_obj_to_flags(dst);
36 rk_s32 size = kmpp_obj_to_flags_size(dst);
37
38 if (p && size)
39 memset(p, 0, size);
40 }
41 }
42
mpp_enc_init_v2(MppEnc * enc,MppEncInitCfg * cfg)43 MPP_RET mpp_enc_init_v2(MppEnc *enc, MppEncInitCfg *cfg)
44 {
45 MPP_RET ret;
46 MppCodingType coding = cfg->coding;
47 EncImpl impl = NULL;
48 MppEncImpl *p = NULL;
49 MppEncHal enc_hal = NULL;
50 MppEncHalCfg enc_hal_cfg;
51 EncImplCfg ctrl_cfg;
52
53 mpp_env_get_u32("mpp_enc_debug", &mpp_enc_debug, 0);
54
55 if (NULL == enc) {
56 mpp_err_f("failed to malloc context\n");
57 return MPP_ERR_NULL_PTR;
58 }
59
60 *enc = NULL;
61
62 p = mpp_calloc(MppEncImpl, 1);
63 if (NULL == p) {
64 mpp_err_f("failed to malloc context\n");
65 return MPP_ERR_MALLOC;
66 }
67
68 mpp_enc_cfg_get(&p->set_obj);
69 mpp_enc_cfg_get(&p->cfg_obj);
70 if (!p->set_obj || !p->cfg_obj) {
71 mpp_err_f("failed to get cfg set\n");
72 ret = MPP_ERR_MALLOC;
73 goto ERR_RET;
74 }
75
76 p->set = (MppEncCfgSet *)kmpp_obj_to_entry(p->set_obj);
77 p->cfg = (MppEncCfgSet *)kmpp_obj_to_entry(p->cfg_obj);
78
79 ret = mpp_enc_refs_init(&p->refs);
80 if (ret) {
81 mpp_err_f("could not init enc refs\n");
82 goto ERR_RET;
83 }
84
85 p->output_cb.callBack = mpp_enc_callback;
86 p->output_cb.ctx = p;
87 p->output_cb.cmd = ENC_CALLBACK_BASE;
88
89 // H.264 encoder use mpp_enc_hal path
90 // create hal first
91 enc_hal_cfg.coding = coding;
92 enc_hal_cfg.cfg = p->cfg;
93 enc_hal_cfg.output_cb = &p->output_cb;
94 enc_hal_cfg.task_cnt = cfg->task_cnt;
95 enc_hal_cfg.type = VPU_CLIENT_BUTT;
96 enc_hal_cfg.dev = NULL;
97 enc_hal_cfg.cap_recn_out = 0;
98
99 ctrl_cfg.coding = coding;
100 ctrl_cfg.type = VPU_CLIENT_BUTT;
101 ctrl_cfg.cfg = p->cfg;
102 ctrl_cfg.refs = p->refs;
103
104 ret = mpp_enc_hal_init(&enc_hal, &enc_hal_cfg);
105 if (ret) {
106 mpp_err_f("could not init enc hal\n");
107 goto ERR_RET;
108 }
109
110 ctrl_cfg.type = enc_hal_cfg.type;
111
112 ret = enc_impl_init(&impl, &ctrl_cfg);
113 if (ret) {
114 mpp_err_f("could not init impl\n");
115 goto ERR_RET;
116 }
117
118 ret = hal_info_init(&p->hal_info, MPP_CTX_ENC, coding);
119 if (ret) {
120 mpp_err_f("could not init hal info\n");
121 goto ERR_RET;
122 }
123
124 p->coding = coding;
125 p->impl = impl;
126 p->enc_hal = enc_hal;
127 p->dev = enc_hal_cfg.dev;
128 p->mpp = cfg->mpp;
129 p->tasks = enc_hal_cfg.tasks;
130 p->sei_mode = MPP_ENC_SEI_MODE_ONE_SEQ;
131 p->version_info = get_mpp_version();
132 p->version_length = strlen(p->version_info);
133 p->rc_cfg_size = SZ_1K;
134 p->rc_cfg_info = mpp_calloc_size(char, p->rc_cfg_size);
135
136 if (enc_hal_cfg.cap_recn_out)
137 p->support_hw_deflicker = 1;
138
139 {
140 // create header packet storage
141 size_t size = SZ_4K;
142 p->hdr_buf = mpp_calloc_size(void, size);
143
144 mpp_packet_init(&p->hdr_pkt, p->hdr_buf, size);
145 mpp_packet_set_length(p->hdr_pkt, 0);
146 }
147 {
148 Mpp *mpp = (Mpp *)p->mpp;
149
150 p->input = mpp_task_queue_get_port(mpp->mInputTaskQueue, MPP_PORT_OUTPUT);
151 p->output = mpp_task_queue_get_port(mpp->mOutputTaskQueue, MPP_PORT_INPUT);
152 }
153
154 /* NOTE: setup configure coding for check */
155 p->cfg->base.coding = coding;
156 p->cfg->plt_cfg.plt = &p->cfg->plt_data;
157 copy_enc_cfg(p->set_obj, p->cfg_obj);
158
159 mpp_enc_ref_cfg_init(&p->cfg->ref_cfg);
160 mpp_enc_ref_cfg_init(&p->set->ref_cfg);
161 ret = mpp_enc_ref_cfg_copy(p->cfg->ref_cfg, mpp_enc_ref_default());
162 ret = mpp_enc_ref_cfg_copy(p->set->ref_cfg, mpp_enc_ref_default());
163
164 ret = mpp_enc_refs_set_cfg(p->refs, mpp_enc_ref_default());
165 mpp_enc_refs_set_rc_igop(p->refs, p->cfg->rc.gop);
166
167 sem_init(&p->enc_reset, 0, 0);
168 sem_init(&p->cmd_start, 0, 0);
169 sem_init(&p->cmd_done, 0, 0);
170 mpp_mutex_init(&p->lock);
171
172 *enc = p;
173 return ret;
174 ERR_RET:
175 mpp_enc_deinit_v2(p);
176 return ret;
177 }
178
mpp_enc_deinit_v2(MppEnc ctx)179 MPP_RET mpp_enc_deinit_v2(MppEnc ctx)
180 {
181 MppEncImpl *enc = (MppEncImpl *)ctx;
182
183 if (NULL == enc) {
184 mpp_err_f("found NULL input\n");
185 return MPP_ERR_NULL_PTR;
186 }
187
188 mpp_mutex_destroy(&enc->lock);
189
190 if (enc->hal_info) {
191 hal_info_deinit(enc->hal_info);
192 enc->hal_info = NULL;
193 }
194
195 if (enc->impl) {
196 enc_impl_deinit(enc->impl);
197 enc->impl = NULL;
198 }
199
200 if (enc->enc_hal) {
201 mpp_enc_hal_deinit(enc->enc_hal);
202 enc->enc_hal = NULL;
203 }
204
205 if (enc->hdr_pkt)
206 mpp_packet_deinit(&enc->hdr_pkt);
207
208 MPP_FREE(enc->hdr_buf);
209
210 if (enc->set->ref_cfg) {
211 mpp_enc_ref_cfg_deinit(&enc->set->ref_cfg);
212 enc->set->ref_cfg = NULL;
213 }
214
215 if (enc->cfg->ref_cfg) {
216 mpp_enc_ref_cfg_deinit(&enc->cfg->ref_cfg);
217 enc->cfg->ref_cfg = NULL;
218 }
219
220 if (enc->refs) {
221 mpp_enc_refs_deinit(&enc->refs);
222 enc->refs = NULL;
223 }
224
225 if (enc->set_obj) {
226 kmpp_obj_put_f(enc->set_obj);
227 enc->set_obj = NULL;
228 }
229
230 if (enc->cfg_obj) {
231 kmpp_obj_put_f(enc->cfg_obj);
232 enc->cfg_obj = NULL;
233 }
234
235 if (enc->rc_ctx) {
236 rc_deinit(enc->rc_ctx);
237 enc->rc_ctx = NULL;
238 }
239
240 MPP_FREE(enc->rc_cfg_info);
241 enc->rc_cfg_size = 0;
242 enc->rc_cfg_length = 0;
243
244 sem_destroy(&enc->enc_reset);
245 sem_destroy(&enc->cmd_start);
246 sem_destroy(&enc->cmd_done);
247
248 mpp_free(enc);
249 return MPP_OK;
250 }
251
mpp_enc_start_v2(MppEnc ctx)252 MPP_RET mpp_enc_start_v2(MppEnc ctx)
253 {
254 MppEncImpl *enc = (MppEncImpl *)ctx;
255 char name[16];
256
257 enc_dbg_func("%p in\n", enc);
258
259 snprintf(name, sizeof(name) - 1, "mpp_%se_%d",
260 strof_coding_type(enc->coding), getpid());
261
262 enc->thread_enc = mpp_thread_create(mpp_enc_thread, enc->mpp, name);
263 mpp_thread_start(enc->thread_enc);
264
265 enc_dbg_func("%p out\n", enc);
266
267 return MPP_OK;
268 }
269
mpp_enc_start_async(MppEnc ctx)270 MPP_RET mpp_enc_start_async(MppEnc ctx)
271 {
272 MppEncImpl *enc = (MppEncImpl *)ctx;
273 char name[16];
274
275 enc_dbg_func("%p in\n", enc);
276
277 snprintf(name, sizeof(name) - 1, "mpp_%se_%d",
278 strof_coding_type(enc->coding), getpid());
279
280 enc->thread_enc = mpp_thread_create(mpp_enc_async_thread, enc->mpp, name);
281 mpp_thread_start(enc->thread_enc);
282
283 enc_dbg_func("%p out\n", enc);
284
285 return MPP_OK;
286 }
287
mpp_enc_stop_v2(MppEnc ctx)288 MPP_RET mpp_enc_stop_v2(MppEnc ctx)
289 {
290 MPP_RET ret = MPP_OK;
291 MppEncImpl *enc = (MppEncImpl *)ctx;
292
293 enc_dbg_func("%p in\n", enc);
294
295 if (enc->thread_enc) {
296 mpp_thread_stop(enc->thread_enc);
297 mpp_thread_destroy(enc->thread_enc);
298 enc->thread_enc = NULL;
299 }
300
301 enc_dbg_func("%p out\n", enc);
302 return ret;
303
304 }
305
mpp_enc_reset_v2(MppEnc ctx)306 MPP_RET mpp_enc_reset_v2(MppEnc ctx)
307 {
308 MppEncImpl *enc = (MppEncImpl *)ctx;
309 MppThread *thd;
310
311 enc_dbg_func("%p in\n", enc);
312
313 if (NULL == enc) {
314 mpp_err_f("found NULL input enc\n");
315 return MPP_ERR_NULL_PTR;
316 }
317
318 thd = enc->thread_enc;
319
320 mpp_thread_lock(thd, THREAD_CONTROL);
321 enc->reset_flag = 1;
322 mpp_enc_notify_v2(enc, MPP_ENC_RESET);
323 mpp_thread_unlock(thd, THREAD_CONTROL);
324
325 sem_wait(&enc->enc_reset);
326 mpp_assert(enc->reset_flag == 0);
327
328 return MPP_OK;
329 }
330
mpp_enc_notify_v2(MppEnc ctx,RK_U32 flag)331 MPP_RET mpp_enc_notify_v2(MppEnc ctx, RK_U32 flag)
332 {
333 MppEncImpl *enc = (MppEncImpl *)ctx;
334 MppThread *thd = enc->thread_enc;
335
336 enc_dbg_func("%p in flag %08x\n", enc, flag);
337
338 mpp_thread_lock(thd, THREAD_WORK);
339 if (flag == MPP_ENC_CONTROL) {
340 enc->notify_flag |= flag;
341 enc_dbg_notify("%p status %08x notify control signal\n", enc,
342 enc->status_flag);
343 mpp_thread_signal(thd, THREAD_WORK);
344 } else {
345 RK_U32 old_flag = enc->notify_flag;
346
347 enc->notify_flag |= flag;
348 if ((old_flag != enc->notify_flag) &&
349 (enc->notify_flag & enc->status_flag)) {
350 enc_dbg_notify("%p status %08x notify %08x signal\n", enc,
351 enc->status_flag, enc->notify_flag);
352 mpp_thread_signal(thd, THREAD_WORK);
353 }
354 }
355 mpp_thread_unlock(thd, THREAD_WORK);
356 enc_dbg_func("%p out\n", enc);
357 return MPP_OK;
358 }
359
360 /*
361 * preprocess config and rate-control config is common config then they will
362 * be done in mpp_enc layer
363 *
364 * codec related config will be set in each hal component
365 */
mpp_enc_control_v2(MppEnc ctx,MpiCmd cmd,void * param)366 MPP_RET mpp_enc_control_v2(MppEnc ctx, MpiCmd cmd, void *param)
367 {
368 MppEncImpl *enc = (MppEncImpl *)ctx;
369 MPP_RET ret = MPP_OK;
370
371 if (NULL == enc) {
372 mpp_err_f("found NULL enc\n");
373 return MPP_ERR_NULL_PTR;
374 }
375
376 if (NULL == param && cmd != MPP_ENC_SET_IDR_FRAME && cmd != MPP_ENC_SET_REF_CFG) {
377 mpp_err_f("found NULL param enc %p cmd %x\n", enc, cmd);
378 return MPP_ERR_NULL_PTR;
379 }
380
381 mpp_mutex_lock(&enc->lock);
382
383 enc_dbg_ctrl("sending cmd %d param %p\n", cmd, param);
384
385 switch (cmd) {
386 case MPP_ENC_GET_CFG : {
387 enc_dbg_ctrl("get enc config start\n");
388 copy_enc_cfg(param, enc->cfg_obj);
389 enc_dbg_ctrl("get enc config done\n");
390 } break;
391 case MPP_ENC_SET_PREP_CFG :
392 case MPP_ENC_GET_PREP_CFG :
393 case MPP_ENC_SET_RC_CFG :
394 case MPP_ENC_GET_RC_CFG :
395 case MPP_ENC_SET_CODEC_CFG :
396 case MPP_ENC_GET_CODEC_CFG :
397 case MPP_ENC_SET_SPLIT :
398 case MPP_ENC_GET_SPLIT : {
399 mpp_loge("deprecated %s control use MPP_ENC_GET_CFG / MPP_ENC_SET_CFG instead\n",
400 cmd == MPP_ENC_SET_PREP_CFG ? "MPP_ENC_SET_PREP_CFG" :
401 cmd == MPP_ENC_GET_PREP_CFG ? "MPP_ENC_GET_PREP_CFG" :
402 cmd == MPP_ENC_SET_RC_CFG ? "MPP_ENC_SET_RC_CFG" :
403 cmd == MPP_ENC_GET_RC_CFG ? "MPP_ENC_GET_RC_CFG" :
404 cmd == MPP_ENC_SET_CODEC_CFG ? "MPP_ENC_SET_CODEC_CFG" :
405 cmd == MPP_ENC_GET_CODEC_CFG ? "MPP_ENC_GET_CODEC_CFG" :
406 cmd == MPP_ENC_SET_SPLIT ? "MPP_ENC_SET_SPLIT" :
407 cmd == MPP_ENC_GET_SPLIT ? "MPP_ENC_GET_SPLIT" : "unknown");
408 ret = MPP_NOK;
409 } break;
410 case MPP_ENC_GET_HEADER_MODE : {
411 enc_dbg_ctrl("get header mode\n");
412 memcpy(param, &enc->hdr_mode, sizeof(enc->hdr_mode));
413 } break;
414 case MPP_ENC_GET_OSD_PLT_CFG : {
415 enc_dbg_ctrl("get osd plt cfg\n");
416 memcpy(param, &enc->cfg->plt_cfg, sizeof(enc->cfg->plt_cfg));
417 } break;
418 default : {
419 // Cmd which is not get configure will handle by enc_impl
420 if (cmd == MPP_ENC_SET_CFG) {
421 KmppObj obj = (KmppObj)param;
422
423 if (kmpp_obj_is_kobj(obj)) {
424 mpp_loge("can not MPP_ENC_SET_CFG by kobj %p\n", obj);
425 ret = MPP_NOK;
426 break;
427 }
428 }
429
430 enc->cmd = cmd;
431 enc->param = param;
432 enc->cmd_ret = &ret;
433 enc->cmd_send++;
434 mpp_enc_notify_v2(ctx, MPP_ENC_CONTROL);
435 sem_post(&enc->cmd_start);
436 sem_wait(&enc->cmd_done);
437
438 /* check the command is processed */
439 mpp_assert(!enc->cmd);
440 mpp_assert(!enc->param);
441 } break;
442 }
443
444 mpp_mutex_unlock(&enc->lock);
445
446 enc_dbg_ctrl("sending cmd %d done\n", cmd);
447
448 return ret;
449 }
450