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