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