inspect.c (33580B)
1 /* 2 * Copyright (c) 2016, Alliance for Open Media. All rights reserved. 3 * 4 * This source code is subject to the terms of the BSD 2 Clause License and 5 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License 6 * was not distributed with this source code in the LICENSE file, you can 7 * obtain it at www.aomedia.org/license/software. If the Alliance for Open 8 * Media Patent License 1.0 was not distributed with this source code in the 9 * PATENTS file, you can obtain it at www.aomedia.org/license/patent. 10 */ 11 12 // Inspect Decoder 13 // ================ 14 // 15 // This is a simple decoder loop that writes JSON stats to stdout. This tool 16 // can also be compiled with Emscripten and used as a library. 17 18 #include <stdio.h> 19 #include <stdlib.h> 20 #include <string.h> 21 22 #ifdef __EMSCRIPTEN__ 23 #include <emscripten.h> 24 #else 25 #define EMSCRIPTEN_KEEPALIVE 26 #endif 27 28 #include "config/aom_config.h" 29 30 #include "aom/aom_decoder.h" 31 #include "aom/aomdx.h" 32 #include "av1/common/av1_common_int.h" 33 34 #if CONFIG_ACCOUNTING 35 #include "av1/decoder/accounting.h" 36 #endif 37 38 #include "av1/decoder/inspection.h" 39 #include "common/args.h" 40 #include "common/tools_common.h" 41 #include "common/video_common.h" 42 #include "common/video_reader.h" 43 44 // Max JSON buffer size. 45 const int MAX_BUFFER = 1024 * 1024 * 256; 46 47 typedef enum { 48 ACCOUNTING_LAYER = 1, 49 BLOCK_SIZE_LAYER = 1 << 1, 50 TRANSFORM_SIZE_LAYER = 1 << 2, 51 TRANSFORM_TYPE_LAYER = 1 << 3, 52 MODE_LAYER = 1 << 4, 53 SKIP_LAYER = 1 << 5, 54 FILTER_LAYER = 1 << 6, 55 CDEF_LAYER = 1 << 7, 56 REFERENCE_FRAME_LAYER = 1 << 8, 57 MOTION_VECTORS_LAYER = 1 << 9, 58 UV_MODE_LAYER = 1 << 10, 59 CFL_LAYER = 1 << 11, 60 DUAL_FILTER_LAYER = 1 << 12, 61 Q_INDEX_LAYER = 1 << 13, 62 SEGMENT_ID_LAYER = 1 << 14, 63 MOTION_MODE_LAYER = 1 << 15, 64 COMPOUND_TYPE_LAYER = 1 << 16, 65 INTRABC_LAYER = 1 << 17, 66 PALETTE_LAYER = 1 << 18, 67 UV_PALETTE_LAYER = 1 << 19, 68 ALL_LAYERS = (1 << 20) - 1 69 } LayerType; 70 71 static LayerType layers = 0; 72 73 static int stop_after = 0; 74 static int compress = 0; 75 76 static const arg_def_t limit_arg = 77 ARG_DEF(NULL, "limit", 1, "Stop decoding after n frames"); 78 static const arg_def_t dump_all_arg = ARG_DEF("A", "all", 0, "Dump All"); 79 static const arg_def_t compress_arg = 80 ARG_DEF("x", "compress", 0, "Compress JSON using RLE"); 81 static const arg_def_t dump_accounting_arg = 82 ARG_DEF("a", "accounting", 0, "Dump Accounting"); 83 static const arg_def_t dump_block_size_arg = 84 ARG_DEF("bs", "blockSize", 0, "Dump Block Size"); 85 static const arg_def_t dump_motion_vectors_arg = 86 ARG_DEF("mv", "motionVectors", 0, "Dump Motion Vectors"); 87 static const arg_def_t dump_transform_size_arg = 88 ARG_DEF("ts", "transformSize", 0, "Dump Transform Size"); 89 static const arg_def_t dump_transform_type_arg = 90 ARG_DEF("tt", "transformType", 0, "Dump Transform Type"); 91 static const arg_def_t dump_mode_arg = ARG_DEF("m", "mode", 0, "Dump Mode"); 92 static const arg_def_t dump_motion_mode_arg = 93 ARG_DEF("mm", "motion_mode", 0, "Dump Motion Modes"); 94 static const arg_def_t dump_compound_type_arg = 95 ARG_DEF("ct", "compound_type", 0, "Dump Compound Types"); 96 static const arg_def_t dump_uv_mode_arg = 97 ARG_DEF("uvm", "uv_mode", 0, "Dump UV Intra Prediction Modes"); 98 static const arg_def_t dump_skip_arg = ARG_DEF("s", "skip", 0, "Dump Skip"); 99 static const arg_def_t dump_filter_arg = 100 ARG_DEF("f", "filter", 0, "Dump Filter"); 101 static const arg_def_t dump_cdef_arg = ARG_DEF("c", "cdef", 0, "Dump CDEF"); 102 static const arg_def_t dump_cfl_arg = 103 ARG_DEF("cfl", "chroma_from_luma", 0, "Dump Chroma from Luma Alphas"); 104 static const arg_def_t dump_dual_filter_type_arg = 105 ARG_DEF("df", "dualFilterType", 0, "Dump Dual Filter Type"); 106 static const arg_def_t dump_reference_frame_arg = 107 ARG_DEF("r", "referenceFrame", 0, "Dump Reference Frame"); 108 static const arg_def_t dump_delta_q_arg = 109 ARG_DEF("dq", "delta_q", 0, "Dump QIndex"); 110 static const arg_def_t dump_seg_id_arg = 111 ARG_DEF("si", "seg_id", 0, "Dump Segment ID"); 112 static const arg_def_t dump_intrabc_arg = 113 ARG_DEF("ibc", "intrabc", 0, "Dump If IntraBC Is Used"); 114 static const arg_def_t dump_palette_arg = 115 ARG_DEF("plt", "palette", 0, "Dump Palette Size"); 116 static const arg_def_t dump_uv_palette_arg = 117 ARG_DEF("uvp", "uv_palette", 0, "Dump UV Palette Size"); 118 static const arg_def_t usage_arg = ARG_DEF("h", "help", 0, "Help"); 119 static const arg_def_t skip_non_transform_arg = ARG_DEF( 120 "snt", "skip_non_transform", 1, "Skip is counted as a non transform."); 121 static const arg_def_t combined_arg = 122 ARG_DEF("comb", "combined", 1, "combinining parameters into one output."); 123 124 int combined_parm_list[15]; 125 int combined_parm_count = 0; 126 127 static const arg_def_t *main_args[] = { &limit_arg, 128 &dump_all_arg, 129 &compress_arg, 130 #if CONFIG_ACCOUNTING 131 &dump_accounting_arg, 132 #endif 133 &dump_block_size_arg, 134 &dump_transform_size_arg, 135 &dump_transform_type_arg, 136 &dump_mode_arg, 137 &dump_uv_mode_arg, 138 &dump_motion_mode_arg, 139 &dump_compound_type_arg, 140 &dump_skip_arg, 141 &dump_filter_arg, 142 &dump_cdef_arg, 143 &dump_dual_filter_type_arg, 144 &dump_cfl_arg, 145 &dump_reference_frame_arg, 146 &dump_motion_vectors_arg, 147 &dump_delta_q_arg, 148 &dump_seg_id_arg, 149 &dump_intrabc_arg, 150 &dump_palette_arg, 151 &dump_uv_palette_arg, 152 &usage_arg, 153 &skip_non_transform_arg, 154 &combined_arg, 155 NULL }; 156 #define ENUM(name) { #name, name } 157 #define LAST_ENUM { NULL, 0 } 158 typedef struct map_entry { 159 const char *name; 160 int value; 161 } map_entry; 162 163 const map_entry refs_map[] = { 164 ENUM(INTRA_FRAME), ENUM(LAST_FRAME), ENUM(LAST2_FRAME), 165 ENUM(LAST3_FRAME), ENUM(GOLDEN_FRAME), ENUM(BWDREF_FRAME), 166 ENUM(ALTREF2_FRAME), ENUM(ALTREF_FRAME), LAST_ENUM 167 }; 168 169 const map_entry block_size_map[] = { 170 ENUM(BLOCK_4X4), ENUM(BLOCK_4X8), ENUM(BLOCK_8X4), 171 ENUM(BLOCK_8X8), ENUM(BLOCK_8X16), ENUM(BLOCK_16X8), 172 ENUM(BLOCK_16X16), ENUM(BLOCK_16X32), ENUM(BLOCK_32X16), 173 ENUM(BLOCK_32X32), ENUM(BLOCK_32X64), ENUM(BLOCK_64X32), 174 ENUM(BLOCK_64X64), ENUM(BLOCK_64X128), ENUM(BLOCK_128X64), 175 ENUM(BLOCK_128X128), ENUM(BLOCK_4X16), ENUM(BLOCK_16X4), 176 ENUM(BLOCK_8X32), ENUM(BLOCK_32X8), ENUM(BLOCK_16X64), 177 ENUM(BLOCK_64X16), LAST_ENUM 178 }; 179 180 #define TX_SKIP -1 181 182 const map_entry tx_size_map[] = { 183 ENUM(TX_4X4), ENUM(TX_8X8), ENUM(TX_16X16), ENUM(TX_32X32), 184 ENUM(TX_64X64), ENUM(TX_4X8), ENUM(TX_8X4), ENUM(TX_8X16), 185 ENUM(TX_16X8), ENUM(TX_16X32), ENUM(TX_32X16), ENUM(TX_32X64), 186 ENUM(TX_64X32), ENUM(TX_4X16), ENUM(TX_16X4), ENUM(TX_8X32), 187 ENUM(TX_32X8), ENUM(TX_16X64), ENUM(TX_64X16), LAST_ENUM 188 }; 189 190 const map_entry tx_type_map[] = { ENUM(DCT_DCT), 191 ENUM(ADST_DCT), 192 ENUM(DCT_ADST), 193 ENUM(ADST_ADST), 194 ENUM(FLIPADST_DCT), 195 ENUM(DCT_FLIPADST), 196 ENUM(FLIPADST_FLIPADST), 197 ENUM(ADST_FLIPADST), 198 ENUM(FLIPADST_ADST), 199 ENUM(IDTX), 200 ENUM(V_DCT), 201 ENUM(H_DCT), 202 ENUM(V_ADST), 203 ENUM(H_ADST), 204 ENUM(V_FLIPADST), 205 ENUM(H_FLIPADST), 206 LAST_ENUM }; 207 const map_entry dual_filter_map[] = { ENUM(REG_REG), ENUM(REG_SMOOTH), 208 ENUM(REG_SHARP), ENUM(SMOOTH_REG), 209 ENUM(SMOOTH_SMOOTH), ENUM(SMOOTH_SHARP), 210 ENUM(SHARP_REG), ENUM(SHARP_SMOOTH), 211 ENUM(SHARP_SHARP), LAST_ENUM }; 212 213 const map_entry prediction_mode_map[] = { 214 ENUM(DC_PRED), ENUM(V_PRED), ENUM(H_PRED), 215 ENUM(D45_PRED), ENUM(D135_PRED), ENUM(D113_PRED), 216 ENUM(D157_PRED), ENUM(D203_PRED), ENUM(D67_PRED), 217 ENUM(SMOOTH_PRED), ENUM(SMOOTH_V_PRED), ENUM(SMOOTH_H_PRED), 218 ENUM(PAETH_PRED), ENUM(NEARESTMV), ENUM(NEARMV), 219 ENUM(GLOBALMV), ENUM(NEWMV), ENUM(NEAREST_NEARESTMV), 220 ENUM(NEAR_NEARMV), ENUM(NEAREST_NEWMV), ENUM(NEW_NEARESTMV), 221 ENUM(NEAR_NEWMV), ENUM(NEW_NEARMV), ENUM(GLOBAL_GLOBALMV), 222 ENUM(NEW_NEWMV), ENUM(INTRA_INVALID), LAST_ENUM 223 }; 224 225 const map_entry motion_mode_map[] = { ENUM(SIMPLE_TRANSLATION), 226 ENUM(OBMC_CAUSAL), // 2-sided OBMC 227 ENUM(WARPED_CAUSAL), // 2-sided WARPED 228 LAST_ENUM }; 229 230 const map_entry compound_type_map[] = { ENUM(COMPOUND_AVERAGE), 231 ENUM(COMPOUND_WEDGE), 232 ENUM(COMPOUND_DIFFWTD), LAST_ENUM }; 233 234 const map_entry uv_prediction_mode_map[] = { 235 ENUM(UV_DC_PRED), ENUM(UV_V_PRED), 236 ENUM(UV_H_PRED), ENUM(UV_D45_PRED), 237 ENUM(UV_D135_PRED), ENUM(UV_D113_PRED), 238 ENUM(UV_D157_PRED), ENUM(UV_D203_PRED), 239 ENUM(UV_D67_PRED), ENUM(UV_SMOOTH_PRED), 240 ENUM(UV_SMOOTH_V_PRED), ENUM(UV_SMOOTH_H_PRED), 241 ENUM(UV_PAETH_PRED), ENUM(UV_CFL_PRED), 242 ENUM(UV_MODE_INVALID), LAST_ENUM 243 }; 244 #define NO_SKIP 0 245 #define SKIP 1 246 247 const map_entry skip_map[] = { ENUM(SKIP), ENUM(NO_SKIP), LAST_ENUM }; 248 249 const map_entry intrabc_map[] = { { "INTRABC", 1 }, 250 { "NO_INTRABC", 0 }, 251 LAST_ENUM }; 252 253 const map_entry palette_map[] = { 254 { "ZERO_COLORS", 0 }, { "TWO_COLORS", 2 }, { "THREE_COLORS", 3 }, 255 { "FOUR_COLORS", 4 }, { "FIVE_COLORS", 5 }, { "SIX_COLORS", 6 }, 256 { "SEVEN_COLORS", 7 }, { "EIGHT_COLORS", 8 }, LAST_ENUM 257 }; 258 259 const map_entry config_map[] = { ENUM(MI_SIZE), LAST_ENUM }; 260 261 static const char *exec_name; 262 263 struct parm_offset { 264 char parm[60]; 265 char offset; 266 }; 267 struct parm_offset parm_offsets[] = { 268 { "blockSize", offsetof(insp_mi_data, bsize) }, 269 { "transformSize", offsetof(insp_mi_data, tx_size) }, 270 { "transformType", offsetof(insp_mi_data, tx_type) }, 271 { "dualFilterType", offsetof(insp_mi_data, dual_filter_type) }, 272 { "mode", offsetof(insp_mi_data, mode) }, 273 { "uv_mode", offsetof(insp_mi_data, uv_mode) }, 274 { "motion_mode", offsetof(insp_mi_data, motion_mode) }, 275 { "compound_type", offsetof(insp_mi_data, compound_type) }, 276 { "referenceFrame", offsetof(insp_mi_data, ref_frame) }, 277 { "skip", offsetof(insp_mi_data, skip) }, 278 }; 279 int parm_count = sizeof(parm_offsets) / sizeof(parm_offsets[0]); 280 281 static int convert_to_indices(char *str, int *indices, int maxCount, 282 int *count) { 283 *count = 0; 284 do { 285 char *comma = strchr(str, ','); 286 int length = (comma ? (int)(comma - str) : (int)strlen(str)); 287 int i; 288 for (i = 0; i < parm_count; ++i) { 289 if (!strncmp(str, parm_offsets[i].parm, length)) { 290 break; 291 } 292 } 293 if (i == parm_count) return 0; 294 indices[(*count)++] = i; 295 if (*count > maxCount) return 0; 296 str += length + 1; 297 } while (strlen(str) > 0); 298 return 1; 299 } 300 301 insp_frame_data frame_data; 302 int frame_count = 0; 303 int decoded_frame_count = 0; 304 aom_codec_ctx_t codec; 305 AvxVideoReader *reader = NULL; 306 const AvxVideoInfo *info = NULL; 307 aom_image_t *img = NULL; 308 309 static void on_frame_decoded_dump(char *json) { 310 #ifdef __EMSCRIPTEN__ 311 EM_ASM_({ Module.on_frame_decoded_json($0); }, json); 312 #else 313 printf("%s", json); 314 #endif 315 } 316 317 // Writing out the JSON buffer using snprintf is very slow, especially when 318 // compiled with emscripten, these functions speed things up quite a bit. 319 static int put_str(char *buffer, const char *str) { 320 int i; 321 for (i = 0; str[i] != '\0'; i++) { 322 buffer[i] = str[i]; 323 } 324 return i; 325 } 326 327 static int put_str_with_escape(char *buffer, const char *str) { 328 int i; 329 int j = 0; 330 for (i = 0; str[i] != '\0'; i++) { 331 if (str[i] < ' ') { 332 continue; 333 } else if (str[i] == '"' || str[i] == '\\') { 334 buffer[j++] = '\\'; 335 } 336 buffer[j++] = str[i]; 337 } 338 return j; 339 } 340 341 static int put_num(char *buffer, char prefix, int num, char suffix) { 342 int i = 0; 343 char *buf = buffer; 344 int is_neg = 0; 345 if (prefix) { 346 buf[i++] = prefix; 347 } 348 if (num == 0) { 349 buf[i++] = '0'; 350 } else { 351 if (num < 0) { 352 num = -num; 353 is_neg = 1; 354 } 355 int s = i; 356 while (num != 0) { 357 buf[i++] = '0' + (num % 10); 358 num = num / 10; 359 } 360 if (is_neg) { 361 buf[i++] = '-'; 362 } 363 int e = i - 1; 364 while (s < e) { 365 int t = buf[s]; 366 buf[s] = buf[e]; 367 buf[e] = t; 368 s++; 369 e--; 370 } 371 } 372 if (suffix) { 373 buf[i++] = suffix; 374 } 375 return i; 376 } 377 378 static int put_map(char *buffer, const map_entry *map) { 379 char *buf = buffer; 380 const map_entry *entry = map; 381 while (entry->name != NULL) { 382 *(buf++) = '"'; 383 buf += put_str(buf, entry->name); 384 *(buf++) = '"'; 385 buf += put_num(buf, ':', entry->value, 0); 386 entry++; 387 if (entry->name != NULL) { 388 *(buf++) = ','; 389 } 390 } 391 return (int)(buf - buffer); 392 } 393 394 #if 0 395 static int put_reference_frame(char *buffer) { 396 const int mi_rows = frame_data.mi_rows; 397 const int mi_cols = frame_data.mi_cols; 398 char *buf = buffer; 399 int r, c, t; 400 buf += put_str(buf, " \"referenceFrameMap\": {"); 401 buf += put_map(buf, refs_map); 402 buf += put_str(buf, "},\n"); 403 buf += put_str(buf, " \"referenceFrame\": ["); 404 for (r = 0; r < mi_rows; ++r) { 405 *(buf++) = '['; 406 for (c = 0; c < mi_cols; ++c) { 407 insp_mi_data *mi = &frame_data.mi_grid[r * mi_cols + c]; 408 buf += put_num(buf, '[', mi->ref_frame[0], 0); 409 buf += put_num(buf, ',', mi->ref_frame[1], ']'); 410 if (compress) { // RLE 411 for (t = c + 1; t < mi_cols; ++t) { 412 insp_mi_data *next_mi = &frame_data.mi_grid[r * mi_cols + t]; 413 if (mi->ref_frame[0] != next_mi->ref_frame[0] || 414 mi->ref_frame[1] != next_mi->ref_frame[1]) { 415 break; 416 } 417 } 418 if (t - c > 1) { 419 *(buf++) = ','; 420 buf += put_num(buf, '[', t - c - 1, ']'); 421 c = t - 1; 422 } 423 } 424 if (c < mi_cols - 1) *(buf++) = ','; 425 } 426 *(buf++) = ']'; 427 if (r < mi_rows - 1) *(buf++) = ','; 428 } 429 buf += put_str(buf, "],\n"); 430 return (int)(buf - buffer); 431 } 432 #endif 433 434 static int put_motion_vectors(char *buffer) { 435 const int mi_rows = frame_data.mi_rows; 436 const int mi_cols = frame_data.mi_cols; 437 char *buf = buffer; 438 int r, c, t; 439 buf += put_str(buf, " \"motionVectors\": ["); 440 for (r = 0; r < mi_rows; ++r) { 441 *(buf++) = '['; 442 for (c = 0; c < mi_cols; ++c) { 443 insp_mi_data *mi = &frame_data.mi_grid[r * mi_cols + c]; 444 buf += put_num(buf, '[', mi->mv[0].col, 0); 445 buf += put_num(buf, ',', mi->mv[0].row, 0); 446 buf += put_num(buf, ',', mi->mv[1].col, 0); 447 buf += put_num(buf, ',', mi->mv[1].row, ']'); 448 if (compress) { // RLE 449 for (t = c + 1; t < mi_cols; ++t) { 450 insp_mi_data *next_mi = &frame_data.mi_grid[r * mi_cols + t]; 451 if (mi->mv[0].col != next_mi->mv[0].col || 452 mi->mv[0].row != next_mi->mv[0].row || 453 mi->mv[1].col != next_mi->mv[1].col || 454 mi->mv[1].row != next_mi->mv[1].row) { 455 break; 456 } 457 } 458 if (t - c > 1) { 459 *(buf++) = ','; 460 buf += put_num(buf, '[', t - c - 1, ']'); 461 c = t - 1; 462 } 463 } 464 if (c < mi_cols - 1) *(buf++) = ','; 465 } 466 *(buf++) = ']'; 467 if (r < mi_rows - 1) *(buf++) = ','; 468 } 469 buf += put_str(buf, "],\n"); 470 return (int)(buf - buffer); 471 } 472 473 static int put_combined(char *buffer) { 474 const int mi_rows = frame_data.mi_rows; 475 const int mi_cols = frame_data.mi_cols; 476 char *buf = buffer; 477 int r, c, p; 478 buf += put_str(buf, " \""); 479 for (p = 0; p < combined_parm_count; ++p) { 480 if (p) buf += put_str(buf, "&"); 481 buf += put_str(buf, parm_offsets[combined_parm_list[p]].parm); 482 } 483 buf += put_str(buf, "\": ["); 484 for (r = 0; r < mi_rows; ++r) { 485 *(buf++) = '['; 486 for (c = 0; c < mi_cols; ++c) { 487 insp_mi_data *mi = &frame_data.mi_grid[r * mi_cols + c]; 488 *(buf++) = '['; 489 for (p = 0; p < combined_parm_count; ++p) { 490 if (p) *(buf++) = ','; 491 int16_t *v = (int16_t *)(((int8_t *)mi) + 492 parm_offsets[combined_parm_list[p]].offset); 493 buf += put_num(buf, 0, v[0], 0); 494 } 495 *(buf++) = ']'; 496 if (c < mi_cols - 1) *(buf++) = ','; 497 } 498 *(buf++) = ']'; 499 if (r < mi_rows - 1) *(buf++) = ','; 500 } 501 buf += put_str(buf, "],\n"); 502 return (int)(buf - buffer); 503 } 504 505 static int put_block_info(char *buffer, const map_entry *map, const char *name, 506 size_t offset, int len) { 507 const int mi_rows = frame_data.mi_rows; 508 const int mi_cols = frame_data.mi_cols; 509 char *buf = buffer; 510 int r, c, t, i; 511 if (compress && len == 1) { 512 die("Can't encode scalars as arrays when RLE compression is enabled."); 513 } 514 if (map) { 515 buf += snprintf(buf, MAX_BUFFER, " \"%sMap\": {", name); 516 buf += put_map(buf, map); 517 buf += put_str(buf, "},\n"); 518 } 519 buf += snprintf(buf, MAX_BUFFER, " \"%s\": [", name); 520 for (r = 0; r < mi_rows; ++r) { 521 *(buf++) = '['; 522 for (c = 0; c < mi_cols; ++c) { 523 insp_mi_data *mi = &frame_data.mi_grid[r * mi_cols + c]; 524 int16_t *v = (int16_t *)(((int8_t *)mi) + offset); 525 if (len == 0) { 526 buf += put_num(buf, 0, v[0], 0); 527 } else { 528 buf += put_str(buf, "["); 529 for (i = 0; i < len; i++) { 530 buf += put_num(buf, 0, v[i], 0); 531 if (i < len - 1) { 532 buf += put_str(buf, ","); 533 } 534 } 535 buf += put_str(buf, "]"); 536 } 537 if (compress) { // RLE 538 for (t = c + 1; t < mi_cols; ++t) { 539 insp_mi_data *next_mi = &frame_data.mi_grid[r * mi_cols + t]; 540 int16_t *nv = (int16_t *)(((int8_t *)next_mi) + offset); 541 int same = 0; 542 if (len == 0) { 543 same = v[0] == nv[0]; 544 } else { 545 for (i = 0; i < len; i++) { 546 same = v[i] == nv[i]; 547 if (!same) { 548 break; 549 } 550 } 551 } 552 if (!same) { 553 break; 554 } 555 } 556 if (t - c > 1) { 557 *(buf++) = ','; 558 buf += put_num(buf, '[', t - c - 1, ']'); 559 c = t - 1; 560 } 561 } 562 if (c < mi_cols - 1) *(buf++) = ','; 563 } 564 *(buf++) = ']'; 565 if (r < mi_rows - 1) *(buf++) = ','; 566 } 567 buf += put_str(buf, "],\n"); 568 return (int)(buf - buffer); 569 } 570 571 #if CONFIG_ACCOUNTING 572 static int put_accounting(char *buffer) { 573 char *buf = buffer; 574 int i; 575 const Accounting *accounting = frame_data.accounting; 576 if (accounting == NULL) { 577 printf("XXX\n"); 578 return 0; 579 } 580 const int num_syms = accounting->syms.num_syms; 581 const int num_strs = accounting->syms.dictionary.num_strs; 582 buf += put_str(buf, " \"symbolsMap\": ["); 583 for (i = 0; i < num_strs; i++) { 584 buf += snprintf(buf, MAX_BUFFER, "\"%s\"", 585 accounting->syms.dictionary.strs[i]); 586 if (i < num_strs - 1) *(buf++) = ','; 587 } 588 buf += put_str(buf, "],\n"); 589 buf += put_str(buf, " \"symbols\": [\n "); 590 AccountingSymbolContext context; 591 context.x = -2; 592 context.y = -2; 593 AccountingSymbol *sym; 594 for (i = 0; i < num_syms; i++) { 595 sym = &accounting->syms.syms[i]; 596 if (memcmp(&context, &sym->context, sizeof(AccountingSymbolContext)) != 0) { 597 buf += put_num(buf, '[', sym->context.x, 0); 598 buf += put_num(buf, ',', sym->context.y, ']'); 599 } else { 600 buf += put_num(buf, '[', sym->id, 0); 601 buf += put_num(buf, ',', sym->bits, 0); 602 buf += put_num(buf, ',', sym->samples, ']'); 603 } 604 context = sym->context; 605 if (i < num_syms - 1) *(buf++) = ','; 606 } 607 buf += put_str(buf, "],\n"); 608 return (int)(buf - buffer); 609 } 610 #endif 611 612 int skip_non_transform = 0; 613 614 static void inspect(void *pbi, void *data) { 615 /* Fetch frame data. */ 616 ifd_inspect(&frame_data, pbi, skip_non_transform); 617 618 // Show existing frames just show a reference buffer we've already decoded. 619 // There's no information to show. 620 if (frame_data.show_existing_frame) return; 621 622 (void)data; 623 // We allocate enough space and hope we don't write out of bounds. Totally 624 // unsafe but this speeds things up, especially when compiled to Javascript. 625 char *buffer = malloc(MAX_BUFFER); 626 if (!buffer) { 627 fprintf(stderr, "Error allocating inspect info buffer\n"); 628 abort(); 629 } 630 char *buf = buffer; 631 buf += put_str(buf, "{\n"); 632 if (layers & BLOCK_SIZE_LAYER) { 633 buf += put_block_info(buf, block_size_map, "blockSize", 634 offsetof(insp_mi_data, bsize), 0); 635 } 636 if (layers & TRANSFORM_SIZE_LAYER) { 637 buf += put_block_info(buf, tx_size_map, "transformSize", 638 offsetof(insp_mi_data, tx_size), 0); 639 } 640 if (layers & TRANSFORM_TYPE_LAYER) { 641 buf += put_block_info(buf, tx_type_map, "transformType", 642 offsetof(insp_mi_data, tx_type), 0); 643 } 644 if (layers & DUAL_FILTER_LAYER) { 645 buf += put_block_info(buf, dual_filter_map, "dualFilterType", 646 offsetof(insp_mi_data, dual_filter_type), 0); 647 } 648 if (layers & MODE_LAYER) { 649 buf += put_block_info(buf, prediction_mode_map, "mode", 650 offsetof(insp_mi_data, mode), 0); 651 } 652 if (layers & UV_MODE_LAYER) { 653 buf += put_block_info(buf, uv_prediction_mode_map, "uv_mode", 654 offsetof(insp_mi_data, uv_mode), 0); 655 } 656 if (layers & MOTION_MODE_LAYER) { 657 buf += put_block_info(buf, motion_mode_map, "motion_mode", 658 offsetof(insp_mi_data, motion_mode), 0); 659 } 660 if (layers & COMPOUND_TYPE_LAYER) { 661 buf += put_block_info(buf, compound_type_map, "compound_type", 662 offsetof(insp_mi_data, compound_type), 0); 663 } 664 if (layers & SKIP_LAYER) { 665 buf += 666 put_block_info(buf, skip_map, "skip", offsetof(insp_mi_data, skip), 0); 667 } 668 if (layers & FILTER_LAYER) { 669 buf += 670 put_block_info(buf, NULL, "filter", offsetof(insp_mi_data, filter), 2); 671 } 672 if (layers & CDEF_LAYER) { 673 buf += put_block_info(buf, NULL, "cdef_level", 674 offsetof(insp_mi_data, cdef_level), 0); 675 buf += put_block_info(buf, NULL, "cdef_strength", 676 offsetof(insp_mi_data, cdef_strength), 0); 677 } 678 if (layers & CFL_LAYER) { 679 buf += put_block_info(buf, NULL, "cfl_alpha_idx", 680 offsetof(insp_mi_data, cfl_alpha_idx), 0); 681 buf += put_block_info(buf, NULL, "cfl_alpha_sign", 682 offsetof(insp_mi_data, cfl_alpha_sign), 0); 683 } 684 if (layers & Q_INDEX_LAYER) { 685 buf += put_block_info(buf, NULL, "delta_q", 686 offsetof(insp_mi_data, current_qindex), 0); 687 } 688 if (layers & SEGMENT_ID_LAYER) { 689 buf += put_block_info(buf, NULL, "seg_id", 690 offsetof(insp_mi_data, segment_id), 0); 691 } 692 if (layers & MOTION_VECTORS_LAYER) { 693 buf += put_motion_vectors(buf); 694 } 695 if (layers & INTRABC_LAYER) { 696 buf += put_block_info(buf, intrabc_map, "intrabc", 697 offsetof(insp_mi_data, intrabc), 0); 698 } 699 if (layers & PALETTE_LAYER) { 700 buf += put_block_info(buf, palette_map, "palette", 701 offsetof(insp_mi_data, palette), 0); 702 } 703 if (layers & UV_PALETTE_LAYER) { 704 buf += put_block_info(buf, palette_map, "uv_palette", 705 offsetof(insp_mi_data, uv_palette), 0); 706 } 707 if (combined_parm_count > 0) buf += put_combined(buf); 708 if (layers & REFERENCE_FRAME_LAYER) { 709 buf += put_block_info(buf, refs_map, "referenceFrame", 710 offsetof(insp_mi_data, ref_frame), 2); 711 } 712 #if CONFIG_ACCOUNTING 713 if (layers & ACCOUNTING_LAYER) { 714 buf += put_accounting(buf); 715 } 716 #endif 717 buf += 718 snprintf(buf, MAX_BUFFER, " \"frame\": %d,\n", frame_data.frame_number); 719 buf += snprintf(buf, MAX_BUFFER, " \"showFrame\": %d,\n", 720 frame_data.show_frame); 721 buf += snprintf(buf, MAX_BUFFER, " \"frameType\": %d,\n", 722 frame_data.frame_type); 723 buf += snprintf(buf, MAX_BUFFER, " \"baseQIndex\": %d,\n", 724 frame_data.base_qindex); 725 buf += snprintf(buf, MAX_BUFFER, " \"tileCols\": %d,\n", 726 frame_data.tile_mi_cols); 727 buf += snprintf(buf, MAX_BUFFER, " \"tileRows\": %d,\n", 728 frame_data.tile_mi_rows); 729 buf += snprintf(buf, MAX_BUFFER, " \"deltaQPresentFlag\": %d,\n", 730 frame_data.delta_q_present_flag); 731 buf += snprintf(buf, MAX_BUFFER, " \"deltaQRes\": %d,\n", 732 frame_data.delta_q_res); 733 buf += put_str(buf, " \"config\": {"); 734 buf += put_map(buf, config_map); 735 buf += put_str(buf, "},\n"); 736 buf += put_str(buf, " \"configString\": \""); 737 buf += put_str_with_escape(buf, aom_codec_build_config()); 738 buf += put_str(buf, "\"\n"); 739 decoded_frame_count++; 740 buf += put_str(buf, "},\n"); 741 *(buf++) = 0; 742 on_frame_decoded_dump(buffer); 743 free(buffer); 744 } 745 746 static void ifd_init_cb(void) { 747 aom_inspect_init ii; 748 ii.inspect_cb = inspect; 749 ii.inspect_ctx = NULL; 750 aom_codec_control(&codec, AV1_SET_INSPECTION_CALLBACK, &ii); 751 } 752 753 EMSCRIPTEN_KEEPALIVE int open_file(char *file); 754 755 EMSCRIPTEN_KEEPALIVE 756 int open_file(char *file) { 757 if (file == NULL) { 758 // The JS analyzer puts the .ivf file at this location. 759 file = "/tmp/input.ivf"; 760 } 761 reader = aom_video_reader_open(file); 762 if (!reader) die("Failed to open %s for reading.", file); 763 info = aom_video_reader_get_info(reader); 764 aom_codec_iface_t *decoder = get_aom_decoder_by_fourcc(info->codec_fourcc); 765 if (!decoder) die("Unknown input codec."); 766 fprintf(stderr, "Using %s\n", aom_codec_iface_name(decoder)); 767 if (aom_codec_dec_init(&codec, decoder, NULL, 0)) 768 die("Failed to initialize decoder."); 769 ifd_init(&frame_data, info->frame_width, info->frame_height); 770 ifd_init_cb(); 771 return EXIT_SUCCESS; 772 } 773 774 Av1DecodeReturn adr; 775 int have_frame = 0; 776 const unsigned char *frame; 777 const unsigned char *end_frame; 778 size_t frame_size = 0; 779 struct av1_ref_frame ref_dec; 780 781 EMSCRIPTEN_KEEPALIVE int read_frame(void); 782 783 EMSCRIPTEN_KEEPALIVE 784 int read_frame(void) { 785 img = NULL; 786 787 // This loop skips over any frames that are show_existing_frames, as 788 // there is nothing to analyze. 789 do { 790 if (!have_frame) { 791 if (!aom_video_reader_read_frame(reader)) return EXIT_FAILURE; 792 frame = aom_video_reader_get_frame(reader, &frame_size); 793 794 have_frame = 1; 795 end_frame = frame + frame_size; 796 } 797 798 if (aom_codec_decode(&codec, frame, (unsigned int)frame_size, &adr) != 799 AOM_CODEC_OK) { 800 die_codec(&codec, "Failed to decode frame."); 801 } 802 803 frame = adr.buf; 804 frame_size = end_frame - frame; 805 if (frame == end_frame) have_frame = 0; 806 } while (adr.show_existing); 807 808 int got_any_frames = 0; 809 aom_image_t *frame_img; 810 ref_dec.idx = adr.idx; 811 812 // ref_dec.idx is the index to the reference buffer idx to AV1_GET_REFERENCE 813 // if its -1 the decoder didn't update any reference buffer and the only 814 // way to see the frame is aom_codec_get_frame. 815 if (ref_dec.idx == -1) { 816 aom_codec_iter_t iter = NULL; 817 img = frame_img = aom_codec_get_frame(&codec, &iter); 818 ++frame_count; 819 got_any_frames = 1; 820 } else if (!aom_codec_control(&codec, AV1_GET_REFERENCE, &ref_dec)) { 821 img = frame_img = &ref_dec.img; 822 ++frame_count; 823 got_any_frames = 1; 824 } 825 if (!got_any_frames) { 826 return EXIT_FAILURE; 827 } 828 return EXIT_SUCCESS; 829 } 830 831 EMSCRIPTEN_KEEPALIVE const char *get_aom_codec_build_config(void); 832 833 EMSCRIPTEN_KEEPALIVE 834 const char *get_aom_codec_build_config(void) { 835 return aom_codec_build_config(); 836 } 837 838 EMSCRIPTEN_KEEPALIVE int get_bit_depth(void); 839 840 EMSCRIPTEN_KEEPALIVE 841 int get_bit_depth(void) { return img->bit_depth; } 842 843 EMSCRIPTEN_KEEPALIVE int get_bits_per_sample(void); 844 845 EMSCRIPTEN_KEEPALIVE 846 int get_bits_per_sample(void) { return img->bps; } 847 848 EMSCRIPTEN_KEEPALIVE int get_image_format(void); 849 850 EMSCRIPTEN_KEEPALIVE 851 int get_image_format(void) { return img->fmt; } 852 853 EMSCRIPTEN_KEEPALIVE unsigned char *get_plane(int plane); 854 855 EMSCRIPTEN_KEEPALIVE 856 unsigned char *get_plane(int plane) { return img->planes[plane]; } 857 858 EMSCRIPTEN_KEEPALIVE int get_plane_stride(int plane); 859 860 EMSCRIPTEN_KEEPALIVE 861 int get_plane_stride(int plane) { return img->stride[plane]; } 862 863 EMSCRIPTEN_KEEPALIVE int get_plane_width(int plane); 864 865 EMSCRIPTEN_KEEPALIVE 866 int get_plane_width(int plane) { return aom_img_plane_width(img, plane); } 867 868 EMSCRIPTEN_KEEPALIVE int get_plane_height(int plane); 869 870 EMSCRIPTEN_KEEPALIVE 871 int get_plane_height(int plane) { return aom_img_plane_height(img, plane); } 872 873 EMSCRIPTEN_KEEPALIVE int get_frame_width(void); 874 875 EMSCRIPTEN_KEEPALIVE 876 int get_frame_width(void) { return info->frame_width; } 877 878 EMSCRIPTEN_KEEPALIVE int get_frame_height(void); 879 880 EMSCRIPTEN_KEEPALIVE 881 int get_frame_height(void) { return info->frame_height; } 882 883 static void parse_args(char **argv) { 884 char **argi, **argj; 885 struct arg arg; 886 (void)dump_accounting_arg; 887 (void)dump_cdef_arg; 888 for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step) { 889 arg.argv_step = 1; 890 if (arg_match(&arg, &dump_block_size_arg, argi)) layers |= BLOCK_SIZE_LAYER; 891 #if CONFIG_ACCOUNTING 892 else if (arg_match(&arg, &dump_accounting_arg, argi)) 893 layers |= ACCOUNTING_LAYER; 894 #endif 895 else if (arg_match(&arg, &dump_transform_size_arg, argi)) 896 layers |= TRANSFORM_SIZE_LAYER; 897 else if (arg_match(&arg, &dump_transform_type_arg, argi)) 898 layers |= TRANSFORM_TYPE_LAYER; 899 else if (arg_match(&arg, &dump_mode_arg, argi)) 900 layers |= MODE_LAYER; 901 else if (arg_match(&arg, &dump_uv_mode_arg, argi)) 902 layers |= UV_MODE_LAYER; 903 else if (arg_match(&arg, &dump_motion_mode_arg, argi)) 904 layers |= MOTION_MODE_LAYER; 905 else if (arg_match(&arg, &dump_compound_type_arg, argi)) 906 layers |= COMPOUND_TYPE_LAYER; 907 else if (arg_match(&arg, &dump_skip_arg, argi)) 908 layers |= SKIP_LAYER; 909 else if (arg_match(&arg, &dump_filter_arg, argi)) 910 layers |= FILTER_LAYER; 911 else if (arg_match(&arg, &dump_cdef_arg, argi)) 912 layers |= CDEF_LAYER; 913 else if (arg_match(&arg, &dump_cfl_arg, argi)) 914 layers |= CFL_LAYER; 915 else if (arg_match(&arg, &dump_reference_frame_arg, argi)) 916 layers |= REFERENCE_FRAME_LAYER; 917 else if (arg_match(&arg, &dump_motion_vectors_arg, argi)) 918 layers |= MOTION_VECTORS_LAYER; 919 else if (arg_match(&arg, &dump_dual_filter_type_arg, argi)) 920 layers |= DUAL_FILTER_LAYER; 921 else if (arg_match(&arg, &dump_delta_q_arg, argi)) 922 layers |= Q_INDEX_LAYER; 923 else if (arg_match(&arg, &dump_seg_id_arg, argi)) 924 layers |= SEGMENT_ID_LAYER; 925 else if (arg_match(&arg, &dump_intrabc_arg, argi)) 926 layers |= INTRABC_LAYER; 927 else if (arg_match(&arg, &dump_palette_arg, argi)) 928 layers |= PALETTE_LAYER; 929 else if (arg_match(&arg, &dump_uv_palette_arg, argi)) 930 layers |= UV_PALETTE_LAYER; 931 else if (arg_match(&arg, &dump_all_arg, argi)) 932 layers |= ALL_LAYERS; 933 else if (arg_match(&arg, &compress_arg, argi)) 934 compress = 1; 935 else if (arg_match(&arg, &usage_arg, argi)) 936 usage_exit(); 937 else if (arg_match(&arg, &limit_arg, argi)) 938 stop_after = arg_parse_uint(&arg); 939 else if (arg_match(&arg, &skip_non_transform_arg, argi)) 940 skip_non_transform = arg_parse_uint(&arg); 941 else if (arg_match(&arg, &combined_arg, argi)) 942 convert_to_indices( 943 (char *)arg.val, combined_parm_list, 944 sizeof(combined_parm_list) / sizeof(combined_parm_list[0]), 945 &combined_parm_count); 946 else 947 argj++; 948 } 949 } 950 951 static const char *exec_name; 952 953 void usage_exit(void) { 954 fprintf(stderr, "Usage: %s src_filename <options>\n", exec_name); 955 fprintf(stderr, "\nOptions:\n"); 956 arg_show_usage(stderr, main_args); 957 exit(EXIT_FAILURE); 958 } 959 960 EMSCRIPTEN_KEEPALIVE 961 int main(int argc, char **argv) { 962 exec_name = argv[0]; 963 parse_args(argv); 964 if (argc >= 2) { 965 open_file(argv[1]); 966 printf("[\n"); 967 while (1) { 968 if (stop_after && (decoded_frame_count >= stop_after)) break; 969 if (read_frame()) break; 970 } 971 printf("null\n"); 972 printf("]"); 973 } else { 974 usage_exit(); 975 } 976 } 977 978 EMSCRIPTEN_KEEPALIVE void quit(void); 979 980 EMSCRIPTEN_KEEPALIVE 981 void quit(void) { 982 if (aom_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec"); 983 aom_video_reader_close(reader); 984 } 985 986 EMSCRIPTEN_KEEPALIVE void set_layers(LayerType v); 987 988 EMSCRIPTEN_KEEPALIVE 989 void set_layers(LayerType v) { layers = v; } 990 991 EMSCRIPTEN_KEEPALIVE void set_compress(int v); 992 993 EMSCRIPTEN_KEEPALIVE 994 void set_compress(int v) { compress = v; }