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