xref: /rockchip-linux_mpp/test/mpi_dec_multi_test.c (revision 437bfbeb9567cca9cd9080e3f6954aa9d6a94f18)
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