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"
18
19 #include <errno.h>
20 #include <string.h>
21
22 #include "rk_mpi.h"
23
24 #include "mpp_mem.h"
25 #include "mpp_env.h"
26 #include "mpp_time.h"
27 #include "mpp_impl.h"
28 #include "mpp_2str.h"
29 #include "mpp_debug.h"
30
31 #include "mpp.h"
32 #include "mpp_hal.h"
33
34 #include "mpp_task_impl.h"
35 #include "mpp_buffer_impl.h"
36 #include "mpp_frame_impl.h"
37 #include "mpp_packet_impl.h"
38
39 #include "mpp_dec_cfg_impl.h"
40
41 #define MPP_TEST_FRAME_SIZE SZ_1M
42 #define MPP_TEST_PACKET_SIZE SZ_512K
43
mpp_notify_by_buffer_group(void * arg,void * group)44 static void mpp_notify_by_buffer_group(void *arg, void *group)
45 {
46 Mpp *mpp = (Mpp *)arg;
47
48 mpp->notify((MppBufferGroup) group);
49 }
50
list_wraper_packet(void * arg)51 static void *list_wraper_packet(void *arg)
52 {
53 mpp_packet_deinit((MppPacket *)arg);
54 return NULL;
55 }
56
list_wraper_frame(void * arg)57 static void *list_wraper_frame(void *arg)
58 {
59 mpp_frame_deinit((MppFrame *)arg);
60 return NULL;
61 }
62
check_frm_task_cnt_cap(MppCodingType coding)63 static MPP_RET check_frm_task_cnt_cap(MppCodingType coding)
64 {
65 if (coding != MPP_VIDEO_CodingAVC ||
66 !strstr(mpp_get_soc_name(), "rk3588")) {
67 mpp_log("Only rk3588 h264 encoder can use frame parallel\n");
68 return MPP_NOK;
69 }
70
71 return MPP_OK;
72 }
73
Mpp(MppCtx ctx)74 Mpp::Mpp(MppCtx ctx)
75 : mPktIn(NULL),
76 mPktOut(NULL),
77 mFrmIn(NULL),
78 mFrmOut(NULL),
79 mPacketPutCount(0),
80 mPacketGetCount(0),
81 mFramePutCount(0),
82 mFrameGetCount(0),
83 mTaskPutCount(0),
84 mTaskGetCount(0),
85 mPacketGroup(NULL),
86 mFrameGroup(NULL),
87 mExternalFrameGroup(0),
88 mUsrInPort(NULL),
89 mUsrOutPort(NULL),
90 mMppInPort(NULL),
91 mMppOutPort(NULL),
92 mInputTaskQueue(NULL),
93 mOutputTaskQueue(NULL),
94 mInputTimeout(MPP_POLL_BUTT),
95 mOutputTimeout(MPP_POLL_BUTT),
96 mInputTask(NULL),
97 mEosTask(NULL),
98 mCtx(ctx),
99 mDec(NULL),
100 mEnc(NULL),
101 mEncAyncIo(0),
102 mEncAyncProc(0),
103 mIoMode(MPP_IO_MODE_DEFAULT),
104 mDisableThread(0),
105 mDump(NULL),
106 mType(MPP_CTX_BUTT),
107 mCoding(MPP_VIDEO_CodingUnused),
108 mInitDone(0),
109 mStatus(0),
110 mExtraPacket(NULL)
111 {
112 mpp_env_get_u32("mpp_debug", &mpp_debug, 0);
113
114 memset(&mDecInitcfg, 0, sizeof(mDecInitcfg));
115 mpp_dec_cfg_set_default(&mDecInitcfg);
116 mDecInitcfg.base.enable_vproc = MPP_VPROC_MODE_DEINTELACE;
117 mDecInitcfg.base.change |= MPP_DEC_CFG_CHANGE_ENABLE_VPROC;
118
119 mpp_dump_init(&mDump);
120 }
121
init(MppCtxType type,MppCodingType coding)122 MPP_RET Mpp::init(MppCtxType type, MppCodingType coding)
123 {
124 MPP_RET ret = MPP_NOK;
125
126 if (!mpp_check_soc_cap(type, coding)) {
127 mpp_err("unable to create %s %s for soc %s unsupported\n",
128 strof_ctx_type(type), strof_coding_type(coding),
129 mpp_get_soc_info()->compatible);
130 return MPP_NOK;
131 }
132
133 if (mpp_check_support_format(type, coding)) {
134 mpp_err("unable to create %s %s for mpp unsupported\n",
135 strof_ctx_type(type), strof_coding_type(coding));
136 return MPP_NOK;
137 }
138
139 mpp_ops_init(mDump, type, coding);
140
141 mType = type;
142 mCoding = coding;
143
144 mpp_task_queue_init(&mInputTaskQueue, this, "input");
145 mpp_task_queue_init(&mOutputTaskQueue, this, "output");
146
147 switch (mType) {
148 case MPP_CTX_DEC : {
149 mPktIn = new mpp_list(list_wraper_packet);
150 mFrmOut = new mpp_list(list_wraper_frame);
151
152 if (mInputTimeout == MPP_POLL_BUTT)
153 mInputTimeout = MPP_POLL_NON_BLOCK;
154
155 if (mOutputTimeout == MPP_POLL_BUTT)
156 mOutputTimeout = MPP_POLL_NON_BLOCK;
157
158 if (mCoding != MPP_VIDEO_CodingMJPEG) {
159 mpp_buffer_group_get_internal(&mPacketGroup, MPP_BUFFER_TYPE_ION);
160 mpp_buffer_group_limit_config(mPacketGroup, 0, 3);
161
162 mpp_task_queue_setup(mInputTaskQueue, 4);
163 mpp_task_queue_setup(mOutputTaskQueue, 4);
164 } else {
165 mpp_task_queue_setup(mInputTaskQueue, 1);
166 mpp_task_queue_setup(mOutputTaskQueue, 1);
167 }
168
169 mUsrInPort = mpp_task_queue_get_port(mInputTaskQueue, MPP_PORT_INPUT);
170 mUsrOutPort = mpp_task_queue_get_port(mOutputTaskQueue, MPP_PORT_OUTPUT);
171 mMppInPort = mpp_task_queue_get_port(mInputTaskQueue, MPP_PORT_OUTPUT);
172 mMppOutPort = mpp_task_queue_get_port(mOutputTaskQueue, MPP_PORT_INPUT);
173
174 mDecInitcfg.base.disable_thread = mDisableThread;
175 mDecInitcfg.base.change |= MPP_DEC_CFG_CHANGE_DISABLE_THREAD;
176
177 MppDecInitCfg cfg = {
178 coding,
179 this,
180 &mDecInitcfg,
181 };
182
183 ret = mpp_dec_init(&mDec, &cfg);
184 if (ret)
185 break;
186 ret = mpp_dec_start(mDec);
187 if (ret)
188 break;
189 mInitDone = 1;
190 } break;
191 case MPP_CTX_ENC : {
192 mPktIn = new mpp_list(list_wraper_packet);
193 mPktOut = new mpp_list(list_wraper_packet);
194 mFrmIn = new mpp_list(NULL);
195 mFrmOut = new mpp_list(NULL);
196
197 if (mInputTimeout == MPP_POLL_BUTT)
198 mInputTimeout = MPP_POLL_BLOCK;
199
200 if (mOutputTimeout == MPP_POLL_BUTT)
201 mOutputTimeout = MPP_POLL_NON_BLOCK;
202
203 mpp_buffer_group_get_internal(&mPacketGroup, MPP_BUFFER_TYPE_ION);
204 mpp_buffer_group_get_internal(&mFrameGroup, MPP_BUFFER_TYPE_ION);
205
206 mpp_task_queue_setup(mInputTaskQueue, 1);
207 mpp_task_queue_setup(mOutputTaskQueue, 8);
208
209 mUsrInPort = mpp_task_queue_get_port(mInputTaskQueue, MPP_PORT_INPUT);
210 mUsrOutPort = mpp_task_queue_get_port(mOutputTaskQueue, MPP_PORT_OUTPUT);
211 mMppInPort = mpp_task_queue_get_port(mInputTaskQueue, MPP_PORT_OUTPUT);
212 mMppOutPort = mpp_task_queue_get_port(mOutputTaskQueue, MPP_PORT_INPUT);
213
214 if (mInputTimeout == MPP_POLL_NON_BLOCK) {
215 mEncAyncIo = 1;
216 if (check_frm_task_cnt_cap(coding))
217 mInputTimeout = MPP_POLL_BLOCK;
218 }
219
220 MppEncInitCfg cfg = {
221 coding,
222 (mInputTimeout) ? (1) : (2),
223 this,
224 };
225
226 ret = mpp_enc_init_v2(&mEnc, &cfg);
227 if (ret)
228 break;
229
230 if (mInputTimeout == MPP_POLL_NON_BLOCK) {
231 mEncAyncProc = 1;
232 ret = mpp_enc_start_async(mEnc);
233 } else {
234 ret = mpp_enc_start_v2(mEnc);
235 }
236
237 if (ret)
238 break;
239 mInitDone = 1;
240 } break;
241 default : {
242 mpp_err("Mpp error type %d\n", mType);
243 } break;
244 }
245
246
247 if (!mInitDone) {
248 mpp_err("error found on mpp initialization\n");
249 clear();
250 }
251
252 return ret;
253 }
254
~Mpp()255 Mpp::~Mpp ()
256 {
257 clear();
258 }
259
clear()260 void Mpp::clear()
261 {
262 // MUST: release listener here
263 if (mFrameGroup)
264 mpp_buffer_group_set_callback((MppBufferGroupImpl *)mFrameGroup,
265 NULL, NULL);
266
267 if (mType == MPP_CTX_DEC) {
268 if (mDec) {
269 mpp_dec_stop(mDec);
270 mpp_dec_deinit(mDec);
271 mDec = NULL;
272 }
273 } else {
274 if (mEnc) {
275 mpp_enc_stop_v2(mEnc);
276 mpp_enc_deinit_v2(mEnc);
277 mEnc = NULL;
278 }
279 }
280
281 if (mInputTaskQueue) {
282 mpp_task_queue_deinit(mInputTaskQueue);
283 mInputTaskQueue = NULL;
284 }
285 if (mOutputTaskQueue) {
286 mpp_task_queue_deinit(mOutputTaskQueue);
287 mOutputTaskQueue = NULL;
288 }
289
290 mUsrInPort = NULL;
291 mUsrOutPort = NULL;
292 mMppInPort = NULL;
293 mMppOutPort = NULL;
294
295 if (mExtraPacket) {
296 mpp_packet_deinit(&mExtraPacket);
297 mExtraPacket = NULL;
298 }
299
300 if (mPktIn) {
301 delete mPktIn;
302 mPktIn = NULL;
303 }
304 if (mPktOut) {
305 delete mPktOut;
306 mPktOut = NULL;
307 }
308 if (mFrmIn) {
309 delete mFrmIn;
310 mFrmIn = NULL;
311 }
312 if (mFrmOut) {
313 delete mFrmOut;
314 mFrmOut = NULL;
315 }
316
317 if (mPacketGroup) {
318 mpp_buffer_group_put(mPacketGroup);
319 mPacketGroup = NULL;
320 }
321
322 if (mFrameGroup && !mExternalFrameGroup) {
323 mpp_buffer_group_put(mFrameGroup);
324 mFrameGroup = NULL;
325 }
326
327 mpp_dump_deinit(&mDump);
328 }
329
start()330 MPP_RET Mpp::start()
331 {
332 return MPP_OK;
333 }
334
stop()335 MPP_RET Mpp::stop()
336 {
337 return MPP_OK;
338 }
339
pause()340 MPP_RET Mpp::pause()
341 {
342 return MPP_OK;
343 }
344
resume()345 MPP_RET Mpp::resume()
346 {
347 return MPP_OK;
348 }
349
put_packet(MppPacket packet)350 MPP_RET Mpp::put_packet(MppPacket packet)
351 {
352 if (!mInitDone)
353 return MPP_ERR_INIT;
354
355 MPP_RET ret = MPP_NOK;
356 MppPollType timeout = mInputTimeout;
357 MppTask task_dequeue = NULL;
358 RK_U32 pkt_copy = 0;
359
360 if (mDisableThread) {
361 mpp_err_f("no thread decoding case MUST use mpi_decode interface\n");
362 return ret;
363 }
364
365 if (mExtraPacket) {
366 MppPacket extra = mExtraPacket;
367
368 mExtraPacket = NULL;
369 put_packet(extra);
370 }
371
372 if (!mEosTask) {
373 /* handle eos packet on block mode */
374 ret = poll(MPP_PORT_INPUT, MPP_POLL_BLOCK);
375 if (ret < 0)
376 goto RET;
377
378 dequeue(MPP_PORT_INPUT, &mEosTask);
379 if (NULL == mEosTask) {
380 mpp_err_f("fail to reserve eos task\n", ret);
381 ret = MPP_NOK;
382 goto RET;
383 }
384 }
385
386 if (mpp_packet_get_eos(packet)) {
387 mpp_assert(mEosTask);
388 task_dequeue = mEosTask;
389 mEosTask = NULL;
390 }
391
392 /* Use reserved task to send eos packet */
393 if (mInputTask && !task_dequeue) {
394 task_dequeue = mInputTask;
395 mInputTask = NULL;
396 }
397
398 if (NULL == task_dequeue) {
399 ret = poll(MPP_PORT_INPUT, timeout);
400 if (ret < 0) {
401 ret = MPP_ERR_BUFFER_FULL;
402 goto RET;
403 }
404
405 /* do not pull here to avoid block wait */
406 dequeue(MPP_PORT_INPUT, &task_dequeue);
407 if (NULL == task_dequeue) {
408 mpp_err_f("fail to get task on poll ret %d\n", ret);
409 ret = MPP_NOK;
410 goto RET;
411 }
412 }
413
414 if (NULL == mpp_packet_get_buffer(packet)) {
415 /* packet copy path */
416 MppPacket pkt_in = NULL;
417
418 mpp_packet_copy_init(&pkt_in, packet);
419 mpp_packet_set_length(packet, 0);
420 pkt_copy = 1;
421 packet = pkt_in;
422 ret = MPP_OK;
423 } else {
424 /* packet zero copy path */
425 mpp_log_f("not support zero copy path\n");
426 timeout = MPP_POLL_BLOCK;
427 }
428
429 /* setup task */
430 ret = mpp_task_meta_set_packet(task_dequeue, KEY_INPUT_PACKET, packet);
431 if (ret) {
432 mpp_err_f("set input frame to task ret %d\n", ret);
433 /* keep current task for next */
434 mInputTask = task_dequeue;
435 goto RET;
436 }
437
438 mpp_ops_dec_put_pkt(mDump, packet);
439
440 /* enqueue valid task to decoder */
441 ret = enqueue(MPP_PORT_INPUT, task_dequeue);
442 if (ret) {
443 mpp_err_f("enqueue ret %d\n", ret);
444 goto RET;
445 }
446
447 mPacketPutCount++;
448
449 if (timeout && !pkt_copy)
450 ret = poll(MPP_PORT_INPUT, timeout);
451
452 RET:
453 /* wait enqueued task finished */
454 if (NULL == mInputTask) {
455 MPP_RET cnt = poll(MPP_PORT_INPUT, MPP_POLL_NON_BLOCK);
456 /* reserve one task for eos block mode */
457 if (cnt >= 0) {
458 dequeue(MPP_PORT_INPUT, &mInputTask);
459 mpp_assert(mInputTask);
460 }
461 }
462
463 return ret;
464 }
465
get_frame(MppFrame * frame)466 MPP_RET Mpp::get_frame(MppFrame *frame)
467 {
468 if (!mInitDone)
469 return MPP_ERR_INIT;
470
471 AutoMutex autoFrameLock(mFrmOut->mutex());
472 MppFrame frm = NULL;
473
474 if (0 == mFrmOut->list_size()) {
475 if (mOutputTimeout) {
476 if (mOutputTimeout < 0) {
477 /* block wait */
478 mFrmOut->wait();
479 } else {
480 RK_S32 ret = mFrmOut->wait(mOutputTimeout);
481 if (ret) {
482 if (ret == ETIMEDOUT)
483 return MPP_ERR_TIMEOUT;
484 else
485 return MPP_NOK;
486 }
487 }
488 }
489 }
490
491 if (mFrmOut->list_size()) {
492 mFrmOut->del_at_head(&frm, sizeof(frame));
493 mFrameGetCount++;
494 notify(MPP_OUTPUT_DEQUEUE);
495 } else {
496 // NOTE: Add signal here is not efficient
497 // This is for fix bug of stucking on decoder parser thread
498 // When decoder parser thread is block by info change and enter waiting.
499 // There is no way to wake up parser thread to continue decoding.
500 // The put_packet only signal sem on may be it better to use sem on info
501 // change too.
502 AutoMutex autoPacketLock(mPktIn->mutex());
503 if (mPktIn->list_size())
504 notify(MPP_INPUT_ENQUEUE);
505 }
506
507 *frame = frm;
508
509 // dump output
510 mpp_ops_dec_get_frm(mDump, frm);
511
512 return MPP_OK;
513 }
514
get_frame_noblock(MppFrame * frame)515 MPP_RET Mpp::get_frame_noblock(MppFrame *frame)
516 {
517 MppFrame first = NULL;
518
519 if (!mInitDone)
520 return MPP_ERR_INIT;
521
522 mFrmOut->lock();
523 if (mFrmOut->list_size()) {
524 mFrmOut->del_at_head(&first, sizeof(frame));
525 mFrameGetCount++;
526 }
527 mFrmOut->unlock();
528 *frame = first;
529
530 return MPP_OK;
531 }
532
decode(MppPacket packet,MppFrame * frame)533 MPP_RET Mpp::decode(MppPacket packet, MppFrame *frame)
534 {
535 RK_U32 pkt_done = 0;
536 RK_S32 frm_rdy = 0;
537 MPP_RET ret = MPP_OK;
538
539 if (!mDec)
540 return MPP_NOK;
541
542 if (!mInitDone)
543 return MPP_ERR_INIT;
544
545 /*
546 * If there is frame to return get the frame first
547 * But if the output mode is block then we need to send packet first
548 */
549 if (!mOutputTimeout) {
550 AutoMutex autoFrameLock(mFrmOut->mutex());
551
552 if (mFrmOut->list_size()) {
553 mFrmOut->del_at_head(frame, sizeof(*frame));
554 mFrameGetCount++;
555 return MPP_OK;
556 }
557 }
558
559 do {
560 if (!pkt_done)
561 ret = mpp_dec_decode(mDec, packet);
562
563 /* check input packet finished or not */
564 if (!packet || !mpp_packet_get_length(packet))
565 pkt_done = 1;
566
567 /* always try getting frame */
568 {
569 AutoMutex autoFrameLock(mFrmOut->mutex());
570
571 if (mFrmOut->list_size()) {
572 mFrmOut->del_at_head(frame, sizeof(*frame));
573 mFrameGetCount++;
574 frm_rdy = 1;
575 }
576 }
577
578 /* return on flow error */
579 if (ret < 0)
580 break;
581
582 /* return on output frame is ready */
583 if (frm_rdy) {
584 mpp_assert(ret > 0);
585 ret = MPP_OK;
586 break;
587 }
588
589 /* return when packet is send and it is a non-block call */
590 if (pkt_done) {
591 ret = MPP_OK;
592 break;
593 }
594
595 /* otherwise continue decoding and getting frame */
596 } while (1);
597
598 return ret;
599 }
600
put_frame(MppFrame frame)601 MPP_RET Mpp::put_frame(MppFrame frame)
602 {
603 if (!mInitDone)
604 return MPP_ERR_INIT;
605
606 if (mInputTimeout == MPP_POLL_NON_BLOCK) {
607 set_io_mode(MPP_IO_MODE_NORMAL);
608 return put_frame_async(frame);
609 }
610
611 MPP_RET ret = MPP_NOK;
612 MppStopwatch stopwatch = NULL;
613
614 if (mpp_debug & MPP_DBG_TIMING) {
615 mpp_frame_set_stopwatch_enable(frame, 1);
616 stopwatch = mpp_frame_get_stopwatch(frame);
617 }
618
619 mpp_stopwatch_record(stopwatch, NULL);
620 mpp_stopwatch_record(stopwatch, "put frame start");
621
622 if (mInputTask == NULL) {
623 mpp_stopwatch_record(stopwatch, "input port user poll");
624 /* poll input port for valid task */
625 ret = poll(MPP_PORT_INPUT, mInputTimeout);
626 if (ret < 0) {
627 if (mInputTimeout)
628 mpp_log_f("poll on set timeout %d ret %d\n", mInputTimeout, ret);
629 goto RET;
630 }
631
632 /* dequeue task for setup */
633 mpp_stopwatch_record(stopwatch, "input port user dequeue");
634 ret = dequeue(MPP_PORT_INPUT, &mInputTask);
635 if (ret || NULL == mInputTask) {
636 mpp_log_f("dequeue on set ret %d task %p\n", ret, mInputTask);
637 goto RET;
638 }
639 }
640
641 mpp_assert(mInputTask);
642
643 /* setup task */
644 ret = mpp_task_meta_set_frame(mInputTask, KEY_INPUT_FRAME, frame);
645 if (ret) {
646 mpp_log_f("set input frame to task ret %d\n", ret);
647 goto RET;
648 }
649
650 if (mpp_frame_has_meta(frame)) {
651 MppMeta meta = mpp_frame_get_meta(frame);
652 MppPacket packet = NULL;
653 MppBuffer md_info_buf = NULL;
654
655 mpp_meta_get_packet(meta, KEY_OUTPUT_PACKET, &packet);
656 if (packet) {
657 ret = mpp_task_meta_set_packet(mInputTask, KEY_OUTPUT_PACKET, packet);
658 if (ret) {
659 mpp_log_f("set output packet to task ret %d\n", ret);
660 goto RET;
661 }
662 }
663
664 mpp_meta_get_buffer(meta, KEY_MOTION_INFO, &md_info_buf);
665 if (md_info_buf) {
666 ret = mpp_task_meta_set_buffer(mInputTask, KEY_MOTION_INFO, md_info_buf);
667 if (ret) {
668 mpp_log_f("set output motion dection info ret %d\n", ret);
669 goto RET;
670 }
671 }
672 }
673
674 // dump input
675 mpp_ops_enc_put_frm(mDump, frame);
676
677 /* enqueue valid task to encoder */
678 mpp_stopwatch_record(stopwatch, "input port user enqueue");
679 ret = enqueue(MPP_PORT_INPUT, mInputTask);
680 if (ret) {
681 mpp_log_f("enqueue ret %d\n", ret);
682 goto RET;
683 }
684
685 mInputTask = NULL;
686 /* wait enqueued task finished */
687 mpp_stopwatch_record(stopwatch, "input port user poll");
688 ret = poll(MPP_PORT_INPUT, mInputTimeout);
689 if (ret < 0) {
690 if (mInputTimeout)
691 mpp_log_f("poll on get timeout %d ret %d\n", mInputTimeout, ret);
692 goto RET;
693 }
694
695 /* get previous enqueued task back */
696 mpp_stopwatch_record(stopwatch, "input port user dequeue");
697 ret = dequeue(MPP_PORT_INPUT, &mInputTask);
698 if (ret) {
699 mpp_log_f("dequeue on get ret %d\n", ret);
700 goto RET;
701 }
702
703 mpp_assert(mInputTask);
704 if (mInputTask) {
705 MppFrame frm_out = NULL;
706
707 mpp_task_meta_get_frame(mInputTask, KEY_INPUT_FRAME, &frm_out);
708 mpp_assert(frm_out == frame);
709 }
710
711 RET:
712 mpp_stopwatch_record(stopwatch, "put_frame finish");
713 mpp_frame_set_stopwatch_enable(frame, 0);
714 return ret;
715 }
716
get_packet(MppPacket * packet)717 MPP_RET Mpp::get_packet(MppPacket *packet)
718 {
719 if (!mInitDone)
720 return MPP_ERR_INIT;
721
722 if (mInputTimeout == MPP_POLL_NON_BLOCK) {
723 set_io_mode(MPP_IO_MODE_NORMAL);
724 return get_packet_async(packet);
725 }
726
727 MPP_RET ret = MPP_OK;
728 MppTask task = NULL;
729
730 ret = poll(MPP_PORT_OUTPUT, mOutputTimeout);
731 if (ret < 0) {
732 // NOTE: Do not treat poll failure as error. Just clear output
733 ret = MPP_OK;
734 *packet = NULL;
735 goto RET;
736 }
737
738 ret = dequeue(MPP_PORT_OUTPUT, &task);
739 if (ret || NULL == task) {
740 mpp_log_f("dequeue on get ret %d task %p\n", ret, task);
741 goto RET;
742 }
743
744 mpp_assert(task);
745
746 ret = mpp_task_meta_get_packet(task, KEY_OUTPUT_PACKET, packet);
747 if (ret) {
748 mpp_log_f("get output packet from task ret %d\n", ret);
749 goto RET;
750 }
751
752 mpp_assert(*packet);
753
754 mpp_dbg_pts("pts %lld\n", mpp_packet_get_pts(*packet));
755
756 // dump output
757 mpp_ops_enc_get_pkt(mDump, *packet);
758
759 ret = enqueue(MPP_PORT_OUTPUT, task);
760 if (ret)
761 mpp_log_f("enqueue on set ret %d\n", ret);
762 RET:
763
764 return ret;
765 }
766
put_frame_async(MppFrame frame)767 MPP_RET Mpp::put_frame_async(MppFrame frame)
768 {
769 if (NULL == mFrmIn)
770 return MPP_NOK;
771
772 if (mFrmIn->trylock())
773 return MPP_NOK;
774
775 /* NOTE: the max input queue length is 2 */
776 if (mFrmIn->wait_le(10, 1)) {
777 mFrmIn->unlock();
778 return MPP_NOK;
779 }
780
781 mFrmIn->add_at_tail(&frame, sizeof(frame));
782 mFramePutCount++;
783
784 notify(MPP_INPUT_ENQUEUE);
785 mFrmIn->unlock();
786
787 return MPP_OK;
788 }
789
get_packet_async(MppPacket * packet)790 MPP_RET Mpp::get_packet_async(MppPacket *packet)
791 {
792 AutoMutex autoPacketLock(mPktOut->mutex());
793
794 *packet = NULL;
795 if (0 == mPktOut->list_size()) {
796 if (mOutputTimeout) {
797 if (mOutputTimeout < 0) {
798 /* block wait */
799 mPktOut->wait();
800 } else {
801 RK_S32 ret = mPktOut->wait(mOutputTimeout);
802 if (ret) {
803 if (ret == ETIMEDOUT)
804 return MPP_ERR_TIMEOUT;
805 else
806 return MPP_NOK;
807 }
808 }
809 } else {
810 /* NOTE: in non-block mode the sleep is to avoid user's dead loop */
811 msleep(1);
812 }
813 }
814
815 if (mPktOut->list_size()) {
816 MppPacket pkt = NULL;
817
818 mPktOut->del_at_head(&pkt, sizeof(pkt));
819 mPacketGetCount++;
820 notify(MPP_OUTPUT_DEQUEUE);
821
822 *packet = pkt;
823 } else {
824 AutoMutex autoFrameLock(mFrmIn->mutex());
825
826 if (mFrmIn->list_size())
827 notify(MPP_INPUT_ENQUEUE);
828
829 return MPP_NOK;
830 }
831
832 return MPP_OK;
833 }
834
poll(MppPortType type,MppPollType timeout)835 MPP_RET Mpp::poll(MppPortType type, MppPollType timeout)
836 {
837 if (!mInitDone)
838 return MPP_ERR_INIT;
839
840 MPP_RET ret = MPP_NOK;
841 MppTaskQueue port = NULL;
842
843 set_io_mode(MPP_IO_MODE_TASK);
844
845 switch (type) {
846 case MPP_PORT_INPUT : {
847 port = mUsrInPort;
848 } break;
849 case MPP_PORT_OUTPUT : {
850 port = mUsrOutPort;
851 } break;
852 default : {
853 } break;
854 }
855
856 if (port)
857 ret = mpp_port_poll(port, timeout);
858
859 return ret;
860 }
861
dequeue(MppPortType type,MppTask * task)862 MPP_RET Mpp::dequeue(MppPortType type, MppTask *task)
863 {
864 if (!mInitDone)
865 return MPP_ERR_INIT;
866
867 MPP_RET ret = MPP_NOK;
868 MppTaskQueue port = NULL;
869 RK_U32 notify_flag = 0;
870
871 set_io_mode(MPP_IO_MODE_TASK);
872
873 switch (type) {
874 case MPP_PORT_INPUT : {
875 port = mUsrInPort;
876 notify_flag = MPP_INPUT_DEQUEUE;
877 } break;
878 case MPP_PORT_OUTPUT : {
879 port = mUsrOutPort;
880 notify_flag = MPP_OUTPUT_DEQUEUE;
881 } break;
882 default : {
883 } break;
884 }
885
886 if (port) {
887 ret = mpp_port_dequeue(port, task);
888 if (MPP_OK == ret)
889 notify(notify_flag);
890 }
891
892 return ret;
893 }
894
enqueue(MppPortType type,MppTask task)895 MPP_RET Mpp::enqueue(MppPortType type, MppTask task)
896 {
897 if (!mInitDone)
898 return MPP_ERR_INIT;
899
900 MPP_RET ret = MPP_NOK;
901 MppTaskQueue port = NULL;
902 RK_U32 notify_flag = 0;
903
904 set_io_mode(MPP_IO_MODE_TASK);
905
906 switch (type) {
907 case MPP_PORT_INPUT : {
908 port = mUsrInPort;
909 notify_flag = MPP_INPUT_ENQUEUE;
910 } break;
911 case MPP_PORT_OUTPUT : {
912 port = mUsrOutPort;
913 notify_flag = MPP_OUTPUT_ENQUEUE;
914 } break;
915 default : {
916 } break;
917 }
918
919 if (port) {
920 ret = mpp_port_enqueue(port, task);
921 // if enqueue success wait up thread
922 if (MPP_OK == ret)
923 notify(notify_flag);
924 }
925
926 return ret;
927 }
928
set_io_mode(MppIoMode mode)929 void Mpp::set_io_mode(MppIoMode mode)
930 {
931 mpp_assert(mode == MPP_IO_MODE_NORMAL || mode == MPP_IO_MODE_TASK);
932
933 if (mIoMode == MPP_IO_MODE_DEFAULT)
934 mIoMode = mode;
935 else if (mIoMode != mode) {
936 static const char *iomode_2str[] = {
937 "normal",
938 "task queue",
939 };
940
941 mpp_assert(mIoMode < MPP_IO_MODE_BUTT);
942 mpp_assert(mode < MPP_IO_MODE_BUTT);
943 mpp_err("can not reset io mode from %s to %s\n",
944 iomode_2str[!!mIoMode], iomode_2str[!!mode]);
945 }
946 }
947
control(MpiCmd cmd,MppParam param)948 MPP_RET Mpp::control(MpiCmd cmd, MppParam param)
949 {
950 MPP_RET ret = MPP_NOK;
951
952 mpp_ops_ctrl(mDump, cmd);
953
954 switch (cmd & CMD_MODULE_ID_MASK) {
955 case CMD_MODULE_OSAL : {
956 ret = control_osal(cmd, param);
957 } break;
958 case CMD_MODULE_MPP : {
959 mpp_assert(cmd > MPP_CMD_BASE);
960 mpp_assert(cmd < MPP_CMD_END);
961
962 ret = control_mpp(cmd, param);
963 } break;
964 case CMD_MODULE_CODEC : {
965 switch (cmd & CMD_CTX_ID_MASK) {
966 case CMD_CTX_ID_DEC : {
967 mpp_assert(mType == MPP_CTX_DEC || mType == MPP_CTX_BUTT);
968 mpp_assert(cmd > MPP_DEC_CMD_BASE);
969 mpp_assert(cmd < MPP_DEC_CMD_END);
970
971 ret = control_dec(cmd, param);
972 } break;
973 case CMD_CTX_ID_ENC : {
974 mpp_assert(mType == MPP_CTX_ENC);
975 mpp_assert(cmd > MPP_ENC_CMD_BASE);
976 mpp_assert(cmd < MPP_ENC_CMD_END);
977
978 ret = control_enc(cmd, param);
979 } break;
980 case CMD_CTX_ID_ISP : {
981 mpp_assert(mType == MPP_CTX_ISP);
982 ret = control_isp(cmd, param);
983 } break;
984 default : {
985 mpp_assert(cmd > MPP_CODEC_CMD_BASE);
986 mpp_assert(cmd < MPP_CODEC_CMD_END);
987
988 ret = control_codec(cmd, param);
989 } break;
990 }
991 } break;
992 default : {
993 } break;
994 }
995
996 if (ret)
997 mpp_err("command %x param %p ret %d\n", cmd, param, ret);
998
999 return ret;
1000 }
1001
reset()1002 MPP_RET Mpp::reset()
1003 {
1004 if (!mInitDone)
1005 return MPP_ERR_INIT;
1006
1007 mpp_ops_reset(mDump);
1008
1009 if (mType == MPP_CTX_DEC) {
1010 /*
1011 * On mp4 case extra data of sps/pps will be put at the beginning
1012 * If these packet was reset before they are send to decoder then
1013 * decoder can not get these important information to continue decoding
1014 * To avoid this case happen we need to save it on reset beginning
1015 * then restore it on reset end.
1016 */
1017 mPktIn->lock();
1018 while (mPktIn->list_size()) {
1019 MppPacket pkt = NULL;
1020 mPktIn->del_at_head(&pkt, sizeof(pkt));
1021 mPacketGetCount++;
1022
1023 RK_U32 flags = mpp_packet_get_flag(pkt);
1024 if (flags & MPP_PACKET_FLAG_EXTRA_DATA) {
1025 if (mExtraPacket) {
1026 mpp_packet_deinit(&mExtraPacket);
1027 }
1028 mExtraPacket = pkt;
1029 } else {
1030 mpp_packet_deinit(&pkt);
1031 }
1032 }
1033 mPktIn->flush();
1034 mPktIn->unlock();
1035
1036 mpp_dec_reset(mDec);
1037
1038 mFrmOut->lock();
1039 mFrmOut->flush();
1040 mFrmOut->unlock();
1041
1042 mpp_port_awake(mUsrInPort);
1043 mpp_port_awake(mUsrOutPort);
1044 } else {
1045 mpp_enc_reset_v2(mEnc);
1046 }
1047
1048 return MPP_OK;
1049 }
1050
control_mpp(MpiCmd cmd,MppParam param)1051 MPP_RET Mpp::control_mpp(MpiCmd cmd, MppParam param)
1052 {
1053 MPP_RET ret = MPP_OK;
1054
1055 switch (cmd) {
1056 case MPP_SET_INPUT_BLOCK :
1057 case MPP_SET_OUTPUT_BLOCK :
1058 case MPP_SET_INTPUT_BLOCK_TIMEOUT :
1059 case MPP_SET_OUTPUT_BLOCK_TIMEOUT : {
1060 MppPollType block = (param) ? *((MppPollType *)param) : MPP_POLL_NON_BLOCK;
1061
1062 if (block <= MPP_POLL_BUTT || block > MPP_POLL_MAX) {
1063 mpp_err("invalid output timeout type %d should be in range [%d, %d]\n",
1064 block, MPP_POLL_BUTT, MPP_POLL_MAX);
1065 ret = MPP_ERR_VALUE;
1066 break;
1067 }
1068 if (cmd == MPP_SET_INPUT_BLOCK || cmd == MPP_SET_INTPUT_BLOCK_TIMEOUT)
1069 mInputTimeout = block;
1070 else
1071 mOutputTimeout = block;
1072
1073 mpp_log("deprecated block control, use timeout control instead\n");
1074 } break;
1075
1076 case MPP_SET_DISABLE_THREAD: {
1077 mDisableThread = 1;
1078 } break;
1079
1080 case MPP_SET_INPUT_TIMEOUT:
1081 case MPP_SET_OUTPUT_TIMEOUT: {
1082 MppPollType timeout = (param) ? *((MppPollType *)param) : MPP_POLL_NON_BLOCK;
1083
1084 if (timeout <= MPP_POLL_BUTT || timeout > MPP_POLL_MAX) {
1085 mpp_err("invalid output timeout type %d should be in range [%d, %d]\n",
1086 timeout, MPP_POLL_BUTT, MPP_POLL_MAX);
1087 ret = MPP_ERR_VALUE;
1088 break;
1089 }
1090
1091 if (cmd == MPP_SET_INPUT_TIMEOUT)
1092 mInputTimeout = timeout;
1093 else
1094 mOutputTimeout = timeout;
1095 } break;
1096
1097 case MPP_START : {
1098 start();
1099 } break;
1100 case MPP_STOP : {
1101 stop();
1102 } break;
1103
1104 case MPP_PAUSE : {
1105 pause();
1106 } break;
1107 case MPP_RESUME : {
1108 resume();
1109 } break;
1110
1111 default : {
1112 ret = MPP_NOK;
1113 } break;
1114 }
1115 return ret;
1116 }
1117
control_osal(MpiCmd cmd,MppParam param)1118 MPP_RET Mpp::control_osal(MpiCmd cmd, MppParam param)
1119 {
1120 MPP_RET ret = MPP_NOK;
1121
1122 mpp_assert(cmd > MPP_OSAL_CMD_BASE);
1123 mpp_assert(cmd < MPP_OSAL_CMD_END);
1124
1125 (void)cmd;
1126 (void)param;
1127 return ret;
1128 }
1129
control_codec(MpiCmd cmd,MppParam param)1130 MPP_RET Mpp::control_codec(MpiCmd cmd, MppParam param)
1131 {
1132 MPP_RET ret = MPP_NOK;
1133
1134 (void)cmd;
1135 (void)param;
1136 return ret;
1137 }
1138
control_dec(MpiCmd cmd,MppParam param)1139 MPP_RET Mpp::control_dec(MpiCmd cmd, MppParam param)
1140 {
1141 MPP_RET ret = MPP_NOK;
1142
1143 switch (cmd) {
1144 case MPP_DEC_SET_FRAME_INFO: {
1145 ret = mpp_dec_control(mDec, cmd, param);
1146 } break;
1147 case MPP_DEC_SET_EXT_BUF_GROUP: {
1148 mFrameGroup = (MppBufferGroup)param;
1149 if (param) {
1150 mExternalFrameGroup = 1;
1151
1152 mpp_dbg_info("using external buffer group %p\n", mFrameGroup);
1153
1154 if (mInitDone) {
1155 ret = mpp_buffer_group_set_callback((MppBufferGroupImpl *)param,
1156 mpp_notify_by_buffer_group,
1157 (void *)this);
1158
1159 notify(MPP_DEC_NOTIFY_EXT_BUF_GRP_READY);
1160 } else {
1161 /*
1162 * NOTE: If frame buffer group is configured before decoder init
1163 * then the buffer limitation maybe not be correctly setup
1164 * without infomation from InfoChange frame.
1165 * And the thread signal connection may not be setup here. It
1166 * may have a bad effect on MPP efficiency.
1167 */
1168 mpp_err("WARNING: setup buffer group before decoder init\n");
1169 }
1170 } else {
1171 /* The buffer group should be destroyed before */
1172 mExternalFrameGroup = 0;
1173 ret = MPP_OK;
1174 }
1175 } break;
1176 case MPP_DEC_SET_INFO_CHANGE_READY: {
1177 mpp_dbg_info("set info change ready\n");
1178
1179 ret = mpp_dec_control(mDec, cmd, param);
1180 notify(MPP_DEC_NOTIFY_INFO_CHG_DONE | MPP_DEC_NOTIFY_BUFFER_MATCH);
1181 } break;
1182 case MPP_DEC_SET_PRESENT_TIME_ORDER :
1183 case MPP_DEC_SET_PARSER_SPLIT_MODE :
1184 case MPP_DEC_SET_PARSER_FAST_MODE :
1185 case MPP_DEC_SET_IMMEDIATE_OUT :
1186 case MPP_DEC_SET_DISABLE_ERROR :
1187 case MPP_DEC_SET_ENABLE_DEINTERLACE :
1188 case MPP_DEC_SET_ENABLE_FAST_PLAY :
1189 case MPP_DEC_SET_ENABLE_MVC: {
1190 /*
1191 * These control may be set before mpp_init
1192 * When this case happen record the config and wait for decoder init
1193 */
1194 if (mDec) {
1195 ret = mpp_dec_control(mDec, cmd, param);
1196 return ret;
1197 }
1198
1199 ret = mpp_dec_set_cfg_by_cmd(&mDecInitcfg, cmd, param);
1200 } break;
1201 case MPP_DEC_GET_STREAM_COUNT: {
1202 AutoMutex autoLock(mPktIn->mutex());
1203 *((RK_S32 *)param) = mPktIn->list_size();
1204 ret = MPP_OK;
1205 } break;
1206 case MPP_DEC_GET_VPUMEM_USED_COUNT :
1207 case MPP_DEC_SET_OUTPUT_FORMAT :
1208 case MPP_DEC_QUERY :
1209 case MPP_DEC_SET_MAX_USE_BUFFER_SIZE: {
1210 ret = mpp_dec_control(mDec, cmd, param);
1211 } break;
1212 case MPP_DEC_SET_CFG : {
1213 if (mDec)
1214 ret = mpp_dec_control(mDec, cmd, param);
1215 else if (param) {
1216 MppDecCfgImpl *dec_cfg = (MppDecCfgImpl *)param;
1217
1218 ret = mpp_dec_set_cfg(&mDecInitcfg, &dec_cfg->cfg);
1219 }
1220 } break;
1221 case MPP_DEC_GET_CFG : {
1222 if (mDec)
1223 ret = mpp_dec_control(mDec, cmd, param);
1224 else if (param) {
1225 MppDecCfgImpl *dec_cfg = (MppDecCfgImpl *)param;
1226
1227 memcpy(&dec_cfg->cfg, &mDecInitcfg, sizeof(dec_cfg->cfg));
1228 ret = MPP_OK;
1229 }
1230 } break;
1231 default : {
1232 } break;
1233 }
1234 return ret;
1235 }
1236
control_enc(MpiCmd cmd,MppParam param)1237 MPP_RET Mpp::control_enc(MpiCmd cmd, MppParam param)
1238 {
1239 mpp_assert(mEnc);
1240 return mpp_enc_control_v2(mEnc, cmd, param);
1241 }
1242
control_isp(MpiCmd cmd,MppParam param)1243 MPP_RET Mpp::control_isp(MpiCmd cmd, MppParam param)
1244 {
1245 MPP_RET ret = MPP_NOK;
1246
1247 mpp_assert(cmd > MPP_ISP_CMD_BASE);
1248 mpp_assert(cmd < MPP_ISP_CMD_END);
1249
1250 (void)cmd;
1251 (void)param;
1252 return ret;
1253 }
1254
notify(RK_U32 flag)1255 MPP_RET Mpp::notify(RK_U32 flag)
1256 {
1257 switch (mType) {
1258 case MPP_CTX_DEC : {
1259 return mpp_dec_notify(mDec, flag);
1260 } break;
1261 case MPP_CTX_ENC : {
1262 return mpp_enc_notify_v2(mEnc, flag);
1263 } break;
1264 default : {
1265 mpp_err("unsupport context type %d\n", mType);
1266 } break;
1267 }
1268 return MPP_NOK;
1269 }
1270
notify(MppBufferGroup group)1271 MPP_RET Mpp::notify(MppBufferGroup group)
1272 {
1273 MPP_RET ret = MPP_NOK;
1274
1275 switch (mType) {
1276 case MPP_CTX_DEC : {
1277 if (group == mFrameGroup)
1278 ret = notify(MPP_DEC_NOTIFY_BUFFER_VALID |
1279 MPP_DEC_NOTIFY_BUFFER_MATCH);
1280 } break;
1281 default : {
1282 } break;
1283 }
1284
1285 return ret;
1286 }
1287