xref: /aosp_15_r20/external/libopenapv/app/oapv_app_enc.c (revision abb65b4b03b69e1d508d4d9a44dcf199df16e7c3)
1 /*
2  * Copyright (c) 2022 Samsung Electronics Co., Ltd.
3  * All Rights Reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * - Redistributions of source code must retain the above copyright notice,
9  *   this list of conditions and the following disclaimer.
10  *
11  * - Redistributions in binary form must reproduce the above copyright notice,
12  *   this list of conditions and the following disclaimer in the documentation
13  *   and/or other materials provided with the distribution.
14  *
15  * - Neither the name of the copyright owner, nor the names of its contributors
16  *   may be used to endorse or promote products derived from this software
17  *   without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include "oapv.h"
33 #include "oapv_app_util.h"
34 #include "oapv_app_args.h"
35 #include "oapv_app_y4m.h"
36 
37 #define MAX_BS_BUF   (128 * 1024 * 1024)
38 #define MAX_NUM_FRMS (1)           // supports only 1-frame in an access unit
39 #define FRM_IDX      (0)           // supports only 1-frame in an access unit
40 #define MAX_NUM_CC   (OAPV_MAX_CC) // Max number of color componets (upto 4:4:4:4)
41 
42 typedef enum _STATES {
43     STATE_ENCODING,
44     STATE_SKIPPING,
45     STATE_STOP
46 } STATES;
47 
48 // clang-format off
49 
50 /* define various command line options as a table */
51 static const args_opt_t enc_args_opts[] = {
52     {
53         'v',  "verbose", ARGS_VAL_TYPE_INTEGER, 0, NULL,
54         "verbose (log) level\n"
55         "      - 0: no message\n"
56         "      - 1: only error message\n"
57         "      - 2: simple messages\n"
58         "      - 3: frame-level messages"
59     },
60     {
61         'i', "input", ARGS_VAL_TYPE_STRING | ARGS_VAL_TYPE_MANDATORY, 0, NULL,
62         "file name of input video"
63     },
64     {
65         'o', "output", ARGS_VAL_TYPE_STRING, 0, NULL,
66         "file name of output bitstream"
67     },
68     {
69         'r', "recon", ARGS_VAL_TYPE_STRING, 0, NULL,
70         "file name of reconstructed video"
71     },
72     {
73         'w',  "width", ARGS_VAL_TYPE_INTEGER | ARGS_VAL_TYPE_MANDATORY, 0, NULL,
74         "pixel width of input video"
75     },
76     {
77         'h',  "height", ARGS_VAL_TYPE_INTEGER | ARGS_VAL_TYPE_MANDATORY, 0, NULL,
78         "pixel height of input video"
79     },
80     {
81         'q',  "qp", ARGS_VAL_TYPE_INTEGER, 0, NULL,
82         "QP value (0~51)"
83     },
84     {
85         'z',  "fps", ARGS_VAL_TYPE_STRING | ARGS_VAL_TYPE_MANDATORY, 0, NULL,
86         "frame rate (frame per second))"
87     },
88     {
89         'm',  "threads", ARGS_VAL_TYPE_INTEGER, 0, NULL,
90         "force to use a specific number of threads"
91     },
92     {
93         ARGS_NO_KEY,  "preset", ARGS_VAL_TYPE_STRING, 0, NULL,
94         "encoder preset [fastest, fast, medium, slow, placebo]"
95     },
96     {
97         'd',  "input-depth", ARGS_VAL_TYPE_INTEGER, 0, NULL,
98         "input bit depth (8, 10) "
99     },
100     {
101         ARGS_NO_KEY,  "input-csp", ARGS_VAL_TYPE_INTEGER, 0, NULL,
102         "input color space (chroma format)\n"
103         "      - 0: YUV400\n"
104         "      - 1: YUV420\n"
105         "      - 2: YUV422\n"
106         "      - 3: YUV444\n"
107         "      - 4: YUV4444\n"
108         "      - 5: P2(Planar Y, Combined UV, 422)"
109     },
110     {
111         ARGS_NO_KEY,  "profile", ARGS_VAL_TYPE_STRING, 0, NULL,
112         "profile setting flag  (422-10)"
113     },
114     {
115         ARGS_NO_KEY,  "level", ARGS_VAL_TYPE_STRING, 0, NULL,
116         "level setting (1, 1.1, 2, 2.1, 3, 3.1, 4, 4.1, 5, 5.1, 6, 6.1, 7, 7.1)"
117     },
118     {
119         ARGS_NO_KEY,  "band", ARGS_VAL_TYPE_INTEGER, 0, NULL,
120         "band setting (0, 1, 2, 3)"
121     },
122     {
123         ARGS_NO_KEY,  "max-au", ARGS_VAL_TYPE_INTEGER, 0, NULL,
124         "maximum number of access units to be encoded"
125     },
126     {
127         ARGS_NO_KEY,  "seek", ARGS_VAL_TYPE_INTEGER, 0, NULL,
128         "number of skipped access units before encoding"
129     },
130     {
131         ARGS_NO_KEY,  "qp-cb-offset", ARGS_VAL_TYPE_INTEGER, 0, NULL,
132         "QP offset value for Cb"
133     },
134     {
135         ARGS_NO_KEY,  "qp-cr-offset", ARGS_VAL_TYPE_INTEGER, 0, NULL,
136         "QP offset value for Cr"
137     },
138     {
139         ARGS_NO_KEY,  "tile-w-mb", ARGS_VAL_TYPE_INTEGER, 0, NULL,
140         "width of tile in units of MBs"
141     },
142     {
143         ARGS_NO_KEY,  "tile-h-mb", ARGS_VAL_TYPE_INTEGER, 0, NULL,
144         "height of tile in units of MBs"
145     },
146     {
147         ARGS_NO_KEY,  "bitrate", ARGS_VAL_TYPE_STRING, 0, NULL,
148         "enable ABR rate control\n"
149         "      bitrate in terms of kilo-bits per second: Kbps(none,K,k), Mbps(M,m)\n"
150         "      ex) 100 = 100K = 0.1M"
151     },
152     {
153         ARGS_NO_KEY,  "use-filler", ARGS_VAL_TYPE_INTEGER, 0, NULL,
154         "user filler flag"
155     },
156     {
157         ARGS_NO_KEY,  "q-matrix-y", ARGS_VAL_TYPE_STRING, 0, NULL,
158         "custom quantization matrix for Y \"q1 q2 ... q63 q64\""
159     },
160     {
161         ARGS_NO_KEY,  "q-matrix-u", ARGS_VAL_TYPE_STRING, 0, NULL,
162         "custom quantization matrix for U \"q1 q2 ... q63 q64\""
163     },
164     {
165         ARGS_NO_KEY,  "q-matrix-v", ARGS_VAL_TYPE_STRING, 0, NULL,
166         "custom quantization matrix for V \"q1 q2 ... q63 q64\""
167     },
168     {
169         ARGS_NO_KEY,  "q-matrix-x", ARGS_VAL_TYPE_STRING, 0, NULL,
170         "custom quantization matrix for X \"q1 q2 ... q63 q64\""
171     },
172     {
173         ARGS_NO_KEY,  "hash", ARGS_VAL_TYPE_NONE, 0, NULL,
174         "embed frame hash value for conformance checking in decoding"
175     },
176     {ARGS_END_KEY, "", ARGS_VAL_TYPE_NONE, 0, NULL, ""} /* termination */
177 };
178 
179 // clang-format on
180 
181 #define NUM_ARGS_OPT ((int)(sizeof(enc_args_opts) / sizeof(enc_args_opts[0])))
182 
183 typedef struct args_var {
184     /* variables for options */
185     char           fname_inp[256];
186     char           fname_out[256];
187     char           fname_rec[256];
188     int            max_au;
189     int            hash;
190     int            input_depth;
191     int            input_csp;
192     int            seek;
193     int            threads;
194     char           profile[32];
195     char           level[32];
196     int            band;
197     char           bitrate[64];
198     char           fps[256];
199     char           q_matrix_y[512];
200     char           q_matrix_u[512];
201     char           q_matrix_v[512];
202     char           q_matrix_x[512];
203     char           preset[32];
204     oapve_param_t *param;
205 } args_var_t;
206 
args_init_vars(args_parser_t * args,oapve_param_t * param)207 static args_var_t *args_init_vars(args_parser_t *args, oapve_param_t *param)
208 {
209     args_opt_t *opts;
210     args_var_t *vars;
211 
212     opts = args->opts;
213     vars = malloc(sizeof(args_var_t));
214     assert_rv(vars != NULL, NULL);
215     memset(vars, 0, sizeof(args_var_t));
216 
217     vars->param = param;
218 
219     /*args_set_variable_by_key_long(opts, "config", args->fname_cfg);*/
220     args_set_variable_by_key_long(opts, "input", vars->fname_inp);
221     args_set_variable_by_key_long(opts, "output", vars->fname_out);
222     args_set_variable_by_key_long(opts, "recon", vars->fname_rec);
223     args_set_variable_by_key_long(opts, "max-au", &vars->max_au);
224     args_set_variable_by_key_long(opts, "hash", &vars->hash);
225     args_set_variable_by_key_long(opts, "verbose", &op_verbose);
226     op_verbose = VERBOSE_SIMPLE; /* default */
227     args_set_variable_by_key_long(opts, "input-depth", &vars->input_depth);
228     vars->input_depth = 10; /* default */
229     args_set_variable_by_key_long(opts, "input-csp", &vars->input_csp);
230     vars->input_csp = -1;
231     args_set_variable_by_key_long(opts, "seek", &vars->seek);
232     args_set_variable_by_key_long(opts, "profile", vars->profile);
233     strncpy(vars->profile, "422-10", sizeof(vars->profile) - 1);
234     args_set_variable_by_key_long(opts, "level", vars->level);
235     strncpy(vars->level, "4.1", sizeof(vars->level) - 1);
236     args_set_variable_by_key_long(opts, "band", &vars->band);
237     vars->band = 2; /* default */
238     args_set_variable_by_key_long(opts, "bitrate", vars->bitrate);
239     args_set_variable_by_key_long(opts, "fps", vars->fps);
240     strncpy(vars->fps, "60", sizeof(vars->fps) - 1);
241     args_set_variable_by_key_long(opts, "q-matrix-y", vars->q_matrix_y);
242     strncpy(vars->q_matrix_y, "", sizeof(vars->q_matrix_y) - 1);
243     args_set_variable_by_key_long(opts, "q-matrix-u", vars->q_matrix_u);
244     strncpy(vars->q_matrix_u, "", sizeof(vars->q_matrix_y) - 1);
245     args_set_variable_by_key_long(opts, "q-matrix-v", vars->q_matrix_v);
246     strncpy(vars->q_matrix_v, "", sizeof(vars->q_matrix_y) - 1);
247     args_set_variable_by_key_long(opts, "q-matrix-x", vars->q_matrix_x);
248     strncpy(vars->q_matrix_x, "", sizeof(vars->q_matrix_x) - 1);
249     args_set_variable_by_key_long(opts, "threads", &vars->threads);
250     vars->threads = 1; /* default */
251     args_set_variable_by_key_long(opts, "preset", vars->preset);
252     strncpy(vars->preset, "", sizeof(vars->preset) - 1);
253 
254     ARGS_SET_PARAM_VAR_KEY(opts, param, w);
255     ARGS_SET_PARAM_VAR_KEY(opts, param, h);
256     ARGS_SET_PARAM_VAR_KEY_LONG(opts, param, qp);
257     ARGS_SET_PARAM_VAR_KEY_LONG(opts, param, use_filler);
258     ARGS_SET_PARAM_VAR_KEY_LONG(opts, param, tile_w_mb);
259     ARGS_SET_PARAM_VAR_KEY_LONG(opts, param, tile_h_mb);
260     ARGS_SET_PARAM_VAR_KEY_LONG(opts, param, qp_cb_offset);
261     ARGS_SET_PARAM_VAR_KEY_LONG(opts, param, qp_cr_offset);
262 
263     return vars;
264 }
265 
print_usage(const char ** argv)266 static void print_usage(const char **argv)
267 {
268     int            i;
269     char           str[1024];
270     args_parser_t *args;
271     args_var_t    *args_var = NULL;
272     oapve_param_t  default_param;
273 
274     oapve_param_default(&default_param);
275     args = args_create(enc_args_opts, NUM_ARGS_OPT);
276     if(args == NULL)
277         goto ERR;
278     args_var = args_init_vars(args, &default_param);
279     if(args_var == NULL)
280         goto ERR;
281 
282     logv2("Syntax: \n");
283     logv2("  %s -i 'input-file' [ options ] \n\n", argv[0]);
284 
285     logv2("Options:\n");
286     logv2("  --help\n    : list options\n");
287     for(i = 0; i < args->num_option; i++) {
288         if(args->get_help(args, i, str) < 0)
289             return;
290         logv2("%s\n", str);
291     }
292 
293 ERR:
294     if(args)
295         args->release(args);
296     if(args_var)
297         free(args_var);
298 }
299 
check_conf(oapve_cdesc_t * cdesc,args_var_t * vars)300 static int check_conf(oapve_cdesc_t *cdesc, args_var_t *vars)
301 {
302     int i;
303     for(i = 0; i < cdesc->max_num_frms; i++) {
304         if(vars->hash && strlen(vars->fname_rec) == 0) {
305             logerr("cannot use frame hash without reconstructed picture option!\n");
306             return -1;
307         }
308     }
309     return 0;
310 }
311 
set_extra_config(oapve_t id,args_var_t * vars,oapve_param_t * param)312 static int set_extra_config(oapve_t id, args_var_t *vars, oapve_param_t *param)
313 {
314     int ret = 0, size, value;
315 
316     if(vars->hash) {
317         value = 1;
318         size = 4;
319         ret = oapve_config(id, OAPV_CFG_SET_USE_FRM_HASH, &value, &size);
320         if(OAPV_FAILED(ret)) {
321             logerr("failed to set config for using frame hash\n");
322             return -1;
323         }
324     }
325     return ret;
326 }
327 
print_commandline(int argc,const char ** argv)328 static void print_commandline(int argc, const char **argv)
329 {
330     int i;
331     if(op_verbose < VERBOSE_FRAME)
332         return;
333 
334     logv3("Command line: ");
335     for(i = 0; i < argc; i++) {
336         logv3("%s ", argv[i]);
337     }
338     logv3("\n\n");
339 }
340 
print_config(args_var_t * vars,oapve_param_t * param)341 static void print_config(args_var_t *vars, oapve_param_t *param)
342 {
343     if(op_verbose < VERBOSE_FRAME)
344         return;
345 
346     logv3_line("Configurations");
347     logv3("Input sequence : %s \n", vars->fname_inp);
348     if(strlen(vars->fname_out) > 0) {
349         logv3("Output bitstream : %s \n", vars->fname_out);
350     }
351     if(strlen(vars->fname_rec) > 0) {
352         logv3("Reconstructed sequence : %s \n", vars->fname_rec);
353     }
354     logv3("    profile             = %s\n", vars->profile);
355     logv3("    width               = %d\n", param->w);
356     logv3("    height              = %d\n", param->h);
357     logv3("    FPS                 = %.2f\n", (float)param->fps_num / param->fps_den);
358     logv3("    QP                  = %d\n", param->qp);
359     logv3("    max number of AUs   = %d\n", vars->max_au);
360     logv3("    rate control type   = %s\n", (param->rc_type == OAPV_RC_ABR) ? "average Bitrate" : "constant QP");
361     if(param->rc_type == OAPV_RC_ABR) {
362         logv3("    target bitrate      = %dkbps\n", param->bitrate);
363     }
364     logv3("    tile size           = %d x %d\n", param->tile_w_mb * OAPV_MB_W, param->tile_h_mb * OAPV_MB_H);
365 }
366 
print_stat_au(oapve_stat_t * stat,int au_cnt,oapve_param_t * param,int max_au,double bitrate_tot,oapv_clk_t clk_au,oapv_clk_t clk_tot)367 static void print_stat_au(oapve_stat_t *stat, int au_cnt, oapve_param_t *param, int max_au, double bitrate_tot, oapv_clk_t clk_au, oapv_clk_t clk_tot)
368 {
369     if(op_verbose >= VERBOSE_FRAME) {
370         logv3_line("");
371         logv3("AU %-5d  %10d-bytes  %3d-frame(s) %10d msec\n", au_cnt, stat->write, stat->aui.num_frms, oapv_clk_msec(clk_au));
372     }
373     else {
374         int total_time = ((int)oapv_clk_msec(clk_tot) / 1000);
375         int h = total_time / 3600;
376         total_time = total_time % 3600;
377         int m = total_time / 60;
378         total_time = total_time % 60;
379         int    s = total_time;
380         double curr_bitrate = bitrate_tot;
381         curr_bitrate *= (((float)param->fps_num / param->fps_den) * 8);
382         curr_bitrate /= (au_cnt + 1);
383         curr_bitrate /= 1000;
384         logv2("[ %d / %d AU(s) ] [ %.2f AU/sec ] [ %.4f kbps ] [ %2dh %2dm %2ds ] \r",
385               au_cnt, max_au, ((float)(au_cnt + 1) * 1000) / ((float)oapv_clk_msec(clk_tot)), curr_bitrate, h, m, s);
386         fflush(stdout);
387     }
388 }
389 
print_stat_frms(oapve_stat_t * stat,oapv_frms_t * ifrms,oapv_frms_t * rfrms,double psnr_avg[MAX_NUM_FRMS][MAX_NUM_CC])390 static void print_stat_frms(oapve_stat_t *stat, oapv_frms_t *ifrms, oapv_frms_t *rfrms, double psnr_avg[MAX_NUM_FRMS][MAX_NUM_CC])
391 {
392     int              i, j;
393     oapv_frm_info_t *finfo;
394     double           psnr[MAX_NUM_FRMS][MAX_NUM_CC] = { 0 };
395 
396     assert(stat->aui.num_frms == ifrms->num_frms);
397     assert(stat->aui.num_frms <= MAX_NUM_FRMS);
398 
399     // calculate PSNRs
400     if(rfrms != NULL) {
401         for(i = 0; i < stat->aui.num_frms; i++) {
402             if(rfrms->frm[i].imgb) {
403                 measure_psnr(ifrms->frm[i].imgb, rfrms->frm[i].imgb, psnr[i], OAPV_CS_GET_BIT_DEPTH(ifrms->frm[i].imgb->cs));
404                 for(j = 0; j < MAX_NUM_CC; j++) {
405                     psnr_avg[i][j] += psnr[i][j];
406                 }
407             }
408         }
409     }
410     // print verbose messages
411     if(op_verbose < VERBOSE_FRAME)
412         return;
413 
414     finfo = stat->aui.frm_info;
415 
416     for(i = 0; i < stat->aui.num_frms; i++) {
417         // clang-format off
418         const char* str_frm_type = finfo[i].pbu_type == OAPV_PBU_TYPE_PRIMARY_FRAME ? "PRIMARY"
419                                  : finfo[i].pbu_type == OAPV_PBU_TYPE_NON_PRIMARY_FRAME ? "NON-PRIMARY"
420                                  : finfo[i].pbu_type == OAPV_PBU_TYPE_PREVIEW_FRAME ? "PREVIEW"
421                                  : finfo[i].pbu_type == OAPV_PBU_TYPE_DEPTH_FRAME ? "DEPTH"
422                                  : finfo[i].pbu_type == OAPV_PBU_TYPE_ALPHA_FRAME ? "ALPHA"
423                                  : "UNKNOWN";
424         // clang-format on
425 
426         logv3("- FRM %-2d GID %-5d %-11s %9d-bytes %8.4fdB %8.4fdB %8.4fdB\n",
427               i, finfo[i].group_id, str_frm_type, stat->frm_size[i], psnr[i][0], psnr[i][1], psnr[i][2]);
428     }
429     fflush(stdout);
430     fflush(stderr);
431 }
432 
kbps_str_to_int(char * str)433 static int kbps_str_to_int(char *str)
434 {
435     int kbps;
436     if(strchr(str, 'K') || strchr(str, 'k')) {
437         char *tmp = strtok(str, "Kk ");
438         kbps = (int)(atof(tmp));
439     }
440     else if(strchr(str, 'M') || strchr(str, 'm')) {
441         char *tmp = strtok(str, "Mm ");
442         kbps = (int)(atof(tmp) * 1000);
443     }
444     else {
445         kbps = atoi(str);
446     }
447     return kbps;
448 }
449 
update_param(args_var_t * vars,oapve_param_t * param)450 static int update_param(args_var_t *vars, oapve_param_t *param)
451 {
452     /* update reate controller  parameters */
453     if(strlen(vars->bitrate) > 0) {
454         param->bitrate = kbps_str_to_int(vars->bitrate);
455         param->rc_type = OAPV_RC_ABR;
456     }
457 
458     /* update q_matrix */
459     int len_y = (int)strlen(vars->q_matrix_y);
460     if(len_y > 0) {
461         param->use_q_matrix = 1;
462         char *tmp = vars->q_matrix_y;
463         int   cnt = 0;
464         int   len_cnt = 0;
465         while(len_cnt < len_y && cnt < OAPV_BLK_D) {
466             sscanf(tmp, "%d", &param->q_matrix_y[cnt]);
467             if(param->q_matrix_y[cnt] < 1 || param->q_matrix_y[cnt] > 255) {
468                 logerr("input value of q_matrix_y is invalid\n");
469                 return -1;
470             }
471             len_cnt += (int)log10(param->q_matrix_y[cnt]) + 2;
472             tmp = vars->q_matrix_y + len_cnt;
473             cnt++;
474         }
475         if(cnt < OAPV_BLK_D) {
476             logerr("input number of q_matrix_y is not enough\n");
477             return -1;
478         }
479     }
480 
481     int len_u = (int)strlen(vars->q_matrix_u);
482     if(len_u > 0) {
483         param->use_q_matrix = 1;
484         char *tmp = vars->q_matrix_u;
485         int   cnt = 0;
486         int   len_cnt = 0;
487         while(len_cnt < len_u && cnt < OAPV_BLK_D) {
488             sscanf(tmp, "%d", &param->q_matrix_u[cnt]);
489             if(param->q_matrix_u[cnt] < 1 || param->q_matrix_u[cnt] > 255) {
490                 logerr("input value of q_matrix_u is invalid\n");
491                 return -1;
492             }
493             len_cnt += (int)log10(param->q_matrix_u[cnt]) + 2;
494             tmp = vars->q_matrix_u + len_cnt;
495             cnt++;
496         }
497         if(cnt < OAPV_BLK_D) {
498             logerr("input number of q_matrix_u is not enough\n");
499             return -1;
500         }
501     }
502 
503     int len_v = (int)strlen(vars->q_matrix_v);
504     if(len_v > 0) {
505         param->use_q_matrix = 1;
506         char *tmp = vars->q_matrix_v;
507         int   cnt = 0;
508         int   len_cnt = 0;
509         while(len_cnt < len_v && cnt < OAPV_BLK_D) {
510             sscanf(tmp, "%d", &param->q_matrix_v[cnt]);
511             if(param->q_matrix_v[cnt] < 1 || param->q_matrix_v[cnt] > 255) {
512                 logerr("input value of q_matrix_v is invalid\n");
513                 return -1;
514             }
515             len_cnt += (int)log10(param->q_matrix_v[cnt]) + 2;
516             tmp = vars->q_matrix_v + len_cnt;
517             cnt++;
518         }
519         if(cnt < OAPV_BLK_D) {
520             logerr("input number of q_matrix_v is not enough\n");
521             return -1;
522         }
523     }
524 
525     int len_x = (int)strlen(vars->q_matrix_x);
526     if (len_x > 0) {
527         param->use_q_matrix = 1;
528         char* tmp = vars->q_matrix_x;
529         int   cnt = 0;
530         int   len_cnt = 0;
531         while (len_cnt < len_x && cnt < OAPV_BLK_D) {
532             sscanf(tmp, "%d", &param->q_matrix_x[cnt]);
533             if (param->q_matrix_x[cnt] < 1 || param->q_matrix_x[cnt] > 255) {
534                 logerr("input value of q_matrix_x is invalid\n");
535                 return -1;
536             }
537             len_cnt += (int)log10(param->q_matrix_x[cnt]) + 2;
538             tmp = vars->q_matrix_x + len_cnt;
539             cnt++;
540         }
541         if (cnt < OAPV_BLK_D) {
542             logerr("input number of q_matrix_x is not enough\n");
543             return -1;
544         }
545     }
546 
547     if(param->use_q_matrix) {
548         if(len_y == 0) {
549             for(int i = 0; i < OAPV_BLK_D; i++) {
550                 param->q_matrix_y[i] = 16;
551             }
552         }
553 
554         if(len_u == 0) {
555             for(int i = 0; i < OAPV_BLK_D; i++) {
556                 param->q_matrix_u[i] = 16;
557             }
558         }
559 
560         if(len_v == 0) {
561             for(int i = 0; i < OAPV_BLK_D; i++) {
562                 param->q_matrix_v[i] = 16;
563             }
564         }
565 
566         if (len_x == 0) {
567             for (int i = 0; i < OAPV_BLK_D; i++) {
568                 param->q_matrix_x[i] = 16;
569             }
570         }
571     }
572 
573     param->csp = vars->input_csp;
574 
575     /* update level idc */
576     double tmp_level = 0;
577     sscanf(vars->level, "%lf", &tmp_level);
578     param->level_idc = tmp_level * 30;
579     /* update band idc */
580     param->band_idc = vars->band;
581 
582     /* update fps */
583     if(strpbrk(vars->fps, "/") != NULL) {
584         sscanf(vars->fps, "%d/%d", &param->fps_num, &param->fps_den);
585     }
586     else if(strpbrk(vars->fps, ".") != NULL) {
587         float tmp_fps = 0;
588         sscanf(vars->fps, "%f", &tmp_fps);
589         param->fps_num = tmp_fps * 10000;
590         param->fps_den = 10000;
591     }
592     else {
593         sscanf(vars->fps, "%d", &param->fps_num);
594         param->fps_den = 1;
595     }
596 
597     if(strlen(vars->preset) > 0) {
598         if(strcmp(vars->preset, "fastest") == 0) {
599             param->preset = OAPV_PRESET_FASTEST;
600         }
601         else if(strcmp(vars->preset, "fast") == 0) {
602             param->preset = OAPV_PRESET_FAST;
603         }
604         else if(strcmp(vars->preset, "medium") == 0) {
605             param->preset = OAPV_PRESET_MEDIUM;
606         }
607         else if(strcmp(vars->preset, "slow") == 0) {
608             param->preset = OAPV_PRESET_SLOW;
609         }
610         else if(strcmp(vars->preset, "placebo") == 0) {
611             param->preset = OAPV_PRESET_PLACEBO;
612         }
613         else {
614             logerr("input value of preset is invalid\n");
615             return -1;
616         }
617     }
618     else {
619         param->preset = OAPV_PRESET_DEFAULT;
620     }
621 
622     return 0;
623 }
624 
main(int argc,const char ** argv)625 int main(int argc, const char **argv)
626 {
627     args_parser_t *args = NULL;
628     args_var_t    *args_var = NULL;
629     STATES         state = STATE_ENCODING;
630     unsigned char *bs_buf = NULL;
631     FILE          *fp_inp = NULL;
632     oapve_t        id = NULL;
633     oapvm_t        mid = NULL;
634     oapve_cdesc_t  cdesc;
635     oapve_param_t *param = NULL;
636     oapv_bitb_t    bitb;
637     oapve_stat_t   stat;
638     oapv_imgb_t   *imgb_r = NULL; // image buffer for read
639     oapv_imgb_t   *imgb_w = NULL; // image buffer for write
640     oapv_imgb_t   *imgb_i = NULL; // image buffer for input
641     oapv_imgb_t   *imgb_o = NULL; // image buffer for output
642     oapv_frms_t    ifrms = { 0 }; // frames for input
643     oapv_frms_t    rfrms = { 0 }; // frames for reconstruction
644     int            ret;
645     oapv_clk_t     clk_beg, clk_end, clk_tot;
646     oapv_mtime_t   au_cnt, au_skip;
647     double         bitrate_tot; // total bitrate (byte)
648     double         psnr_avg[MAX_NUM_FRMS][MAX_NUM_CC] = { 0 };
649     int            is_y4m;
650     y4m_params_t   y4m;
651     int            is_out = 0, is_rec = 0;
652     char          *errstr = NULL;
653     int            cfmt;                      // color format
654     const int      num_frames = MAX_NUM_FRMS; // number of frames in an access unit
655 
656     /* help message */
657     if(argc < 2 || !strcmp(argv[1], "--help") || !strcmp(argv[1], "-h")) {
658         print_usage(argv);
659         return 0;
660     }
661 
662     /* set default parameters */
663     memset(&cdesc, 0, sizeof(oapve_cdesc_t));
664     param = &cdesc.param[FRM_IDX];
665     ret = oapve_param_default(param);
666     if(OAPV_FAILED(ret)) {
667         logerr("cannot set default parameter\n");
668         ret = -1;
669         goto ERR;
670     }
671     /* parse command line */
672     args = args_create(enc_args_opts, NUM_ARGS_OPT);
673     if(args == NULL) {
674         logerr("cannot create argument parser\n");
675         ret = -1;
676         goto ERR;
677     }
678     args_var = args_init_vars(args, param);
679     if(args_var == NULL) {
680         logerr("cannot initialize argument parser\n");
681         ret = -1;
682         goto ERR;
683     }
684     if(args->parse(args, argc, argv, &errstr)) {
685         logerr("command parsing error (%s)\n", errstr);
686         ret = -1;
687         goto ERR;
688     }
689     // print logo
690     logv2("  ____                ___   ___ _   __\n");
691     logv2(" / __ \\___  ___ ___  / _ | / _ \\ | / / Encoder\n");
692     logv2("/ /_/ / _ \\/ -_) _ \\/ __ |/ ___/ |/ / \n");
693     logv2("\\____/ .__/\\__/_//_/_/ |_/_/   |___/  \n");
694     logv2("    /_/                               \n");
695     logv2("\n");
696 
697     // print command line string for information
698     print_commandline(argc, argv);
699 
700     // check mandatory arguments
701     if(args->check_mandatory(args, &errstr)) {
702         logerr("'--%s' argument is mandatory\n", errstr);
703         ret = -1;
704         goto ERR;
705     }
706 
707     /* try to open input file */
708     fp_inp = fopen(args_var->fname_inp, "rb");
709     if(fp_inp == NULL) {
710         logerr("ERROR: cannot open input file = (%s)\n", args_var->fname_inp);
711         ret = -1;
712         goto ERR;
713     }
714 
715     /* y4m header parsing  */
716     is_y4m = y4m_test(fp_inp);
717     if(is_y4m) {
718         if(y4m_header_parser(fp_inp, &y4m)) {
719             logerr("This y4m is not supported (%s)\n", args_var->fname_inp);
720             ret = -1;
721             goto ERR;
722         }
723         y4m_update_param(args, &y4m);
724         cfmt = y4m.color_format;
725         // clang-format off
726         args_var->input_csp = (cfmt == OAPV_CF_YCBCR400 ? 0 : \
727             (cfmt == OAPV_CF_YCBCR420 ? 1 : \
728             (cfmt == OAPV_CF_YCBCR422 ? 2 : \
729             (cfmt == OAPV_CF_YCBCR444 ? 3 : \
730             (cfmt == OAPV_CF_YCBCR4444 ? 4 : \
731             (cfmt == OAPV_CF_PLANAR2 ? 5 : -1))))));
732         // clang-format on
733 
734         if(args_var->input_csp != -1) {
735             // force "input-csp" argument has set
736             args->set_flag(args, "input-csp", 1);
737         }
738     }
739     else {
740         // clang-format off
741         cfmt = (args_var->input_csp == 0 ? OAPV_CF_YCBCR400 : \
742             (args_var->input_csp == 1 ? OAPV_CF_YCBCR420 : \
743             (args_var->input_csp == 2 ? OAPV_CF_YCBCR422 : \
744             (args_var->input_csp == 3 ? OAPV_CF_YCBCR444  : \
745             (args_var->input_csp == 4 ? OAPV_CF_YCBCR4444 : \
746             (args_var->input_csp == 5 ? OAPV_CF_PLANAR2   : OAPV_CF_UNKNOWN))))));
747         // clang-format on
748     }
749     if(args_var->input_csp == -1) {
750         logerr("Unknown input color space. set '--input-csp' argument\n");
751         ret = -1;
752         goto ERR;
753     }
754 
755     /* update parameters */
756     if(update_param(args_var, param)) {
757         logerr("parameters is not proper\n");
758         ret = -1;
759         goto ERR;
760     }
761 
762     cdesc.max_bs_buf_size = MAX_BS_BUF; /* maximum bitstream buffer size */
763     cdesc.max_num_frms = MAX_NUM_FRMS;
764     cdesc.threads = args_var->threads;
765 
766     if(check_conf(&cdesc, args_var)) {
767         logerr("invalid configuration\n");
768         ret = -1;
769         goto ERR;
770     }
771 
772     if(strlen(args_var->fname_out) > 0) {
773         clear_data(args_var->fname_out);
774         is_out = 1;
775     }
776 
777     if(strlen(args_var->fname_rec) > 0) {
778         clear_data(args_var->fname_rec);
779         is_rec = 1;
780     }
781 
782     /* allocate bitstream buffer */
783     bs_buf = (unsigned char *)malloc(MAX_BS_BUF);
784     if(bs_buf == NULL) {
785         logerr("cannot allocate bitstream buffer, size=%d", MAX_BS_BUF);
786         ret = -1;
787         goto ERR;
788     }
789 
790     /* create encoder */
791     id = oapve_create(&cdesc, NULL);
792     if(id == NULL) {
793         logerr("cannot create OAPV encoder\n");
794         ret = -1;
795         goto ERR;
796     }
797 
798     /* create metadata handler */
799     mid = oapvm_create(&ret);
800     if(mid == NULL || OAPV_FAILED(ret)) {
801         logerr("cannot create OAPV metadata handler\n");
802         ret = -1;
803         goto ERR;
804     }
805 
806     if(set_extra_config(id, args_var, param)) {
807         logerr("cannot set extra configurations\n");
808         ret = -1;
809         goto ERR;
810     }
811 
812     print_config(args_var, param);
813 
814     bitrate_tot = 0;
815     bitb.addr = bs_buf;
816     bitb.bsize = MAX_BS_BUF;
817 
818     if(args_var->seek > 0) {
819         state = STATE_SKIPPING;
820     }
821 
822     clk_tot = 0;
823     au_cnt = 0;
824     au_skip = 0;
825 
826     // create input and reconstruction image buffers
827     memset(&ifrms, 0, sizeof(oapv_frm_t));
828     memset(&rfrms, 0, sizeof(oapv_frm_t));
829 
830     for(int i = 0; i < num_frames; i++) {
831         if(args_var->input_depth == 10) {
832             ifrms.frm[i].imgb = imgb_create(param->w, param->h, OAPV_CS_SET(cfmt, args_var->input_depth, 0));
833         }
834         else {
835             imgb_r = imgb_create(param->w, param->h, OAPV_CS_SET(cfmt, args_var->input_depth, 0));
836             ifrms.frm[i].imgb = imgb_create(param->w, param->h, OAPV_CS_SET(cfmt, 10, 0));
837         }
838 
839         if(is_rec) {
840             if(args_var->input_depth == 10) {
841                 rfrms.frm[i].imgb = imgb_create(param->w, param->h, OAPV_CS_SET(cfmt, args_var->input_depth, 0));
842             }
843             else {
844                 imgb_w = imgb_create(param->w, param->h, OAPV_CS_SET(cfmt, args_var->input_depth, 0));
845                 rfrms.frm[i].imgb = imgb_create(param->w, param->h, OAPV_CS_SET(cfmt, 10, 0));
846             }
847             rfrms.num_frms++;
848         }
849         ifrms.num_frms++;
850     }
851 
852     /* encode pictures *******************************************************/
853     while(args_var->max_au == 0 || (au_cnt < args_var->max_au)) {
854         for(int i = 0; i < num_frames; i++) {
855             if(args_var->input_depth == 10) {
856                 imgb_i = ifrms.frm[i].imgb;
857             }
858             else {
859                 imgb_i = imgb_r;
860             }
861             ret = imgb_read(fp_inp, imgb_i, param->w, param->h, is_y4m);
862             if(ret < 0) {
863                 logv3("reached out the end of input file\n");
864                 ret = OAPV_OK;
865                 state = STATE_STOP;
866                 break;
867             }
868             if(args_var->input_depth != 10) {
869                 imgb_cpy(ifrms.frm[i].imgb, imgb_i);
870             }
871             ifrms.frm[i].group_id = 1; // FIX-ME : need to set properly in case of multi-frame
872             ifrms.frm[i].pbu_type = OAPV_PBU_TYPE_PRIMARY_FRAME;
873         }
874 
875         if(state == STATE_ENCODING) {
876             /* encoding */
877             clk_beg = oapv_clk_get();
878 
879             ret = oapve_encode(id, &ifrms, mid, &bitb, &stat, &rfrms);
880 
881             clk_end = oapv_clk_from(clk_beg);
882             clk_tot += clk_end;
883 
884             bitrate_tot += stat.frm_size[FRM_IDX];
885 
886             print_stat_au(&stat, au_cnt, param, args_var->max_au, bitrate_tot, clk_end, clk_tot);
887 
888             for(int i = 0; i < num_frames; i++) {
889                 if(is_rec) {
890                     if(args_var->input_depth != 10) {
891                         imgb_cpy(imgb_w, rfrms.frm[i].imgb);
892                         imgb_o = imgb_w;
893                     }
894                     else {
895                         imgb_o = rfrms.frm[i].imgb;
896                     }
897                 }
898 
899                 /* store bitstream */
900                 if(OAPV_SUCCEEDED(ret)) {
901                     if(is_out && stat.write > 0) {
902                         if(write_data(args_var->fname_out, bs_buf, stat.write)) {
903                             logerr("cannot write bitstream\n");
904                             ret = -1;
905                             goto ERR;
906                         }
907                     }
908                 }
909                 else {
910                     logerr("failed to encode\n");
911                     ret = -1;
912                     goto ERR;
913                 }
914 
915                 // store recon image
916                 if(is_rec) {
917                     if(imgb_write(args_var->fname_rec, imgb_o)) {
918                         logerr("cannot write reconstruction image\n");
919                         ret = -1;
920                         goto ERR;
921                     }
922                 }
923 
924                 print_stat_frms(&stat, &ifrms, &rfrms, psnr_avg);
925                 au_cnt++;
926             }
927         }
928         else if(state == STATE_SKIPPING) {
929             if(au_skip < args_var->seek) {
930                 au_skip++;
931                 continue;
932             }
933             else {
934                 state = STATE_ENCODING;
935             }
936         }
937         else if(state == STATE_STOP) {
938             break;
939         }
940         oapvm_rem_all(mid);
941     }
942 
943     logv2_line("Summary");
944     psnr_avg[FRM_IDX][0] /= au_cnt;
945     psnr_avg[FRM_IDX][1] /= au_cnt;
946     psnr_avg[FRM_IDX][2] /= au_cnt;
947     if(cfmt == OAPV_CF_YCBCR4444) {
948         psnr_avg[FRM_IDX][3] /= au_cnt;
949     }
950 
951     logv3("  PSNR Y(dB)       : %-5.4f\n", psnr_avg[FRM_IDX][0]);
952     logv3("  PSNR U(dB)       : %-5.4f\n", psnr_avg[FRM_IDX][1]);
953     logv3("  PSNR V(dB)       : %-5.4f\n", psnr_avg[FRM_IDX][2]);
954     if(cfmt == OAPV_CF_YCBCR4444) {
955         logv3("  PSNR T(dB)       : %-5.4f\n", psnr_avg[FRM_IDX][3]);
956     }
957     logv3("  Total bits(bits) : %.0f\n", bitrate_tot * 8);
958     bitrate_tot *= (((float)param->fps_num / param->fps_den) * 8);
959     bitrate_tot /= au_cnt;
960     bitrate_tot /= 1000;
961 
962     logv3("  -----------------: bitrate(kbps)\tPSNR-Y\tPSNR-U\tPSNR-V\n");
963     if(cfmt == OAPV_CF_YCBCR4444) {
964         logv3("  Summary          : %-4.4f\t%-5.4f\t%-5.4f\t%-5.4f\t%-5.4f\n",
965               bitrate_tot, psnr_avg[FRM_IDX][0], psnr_avg[FRM_IDX][1], psnr_avg[FRM_IDX][2], psnr_avg[FRM_IDX][3]);
966     }
967     else {
968         logv3("  Summary          : %-5.4f\t%-5.4f\t%-5.4f\t%-5.4f\n",
969               bitrate_tot, psnr_avg[FRM_IDX][0], psnr_avg[FRM_IDX][1], psnr_avg[FRM_IDX][2]);
970     }
971 
972     logv2("Bitrate                           = %.4f kbps\n", bitrate_tot);
973     logv2("Encoded frame count               = %d\n", (int)au_cnt);
974     logv2("Total encoding time               = %.3f msec,",
975           (float)oapv_clk_msec(clk_tot));
976     logv2(" %.3f sec\n", (float)(oapv_clk_msec(clk_tot) / 1000.0));
977 
978     logv2("Average encoding time for a frame = %.3f msec\n",
979           (float)oapv_clk_msec(clk_tot) / au_cnt);
980     logv2("Average encoding speed            = %.3f frames/sec\n",
981           ((float)au_cnt * 1000) / ((float)oapv_clk_msec(clk_tot)));
982     logv2_line(NULL);
983 
984     if(args_var->max_au > 0 && au_cnt != args_var->max_au) {
985         logv3("Wrong frames count: should be %d was %d\n", args_var->max_au, (int)au_cnt);
986     }
987 ERR:
988 
989     if(imgb_r != NULL)
990         imgb_r->release(imgb_r);
991     if(imgb_w != NULL)
992         imgb_w->release(imgb_w);
993 
994     for(int i = 0; i < num_frames; i++) {
995         if(ifrms.frm[i].imgb != NULL) {
996             ifrms.frm[i].imgb->release(ifrms.frm[i].imgb);
997         }
998     }
999     for(int i = 0; i < num_frames; i++) {
1000         if(rfrms.frm[i].imgb != NULL) {
1001             rfrms.frm[i].imgb->release(rfrms.frm[i].imgb);
1002         }
1003     }
1004 
1005     if(id)
1006         oapve_delete(id);
1007     if(mid)
1008         oapvm_delete(mid);
1009     if(fp_inp)
1010         fclose(fp_inp);
1011     if(bs_buf)
1012         free(bs_buf); /* release bitstream buffer */
1013     if(args)
1014         args->release(args);
1015     if(args_var)
1016         free(args_var);
1017 
1018     return ret;
1019 }
1020