feat[dec_test]: Add buffer mode option

Add an option in dec_test to demo zero-copy external buffers mode.

use -bufmode to config the buffer mode option
hl - half internal mode
i  - pure internal mode
e  - pure external mode

Change-Id: Ib92c30acd8c370843becb286c935de056b09bcbd
Signed-off-by: Yanjun Liao <yanjun.liao@rock-chips.com>
Signed-off-by: Herman Chen <herman.chen@rock-chips.com>
This commit is contained in:
Yanjun Liao
2023-10-31 14:36:38 +08:00
committed by Herman Chen
parent 0d773814cf
commit ce39aff31f
9 changed files with 419 additions and 304 deletions

View File

@@ -678,10 +678,8 @@ MPP_RET mpp_buffer_group_reset(MppBufferGroupImpl *p)
MPP_RET mpp_buffer_group_set_callback(MppBufferGroupImpl *p, MPP_RET mpp_buffer_group_set_callback(MppBufferGroupImpl *p,
MppBufCallback callback, void *arg) MppBufCallback callback, void *arg)
{ {
if (NULL == p) { if (!p)
mpp_err_f("found NULL pointer\n"); return MPP_OK;
return MPP_ERR_NULL_PTR;
}
MPP_BUF_FUNCTION_ENTER(); MPP_BUF_FUNCTION_ENTER();

View File

@@ -153,7 +153,7 @@ public:
*/ */
MppBufferGroup mPacketGroup; MppBufferGroup mPacketGroup;
MppBufferGroup mFrameGroup; MppBufferGroup mFrameGroup;
RK_U32 mExternalFrameGroup; RK_U32 mExternalBufferMode;
/* /*
* Mpp task queue for advance task mode * Mpp task queue for advance task mode

View File

@@ -88,7 +88,7 @@ Mpp::Mpp(MppCtx ctx)
mTaskGetCount(0), mTaskGetCount(0),
mPacketGroup(NULL), mPacketGroup(NULL),
mFrameGroup(NULL), mFrameGroup(NULL),
mExternalFrameGroup(0), mExternalBufferMode(0),
mUsrInPort(NULL), mUsrInPort(NULL),
mUsrOutPort(NULL), mUsrOutPort(NULL),
mMppInPort(NULL), mMppInPort(NULL),
@@ -327,7 +327,7 @@ void Mpp::clear()
mPacketGroup = NULL; mPacketGroup = NULL;
} }
if (mFrameGroup && !mExternalFrameGroup) { if (mFrameGroup && !mExternalBufferMode) {
mpp_buffer_group_put(mFrameGroup); mpp_buffer_group_put(mFrameGroup);
mFrameGroup = NULL; mFrameGroup = NULL;
} }
@@ -1173,19 +1173,6 @@ MPP_RET Mpp::control_dec(MpiCmd cmd, MppParam param)
ret = mpp_dec_control(mDec, cmd, param); ret = mpp_dec_control(mDec, cmd, param);
} break; } break;
case MPP_DEC_SET_EXT_BUF_GROUP: { 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 * NOTE: If frame buffer group is configured before decoder init
* then the buffer limitation maybe not be correctly setup * then the buffer limitation maybe not be correctly setup
@@ -1193,12 +1180,53 @@ MPP_RET Mpp::control_dec(MpiCmd cmd, MppParam param)
* And the thread signal connection may not be setup here. It * And the thread signal connection may not be setup here. It
* may have a bad effect on MPP efficiency. * may have a bad effect on MPP efficiency.
*/ */
if (!mInitDone) {
mpp_err("WARNING: setup buffer group before decoder init\n"); 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 { } else {
/* The buffer group should be destroyed before */ /* switch from intenal mode to external mode */
mExternalFrameGroup = 0; if (mFrameGroup)
ret = MPP_OK; mpp_buffer_group_put(mFrameGroup);
}
mpp_dbg_info("using external buffer group %p\n", mFrameGroup);
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; } break;
case MPP_DEC_SET_INFO_CHANGE_READY: { case MPP_DEC_SET_INFO_CHANGE_READY: {

View File

@@ -43,6 +43,7 @@ typedef struct {
char *buf; char *buf;
/* input and output */ /* input and output */
DecBufMgr buf_mgr;
MppBufferGroup frm_grp; MppBufferGroup frm_grp;
MppPacket packet; MppPacket packet;
size_t packet_size; 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 hor_stride = mpp_frame_get_hor_stride(frame);
RK_U32 ver_stride = mpp_frame_get_ver_stride(frame); RK_U32 ver_stride = mpp_frame_get_ver_stride(frame);
RK_U32 buf_size = mpp_frame_get_buf_size(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, "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", 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); width, height, hor_stride, ver_stride, buf_size);
if (NULL == data->frm_grp) { grp = dec_buf_mgr_setup(data->buf_mgr, buf_size, 24, cmd->buf_mode);
/* 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 */ /* Set buffer to mpp decoder */
ret = mpi->control(ctx, MPP_DEC_SET_EXT_BUF_GROUP, data->frm_grp); ret = mpi->control(ctx, MPP_DEC_SET_EXT_BUF_GROUP, grp);
if (ret) { if (ret) {
mpp_err("set buffer group failed ret %d\n", 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("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);
if (ret) {
mpp_err("limit buffer group failed ret %d\n", ret);
break; break;
} }
data->frm_grp = grp;
ret = mpi->control(ctx, MPP_DEC_SET_INFO_CHANGE_READY, NULL); ret = mpi->control(ctx, MPP_DEC_SET_INFO_CHANGE_READY, NULL);
if (ret) { 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); ret = mpp_packet_init(&packet, NULL, 0);
if (ret) { if (ret) {
mpp_err("mpp_packet_init failed\n"); mpp_err("mpp_packet_init failed\n");
@@ -396,9 +383,10 @@ MPP_TEST_OUT:
ctx = NULL; 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) { if (data.fp_output) {

View File

@@ -42,6 +42,7 @@ typedef struct {
RK_U32 loop_end; RK_U32 loop_end;
/* input and output */ /* input and output */
DecBufMgr buf_mgr;
MppBufferGroup frm_grp; MppBufferGroup frm_grp;
MppPacket packet; MppPacket packet;
MppFrame frame; 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 hor_stride = mpp_frame_get_hor_stride(frame);
RK_U32 ver_stride = mpp_frame_get_ver_stride(frame); RK_U32 ver_stride = mpp_frame_get_ver_stride(frame);
RK_U32 buf_size = mpp_frame_get_buf_size(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, "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", 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); width, height, hor_stride, ver_stride, buf_size);
if (NULL == data->frm_grp) { grp = dec_buf_mgr_setup(data->buf_mgr, buf_size, 24, cmd->buf_mode);
/* 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 */ /* Set buffer to mpp decoder */
ret = mpi->control(ctx, MPP_DEC_SET_EXT_BUF_GROUP, data->frm_grp); ret = mpi->control(ctx, MPP_DEC_SET_EXT_BUF_GROUP, grp);
if (ret) { if (ret) {
mpp_err("set buffer group failed ret %d\n", 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("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);
if (ret) {
mpp_err("limit buffer group failed ret %d\n", ret);
break; break;
} }
data->frm_grp = grp;
/* /*
* All buffer group config done. Set info change ready to let * 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) { if (cmd->simple) {
ret = mpp_packet_init(&packet, NULL, 0); ret = mpp_packet_init(&packet, NULL, 0);
if (ret) { if (ret) {
@@ -438,18 +425,19 @@ void* multi_dec_decode(void *cmd_ctx)
RK_U32 hor_stride = MPP_ALIGN(width, 16); RK_U32 hor_stride = MPP_ALIGN(width, 16);
RK_U32 ver_stride = MPP_ALIGN(height, 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 */ ret = mpp_frame_init(&frame); /* output frame */
if (ret) { if (ret) {
mpp_err("mpp_frame_init failed\n"); mpp_err("mpp_frame_init failed\n");
goto MPP_TEST_OUT; 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 * NOTE: For jpeg could have YUV420 and YUV422 the buffer should be
* larger for output. And the buffer dimension should align to 16. * 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) { if (dec_ctx->fp_output) {

View File

@@ -39,6 +39,7 @@ typedef struct {
RK_U32 loop_end; RK_U32 loop_end;
/* input and output */ /* input and output */
DecBufMgr buf_mgr;
MppBufferGroup frm_grp; MppBufferGroup frm_grp;
MppPacket packet; MppPacket packet;
MppFrame frame; MppFrame frame;
@@ -116,100 +117,21 @@ static int dec_loop(MpiDecLoopData *data)
RK_U32 hor_stride = mpp_frame_get_hor_stride(frame); RK_U32 hor_stride = mpp_frame_get_hor_stride(frame);
RK_U32 ver_stride = mpp_frame_get_ver_stride(frame); RK_U32 ver_stride = mpp_frame_get_ver_stride(frame);
RK_U32 buf_size = mpp_frame_get_buf_size(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 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", 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); ctx, width, height, hor_stride, ver_stride, buf_size);
/* grp = dec_buf_mgr_setup(data->buf_mgr, buf_size, 24, cmd->buf_mode);
* 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 */ /* Set buffer to mpp decoder */
ret = mpi->control(ctx, MPP_DEC_SET_EXT_BUF_GROUP, data->frm_grp); ret = mpi->control(ctx, MPP_DEC_SET_EXT_BUF_GROUP, grp);
if (ret) { if (ret) {
mpp_err("%p set buffer group failed ret %d\n", ctx, ret); mpp_err("%p set buffer group failed ret %d\n", ctx, ret);
break; 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 */ data->frm_grp = grp;
ret = mpp_buffer_group_limit_config(data->frm_grp, buf_size, 24);
if (ret) {
mpp_err("%p limit buffer group failed ret %d\n", ctx, ret);
break;
}
/* /*
* All buffer group config done. Set info change ready to let * All buffer group config done. Set info change ready to let
@@ -403,6 +325,12 @@ int dec_nt_decode(MpiDecTestCmd *cmd)
mpp_err("failed to open verify file %s\n", cmd->file_slt); 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) { if (cmd->simple) {
ret = mpp_packet_init(&packet, NULL, 0); ret = mpp_packet_init(&packet, NULL, 0);
mpp_err_f("mpp_packet_init get %p\n", packet); 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 hor_stride = MPP_ALIGN(width, 16);
RK_U32 ver_stride = MPP_ALIGN(height, 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 */ ret = mpp_frame_init(&frame); /* output frame */
if (ret) { if (ret) {
mpp_err("mpp_frame_init failed\n"); mpp_err("mpp_frame_init failed\n");
goto MPP_TEST_OUT; 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 * NOTE: For jpeg could have YUV420 and YUV422 the buffer should be
* larger for output. And the buffer dimension should align to 16. * 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) { if (data.fp_output) {

View File

@@ -39,6 +39,7 @@ typedef struct {
RK_U32 loop_end; RK_U32 loop_end;
/* input and output */ /* input and output */
DecBufMgr buf_mgr;
MppBufferGroup frm_grp; MppBufferGroup frm_grp;
MppPacket packet; MppPacket packet;
MppFrame frame; MppFrame frame;
@@ -139,100 +140,20 @@ static int dec_simple(MpiDecLoopData *data)
RK_U32 hor_stride = mpp_frame_get_hor_stride(frame); RK_U32 hor_stride = mpp_frame_get_hor_stride(frame);
RK_U32 ver_stride = mpp_frame_get_ver_stride(frame); RK_U32 ver_stride = mpp_frame_get_ver_stride(frame);
RK_U32 buf_size = mpp_frame_get_buf_size(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 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", 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); ctx, width, height, hor_stride, ver_stride, buf_size);
/* grp = dec_buf_mgr_setup(data->buf_mgr, buf_size, 24, cmd->buf_mode);
* 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 */ /* Set buffer to mpp decoder */
ret = mpi->control(ctx, MPP_DEC_SET_EXT_BUF_GROUP, data->frm_grp); ret = mpi->control(ctx, MPP_DEC_SET_EXT_BUF_GROUP, grp);
if (ret) { if (ret) {
mpp_err("%p set buffer group failed ret %d\n", ctx, ret); mpp_err("%p set buffer group failed ret %d\n", ctx, ret);
break; break;
} }
} else { data->frm_grp = grp;
/* 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);
if (ret) {
mpp_err("%p limit buffer group failed ret %d\n", ctx, ret);
break;
}
/* /*
* All buffer group config done. Set info change ready to let * 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); 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) { if (cmd->simple) {
ret = mpp_packet_init(&packet, NULL, 0); ret = mpp_packet_init(&packet, NULL, 0);
if (ret) { if (ret) {
@@ -580,18 +507,19 @@ int dec_decode(MpiDecTestCmd *cmd)
RK_U32 hor_stride = MPP_ALIGN(width, 16); RK_U32 hor_stride = MPP_ALIGN(width, 16);
RK_U32 ver_stride = MPP_ALIGN(height, 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 */ ret = mpp_frame_init(&frame); /* output frame */
if (ret) { if (ret) {
mpp_err("mpp_frame_init failed\n"); mpp_err("mpp_frame_init failed\n");
goto MPP_TEST_OUT; 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 * NOTE: For jpeg could have YUV420 and YUV422 the buffer should be
* larger for output. And the buffer dimension should align to 16. * 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) { if (data.fp_output) {

View File

@@ -71,23 +71,15 @@ typedef struct FileReader_t {
FileBufSlot **slots; FileBufSlot **slots;
} FileReaderImpl; } 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[] = { #define READ_ONCE(var) (*((volatile typeof(var) *)(&(var))))
{"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},
};
static MPP_RET add_new_slot(FileReaderImpl* impl, FileBufSlot *slot) 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; 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) RK_S32 mpi_dec_opt_help(void *ctx, const char *next)
{ {
(void)ctx; (void)ctx;
@@ -620,6 +635,7 @@ static MppOptInfo dec_opts[] = {
{"v", "trace option", "q - quiet f - show fps", mpi_dec_opt_v}, {"v", "trace option", "q - quiet f - show fps", mpi_dec_opt_v},
{"slt", "slt file", "slt verify data file", mpi_dec_opt_slt}, {"slt", "slt file", "slt verify data file", mpi_dec_opt_slt},
{"help", "help", "show help", mpi_dec_opt_help}, {"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); 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); mpp_opt_init(&opts);
/* should change node count when option increases */ /* 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++) for (i = 0; i < dec_opt_cnt; i++)
mpp_opt_add(opts, &dec_opts[i]); mpp_opt_add(opts, &dec_opts[i]);
@@ -748,3 +764,170 @@ void mpi_dec_test_cmd_options(MpiDecTestCmd* cmd)
if (cmd->file_slt) if (cmd->file_slt)
mpp_log("verify : %s\n", 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;
}

View File

@@ -24,7 +24,74 @@
#define MPI_DEC_STREAM_SIZE (SZ_4K) #define MPI_DEC_STREAM_SIZE (SZ_4K)
#define MPI_DEC_LOOP_COUNT 4 #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* FileReader;
typedef void* DecBufMgr;
typedef struct FileBufSlot_t { typedef struct FileBufSlot_t {
RK_S32 index; RK_S32 index;
@@ -51,6 +118,8 @@ typedef struct MpiDecTestCmd_t {
RK_S32 timeout; RK_S32 timeout;
RK_S32 frame_num; RK_S32 frame_num;
size_t pkt_size; size_t pkt_size;
MppDecBufMode buf_mode;
/* use for mpi_dec_multi_test */ /* use for mpi_dec_multi_test */
RK_S32 nthreads; RK_S32 nthreads;
// report information // report information
@@ -66,8 +135,6 @@ typedef struct MpiDecTestCmd_t {
char *file_slt; char *file_slt;
} MpiDecTestCmd; } 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_init(MpiDecTestCmd* cmd, int argc, char **argv);
RK_S32 mpi_dec_test_cmd_deinit(MpiDecTestCmd* cmd); RK_S32 mpi_dec_test_cmd_deinit(MpiDecTestCmd* cmd);
void mpi_dec_test_cmd_options(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); MPP_RET reader_index_read(FileReader reader, RK_S32 index, FileBufSlot **buf);
void reader_rewind(FileReader reader); 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); void show_dec_fps(RK_S64 total_time, RK_S64 total_count, RK_S64 last_time, RK_S64 last_count);
#endif #endif