diff --git a/mpp/base/mpp_buffer_impl.cpp b/mpp/base/mpp_buffer_impl.cpp index d86790ef..c3d23104 100644 --- a/mpp/base/mpp_buffer_impl.cpp +++ b/mpp/base/mpp_buffer_impl.cpp @@ -678,10 +678,8 @@ MPP_RET mpp_buffer_group_reset(MppBufferGroupImpl *p) MPP_RET mpp_buffer_group_set_callback(MppBufferGroupImpl *p, MppBufCallback callback, void *arg) { - if (NULL == p) { - mpp_err_f("found NULL pointer\n"); - return MPP_ERR_NULL_PTR; - } + if (!p) + return MPP_OK; MPP_BUF_FUNCTION_ENTER(); diff --git a/mpp/inc/mpp.h b/mpp/inc/mpp.h index f67753f4..c4a621db 100644 --- a/mpp/inc/mpp.h +++ b/mpp/inc/mpp.h @@ -153,7 +153,7 @@ public: */ MppBufferGroup mPacketGroup; MppBufferGroup mFrameGroup; - RK_U32 mExternalFrameGroup; + RK_U32 mExternalBufferMode; /* * Mpp task queue for advance task mode diff --git a/mpp/mpp.cpp b/mpp/mpp.cpp index 43179ddc..addf48e7 100644 --- a/mpp/mpp.cpp +++ b/mpp/mpp.cpp @@ -88,7 +88,7 @@ Mpp::Mpp(MppCtx ctx) mTaskGetCount(0), mPacketGroup(NULL), mFrameGroup(NULL), - mExternalFrameGroup(0), + mExternalBufferMode(0), mUsrInPort(NULL), mUsrOutPort(NULL), mMppInPort(NULL), @@ -327,7 +327,7 @@ void Mpp::clear() mPacketGroup = NULL; } - if (mFrameGroup && !mExternalFrameGroup) { + if (mFrameGroup && !mExternalBufferMode) { mpp_buffer_group_put(mFrameGroup); mFrameGroup = NULL; } @@ -1173,32 +1173,60 @@ MPP_RET Mpp::control_dec(MpiCmd cmd, MppParam param) ret = mpp_dec_control(mDec, cmd, param); } break; case MPP_DEC_SET_EXT_BUF_GROUP: { - mFrameGroup = (MppBufferGroup)param; - if (param) { - mExternalFrameGroup = 1; + /* + * 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. + */ + if (!mInitDone) { + mpp_err("WARNING: setup buffer group before decoder init\n"); + break; + } + + ret = MPP_OK; + if (!param) { + /* set to internal mode */ + if (mExternalBufferMode) { + /* switch from external mode to internal mode */ + mpp_assert(mFrameGroup); + mpp_buffer_group_set_callback((MppBufferGroupImpl *)mFrameGroup, + NULL, NULL); + mFrameGroup = NULL; + } else { + /* keep internal buffer mode cleanup old buffers */ + if (mFrameGroup) + mpp_buffer_group_clear(mFrameGroup); + } + + mpp_dbg_info("using internal buffer group %p\n", mFrameGroup); + mExternalBufferMode = 0; + } else { + /* set to external mode */ + if (mExternalBufferMode) { + /* keep external buffer mode */ + if (mFrameGroup != param) { + /* switch to new buffer group */ + mpp_assert(mFrameGroup); + mpp_buffer_group_set_callback((MppBufferGroupImpl *)mFrameGroup, + NULL, NULL); + } else { + /* keep old group the external group user should cleanup its old buffers */ + } + } else { + /* switch from intenal mode to external mode */ + if (mFrameGroup) + mpp_buffer_group_put(mFrameGroup); + } 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; + mFrameGroup = (MppBufferGroup)param; + mpp_buffer_group_set_callback((MppBufferGroupImpl *)mFrameGroup, + mpp_notify_by_buffer_group, (void *)this); + mExternalBufferMode = 1; + notify(MPP_DEC_NOTIFY_EXT_BUF_GRP_READY); } } break; case MPP_DEC_SET_INFO_CHANGE_READY: { diff --git a/test/mpi_dec_mt_test.c b/test/mpi_dec_mt_test.c index 97f02624..d71fcd8f 100644 --- a/test/mpi_dec_mt_test.c +++ b/test/mpi_dec_mt_test.c @@ -43,6 +43,7 @@ typedef struct { char *buf; /* input and output */ + DecBufMgr buf_mgr; MppBufferGroup frm_grp; MppPacket packet; size_t packet_size; @@ -147,40 +148,20 @@ void *thread_output(void *arg) RK_U32 hor_stride = mpp_frame_get_hor_stride(frame); RK_U32 ver_stride = mpp_frame_get_ver_stride(frame); RK_U32 buf_size = mpp_frame_get_buf_size(frame); + MppBufferGroup grp = NULL; mpp_log_q(quiet, "decode_get_frame get info changed found\n"); mpp_log_q(quiet, "decoder require buffer w:h [%d:%d] stride [%d:%d] size %d\n", width, height, hor_stride, ver_stride, buf_size); - if (NULL == data->frm_grp) { - /* If buffer group is not set create one and limit it */ - ret = mpp_buffer_group_get_internal(&data->frm_grp, MPP_BUFFER_TYPE_ION | MPP_BUFFER_FLAGS_CACHABLE); - if (ret) { - mpp_err("get mpp buffer group failed ret %d\n", ret); - break; - } - - /* Set buffer to mpp decoder */ - ret = mpi->control(ctx, MPP_DEC_SET_EXT_BUF_GROUP, data->frm_grp); - if (ret) { - mpp_err("set buffer group failed ret %d\n", ret); - break; - } - } else { - /* If old buffer group exist clear it */ - ret = mpp_buffer_group_clear(data->frm_grp); - if (ret) { - mpp_err("clear buffer group failed ret %d\n", ret); - break; - } - } - - /* Use limit config to limit buffer count to 24 */ - ret = mpp_buffer_group_limit_config(data->frm_grp, buf_size, 24); + grp = dec_buf_mgr_setup(data->buf_mgr, buf_size, 24, cmd->buf_mode); + /* Set buffer to mpp decoder */ + ret = mpi->control(ctx, MPP_DEC_SET_EXT_BUF_GROUP, grp); if (ret) { - mpp_err("limit buffer group failed ret %d\n", ret); + mpp_err("%p set buffer group failed ret %d\n", ctx, ret); break; } + data->frm_grp = grp; ret = mpi->control(ctx, MPP_DEC_SET_INFO_CHANGE_READY, NULL); if (ret) { @@ -271,6 +252,12 @@ int mt_dec_decode(MpiDecTestCmd *cmd) } } + ret = dec_buf_mgr_init(&data.buf_mgr); + if (ret) { + mpp_err("dec_buf_mgr_init failed\n"); + goto MPP_TEST_OUT; + } + ret = mpp_packet_init(&packet, NULL, 0); if (ret) { mpp_err("mpp_packet_init failed\n"); @@ -396,9 +383,10 @@ MPP_TEST_OUT: ctx = NULL; } - if (data.frm_grp) { - mpp_buffer_group_put(data.frm_grp); - data.frm_grp = NULL; + data.frm_grp = NULL; + if (data.buf_mgr) { + dec_buf_mgr_deinit(data.buf_mgr); + data.buf_mgr = NULL; } if (data.fp_output) { diff --git a/test/mpi_dec_multi_test.c b/test/mpi_dec_multi_test.c index 84e83652..89400058 100644 --- a/test/mpi_dec_multi_test.c +++ b/test/mpi_dec_multi_test.c @@ -42,6 +42,7 @@ typedef struct { RK_U32 loop_end; /* input and output */ + DecBufMgr buf_mgr; MppBufferGroup frm_grp; MppPacket packet; MppFrame frame; @@ -151,40 +152,20 @@ static int multi_dec_simple(MpiDecMultiCtx *data) RK_U32 hor_stride = mpp_frame_get_hor_stride(frame); RK_U32 ver_stride = mpp_frame_get_ver_stride(frame); RK_U32 buf_size = mpp_frame_get_buf_size(frame); + MppBufferGroup grp = NULL; mpp_log_q(quiet, "decode_get_frame get info changed found\n"); mpp_log_q(quiet, "decoder require buffer w:h [%d:%d] stride [%d:%d] buf_size %d", width, height, hor_stride, ver_stride, buf_size); - if (NULL == data->frm_grp) { - /* If buffer group is not set create one and limit it */ - ret = mpp_buffer_group_get_internal(&data->frm_grp, MPP_BUFFER_TYPE_ION | MPP_BUFFER_FLAGS_CACHABLE); - if (ret) { - mpp_err("get mpp buffer group failed ret %d\n", ret); - break; - } - - /* Set buffer to mpp decoder */ - ret = mpi->control(ctx, MPP_DEC_SET_EXT_BUF_GROUP, data->frm_grp); - if (ret) { - mpp_err("set buffer group failed ret %d\n", ret); - break; - } - } else { - /* If old buffer group exist clear it */ - ret = mpp_buffer_group_clear(data->frm_grp); - if (ret) { - mpp_err("clear buffer group failed ret %d\n", ret); - break; - } - } - - /* Use limit config to limit buffer count to 24 with buf_size */ - ret = mpp_buffer_group_limit_config(data->frm_grp, buf_size, 24); + grp = dec_buf_mgr_setup(data->buf_mgr, buf_size, 24, cmd->buf_mode); + /* Set buffer to mpp decoder */ + ret = mpi->control(ctx, MPP_DEC_SET_EXT_BUF_GROUP, grp); if (ret) { - mpp_err("limit buffer group failed ret %d\n", ret); + mpp_err("%p set buffer group failed ret %d\n", ctx, ret); break; } + data->frm_grp = grp; /* * All buffer group config done. Set info change ready to let @@ -428,6 +409,12 @@ void* multi_dec_decode(void *cmd_ctx) } } + ret = dec_buf_mgr_init(&dec_ctx->buf_mgr); + if (ret) { + mpp_err("dec_buf_mgr_init failed\n"); + goto MPP_TEST_OUT; + } + if (cmd->simple) { ret = mpp_packet_init(&packet, NULL, 0); if (ret) { @@ -438,18 +425,19 @@ void* multi_dec_decode(void *cmd_ctx) RK_U32 hor_stride = MPP_ALIGN(width, 16); RK_U32 ver_stride = MPP_ALIGN(height, 16); - ret = mpp_buffer_group_get_internal(&dec_ctx->frm_grp, MPP_BUFFER_TYPE_ION | MPP_BUFFER_FLAGS_CACHABLE); - if (ret) { - mpp_err("failed to get buffer group for input frame ret %d\n", ret); - goto MPP_TEST_OUT; - } - ret = mpp_frame_init(&frame); /* output frame */ if (ret) { mpp_err("mpp_frame_init failed\n"); goto MPP_TEST_OUT; } + dec_ctx->frm_grp = dec_buf_mgr_setup(dec_ctx->buf_mgr, hor_stride * ver_stride * 2, 4, cmd->buf_mode); + if (!dec_ctx->frm_grp) { + mpp_err("failed to get buffer group for input frame ret %d\n", ret); + ret = MPP_NOK; + goto MPP_TEST_OUT; + } + /* * NOTE: For jpeg could have YUV420 and YUV422 the buffer should be * larger for output. And the buffer dimension should align to 16. @@ -563,9 +551,10 @@ MPP_TEST_OUT: } } - if (dec_ctx->frm_grp) { - mpp_buffer_group_put(dec_ctx->frm_grp); - dec_ctx->frm_grp = NULL; + dec_ctx->frm_grp = NULL; + if (dec_ctx->buf_mgr) { + dec_buf_mgr_deinit(dec_ctx->buf_mgr); + dec_ctx->buf_mgr = NULL; } if (dec_ctx->fp_output) { diff --git a/test/mpi_dec_nt_test.c b/test/mpi_dec_nt_test.c index 4cf4efa9..daf16c9b 100644 --- a/test/mpi_dec_nt_test.c +++ b/test/mpi_dec_nt_test.c @@ -39,6 +39,7 @@ typedef struct { RK_U32 loop_end; /* input and output */ + DecBufMgr buf_mgr; MppBufferGroup frm_grp; MppPacket packet; MppFrame frame; @@ -116,101 +117,22 @@ static int dec_loop(MpiDecLoopData *data) RK_U32 hor_stride = mpp_frame_get_hor_stride(frame); RK_U32 ver_stride = mpp_frame_get_ver_stride(frame); RK_U32 buf_size = mpp_frame_get_buf_size(frame); + MppBufferGroup grp = NULL; mpp_log_q(quiet, "%p decode_get_frame get info changed found\n", ctx); mpp_log_q(quiet, "%p decoder require buffer w:h [%d:%d] stride [%d:%d] buf_size %d", ctx, width, height, hor_stride, ver_stride, buf_size); - /* - * NOTE: We can choose decoder's buffer mode here. - * There are three mode that decoder can support: - * - * Mode 1: Pure internal mode - * In the mode user will NOT call MPP_DEC_SET_EXT_BUF_GROUP - * control to decoder. Only call MPP_DEC_SET_INFO_CHANGE_READY - * to let decoder go on. Then decoder will use create buffer - * internally and user need to release each frame they get. - * - * Advantage: - * Easy to use and get a demo quickly - * Disadvantage: - * 1. The buffer from decoder may not be return before - * decoder is close. So memroy leak or crash may happen. - * 2. The decoder memory usage can not be control. Decoder - * is on a free-to-run status and consume all memory it can - * get. - * 3. Difficult to implement zero-copy display path. - * - * Mode 2: Half internal mode - * This is the mode current test code using. User need to - * create MppBufferGroup according to the returned info - * change MppFrame. User can use mpp_buffer_group_limit_config - * function to limit decoder memory usage. - * - * Advantage: - * 1. Easy to use - * 2. User can release MppBufferGroup after decoder is closed. - * So memory can stay longer safely. - * 3. Can limit the memory usage by mpp_buffer_group_limit_config - * Disadvantage: - * 1. The buffer limitation is still not accurate. Memory usage - * is 100% fixed. - * 2. Also difficult to implement zero-copy display path. - * - * Mode 3: Pure external mode - * In this mode use need to create empty MppBufferGroup and - * import memory from external allocator by file handle. - * On Android surfaceflinger will create buffer. Then - * mediaserver get the file handle from surfaceflinger and - * commit to decoder's MppBufferGroup. - * - * Advantage: - * 1. Most efficient way for zero-copy display - * Disadvantage: - * 1. Difficult to learn and use. - * 2. Player work flow may limit this usage. - * 3. May need a external parser to get the correct buffer - * size for the external allocator. - * - * The required buffer size caculation: - * hor_stride * ver_stride * 3 / 2 for pixel data - * hor_stride * ver_stride / 2 for extra info - * Total hor_stride * ver_stride * 2 will be enough. - * - * For H.264/H.265 20+ buffers will be enough. - * For other codec 10 buffers will be enough. - */ - - if (NULL == data->frm_grp) { - /* If buffer group is not set create one and limit it */ - ret = mpp_buffer_group_get_internal(&data->frm_grp, MPP_BUFFER_TYPE_ION); - if (ret) { - mpp_err("%p get mpp buffer group failed ret %d\n", ctx, ret); - break; - } - - /* Set buffer to mpp decoder */ - ret = mpi->control(ctx, MPP_DEC_SET_EXT_BUF_GROUP, data->frm_grp); - if (ret) { - mpp_err("%p set buffer group failed ret %d\n", ctx, ret); - break; - } - } else { - /* If old buffer group exist clear it */ - ret = mpp_buffer_group_clear(data->frm_grp); - if (ret) { - mpp_err("%p clear buffer group failed ret %d\n", ctx, ret); - break; - } - } - - /* Use limit config to limit buffer count to 24 with buf_size */ - ret = mpp_buffer_group_limit_config(data->frm_grp, buf_size, 24); + grp = dec_buf_mgr_setup(data->buf_mgr, buf_size, 24, cmd->buf_mode); + /* Set buffer to mpp decoder */ + ret = mpi->control(ctx, MPP_DEC_SET_EXT_BUF_GROUP, grp); if (ret) { - mpp_err("%p limit buffer group failed ret %d\n", ctx, ret); + mpp_err("%p set buffer group failed ret %d\n", ctx, ret); break; } + data->frm_grp = grp; + /* * All buffer group config done. Set info change ready to let * decoder continue decoding @@ -403,6 +325,12 @@ int dec_nt_decode(MpiDecTestCmd *cmd) mpp_err("failed to open verify file %s\n", cmd->file_slt); } + ret = dec_buf_mgr_init(&data.buf_mgr); + if (ret) { + mpp_err("dec_buf_mgr_init failed\n"); + goto MPP_TEST_OUT; + } + if (cmd->simple) { ret = mpp_packet_init(&packet, NULL, 0); mpp_err_f("mpp_packet_init get %p\n", packet); @@ -414,18 +342,18 @@ int dec_nt_decode(MpiDecTestCmd *cmd) RK_U32 hor_stride = MPP_ALIGN(width, 16); RK_U32 ver_stride = MPP_ALIGN(height, 16); - ret = mpp_buffer_group_get_internal(&data.frm_grp, MPP_BUFFER_TYPE_ION); - if (ret) { - mpp_err("failed to get buffer group for input frame ret %d\n", ret); - goto MPP_TEST_OUT; - } - ret = mpp_frame_init(&frame); /* output frame */ if (ret) { mpp_err("mpp_frame_init failed\n"); goto MPP_TEST_OUT; } + data.frm_grp = dec_buf_mgr_setup(data.buf_mgr, hor_stride * ver_stride * 4, 4, cmd->buf_mode); + if (!data.frm_grp) { + mpp_err("failed to get buffer group for input frame ret %d\n", ret); + goto MPP_TEST_OUT; + } + /* * NOTE: For jpeg could have YUV420 and YUV422 the buffer should be * larger for output. And the buffer dimension should align to 16. @@ -546,9 +474,10 @@ MPP_TEST_OUT: } } - if (data.frm_grp) { - mpp_buffer_group_put(data.frm_grp); - data.frm_grp = NULL; + data.frm_grp = NULL; + if (data.buf_mgr) { + dec_buf_mgr_deinit(data.buf_mgr); + data.buf_mgr = NULL; } if (data.fp_output) { diff --git a/test/mpi_dec_test.c b/test/mpi_dec_test.c index 2d035248..a642f143 100644 --- a/test/mpi_dec_test.c +++ b/test/mpi_dec_test.c @@ -39,6 +39,7 @@ typedef struct { RK_U32 loop_end; /* input and output */ + DecBufMgr buf_mgr; MppBufferGroup frm_grp; MppPacket packet; MppFrame frame; @@ -139,100 +140,20 @@ static int dec_simple(MpiDecLoopData *data) RK_U32 hor_stride = mpp_frame_get_hor_stride(frame); RK_U32 ver_stride = mpp_frame_get_ver_stride(frame); RK_U32 buf_size = mpp_frame_get_buf_size(frame); + MppBufferGroup grp = NULL; mpp_log_q(quiet, "%p decode_get_frame get info changed found\n", ctx); mpp_log_q(quiet, "%p decoder require buffer w:h [%d:%d] stride [%d:%d] buf_size %d", ctx, width, height, hor_stride, ver_stride, buf_size); - /* - * NOTE: We can choose decoder's buffer mode here. - * There are three mode that decoder can support: - * - * Mode 1: Pure internal mode - * In the mode user will NOT call MPP_DEC_SET_EXT_BUF_GROUP - * control to decoder. Only call MPP_DEC_SET_INFO_CHANGE_READY - * to let decoder go on. Then decoder will use create buffer - * internally and user need to release each frame they get. - * - * Advantage: - * Easy to use and get a demo quickly - * Disadvantage: - * 1. The buffer from decoder may not be return before - * decoder is close. So memroy leak or crash may happen. - * 2. The decoder memory usage can not be control. Decoder - * is on a free-to-run status and consume all memory it can - * get. - * 3. Difficult to implement zero-copy display path. - * - * Mode 2: Half internal mode - * This is the mode current test code using. User need to - * create MppBufferGroup according to the returned info - * change MppFrame. User can use mpp_buffer_group_limit_config - * function to limit decoder memory usage. - * - * Advantage: - * 1. Easy to use - * 2. User can release MppBufferGroup after decoder is closed. - * So memory can stay longer safely. - * 3. Can limit the memory usage by mpp_buffer_group_limit_config - * Disadvantage: - * 1. The buffer limitation is still not accurate. Memory usage - * is 100% fixed. - * 2. Also difficult to implement zero-copy display path. - * - * Mode 3: Pure external mode - * In this mode use need to create empty MppBufferGroup and - * import memory from external allocator by file handle. - * On Android surfaceflinger will create buffer. Then - * mediaserver get the file handle from surfaceflinger and - * commit to decoder's MppBufferGroup. - * - * Advantage: - * 1. Most efficient way for zero-copy display - * Disadvantage: - * 1. Difficult to learn and use. - * 2. Player work flow may limit this usage. - * 3. May need a external parser to get the correct buffer - * size for the external allocator. - * - * The required buffer size caculation: - * hor_stride * ver_stride * 3 / 2 for pixel data - * hor_stride * ver_stride / 2 for extra info - * Total hor_stride * ver_stride * 2 will be enough. - * - * For H.264/H.265 20+ buffers will be enough. - * For other codec 10 buffers will be enough. - */ - - if (NULL == data->frm_grp) { - /* If buffer group is not set create one and limit it */ - ret = mpp_buffer_group_get_internal(&data->frm_grp, MPP_BUFFER_TYPE_ION | MPP_BUFFER_FLAGS_CACHABLE); - if (ret) { - mpp_err("%p get mpp buffer group failed ret %d\n", ctx, ret); - break; - } - - /* Set buffer to mpp decoder */ - ret = mpi->control(ctx, MPP_DEC_SET_EXT_BUF_GROUP, data->frm_grp); - if (ret) { - mpp_err("%p set buffer group failed ret %d\n", ctx, ret); - break; - } - } else { - /* If old buffer group exist clear it */ - ret = mpp_buffer_group_clear(data->frm_grp); - if (ret) { - mpp_err("%p clear buffer group failed ret %d\n", ctx, ret); - break; - } - } - - /* Use limit config to limit buffer count to 24 with buf_size */ - ret = mpp_buffer_group_limit_config(data->frm_grp, buf_size, 24); + grp = dec_buf_mgr_setup(data->buf_mgr, buf_size, 24, cmd->buf_mode); + /* Set buffer to mpp decoder */ + ret = mpi->control(ctx, MPP_DEC_SET_EXT_BUF_GROUP, grp); if (ret) { - mpp_err("%p limit buffer group failed ret %d\n", ctx, ret); + mpp_err("%p set buffer group failed ret %d\n", ctx, ret); break; } + data->frm_grp = grp; /* * All buffer group config done. Set info change ready to let @@ -570,6 +491,12 @@ int dec_decode(MpiDecTestCmd *cmd) mpp_err("failed to open verify file %s\n", cmd->file_slt); } + ret = dec_buf_mgr_init(&data.buf_mgr); + if (ret) { + mpp_err("dec_buf_mgr_init failed\n"); + goto MPP_TEST_OUT; + } + if (cmd->simple) { ret = mpp_packet_init(&packet, NULL, 0); if (ret) { @@ -580,18 +507,19 @@ int dec_decode(MpiDecTestCmd *cmd) RK_U32 hor_stride = MPP_ALIGN(width, 16); RK_U32 ver_stride = MPP_ALIGN(height, 16); - ret = mpp_buffer_group_get_internal(&data.frm_grp, MPP_BUFFER_TYPE_ION | MPP_BUFFER_FLAGS_CACHABLE); - if (ret) { - mpp_err("failed to get buffer group for input frame ret %d\n", ret); - goto MPP_TEST_OUT; - } - ret = mpp_frame_init(&frame); /* output frame */ if (ret) { mpp_err("mpp_frame_init failed\n"); goto MPP_TEST_OUT; } + data.frm_grp = dec_buf_mgr_setup(data.buf_mgr, hor_stride * ver_stride * 4, 4, cmd->buf_mode); + if (!data.frm_grp) { + mpp_err("failed to get buffer group for input frame ret %d\n", ret); + ret = MPP_NOK; + goto MPP_TEST_OUT; + } + /* * NOTE: For jpeg could have YUV420 and YUV422 the buffer should be * larger for output. And the buffer dimension should align to 16. @@ -710,9 +638,10 @@ MPP_TEST_OUT: } } - if (data.frm_grp) { - mpp_buffer_group_put(data.frm_grp); - data.frm_grp = NULL; + data.frm_grp = NULL; + if (data.buf_mgr) { + dec_buf_mgr_deinit(data.buf_mgr); + data.buf_mgr = NULL; } if (data.fp_output) { diff --git a/utils/mpi_dec_utils.c b/utils/mpi_dec_utils.c index 6a408f88..c78b761d 100644 --- a/utils/mpi_dec_utils.c +++ b/utils/mpi_dec_utils.c @@ -71,23 +71,15 @@ typedef struct FileReader_t { FileBufSlot **slots; } FileReaderImpl; -#define READ_ONCE(var) (*((volatile typeof(var) *)(&(var)))) +typedef struct DecBufMgrImpl_t { + MppDecBufMode buf_mode; + RK_U32 buf_count; + RK_U32 buf_size; + MppBufferGroup group; + MppBuffer *bufs; +} DecBufMgrImpl; -OptionInfo mpi_dec_cmd[] = { - {"i", "input_file", "input bitstream file"}, - {"o", "output_file", "output bitstream file, "}, - {"c", "ops_file", "input operation config file"}, - {"w", "width", "the width of input bitstream"}, - {"h", "height", "the height of input bitstream"}, - {"t", "type", "input stream coding type"}, - {"f", "format", "output frame format type"}, - {"x", "timeout", "output timeout interval"}, - {"n", "frame_number", "max output frame number"}, - {"s", "instance_nb", "number of instances"}, - {"v", "trace", "q - quiet f - show fps"}, - {"c", "verify_file", "verify file for slt check"}, - {NULL, NULL, NULL}, -}; +#define READ_ONCE(var) (*((volatile typeof(var) *)(&(var)))) static MPP_RET add_new_slot(FileReaderImpl* impl, FileBufSlot *slot) { @@ -600,6 +592,29 @@ RK_S32 mpi_dec_opt_slt(void *ctx, const char *next) return 0; } +RK_S32 mpi_dec_opt_bufmode(void *ctx, const char *next) +{ + MpiDecTestCmd *cmd = (MpiDecTestCmd *)ctx; + + if (next) { + if (strstr(next, "hi")) { + cmd->buf_mode = MPP_DEC_BUF_HALF_INT; + } else if (strstr(next, "i")) { + cmd->buf_mode = MPP_DEC_BUF_INTERNAL; + } else if (strstr(next, "e")) { + cmd->buf_mode = MPP_DEC_BUF_EXTERNAL; + } else { + cmd->buf_mode = MPP_DEC_BUF_HALF_INT; + } + + return 1; + } + + mpp_err("invalid ext buf mode value\n"); + return 0; +} + + RK_S32 mpi_dec_opt_help(void *ctx, const char *next) { (void)ctx; @@ -620,6 +635,7 @@ static MppOptInfo dec_opts[] = { {"v", "trace option", "q - quiet f - show fps", mpi_dec_opt_v}, {"slt", "slt file", "slt verify data file", mpi_dec_opt_slt}, {"help", "help", "show help", mpi_dec_opt_help}, + {"bufmode", "buffer mode", "hi - half internal (default) i -internal e - external", mpi_dec_opt_bufmode}, }; static RK_U32 dec_opt_cnt = MPP_ARRAY_ELEMS(dec_opts); @@ -680,7 +696,7 @@ RK_S32 mpi_dec_test_cmd_init(MpiDecTestCmd* cmd, int argc, char **argv) mpp_opt_init(&opts); /* should change node count when option increases */ - mpp_opt_setup(opts, cmd, 22, dec_opt_cnt); + mpp_opt_setup(opts, cmd, 35, dec_opt_cnt); for (i = 0; i < dec_opt_cnt; i++) mpp_opt_add(opts, &dec_opts[i]); @@ -748,3 +764,170 @@ void mpi_dec_test_cmd_options(MpiDecTestCmd* cmd) if (cmd->file_slt) mpp_log("verify : %s\n", cmd->file_slt); } + +MPP_RET dec_buf_mgr_init(DecBufMgr *mgr) +{ + DecBufMgrImpl *impl = NULL; + MPP_RET ret = MPP_NOK; + + if (mgr) { + impl = mpp_calloc(DecBufMgrImpl, 1); + if (impl) { + ret = MPP_OK; + } else { + mpp_err_f("failed to create decoder buffer manager\n"); + } + + *mgr = impl; + } + + return ret; +} + +void dec_buf_mgr_deinit(DecBufMgr mgr) +{ + DecBufMgrImpl *impl = (DecBufMgrImpl *)mgr; + + if (NULL == impl) + return; + + /* release buffer group for half internal and external mode */ + if (impl->group) { + mpp_buffer_group_put(impl->group); + impl->group = NULL; + } + + /* release the buffers used in external mode */ + if (impl->buf_count && impl->bufs) { + RK_U32 i; + + for (i = 0; i < impl->buf_count; i++) { + if (impl->bufs[i]) { + mpp_buffer_put(impl->bufs[i]); + impl->bufs[i] = NULL; + } + } + + MPP_FREE(impl->bufs); + } + + MPP_FREE(impl); +} + +MppBufferGroup dec_buf_mgr_setup(DecBufMgr mgr, RK_U32 size, RK_U32 count, MppDecBufMode mode) +{ + DecBufMgrImpl *impl = (DecBufMgrImpl *)mgr; + MPP_RET ret = MPP_NOK; + + if (!impl) + return NULL; + + /* cleanup old buffers if previous buffer group exists */ + if (impl->group) { + if (mode != impl->buf_mode) { + /* switch to different buffer mode just release old buffer group */ + mpp_buffer_group_put(impl->group); + impl->group = NULL; + } else { + /* otherwise just cleanup old buffers */ + mpp_buffer_group_clear(impl->group); + } + + /* if there are external mode old buffers do cleanup */ + if (impl->bufs) { + RK_U32 i; + + for (i = 0; i < impl->buf_count; i++) { + if (impl->bufs[i]) { + mpp_buffer_put(impl->bufs[i]); + impl->bufs[i] = NULL; + } + } + + MPP_FREE(impl->bufs); + } + } + + switch (mode) { + case MPP_DEC_BUF_HALF_INT : { + /* reuse previous half internal buffer group and just reconfig limit */ + if (NULL == impl->group) { + ret = mpp_buffer_group_get_internal(&impl->group, MPP_BUFFER_TYPE_ION); + if (ret) { + mpp_err_f("get mpp internal buffer group failed ret %d\n", ret); + break; + } + } + /* Use limit config to limit buffer count and buffer size */ + ret = mpp_buffer_group_limit_config(impl->group, size, count); + if (ret) { + mpp_err_f("limit buffer group failed ret %d\n", ret); + } + } break; + case MPP_DEC_BUF_INTERNAL : { + /* do nothing juse keep buffer group empty */ + mpp_assert(NULL == impl->group); + ret = MPP_OK; + } break; + case MPP_DEC_BUF_EXTERNAL : { + RK_U32 i; + MppBufferInfo commit; + + impl->bufs = mpp_calloc(MppBuffer, count); + if (!impl->bufs) { + mpp_err_f("create %d external buffer record failed\n", count); + break; + } + + /* reuse previous external buffer group */ + if (NULL == impl->group) { + ret = mpp_buffer_group_get_external(&impl->group, MPP_BUFFER_TYPE_ION); + if (ret) { + mpp_err_f("get mpp external buffer group failed ret %d\n", ret); + break; + } + } + + /* + * NOTE: Use default misc allocater here as external allocator for demo. + * But in practical case the external buffer could be GraphicBuffer or gst dmabuf. + * The misc allocator will cause the print at the end like: + * ~MppBufferService cleaning misc group + */ + commit.type = MPP_BUFFER_TYPE_ION; + commit.size = size; + + for (i = 0; i < count; i++) { + ret = mpp_buffer_get(NULL, &impl->bufs[i], size); + if (ret || NULL == impl->bufs[i]) { + mpp_err_f("get misc buffer failed ret %d\n", ret); + break; + } + + commit.index = i; + commit.ptr = mpp_buffer_get_ptr(impl->bufs[i]); + commit.fd = mpp_buffer_get_fd(impl->bufs[i]); + + ret = mpp_buffer_commit(impl->group, &commit); + if (ret) { + mpp_err_f("external buffer commit failed ret %d\n", ret); + break; + } + } + } break; + default : { + mpp_err_f("unsupport buffer mode %d\n", mode); + } break; + } + + if (ret) { + dec_buf_mgr_deinit(impl); + impl = NULL; + } else { + impl->buf_count = count; + impl->buf_size = size; + impl->buf_mode = mode; + } + + return impl ? impl->group : NULL; +} \ No newline at end of file diff --git a/utils/mpi_dec_utils.h b/utils/mpi_dec_utils.h index 1c2cbcd1..378d8a5b 100644 --- a/utils/mpi_dec_utils.h +++ b/utils/mpi_dec_utils.h @@ -24,7 +24,74 @@ #define MPI_DEC_STREAM_SIZE (SZ_4K) #define MPI_DEC_LOOP_COUNT 4 +/* + * NOTE: We can choose decoder's buffer mode here. + * There are three mode that decoder can support: + * + * Mode 1: Pure internal mode + * In the mode user will NOT call MPP_DEC_SET_EXT_BUF_GROUP + * control to decoder. Only call MPP_DEC_SET_INFO_CHANGE_READY + * to let decoder go on. Then decoder will use create buffer + * internally and user need to release each frame they get. + * + * Advantage: + * Easy to use and get a demo quickly + * Disadvantage: + * 1. The buffer from decoder may not be return before + * decoder is close. So memroy leak or crash may happen. + * 2. The decoder memory usage can not be control. Decoder + * is on a free-to-run status and consume all memory it can + * get. + * 3. Difficult to implement zero-copy display path. + * + * Mode 2: Half internal mode + * This is the mode current test code using. User need to + * create MppBufferGroup according to the returned info + * change MppFrame. User can use mpp_buffer_group_limit_config + * function to limit decoder memory usage. + * + * Advantage: + * 1. Easy to use + * 2. User can release MppBufferGroup after decoder is closed. + * So memory can stay longer safely. + * 3. Can limit the memory usage by mpp_buffer_group_limit_config + * Disadvantage: + * 1. The buffer limitation is still not accurate. Memory usage + * is 100% fixed. + * 2. Also difficult to implement zero-copy display path. + * + * Mode 3: Pure external mode + * In this mode use need to create empty MppBufferGroup and + * import memory from external allocator by file handle. + * On Android surfaceflinger will create buffer. Then + * mediaserver get the file handle from surfaceflinger and + * commit to decoder's MppBufferGroup. + * + * Advantage: + * 1. Most efficient way for zero-copy display + * Disadvantage: + * 1. Difficult to learn and use. + * 2. Player work flow may limit this usage. + * 3. May need a external parser to get the correct buffer + * size for the external allocator. + * + * The required buffer size caculation: + * hor_stride * ver_stride * 3 / 2 for pixel data + * hor_stride * ver_stride / 2 for extra info + * Total hor_stride * ver_stride * 2 will be enough. + * + * For H.264/H.265 20+ buffers will be enough. + * For other codec 10 buffers will be enough. + */ +typedef enum MppDecBufMode_e { + MPP_DEC_BUF_HALF_INT, + MPP_DEC_BUF_INTERNAL, + MPP_DEC_BUF_EXTERNAL, + MPP_DEC_BUF_MODE_BUTT, +} MppDecBufMode; + typedef void* FileReader; +typedef void* DecBufMgr; typedef struct FileBufSlot_t { RK_S32 index; @@ -51,6 +118,8 @@ typedef struct MpiDecTestCmd_t { RK_S32 timeout; RK_S32 frame_num; size_t pkt_size; + MppDecBufMode buf_mode; + /* use for mpi_dec_multi_test */ RK_S32 nthreads; // report information @@ -66,8 +135,6 @@ typedef struct MpiDecTestCmd_t { char *file_slt; } MpiDecTestCmd; -extern OptionInfo mpi_dec_cmd[]; - RK_S32 mpi_dec_test_cmd_init(MpiDecTestCmd* cmd, int argc, char **argv); RK_S32 mpi_dec_test_cmd_deinit(MpiDecTestCmd* cmd); void mpi_dec_test_cmd_options(MpiDecTestCmd* cmd); @@ -84,6 +151,10 @@ MPP_RET reader_read(FileReader reader, FileBufSlot **buf); MPP_RET reader_index_read(FileReader reader, RK_S32 index, FileBufSlot **buf); void reader_rewind(FileReader reader); +MPP_RET dec_buf_mgr_init(DecBufMgr *mgr); +void dec_buf_mgr_deinit(DecBufMgr mgr); +MppBufferGroup dec_buf_mgr_setup(DecBufMgr mgr, RK_U32 size, RK_U32 count, MppDecBufMode mode); + void show_dec_fps(RK_S64 total_time, RK_S64 total_count, RK_S64 last_time, RK_S64 last_count); -#endif +#endif \ No newline at end of file