[test]: Improve decoder tests

1. All cases use reader to improve performance.
2. Rename cmd parser and create share data on cmd parsing.
3. Add reader_size function to get file size.
4. Change test log flag to -v options.
5. Fix FileBufSlot release MppBuffer issue.
6. Use index_read in multi test to improve performance.

Usage:

mpi_dec_test -i xxx.h264
Decode to the end of input stream.

mpi_dec_test -i xxx.h264 -n 10
Decode to the first 10 frame of input stream. If the xxx.h264 has only 5
frames then loop decoding from the beginning.

mpi_dec_test -i xxx.h264 -n -1 -v qf
Infinitely loop decoding xxx.h264.
It is usefull for performance test.

mpi_dec_multi_test -i xxx.h264 -n -1 -v qf -s 8
Parallelly infinitely loop run 8 decoders with same xxx.h264 input.
It is usefull for performance test.

-v q  will disable each frame output log.
-v f  will enable fps print per second.
-n -1 will enter infinite decode mode. Press <enter> will quit the loop.

Change-Id: I3d54123f0e9b9a85cb35e4fea71ebf665889750a
Signed-off-by: Herman Chen <herman.chen@rock-chips.com>
This commit is contained in:
Herman Chen
2021-10-19 15:33:16 +08:00
parent 02320fb506
commit 180dd8136a
6 changed files with 433 additions and 490 deletions

View File

@@ -34,25 +34,22 @@
/* For each instance thread setup */
typedef struct {
MpiDecTestCmd *cmd;
MppCtx ctx;
MppApi *mpi;
/* end of stream flag when set quit the loop */
RK_U32 eos;
/* buffer for stream data reading */
char *buf;
RK_U32 loop_end;
/* input and output */
MppBufferGroup frm_grp;
MppBufferGroup pkt_grp;
MppPacket packet;
size_t packet_size;
MppFrame frame;
FILE *fp_input;
FILE *fp_output;
RK_U32 frame_count;
RK_S32 packet_count;
RK_S32 frame_count;
RK_S64 first_pkt;
RK_S64 first_frm;
@@ -61,38 +58,40 @@ typedef struct {
/* runtime flag */
RK_U32 quiet;
} MpiDecCtx;
} MpiDecMultiCtx;
/* For each instance thread return value */
typedef struct {
volatile float frame_rate;
float frame_rate;
RK_S64 elapsed_time;
RK_S64 frame_count;
} MpiDecCtxRet;
RK_S32 frame_count;
RK_S64 delay;
} MpiDecMultiCtxRet;
typedef struct {
MpiDecTestCmd *cmd; // pointer to global command line info
MpiDecTestCmd *cmd; // pointer to global command line info
pthread_t thd; // thread for for each instance
MpiDecCtx ctx; // context of decoder
MpiDecCtxRet ret; // return of decoder
} MpiDecCtxInfo;
pthread_t thd; // thread for for each instance
MpiDecMultiCtx ctx; // context of decoder
MpiDecMultiCtxRet ret; // return of decoder
} MpiDecMultiCtxInfo;
static int multi_dec_simple(MpiDecCtx *data)
static int multi_dec_simple(MpiDecMultiCtx *data)
{
MpiDecTestCmd *cmd = data->cmd;
RK_U32 pkt_done = 0;
RK_U32 pkt_eos = 0;
RK_U32 err_info = 0;
MppCtx ctx = data->ctx;
MppApi *mpi = data->mpi;
char *buf = data->buf;
char *buf = NULL;
MppPacket packet = data->packet;
MppFrame frame = NULL;
FileReader reader = data->reader;
FileBufSlot *slot = NULL;
size_t read_size = 0;
RK_U32 quiet = data->quiet;
MPP_RET ret = reader_read(reader, &slot);
MPP_RET ret = reader_index_read(reader, data->packet_count++, &slot);
mpp_assert(ret == MPP_OK);
mpp_assert(slot);
@@ -100,15 +99,15 @@ static int multi_dec_simple(MpiDecCtx *data)
pkt_eos = slot->eos;
buf = slot->data;
read_size = slot->size;
data->eos = pkt_eos;
if (pkt_eos) {
if (data->frame_num < 0) {
if (data->frame_num < 0 || data->frame_num > data->frame_count) {
mpp_log_q(quiet, "%p loop again\n", ctx);
reader_rewind(reader);
data->eos = pkt_eos = 0;
data->packet_count = 0;
pkt_eos = 0;
} else {
mpp_log_q(quiet, "%p found last packet\n", ctx);
data->loop_end = 1;
}
}
@@ -122,6 +121,7 @@ static int multi_dec_simple(MpiDecCtx *data)
mpp_packet_set_eos(packet);
do {
RK_U32 frm_eos = 0;
RK_S32 times = 5;
// send the packet first if packet is not done
if (!pkt_done) {
@@ -136,7 +136,6 @@ static int multi_dec_simple(MpiDecCtx *data)
// then get all available frame and release
do {
RK_S32 get_frm = 0;
RK_U32 frm_eos = 0;
try_again:
ret = mpi->decode_get_frame(ctx, &frame);
@@ -148,7 +147,7 @@ static int multi_dec_simple(MpiDecCtx *data)
}
mpp_err("decode_get_frame failed too much time\n");
}
if (MPP_OK != ret) {
if (ret) {
mpp_err("decode_get_frame failed ret %d\n", ret);
break;
}
@@ -221,6 +220,8 @@ static int multi_dec_simple(MpiDecCtx *data)
data->frame_count++;
if (data->fp_output && !err_info)
dump_mpp_frame_to_file(frame, data->fp_output);
fps_calc_inc(cmd->fps);
}
frm_eos = mpp_frame_get_eos(frame);
mpp_frame_deinit(&frame);
@@ -234,14 +235,9 @@ static int multi_dec_simple(MpiDecCtx *data)
continue;
}
if (frm_eos) {
// mpp_log("found last frame\n");
if ((data->frame_num > 0 && (data->frame_count >= data->frame_num)) ||
((data->frame_num == 0) && frm_eos))
break;
}
if (data->frame_num > 0 && data->frame_count >= (RK_U32)data->frame_num) {
data->eos = 1;
break;
}
if (get_frm)
continue;
@@ -251,6 +247,12 @@ static int multi_dec_simple(MpiDecCtx *data)
if (pkt_done)
break;
if ((data->frame_num > 0 && (data->frame_count >= data->frame_num)) ||
((data->frame_num == 0) && frm_eos)) {
data->loop_end = 1;
break;
}
/*
* why sleep here:
* mpi->decode_put_packet will failed when packet in internal queue is
@@ -264,30 +266,26 @@ static int multi_dec_simple(MpiDecCtx *data)
return ret;
}
static int multi_dec_advanced(MpiDecCtx *data)
static int multi_dec_advanced(MpiDecMultiCtx *data)
{
RK_U32 pkt_eos = 0;
MPP_RET ret = MPP_OK;
MpiDecTestCmd *cmd = data->cmd;
MppCtx ctx = data->ctx;
MppApi *mpi = data->mpi;
char *buf = data->buf;
MppPacket packet = data->packet;
MppPacket packet = NULL;
MppFrame frame = data->frame;
MppTask task = NULL;
size_t read_size = fread(buf, 1, data->packet_size, data->fp_input);
RK_U32 quiet = data->quiet;
FileBufSlot *slot = NULL;
if (read_size != data->packet_size || feof(data->fp_input)) {
// mpp_log("found last packet\n");
ret = reader_index_read(cmd->reader, 0, &slot);
mpp_assert(ret == MPP_OK);
mpp_assert(slot);
// setup eos flag
data->eos = pkt_eos = 1;
}
mpp_packet_init_with_buffer(&packet, slot->buf);
// reset pos
mpp_packet_set_pos(packet, buf);
mpp_packet_set_length(packet, read_size);
// setup eos flag
if (pkt_eos)
if (slot->eos)
mpp_packet_set_eos(packet);
ret = mpi->poll(ctx, MPP_PORT_INPUT, MPP_POLL_BLOCK);
@@ -330,26 +328,28 @@ static int multi_dec_advanced(MpiDecCtx *data)
if (task) {
MppFrame frame_out = NULL;
mpp_task_meta_get_frame(task, KEY_OUTPUT_FRAME, &frame_out);
//mpp_assert(packet_out == packet);
if (frame) {
/* write frame to file here */
MppBuffer buf_out = mpp_frame_get_buffer(frame_out);
if (data->fp_output)
dump_mpp_frame_to_file(frame, data->fp_output);
if (buf_out) {
void *ptr = mpp_buffer_get_ptr(buf_out);
size_t len = mpp_buffer_get_size(buf_out);
if (data->fp_output)
fwrite(ptr, 1, len, data->fp_output);
mpp_log("decoded frame %d size %d\n", data->frame_count, len);
}
mpp_log_q(quiet, "%p decoded frame %d\n", ctx, data->frame_count);
data->frame_count++;
if (mpp_frame_get_eos(frame_out)) {
; //mpp_log("found eos frame\n");
mpp_log_q(quiet, "%p found eos frame\n", ctx);
}
fps_calc_inc(cmd->fps);
}
if (data->frame_num > 0) {
if (data->frame_count >= data->frame_num)
data->loop_end = 1;
} else if (data->frame_num == 0) {
if (slot->eos)
data->loop_end = 1;
}
/* output queue */
@@ -358,17 +358,49 @@ static int multi_dec_advanced(MpiDecCtx *data)
mpp_err("mpp task output enqueue failed\n");
}
/*
* The following input port task dequeue and enqueue is to make sure that
* the input packet can be released. We can directly deinit the input packet
* after frame output in most cases.
*/
if (0) {
mpp_packet_deinit(&packet);
} else {
ret = mpi->dequeue(ctx, MPP_PORT_INPUT, &task); /* input queue */
if (ret) {
mpp_err("%p mpp task input dequeue failed\n", ctx);
return ret;
}
mpp_assert(task);
if (task) {
MppPacket packet_out = NULL;
mpp_task_meta_get_packet(task, KEY_INPUT_PACKET, &packet_out);
if (!packet_out || packet_out != packet)
mpp_err_f("mismatch packet %p -> %p\n", packet, packet_out);
mpp_packet_deinit(&packet_out);
/* input empty task back to mpp to maintain task status */
ret = mpi->enqueue(ctx, MPP_PORT_INPUT, task);
if (ret)
mpp_err("%p mpp task input enqueue failed\n", ctx);
}
}
return ret;
}
void* multi_dec_decode(void *cmd_ctx)
{
MpiDecCtxInfo *info = (MpiDecCtxInfo *)cmd_ctx;
MpiDecMultiCtxInfo *info = (MpiDecMultiCtxInfo *)cmd_ctx;
MpiDecMultiCtx *dec_ctx = &info->ctx;
MpiDecMultiCtxRet *rets = &info->ret;
MpiDecTestCmd *cmd = info->cmd;
MpiDecCtx *dec_ctx = &info->ctx;
MpiDecCtxRet *rets = &info->ret;
FileReader reader = cmd->reader;
MPP_RET ret = MPP_OK;
size_t file_size = 0;
// base flow context
MppCtx ctx = NULL;
@@ -389,26 +421,7 @@ void* multi_dec_decode(void *cmd_ctx)
MppCodingType type = cmd->type;
// resources
char *buf = NULL;
size_t packet_size = MPI_DEC_STREAM_SIZE;
MppBuffer pkt_buf = NULL;
MppBuffer frm_buf = NULL;
FileReader reader = NULL;
// mpp_log("mpi_dec_test start\n");
if (cmd->have_input) {
dec_ctx->fp_input = fopen(cmd->file_input, "rb");
if (NULL == dec_ctx->fp_input) {
mpp_err("failed to open input file %s\n", cmd->file_input);
goto MPP_TEST_OUT;
}
fseek(dec_ctx->fp_input, 0L, SEEK_END);
file_size = ftell(dec_ctx->fp_input);
rewind(dec_ctx->fp_input);
// mpp_log("input file size %ld\n", file_size);
}
if (cmd->have_output) {
dec_ctx->fp_output = fopen(cmd->file_output, "w+b");
@@ -419,8 +432,6 @@ void* multi_dec_decode(void *cmd_ctx)
}
if (cmd->simple) {
reader_init(&reader, cmd->file_input, dec_ctx->fp_input);
ret = mpp_packet_init(&packet, NULL, 0);
if (ret) {
mpp_err("mpp_packet_init failed\n");
@@ -436,14 +447,8 @@ void* multi_dec_decode(void *cmd_ctx)
goto MPP_TEST_OUT;
}
ret = mpp_buffer_group_get_internal(&dec_ctx->pkt_grp, MPP_BUFFER_TYPE_ION);
if (ret) {
mpp_err("failed to get buffer group for output packet ret %d\n", ret);
goto MPP_TEST_OUT;
}
ret = mpp_frame_init(&frame); /* output frame */
if (MPP_OK != ret) {
if (ret) {
mpp_err("mpp_frame_init failed\n");
goto MPP_TEST_OUT;
}
@@ -461,37 +466,24 @@ void* multi_dec_decode(void *cmd_ctx)
goto MPP_TEST_OUT;
}
// NOTE: for mjpeg decoding send the whole file
if (type == MPP_VIDEO_CodingMJPEG) {
packet_size = file_size;
}
ret = mpp_buffer_get(dec_ctx->pkt_grp, &pkt_buf, packet_size);
if (ret) {
mpp_err("failed to get buffer for input frame ret %d\n", ret);
goto MPP_TEST_OUT;
}
mpp_packet_init_with_buffer(&packet, pkt_buf);
buf = mpp_buffer_get_ptr(pkt_buf);
mpp_frame_set_buffer(frame, frm_buf);
}
mpp_log("mpi_dec_test decoder test start w %d h %d type %d\n", width, height, type);
// decoder demo
ret = mpp_create(&ctx, &mpi);
if (MPP_OK != ret) {
if (ret) {
mpp_err("mpp_create failed\n");
goto MPP_TEST_OUT;
}
mpp_log("%p mpi_dec_test decoder test start w %d h %d type %d\n",
ctx, width, height, type);
// NOTE: decoder split mode need to be set before init
mpi_cmd = MPP_DEC_SET_PARSER_SPLIT_MODE;
param = &need_split;
ret = mpi->control(ctx, mpi_cmd, param);
if (MPP_OK != ret) {
if (ret) {
mpp_err("mpi->control failed\n");
goto MPP_TEST_OUT;
}
@@ -503,25 +495,24 @@ void* multi_dec_decode(void *cmd_ctx)
if (timeout) {
param = &timeout;
ret = mpi->control(ctx, MPP_SET_OUTPUT_TIMEOUT, param);
if (MPP_OK != ret) {
if (ret) {
mpp_err("Failed to set output timeout %d ret %d\n", timeout, ret);
goto MPP_TEST_OUT;
}
}
ret = mpp_init(ctx, MPP_CTX_DEC, type);
if (MPP_OK != ret) {
if (ret) {
mpp_err("mpp_init failed\n");
goto MPP_TEST_OUT;
}
dec_ctx->cmd = cmd;
dec_ctx->ctx = ctx;
dec_ctx->mpi = mpi;
dec_ctx->eos = 0;
dec_ctx->buf = buf;
dec_ctx->packet = packet;
dec_ctx->packet_size = packet_size;
dec_ctx->frame = frame;
dec_ctx->packet_count = 0;
dec_ctx->frame_count = 0;
dec_ctx->frame_num = cmd->frame_num;
dec_ctx->reader = reader;
@@ -531,27 +522,25 @@ void* multi_dec_decode(void *cmd_ctx)
t_s = mpp_time();
if (cmd->simple) {
while (!dec_ctx->eos) {
while (!dec_ctx->loop_end)
multi_dec_simple(dec_ctx);
}
} else {
while (!dec_ctx->eos) {
while (!dec_ctx->loop_end)
multi_dec_advanced(dec_ctx);
}
}
t_e = mpp_time();
rets->elapsed_time = t_e - t_s;
rets->frame_count = dec_ctx->frame_count;
rets->frame_rate = (float)dec_ctx->frame_count * 1000000 / rets->elapsed_time;
mpp_log("decode %d frame use time %lld ms frm rate %.2f\n",
dec_ctx->frame_count, rets->elapsed_time / 1000, rets->frame_rate);
ret = mpi->reset(ctx);
if (MPP_OK != ret) {
if (ret) {
mpp_err("mpi->reset failed\n");
goto MPP_TEST_OUT;
}
rets->elapsed_time = t_e - t_s;
rets->frame_count = dec_ctx->frame_count;
rets->frame_rate = (float)dec_ctx->frame_count * 1000000 / rets->elapsed_time;
rets->delay = dec_ctx->first_frm - dec_ctx->first_pkt;
MPP_TEST_OUT:
if (packet) {
mpp_packet_deinit(&packet);
@@ -568,25 +557,13 @@ MPP_TEST_OUT:
ctx = NULL;
}
if (cmd->simple) {
reader_deinit(&reader);
} else {
if (pkt_buf) {
mpp_buffer_put(pkt_buf);
pkt_buf = NULL;
}
if (!cmd->simple) {
if (frm_buf) {
mpp_buffer_put(frm_buf);
frm_buf = NULL;
}
}
if (dec_ctx->pkt_grp) {
mpp_buffer_group_put(dec_ctx->pkt_grp);
dec_ctx->pkt_grp = NULL;
}
if (dec_ctx->frm_grp) {
mpp_buffer_group_put(dec_ctx->frm_grp);
dec_ctx->frm_grp = NULL;
@@ -610,7 +587,7 @@ int main(int argc, char **argv)
RK_S32 ret = 0;
MpiDecTestCmd cmd_ctx;
MpiDecTestCmd* cmd = &cmd_ctx;
MpiDecCtxInfo *ctxs = NULL;
MpiDecMultiCtxInfo *ctxs = NULL;
RK_S32 i = 0;
float total_rate = 0.0;
@@ -618,21 +595,21 @@ int main(int argc, char **argv)
cmd->nthreads = 1;
// parse the cmd option
ret = mpi_dec_test_parse_options(argc, argv, cmd);
ret = mpi_dec_test_cmd_init(cmd, argc, argv);
if (ret) {
if (ret < 0) {
mpp_err("mpi_dec_multi_test_parse_options: input parameter invalid\n");
}
mpi_dec_test_help();
return ret;
mpi_dec_test_cmd_help();
goto RET;
}
mpi_dec_test_show_options(cmd);
mpi_dec_test_cmd_options(cmd);
cmd->simple = (cmd->type != MPP_VIDEO_CodingMJPEG) ? (1) : (0);
ctxs = mpp_calloc(MpiDecCtxInfo, cmd->nthreads);
ctxs = mpp_calloc(MpiDecMultiCtxInfo, cmd->nthreads);
if (NULL == ctxs) {
mpp_err("failed to alloc context for instances\n");
return -1;
@@ -648,20 +625,37 @@ int main(int argc, char **argv)
}
}
if (cmd->frame_num < 0) {
// wait for input then quit decoding
mpp_log("*******************************************\n");
mpp_log("**** Press Enter to stop loop decoding ****\n");
mpp_log("*******************************************\n");
getc(stdin);
for (i = 0; i < cmd->nthreads; i++)
ctxs[i].ctx.loop_end = 1;
}
for (i = 0; i < cmd->nthreads; i++)
pthread_join(ctxs[i].thd, NULL);
for (i = 0; i < cmd->nthreads; i++) {
total_rate += ctxs[i].ret.frame_rate;
mpp_log("payload %d frame rate: %.2f first delay %d ms\n", i,
ctxs[i].ret.frame_rate,
(ctxs[i].ctx.first_frm - ctxs[i].ctx.first_pkt) / 1000);
MpiDecMultiCtxRet *dec_ret = &ctxs[i].ret;
mpp_log("chn %2d decode %d frames time %lld ms delay %3d ms fps %3.2f\n", i,
dec_ret->frame_count, (RK_S64)(dec_ret->elapsed_time / 1000),
(RK_S32)(dec_ret->delay / 1000), dec_ret->frame_rate);
total_rate += dec_ret->frame_rate;
}
mpp_free(ctxs);
ctxs = NULL;
total_rate /= cmd->nthreads;
mpp_log("average frame rate %d\n", (int)total_rate);
mpp_log("average frame rate %.2f\n", total_rate);
RET:
mpi_dec_test_cmd_deinit(cmd);
return (int)total_rate;
}