1 /* SPDX-License-Identifier: Apache-2.0 OR MIT */
2 /*
3 * Copyright (c) 2015 Rockchip Electronics Co., Ltd.
4 */
5
6 #if defined(_WIN32)
7 #include "vld.h"
8 #endif
9
10 #define MODULE_TAG "mpi_dec_multi_test"
11
12 #include <string.h>
13 #include <pthread.h>
14
15 #include "rk_mpi.h"
16
17 #include "mpp_mem.h"
18 #include "mpp_env.h"
19 #include "mpp_time.h"
20 #include "mpp_common.h"
21
22 #include "mpi_dec_utils.h"
23
24 /* For each instance thread setup */
25 typedef struct {
26 MpiDecTestCmd *cmd;
27 MppCtx ctx;
28 MppApi *mpi;
29
30 /* end of stream flag when set quit the loop */
31 RK_U32 loop_end;
32
33 /* input and output */
34 DecBufMgr buf_mgr;
35 MppBufferGroup frm_grp;
36 MppPacket packet;
37 MppFrame frame;
38
39 FILE *fp_output;
40 RK_S32 packet_count;
41 RK_S32 frame_count;
42 RK_S32 frame_num;
43
44 RK_S64 first_pkt;
45 RK_S64 first_frm;
46
47 /* runtime flag */
48 RK_U32 quiet;
49 } MpiDecMultiCtx;
50
51 /* For each instance thread return value */
52 typedef struct {
53 float frame_rate;
54 RK_S64 elapsed_time;
55 RK_S32 frame_count;
56 RK_S64 delay;
57 } MpiDecMultiCtxRet;
58
59 typedef struct {
60 MpiDecTestCmd *cmd; // pointer to global command line info
61
62 pthread_t thd; // thread for for each instance
63 MpiDecMultiCtx ctx; // context of decoder
64 MpiDecMultiCtxRet ret; // return of decoder
65 } MpiDecMultiCtxInfo;
66
multi_dec_simple(MpiDecMultiCtx * data)67 static int multi_dec_simple(MpiDecMultiCtx *data)
68 {
69 MpiDecTestCmd *cmd = data->cmd;
70 RK_U32 pkt_done = 0;
71 RK_U32 pkt_eos = 0;
72 MppCtx ctx = data->ctx;
73 MppApi *mpi = data->mpi;
74 MppPacket packet = data->packet;
75 FileReader reader = cmd->reader;
76 FileBufSlot *slot = NULL;
77 RK_U32 quiet = data->quiet;
78 MPP_RET ret = reader_index_read(reader, data->packet_count++, &slot);
79
80 mpp_assert(ret == MPP_OK);
81 mpp_assert(slot);
82
83 pkt_eos = slot->eos;
84
85 if (pkt_eos) {
86 if (data->frame_num < 0 || data->frame_num > data->frame_count) {
87 mpp_log_q(quiet, "%p loop again\n", ctx);
88 data->packet_count = 0;
89 pkt_eos = 0;
90 } else {
91 mpp_log_q(quiet, "%p found last packet\n", ctx);
92 data->loop_end = 1;
93 }
94 }
95
96 mpp_packet_set_data(packet, slot->data);
97 mpp_packet_set_size(packet, slot->size);
98 mpp_packet_set_pos(packet, slot->data);
99 mpp_packet_set_length(packet, slot->size);
100 // setup eos flag
101 if (pkt_eos)
102 mpp_packet_set_eos(packet);
103
104 do {
105 RK_U32 frm_eos = 0;
106 RK_S32 times = 5;
107 // send the packet first if packet is not done
108 if (!pkt_done) {
109 ret = mpi->decode_put_packet(ctx, packet);
110 if (MPP_OK == ret) {
111 pkt_done = 1;
112 if (!data->first_pkt)
113 data->first_pkt = mpp_time();
114 }
115 }
116
117 // then get all available frame and release
118 do {
119 RK_S32 get_frm = 0;
120 MppFrame frame = NULL;
121
122 try_again:
123 ret = mpi->decode_get_frame(ctx, &frame);
124 if (MPP_ERR_TIMEOUT == ret) {
125 if (times > 0) {
126 times--;
127 msleep(2);
128 goto try_again;
129 }
130 mpp_err("decode_get_frame failed too much time\n");
131 }
132 if (ret) {
133 mpp_err("decode_get_frame failed ret %d\n", ret);
134 break;
135 }
136
137 if (frame) {
138 if (mpp_frame_get_info_change(frame)) {
139 RK_U32 width = mpp_frame_get_width(frame);
140 RK_U32 height = mpp_frame_get_height(frame);
141 RK_U32 hor_stride = mpp_frame_get_hor_stride(frame);
142 RK_U32 ver_stride = mpp_frame_get_ver_stride(frame);
143 RK_U32 buf_size = mpp_frame_get_buf_size(frame);
144 MppBufferGroup grp = NULL;
145
146 mpp_log_q(quiet, "decode_get_frame get info changed found\n");
147 mpp_log_q(quiet, "decoder require buffer w:h [%d:%d] stride [%d:%d] buf_size %d",
148 width, height, hor_stride, ver_stride, buf_size);
149
150 if (MPP_FRAME_FMT_IS_FBC(cmd->format)) {
151 MppFrame frm = NULL;
152
153 mpp_frame_init(&frm);
154 mpp_frame_set_width(frm, width);
155 mpp_frame_set_height(frm, height);
156 mpp_frame_set_fmt(frm, cmd->format);
157
158 ret = mpi->control(ctx, MPP_DEC_SET_FRAME_INFO, frm);
159 mpp_frame_deinit(&frm);
160
161 if (ret) {
162 mpp_err("set fbc frame info failed\n");
163 break;
164 }
165 }
166
167 grp = dec_buf_mgr_setup(data->buf_mgr, buf_size, 24, cmd->buf_mode);
168 /* Set buffer to mpp decoder */
169 ret = mpi->control(ctx, MPP_DEC_SET_EXT_BUF_GROUP, grp);
170 if (ret) {
171 mpp_err("%p set buffer group failed ret %d\n", ctx, ret);
172 break;
173 }
174 data->frm_grp = grp;
175
176 /*
177 * All buffer group config done. Set info change ready to let
178 * decoder continue decoding
179 */
180 ret = mpi->control(ctx, MPP_DEC_SET_INFO_CHANGE_READY, NULL);
181 if (ret) {
182 mpp_err("info change ready failed ret %d\n", ret);
183 break;
184 }
185 } else {
186 RK_U32 err_info = 0;
187
188 if (!data->first_frm)
189 data->first_frm = mpp_time();
190
191 err_info = mpp_frame_get_errinfo(frame) |
192 mpp_frame_get_discard(frame);
193 if (err_info) {
194 mpp_log_q(quiet, "decoder_get_frame get err info:%d discard:%d.\n",
195 mpp_frame_get_errinfo(frame),
196 mpp_frame_get_discard(frame));
197 }
198 mpp_log_q(quiet, "decode_get_frame get frame %d\n",
199 data->frame_count);
200
201 data->frame_count++;
202 if (data->fp_output && !err_info)
203 dump_mpp_frame_to_file(frame, data->fp_output);
204
205 fps_calc_inc(cmd->fps);
206 }
207 frm_eos = mpp_frame_get_eos(frame);
208 mpp_frame_deinit(&frame);
209 get_frm = 1;
210 }
211
212 // if last packet is send but last frame is not found continue
213 if (pkt_eos && pkt_done && !frm_eos) {
214 msleep(1);
215 continue;
216 }
217
218 if ((data->frame_num > 0 && (data->frame_count >= data->frame_num)) ||
219 ((data->frame_num == 0) && frm_eos))
220 break;
221
222 if (get_frm)
223 continue;
224 break;
225 } while (1);
226
227 if ((data->frame_num > 0 && (data->frame_count >= data->frame_num)) ||
228 ((data->frame_num == 0) && frm_eos)) {
229 data->loop_end = 1;
230 break;
231 }
232
233 if (pkt_done)
234 break;
235
236 /*
237 * why sleep here:
238 * mpi->decode_put_packet will failed when packet in internal queue is
239 * full,waiting the package is consumed .Usually hardware decode one
240 * frame which resolution is 1080p needs 2 ms,so here we sleep 3ms
241 * * is enough.
242 */
243 msleep(1);
244 } while (1);
245
246 return ret;
247 }
248
multi_dec_advanced(MpiDecMultiCtx * data)249 static int multi_dec_advanced(MpiDecMultiCtx *data)
250 {
251 MPP_RET ret = MPP_OK;
252 MpiDecTestCmd *cmd = data->cmd;
253 MppCtx ctx = data->ctx;
254 MppApi *mpi = data->mpi;
255 MppPacket packet = NULL;
256 MppFrame frame = data->frame;
257 MppTask task = NULL;
258 RK_U32 quiet = data->quiet;
259 FileBufSlot *slot = NULL;
260
261 ret = reader_index_read(cmd->reader, 0, &slot);
262 mpp_assert(ret == MPP_OK);
263 mpp_assert(slot);
264
265 mpp_packet_init_with_buffer(&packet, slot->buf);
266
267 // setup eos flag
268 if (slot->eos)
269 mpp_packet_set_eos(packet);
270
271 ret = mpi->poll(ctx, MPP_PORT_INPUT, MPP_POLL_BLOCK);
272 if (ret) {
273 mpp_err("mpp input poll failed\n");
274 return ret;
275 }
276
277 ret = mpi->dequeue(ctx, MPP_PORT_INPUT, &task); /* input queue */
278 if (ret) {
279 mpp_err("mpp task input dequeue failed\n");
280 return ret;
281 }
282
283 mpp_assert(task);
284
285 mpp_task_meta_set_packet(task, KEY_INPUT_PACKET, packet);
286 mpp_task_meta_set_frame (task, KEY_OUTPUT_FRAME, frame);
287
288 ret = mpi->enqueue(ctx, MPP_PORT_INPUT, task); /* input queue */
289 if (ret) {
290 mpp_err("mpp task input enqueue failed\n");
291 return ret;
292 }
293
294 if (!data->first_pkt)
295 data->first_pkt = mpp_time();
296
297 /* poll and wait here */
298 ret = mpi->poll(ctx, MPP_PORT_OUTPUT, MPP_POLL_BLOCK);
299 if (ret) {
300 mpp_err("mpp output poll failed\n");
301 return ret;
302 }
303
304 ret = mpi->dequeue(ctx, MPP_PORT_OUTPUT, &task); /* output queue */
305 if (ret) {
306 mpp_err("mpp task output dequeue failed\n");
307 return ret;
308 }
309
310 mpp_assert(task);
311
312 if (task) {
313 MppFrame frame_out = NULL;
314
315 mpp_task_meta_get_frame(task, KEY_OUTPUT_FRAME, &frame_out);
316
317 if (frame) {
318 if (!data->first_frm)
319 data->first_frm = mpp_time();
320
321 if (data->fp_output)
322 dump_mpp_frame_to_file(frame, data->fp_output);
323
324 mpp_log_q(quiet, "%p decoded frame %d\n", ctx, data->frame_count);
325 data->frame_count++;
326
327 if (mpp_frame_get_eos(frame_out)) {
328 mpp_log_q(quiet, "%p found eos frame\n", ctx);
329 }
330 fps_calc_inc(cmd->fps);
331 }
332
333 if (data->frame_num > 0) {
334 if (data->frame_count >= data->frame_num)
335 data->loop_end = 1;
336 } else if (data->frame_num == 0) {
337 if (slot->eos)
338 data->loop_end = 1;
339 }
340
341 /* output queue */
342 ret = mpi->enqueue(ctx, MPP_PORT_OUTPUT, task);
343 if (ret)
344 mpp_err("mpp task output enqueue failed\n");
345 }
346
347 /*
348 * The following input port task dequeue and enqueue is to make sure that
349 * the input packet can be released. We can directly deinit the input packet
350 * after frame output in most cases.
351 */
352 if (0) {
353 mpp_packet_deinit(&packet);
354 } else {
355 ret = mpi->dequeue(ctx, MPP_PORT_INPUT, &task); /* input queue */
356 if (ret) {
357 mpp_err("%p mpp task input dequeue failed\n", ctx);
358 return ret;
359 }
360
361 mpp_assert(task);
362 if (task) {
363 MppPacket packet_out = NULL;
364
365 mpp_task_meta_get_packet(task, KEY_INPUT_PACKET, &packet_out);
366
367 if (!packet_out || packet_out != packet)
368 mpp_err_f("mismatch packet %p -> %p\n", packet, packet_out);
369
370 mpp_packet_deinit(&packet_out);
371
372 /* input empty task back to mpp to maintain task status */
373 ret = mpi->enqueue(ctx, MPP_PORT_INPUT, task);
374 if (ret)
375 mpp_err("%p mpp task input enqueue failed\n", ctx);
376 }
377 }
378
379 return ret;
380 }
381
multi_dec_decode(void * cmd_ctx)382 void* multi_dec_decode(void *cmd_ctx)
383 {
384 MpiDecMultiCtxInfo *info = (MpiDecMultiCtxInfo *)cmd_ctx;
385 MpiDecMultiCtx *dec_ctx = &info->ctx;
386 MpiDecMultiCtxRet *rets = &info->ret;
387 MpiDecTestCmd *cmd = info->cmd;
388 MPP_RET ret = MPP_OK;
389
390 // base flow context
391 MppCtx ctx = NULL;
392 MppApi *mpi = NULL;
393
394 // input / output
395 MppPacket packet = NULL;
396 MppFrame frame = NULL;
397
398 // config for runtime mode
399 MppDecCfg cfg = NULL;
400 RK_U32 need_split = 1;
401
402 // paramter for resource malloc
403 RK_U32 width = cmd->width;
404 RK_U32 height = cmd->height;
405 MppCodingType type = cmd->type;
406
407 // resources
408 MppBuffer frm_buf = NULL;
409
410 if (cmd->have_output) {
411 dec_ctx->fp_output = fopen(cmd->file_output, "w+b");
412 if (NULL == dec_ctx->fp_output) {
413 mpp_err("failed to open output file %s\n", cmd->file_output);
414 goto MPP_TEST_OUT;
415 }
416 }
417
418 ret = dec_buf_mgr_init(&dec_ctx->buf_mgr);
419 if (ret) {
420 mpp_err("dec_buf_mgr_init failed\n");
421 goto MPP_TEST_OUT;
422 }
423
424 if (cmd->simple) {
425 ret = mpp_packet_init(&packet, NULL, 0);
426 if (ret) {
427 mpp_err("mpp_packet_init failed\n");
428 goto MPP_TEST_OUT;
429 }
430 } else {
431 RK_U32 hor_stride = MPP_ALIGN(width, 16);
432 RK_U32 ver_stride = MPP_ALIGN(height, 16);
433
434 ret = mpp_frame_init(&frame); /* output frame */
435 if (ret) {
436 mpp_err("mpp_frame_init failed\n");
437 goto MPP_TEST_OUT;
438 }
439
440 dec_ctx->frm_grp = dec_buf_mgr_setup(dec_ctx->buf_mgr, hor_stride * ver_stride * 2, 4, cmd->buf_mode);
441 if (!dec_ctx->frm_grp) {
442 mpp_err("failed to get buffer group for input frame ret %d\n", ret);
443 ret = MPP_NOK;
444 goto MPP_TEST_OUT;
445 }
446
447 /*
448 * NOTE: For jpeg could have YUV420 and YUV422 the buffer should be
449 * larger for output. And the buffer dimension should align to 16.
450 * YUV420 buffer is 3/2 times of w*h.
451 * YUV422 buffer is 2 times of w*h.
452 * So create larger buffer with 2 times w*h.
453 */
454 ret = mpp_buffer_get(dec_ctx->frm_grp, &frm_buf, hor_stride * ver_stride * 2);
455 if (ret) {
456 mpp_err("failed to get buffer for input frame ret %d\n", ret);
457 goto MPP_TEST_OUT;
458 }
459
460 mpp_frame_set_buffer(frame, frm_buf);
461 }
462
463 // decoder demo
464 ret = mpp_create(&ctx, &mpi);
465 if (ret) {
466 mpp_err("mpp_create failed\n");
467 goto MPP_TEST_OUT;
468 }
469
470 mpp_log("%p mpi_dec_test decoder test start w %d h %d type %d\n",
471 ctx, width, height, type);
472
473 ret = mpp_init(ctx, MPP_CTX_DEC, type);
474 if (ret) {
475 mpp_err("mpp_init failed\n");
476 goto MPP_TEST_OUT;
477 }
478
479 mpp_dec_cfg_init(&cfg);
480
481 /* get default config from decoder context */
482 ret = mpi->control(ctx, MPP_DEC_GET_CFG, cfg);
483 if (ret) {
484 mpp_err("%p failed to get decoder cfg ret %d\n", ctx, ret);
485 goto MPP_TEST_OUT;
486 }
487
488 /*
489 * split_parse is to enable mpp internal frame spliter when the input
490 * packet is not aplited into frames.
491 */
492 ret = mpp_dec_cfg_set_u32(cfg, "base:split_parse", need_split);
493 if (ret) {
494 mpp_err("%p failed to set split_parse ret %d\n", ctx, ret);
495 goto MPP_TEST_OUT;
496 }
497
498 ret = mpi->control(ctx, MPP_DEC_SET_CFG, cfg);
499 if (ret) {
500 mpp_err("%p failed to set cfg %p ret %d\n", ctx, cfg, ret);
501 goto MPP_TEST_OUT;
502 }
503
504 dec_ctx->cmd = cmd;
505 dec_ctx->ctx = ctx;
506 dec_ctx->mpi = mpi;
507 dec_ctx->packet = packet;
508 dec_ctx->frame = frame;
509 dec_ctx->packet_count = 0;
510 dec_ctx->frame_count = 0;
511 dec_ctx->frame_num = cmd->frame_num;
512 dec_ctx->quiet = cmd->quiet;
513
514 RK_S64 t_s, t_e;
515
516 t_s = mpp_time();
517 if (cmd->simple) {
518 while (!dec_ctx->loop_end)
519 multi_dec_simple(dec_ctx);
520 } else {
521 while (!dec_ctx->loop_end)
522 multi_dec_advanced(dec_ctx);
523 }
524 t_e = mpp_time();
525
526 ret = mpi->reset(ctx);
527 if (ret) {
528 mpp_err("mpi->reset failed\n");
529 goto MPP_TEST_OUT;
530 }
531
532 rets->elapsed_time = t_e - t_s;
533 rets->frame_count = dec_ctx->frame_count;
534 rets->frame_rate = (float)dec_ctx->frame_count * 1000000 / rets->elapsed_time;
535 rets->delay = dec_ctx->first_frm - dec_ctx->first_pkt;
536
537 MPP_TEST_OUT:
538 if (packet) {
539 mpp_packet_deinit(&packet);
540 packet = NULL;
541 }
542
543 if (frame) {
544 mpp_frame_deinit(&frame);
545 frame = NULL;
546 }
547
548 if (ctx) {
549 mpp_destroy(ctx);
550 ctx = NULL;
551 }
552
553 if (!cmd->simple) {
554 if (frm_buf) {
555 mpp_buffer_put(frm_buf);
556 frm_buf = NULL;
557 }
558 }
559
560 dec_ctx->frm_grp = NULL;
561 if (dec_ctx->buf_mgr) {
562 dec_buf_mgr_deinit(dec_ctx->buf_mgr);
563 dec_ctx->buf_mgr = NULL;
564 }
565
566 if (dec_ctx->fp_output) {
567 fclose(dec_ctx->fp_output);
568 dec_ctx->fp_output = NULL;
569 }
570
571 if (cfg) {
572 mpp_dec_cfg_deinit(cfg);
573 cfg = NULL;
574 }
575
576 return NULL;
577 }
578
main(int argc,char ** argv)579 int main(int argc, char **argv)
580 {
581 RK_S32 ret = 0;
582 MpiDecTestCmd cmd_ctx;
583 MpiDecTestCmd* cmd = &cmd_ctx;
584 MpiDecMultiCtxInfo *ctxs = NULL;
585 RK_S32 i = 0;
586 float total_rate = 0.0;
587
588 memset((void*)cmd, 0, sizeof(*cmd));
589 cmd->nthreads = 1;
590
591 // parse the cmd option
592 ret = mpi_dec_test_cmd_init(cmd, argc, argv);
593 if (ret)
594 goto RET;
595
596 mpi_dec_test_cmd_options(cmd);
597
598 cmd->simple = (cmd->type != MPP_VIDEO_CodingMJPEG) ? (1) : (0);
599
600 ctxs = mpp_calloc(MpiDecMultiCtxInfo, cmd->nthreads);
601 if (NULL == ctxs) {
602 mpp_err("failed to alloc context for instances\n");
603 return -1;
604 }
605
606 for (i = 0; i < cmd->nthreads; i++) {
607 ctxs[i].cmd = cmd;
608
609 ret = pthread_create(&ctxs[i].thd, NULL, multi_dec_decode, &ctxs[i]);
610 if (ret) {
611 mpp_log("failed to create thread %d\n", i);
612 return ret;
613 }
614 }
615
616 if (cmd->frame_num < 0) {
617 // wait for input then quit decoding
618 mpp_log("*******************************************\n");
619 mpp_log("**** Press Enter to stop loop decoding ****\n");
620 mpp_log("*******************************************\n");
621
622 getc(stdin);
623 for (i = 0; i < cmd->nthreads; i++)
624 ctxs[i].ctx.loop_end = 1;
625 }
626
627 for (i = 0; i < cmd->nthreads; i++)
628 pthread_join(ctxs[i].thd, NULL);
629
630 for (i = 0; i < cmd->nthreads; i++) {
631 MpiDecMultiCtxRet *dec_ret = &ctxs[i].ret;
632
633 mpp_log("chn %2d decode %d frames time %lld ms delay %3d ms fps %3.2f\n", i,
634 dec_ret->frame_count, (RK_S64)(dec_ret->elapsed_time / 1000),
635 (RK_S32)(dec_ret->delay / 1000), dec_ret->frame_rate);
636
637 total_rate += dec_ret->frame_rate;
638 }
639 mpp_free(ctxs);
640 ctxs = NULL;
641
642 total_rate /= cmd->nthreads;
643 mpp_log("average frame rate %.2f\n", total_rate);
644
645 RET:
646 mpi_dec_test_cmd_deinit(cmd);
647
648 return (int)total_rate;
649 }
650