xref: /OK3568_Linux_fs/external/mpp/mpp/mpp.cpp (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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