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