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