瀏覽代碼

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>
Yanjun Liao 1 年之前
父節點
當前提交
ce39aff31f
共有 9 個文件被更改,包括 415 次插入300 次删除
  1. 2 4
      mpp/base/mpp_buffer_impl.cpp
  2. 1 1
      mpp/inc/mpp.h
  3. 52 24
      mpp/mpp.cpp
  4. 17 29
      test/mpi_dec_mt_test.c
  5. 23 34
      test/mpi_dec_multi_test.c
  6. 23 94
      test/mpi_dec_nt_test.c
  7. 23 94
      test/mpi_dec_test.c
  8. 200 17
      utils/mpi_dec_utils.c
  9. 74 3
      utils/mpi_dec_utils.h

+ 2 - 4
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();
 

+ 1 - 1
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

+ 52 - 24
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;
-
-            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);
+        /*
+         * 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;
+        }
 
-                notify(MPP_DEC_NOTIFY_EXT_BUF_GRP_READY);
+        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 {
-                /*
-                 * 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");
+                /* 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 {
-            /* The buffer group should be destroyed before */
-            mExternalFrameGroup = 0;
-            ret = MPP_OK;
+            /* 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);
+
+            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: {

+ 17 - 29
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) {

+ 23 - 34
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,15 +425,16 @@ 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);
+        ret = mpp_frame_init(&frame); /* output frame */
         if (ret) {
-            mpp_err("failed to get buffer group for input frame ret %d\n", ret);
+            mpp_err("mpp_frame_init failed\n");
             goto MPP_TEST_OUT;
         }
 
-        ret = mpp_frame_init(&frame); /* output frame */
-        if (ret) {
-            mpp_err("mpp_frame_init failed\n");
+        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;
         }
 
@@ -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) {

+ 23 - 94
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,15 +342,15 @@ 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);
+        ret = mpp_frame_init(&frame); /* output frame */
         if (ret) {
-            mpp_err("failed to get buffer group for input frame ret %d\n", ret);
+            mpp_err("mpp_frame_init failed\n");
             goto MPP_TEST_OUT;
         }
 
-        ret = mpp_frame_init(&frame); /* output frame */
-        if (ret) {
-            mpp_err("mpp_frame_init failed\n");
+        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;
         }
 
@@ -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) {

+ 23 - 94
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,15 +507,16 @@ 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);
+        ret = mpp_frame_init(&frame); /* output frame */
         if (ret) {
-            mpp_err("failed to get buffer group for input frame ret %d\n", ret);
+            mpp_err("mpp_frame_init failed\n");
             goto MPP_TEST_OUT;
         }
 
-        ret = mpp_frame_init(&frame); /* output frame */
-        if (ret) {
-            mpp_err("mpp_frame_init failed\n");
+        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;
         }
 
@@ -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) {

+ 200 - 17
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;
+}

+ 74 - 3
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