xref: /rockchip-linux_mpp/mpp/codec/mpp_enc_v2.c (revision 437bfbeb9567cca9cd9080e3f6954aa9d6a94f18)
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