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