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