/* * Copyright 2015 Rockchip Electronics Co. LTD * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define MODULE_TAG "mpp" #include #include #include "rk_mpi.h" #include "mpp_mem.h" #include "mpp_env.h" #include "mpp_time.h" #include "mpp_impl.h" #include "mpp_2str.h" #include "mpp_debug.h" #include "mpp.h" #include "mpp_hal.h" #include "mpp_task_impl.h" #include "mpp_buffer_impl.h" #include "mpp_frame_impl.h" #include "mpp_packet_impl.h" #include "mpp_dec_cfg_impl.h" #define MPP_TEST_FRAME_SIZE SZ_1M #define MPP_TEST_PACKET_SIZE SZ_512K typedef MPP_RET (*QueueFunc)(Mpp* mpp, MppPortType type, MppTask *task); static void mpp_notify_by_buffer_group(void *arg, void *group) { Mpp *mpp = (Mpp *)arg; mpp->notify((MppBufferGroup) group); } static void *list_wraper_packet(void *arg) { mpp_packet_deinit((MppPacket *)arg); return NULL; } static void *list_wraper_frame(void *arg) { mpp_frame_deinit((MppFrame *)arg); return NULL; } static MPP_RET check_frm_task_cnt_cap(MppCodingType coding) { if (coding != MPP_VIDEO_CodingAVC || !strstr(mpp_get_soc_name(), "rk3588")) { mpp_log("Only rk3588 h264 encoder can use frame parallel\n"); return MPP_NOK; } return MPP_OK; } Mpp::Mpp(MppCtx ctx) : mPktIn(NULL), mPktOut(NULL), mFrmIn(NULL), mFrmOut(NULL), mPacketPutCount(0), mPacketGetCount(0), mFramePutCount(0), mFrameGetCount(0), mTaskPutCount(0), mTaskGetCount(0), mPacketGroup(NULL), mFrameGroup(NULL), mExternalFrameGroup(0), mUsrInPort(NULL), mUsrOutPort(NULL), mMppInPort(NULL), mMppOutPort(NULL), mInputTaskQueue(NULL), mOutputTaskQueue(NULL), mInputTimeout(MPP_POLL_BUTT), mOutputTimeout(MPP_POLL_BUTT), mInputTask(NULL), mEosTask(NULL), mCtx(ctx), mDec(NULL), mEnc(NULL), mEncAyncIo(0), mEncAyncProc(0), mIoMode(MPP_IO_MODE_DEFAULT), mType(MPP_CTX_BUTT), mCoding(MPP_VIDEO_CodingUnused), mInitDone(0), mStatus(0), mExtraPacket(NULL), mDump(NULL) { mpp_env_get_u32("mpp_debug", &mpp_debug, 0); memset(&mDecInitcfg, 0, sizeof(mDecInitcfg)); mpp_dec_cfg_set_default(&mDecInitcfg); mDecInitcfg.base.enable_vproc = 1; mDecInitcfg.base.change |= MPP_DEC_CFG_CHANGE_ENABLE_VPROC; mpp_dump_init(&mDump); } MPP_RET Mpp::init(MppCtxType type, MppCodingType coding) { MPP_RET ret = MPP_NOK; if (!mpp_check_soc_cap(type, coding)) { mpp_err("unable to create %s %s for soc %s unsupported\n", strof_ctx_type(type), strof_coding_type(coding), mpp_get_soc_info()->compatible); return MPP_NOK; } if (mpp_check_support_format(type, coding)) { mpp_err("unable to create %s %s for mpp unsupported\n", strof_ctx_type(type), strof_coding_type(coding)); return MPP_NOK; } mpp_ops_init(mDump, type, coding); mType = type; mCoding = coding; mpp_task_queue_init(&mInputTaskQueue, this, "input"); mpp_task_queue_init(&mOutputTaskQueue, this, "output"); switch (mType) { case MPP_CTX_DEC : { mPktIn = new mpp_list(list_wraper_packet); mFrmOut = new mpp_list(list_wraper_frame); if (mInputTimeout == MPP_POLL_BUTT) mInputTimeout = MPP_POLL_NON_BLOCK; if (mOutputTimeout == MPP_POLL_BUTT) mOutputTimeout = MPP_POLL_NON_BLOCK; if (mCoding != MPP_VIDEO_CodingMJPEG) { mpp_buffer_group_get_internal(&mPacketGroup, MPP_BUFFER_TYPE_ION); mpp_buffer_group_limit_config(mPacketGroup, 0, 3); mpp_task_queue_setup(mInputTaskQueue, 4); mpp_task_queue_setup(mOutputTaskQueue, 4); } else { mpp_task_queue_setup(mInputTaskQueue, 1); mpp_task_queue_setup(mOutputTaskQueue, 1); } mUsrInPort = mpp_task_queue_get_port(mInputTaskQueue, MPP_PORT_INPUT); mUsrOutPort = mpp_task_queue_get_port(mOutputTaskQueue, MPP_PORT_OUTPUT); mMppInPort = mpp_task_queue_get_port(mInputTaskQueue, MPP_PORT_OUTPUT); mMppOutPort = mpp_task_queue_get_port(mOutputTaskQueue, MPP_PORT_INPUT); MppDecInitCfg cfg = { coding, this, &mDecInitcfg, }; ret = mpp_dec_init(&mDec, &cfg); if (ret) break; ret = mpp_dec_start(mDec); if (ret) break; mInitDone = 1; } break; case MPP_CTX_ENC : { mPktIn = new mpp_list(list_wraper_packet); mPktOut = new mpp_list(list_wraper_packet); mFrmIn = new mpp_list(NULL); mFrmOut = new mpp_list(NULL); if (mInputTimeout == MPP_POLL_BUTT) mInputTimeout = MPP_POLL_BLOCK; if (mOutputTimeout == MPP_POLL_BUTT) mOutputTimeout = MPP_POLL_NON_BLOCK; mpp_buffer_group_get_internal(&mPacketGroup, MPP_BUFFER_TYPE_ION); mpp_buffer_group_get_internal(&mFrameGroup, MPP_BUFFER_TYPE_ION); mpp_task_queue_setup(mInputTaskQueue, 1); mpp_task_queue_setup(mOutputTaskQueue, 8); mUsrInPort = mpp_task_queue_get_port(mInputTaskQueue, MPP_PORT_INPUT); mUsrOutPort = mpp_task_queue_get_port(mOutputTaskQueue, MPP_PORT_OUTPUT); mMppInPort = mpp_task_queue_get_port(mInputTaskQueue, MPP_PORT_OUTPUT); mMppOutPort = mpp_task_queue_get_port(mOutputTaskQueue, MPP_PORT_INPUT); if (mInputTimeout == MPP_POLL_NON_BLOCK) { mEncAyncIo = 1; if (check_frm_task_cnt_cap(coding)) mInputTimeout = MPP_POLL_BLOCK; } MppEncInitCfg cfg = { coding, (mInputTimeout) ? (1) : (2), this, }; ret = mpp_enc_init_v2(&mEnc, &cfg); if (ret) break; if (mInputTimeout == MPP_POLL_NON_BLOCK) { mEncAyncProc = 1; ret = mpp_enc_start_async(mEnc); } else { ret = mpp_enc_start_v2(mEnc); } if (ret) break; mInitDone = 1; } break; default : { mpp_err("Mpp error type %d\n", mType); } break; } if (!mInitDone) { mpp_err("error found on mpp initialization\n"); clear(); } return ret; } Mpp::~Mpp () { clear(); } void Mpp::clear() { // MUST: release listener here if (mFrameGroup) mpp_buffer_group_set_callback((MppBufferGroupImpl *)mFrameGroup, NULL, NULL); if (mType == MPP_CTX_DEC) { if (mDec) { mpp_dec_stop(mDec); mpp_dec_deinit(mDec); mDec = NULL; } } else { if (mEnc) { mpp_enc_stop_v2(mEnc); mpp_enc_deinit_v2(mEnc); mEnc = NULL; } } if (mInputTaskQueue) { mpp_task_queue_deinit(mInputTaskQueue); mInputTaskQueue = NULL; } if (mOutputTaskQueue) { mpp_task_queue_deinit(mOutputTaskQueue); mOutputTaskQueue = NULL; } mUsrInPort = NULL; mUsrOutPort = NULL; mMppInPort = NULL; mMppOutPort = NULL; if (mExtraPacket) { mpp_packet_deinit(&mExtraPacket); mExtraPacket = NULL; } if (mPktIn) { delete mPktIn; mPktIn = NULL; } if (mPktOut) { delete mPktOut; mPktOut = NULL; } if (mFrmIn) { delete mFrmIn; mFrmIn = NULL; } if (mFrmOut) { delete mFrmOut; mFrmOut = NULL; } if (mPacketGroup) { mpp_buffer_group_put(mPacketGroup); mPacketGroup = NULL; } if (mFrameGroup && !mExternalFrameGroup) { mpp_buffer_group_put(mFrameGroup); mFrameGroup = NULL; } mpp_dump_deinit(&mDump); } MPP_RET Mpp::start() { return MPP_OK; } MPP_RET Mpp::stop() { return MPP_OK; } MPP_RET Mpp::pause() { return MPP_OK; } MPP_RET Mpp::resume() { return MPP_OK; } MPP_RET Mpp::put_packet(MppPacket packet) { if (!mInitDone) return MPP_ERR_INIT; MPP_RET ret = MPP_NOK; MppPollType timeout = mInputTimeout; MppTask task_dequeue = NULL; RK_U32 pkt_copy = 0; if (mExtraPacket) { MppPacket extra = mExtraPacket; mExtraPacket = NULL; put_packet(extra); } if (!mEosTask) { /* handle eos packet on block mode */ ret = poll(MPP_PORT_INPUT, MPP_POLL_BLOCK); if (ret < 0) goto RET; dequeue(MPP_PORT_INPUT, &mEosTask); if (NULL == mEosTask) { mpp_err_f("fail to reserve eos task\n", ret); ret = MPP_NOK; goto RET; } } if (mpp_packet_get_eos(packet)) { mpp_assert(mEosTask); task_dequeue = mEosTask; mEosTask = NULL; } /* Use reserved task to send eos packet */ if (mInputTask && !task_dequeue) { task_dequeue = mInputTask; mInputTask = NULL; } if (NULL == task_dequeue) { ret = poll(MPP_PORT_INPUT, timeout); if (ret < 0) { ret = MPP_ERR_BUFFER_FULL; goto RET; } /* do not pull here to avoid block wait */ dequeue(MPP_PORT_INPUT, &task_dequeue); if (NULL == task_dequeue) { mpp_err_f("fail to get task on poll ret %d\n", ret); ret = MPP_NOK; goto RET; } } if (NULL == mpp_packet_get_buffer(packet)) { /* packet copy path */ MppPacket pkt_in = NULL; mpp_packet_copy_init(&pkt_in, packet); mpp_packet_set_length(packet, 0); pkt_copy = 1; packet = pkt_in; ret = MPP_OK; } else { /* packet zero copy path */ mpp_log_f("not support zero copy path\n"); timeout = MPP_POLL_BLOCK; } /* setup task */ ret = mpp_task_meta_set_packet(task_dequeue, KEY_INPUT_PACKET, packet); if (ret) { mpp_err_f("set input frame to task ret %d\n", ret); /* keep current task for next */ mInputTask = task_dequeue; goto RET; } mpp_ops_dec_put_pkt(mDump, packet); /* enqueue valid task to decoder */ ret = enqueue(MPP_PORT_INPUT, task_dequeue); if (ret) { mpp_err_f("enqueue ret %d\n", ret); goto RET; } mPacketPutCount++; if (timeout && !pkt_copy) ret = poll(MPP_PORT_INPUT, timeout); RET: /* wait enqueued task finished */ if (NULL == mInputTask) { MPP_RET cnt = poll(MPP_PORT_INPUT, MPP_POLL_NON_BLOCK); /* reserve one task for eos block mode */ if (cnt >= 0) { dequeue(MPP_PORT_INPUT, &mInputTask); mpp_assert(mInputTask); } } return ret; } MPP_RET Mpp::get_frame(MppFrame *frame) { if (!mInitDone) return MPP_ERR_INIT; AutoMutex autoFrameLock(mFrmOut->mutex()); MppFrame frm = NULL; if (0 == mFrmOut->list_size()) { if (mOutputTimeout) { if (mOutputTimeout < 0) { /* block wait */ mFrmOut->wait(); } else { RK_S32 ret = mFrmOut->wait(mOutputTimeout); if (ret) { if (ret == ETIMEDOUT) return MPP_ERR_TIMEOUT; else return MPP_NOK; } } } } if (mFrmOut->list_size()) { mFrmOut->del_at_head(&frm, sizeof(frame)); mFrameGetCount++; notify(MPP_OUTPUT_DEQUEUE); } else { // NOTE: Add signal here is not efficient // This is for fix bug of stucking on decoder parser thread // When decoder parser thread is block by info change and enter waiting. // There is no way to wake up parser thread to continue decoding. // The put_packet only signal sem on may be it better to use sem on info // change too. AutoMutex autoPacketLock(mPktIn->mutex()); if (mPktIn->list_size()) notify(MPP_INPUT_ENQUEUE); } *frame = frm; // dump output mpp_ops_dec_get_frm(mDump, frm); return MPP_OK; } MPP_RET Mpp::put_frame(MppFrame frame) { if (!mInitDone) return MPP_ERR_INIT; if (mInputTimeout == MPP_POLL_NON_BLOCK) { set_io_mode(MPP_IO_MODE_NORMAL); return put_frame_async(frame); } MPP_RET ret = MPP_NOK; MppStopwatch stopwatch = NULL; if (mpp_debug & MPP_DBG_TIMING) { mpp_frame_set_stopwatch_enable(frame, 1); stopwatch = mpp_frame_get_stopwatch(frame); } mpp_stopwatch_record(stopwatch, NULL); mpp_stopwatch_record(stopwatch, "put frame start"); if (mInputTask == NULL) { mpp_stopwatch_record(stopwatch, "input port user poll"); /* poll input port for valid task */ ret = poll(MPP_PORT_INPUT, mInputTimeout); if (ret < 0) { if (mInputTimeout) mpp_log_f("poll on set timeout %d ret %d\n", mInputTimeout, ret); goto RET; } /* dequeue task for setup */ mpp_stopwatch_record(stopwatch, "input port user dequeue"); ret = dequeue(MPP_PORT_INPUT, &mInputTask); if (ret || NULL == mInputTask) { mpp_log_f("dequeue on set ret %d task %p\n", ret, mInputTask); goto RET; } } mpp_assert(mInputTask); /* setup task */ ret = mpp_task_meta_set_frame(mInputTask, KEY_INPUT_FRAME, frame); if (ret) { mpp_log_f("set input frame to task ret %d\n", ret); goto RET; } if (mpp_frame_has_meta(frame)) { MppMeta meta = mpp_frame_get_meta(frame); MppPacket packet = NULL; MppBuffer md_info_buf = NULL; mpp_meta_get_packet(meta, KEY_OUTPUT_PACKET, &packet); if (packet) { ret = mpp_task_meta_set_packet(mInputTask, KEY_OUTPUT_PACKET, packet); if (ret) { mpp_log_f("set output packet to task ret %d\n", ret); goto RET; } } mpp_meta_get_buffer(meta, KEY_MOTION_INFO, &md_info_buf); if (md_info_buf) { ret = mpp_task_meta_set_buffer(mInputTask, KEY_MOTION_INFO, md_info_buf); if (ret) { mpp_log_f("set output motion dection info ret %d\n", ret); goto RET; } } } // dump input mpp_ops_enc_put_frm(mDump, frame); /* enqueue valid task to encoder */ mpp_stopwatch_record(stopwatch, "input port user enqueue"); ret = enqueue(MPP_PORT_INPUT, mInputTask); if (ret) { mpp_log_f("enqueue ret %d\n", ret); goto RET; } mInputTask = NULL; /* wait enqueued task finished */ mpp_stopwatch_record(stopwatch, "input port user poll"); ret = poll(MPP_PORT_INPUT, mInputTimeout); if (ret < 0) { if (mInputTimeout) mpp_log_f("poll on get timeout %d ret %d\n", mInputTimeout, ret); goto RET; } /* get previous enqueued task back */ mpp_stopwatch_record(stopwatch, "input port user dequeue"); ret = dequeue(MPP_PORT_INPUT, &mInputTask); if (ret) { mpp_log_f("dequeue on get ret %d\n", ret); goto RET; } mpp_assert(mInputTask); if (mInputTask) { MppFrame frm_out = NULL; mpp_task_meta_get_frame(mInputTask, KEY_INPUT_FRAME, &frm_out); mpp_assert(frm_out == frame); } RET: mpp_stopwatch_record(stopwatch, "put_frame finish"); mpp_frame_set_stopwatch_enable(frame, 0); return ret; } MPP_RET Mpp::get_packet(MppPacket *packet) { if (!mInitDone) return MPP_ERR_INIT; if (mInputTimeout == MPP_POLL_NON_BLOCK) { set_io_mode(MPP_IO_MODE_NORMAL); return get_packet_async(packet); } MPP_RET ret = MPP_OK; MppTask task = NULL; ret = poll(MPP_PORT_OUTPUT, mOutputTimeout); if (ret < 0) { // NOTE: Do not treat poll failure as error. Just clear output ret = MPP_OK; *packet = NULL; goto RET; } ret = dequeue(MPP_PORT_OUTPUT, &task); if (ret || NULL == task) { mpp_log_f("dequeue on get ret %d task %p\n", ret, task); goto RET; } mpp_assert(task); ret = mpp_task_meta_get_packet(task, KEY_OUTPUT_PACKET, packet); if (ret) { mpp_log_f("get output packet from task ret %d\n", ret); goto RET; } mpp_assert(*packet); mpp_dbg_pts("pts %lld\n", mpp_packet_get_pts(*packet)); // dump output mpp_ops_enc_get_pkt(mDump, *packet); ret = enqueue(MPP_PORT_OUTPUT, task); if (ret) mpp_log_f("enqueue on set ret %d\n", ret); RET: return ret; } MPP_RET Mpp::put_frame_async(MppFrame frame) { if (NULL == mFrmIn) return MPP_NOK; if (mFrmIn->trylock()) return MPP_NOK; /* NOTE: the max input queue length is 2 */ if (mFrmIn->list_size() >= 2) { mFrmIn->unlock(); return MPP_NOK; } mFrmIn->add_at_tail(&frame, sizeof(frame)); mFramePutCount++; notify(MPP_INPUT_ENQUEUE); mFrmIn->unlock(); return MPP_OK; } MPP_RET Mpp::get_packet_async(MppPacket *packet) { MppPacket pkt = NULL; AutoMutex autoPacketLock(mPktOut->mutex()); if (0 == mPktOut->list_size()) { if (mOutputTimeout) { if (mOutputTimeout < 0) { /* block wait */ mPktOut->wait(); } else { RK_S32 ret = mPktOut->wait(mOutputTimeout); if (ret) { if (ret == ETIMEDOUT) return MPP_ERR_TIMEOUT; else return MPP_NOK; } } } else { /* NOTE: in non-block mode the sleep is to avoid user's dead loop */ msleep(1); } } if (mPktOut->list_size()) { mPktOut->del_at_head(&pkt, sizeof(pkt)); mPacketGetCount++; notify(MPP_OUTPUT_DEQUEUE); } else { AutoMutex autoFrameLock(mFrmIn->mutex()); if (mFrmIn->list_size()) notify(MPP_INPUT_ENQUEUE); } *packet = pkt; return MPP_OK; } MPP_RET Mpp::poll(MppPortType type, MppPollType timeout) { if (!mInitDone) return MPP_ERR_INIT; MPP_RET ret = MPP_NOK; MppTaskQueue port = NULL; set_io_mode(MPP_IO_MODE_TASK); switch (type) { case MPP_PORT_INPUT : { port = mUsrInPort; } break; case MPP_PORT_OUTPUT : { port = mUsrOutPort; } break; default : { } break; } if (port) ret = mpp_port_poll(port, timeout); return ret; } MPP_RET Mpp::dequeue(MppPortType type, MppTask *task) { if (!mInitDone) return MPP_ERR_INIT; MPP_RET ret = MPP_NOK; MppTaskQueue port = NULL; RK_U32 notify_flag = 0; set_io_mode(MPP_IO_MODE_TASK); switch (type) { case MPP_PORT_INPUT : { port = mUsrInPort; notify_flag = MPP_INPUT_DEQUEUE; } break; case MPP_PORT_OUTPUT : { port = mUsrOutPort; notify_flag = MPP_OUTPUT_DEQUEUE; } break; default : { } break; } if (port) { ret = mpp_port_dequeue(port, task); if (MPP_OK == ret) notify(notify_flag); } return ret; } MPP_RET Mpp::enqueue(MppPortType type, MppTask task) { if (!mInitDone) return MPP_ERR_INIT; MPP_RET ret = MPP_NOK; MppTaskQueue port = NULL; RK_U32 notify_flag = 0; set_io_mode(MPP_IO_MODE_TASK); switch (type) { case MPP_PORT_INPUT : { port = mUsrInPort; notify_flag = MPP_INPUT_ENQUEUE; } break; case MPP_PORT_OUTPUT : { port = mUsrOutPort; notify_flag = MPP_OUTPUT_ENQUEUE; } break; default : { } break; } if (port) { ret = mpp_port_enqueue(port, task); // if enqueue success wait up thread if (MPP_OK == ret) notify(notify_flag); } return ret; } void Mpp::set_io_mode(MppIoMode mode) { mpp_assert(mode == MPP_IO_MODE_NORMAL || mode == MPP_IO_MODE_TASK); if (mIoMode == MPP_IO_MODE_DEFAULT) mIoMode = mode; else if (mIoMode != mode) { static const char *iomode_2str[] = { "normal", "task queue", }; mpp_assert(mIoMode < MPP_IO_MODE_BUTT); mpp_assert(mode < MPP_IO_MODE_BUTT); mpp_err("can not reset io mode from %s to %s\n", iomode_2str[!!mIoMode], iomode_2str[!!mode]); } } MPP_RET Mpp::control(MpiCmd cmd, MppParam param) { MPP_RET ret = MPP_NOK; mpp_ops_ctrl(mDump, cmd); switch (cmd & CMD_MODULE_ID_MASK) { case CMD_MODULE_OSAL : { ret = control_osal(cmd, param); } break; case CMD_MODULE_MPP : { mpp_assert(cmd > MPP_CMD_BASE); mpp_assert(cmd < MPP_CMD_END); ret = control_mpp(cmd, param); } break; case CMD_MODULE_CODEC : { switch (cmd & CMD_CTX_ID_MASK) { case CMD_CTX_ID_DEC : { mpp_assert(mType == MPP_CTX_DEC || mType == MPP_CTX_BUTT); mpp_assert(cmd > MPP_DEC_CMD_BASE); mpp_assert(cmd < MPP_DEC_CMD_END); ret = control_dec(cmd, param); } break; case CMD_CTX_ID_ENC : { mpp_assert(mType == MPP_CTX_ENC); mpp_assert(cmd > MPP_ENC_CMD_BASE); mpp_assert(cmd < MPP_ENC_CMD_END); ret = control_enc(cmd, param); } break; case CMD_CTX_ID_ISP : { mpp_assert(mType == MPP_CTX_ISP); ret = control_isp(cmd, param); } break; default : { mpp_assert(cmd > MPP_CODEC_CMD_BASE); mpp_assert(cmd < MPP_CODEC_CMD_END); ret = control_codec(cmd, param); } break; } } break; default : { } break; } if (ret) mpp_err("command %x param %p ret %d\n", cmd, param, ret); return ret; } MPP_RET Mpp::reset() { if (!mInitDone) return MPP_ERR_INIT; mpp_ops_reset(mDump); if (mType == MPP_CTX_DEC) { /* * On mp4 case extra data of sps/pps will be put at the beginning * If these packet was reset before they are send to decoder then * decoder can not get these important information to continue decoding * To avoid this case happen we need to save it on reset beginning * then restore it on reset end. */ mPktIn->lock(); while (mPktIn->list_size()) { MppPacket pkt = NULL; mPktIn->del_at_head(&pkt, sizeof(pkt)); mPacketGetCount++; RK_U32 flags = mpp_packet_get_flag(pkt); if (flags & MPP_PACKET_FLAG_EXTRA_DATA) { if (mExtraPacket) { mpp_packet_deinit(&mExtraPacket); } mExtraPacket = pkt; } else { mpp_packet_deinit(&pkt); } } mPktIn->flush(); mPktIn->unlock(); mpp_dec_reset(mDec); mFrmOut->lock(); mFrmOut->flush(); mFrmOut->unlock(); mpp_port_awake(mUsrInPort); mpp_port_awake(mUsrOutPort); } else { mpp_enc_reset_v2(mEnc); } return MPP_OK; } MPP_RET Mpp::control_mpp(MpiCmd cmd, MppParam param) { MPP_RET ret = MPP_OK; switch (cmd) { case MPP_SET_INPUT_BLOCK : case MPP_SET_OUTPUT_BLOCK : case MPP_SET_INTPUT_BLOCK_TIMEOUT : case MPP_SET_OUTPUT_BLOCK_TIMEOUT : { MppPollType block = (param) ? *((MppPollType *)param) : MPP_POLL_NON_BLOCK; if (block <= MPP_POLL_BUTT || block > MPP_POLL_MAX) { mpp_err("invalid output timeout type %d should be in range [%d, %d]\n", block, MPP_POLL_BUTT, MPP_POLL_MAX); ret = MPP_ERR_VALUE; break; } if (cmd == MPP_SET_INPUT_BLOCK || cmd == MPP_SET_INTPUT_BLOCK_TIMEOUT) mInputTimeout = block; else mOutputTimeout = block; mpp_log("deprecated block control, use timeout control instead\n"); } break; case MPP_SET_INPUT_TIMEOUT: case MPP_SET_OUTPUT_TIMEOUT: { MppPollType timeout = (param) ? *((MppPollType *)param) : MPP_POLL_NON_BLOCK; if (timeout <= MPP_POLL_BUTT || timeout > MPP_POLL_MAX) { mpp_err("invalid output timeout type %d should be in range [%d, %d]\n", timeout, MPP_POLL_BUTT, MPP_POLL_MAX); ret = MPP_ERR_VALUE; break; } if (cmd == MPP_SET_INPUT_TIMEOUT) mInputTimeout = timeout; else mOutputTimeout = timeout; } break; case MPP_START : { start(); } break; case MPP_STOP : { stop(); } break; case MPP_PAUSE : { pause(); } break; case MPP_RESUME : { resume(); } break; default : { ret = MPP_NOK; } break; } return ret; } MPP_RET Mpp::control_osal(MpiCmd cmd, MppParam param) { MPP_RET ret = MPP_NOK; mpp_assert(cmd > MPP_OSAL_CMD_BASE); mpp_assert(cmd < MPP_OSAL_CMD_END); (void)cmd; (void)param; return ret; } MPP_RET Mpp::control_codec(MpiCmd cmd, MppParam param) { MPP_RET ret = MPP_NOK; (void)cmd; (void)param; return ret; } MPP_RET Mpp::control_dec(MpiCmd cmd, MppParam param) { MPP_RET ret = MPP_NOK; switch (cmd) { case MPP_DEC_SET_FRAME_INFO: { ret = mpp_dec_control(mDec, cmd, param); } break; case MPP_DEC_SET_EXT_BUF_GROUP: { mFrameGroup = (MppBufferGroup)param; if (param) { mExternalFrameGroup = 1; mpp_dbg_info("using external buffer group %p\n", mFrameGroup); if (mInitDone) { ret = mpp_buffer_group_set_callback((MppBufferGroupImpl *)param, mpp_notify_by_buffer_group, (void *)this); notify(MPP_DEC_NOTIFY_EXT_BUF_GRP_READY); } else { /* * NOTE: If frame buffer group is configured before decoder init * then the buffer limitation maybe not be correctly setup * without infomation from InfoChange frame. * And the thread signal connection may not be setup here. It * may have a bad effect on MPP efficiency. */ mpp_err("WARNING: setup buffer group before decoder init\n"); } } else { /* The buffer group should be destroyed before */ mExternalFrameGroup = 0; ret = MPP_OK; } } break; case MPP_DEC_SET_INFO_CHANGE_READY: { mpp_dbg_info("set info change ready\n"); ret = mpp_dec_control(mDec, cmd, param); notify(MPP_DEC_NOTIFY_INFO_CHG_DONE | MPP_DEC_NOTIFY_BUFFER_MATCH); } break; case MPP_DEC_SET_PRESENT_TIME_ORDER : case MPP_DEC_SET_PARSER_SPLIT_MODE : case MPP_DEC_SET_PARSER_FAST_MODE : case MPP_DEC_SET_IMMEDIATE_OUT : case MPP_DEC_SET_DISABLE_ERROR : case MPP_DEC_SET_ENABLE_DEINTERLACE : case MPP_DEC_SET_ENABLE_FAST_PLAY : { /* * These control may be set before mpp_init * When this case happen record the config and wait for decoder init */ if (mDec) { ret = mpp_dec_control(mDec, cmd, param); return ret; } ret = mpp_dec_set_cfg_by_cmd(&mDecInitcfg, cmd, param); } break; case MPP_DEC_GET_STREAM_COUNT: { AutoMutex autoLock(mPktIn->mutex()); *((RK_S32 *)param) = mPktIn->list_size(); ret = MPP_OK; } break; case MPP_DEC_GET_VPUMEM_USED_COUNT : case MPP_DEC_SET_OUTPUT_FORMAT : case MPP_DEC_QUERY : { ret = mpp_dec_control(mDec, cmd, param); } break; case MPP_DEC_SET_CFG : { if (mDec) ret = mpp_dec_control(mDec, cmd, param); else if (param) { MppDecCfgImpl *dec_cfg = (MppDecCfgImpl *)param; ret = mpp_dec_set_cfg(&mDecInitcfg, &dec_cfg->cfg); } } break; case MPP_DEC_GET_CFG : { if (mDec) ret = mpp_dec_control(mDec, cmd, param); else if (param) { MppDecCfgImpl *dec_cfg = (MppDecCfgImpl *)param; memcpy(&dec_cfg->cfg, &mDecInitcfg, sizeof(dec_cfg->cfg)); ret = MPP_OK; } } break; default : { } break; } return ret; } MPP_RET Mpp::control_enc(MpiCmd cmd, MppParam param) { mpp_assert(mEnc); return mpp_enc_control_v2(mEnc, cmd, param); } MPP_RET Mpp::control_isp(MpiCmd cmd, MppParam param) { MPP_RET ret = MPP_NOK; mpp_assert(cmd > MPP_ISP_CMD_BASE); mpp_assert(cmd < MPP_ISP_CMD_END); (void)cmd; (void)param; return ret; } MPP_RET Mpp::notify(RK_U32 flag) { switch (mType) { case MPP_CTX_DEC : { return mpp_dec_notify(mDec, flag); } break; case MPP_CTX_ENC : { return mpp_enc_notify_v2(mEnc, flag); } break; default : { mpp_err("unsupport context type %d\n", mType); } break; } return MPP_NOK; } MPP_RET Mpp::notify(MppBufferGroup group) { MPP_RET ret = MPP_NOK; switch (mType) { case MPP_CTX_DEC : { if (group == mFrameGroup) ret = notify(MPP_DEC_NOTIFY_BUFFER_VALID | MPP_DEC_NOTIFY_BUFFER_MATCH); } break; default : { } break; } return ret; }