1 /* SPDX-License-Identifier: Apache-2.0 OR MIT */
2 /*
3 * Copyright (c) 2022 Rockchip Electronics Co., Ltd.
4 */
5
6 #define MODULE_TAG "mpp_dec_nt"
7
8 #include <string.h>
9
10 #include "mpp_buffer_impl.h"
11
12 #include "mpp_dec_debug.h"
13 #include "mpp_dec_vproc.h"
14 #include "mpp_dec_no_thread.h"
15 #include "rk_hdr_meta_com.h"
16
mpp_dec_decode(MppDec ctx,MppPacket packet)17 MPP_RET mpp_dec_decode(MppDec ctx, MppPacket packet)
18 {
19 MppDecImpl *dec = (MppDecImpl *)ctx;
20 Mpp *mpp = (Mpp *)dec->mpp;
21 DecTask *task = (DecTask *)dec->task_single;
22 DecTaskStatus *status = &task->status;
23 MppBufSlots frame_slots = dec->frame_slots;
24 MppBufSlots packet_slots = dec->packet_slots;
25 HalDecTask *task_dec = &task->info.dec;
26 MppMutexCond *cmd_lock = &dec->cmd_lock;
27 MppPacket input = dec->mpp_pkt_in;
28 size_t stream_size = 0;
29 RK_S32 output = 0;
30 RK_U32 i;
31
32 mpp_mutex_cond_lock(cmd_lock);
33
34 /*
35 * 1. task no ready and last packet is done try process new input packet
36 */
37 if (input == NULL && !status->curr_task_rdy) {
38 input = packet;
39
40 if (input == NULL) {
41 mpp_mutex_cond_unlock(cmd_lock);
42 return MPP_OK;
43 }
44 }
45
46 if (input)
47 dec_dbg_detail("detail: %p input pkt %p len %d task ready %d\n", dec,
48 input, mpp_packet_get_length(input), status->curr_task_rdy);
49 else
50 dec_dbg_detail("detail: %p input pkt NULL task ready %d\n", dec,
51 input, status->curr_task_rdy);
52
53 /*
54 * 2. prepare stream to generate task
55 */
56 if (!status->curr_task_rdy) {
57 mpp_parser_prepare(dec->parser, input, task_dec);
58
59 dec_dbg_detail("detail: %p prepare pkt %p get task %d\n", dec,
60 input, task_dec->valid);
61
62 /* record remaining packet */
63 if (task_dec->valid) {
64 status->curr_task_rdy = 1;
65 dec->mpp_pkt_in = input;
66 }
67
68 if (input && !mpp_packet_get_length(input))
69 dec->mpp_pkt_in = NULL;
70 }
71
72 /*
73 * 3. when task not ready check eos empty task
74 */
75 if (!status->curr_task_rdy) {
76 if (task_dec->flags.eos) {
77 mpp_dec_flush(dec);
78 output += mpp_dec_push_display(mpp, task_dec->flags);
79 /*
80 * Use -1 as invalid buffer slot index.
81 * Reason: the last task maybe is a empty task with eos flag
82 * only but this task may go through vproc process also. We need
83 * create a buffer slot index for it.
84 */
85 mpp_dec_put_frame(mpp, -1, task_dec->flags);
86 output++;
87 }
88 mpp_mutex_cond_unlock(cmd_lock);
89 return (MPP_RET)output;
90 }
91
92 // NOTE: packet in task should be ready now
93 mpp_assert(task_dec->input_packet);
94
95 dec_dbg_detail("detail: %p hw pkt %p process start\n", dec, task_dec->input_packet);
96
97 /*
98 * 4. look for a unused packet slot index
99 * 5. malloc hardware buffer for the packet slot index
100 */
101 dec_dbg_detail("detail: %p hal_pkt_buf_in %p\n", dec, task->hal_pkt_buf_in);
102 if (!task->hal_pkt_buf_in) {
103 MppBuffer hal_buf_in = mpp_packet_get_buffer(task_dec->input_packet);
104 RK_S32 slot_pkt = -1;
105
106 mpp_buf_slot_get_unused(packet_slots, &slot_pkt);
107 mpp_assert(slot_pkt >= 0);
108 stream_size = mpp_packet_get_size(task_dec->input_packet);
109
110 if (NULL == hal_buf_in) {
111 mpp_buf_slot_get_prop(packet_slots, slot_pkt, SLOT_BUFFER, &hal_buf_in);
112 } else {
113 /* use external buffer and set to slot */
114 task_dec->input_no_copy = 1;
115
116 mpp_buf_slot_set_prop(packet_slots, slot_pkt, SLOT_BUFFER, hal_buf_in);
117 mpp_buffer_attach_dev(hal_buf_in, dec->dev);
118 }
119
120 if (NULL == hal_buf_in) {
121 mpp_buffer_get(mpp->mPacketGroup, &hal_buf_in, stream_size);
122 if (hal_buf_in) {
123 mpp_buf_slot_set_prop(packet_slots, slot_pkt, SLOT_BUFFER, hal_buf_in);
124 mpp_buffer_attach_dev(hal_buf_in, dec->dev);
125 mpp_buffer_put(hal_buf_in);
126 }
127 } else {
128 MppBufferImpl *buf = (MppBufferImpl *)hal_buf_in;
129 mpp_assert(buf->info.size >= stream_size);
130 }
131
132 dec_dbg_detail("detail: %p hw pkt %p get buf %p slot %d\n", dec,
133 task_dec->input_packet, hal_buf_in, slot_pkt);
134
135 task_dec->input = slot_pkt;
136 task->hal_pkt_buf_in = hal_buf_in;
137 }
138
139 /*
140 * 6. copy data to hardware buffer
141 */
142 if (!status->dec_pkt_copy_rdy) {
143 if (!task_dec->input_no_copy) {
144 void *src = mpp_packet_get_data(task_dec->input_packet);
145 size_t length = mpp_packet_get_length(task_dec->input_packet);
146
147 mpp_assert(task->hal_pkt_buf_in);
148 mpp_assert(task_dec->input_packet);
149
150 dec_dbg_detail("detail: %p copy to hw length %d\n", dec, length);
151 mpp_buffer_write(task->hal_pkt_buf_in, 0, src, length);
152 mpp_buffer_sync_partial_end(task->hal_pkt_buf_in, 0, length);
153
154 }
155
156 mpp_buf_slot_set_flag(packet_slots, task_dec->input, SLOT_CODEC_READY);
157 mpp_buf_slot_set_flag(packet_slots, task_dec->input, SLOT_HAL_INPUT);
158
159 status->dec_pkt_copy_rdy = 1;
160 }
161
162 /*
163 * 7. parse the stream in input buffer and generate task
164 */
165 if (!status->task_parsed_rdy) {
166 mpp_clock_start(dec->clocks[DEC_PRS_PARSE]);
167 mpp_parser_parse(dec->parser, task_dec);
168 mpp_clock_pause(dec->clocks[DEC_PRS_PARSE]);
169 status->task_parsed_rdy = 1;
170
171 /* add extra output slot operaton for jpeg decoding */
172 if (task_dec->input_no_copy && task_dec->output >= 0) {
173 mpp_buf_slot_set_flag(frame_slots, task_dec->output, SLOT_QUEUE_USE);
174 mpp_buf_slot_enqueue(frame_slots, task_dec->output, QUEUE_DISPLAY);
175 }
176 }
177
178 dec_dbg_detail("detail: %p parse output slot %d valid %d\n", dec,
179 task_dec->output, task_dec->valid);
180 /*
181 * 8. check task generate failure
182 */
183 if (task_dec->output < 0 || !task_dec->valid) {
184 /*
185 * We may meet an eos in parser step and there will be no anymore vaild
186 * task generated. So here we try push eos task to hal, hal will push
187 * all frame(s) to display, a frame of them with a eos flag will be
188 * used to inform that all frame have decoded
189 */
190 if (task_dec->flags.eos) {
191 mpp_dec_flush(dec);
192 output += mpp_dec_push_display(mpp, task_dec->flags);
193 }
194
195 if (status->dec_pkt_copy_rdy) {
196 mpp_buf_slot_clr_flag(packet_slots, task_dec->input, SLOT_HAL_INPUT);
197 status->dec_pkt_copy_rdy = 0;
198 }
199 status->curr_task_rdy = 0;
200 status->task_parsed_rdy = 0;
201 dec_task_info_init(&task->info);
202 task->hal_pkt_buf_in = NULL;
203
204 dec_dbg_detail("detail: %p parse return no task with output %d\n", dec, output);
205 mpp_mutex_cond_unlock(cmd_lock);
206 return (MPP_RET)output;
207 }
208 dec_dbg_detail("detail: %p check output index pass\n", dec);
209
210 /*
211 * 9. parse local task and slot to check whether new buffer or info change is needed.
212 *
213 * detect info change from frame slot
214 */
215 if (mpp_buf_slot_is_changed(frame_slots)) {
216 if (!status->info_task_gen_rdy) {
217 RK_U32 eos = task_dec->flags.eos;
218 // NOTE: info change should not go with eos flag
219 task_dec->flags.info_change = 1;
220 task_dec->flags.eos = 0;
221 mpp_dec_flush(dec);
222 output += mpp_dec_push_display(mpp, task_dec->flags);
223 mpp_dec_put_frame(mpp, task_dec->output, task_dec->flags);
224 output++;
225 task_dec->flags.eos = eos;
226 status->info_task_gen_rdy = 1;
227 dec_dbg_detail("detail: %p info change found return frame %d\n",
228 dec, output);
229 mpp_mutex_cond_unlock(cmd_lock);
230 return (MPP_RET)output;
231 }
232 dec->info_updated = 0;
233 }
234
235 task->wait.info_change = mpp_buf_slot_is_changed(frame_slots);
236 if (task->wait.info_change) {
237 mpp_mutex_cond_unlock(cmd_lock);
238 return MPP_OK;
239 } else {
240 status->info_task_gen_rdy = 0;
241 task_dec->flags.info_change = 0;
242 }
243
244 /* 10. whether the frame buffer group is internal or external */
245 if (NULL == mpp->mFrameGroup) {
246 mpp_log("mpp_dec use internal frame buffer group\n");
247 mpp_buffer_group_get_internal(&mpp->mFrameGroup, MPP_BUFFER_TYPE_ION);
248 }
249
250 /* 10.1 look for a unused hardware buffer for output */
251 if (mpp->mFrameGroup) {
252 RK_S32 unused = mpp_buffer_group_unused(mpp->mFrameGroup);
253
254 // NOTE: When dec post-process is enabled reserve 2 buffer for it.
255 task->wait.dec_pic_unusd = (dec->vproc) ? (unused < 3) : (unused < 1);
256 if (task->wait.dec_pic_unusd) {
257 mpp_mutex_cond_wait(cmd_lock);
258 /* return here and process all the flow again */
259 mpp_mutex_cond_unlock(cmd_lock);
260 return MPP_OK;
261 }
262 }
263 dec_dbg_detail("detail: %p check frame group count pass\n", dec);
264
265 /* if dec_task is reset quit decoding and mark current packet is done */
266 if (task_dec->output < 0 || !task_dec->valid)
267 return MPP_OK;
268
269 if (!task->hal_frm_buf_out) {
270 MppBuffer hal_buf_out = NULL;
271
272 output = task_dec->output;
273 mpp_buf_slot_get_prop(frame_slots, output, SLOT_BUFFER, &hal_buf_out);
274 if (NULL == hal_buf_out) {
275 size_t size = mpp_buf_slot_get_size(frame_slots);
276 mpp_buffer_get(mpp->mFrameGroup, &hal_buf_out, size);
277 if (hal_buf_out)
278 mpp_buf_slot_set_prop(frame_slots, output, SLOT_BUFFER,
279 hal_buf_out);
280 }
281 if (!dec->info_updated && dec->dev) {
282 MppFrame slot_frm = NULL;
283
284 mpp_buf_slot_get_prop(frame_slots, output, SLOT_FRAME_PTR, &slot_frm);
285 update_dec_hal_info(dec, slot_frm);
286 dec->info_updated = 1;
287 }
288
289 task->hal_frm_buf_out = hal_buf_out;
290 }
291
292 {
293 MppFrame mframe = NULL;
294
295 mpp_buf_slot_get_prop(frame_slots, task_dec->output, SLOT_FRAME_PTR, &mframe);
296
297 if (MPP_FRAME_FMT_IS_HDR(mpp_frame_get_fmt(mframe)) &&
298 dec->cfg->base.enable_hdr_meta) {
299 fill_hdr_meta_to_frame(mframe, dec->coding);
300 }
301 }
302
303 task->wait.dec_pic_match = (NULL == task->hal_frm_buf_out);
304 if (task->wait.dec_pic_match) {
305 mpp_mutex_cond_unlock(cmd_lock);
306 return MPP_NOK;
307 }
308
309 mpp_hal_reg_gen(dec->hal, &task->info);
310 mpp_hal_hw_start(dec->hal, &task->info);
311 mpp_hal_hw_wait(dec->hal, &task->info);
312 dec->dec_hw_run_count++;
313
314 /*
315 * when hardware decoding is done:
316 * 1. clear decoding flag (mark buffer is ready)
317 * 2. use get_display to get a new frame with buffer
318 * 3. add frame to output list
319 * repeat 2 and 3 until not frame can be output
320 */
321 mpp_buf_slot_clr_flag(packet_slots, task_dec->input, SLOT_HAL_INPUT);
322
323 if (task_dec->output >= 0)
324 mpp_buf_slot_clr_flag(frame_slots, task_dec->output, SLOT_HAL_OUTPUT);
325
326 for (i = 0; i < MPP_ARRAY_ELEMS(task_dec->refer); i++) {
327 RK_S32 index = task_dec->refer[i];
328 if (index >= 0)
329 mpp_buf_slot_clr_flag(frame_slots, index, SLOT_HAL_INPUT);
330 }
331 if (task_dec->flags.eos)
332 mpp_dec_flush(dec);
333
334 output += mpp_dec_push_display(mpp, task_dec->flags);
335
336 status->dec_pkt_copy_rdy = 0;
337 status->curr_task_rdy = 0;
338 status->task_parsed_rdy = 0;
339 status->prev_task_rdy = 0;
340 dec_task_info_init(&task->info);
341 task->hal_pkt_buf_in = NULL;
342 task->hal_frm_buf_out = NULL;
343 mpp_mutex_cond_unlock(cmd_lock);
344
345 return (MPP_RET)output;
346 }
347
mpp_dec_reset_no_thread(MppDecImpl * dec)348 MPP_RET mpp_dec_reset_no_thread(MppDecImpl *dec)
349 {
350 DecTask *task = (DecTask *)dec->task_single;
351 MppBufSlots frame_slots = dec->frame_slots;
352 MppMutexCond *cmd_lock = &dec->cmd_lock;
353 HalDecTask *task_dec = &task->info.dec;
354 RK_S32 index;
355 RK_U32 i;
356
357 mpp_mutex_cond_lock(cmd_lock);
358
359 task->status.curr_task_rdy = 0;
360 task->status.prev_task_rdy = 1;
361 task_dec->valid = 0;
362 mpp_parser_reset(dec->parser);
363 mpp_hal_reset(dec->hal);
364 if (dec->vproc) {
365 dec_dbg_reset("reset: vproc reset start\n");
366 dec_vproc_reset(dec->vproc);
367 dec_dbg_reset("reset: vproc reset done\n");
368 }
369
370 // wait hal thread reset ready
371 if (task->wait.info_change) {
372 mpp_log("reset at info change status\n");
373 mpp_buf_slot_reset(frame_slots, task_dec->output);
374 }
375
376 if (task->status.task_parsed_rdy) {
377 mpp_log("task no send to hal que must clr current frame hal status\n");
378 mpp_buf_slot_clr_flag(frame_slots, task_dec->output, SLOT_HAL_OUTPUT);
379 for (i = 0; i < MPP_ARRAY_ELEMS(task_dec->refer); i++) {
380 index = task_dec->refer[i];
381 if (index >= 0)
382 mpp_buf_slot_clr_flag(frame_slots, index, SLOT_HAL_INPUT);
383 }
384 task->status.task_parsed_rdy = 0;
385 }
386
387 while (MPP_OK == mpp_buf_slot_dequeue(frame_slots, &index, QUEUE_DISPLAY)) {
388 /* release extra ref in slot's MppBuffer */
389 MppBuffer buffer = NULL;
390
391 mpp_buf_slot_get_prop(frame_slots, index, SLOT_BUFFER, &buffer);
392 if (buffer)
393 mpp_buffer_put(buffer);
394 mpp_buf_slot_clr_flag(frame_slots, index, SLOT_QUEUE_USE);
395 }
396
397 if (task->status.dec_pkt_copy_rdy) {
398 mpp_buf_slot_clr_flag(dec->packet_slots, task_dec->input, SLOT_HAL_INPUT);
399 mpp_buf_slot_clr_flag(dec->packet_slots, task_dec->input, SLOT_CODEC_READY);
400 task->status.dec_pkt_copy_rdy = 0;
401 task->hal_pkt_buf_in = NULL;
402 task_dec->input = -1;
403 }
404
405 // external packet release by user
406 dec->mpp_pkt_in = NULL;
407
408 task->status.task_parsed_rdy = 0;
409 dec_task_init(task);
410
411 dec_dbg_reset("reset: parser reset all done\n");
412
413 dec->dec_in_pkt_count = 0;
414 dec->dec_hw_run_count = 0;
415 dec->dec_out_frame_count = 0;
416 dec->info_updated = 0;
417
418 mpp_mutex_cond_signal(cmd_lock);
419 mpp_mutex_cond_unlock(cmd_lock);
420
421 return MPP_OK;
422 }
423
mpp_dec_notify_no_thread(MppDecImpl * dec,RK_U32 flag)424 MPP_RET mpp_dec_notify_no_thread(MppDecImpl *dec, RK_U32 flag)
425 {
426 // Only notify buffer group control
427 if (flag == (MPP_DEC_NOTIFY_BUFFER_VALID | MPP_DEC_NOTIFY_BUFFER_MATCH)) {
428 mpp_mutex_cond_signal(&dec->cmd_lock);
429 return MPP_OK;
430 }
431
432 return MPP_OK;
433 }
434
mpp_dec_control_no_thread(MppDecImpl * dec,MpiCmd cmd,void * param)435 MPP_RET mpp_dec_control_no_thread(MppDecImpl *dec, MpiCmd cmd, void *param)
436 {
437 // cmd_lock is used to sync all async operations
438 MPP_RET ret = MPP_NOK;
439
440 mpp_mutex_cond_lock(&dec->cmd_lock);
441 dec->cmd_send++;
442 ret = mpp_dec_proc_cfg(dec, cmd, param);
443 mpp_mutex_cond_unlock(&dec->cmd_lock);
444
445 return ret;
446 }
447
448 MppDecModeApi dec_api_no_thread = {
449 NULL,
450 NULL,
451 mpp_dec_reset_no_thread,
452 mpp_dec_notify_no_thread,
453 mpp_dec_control_no_thread,
454 };
455