2 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
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.
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.
23 #include <emscripten.h>
25 #define EMSCRIPTEN_KEEPALIVE
28 #include "config/aom_config.h"
30 #include "aom/aom_decoder.h"
31 #include "aom/aomdx.h"
32 #include "av1/common/av1_common_int.h"
35 #include "av1/decoder/accounting.h"
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"
44 // Max JSON buffer size.
45 const int MAX_BUFFER
= 1024 * 1024 * 256;
49 BLOCK_SIZE_LAYER
= 1 << 1,
50 TRANSFORM_SIZE_LAYER
= 1 << 2,
51 TRANSFORM_TYPE_LAYER
= 1 << 3,
54 FILTER_LAYER
= 1 << 6,
56 REFERENCE_FRAME_LAYER
= 1 << 8,
57 MOTION_VECTORS_LAYER
= 1 << 9,
58 UV_MODE_LAYER
= 1 << 10,
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
71 static LayerType layers
= 0;
73 static int stop_after
= 0;
74 static int compress
= 0;
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.");
124 int combined_parm_list
[15];
125 int combined_parm_count
= 0;
127 static const arg_def_t
*main_args
[] = { &limit_arg
,
130 #if CONFIG_ACCOUNTING
131 &dump_accounting_arg
,
133 &dump_block_size_arg
,
134 &dump_transform_size_arg
,
135 &dump_transform_type_arg
,
138 &dump_motion_mode_arg
,
139 &dump_compound_type_arg
,
143 &dump_dual_filter_type_arg
,
145 &dump_reference_frame_arg
,
146 &dump_motion_vectors_arg
,
151 &dump_uv_palette_arg
,
153 &skip_non_transform_arg
,
160 typedef struct map_entry
{
165 const map_entry refs_map
[] = {
166 ENUM(INTRA_FRAME
), ENUM(LAST_FRAME
), ENUM(LAST2_FRAME
),
167 ENUM(LAST3_FRAME
), ENUM(GOLDEN_FRAME
), ENUM(BWDREF_FRAME
),
168 ENUM(ALTREF2_FRAME
), ENUM(ALTREF_FRAME
), LAST_ENUM
171 const map_entry block_size_map
[] = {
172 ENUM(BLOCK_4X4
), ENUM(BLOCK_4X8
), ENUM(BLOCK_8X4
),
173 ENUM(BLOCK_8X8
), ENUM(BLOCK_8X16
), ENUM(BLOCK_16X8
),
174 ENUM(BLOCK_16X16
), ENUM(BLOCK_16X32
), ENUM(BLOCK_32X16
),
175 ENUM(BLOCK_32X32
), ENUM(BLOCK_32X64
), ENUM(BLOCK_64X32
),
176 ENUM(BLOCK_64X64
), ENUM(BLOCK_64X128
), ENUM(BLOCK_128X64
),
177 ENUM(BLOCK_128X128
), ENUM(BLOCK_4X16
), ENUM(BLOCK_16X4
),
178 ENUM(BLOCK_8X32
), ENUM(BLOCK_32X8
), ENUM(BLOCK_16X64
),
179 ENUM(BLOCK_64X16
), LAST_ENUM
184 const map_entry tx_size_map
[] = {
185 ENUM(TX_4X4
), ENUM(TX_8X8
), ENUM(TX_16X16
), ENUM(TX_32X32
),
186 ENUM(TX_64X64
), ENUM(TX_4X8
), ENUM(TX_8X4
), ENUM(TX_8X16
),
187 ENUM(TX_16X8
), ENUM(TX_16X32
), ENUM(TX_32X16
), ENUM(TX_32X64
),
188 ENUM(TX_64X32
), ENUM(TX_4X16
), ENUM(TX_16X4
), ENUM(TX_8X32
),
189 ENUM(TX_32X8
), ENUM(TX_16X64
), ENUM(TX_64X16
), LAST_ENUM
192 const map_entry tx_type_map
[] = { ENUM(DCT_DCT
),
198 ENUM(FLIPADST_FLIPADST
),
209 const map_entry dual_filter_map
[] = { ENUM(REG_REG
), ENUM(REG_SMOOTH
),
210 ENUM(REG_SHARP
), ENUM(SMOOTH_REG
),
211 ENUM(SMOOTH_SMOOTH
), ENUM(SMOOTH_SHARP
),
212 ENUM(SHARP_REG
), ENUM(SHARP_SMOOTH
),
213 ENUM(SHARP_SHARP
), LAST_ENUM
};
215 const map_entry prediction_mode_map
[] = {
216 ENUM(DC_PRED
), ENUM(V_PRED
), ENUM(H_PRED
),
217 ENUM(D45_PRED
), ENUM(D135_PRED
), ENUM(D113_PRED
),
218 ENUM(D157_PRED
), ENUM(D203_PRED
), ENUM(D67_PRED
),
219 ENUM(SMOOTH_PRED
), ENUM(SMOOTH_V_PRED
), ENUM(SMOOTH_H_PRED
),
220 ENUM(PAETH_PRED
), ENUM(NEARESTMV
), ENUM(NEARMV
),
221 ENUM(GLOBALMV
), ENUM(NEWMV
), ENUM(NEAREST_NEARESTMV
),
222 ENUM(NEAR_NEARMV
), ENUM(NEAREST_NEWMV
), ENUM(NEW_NEARESTMV
),
223 ENUM(NEAR_NEWMV
), ENUM(NEW_NEARMV
), ENUM(GLOBAL_GLOBALMV
),
224 ENUM(NEW_NEWMV
), ENUM(INTRA_INVALID
), LAST_ENUM
227 const map_entry motion_mode_map
[] = { ENUM(SIMPLE_TRANSLATION
),
228 ENUM(OBMC_CAUSAL
), // 2-sided OBMC
229 ENUM(WARPED_CAUSAL
), // 2-sided WARPED
232 const map_entry compound_type_map
[] = { ENUM(COMPOUND_AVERAGE
),
233 ENUM(COMPOUND_WEDGE
),
234 ENUM(COMPOUND_DIFFWTD
), LAST_ENUM
};
236 const map_entry uv_prediction_mode_map
[] = {
237 ENUM(UV_DC_PRED
), ENUM(UV_V_PRED
),
238 ENUM(UV_H_PRED
), ENUM(UV_D45_PRED
),
239 ENUM(UV_D135_PRED
), ENUM(UV_D113_PRED
),
240 ENUM(UV_D157_PRED
), ENUM(UV_D203_PRED
),
241 ENUM(UV_D67_PRED
), ENUM(UV_SMOOTH_PRED
),
242 ENUM(UV_SMOOTH_V_PRED
), ENUM(UV_SMOOTH_H_PRED
),
243 ENUM(UV_PAETH_PRED
), ENUM(UV_CFL_PRED
),
244 ENUM(UV_MODE_INVALID
), LAST_ENUM
249 const map_entry skip_map
[] = { ENUM(SKIP
), ENUM(NO_SKIP
), LAST_ENUM
};
251 const map_entry intrabc_map
[] = { { "INTRABC", 1 },
255 const map_entry palette_map
[] = {
256 { "ZERO_COLORS", 0 }, { "TWO_COLORS", 2 }, { "THREE_COLORS", 3 },
257 { "FOUR_COLORS", 4 }, { "FIVE_COLORS", 5 }, { "SIX_COLORS", 6 },
258 { "SEVEN_COLORS", 7 }, { "EIGHT_COLORS", 8 }, LAST_ENUM
261 const map_entry config_map
[] = { ENUM(MI_SIZE
), LAST_ENUM
};
263 static const char *exec_name
;
269 struct parm_offset parm_offsets
[] = {
270 { "blockSize", offsetof(insp_mi_data
, bsize
) },
271 { "transformSize", offsetof(insp_mi_data
, tx_size
) },
272 { "transformType", offsetof(insp_mi_data
, tx_type
) },
273 { "dualFilterType", offsetof(insp_mi_data
, dual_filter_type
) },
274 { "mode", offsetof(insp_mi_data
, mode
) },
275 { "uv_mode", offsetof(insp_mi_data
, uv_mode
) },
276 { "motion_mode", offsetof(insp_mi_data
, motion_mode
) },
277 { "compound_type", offsetof(insp_mi_data
, compound_type
) },
278 { "referenceFrame", offsetof(insp_mi_data
, ref_frame
) },
279 { "skip", offsetof(insp_mi_data
, skip
) },
281 int parm_count
= sizeof(parm_offsets
) / sizeof(parm_offsets
[0]);
283 int convert_to_indices(char *str
, int *indices
, int maxCount
, int *count
) {
286 char *comma
= strchr(str
, ',');
287 int length
= (comma
? (int)(comma
- str
) : (int)strlen(str
));
289 for (i
= 0; i
< parm_count
; ++i
) {
290 if (!strncmp(str
, parm_offsets
[i
].parm
, length
)) {
294 if (i
== parm_count
) return 0;
295 indices
[(*count
)++] = i
;
296 if (*count
> maxCount
) return 0;
298 } while (strlen(str
) > 0);
302 insp_frame_data frame_data
;
304 int decoded_frame_count
= 0;
305 aom_codec_ctx_t codec
;
306 AvxVideoReader
*reader
= NULL
;
307 const AvxVideoInfo
*info
= NULL
;
308 aom_image_t
*img
= NULL
;
310 void on_frame_decoded_dump(char *json
) {
311 #ifdef __EMSCRIPTEN__
312 EM_ASM_({ Module
.on_frame_decoded_json($
0); }, json
);
318 // Writing out the JSON buffer using snprintf is very slow, especially when
319 // compiled with emscripten, these functions speed things up quite a bit.
320 int put_str(char *buffer
, const char *str
) {
322 for (i
= 0; str
[i
] != '\0'; i
++) {
328 int put_str_with_escape(char *buffer
, const char *str
) {
331 for (i
= 0; str
[i
] != '\0'; i
++) {
334 } else if (str
[i
] == '"' || str
[i
] == '\\') {
337 buffer
[j
++] = str
[i
];
342 int put_num(char *buffer
, char prefix
, int num
, char suffix
) {
358 buf
[i
++] = '0' + (num
% 10);
379 int put_map(char *buffer
, const map_entry
*map
) {
381 const map_entry
*entry
= map
;
382 while (entry
->name
!= NULL
) {
384 buf
+= put_str(buf
, entry
->name
);
386 buf
+= put_num(buf
, ':', entry
->value
, 0);
388 if (entry
->name
!= NULL
) {
392 return (int)(buf
- buffer
);
395 int put_reference_frame(char *buffer
) {
396 const int mi_rows
= frame_data
.mi_rows
;
397 const int mi_cols
= frame_data
.mi_cols
;
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
) {
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]) {
420 buf
+= put_num(buf
, '[', t
- c
- 1, ']');
424 if (c
< mi_cols
- 1) *(buf
++) = ',';
427 if (r
< mi_rows
- 1) *(buf
++) = ',';
429 buf
+= put_str(buf
, "],\n");
430 return (int)(buf
- buffer
);
433 int put_motion_vectors(char *buffer
) {
434 const int mi_rows
= frame_data
.mi_rows
;
435 const int mi_cols
= frame_data
.mi_cols
;
438 buf
+= put_str(buf
, " \"motionVectors\": [");
439 for (r
= 0; r
< mi_rows
; ++r
) {
441 for (c
= 0; c
< mi_cols
; ++c
) {
442 insp_mi_data
*mi
= &frame_data
.mi_grid
[r
* mi_cols
+ c
];
443 buf
+= put_num(buf
, '[', mi
->mv
[0].col
, 0);
444 buf
+= put_num(buf
, ',', mi
->mv
[0].row
, 0);
445 buf
+= put_num(buf
, ',', mi
->mv
[1].col
, 0);
446 buf
+= put_num(buf
, ',', mi
->mv
[1].row
, ']');
447 if (compress
) { // RLE
448 for (t
= c
+ 1; t
< mi_cols
; ++t
) {
449 insp_mi_data
*next_mi
= &frame_data
.mi_grid
[r
* mi_cols
+ t
];
450 if (mi
->mv
[0].col
!= next_mi
->mv
[0].col
||
451 mi
->mv
[0].row
!= next_mi
->mv
[0].row
||
452 mi
->mv
[1].col
!= next_mi
->mv
[1].col
||
453 mi
->mv
[1].row
!= next_mi
->mv
[1].row
) {
459 buf
+= put_num(buf
, '[', t
- c
- 1, ']');
463 if (c
< mi_cols
- 1) *(buf
++) = ',';
466 if (r
< mi_rows
- 1) *(buf
++) = ',';
468 buf
+= put_str(buf
, "],\n");
469 return (int)(buf
- buffer
);
472 int put_combined(char *buffer
) {
473 const int mi_rows
= frame_data
.mi_rows
;
474 const int mi_cols
= frame_data
.mi_cols
;
477 buf
+= put_str(buf
, " \"");
478 for (p
= 0; p
< combined_parm_count
; ++p
) {
479 if (p
) buf
+= put_str(buf
, "&");
480 buf
+= put_str(buf
, parm_offsets
[combined_parm_list
[p
]].parm
);
482 buf
+= put_str(buf
, "\": [");
483 for (r
= 0; r
< mi_rows
; ++r
) {
485 for (c
= 0; c
< mi_cols
; ++c
) {
486 insp_mi_data
*mi
= &frame_data
.mi_grid
[r
* mi_cols
+ c
];
488 for (p
= 0; p
< combined_parm_count
; ++p
) {
489 if (p
) *(buf
++) = ',';
490 int16_t *v
= (int16_t *)(((int8_t *)mi
) +
491 parm_offsets
[combined_parm_list
[p
]].offset
);
492 buf
+= put_num(buf
, 0, v
[0], 0);
495 if (c
< mi_cols
- 1) *(buf
++) = ',';
498 if (r
< mi_rows
- 1) *(buf
++) = ',';
500 buf
+= put_str(buf
, "],\n");
501 return (int)(buf
- buffer
);
504 int put_block_info(char *buffer
, const map_entry
*map
, const char *name
,
505 size_t offset
, int len
) {
506 const int mi_rows
= frame_data
.mi_rows
;
507 const int mi_cols
= frame_data
.mi_cols
;
510 if (compress
&& len
== 1) {
511 die("Can't encode scalars as arrays when RLE compression is enabled.");
514 buf
+= snprintf(buf
, MAX_BUFFER
, " \"%sMap\": {", name
);
515 buf
+= put_map(buf
, map
);
516 buf
+= put_str(buf
, "},\n");
518 buf
+= snprintf(buf
, MAX_BUFFER
, " \"%s\": [", name
);
519 for (r
= 0; r
< mi_rows
; ++r
) {
521 for (c
= 0; c
< mi_cols
; ++c
) {
522 insp_mi_data
*mi
= &frame_data
.mi_grid
[r
* mi_cols
+ c
];
523 int16_t *v
= (int16_t *)(((int8_t *)mi
) + offset
);
525 buf
+= put_num(buf
, 0, v
[0], 0);
527 buf
+= put_str(buf
, "[");
528 for (i
= 0; i
< len
; i
++) {
529 buf
+= put_num(buf
, 0, v
[i
], 0);
531 buf
+= put_str(buf
, ",");
534 buf
+= put_str(buf
, "]");
536 if (compress
) { // RLE
537 for (t
= c
+ 1; t
< mi_cols
; ++t
) {
538 insp_mi_data
*next_mi
= &frame_data
.mi_grid
[r
* mi_cols
+ t
];
539 int16_t *nv
= (int16_t *)(((int8_t *)next_mi
) + offset
);
542 same
= v
[0] == nv
[0];
544 for (i
= 0; i
< len
; i
++) {
545 same
= v
[i
] == nv
[i
];
557 buf
+= put_num(buf
, '[', t
- c
- 1, ']');
561 if (c
< mi_cols
- 1) *(buf
++) = ',';
564 if (r
< mi_rows
- 1) *(buf
++) = ',';
566 buf
+= put_str(buf
, "],\n");
567 return (int)(buf
- buffer
);
570 #if CONFIG_ACCOUNTING
571 int put_accounting(char *buffer
) {
574 const Accounting
*accounting
= frame_data
.accounting
;
575 if (accounting
== NULL
) {
579 const int num_syms
= accounting
->syms
.num_syms
;
580 const int num_strs
= accounting
->syms
.dictionary
.num_strs
;
581 buf
+= put_str(buf
, " \"symbolsMap\": [");
582 for (i
= 0; i
< num_strs
; i
++) {
583 buf
+= snprintf(buf
, MAX_BUFFER
, "\"%s\"",
584 accounting
->syms
.dictionary
.strs
[i
]);
585 if (i
< num_strs
- 1) *(buf
++) = ',';
587 buf
+= put_str(buf
, "],\n");
588 buf
+= put_str(buf
, " \"symbols\": [\n ");
589 AccountingSymbolContext context
;
592 AccountingSymbol
*sym
;
593 for (i
= 0; i
< num_syms
; i
++) {
594 sym
= &accounting
->syms
.syms
[i
];
595 if (memcmp(&context
, &sym
->context
, sizeof(AccountingSymbolContext
)) != 0) {
596 buf
+= put_num(buf
, '[', sym
->context
.x
, 0);
597 buf
+= put_num(buf
, ',', sym
->context
.y
, ']');
599 buf
+= put_num(buf
, '[', sym
->id
, 0);
600 buf
+= put_num(buf
, ',', sym
->bits
, 0);
601 buf
+= put_num(buf
, ',', sym
->samples
, ']');
603 context
= sym
->context
;
604 if (i
< num_syms
- 1) *(buf
++) = ',';
606 buf
+= put_str(buf
, "],\n");
607 return (int)(buf
- buffer
);
611 int skip_non_transform
= 0;
613 void inspect(void *pbi
, void *data
) {
614 /* Fetch frame data. */
615 ifd_inspect(&frame_data
, pbi
, skip_non_transform
);
617 // Show existing frames just show a reference buffer we've already decoded.
618 // There's no information to show.
619 if (frame_data
.show_existing_frame
) return;
622 // We allocate enough space and hope we don't write out of bounds. Totally
623 // unsafe but this speeds things up, especially when compiled to Javascript.
624 char *buffer
= aom_malloc(MAX_BUFFER
);
626 fprintf(stderr
, "Error allocating inspect info buffer\n");
630 buf
+= put_str(buf
, "{\n");
631 if (layers
& BLOCK_SIZE_LAYER
) {
632 buf
+= put_block_info(buf
, block_size_map
, "blockSize",
633 offsetof(insp_mi_data
, bsize
), 0);
635 if (layers
& TRANSFORM_SIZE_LAYER
) {
636 buf
+= put_block_info(buf
, tx_size_map
, "transformSize",
637 offsetof(insp_mi_data
, tx_size
), 0);
639 if (layers
& TRANSFORM_TYPE_LAYER
) {
640 buf
+= put_block_info(buf
, tx_type_map
, "transformType",
641 offsetof(insp_mi_data
, tx_type
), 0);
643 if (layers
& DUAL_FILTER_LAYER
) {
644 buf
+= put_block_info(buf
, dual_filter_map
, "dualFilterType",
645 offsetof(insp_mi_data
, dual_filter_type
), 0);
647 if (layers
& MODE_LAYER
) {
648 buf
+= put_block_info(buf
, prediction_mode_map
, "mode",
649 offsetof(insp_mi_data
, mode
), 0);
651 if (layers
& UV_MODE_LAYER
) {
652 buf
+= put_block_info(buf
, uv_prediction_mode_map
, "uv_mode",
653 offsetof(insp_mi_data
, uv_mode
), 0);
655 if (layers
& MOTION_MODE_LAYER
) {
656 buf
+= put_block_info(buf
, motion_mode_map
, "motion_mode",
657 offsetof(insp_mi_data
, motion_mode
), 0);
659 if (layers
& COMPOUND_TYPE_LAYER
) {
660 buf
+= put_block_info(buf
, compound_type_map
, "compound_type",
661 offsetof(insp_mi_data
, compound_type
), 0);
663 if (layers
& SKIP_LAYER
) {
665 put_block_info(buf
, skip_map
, "skip", offsetof(insp_mi_data
, skip
), 0);
667 if (layers
& FILTER_LAYER
) {
669 put_block_info(buf
, NULL
, "filter", offsetof(insp_mi_data
, filter
), 2);
671 if (layers
& CDEF_LAYER
) {
672 buf
+= put_block_info(buf
, NULL
, "cdef_level",
673 offsetof(insp_mi_data
, cdef_level
), 0);
674 buf
+= put_block_info(buf
, NULL
, "cdef_strength",
675 offsetof(insp_mi_data
, cdef_strength
), 0);
677 if (layers
& CFL_LAYER
) {
678 buf
+= put_block_info(buf
, NULL
, "cfl_alpha_idx",
679 offsetof(insp_mi_data
, cfl_alpha_idx
), 0);
680 buf
+= put_block_info(buf
, NULL
, "cfl_alpha_sign",
681 offsetof(insp_mi_data
, cfl_alpha_sign
), 0);
683 if (layers
& Q_INDEX_LAYER
) {
684 buf
+= put_block_info(buf
, NULL
, "delta_q",
685 offsetof(insp_mi_data
, current_qindex
), 0);
687 if (layers
& SEGMENT_ID_LAYER
) {
688 buf
+= put_block_info(buf
, NULL
, "seg_id",
689 offsetof(insp_mi_data
, segment_id
), 0);
691 if (layers
& MOTION_VECTORS_LAYER
) {
692 buf
+= put_motion_vectors(buf
);
694 if (layers
& INTRABC_LAYER
) {
695 buf
+= put_block_info(buf
, intrabc_map
, "intrabc",
696 offsetof(insp_mi_data
, intrabc
), 0);
698 if (layers
& PALETTE_LAYER
) {
699 buf
+= put_block_info(buf
, palette_map
, "palette",
700 offsetof(insp_mi_data
, palette
), 0);
702 if (layers
& UV_PALETTE_LAYER
) {
703 buf
+= put_block_info(buf
, palette_map
, "uv_palette",
704 offsetof(insp_mi_data
, uv_palette
), 0);
706 if (combined_parm_count
> 0) buf
+= put_combined(buf
);
707 if (layers
& REFERENCE_FRAME_LAYER
) {
708 buf
+= put_block_info(buf
, refs_map
, "referenceFrame",
709 offsetof(insp_mi_data
, ref_frame
), 2);
711 #if CONFIG_ACCOUNTING
712 if (layers
& ACCOUNTING_LAYER
) {
713 buf
+= put_accounting(buf
);
717 snprintf(buf
, MAX_BUFFER
, " \"frame\": %d,\n", frame_data
.frame_number
);
718 buf
+= snprintf(buf
, MAX_BUFFER
, " \"showFrame\": %d,\n",
719 frame_data
.show_frame
);
720 buf
+= snprintf(buf
, MAX_BUFFER
, " \"frameType\": %d,\n",
721 frame_data
.frame_type
);
722 buf
+= snprintf(buf
, MAX_BUFFER
, " \"baseQIndex\": %d,\n",
723 frame_data
.base_qindex
);
724 buf
+= snprintf(buf
, MAX_BUFFER
, " \"tileCols\": %d,\n",
725 frame_data
.tile_mi_cols
);
726 buf
+= snprintf(buf
, MAX_BUFFER
, " \"tileRows\": %d,\n",
727 frame_data
.tile_mi_rows
);
728 buf
+= snprintf(buf
, MAX_BUFFER
, " \"deltaQPresentFlag\": %d,\n",
729 frame_data
.delta_q_present_flag
);
730 buf
+= snprintf(buf
, MAX_BUFFER
, " \"deltaQRes\": %d,\n",
731 frame_data
.delta_q_res
);
732 buf
+= put_str(buf
, " \"config\": {");
733 buf
+= put_map(buf
, config_map
);
734 buf
+= put_str(buf
, "},\n");
735 buf
+= put_str(buf
, " \"configString\": \"");
736 buf
+= put_str_with_escape(buf
, aom_codec_build_config());
737 buf
+= put_str(buf
, "\"\n");
738 decoded_frame_count
++;
739 buf
+= put_str(buf
, "},\n");
741 on_frame_decoded_dump(buffer
);
745 void ifd_init_cb(void) {
747 ii
.inspect_cb
= inspect
;
748 ii
.inspect_ctx
= NULL
;
749 aom_codec_control(&codec
, AV1_SET_INSPECTION_CALLBACK
, &ii
);
753 int open_file(char *file
) {
755 // The JS analyzer puts the .ivf file at this location.
756 file
= "/tmp/input.ivf";
758 reader
= aom_video_reader_open(file
);
759 if (!reader
) die("Failed to open %s for reading.", file
);
760 info
= aom_video_reader_get_info(reader
);
761 aom_codec_iface_t
*decoder
= get_aom_decoder_by_fourcc(info
->codec_fourcc
);
762 if (!decoder
) die("Unknown input codec.");
763 fprintf(stderr
, "Using %s\n", aom_codec_iface_name(decoder
));
764 if (aom_codec_dec_init(&codec
, decoder
, NULL
, 0))
765 die("Failed to initialize decoder.");
766 ifd_init(&frame_data
, info
->frame_width
, info
->frame_height
);
773 const unsigned char *frame
;
774 const unsigned char *end_frame
;
775 size_t frame_size
= 0;
778 int read_frame(void) {
781 // This loop skips over any frames that are show_existing_frames, as
782 // there is nothing to analyze.
785 if (!aom_video_reader_read_frame(reader
)) return EXIT_FAILURE
;
786 frame
= aom_video_reader_get_frame(reader
, &frame_size
);
789 end_frame
= frame
+ frame_size
;
792 if (aom_codec_decode(&codec
, frame
, (unsigned int)frame_size
, &adr
) !=
794 die_codec(&codec
, "Failed to decode frame.");
798 frame_size
= end_frame
- frame
;
799 if (frame
== end_frame
) have_frame
= 0;
800 } while (adr
.show_existing
);
802 int got_any_frames
= 0;
803 aom_image_t
*frame_img
;
804 struct av1_ref_frame ref_dec
;
805 ref_dec
.idx
= adr
.idx
;
807 // ref_dec.idx is the index to the reference buffer idx to AV1_GET_REFERENCE
808 // if its -1 the decoder didn't update any reference buffer and the only
809 // way to see the frame is aom_codec_get_frame.
810 if (ref_dec
.idx
== -1) {
811 aom_codec_iter_t iter
= NULL
;
812 img
= frame_img
= aom_codec_get_frame(&codec
, &iter
);
815 } else if (!aom_codec_control(&codec
, AV1_GET_REFERENCE
, &ref_dec
)) {
816 img
= frame_img
= &ref_dec
.img
;
820 if (!got_any_frames
) {
827 const char *get_aom_codec_build_config(void) {
828 return aom_codec_build_config();
832 int get_bit_depth(void) { return img
->bit_depth
; }
835 int get_bits_per_sample(void) { return img
->bps
; }
838 int get_image_format(void) { return img
->fmt
; }
841 unsigned char *get_plane(int plane
) { return img
->planes
[plane
]; }
844 int get_plane_stride(int plane
) { return img
->stride
[plane
]; }
847 int get_plane_width(int plane
) { return aom_img_plane_width(img
, plane
); }
850 int get_plane_height(int plane
) { return aom_img_plane_height(img
, plane
); }
853 int get_frame_width(void) { return info
->frame_width
; }
856 int get_frame_height(void) { return info
->frame_height
; }
858 static void parse_args(char **argv
) {
861 (void)dump_accounting_arg
;
863 for (argi
= argj
= argv
; (*argj
= *argi
); argi
+= arg
.argv_step
) {
865 if (arg_match(&arg
, &dump_block_size_arg
, argi
)) layers
|= BLOCK_SIZE_LAYER
;
866 #if CONFIG_ACCOUNTING
867 else if (arg_match(&arg
, &dump_accounting_arg
, argi
))
868 layers
|= ACCOUNTING_LAYER
;
870 else if (arg_match(&arg
, &dump_transform_size_arg
, argi
))
871 layers
|= TRANSFORM_SIZE_LAYER
;
872 else if (arg_match(&arg
, &dump_transform_type_arg
, argi
))
873 layers
|= TRANSFORM_TYPE_LAYER
;
874 else if (arg_match(&arg
, &dump_mode_arg
, argi
))
875 layers
|= MODE_LAYER
;
876 else if (arg_match(&arg
, &dump_uv_mode_arg
, argi
))
877 layers
|= UV_MODE_LAYER
;
878 else if (arg_match(&arg
, &dump_motion_mode_arg
, argi
))
879 layers
|= MOTION_MODE_LAYER
;
880 else if (arg_match(&arg
, &dump_compound_type_arg
, argi
))
881 layers
|= COMPOUND_TYPE_LAYER
;
882 else if (arg_match(&arg
, &dump_skip_arg
, argi
))
883 layers
|= SKIP_LAYER
;
884 else if (arg_match(&arg
, &dump_filter_arg
, argi
))
885 layers
|= FILTER_LAYER
;
886 else if (arg_match(&arg
, &dump_cdef_arg
, argi
))
887 layers
|= CDEF_LAYER
;
888 else if (arg_match(&arg
, &dump_cfl_arg
, argi
))
890 else if (arg_match(&arg
, &dump_reference_frame_arg
, argi
))
891 layers
|= REFERENCE_FRAME_LAYER
;
892 else if (arg_match(&arg
, &dump_motion_vectors_arg
, argi
))
893 layers
|= MOTION_VECTORS_LAYER
;
894 else if (arg_match(&arg
, &dump_dual_filter_type_arg
, argi
))
895 layers
|= DUAL_FILTER_LAYER
;
896 else if (arg_match(&arg
, &dump_delta_q_arg
, argi
))
897 layers
|= Q_INDEX_LAYER
;
898 else if (arg_match(&arg
, &dump_seg_id_arg
, argi
))
899 layers
|= SEGMENT_ID_LAYER
;
900 else if (arg_match(&arg
, &dump_intrabc_arg
, argi
))
901 layers
|= INTRABC_LAYER
;
902 else if (arg_match(&arg
, &dump_palette_arg
, argi
))
903 layers
|= PALETTE_LAYER
;
904 else if (arg_match(&arg
, &dump_uv_palette_arg
, argi
))
905 layers
|= UV_PALETTE_LAYER
;
906 else if (arg_match(&arg
, &dump_all_arg
, argi
))
907 layers
|= ALL_LAYERS
;
908 else if (arg_match(&arg
, &compress_arg
, argi
))
910 else if (arg_match(&arg
, &usage_arg
, argi
))
912 else if (arg_match(&arg
, &limit_arg
, argi
))
913 stop_after
= arg_parse_uint(&arg
);
914 else if (arg_match(&arg
, &skip_non_transform_arg
, argi
))
915 skip_non_transform
= arg_parse_uint(&arg
);
916 else if (arg_match(&arg
, &combined_arg
, argi
))
918 (char *)arg
.val
, combined_parm_list
,
919 sizeof(combined_parm_list
) / sizeof(combined_parm_list
[0]),
920 &combined_parm_count
);
926 static const char *exec_name
;
928 void usage_exit(void) {
929 fprintf(stderr
, "Usage: %s src_filename <options>\n", exec_name
);
930 fprintf(stderr
, "\nOptions:\n");
931 arg_show_usage(stderr
, main_args
);
936 int main(int argc
, char **argv
) {
943 if (stop_after
&& (decoded_frame_count
>= stop_after
)) break;
944 if (read_frame()) break;
955 if (aom_codec_destroy(&codec
)) die_codec(&codec
, "Failed to destroy codec");
956 aom_video_reader_close(reader
);
960 void set_layers(LayerType v
) { layers
= v
; }
963 void set_compress(int v
) { compress
= v
; }