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 /* byte */
38
39 // check generic frame or not
40 #define IS_NON_AUX_FRM(frm) (((frm)->pbu_type == OAPV_PBU_TYPE_PRIMARY_FRAME) || ((frm)->pbu_type == OAPV_PBU_TYPE_NON_PRIMARY_FRAME))
41 // check auxiliary frame or not
42 #define IS_AUX_FRM(frm) (!(IS_NON_AUX_FRM(frm)))
43
44 #define OUTPUT_CSP_NATIVE (0)
45 #define OUTPUT_CSP_P210 (1)
46
47 // clang-format off
48
49 /* define various command line options as a table */
50 static const args_opt_t dec_args_opts[] = {
51 {
52 'v', "verbose", ARGS_VAL_TYPE_INTEGER, 0, NULL,
53 "verbose (log) level\n"
54 " - 0: no message\n"
55 " - 1: only error message\n"
56 " - 2: simple messages\n"
57 " - 3: frame-level messages"
58 },
59 {
60 'i', "input", ARGS_VAL_TYPE_STRING | ARGS_VAL_TYPE_MANDATORY, 0, NULL,
61 "file name of input bitstream"
62 },
63 {
64 'o', "output", ARGS_VAL_TYPE_STRING, 0, NULL,
65 "file name of decoded output"
66 },
67 {
68 ARGS_NO_KEY, "max-au", ARGS_VAL_TYPE_INTEGER, 0, NULL,
69 "maximum number of access units to be decoded"
70 },
71 {
72 'm', "threads", ARGS_VAL_TYPE_INTEGER, 0, NULL,
73 "force to use a specific number of threads"
74 },
75 {
76 'd', "output-depth", ARGS_VAL_TYPE_INTEGER, 0, NULL,
77 "output bit depth (8, 10) "
78 },
79 {
80 ARGS_NO_KEY, "hash", ARGS_VAL_TYPE_NONE, 0, NULL,
81 "parse frame hash value for conformance checking in decoding"
82 },
83 {
84 ARGS_NO_KEY, "output-csp", ARGS_VAL_TYPE_INTEGER, 0, NULL,
85 "output color space (chroma format)\n"
86 " - 0: coded CSP\n"
87 " - 1: convert to P210 in case of YCbCr422\n"
88 },
89 {ARGS_END_KEY, "", ARGS_VAL_TYPE_NONE, 0, NULL, ""} /* termination */
90 };
91
92 // clang-format on
93
94 #define NUM_ARGS_OPT ((int)(sizeof(dec_args_opts) / sizeof(dec_args_opts[0])))
95
96 typedef struct args_var {
97 char fname_inp[256];
98 char fname_out[256];
99 int max_au;
100 int hash;
101 int threads;
102 int output_depth;
103 int output_csp;
104 } args_var_t;
105
args_init_vars(args_parser_t * args)106 static args_var_t *args_init_vars(args_parser_t *args)
107 {
108 args_opt_t *opts;
109 args_var_t *vars;
110 opts = args->opts;
111 vars = malloc(sizeof(args_var_t));
112 assert_rv(vars != NULL, NULL);
113 memset(vars, 0, sizeof(args_var_t));
114
115 /*args_set_variable_by_key_long(opts, "config", args->fname_cfg);*/
116 args_set_variable_by_key_long(opts, "input", vars->fname_inp);
117 args_set_variable_by_key_long(opts, "output", vars->fname_out);
118 args_set_variable_by_key_long(opts, "max-au", &vars->max_au);
119 args_set_variable_by_key_long(opts, "hash", &vars->hash);
120 args_set_variable_by_key_long(opts, "verbose", &op_verbose);
121 op_verbose = VERBOSE_SIMPLE; /* default */
122 args_set_variable_by_key_long(opts, "threads", &vars->threads);
123 vars->threads = 1; /* default */
124 args_set_variable_by_key_long(opts, "output-depth", &vars->output_depth);
125 args_set_variable_by_key_long(opts, "output-csp", &vars->output_csp);
126 vars->output_csp = 0; /* default: coded CSP */
127
128 return vars;
129 }
130
print_usage(const char ** argv)131 static void print_usage(const char **argv)
132 {
133 int i;
134 char str[1024];
135 args_var_t *args_var = NULL;
136 args_parser_t *args;
137
138 args = args_create(dec_args_opts, NUM_ARGS_OPT);
139 if(args == NULL)
140 goto ERR;
141 args_var = args_init_vars(args);
142 if(args_var == NULL)
143 goto ERR;
144
145 logv2("Syntax: \n");
146 logv2(" %s -i 'input-file' [ options ] \n\n", argv[0]);
147
148 logv2("Options:\n");
149 logv2(" --help\n : list options\n");
150 for(i = 0; i < args->num_option; i++) {
151 if(args->get_help(args, i, str) < 0)
152 return;
153 logv2("%s\n", str);
154 }
155
156 ERR:
157 if(args)
158 args->release(args);
159 if(args_var)
160 free(args_var);
161 }
162
read_au_size(FILE * fp)163 static int read_au_size(FILE *fp)
164 {
165 unsigned char buf[4];
166
167 for(int i = 0; i < 4; i++) {
168 if(1 != fread(&buf[i], 1, 1, fp))
169 return -1;
170 }
171 return ((buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | (buf[3]));
172 }
173
read_bitstream(FILE * fp,unsigned char * bs_buf,int * bs_buf_size)174 static int read_bitstream(FILE *fp, unsigned char *bs_buf, int *bs_buf_size)
175 {
176 int au_size, read_size = 0;
177 unsigned char b = 0;
178 if(!fseek(fp, 0, SEEK_CUR)) {
179 /* read size first */
180 au_size = read_au_size(fp);
181 if(au_size > 0) {
182 while(au_size > 0) {
183 /* read byte */
184 if(1 != fread(&b, 1, 1, fp)) {
185 logerr("Cannot read bitstream!\n");
186 return -1;
187 }
188 bs_buf[read_size] = b;
189 read_size++;
190 au_size--;
191 }
192 *bs_buf_size = read_size;
193 }
194 else {
195 if(feof(fp)) {
196 logv2_line("");
197 logv2("End of file\n");
198 return 0;
199 }
200 else {
201 logerr("Cannot read bitstream size!\n")
202 return -1;
203 };
204 }
205 }
206 else {
207 logerr("Cannot seek bitstream!\n");
208 return -1;
209 }
210 return read_size + 4;
211 }
212
set_extra_config(oapvd_t id,args_var_t * args_vars)213 static int set_extra_config(oapvd_t id, args_var_t *args_vars)
214 {
215 int ret, size, value;
216
217 if(args_vars->hash) { // enable frame hash calculation
218 value = 1;
219 size = 4;
220 ret = oapvd_config(id, OAPV_CFG_SET_USE_FRM_HASH, &value, &size);
221 if(OAPV_FAILED(ret)) {
222 logerr("failed to set config for using frame hash\n");
223 return -1;
224 }
225 }
226 return 0;
227 }
228
write_dec_img(char * fname,oapv_imgb_t * img,int flag_y4m)229 static int write_dec_img(char *fname, oapv_imgb_t *img, int flag_y4m)
230 {
231 if(flag_y4m) {
232 if(write_y4m_frame_header(fname))
233 return -1;
234 }
235 if(imgb_write(fname, img))
236 return -1;
237 return 0;
238 }
239
check_frm_hash(oapvm_t mid,oapv_imgb_t * imgb,int group_id)240 static int check_frm_hash(oapvm_t mid, oapv_imgb_t *imgb, int group_id)
241 {
242 unsigned char uuid_frm_hash[16] = { 0xf8, 0x72, 0x1b, 0x3e, 0xcd, 0xee, 0x47, 0x21, 0x98, 0x0d, 0x9b, 0x9e, 0x39, 0x20, 0x28, 0x49 };
243 void *buf;
244 int size;
245 if(OAPV_SUCCEEDED(oapvm_get(mid, group_id, OAPV_METADATA_USER_DEFINED, &buf, &size, uuid_frm_hash))) {
246 if(size != (imgb->np * 16) /* hash */ + 16 /* uuid */) {
247 return 1; // unexpected error
248 }
249 for(int i = 0; i < imgb->np; i++) {
250 if(memcmp((unsigned char *)buf + ((i + 1) * 16), imgb->hash[i], 16) != 0) {
251 return -1; // frame hash is mismatched
252 }
253 }
254 return 0; // frame hash is correct
255 }
256 return 1; // frame hash data is not available
257 }
258
print_commandline(int argc,const char ** argv)259 static void print_commandline(int argc, const char **argv)
260 {
261 int i;
262 if(op_verbose < VERBOSE_FRAME)
263 return;
264
265 logv3("Command line: ");
266 for(i = 0; i < argc; i++) {
267 logv3("%s ", argv[i]);
268 }
269 logv3("\n\n");
270 }
271
print_stat_au(oapvd_stat_t * stat,int au_cnt,args_var_t * args_var,oapv_clk_t clk_au,oapv_clk_t clk_tot)272 static void print_stat_au(oapvd_stat_t *stat, int au_cnt, args_var_t *args_var, oapv_clk_t clk_au, oapv_clk_t clk_tot)
273 {
274 if(op_verbose >= VERBOSE_FRAME) {
275 if(au_cnt == 0) {
276 if(args_var->output_csp != OUTPUT_CSP_NATIVE && args_var->hash != 0) {
277 logv2("[Warning] cannot check frame hash value if special output CSP is defined\n")
278 }
279 }
280 logv3_line("");
281 logv3("AU %-5d %10d-bytes %3d-frame(s) %10d msec\n", au_cnt, stat->read, stat->aui.num_frms, oapv_clk_msec(clk_au));
282 }
283 else {
284 int total_time = ((int)oapv_clk_msec(clk_tot) / 1000);
285 int h = total_time / 3600;
286 total_time = total_time % 3600;
287 int m = total_time / 60;
288 total_time = total_time % 60;
289 int s = total_time;
290 logv2("[ %d AU(s) ] [ %.2f AU/sec ] [ %2dh %2dm %2ds ] \r",
291 au_cnt, ((float)(au_cnt + 1) * 1000) / ((float)oapv_clk_msec(clk_tot)), h, m, s);
292 fflush(stdout);
293 }
294 }
295
print_stat_frm(oapvd_stat_t * stat,oapv_frms_t * frms,oapvm_t mid,args_var_t * args_var)296 static void print_stat_frm(oapvd_stat_t *stat, oapv_frms_t *frms, oapvm_t mid, args_var_t *args_var)
297 {
298 oapv_frm_info_t *finfo;
299 int i, ret, hash_idx;
300
301 if(op_verbose < VERBOSE_FRAME)
302 return;
303
304 assert(stat->aui.num_frms == frms->num_frms);
305
306 finfo = stat->aui.frm_info;
307
308 for(i = 0; i < stat->aui.num_frms; i++) {
309 // clang-format off
310 const char* str_frm_type = finfo[i].pbu_type == OAPV_PBU_TYPE_PRIMARY_FRAME ? "PRIMARY"
311 : finfo[i].pbu_type == OAPV_PBU_TYPE_NON_PRIMARY_FRAME ? "NON-PRIMARY"
312 : finfo[i].pbu_type == OAPV_PBU_TYPE_PREVIEW_FRAME ? "PREVIEW"
313 : finfo[i].pbu_type == OAPV_PBU_TYPE_DEPTH_FRAME ? "DEPTH"
314 : finfo[i].pbu_type == OAPV_PBU_TYPE_ALPHA_FRAME ? "ALPHA"
315 : "UNKNOWN";
316
317 const char * str_csp = finfo[i].cs == OAPV_CS_YCBCR400_10LE ? "4:0:0-10"
318 : finfo[i].cs == OAPV_CS_YCBCR422_10LE ? "4:2:2-10"
319 : finfo[i].cs == OAPV_CS_YCBCR444_10LE ? "4:4:4-10"
320 : finfo[i].cs == OAPV_CS_YCBCR4444_10LE ? "4:4:4:4-10"
321 : "unknown-cs";
322
323 // clang-format on
324
325 logv2("- FRM %-2d GID %-5d %-11s %9d-bytes %5dx%4d %-10s",
326 i, finfo[i].group_id, str_frm_type, stat->frm_size[i], finfo[i].w, finfo[i].h, str_csp);
327
328 if(args_var->hash) {
329 char *str_hash[4] = { "unsupport", "mismatch", "unavail", "match" };
330
331 if(args_var->output_csp != OUTPUT_CSP_NATIVE) {
332 hash_idx = 0;
333 }
334 else {
335 ret = check_frm_hash(mid, frms->frm[i].imgb, frms->frm[i].group_id);
336 if(ret < 0)
337 hash_idx = 1; // mismatch
338 else if(ret > 0)
339 hash_idx = 2; // unavailable
340 else
341 hash_idx = 3; // matched
342 }
343 logv2("hash:%s", str_hash[hash_idx]);
344 }
345 logv2("\n");
346 }
347 }
348
main(int argc,const char ** argv)349 int main(int argc, const char **argv)
350 {
351 args_parser_t *args;
352 args_var_t *args_var = NULL;
353 unsigned char *bs_buf = NULL;
354 oapvd_t did = NULL;
355 oapvm_t mid = NULL;
356 oapvd_cdesc_t cdesc;
357 oapv_bitb_t bitb;
358 oapv_frms_t ofrms;
359 oapv_imgb_t *imgb_w = NULL;
360 oapv_imgb_t *imgb_o = NULL;
361 oapv_frm_t *frm = NULL;
362 oapv_au_info_t aui;
363 oapvd_stat_t stat;
364 int i, ret = 0;
365 oapv_clk_t clk_beg, clk_end, clk_tot;
366 int au_cnt, frm_cnt[OAPV_MAX_NUM_FRAMES];
367 int read_size, bs_buf_size = 0;
368 FILE *fp_bs = NULL;
369 int is_y4m = 0;
370 char *errstr = NULL;
371 oapv_frm_info_t *finfo = NULL;
372
373 memset(frm_cnt, 0, sizeof(int) * OAPV_MAX_NUM_FRAMES);
374 memset(&aui, 0, sizeof(oapv_au_info_t));
375 memset(&ofrms, 0, sizeof(oapv_frms_t));
376
377 /* help message */
378 if(argc < 2 || !strcmp(argv[1], "--help") || !strcmp(argv[1], "-h")) {
379 print_usage(argv);
380 return 0;
381 }
382 /* parse command line */
383 args = args_create(dec_args_opts, NUM_ARGS_OPT);
384 if(args == NULL) {
385 logerr("cannot create argument parser\n");
386 ret = -1;
387 goto ERR;
388 }
389 args_var = args_init_vars(args);
390 if(args_var == NULL) {
391 logerr("cannot initialize argument parser\n");
392 ret = -1;
393 goto ERR;
394 }
395 if(args->parse(args, argc, argv, &errstr)) {
396 logerr("command parsing error (%s)\n", errstr);
397 ret = -1;
398 goto ERR;
399 }
400 // print logo
401 logv2(" ____ ___ ___ _ __\n");
402 logv2(" / __ \\___ ___ ___ / _ | / _ \\ | / / Decoder\n");
403 logv2("/ /_/ / _ \\/ -_) _ \\/ __ |/ ___/ |/ / \n");
404 logv2("\\____/ .__/\\__/_//_/_/ |_/_/ |___/ \n");
405 logv2(" /_/ \n");
406 logv2("\n");
407
408 // print command line string for information
409 print_commandline(argc, argv);
410
411 if(args->check_mandatory(args, &errstr)) {
412 logerr("'--%s' argument is mandatory\n", errstr);
413 ret = -1;
414 goto ERR;
415 }
416
417 /* open input file */
418 fp_bs = fopen(args_var->fname_inp, "rb");
419 if(fp_bs == NULL) {
420 logerr("ERROR: cannot open bitstream file = %s\n", args_var->fname_inp);
421 print_usage(argv);
422 return -1;
423 }
424 /* open output file */
425 if(strlen(args_var->fname_out) > 0) {
426 char fext[16];
427 char *fname = (char *)args_var->fname_out;
428
429 if(strlen(fname) < 5) { /* at least x.yuv or x.y4m */
430 logerr("ERROR: invalide output file name\n");
431 return -1;
432 }
433 strncpy(fext, fname + strlen(fname) - 3, sizeof(fext) - 1);
434 fext[0] = toupper(fext[0]);
435 fext[1] = toupper(fext[1]);
436 fext[2] = toupper(fext[2]);
437
438 if(strcmp(fext, "YUV") == 0) {
439 is_y4m = 0;
440 }
441 else if(strcmp(fext, "Y4M") == 0) {
442 is_y4m = 1;
443 }
444 else {
445 logerr("ERROR: unknown output format\n");
446 ret = -1;
447 goto ERR;
448 }
449 clear_data(fname); /* remove decoded file contents if exists */
450 }
451
452 // create bitstream buffer
453 bs_buf = malloc(MAX_BS_BUF);
454 if(bs_buf == NULL) {
455 logerr("ERROR: cannot allocate bitstream buffer, size=%d\n", MAX_BS_BUF);
456 ret = -1;
457 goto ERR;
458 }
459 // create decoder
460 cdesc.threads = args_var->threads;
461 did = oapvd_create(&cdesc, &ret);
462 if(did == NULL) {
463 logerr("ERROR: cannot create OAPV decoder (err=%d)\n", ret);
464 ret = -1;
465 goto ERR;
466 }
467 if(set_extra_config(did, args_var)) {
468 logerr("ERROR: cannot set extra configurations\n");
469 ret = -1;
470 goto ERR;
471 }
472
473 clk_tot = 0;
474 au_cnt = 0;
475
476 /* create metadata container */
477 mid = oapvm_create(&ret);
478 if(OAPV_FAILED(ret)) {
479 logerr("ERROR: cannot create OAPV metadata container (err=%d)\n", ret);
480 ret = -1;
481 goto ERR;
482 }
483
484 /* decoding loop */
485 while(args_var->max_au == 0 || (au_cnt < args_var->max_au)) {
486 read_size = read_bitstream(fp_bs, bs_buf, &bs_buf_size);
487 if (read_size == 0) {
488 logv3("--> end of bitstream\n")
489 break;
490 }
491 if (read_size < 0) {
492 logv3("--> bitstream reading error\n")
493 ret = -1;
494 goto ERR;
495 }
496
497 if(OAPV_FAILED(oapvd_info(bs_buf, bs_buf_size, &aui))) {
498 logerr("cannot get information from bitstream\n");
499 ret = -1;
500 goto ERR;
501 }
502
503 /* create decoding frame buffers */
504 ofrms.num_frms = aui.num_frms;
505 for(i = 0; i < ofrms.num_frms; i++) {
506 finfo = &aui.frm_info[i];
507 frm = &ofrms.frm[i];
508
509 if(frm->imgb != NULL && (frm->imgb->w[0] != finfo->w || frm->imgb->h[0] != finfo->h)) {
510 frm->imgb->release(frm->imgb);
511 frm->imgb = NULL;
512 }
513
514 if(frm->imgb == NULL) {
515 if(args_var->output_csp == 1) {
516 frm->imgb = imgb_create(finfo->w, finfo->h, OAPV_CS_SET(OAPV_CF_PLANAR2, 10, 0));
517 }
518 else {
519 frm->imgb = imgb_create(finfo->w, finfo->h, finfo->cs);
520 }
521 if(frm->imgb == NULL) {
522 logerr("cannot allocate image buffer (w:%d, h:%d, cs:%d)\n",
523 finfo->w, finfo->h, finfo->cs);
524 ret = -1;
525 goto ERR;
526 }
527 }
528 }
529
530 if(args_var->output_depth == 0) {
531 args_var->output_depth = OAPV_CS_GET_BIT_DEPTH(finfo->cs);
532 }
533
534 /* main decoding block */
535 bitb.addr = bs_buf;
536 bitb.ssize = bs_buf_size;
537 memset(&stat, 0, sizeof(oapvd_stat_t));
538
539 clk_beg = oapv_clk_get();
540
541 ret = oapvd_decode(did, &bitb, &ofrms, mid, &stat);
542
543 clk_end = oapv_clk_from(clk_beg);
544 clk_tot += clk_end;
545
546 if(OAPV_FAILED(ret)) {
547 logerr("failed to decode bitstream\n");
548 ret = -1;
549 goto END;
550 }
551 if(stat.read != bs_buf_size) {
552 logerr("\t=> different reading of bitstream (in:%d, read:%d)\n",
553 bs_buf_size, stat.read);
554 continue;
555 }
556
557 /* testing of metadata reading */
558 if(mid) {
559 oapvm_payload_t *pld = NULL; // metadata payload
560 int num_plds = 0; // number of metadata payload
561
562 ret = oapvm_get_all(mid, NULL, &num_plds);
563
564 if(OAPV_FAILED(ret)) {
565 logerr("failed to read metadata\n");
566 goto END;
567 }
568 if(num_plds > 0) {
569 pld = malloc(sizeof(oapvm_payload_t) * num_plds);
570 ret = oapvm_get_all(mid, pld, &num_plds);
571 if(OAPV_FAILED(ret)) {
572 logerr("failed to read metadata\n");
573 free(pld);
574 goto END;
575 }
576 }
577 if(pld != NULL)
578 free(pld);
579 }
580
581 /* print decoding results */
582 print_stat_au(&stat, au_cnt, args_var, clk_end, clk_tot);
583 print_stat_frm(&stat, &ofrms, mid, args_var);
584
585 /* write decoded frames into files */
586 for(i = 0; i < ofrms.num_frms; i++) {
587 frm = &ofrms.frm[i];
588 if(ofrms.num_frms > 0) {
589 if(OAPV_CS_GET_BIT_DEPTH(frm->imgb->cs) != args_var->output_depth) {
590 if(imgb_w == NULL) {
591 imgb_w = imgb_create(frm->imgb->w[0], frm->imgb->h[0],
592 OAPV_CS_SET(OAPV_CS_GET_FORMAT(frm->imgb->cs), args_var->output_depth, 0));
593 if(imgb_w == NULL) {
594 logerr("cannot allocate image buffer (w:%d, h:%d, cs:%d)\n",
595 frm->imgb->w[0], frm->imgb->h[0], frm->imgb->cs);
596 ret = -1;
597 goto ERR;
598 }
599 }
600 imgb_cpy(imgb_w, frm->imgb);
601 imgb_o = imgb_w;
602 }
603 else {
604 imgb_o = frm->imgb;
605 }
606
607 if(strlen(args_var->fname_out)) {
608 if(frm_cnt[i] == 0 && is_y4m) {
609 if(write_y4m_header(args_var->fname_out, imgb_o)) {
610 logerr("cannot write Y4M header\n");
611 ret = -1;
612 goto END;
613 }
614 }
615 write_dec_img(args_var->fname_out, imgb_o, is_y4m);
616 }
617 frm_cnt[i]++;
618 }
619 }
620 au_cnt++;
621 oapvm_rem_all(mid); // remove all metadata for next au decoding
622 fflush(stdout);
623 fflush(stderr);
624 }
625
626 END:
627 logv2_line("Summary");
628 logv2("Processed access units = %d\n", au_cnt);
629 int total_frame_count = 0;
630 for(i = 0; i < OAPV_MAX_NUM_FRAMES; i++)
631 total_frame_count += frm_cnt[i];
632 logv2("Decoded frame count = %d\n", total_frame_count);
633 if(total_frame_count > 0) {
634 logv2("Total decoding time = %d msec,", (int)oapv_clk_msec(clk_tot));
635 logv2(" %.3f sec\n", (float)(oapv_clk_msec(clk_tot) / 1000.0));
636 logv2("Average decoding time for a frame = %d msec\n", (int)oapv_clk_msec(clk_tot) / total_frame_count);
637 logv2("Average decoding speed = %.3f frames/sec\n", ((float)total_frame_count * 1000) / ((float)oapv_clk_msec(clk_tot)));
638 }
639 logv2_line(NULL);
640
641 ERR:
642 if(did)
643 oapvd_delete(did);
644
645 if(mid)
646 oapvm_delete(mid);
647
648 for(int i = 0; i < ofrms.num_frms; i++) {
649 if(ofrms.frm[i].imgb != NULL) {
650 ofrms.frm[i].imgb->release(ofrms.frm[i].imgb);
651 }
652 }
653 if(imgb_w != NULL)
654 imgb_w->release(imgb_w);
655 if(fp_bs)
656 fclose(fp_bs);
657 if(bs_buf)
658 free(bs_buf);
659 if(args)
660 args->release(args);
661 if(args_var)
662 free(args_var);
663 return ret;
664 }
665