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