xref: /rockchip-linux_mpp/test/mpi_enc_mt_test.c (revision 437bfbeb9567cca9cd9080e3f6954aa9d6a94f18)
1 /* SPDX-License-Identifier: Apache-2.0 OR MIT */
2 /*
3  * Copyright (c) 2022 Rockchip Electronics Co., Ltd.
4  */
5 
6 #define MODULE_TAG "mpi_enc_mt_test"
7 
8 #include <string.h>
9 #include "rk_mpi.h"
10 
11 #include "mpp_env.h"
12 #include "mpp_mem.h"
13 #include "mpp_time.h"
14 #include "mpp_list.h"
15 #include "mpp_lock.h"
16 #include "mpp_debug.h"
17 #include "mpp_common.h"
18 
19 #include "utils.h"
20 #include "mpi_enc_utils.h"
21 #include "camera_source.h"
22 #include "mpp_enc_roi_utils.h"
23 
24 #define BUF_COUNT   4
25 
26 typedef struct {
27     // base flow context
28     MppCtx ctx;
29     MppApi *mpi;
30     RK_S32 chn;
31 
32     // global flow control flag
33     RK_U32 frm_eos;
34     RK_U32 pkt_eos;
35     RK_U32 frm_pkt_cnt;
36     RK_S32 frame_num;
37     RK_S32 frm_cnt_in;
38     RK_S32 frm_cnt_out;
39     RK_S32 frm_step;
40     RK_U64 stream_size;
41     /* end of encoding flag when set quit the loop */
42     volatile RK_U32 loop_end;
43 
44     // src and dst
45     FILE *fp_input;
46     FILE *fp_output;
47     FILE *fp_verify;
48 
49     /* encoder config set */
50     MppEncCfg       cfg;
51     MppEncPrepCfg   prep_cfg;
52     MppEncRcCfg     rc_cfg;
53     MppEncOSDPltCfg osd_plt_cfg;
54     MppEncOSDPlt    osd_plt;
55     MppEncOSDData   osd_data;
56     RoiRegionCfg    roi_region;
57     MppEncROICfg    roi_cfg;
58 
59     // input / output
60     MppList         *list_buf;
61     MppBufferGroup  buf_grp;
62     MppBuffer frm_buf[BUF_COUNT];
63     MppBuffer pkt_buf[BUF_COUNT];
64     RK_S32 buf_idx;
65     MppEncSeiMode sei_mode;
66     MppEncHeaderMode header_mode;
67 
68     // paramter for resource malloc
69     RK_U32 width;
70     RK_U32 height;
71     RK_U32 hor_stride;
72     RK_U32 ver_stride;
73     MppFrameFormat fmt;
74     MppCodingType type;
75     RK_S32 loop_times;
76     CamSource *cam_ctx;
77     MppEncRoiCtx roi_ctx;
78 
79     // resources
80     size_t header_size;
81     size_t frame_size;
82     /* NOTE: packet buffer may overflow */
83     size_t packet_size;
84 
85     RK_U32 osd_enable;
86     RK_U32 osd_mode;
87     RK_U32 split_mode;
88     RK_U32 split_arg;
89     RK_U32 split_out;
90 
91     RK_U32 user_data_enable;
92     RK_U32 roi_enable;
93 
94     // rate control runtime parameter
95     RK_S32 fps_in_flex;
96     RK_S32 fps_in_den;
97     RK_S32 fps_in_num;
98     RK_S32 fps_out_flex;
99     RK_S32 fps_out_den;
100     RK_S32 fps_out_num;
101     RK_S32 bps;
102     RK_S32 bps_max;
103     RK_S32 bps_min;
104     RK_S32 rc_mode;
105     RK_S32 gop_mode;
106     RK_S32 gop_len;
107     RK_S32 vi_len;
108 
109     RK_S64 first_frm;
110     RK_S64 first_pkt;
111     RK_S64 last_pkt;
112 } MpiEncMtTestData;
113 
114 /* For each instance thread return value */
115 typedef struct {
116     float           frame_rate;
117     RK_U64          bit_rate;
118 
119     RK_S64          time_start;
120     RK_S64          time_delay;
121     RK_S64          time_total;
122 
123     RK_S64          elapsed_time;
124     RK_S32          frame_count;
125     RK_S64          stream_size;
126     RK_S64          delay;
127 } MpiEncMtCtxRet;
128 
129 typedef struct {
130     MpiEncTestArgs      *cmd;       // pointer to global command line info
131     const char          *name;
132     RK_S32              chn;
133 
134     pthread_t           thd_in;     // thread for for frame input
135     pthread_t           thd_out;    // thread for for packet output
136 
137     struct list_head    frm_list;
138     spinlock_t          frm_lock;
139 
140     MpiEncMtTestData    ctx;        // context of encoder
141     MpiEncMtCtxRet      ret;        // return of encoder
142 } MpiEncMtCtxInfo;
143 
mt_test_ctx_init(MpiEncMtCtxInfo * info)144 MPP_RET mt_test_ctx_init(MpiEncMtCtxInfo *info)
145 {
146     MpiEncTestArgs *cmd = info->cmd;
147     MpiEncMtTestData *p = &info->ctx;
148     MPP_RET ret = MPP_OK;
149 
150     // get paramter from cmd
151     p->width        = cmd->width;
152     p->height       = cmd->height;
153     p->hor_stride   = (cmd->hor_stride) ? (cmd->hor_stride) :
154                       (MPP_ALIGN(cmd->width, 16));
155     p->ver_stride   = (cmd->ver_stride) ? (cmd->ver_stride) :
156                       (MPP_ALIGN(cmd->height, 16));
157     p->fmt          = cmd->format;
158     p->type         = cmd->type;
159     p->bps          = cmd->bps_target;
160     p->bps_min      = cmd->bps_min;
161     p->bps_max      = cmd->bps_max;
162     p->rc_mode      = cmd->rc_mode;
163     p->frame_num    = cmd->frame_num;
164     if (cmd->type == MPP_VIDEO_CodingMJPEG && p->frame_num == 0) {
165         mpp_log("jpege default encode only one frame. Use -n [num] for rc case\n");
166         p->frame_num = 1;
167     }
168 
169     p->frm_step     = cmd->frm_step;
170     p->gop_mode     = cmd->gop_mode;
171     p->gop_len      = cmd->gop_len;
172     p->vi_len       = cmd->vi_len;
173 
174     p->fps_in_flex  = cmd->fps_in_flex;
175     p->fps_in_den   = cmd->fps_in_den;
176     p->fps_in_num   = cmd->fps_in_num;
177     p->fps_out_flex = cmd->fps_out_flex;
178     p->fps_out_den  = cmd->fps_out_den;
179     p->fps_out_num  = cmd->fps_out_num;
180 
181     if (cmd->file_input) {
182         if (!strncmp(cmd->file_input, "/dev/video", 10)) {
183             mpp_log("open camera device");
184             p->cam_ctx = camera_source_init(cmd->file_input, 4, p->width, p->height, p->fmt);
185             mpp_log("new framecap ok");
186             if (p->cam_ctx == NULL)
187                 mpp_err("open %s fail", cmd->file_input);
188         } else {
189             p->fp_input = fopen(cmd->file_input, "rb");
190             if (NULL == p->fp_input) {
191                 mpp_err("failed to open input file %s\n", cmd->file_input);
192                 mpp_err("create default yuv image for test\n");
193             }
194         }
195     }
196 
197     if (cmd->file_output) {
198         p->fp_output = fopen(cmd->file_output, "w+b");
199         if (NULL == p->fp_output) {
200             mpp_err("failed to open output file %s\n", cmd->file_output);
201             ret = MPP_ERR_OPEN_FILE;
202         }
203     }
204 
205     if (cmd->file_slt) {
206         p->fp_verify = fopen(cmd->file_slt, "wt");
207         if (!p->fp_verify)
208             mpp_err("failed to open verify file %s\n", cmd->file_slt);
209     }
210 
211     // update resource parameter
212     switch (p->fmt & MPP_FRAME_FMT_MASK) {
213     case MPP_FMT_YUV420SP:
214     case MPP_FMT_YUV420P: {
215         p->frame_size = MPP_ALIGN(p->hor_stride, 64) * MPP_ALIGN(p->ver_stride, 64) * 3 / 2;
216     } break;
217 
218     case MPP_FMT_YUV422_YUYV :
219     case MPP_FMT_YUV422_YVYU :
220     case MPP_FMT_YUV422_UYVY :
221     case MPP_FMT_YUV422_VYUY :
222     case MPP_FMT_YUV422P :
223     case MPP_FMT_YUV422SP : {
224         p->frame_size = MPP_ALIGN(p->hor_stride, 64) * MPP_ALIGN(p->ver_stride, 64) * 2;
225     } break;
226     case MPP_FMT_YUV400 :
227     case MPP_FMT_RGB444 :
228     case MPP_FMT_BGR444 :
229     case MPP_FMT_RGB555 :
230     case MPP_FMT_BGR555 :
231     case MPP_FMT_RGB565 :
232     case MPP_FMT_BGR565 :
233     case MPP_FMT_RGB888 :
234     case MPP_FMT_BGR888 :
235     case MPP_FMT_RGB101010 :
236     case MPP_FMT_BGR101010 :
237     case MPP_FMT_ARGB8888 :
238     case MPP_FMT_ABGR8888 :
239     case MPP_FMT_BGRA8888 :
240     case MPP_FMT_RGBA8888 : {
241         p->frame_size = MPP_ALIGN(p->hor_stride, 64) * MPP_ALIGN(p->ver_stride, 64);
242     } break;
243 
244     default: {
245         p->frame_size = MPP_ALIGN(p->hor_stride, 64) * MPP_ALIGN(p->ver_stride, 64) * 4;
246     } break;
247     }
248 
249     if (MPP_FRAME_FMT_IS_FBC(p->fmt))
250         p->header_size = MPP_ALIGN(MPP_ALIGN(p->width, 16) * MPP_ALIGN(p->height, 16) / 16, SZ_4K);
251     else
252         p->header_size = 0;
253 
254     return ret;
255 }
256 
mt_test_ctx_deinit(MpiEncMtCtxInfo * info)257 MPP_RET mt_test_ctx_deinit(MpiEncMtCtxInfo *info)
258 {
259     MpiEncMtTestData *p = NULL;
260 
261     if (NULL == info)
262         return MPP_OK;
263 
264     p = &info->ctx;
265 
266     if (p->cam_ctx) {
267         camera_source_deinit(p->cam_ctx);
268         p->cam_ctx = NULL;
269     }
270     if (p->fp_input) {
271         fclose(p->fp_input);
272         p->fp_input = NULL;
273     }
274     if (p->fp_output) {
275         fclose(p->fp_output);
276         p->fp_output = NULL;
277     }
278     if (p->fp_verify) {
279         fclose(p->fp_verify);
280         p->fp_verify = NULL;
281     }
282 
283     return MPP_OK;
284 }
285 
test_mt_cfg_setup(MpiEncMtCtxInfo * info)286 MPP_RET test_mt_cfg_setup(MpiEncMtCtxInfo *info)
287 {
288     MpiEncTestArgs *cmd = info->cmd;
289     MpiEncMtTestData *p = &info->ctx;
290     MppApi *mpi = p->mpi;
291     MppCtx ctx = p->ctx;
292     MppEncCfg cfg = p->cfg;
293     RK_U32 gop_mode = p->gop_mode;
294     RK_U32 quiet = cmd->quiet;
295     MPP_RET ret;
296     MppEncRefCfg ref = NULL;
297 
298     /* setup default parameter */
299     if (p->fps_in_den == 0)
300         p->fps_in_den = 1;
301     if (p->fps_in_num == 0)
302         p->fps_in_num = 30;
303     if (p->fps_out_den == 0)
304         p->fps_out_den = 1;
305     if (p->fps_out_num == 0)
306         p->fps_out_num = 30;
307 
308     if (!p->bps)
309         p->bps = p->width * p->height / 8 * (p->fps_out_num / p->fps_out_den);
310 
311     mpp_enc_cfg_set_s32(cfg, "codec:type", p->type);
312 
313     mpp_enc_cfg_set_s32(cfg, "prep:width", p->width);
314     mpp_enc_cfg_set_s32(cfg, "prep:height", p->height);
315     mpp_enc_cfg_set_s32(cfg, "prep:hor_stride", p->hor_stride);
316     mpp_enc_cfg_set_s32(cfg, "prep:ver_stride", p->ver_stride);
317     mpp_enc_cfg_set_s32(cfg, "prep:format", p->fmt);
318 
319     mpp_enc_cfg_set_s32(cfg, "rc:mode", p->rc_mode);
320 
321     /* fix input / output frame rate */
322     mpp_enc_cfg_set_s32(cfg, "rc:fps_in_flex", p->fps_in_flex);
323     mpp_enc_cfg_set_s32(cfg, "rc:fps_in_num", p->fps_in_num);
324     mpp_enc_cfg_set_s32(cfg, "rc:fps_in_denom", p->fps_in_den);
325     mpp_enc_cfg_set_s32(cfg, "rc:fps_out_flex", p->fps_out_flex);
326     mpp_enc_cfg_set_s32(cfg, "rc:fps_out_num", p->fps_out_num);
327     mpp_enc_cfg_set_s32(cfg, "rc:fps_out_denom", p->fps_out_den);
328 
329     /* drop frame or not when bitrate overflow */
330     mpp_enc_cfg_set_u32(cfg, "rc:drop_mode", MPP_ENC_RC_DROP_FRM_DISABLED);
331     mpp_enc_cfg_set_u32(cfg, "rc:drop_thd", 20);        /* 20% of max bps */
332     mpp_enc_cfg_set_u32(cfg, "rc:drop_gap", 1);         /* Do not continuous drop frame */
333 
334     /* setup bitrate for different rc_mode */
335     mpp_enc_cfg_set_s32(cfg, "rc:bps_target", p->bps);
336     switch (p->rc_mode) {
337     case MPP_ENC_RC_MODE_FIXQP : {
338         /* do not setup bitrate on FIXQP mode */
339     } break;
340     case MPP_ENC_RC_MODE_CBR : {
341         /* CBR mode has narrow bound */
342         mpp_enc_cfg_set_s32(cfg, "rc:bps_max", p->bps_max ? p->bps_max : p->bps * 17 / 16);
343         mpp_enc_cfg_set_s32(cfg, "rc:bps_min", p->bps_min ? p->bps_min : p->bps * 15 / 16);
344     } break;
345     case MPP_ENC_RC_MODE_VBR :
346     case MPP_ENC_RC_MODE_AVBR : {
347         /* VBR mode has wide bound */
348         mpp_enc_cfg_set_s32(cfg, "rc:bps_max", p->bps_max ? p->bps_max : p->bps * 17 / 16);
349         mpp_enc_cfg_set_s32(cfg, "rc:bps_min", p->bps_min ? p->bps_min : p->bps * 1 / 16);
350     } break;
351     default : {
352         /* default use CBR mode */
353         mpp_enc_cfg_set_s32(cfg, "rc:bps_max", p->bps_max ? p->bps_max : p->bps * 17 / 16);
354         mpp_enc_cfg_set_s32(cfg, "rc:bps_min", p->bps_min ? p->bps_min : p->bps * 15 / 16);
355     } break;
356     }
357 
358     /* setup qp for different codec and rc_mode */
359     switch (p->type) {
360     case MPP_VIDEO_CodingAVC :
361     case MPP_VIDEO_CodingHEVC : {
362         switch (p->rc_mode) {
363         case MPP_ENC_RC_MODE_FIXQP : {
364             RK_S32 fix_qp = cmd->qp_init;
365 
366             mpp_enc_cfg_set_s32(cfg, "rc:qp_init", fix_qp);
367             mpp_enc_cfg_set_s32(cfg, "rc:qp_max", fix_qp);
368             mpp_enc_cfg_set_s32(cfg, "rc:qp_min", fix_qp);
369             mpp_enc_cfg_set_s32(cfg, "rc:qp_max_i", fix_qp);
370             mpp_enc_cfg_set_s32(cfg, "rc:qp_min_i", fix_qp);
371             mpp_enc_cfg_set_s32(cfg, "rc:qp_ip", 0);
372         } break;
373         case MPP_ENC_RC_MODE_CBR :
374         case MPP_ENC_RC_MODE_VBR :
375         case MPP_ENC_RC_MODE_AVBR : {
376             mpp_enc_cfg_set_s32(cfg, "rc:qp_init", cmd->qp_init ? cmd->qp_init : -1);
377             mpp_enc_cfg_set_s32(cfg, "rc:qp_max", cmd->qp_max ? cmd->qp_max : 51);
378             mpp_enc_cfg_set_s32(cfg, "rc:qp_min", cmd->qp_min ? cmd->qp_min : 10);
379             mpp_enc_cfg_set_s32(cfg, "rc:qp_max_i", cmd->qp_max_i ? cmd->qp_max_i : 51);
380             mpp_enc_cfg_set_s32(cfg, "rc:qp_min_i", cmd->qp_min_i ? cmd->qp_min_i : 10);
381             mpp_enc_cfg_set_s32(cfg, "rc:qp_ip", 2);
382         } break;
383         default : {
384             mpp_err_f("unsupport encoder rc mode %d\n", p->rc_mode);
385         } break;
386         }
387     } break;
388     case MPP_VIDEO_CodingVP8 : {
389         /* vp8 only setup base qp range */
390         mpp_enc_cfg_set_s32(cfg, "rc:qp_init", cmd->qp_init ? cmd->qp_init : 40);
391         mpp_enc_cfg_set_s32(cfg, "rc:qp_max",  cmd->qp_max ? cmd->qp_max : 127);
392         mpp_enc_cfg_set_s32(cfg, "rc:qp_min",  cmd->qp_min ? cmd->qp_min : 0);
393         mpp_enc_cfg_set_s32(cfg, "rc:qp_max_i", cmd->qp_max_i ? cmd->qp_max_i : 127);
394         mpp_enc_cfg_set_s32(cfg, "rc:qp_min_i", cmd->qp_min_i ? cmd->qp_min_i : 0);
395         mpp_enc_cfg_set_s32(cfg, "rc:qp_ip", 6);
396     } break;
397     case MPP_VIDEO_CodingMJPEG : {
398         /* jpeg use special codec config to control qtable */
399         mpp_enc_cfg_set_s32(cfg, "jpeg:q_factor", cmd->qp_init ? cmd->qp_init : 80);
400         mpp_enc_cfg_set_s32(cfg, "jpeg:qf_max", cmd->qp_max ? cmd->qp_max : 99);
401         mpp_enc_cfg_set_s32(cfg, "jpeg:qf_min", cmd->qp_min ? cmd->qp_min : 1);
402     } break;
403     default : {
404     } break;
405     }
406 
407     /* setup codec  */
408     mpp_enc_cfg_set_s32(cfg, "codec:type", p->type);
409     switch (p->type) {
410     case MPP_VIDEO_CodingAVC : {
411         /*
412          * H.264 profile_idc parameter
413          * 66  - Baseline profile
414          * 77  - Main profile
415          * 100 - High profile
416          */
417         mpp_enc_cfg_set_s32(cfg, "h264:profile", 100);
418         /*
419          * H.264 level_idc parameter
420          * 10 / 11 / 12 / 13    - qcif@15fps / cif@7.5fps / cif@15fps / cif@30fps
421          * 20 / 21 / 22         - cif@30fps / half-D1@@25fps / D1@12.5fps
422          * 30 / 31 / 32         - D1@25fps / 720p@30fps / 720p@60fps
423          * 40 / 41 / 42         - 1080p@30fps / 1080p@30fps / 1080p@60fps
424          * 50 / 51 / 52         - 4K@30fps
425          */
426         mpp_enc_cfg_set_s32(cfg, "h264:level", 40);
427         mpp_enc_cfg_set_s32(cfg, "h264:cabac_en", 1);
428         mpp_enc_cfg_set_s32(cfg, "h264:cabac_idc", 0);
429         mpp_enc_cfg_set_s32(cfg, "h264:trans8x8", 1);
430     } break;
431     case MPP_VIDEO_CodingHEVC :
432     case MPP_VIDEO_CodingMJPEG :
433     case MPP_VIDEO_CodingVP8 : {
434     } break;
435     default : {
436         mpp_err_f("unsupport encoder coding type %d\n", p->type);
437     } break;
438     }
439 
440     p->split_mode = 0;
441     p->split_arg = 0;
442     p->split_out = 0;
443 
444     mpp_env_get_u32("split_mode", &p->split_mode, MPP_ENC_SPLIT_NONE);
445     mpp_env_get_u32("split_arg", &p->split_arg, 0);
446     mpp_env_get_u32("split_out", &p->split_out, 0);
447 
448     if (p->split_mode) {
449         mpp_log_q(quiet, "%p split mode %d arg %d out %d\n", ctx,
450                   p->split_mode, p->split_arg, p->split_out);
451         mpp_enc_cfg_set_s32(cfg, "split:mode", p->split_mode);
452         mpp_enc_cfg_set_s32(cfg, "split:arg", p->split_arg);
453         mpp_enc_cfg_set_s32(cfg, "split:out", p->split_out);
454     }
455 
456     // config gop_len and ref cfg
457     mpp_enc_cfg_set_s32(cfg, "rc:gop", p->gop_len ? p->gop_len : p->fps_out_num * 2);
458 
459     mpp_env_get_u32("gop_mode", &gop_mode, gop_mode);
460 
461     if (gop_mode) {
462         mpp_enc_ref_cfg_init(&ref);
463 
464         if (p->gop_mode < 4)
465             mpi_enc_gen_ref_cfg(ref, gop_mode);
466         else
467             mpi_enc_gen_smart_gop_ref_cfg(ref, p->gop_len, p->vi_len);
468 
469         mpp_enc_cfg_set_ptr(cfg, "rc:ref_cfg", ref);
470     }
471 
472     ret = mpi->control(ctx, MPP_ENC_SET_CFG, cfg);
473     if (ret) {
474         mpp_err("mpi control enc set cfg failed ret %d\n", ret);
475         goto RET;
476     }
477 
478     if (ref)
479         mpp_enc_ref_cfg_deinit(&ref);
480 
481     /* optional */
482     p->sei_mode = MPP_ENC_SEI_MODE_ONE_FRAME;
483     ret = mpi->control(ctx, MPP_ENC_SET_SEI_CFG, &p->sei_mode);
484     if (ret) {
485         mpp_err("mpi control enc set sei cfg failed ret %d\n", ret);
486         goto RET;
487     }
488 
489     if (p->type == MPP_VIDEO_CodingAVC || p->type == MPP_VIDEO_CodingHEVC) {
490         p->header_mode = MPP_ENC_HEADER_MODE_EACH_IDR;
491         ret = mpi->control(ctx, MPP_ENC_SET_HEADER_MODE, &p->header_mode);
492         if (ret) {
493             mpp_err("mpi control enc set header mode failed ret %d\n", ret);
494             goto RET;
495         }
496     }
497 
498     /* setup test mode by env */
499     mpp_env_get_u32("osd_enable", &p->osd_enable, 0);
500     mpp_env_get_u32("osd_mode", &p->osd_mode, MPP_ENC_OSD_PLT_TYPE_DEFAULT);
501     mpp_env_get_u32("roi_enable", &p->roi_enable, 0);
502     mpp_env_get_u32("user_data_enable", &p->user_data_enable, 0);
503 
504     if (p->roi_enable) {
505         mpp_enc_roi_init(&p->roi_ctx, p->width, p->height, p->type, 4);
506         mpp_assert(p->roi_ctx);
507     }
508 
509 RET:
510     return ret;
511 }
512 
mt_test_res_init(MpiEncMtCtxInfo * info)513 MPP_RET mt_test_res_init(MpiEncMtCtxInfo *info)
514 {
515     MpiEncTestArgs *cmd = info->cmd;
516     MpiEncMtTestData *p = &info->ctx;
517     MppPollType timeout = MPP_POLL_NON_BLOCK;
518     RK_U32 quiet = cmd->quiet;
519     MPP_RET ret = MPP_OK;
520     RK_S32 i;
521 
522     mpp_log_q(quiet, "%s start\n", info->name);
523 
524     p->list_buf = mpp_list_create(NULL);
525     if (NULL == p->list_buf) {
526         mpp_err_f("failed to get mpp buffer list\n");
527         return MPP_ERR_MALLOC;
528     }
529 
530     ret = mpp_buffer_group_get_internal(&p->buf_grp, MPP_BUFFER_TYPE_DRM);
531     if (ret) {
532         mpp_err_f("failed to get mpp buffer group ret %d\n", ret);
533         return ret;
534     }
535 
536     for (i = 0; i < BUF_COUNT; i++) {
537         ret = mpp_buffer_get(p->buf_grp, &p->frm_buf[i], p->frame_size + p->header_size);
538         if (ret) {
539             mpp_err_f("failed to get buffer for input frame ret %d\n", ret);
540             return ret;
541         }
542 
543         ret = mpp_buffer_get(p->buf_grp, &p->pkt_buf[i], p->frame_size);
544         if (ret) {
545             mpp_err_f("failed to get buffer for output packet ret %d\n", ret);
546             return ret;
547         }
548 
549         mpp_list_add_at_tail(p->list_buf, &p->frm_buf[i], sizeof(p->frm_buf[i]));
550     }
551 
552     // encoder demo
553     ret = mpp_create(&p->ctx, &p->mpi);
554     if (ret) {
555         mpp_err("mpp_create failed ret %d\n", ret);
556         return ret;
557     }
558 
559     mpp_log_q(quiet, "%p encoder test start w %d h %d type %d\n",
560               p->ctx, p->width, p->height, p->type);
561 
562     ret = p->mpi->control(p->ctx, MPP_SET_INPUT_TIMEOUT, &timeout);
563     if (ret) {
564         mpp_err("mpi control set input timeout %d ret %d\n", timeout, ret);
565         return ret;
566     }
567 
568     timeout = MPP_POLL_BLOCK;
569 
570     ret = p->mpi->control(p->ctx, MPP_SET_OUTPUT_TIMEOUT, &timeout);
571     if (ret) {
572         mpp_err("mpi control set output timeout %d ret %d\n", timeout, ret);
573         return ret;
574     }
575 
576     ret = mpp_init(p->ctx, MPP_CTX_ENC, p->type);
577     if (ret) {
578         mpp_err("mpp_init failed ret %d\n", ret);
579         return ret;
580     }
581 
582     ret = mpp_enc_cfg_init(&p->cfg);
583     if (ret) {
584         mpp_err_f("mpp_enc_cfg_init failed ret %d\n", ret);
585         return ret;
586     }
587 
588     ret = p->mpi->control(p->ctx, MPP_ENC_GET_CFG, p->cfg);
589     if (ret) {
590         mpp_err_f("get enc cfg failed ret %d\n", ret);
591         return ret;
592     }
593 
594     ret = test_mt_cfg_setup(info);
595     if (ret) {
596         mpp_err_f("test mpp setup failed ret %d\n", ret);
597     }
598 
599     return ret;
600 }
601 
mt_test_res_deinit(MpiEncMtCtxInfo * info)602 MPP_RET mt_test_res_deinit(MpiEncMtCtxInfo *info)
603 {
604     MpiEncMtTestData *p = &info->ctx;
605     MPP_RET ret = MPP_OK;
606     RK_S32 i;
607 
608     p->mpi->reset(p->ctx);
609     if (ret) {
610         mpp_err("mpi->reset failed\n");
611         return ret;
612     }
613 
614     if (p->ctx) {
615         mpp_destroy(p->ctx);
616         p->ctx = NULL;
617     }
618 
619     if (p->cfg) {
620         mpp_enc_cfg_deinit(p->cfg);
621         p->cfg = NULL;
622     }
623 
624     for (i = 0; i < BUF_COUNT; i++) {
625         if (p->frm_buf[i]) {
626             mpp_buffer_put(p->frm_buf[i]);
627             p->frm_buf[i] = NULL;
628         }
629 
630         if (p->pkt_buf[i]) {
631             mpp_buffer_put(p->pkt_buf[i]);
632             p->pkt_buf[i] = NULL;
633         }
634     }
635 
636     if (p->osd_data.buf) {
637         mpp_buffer_put(p->osd_data.buf);
638         p->osd_data.buf = NULL;
639     }
640 
641     if (p->buf_grp) {
642         mpp_buffer_group_put(p->buf_grp);
643         p->buf_grp = NULL;
644     }
645 
646     if (p->list_buf) {
647         mpp_list_destroy(p->list_buf);
648         p->list_buf = NULL;
649     }
650 
651     if (p->roi_ctx) {
652         mpp_enc_roi_deinit(p->roi_ctx);
653         p->roi_ctx = NULL;
654     }
655 
656     return MPP_OK;
657 }
658 
enc_test_input(void * arg)659 void *enc_test_input(void *arg)
660 {
661     MpiEncMtCtxInfo *info = (MpiEncMtCtxInfo *)arg;
662     MpiEncTestArgs *cmd = info->cmd;
663     MpiEncMtTestData *p = &info->ctx;
664     RK_S32 chn = info->chn;
665     MppApi *mpi = p->mpi;
666     MppCtx ctx = p->ctx;
667     MppList *list_buf = p->list_buf;
668     RK_U32 cap_num = 0;
669     RK_U32 quiet = cmd->quiet;
670     MPP_RET ret = MPP_OK;
671 
672     mpp_log_q(quiet, "%s start\n", info->name);
673 
674     while (1) {
675         MppMeta meta = NULL;
676         MppFrame frame = NULL;
677         MppBuffer buffer = NULL;
678         void *buf = NULL;
679         RK_S32 cam_frm_idx = -1;
680         MppBuffer cam_buf = NULL;
681 
682         mpp_mutex_cond_lock(&list_buf->cond_lock);
683         if (!mpp_list_size(list_buf))
684             mpp_list_wait(list_buf);
685 
686         buffer = NULL;
687         mpp_list_del_at_head(list_buf, &buffer, sizeof(buffer));
688         if (NULL == buffer) {
689             mpp_mutex_cond_unlock(&list_buf->cond_lock);
690             continue;
691         }
692 
693         buf = mpp_buffer_get_ptr(buffer);
694         mpp_mutex_cond_unlock(&list_buf->cond_lock);
695 
696         if (p->fp_input) {
697             ret = read_image((RK_U8 *)buf, p->fp_input, p->width, p->height,
698                              p->hor_stride, p->ver_stride, p->fmt);
699             if (ret == MPP_NOK || feof(p->fp_input)) {
700                 p->frm_eos = 1;
701 
702                 if (p->frame_num < 0 || p->frm_cnt_in < p->frame_num) {
703                     clearerr(p->fp_input);
704                     rewind(p->fp_input);
705                     p->frm_eos = 0;
706                     mpp_log_q(quiet, "chn %d loop times %d\n", chn, ++p->loop_times);
707                     if (buffer) {
708                         mpp_mutex_cond_lock(&list_buf->cond_lock);
709                         mpp_list_add_at_tail(list_buf, &buffer, sizeof(buffer));
710                         mpp_mutex_cond_unlock(&list_buf->cond_lock);
711                     }
712                     continue;
713                 }
714                 mpp_log_q(quiet, "chn %d found last frame. feof %d\n", chn, feof(p->fp_input));
715             } else if (ret == MPP_ERR_VALUE)
716                 break;
717         } else {
718             if (p->cam_ctx == NULL) {
719                 ret = fill_image((RK_U8 *)buf, p->width, p->height, p->hor_stride,
720                                  p->ver_stride, p->fmt, p->frm_cnt_in * p->frm_step);
721                 if (ret)
722                     break;
723             } else {
724                 cam_frm_idx = camera_source_get_frame(p->cam_ctx);
725                 mpp_assert(cam_frm_idx >= 0);
726 
727                 /* skip unstable frames */
728                 if (cap_num++ < 50) {
729                     camera_source_put_frame(p->cam_ctx, cam_frm_idx);
730                     continue;
731                 }
732 
733                 cam_buf = camera_frame_to_buf(p->cam_ctx, cam_frm_idx);
734                 mpp_assert(cam_buf);
735             }
736         }
737 
738         ret = mpp_frame_init(&frame);
739         if (ret) {
740             mpp_err_f("mpp_frame_init failed\n");
741             break;
742         }
743 
744         mpp_frame_set_width(frame, p->width);
745         mpp_frame_set_height(frame, p->height);
746         mpp_frame_set_hor_stride(frame, p->hor_stride);
747         mpp_frame_set_ver_stride(frame, p->ver_stride);
748         mpp_frame_set_fmt(frame, p->fmt);
749         mpp_frame_set_eos(frame, p->frm_eos);
750 
751         if (p->fp_input && feof(p->fp_input))
752             mpp_frame_set_buffer(frame, NULL);
753         else if (cam_buf)
754             mpp_frame_set_buffer(frame, cam_buf);
755         else
756             mpp_frame_set_buffer(frame, buffer);
757 
758         meta = mpp_frame_get_meta(frame);
759 
760         if (p->osd_enable || p->user_data_enable || p->roi_enable) {
761             if (p->user_data_enable) {
762                 MppEncUserData user_data;
763                 const char *str = "this is user data\n";
764 
765                 if ((p->frm_cnt_in & 10) == 0) {
766                     user_data.pdata = (void *)str;
767                     user_data.len = strlen(str) + 1;
768                     mpp_meta_set_ptr(meta, KEY_USER_DATA, &user_data);
769                 }
770                 static RK_U8 uuid_debug_info[16] = {
771                     0x57, 0x68, 0x97, 0x80, 0xe7, 0x0c, 0x4b, 0x65,
772                     0xa9, 0x06, 0xae, 0x29, 0x94, 0x11, 0xcd, 0x9a
773                 };
774 
775                 MppEncUserDataSet data_group;
776                 MppEncUserDataFull datas[2];
777                 const char *str1 = "this is user data 1\n";
778                 const char *str2 = "this is user data 2\n";
779                 data_group.count = 2;
780                 datas[0].len = strlen(str1) + 1;
781                 datas[0].pdata = (void *)str1;
782                 datas[0].uuid = uuid_debug_info;
783 
784                 datas[1].len = strlen(str2) + 1;
785                 datas[1].pdata = (void *)str2;
786                 datas[1].uuid = uuid_debug_info;
787 
788                 data_group.datas = datas;
789 
790                 mpp_meta_set_ptr(meta, KEY_USER_DATAS, &data_group);
791             }
792 
793             if (p->osd_enable) {
794                 /* gen and cfg osd plt */
795                 mpi_enc_gen_osd_plt(&p->osd_plt, p->frm_cnt_in);
796 
797                 p->osd_plt_cfg.change = MPP_ENC_OSD_PLT_CFG_CHANGE_ALL;
798                 p->osd_plt_cfg.type = MPP_ENC_OSD_PLT_TYPE_USERDEF;
799                 p->osd_plt_cfg.plt = &p->osd_plt;
800 
801                 ret = mpi->control(ctx, MPP_ENC_SET_OSD_PLT_CFG, &p->osd_plt_cfg);
802                 if (ret) {
803                     mpp_err("mpi control enc set osd plt failed ret %d\n", ret);
804                     break;
805                 }
806 
807                 /* gen and cfg osd plt */
808                 mpi_enc_gen_osd_data(&p->osd_data, p->buf_grp, p->width,
809                                      p->height, p->frm_cnt_in);
810                 mpp_meta_set_ptr(meta, KEY_OSD_DATA, (void*)&p->osd_data);
811             }
812 
813             if (p->roi_enable) {
814                 RoiRegionCfg *region = &p->roi_region;
815 
816                 /* calculated in pixels */
817                 region->x = MPP_ALIGN(p->width / 8, 16);
818                 region->y = MPP_ALIGN(p->height / 8, 16);
819                 region->w = 128;
820                 region->h = 256;
821                 region->force_intra = 0;
822                 region->qp_mode = 1;
823                 region->qp_val = 24;
824 
825                 mpp_enc_roi_add_region(p->roi_ctx, region);
826 
827                 region->x = MPP_ALIGN(p->width / 2, 16);
828                 region->y = MPP_ALIGN(p->height / 4, 16);
829                 region->w = 256;
830                 region->h = 128;
831                 region->force_intra = 1;
832                 region->qp_mode = 1;
833                 region->qp_val = 10;
834 
835                 mpp_enc_roi_add_region(p->roi_ctx, region);
836 
837                 /* send roi info by metadata */
838                 mpp_enc_roi_setup_meta(p->roi_ctx, meta);
839             }
840         }
841 
842         if (!p->first_frm)
843             p->first_frm = mpp_time();
844         /*
845          * NOTE: in non-block mode the frame can be resent.
846          * The default input timeout mode is block.
847          *
848          * User should release the input frame to meet the requirements of
849          * resource creator must be the resource destroyer.
850          */
851         p->frm_cnt_in++;
852         do {
853             ret = mpi->encode_put_frame(ctx, frame);
854             if (ret)
855                 msleep(1);
856         } while (ret);
857 
858         if (cam_frm_idx >= 0)
859             camera_source_put_frame(p->cam_ctx, cam_frm_idx);
860 
861         if (p->frame_num > 0 && p->frm_cnt_in >= p->frame_num) {
862             p->frm_eos = 1;
863             break;
864         }
865 
866         if (p->loop_end) {
867             p->frm_eos = 1;
868             break;
869         }
870 
871         if (p->frm_eos)
872             break;
873     }
874 
875     return NULL;
876 }
877 
enc_test_output(void * arg)878 void *enc_test_output(void *arg)
879 {
880     MpiEncMtCtxInfo *info = (MpiEncMtCtxInfo *)arg;
881     MpiEncTestArgs *cmd = info->cmd;
882     MpiEncMtTestData *p = &info->ctx;
883     MpiEncMtCtxRet *enc_ret = &info->ret;
884     MppList *list_buf = p->list_buf;
885     RK_S32 chn = info->chn;
886     MppApi *mpi = p->mpi;
887     MppCtx ctx = p->ctx;
888     RK_U32 quiet = cmd->quiet;
889     MPP_RET ret = MPP_OK;
890     MppPacket packet = NULL;
891     RK_U32 eoi = 1;
892 
893     void *ptr;
894     size_t len;
895     char log_buf[256];
896     RK_S32 log_size = sizeof(log_buf) - 1;
897     RK_S32 log_len = 0;
898 
899     while (1) {
900         ret = mpi->encode_get_packet(ctx, &packet);
901         if (ret || NULL == packet) {
902             msleep(1);
903             continue;
904         }
905 
906         p->last_pkt = mpp_time();
907 
908         // write packet to file here
909         ptr = mpp_packet_get_pos(packet);
910         len = mpp_packet_get_length(packet);
911         log_size = sizeof(log_buf) - 1;
912         log_len = 0;
913 
914         if (!p->first_pkt)
915             p->first_pkt = mpp_time();
916 
917         p->pkt_eos = mpp_packet_get_eos(packet);
918 
919         if (p->fp_output)
920             fwrite(ptr, 1, len, p->fp_output);
921 
922         log_len += snprintf(log_buf + log_len, log_size - log_len,
923                             "encoded frame %-4d", p->frm_cnt_out);
924 
925         /* for low delay partition encoding */
926         if (mpp_packet_is_partition(packet)) {
927             eoi = mpp_packet_is_eoi(packet);
928 
929             log_len += snprintf(log_buf + log_len, log_size - log_len,
930                                 " pkt %d", p->frm_pkt_cnt);
931             p->frm_pkt_cnt = (eoi) ? (0) : (p->frm_pkt_cnt + 1);
932         }
933 
934         log_len += snprintf(log_buf + log_len, log_size - log_len,
935                             " size %-7zu", len);
936 
937         if (mpp_packet_has_meta(packet)) {
938             MppMeta meta = mpp_packet_get_meta(packet);
939             MppFrame frm = NULL;
940             RK_S32 temporal_id = 0;
941             RK_S32 lt_idx = -1;
942             RK_S32 avg_qp = -1;
943 
944             if (MPP_OK == mpp_meta_get_s32(meta, KEY_TEMPORAL_ID, &temporal_id))
945                 log_len += snprintf(log_buf + log_len, log_size - log_len,
946                                     " tid %d", temporal_id);
947 
948             if (MPP_OK == mpp_meta_get_s32(meta, KEY_LONG_REF_IDX, &lt_idx))
949                 log_len += snprintf(log_buf + log_len, log_size - log_len,
950                                     " lt %d", lt_idx);
951 
952             if (MPP_OK == mpp_meta_get_s32(meta, KEY_ENC_AVERAGE_QP, &avg_qp))
953                 log_len += snprintf(log_buf + log_len, log_size - log_len,
954                                     " qp %d", avg_qp);
955 
956             if (MPP_OK == mpp_meta_get_frame(meta, KEY_INPUT_FRAME, &frm)) {
957                 MppBuffer frm_buf = NULL;
958 
959                 mpp_assert(frm);
960                 frm_buf = mpp_frame_get_buffer(frm);
961 
962                 if (frm_buf) {
963                     mpp_mutex_cond_lock(&list_buf->cond_lock);
964                     mpp_list_add_at_tail(list_buf, &frm_buf, sizeof(frm_buf));
965                     mpp_list_signal(list_buf);
966                     mpp_mutex_cond_unlock(&list_buf->cond_lock);
967                 }
968 
969                 mpp_frame_deinit(&frm);
970             }
971         }
972 
973         mpp_log_q(quiet, "chn %d %s\n", chn, log_buf);
974 
975         mpp_packet_deinit(&packet);
976         fps_calc_inc(cmd->fps);
977 
978         p->stream_size += len;
979         p->frm_cnt_out += eoi;
980 
981         if (p->frm_cnt_out != p->frm_cnt_in)
982             continue;
983 
984         if (p->frame_num > 0 && p->frm_cnt_out >= p->frame_num) {
985             p->pkt_eos = 1;
986             break;
987         }
988 
989         if (p->frm_eos) {
990             p->pkt_eos = 1;
991             break;
992         }
993 
994         if (p->pkt_eos) {
995             mpp_log_q(quiet, "chn %d found last packet\n", chn);
996             mpp_assert(p->frm_eos);
997             break;
998         }
999     } while (!eoi);
1000 
1001     enc_ret->elapsed_time = p->last_pkt - p->first_frm;
1002     enc_ret->frame_count = p->frm_cnt_out;
1003     enc_ret->stream_size = p->stream_size;
1004     enc_ret->frame_rate = (float)p->frm_cnt_out * 1000000 / enc_ret->elapsed_time;
1005     enc_ret->bit_rate = (p->stream_size * 8 * (p->fps_out_num / p->fps_out_den)) / p->frm_cnt_out;
1006     enc_ret->delay = p->first_pkt - p->first_frm;
1007 
1008     return NULL;
1009 }
1010 
enc_test_mt(MpiEncTestArgs * cmd,const char * name)1011 int enc_test_mt(MpiEncTestArgs* cmd, const char *name)
1012 {
1013     MpiEncMtCtxInfo *ctxs = NULL;
1014     float total_rate = 0.0;
1015     RK_S32 ret = MPP_NOK;
1016     RK_S32 i = 0;
1017 
1018     ctxs = mpp_calloc(MpiEncMtCtxInfo, cmd->nthreads);
1019     if (NULL == ctxs) {
1020         mpp_err("failed to alloc context for instances\n");
1021         return -1;
1022     }
1023 
1024     for (i = 0; i < cmd->nthreads; i++) {
1025         ctxs[i].cmd = cmd;
1026         ctxs[i].name = name;
1027         ctxs[i].chn = i;
1028 
1029         ret = mt_test_ctx_init(&ctxs[i]);
1030         if (ret) {
1031             mpp_err_f("test ctx init failed ret %d\n", ret);
1032             return ret;
1033         }
1034 
1035         ret = mt_test_res_init(&ctxs[i]);
1036         if (ret) {
1037             mpp_err_f("test resource deinit failed ret %d\n", ret);
1038             return ret;
1039         }
1040 
1041         ret = pthread_create(&ctxs[i].thd_out, NULL, enc_test_output, &ctxs[i]);
1042         if (ret) {
1043             mpp_err("failed to create thread %d\n", i);
1044             return ret;
1045         }
1046 
1047         ret = pthread_create(&ctxs[i].thd_in, NULL, enc_test_input, &ctxs[i]);
1048         if (ret) {
1049             mpp_err("failed to create thread %d\n", i);
1050             return ret;
1051         }
1052     }
1053 
1054 
1055     if (cmd->frame_num < 0) {
1056         // wait for input then quit encoding
1057         mpp_log("*******************************************\n");
1058         mpp_log("**** Press Enter to stop loop encoding ****\n");
1059         mpp_log("*******************************************\n");
1060 
1061         getc(stdin);
1062         mpp_log_f("loop_end start");
1063         for (i = 0; i < cmd->nthreads; i++)
1064             ctxs[i].ctx.loop_end = 1;
1065     }
1066 
1067     for (i = 0; i < cmd->nthreads; i++) {
1068         pthread_join(ctxs[i].thd_in, NULL);
1069         pthread_join(ctxs[i].thd_out, NULL);
1070 
1071         ret = mt_test_res_deinit(&ctxs[i]);
1072         if (ret) {
1073             mpp_err_f("test resource deinit failed ret %d\n", ret);
1074             return ret;
1075         }
1076 
1077         ret = mt_test_ctx_deinit(&ctxs[i]);
1078         if (ret) {
1079             mpp_err_f("test ctx deinit failed ret %d\n", ret);
1080             return ret;
1081         }
1082     }
1083 
1084     for (i = 0; i < cmd->nthreads; i++) {
1085         MpiEncMtCtxRet *enc_ret = &ctxs[i].ret;
1086 
1087         mpp_log("chn %d encode %d frames time %lld ms delay %3d ms fps %3.2f bps %lld\n",
1088                 i, enc_ret->frame_count, (RK_S64)(enc_ret->elapsed_time / 1000),
1089                 (RK_S32)(enc_ret->delay / 1000), enc_ret->frame_rate, enc_ret->bit_rate);
1090 
1091         total_rate += enc_ret->frame_rate;
1092     }
1093 
1094     MPP_FREE(ctxs);
1095 
1096     total_rate /= cmd->nthreads;
1097     mpp_log("%s average frame rate %.2f\n", name, total_rate);
1098 
1099     return ret;
1100 }
1101 
main(int argc,char ** argv)1102 int main(int argc, char **argv)
1103 {
1104     RK_S32 ret = MPP_NOK;
1105     MpiEncTestArgs* cmd = mpi_enc_test_cmd_get();
1106 
1107     // parse the cmd option
1108     ret = mpi_enc_test_cmd_update_by_args(cmd, argc, argv);
1109     if (ret)
1110         goto DONE;
1111 
1112     mpi_enc_test_cmd_show_opt(cmd);
1113 
1114     ret = enc_test_mt(cmd, argv[0]);
1115 
1116 DONE:
1117     mpi_enc_test_cmd_put(cmd);
1118 
1119     return ret;
1120 }
1121