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", ¶m->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", ¶m->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", ¶m->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", ¶m->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", ¶m->fps_num, ¶m->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", ¶m->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