blob: ceb7fc265957a80f07a544eb409bd4d24b7c82f8 [file] [log] [blame]
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -08001/*
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#include "./args.h"
23#ifdef __EMSCRIPTEN__
24#include <emscripten.h>
25#else
26#define EMSCRIPTEN_KEEPALIVE
27#endif
28
29#include "aom/aom_decoder.h"
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -080030#include "./aom_config.h"
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -080031#if CONFIG_ACCOUNTING
Luc Trudeau83fbd572017-04-21 11:24:34 -040032#include "../av1/decoder/accounting.h"
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -080033#endif
34#include "../av1/decoder/inspection.h"
Nathan E. Egge1e412752017-05-04 21:09:39 -040035#include "aom/aomdx.h"
36
37#include "../tools_common.h"
38#include "../video_reader.h"
39// #include "av1/av1_dx_iface.c"
40#include "../av1/common/onyxc_int.h"
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -080041
42#include "../video_common.h"
43
44// Max JSON buffer size.
45const int MAX_BUFFER = 1024 * 1024 * 32;
46
47typedef 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,
Luc Trudeau0be435a2017-04-07 23:38:52 -040058 UV_MODE_LAYER = 1 << 10,
Luc Trudeauf89056a2017-04-28 16:07:22 -040059 CFL_LAYER = 1 << 11,
Ankur Saxena6e6b6972017-10-20 22:10:10 -070060 DUAL_FILTER_LAYER = 1 << 12,
Yushin Choc24351c2017-10-24 14:59:08 -070061 Q_INDEX_LAYER = 1 << 13,
Yushin Cho4be87e02017-10-25 16:27:04 -070062 SEGMENT_ID_LAYER = 1 << 14,
63 ALL_LAYERS = (1 << 15) - 1
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -080064} LayerType;
65
66static LayerType layers = 0;
67
68static int stop_after = 0;
Michael Bebenitaf1207b62017-04-14 22:30:56 -070069static int compress = 0;
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -080070
71static const arg_def_t limit_arg =
72 ARG_DEF(NULL, "limit", 1, "Stop decoding after n frames");
73static const arg_def_t dump_all_arg = ARG_DEF("A", "all", 0, "Dump All");
Michael Bebenitaf1207b62017-04-14 22:30:56 -070074static const arg_def_t compress_arg =
75 ARG_DEF("x", "compress", 0, "Compress JSON using RLE");
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -080076static const arg_def_t dump_accounting_arg =
77 ARG_DEF("a", "accounting", 0, "Dump Accounting");
78static const arg_def_t dump_block_size_arg =
79 ARG_DEF("bs", "blockSize", 0, "Dump Block Size");
80static const arg_def_t dump_motion_vectors_arg =
81 ARG_DEF("mv", "motionVectors", 0, "Dump Motion Vectors");
82static const arg_def_t dump_transform_size_arg =
83 ARG_DEF("ts", "transformSize", 0, "Dump Transform Size");
84static const arg_def_t dump_transform_type_arg =
85 ARG_DEF("tt", "transformType", 0, "Dump Transform Type");
86static const arg_def_t dump_mode_arg = ARG_DEF("m", "mode", 0, "Dump Mode");
Luc Trudeau0be435a2017-04-07 23:38:52 -040087static const arg_def_t dump_uv_mode_arg =
88 ARG_DEF("uvm", "uv_mode", 0, "Dump UV Intra Prediction Modes");
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -080089static const arg_def_t dump_skip_arg = ARG_DEF("s", "skip", 0, "Dump Skip");
90static const arg_def_t dump_filter_arg =
91 ARG_DEF("f", "filter", 0, "Dump Filter");
92static const arg_def_t dump_cdef_arg = ARG_DEF("c", "cdef", 0, "Dump CDEF");
Luc Trudeauf89056a2017-04-28 16:07:22 -040093static const arg_def_t dump_cfl_arg =
94 ARG_DEF("cfl", "chroma_from_luma", 0, "Dump Chroma from Luma Alphas");
Ankur Saxena6e6b6972017-10-20 22:10:10 -070095static const arg_def_t dump_dual_filter_type_arg =
96 ARG_DEF("df", "dualFilterType", 0, "Dump Dual Filter Type");
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -080097static const arg_def_t dump_reference_frame_arg =
98 ARG_DEF("r", "referenceFrame", 0, "Dump Reference Frame");
Yushin Choc24351c2017-10-24 14:59:08 -070099static const arg_def_t dump_delta_q_arg =
100 ARG_DEF("dq", "delta_q", 0, "Dump QIndex");
Yushin Cho4be87e02017-10-25 16:27:04 -0700101static const arg_def_t dump_seg_id_arg =
102 ARG_DEF("si", "seg_id", 0, "Dump Segment ID");
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800103static const arg_def_t usage_arg = ARG_DEF("h", "help", 0, "Help");
104
105static const arg_def_t *main_args[] = { &limit_arg,
106 &dump_all_arg,
Michael Bebenitaf1207b62017-04-14 22:30:56 -0700107 &compress_arg,
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800108#if CONFIG_ACCOUNTING
109 &dump_accounting_arg,
110#endif
111 &dump_block_size_arg,
112 &dump_transform_size_arg,
113 &dump_transform_type_arg,
114 &dump_mode_arg,
Luc Trudeau0be435a2017-04-07 23:38:52 -0400115 &dump_uv_mode_arg,
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800116 &dump_skip_arg,
117 &dump_filter_arg,
118 &dump_cdef_arg,
Ankur Saxena6e6b6972017-10-20 22:10:10 -0700119 &dump_dual_filter_type_arg,
Luc Trudeauf89056a2017-04-28 16:07:22 -0400120 &dump_cfl_arg,
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800121 &dump_reference_frame_arg,
122 &dump_motion_vectors_arg,
Yushin Choc24351c2017-10-24 14:59:08 -0700123 &dump_delta_q_arg,
Yushin Cho4be87e02017-10-25 16:27:04 -0700124 &dump_seg_id_arg,
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800125 &usage_arg,
126 NULL };
127#define ENUM(name) \
128 { #name, name }
129#define LAST_ENUM \
130 { NULL, 0 }
131typedef struct map_entry {
132 const char *name;
133 int value;
134} map_entry;
135
Michael Bebenitab9f52562017-10-30 16:18:18 -0700136const map_entry refs_map[] = {
137 ENUM(INTRA_FRAME), ENUM(LAST_FRAME), ENUM(LAST2_FRAME),
138 ENUM(LAST3_FRAME), ENUM(GOLDEN_FRAME), ENUM(BWDREF_FRAME),
139 ENUM(ALTREF2_FRAME), ENUM(ALTREF_FRAME), LAST_ENUM
140};
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800141
Yue Chen8fe9eda2018-03-21 14:41:58 -0700142const map_entry block_size_map[] = {
143 ENUM(BLOCK_4X4), ENUM(BLOCK_4X8), ENUM(BLOCK_8X4),
144 ENUM(BLOCK_8X8), ENUM(BLOCK_8X16), ENUM(BLOCK_16X8),
145 ENUM(BLOCK_16X16), ENUM(BLOCK_16X32), ENUM(BLOCK_32X16),
146 ENUM(BLOCK_32X32), ENUM(BLOCK_32X64), ENUM(BLOCK_64X32),
147 ENUM(BLOCK_64X64), ENUM(BLOCK_64X128), ENUM(BLOCK_128X64),
148 ENUM(BLOCK_128X128), ENUM(BLOCK_4X16), ENUM(BLOCK_16X4),
149 ENUM(BLOCK_8X32), ENUM(BLOCK_32X8), ENUM(BLOCK_16X64),
150 ENUM(BLOCK_64X16), LAST_ENUM
151};
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800152
153const map_entry tx_size_map[] = {
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800154 ENUM(TX_4X4), ENUM(TX_8X8), ENUM(TX_16X16), ENUM(TX_32X32),
Yaowu Xud3d41592018-02-14 13:26:52 -0800155 ENUM(TX_64X64), ENUM(TX_4X8), ENUM(TX_8X4), ENUM(TX_8X16),
156 ENUM(TX_16X8), ENUM(TX_16X32), ENUM(TX_32X16), ENUM(TX_32X64),
157 ENUM(TX_64X32), ENUM(TX_4X16), ENUM(TX_16X4), ENUM(TX_8X32),
158 ENUM(TX_32X8), LAST_ENUM
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800159};
160
161const map_entry tx_type_map[] = { ENUM(DCT_DCT),
162 ENUM(ADST_DCT),
163 ENUM(DCT_ADST),
164 ENUM(ADST_ADST),
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800165 ENUM(FLIPADST_DCT),
166 ENUM(DCT_FLIPADST),
167 ENUM(FLIPADST_FLIPADST),
168 ENUM(ADST_FLIPADST),
169 ENUM(FLIPADST_ADST),
170 ENUM(IDTX),
171 ENUM(V_DCT),
172 ENUM(H_DCT),
173 ENUM(V_ADST),
174 ENUM(H_ADST),
175 ENUM(V_FLIPADST),
176 ENUM(H_FLIPADST),
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800177 LAST_ENUM };
Ankur Saxena6e6b6972017-10-20 22:10:10 -0700178const map_entry dual_filter_map[] = { ENUM(REG_REG), ENUM(REG_SMOOTH),
179 ENUM(REG_SHARP), ENUM(SMOOTH_REG),
180 ENUM(SMOOTH_SMOOTH), ENUM(SMOOTH_SHARP),
181 ENUM(SHARP_REG), ENUM(SHARP_SMOOTH),
182 ENUM(SHARP_SHARP), LAST_ENUM };
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800183
Sebastien Alaiwan0bdea0d2017-10-02 15:15:05 +0200184const map_entry prediction_mode_map[] = {
Urvang Joshib7301cd2017-11-09 15:08:56 -0800185 ENUM(DC_PRED), ENUM(V_PRED), ENUM(H_PRED),
Hui Su69ae7b82018-02-20 20:10:51 -0800186 ENUM(D45_PRED), ENUM(D135_PRED), ENUM(D113_PRED),
187 ENUM(D157_PRED), ENUM(D203_PRED), ENUM(D67_PRED),
Urvang Joshib7301cd2017-11-09 15:08:56 -0800188 ENUM(SMOOTH_PRED), ENUM(SMOOTH_V_PRED), ENUM(SMOOTH_H_PRED),
189 ENUM(PAETH_PRED), ENUM(NEARESTMV), ENUM(NEARMV),
190 ENUM(GLOBALMV), ENUM(NEWMV), ENUM(NEAREST_NEARESTMV),
191 ENUM(NEAR_NEARMV), ENUM(NEAREST_NEWMV), ENUM(NEW_NEARESTMV),
192 ENUM(NEAR_NEWMV), ENUM(NEW_NEARMV), ENUM(GLOBAL_GLOBALMV),
193 ENUM(NEW_NEWMV), ENUM(INTRA_INVALID), LAST_ENUM
Sebastien Alaiwan0bdea0d2017-10-02 15:15:05 +0200194};
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800195
Luc Trudeaud6d9eee2017-07-12 12:36:50 -0400196const map_entry uv_prediction_mode_map[] = {
Luc Trudeau6e1cd782017-06-21 13:52:36 -0400197 ENUM(UV_DC_PRED), ENUM(UV_V_PRED),
198 ENUM(UV_H_PRED), ENUM(UV_D45_PRED),
Hui Su69ae7b82018-02-20 20:10:51 -0800199 ENUM(UV_D135_PRED), ENUM(UV_D113_PRED),
200 ENUM(UV_D157_PRED), ENUM(UV_D203_PRED),
201 ENUM(UV_D67_PRED), ENUM(UV_SMOOTH_PRED),
Luc Trudeaud6d9eee2017-07-12 12:36:50 -0400202 ENUM(UV_SMOOTH_V_PRED), ENUM(UV_SMOOTH_H_PRED),
Luc Trudeau3ec16a32018-03-01 20:58:09 -0500203 ENUM(UV_PAETH_PRED), ENUM(UV_CFL_PRED),
Luc Trudeau6e1cd782017-06-21 13:52:36 -0400204 ENUM(UV_MODE_INVALID), LAST_ENUM
Luc Trudeaud6d9eee2017-07-12 12:36:50 -0400205};
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800206#define NO_SKIP 0
207#define SKIP 1
208
209const map_entry skip_map[] = { ENUM(SKIP), ENUM(NO_SKIP), LAST_ENUM };
210
211const map_entry config_map[] = { ENUM(MI_SIZE), LAST_ENUM };
212
213static const char *exec_name;
214
215insp_frame_data frame_data;
216int frame_count = 0;
217int decoded_frame_count = 0;
218aom_codec_ctx_t codec;
219AvxVideoReader *reader = NULL;
220const AvxVideoInfo *info = NULL;
221aom_image_t *img = NULL;
222
223void on_frame_decoded_dump(char *json) {
224#ifdef __EMSCRIPTEN__
225 EM_ASM_({ Module.on_frame_decoded_json($0); }, json);
226#else
227 printf("%s", json);
228#endif
229}
230
231// Writing out the JSON buffer using snprintf is very slow, especially when
232// compiled with emscripten, these functions speed things up quite a bit.
233int put_str(char *buffer, const char *str) {
234 int i;
235 for (i = 0; str[i] != '\0'; i++) {
236 buffer[i] = str[i];
237 }
238 return i;
239}
240
Michael Bebenita4aee17d2017-07-05 14:03:36 -0700241int put_str_with_escape(char *buffer, const char *str) {
242 int i;
243 int j = 0;
244 for (i = 0; str[i] != '\0'; i++) {
Thomas Daede3a1bd782017-07-21 12:17:10 -0700245 if (str[i] < ' ') {
246 continue;
247 } else if (str[i] == '"' || str[i] == '\\') {
Michael Bebenita4aee17d2017-07-05 14:03:36 -0700248 buffer[j++] = '\\';
249 }
250 buffer[j++] = str[i];
251 }
252 return j;
253}
254
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800255int put_num(char *buffer, char prefix, int num, char suffix) {
256 int i = 0;
257 char *buf = buffer;
258 int is_neg = 0;
259 if (prefix) {
260 buf[i++] = prefix;
261 }
262 if (num == 0) {
263 buf[i++] = '0';
264 } else {
265 if (num < 0) {
266 num = -num;
267 is_neg = 1;
268 }
269 int s = i;
270 while (num != 0) {
271 buf[i++] = '0' + (num % 10);
272 num = num / 10;
273 }
274 if (is_neg) {
275 buf[i++] = '-';
276 }
277 int e = i - 1;
278 while (s < e) {
279 int t = buf[s];
280 buf[s] = buf[e];
281 buf[e] = t;
282 s++;
283 e--;
284 }
285 }
286 if (suffix) {
287 buf[i++] = suffix;
288 }
289 return i;
290}
291
292int put_map(char *buffer, const map_entry *map) {
293 char *buf = buffer;
294 const map_entry *entry = map;
295 while (entry->name != NULL) {
296 *(buf++) = '"';
297 buf += put_str(buf, entry->name);
298 *(buf++) = '"';
299 buf += put_num(buf, ':', entry->value, 0);
300 entry++;
301 if (entry->name != NULL) {
302 *(buf++) = ',';
303 }
304 }
Yushin Chof6741572017-10-24 20:07:46 -0700305 return (int)(buf - buffer);
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800306}
307
308int put_reference_frame(char *buffer) {
309 const int mi_rows = frame_data.mi_rows;
310 const int mi_cols = frame_data.mi_cols;
311 char *buf = buffer;
Michael Bebenitaf1207b62017-04-14 22:30:56 -0700312 int r, c, t;
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800313 buf += put_str(buf, " \"referenceFrameMap\": {");
314 buf += put_map(buf, refs_map);
315 buf += put_str(buf, "},\n");
316 buf += put_str(buf, " \"referenceFrame\": [");
317 for (r = 0; r < mi_rows; ++r) {
318 *(buf++) = '[';
319 for (c = 0; c < mi_cols; ++c) {
320 insp_mi_data *mi = &frame_data.mi_grid[r * mi_cols + c];
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800321 buf += put_num(buf, '[', mi->ref_frame[0], 0);
322 buf += put_num(buf, ',', mi->ref_frame[1], ']');
Michael Bebenitaf1207b62017-04-14 22:30:56 -0700323 if (compress) { // RLE
324 for (t = c + 1; t < mi_cols; ++t) {
325 insp_mi_data *next_mi = &frame_data.mi_grid[r * mi_cols + t];
326 if (mi->ref_frame[0] != next_mi->ref_frame[0] ||
327 mi->ref_frame[1] != next_mi->ref_frame[1]) {
328 break;
329 }
330 }
331 if (t - c > 1) {
332 *(buf++) = ',';
333 buf += put_num(buf, '[', t - c - 1, ']');
334 c = t - 1;
335 }
336 }
337 if (c < mi_cols - 1) *(buf++) = ',';
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800338 }
339 *(buf++) = ']';
340 if (r < mi_rows - 1) *(buf++) = ',';
341 }
342 buf += put_str(buf, "],\n");
Yushin Chof6741572017-10-24 20:07:46 -0700343 return (int)(buf - buffer);
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800344}
345
346int put_motion_vectors(char *buffer) {
347 const int mi_rows = frame_data.mi_rows;
348 const int mi_cols = frame_data.mi_cols;
349 char *buf = buffer;
Michael Bebenitaf1207b62017-04-14 22:30:56 -0700350 int r, c, t;
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800351 buf += put_str(buf, " \"motionVectors\": [");
352 for (r = 0; r < mi_rows; ++r) {
353 *(buf++) = '[';
354 for (c = 0; c < mi_cols; ++c) {
355 insp_mi_data *mi = &frame_data.mi_grid[r * mi_cols + c];
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800356 buf += put_num(buf, '[', mi->mv[0].col, 0);
357 buf += put_num(buf, ',', mi->mv[0].row, 0);
358 buf += put_num(buf, ',', mi->mv[1].col, 0);
359 buf += put_num(buf, ',', mi->mv[1].row, ']');
Michael Bebenitaf1207b62017-04-14 22:30:56 -0700360 if (compress) { // RLE
361 for (t = c + 1; t < mi_cols; ++t) {
362 insp_mi_data *next_mi = &frame_data.mi_grid[r * mi_cols + t];
363 if (mi->mv[0].col != next_mi->mv[0].col ||
364 mi->mv[0].row != next_mi->mv[0].row ||
365 mi->mv[1].col != next_mi->mv[1].col ||
366 mi->mv[1].row != next_mi->mv[1].row) {
367 break;
368 }
369 }
370 if (t - c > 1) {
371 *(buf++) = ',';
372 buf += put_num(buf, '[', t - c - 1, ']');
373 c = t - 1;
374 }
375 }
376 if (c < mi_cols - 1) *(buf++) = ',';
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800377 }
378 *(buf++) = ']';
379 if (r < mi_rows - 1) *(buf++) = ',';
380 }
381 buf += put_str(buf, "],\n");
Yushin Chof6741572017-10-24 20:07:46 -0700382 return (int)(buf - buffer);
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800383}
384
385int put_block_info(char *buffer, const map_entry *map, const char *name,
Michael Bebenita14e1b742017-10-24 12:49:15 -0700386 size_t offset, int len) {
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800387 const int mi_rows = frame_data.mi_rows;
388 const int mi_cols = frame_data.mi_cols;
389 char *buf = buffer;
Michael Bebenita14e1b742017-10-24 12:49:15 -0700390 int r, c, t, i;
391 if (compress && len == 1) {
392 die("Can't encode scalars as arrays when RLE compression is enabled.");
393 return -1;
394 }
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800395 if (map) {
396 buf += snprintf(buf, MAX_BUFFER, " \"%sMap\": {", name);
397 buf += put_map(buf, map);
398 buf += put_str(buf, "},\n");
399 }
400 buf += snprintf(buf, MAX_BUFFER, " \"%s\": [", name);
401 for (r = 0; r < mi_rows; ++r) {
402 *(buf++) = '[';
403 for (c = 0; c < mi_cols; ++c) {
Michael Bebenita14e1b742017-10-24 12:49:15 -0700404 insp_mi_data *mi = &frame_data.mi_grid[r * mi_cols + c];
Yushin Choc24351c2017-10-24 14:59:08 -0700405 int16_t *v = (int16_t *)(((int8_t *)mi) + offset);
Michael Bebenita14e1b742017-10-24 12:49:15 -0700406 if (len == 0) {
407 buf += put_num(buf, 0, v[0], 0);
408 } else {
409 buf += put_str(buf, "[");
410 for (i = 0; i < len; i++) {
411 buf += put_num(buf, 0, v[i], 0);
412 if (i < len - 1) {
413 buf += put_str(buf, ",");
414 }
415 }
416 buf += put_str(buf, "]");
417 }
Michael Bebenitaf1207b62017-04-14 22:30:56 -0700418 if (compress) { // RLE
419 for (t = c + 1; t < mi_cols; ++t) {
420 insp_mi_data *next_mi = &frame_data.mi_grid[r * mi_cols + t];
Yushin Choc24351c2017-10-24 14:59:08 -0700421 int16_t *nv = (int16_t *)(((int8_t *)next_mi) + offset);
Michael Bebenita14e1b742017-10-24 12:49:15 -0700422 int same = 0;
423 if (len == 0) {
424 same = v[0] == nv[0];
425 } else {
426 for (i = 0; i < len; i++) {
427 same = v[i] == nv[i];
428 if (!same) {
429 break;
430 }
431 }
432 }
433 if (!same) {
Michael Bebenitaf1207b62017-04-14 22:30:56 -0700434 break;
435 }
436 }
437 if (t - c > 1) {
438 *(buf++) = ',';
439 buf += put_num(buf, '[', t - c - 1, ']');
440 c = t - 1;
441 }
442 }
443 if (c < mi_cols - 1) *(buf++) = ',';
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800444 }
445 *(buf++) = ']';
446 if (r < mi_rows - 1) *(buf++) = ',';
447 }
448 buf += put_str(buf, "],\n");
Yushin Chof6741572017-10-24 20:07:46 -0700449 return (int)(buf - buffer);
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800450}
451
452#if CONFIG_ACCOUNTING
453int put_accounting(char *buffer) {
454 char *buf = buffer;
455 int i;
456 const Accounting *accounting = frame_data.accounting;
457 if (accounting == NULL) {
458 printf("XXX\n");
459 return 0;
460 }
461 const int num_syms = accounting->syms.num_syms;
462 const int num_strs = accounting->syms.dictionary.num_strs;
463 buf += put_str(buf, " \"symbolsMap\": [");
464 for (i = 0; i < num_strs; i++) {
465 buf += snprintf(buf, MAX_BUFFER, "\"%s\"",
466 accounting->syms.dictionary.strs[i]);
467 if (i < num_strs - 1) *(buf++) = ',';
468 }
469 buf += put_str(buf, "],\n");
470 buf += put_str(buf, " \"symbols\": [\n ");
471 AccountingSymbolContext context;
472 context.x = -2;
473 context.y = -2;
474 AccountingSymbol *sym;
475 for (i = 0; i < num_syms; i++) {
476 sym = &accounting->syms.syms[i];
477 if (memcmp(&context, &sym->context, sizeof(AccountingSymbolContext)) != 0) {
478 buf += put_num(buf, '[', sym->context.x, 0);
479 buf += put_num(buf, ',', sym->context.y, ']');
480 } else {
481 buf += put_num(buf, '[', sym->id, 0);
482 buf += put_num(buf, ',', sym->bits, 0);
483 buf += put_num(buf, ',', sym->samples, ']');
484 }
485 context = sym->context;
486 if (i < num_syms - 1) *(buf++) = ',';
487 }
488 buf += put_str(buf, "],\n");
Yushin Chof6741572017-10-24 20:07:46 -0700489 return (int)(buf - buffer);
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800490}
491#endif
492
493void inspect(void *pbi, void *data) {
494 /* Fetch frame data. */
495 ifd_inspect(&frame_data, pbi);
496 (void)data;
497 // We allocate enough space and hope we don't write out of bounds. Totally
498 // unsafe but this speeds things up, especially when compiled to Javascript.
499 char *buffer = aom_malloc(MAX_BUFFER);
500 char *buf = buffer;
501 buf += put_str(buf, "{\n");
502 if (layers & BLOCK_SIZE_LAYER) {
503 buf += put_block_info(buf, block_size_map, "blockSize",
Michael Bebenita14e1b742017-10-24 12:49:15 -0700504 offsetof(insp_mi_data, sb_type), 0);
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800505 }
506 if (layers & TRANSFORM_SIZE_LAYER) {
507 buf += put_block_info(buf, tx_size_map, "transformSize",
Michael Bebenita14e1b742017-10-24 12:49:15 -0700508 offsetof(insp_mi_data, tx_size), 0);
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800509 }
510 if (layers & TRANSFORM_TYPE_LAYER) {
511 buf += put_block_info(buf, tx_type_map, "transformType",
Michael Bebenita14e1b742017-10-24 12:49:15 -0700512 offsetof(insp_mi_data, tx_type), 0);
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800513 }
Ankur Saxena6e6b6972017-10-20 22:10:10 -0700514 if (layers & DUAL_FILTER_LAYER) {
515 buf += put_block_info(buf, dual_filter_map, "dualFilterType",
Michael Bebenita14e1b742017-10-24 12:49:15 -0700516 offsetof(insp_mi_data, dual_filter_type), 0);
Ankur Saxena6e6b6972017-10-20 22:10:10 -0700517 }
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800518 if (layers & MODE_LAYER) {
519 buf += put_block_info(buf, prediction_mode_map, "mode",
Michael Bebenita14e1b742017-10-24 12:49:15 -0700520 offsetof(insp_mi_data, mode), 0);
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800521 }
Luc Trudeau0be435a2017-04-07 23:38:52 -0400522 if (layers & UV_MODE_LAYER) {
Luc Trudeaud6d9eee2017-07-12 12:36:50 -0400523 buf += put_block_info(buf, uv_prediction_mode_map, "uv_mode",
Michael Bebenita14e1b742017-10-24 12:49:15 -0700524 offsetof(insp_mi_data, uv_mode), 0);
Luc Trudeau0be435a2017-04-07 23:38:52 -0400525 }
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800526 if (layers & SKIP_LAYER) {
Michael Bebenita14e1b742017-10-24 12:49:15 -0700527 buf +=
Michael Bebenita7a144cd2017-11-07 11:26:34 -0800528 put_block_info(buf, skip_map, "skip", offsetof(insp_mi_data, skip), 0);
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800529 }
530 if (layers & FILTER_LAYER) {
Michael Bebenita14e1b742017-10-24 12:49:15 -0700531 buf +=
532 put_block_info(buf, NULL, "filter", offsetof(insp_mi_data, filter), 2);
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800533 }
534 if (layers & CDEF_LAYER) {
Michael Bebenita09558812017-04-01 20:10:53 -0700535 buf += put_block_info(buf, NULL, "cdef_level",
Michael Bebenita14e1b742017-10-24 12:49:15 -0700536 offsetof(insp_mi_data, cdef_level), 0);
Michael Bebenita09558812017-04-01 20:10:53 -0700537 buf += put_block_info(buf, NULL, "cdef_strength",
Michael Bebenita14e1b742017-10-24 12:49:15 -0700538 offsetof(insp_mi_data, cdef_strength), 0);
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800539 }
Luc Trudeauf89056a2017-04-28 16:07:22 -0400540 if (layers & CFL_LAYER) {
Luc Trudeaua9bd85f2017-05-11 14:37:56 -0400541 buf += put_block_info(buf, NULL, "cfl_alpha_idx",
Michael Bebenita14e1b742017-10-24 12:49:15 -0700542 offsetof(insp_mi_data, cfl_alpha_idx), 0);
Luc Trudeau9bab28b2017-05-11 15:23:02 -0400543 buf += put_block_info(buf, NULL, "cfl_alpha_sign",
Michael Bebenita14e1b742017-10-24 12:49:15 -0700544 offsetof(insp_mi_data, cfl_alpha_sign), 0);
Luc Trudeauf89056a2017-04-28 16:07:22 -0400545 }
Yushin Choc24351c2017-10-24 14:59:08 -0700546 if (layers & Q_INDEX_LAYER) {
547 buf += put_block_info(buf, NULL, "delta_q",
548 offsetof(insp_mi_data, current_qindex), 0);
549 }
Yushin Cho4be87e02017-10-25 16:27:04 -0700550 if (layers & SEGMENT_ID_LAYER) {
551 buf += put_block_info(buf, NULL, "seg_id",
552 offsetof(insp_mi_data, segment_id), 0);
553 }
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800554 if (layers & MOTION_VECTORS_LAYER) {
555 buf += put_motion_vectors(buf);
556 }
557 if (layers & REFERENCE_FRAME_LAYER) {
Michael Bebenita14e1b742017-10-24 12:49:15 -0700558 buf += put_block_info(buf, refs_map, "referenceFrame",
559 offsetof(insp_mi_data, ref_frame), 2);
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800560 }
561#if CONFIG_ACCOUNTING
562 if (layers & ACCOUNTING_LAYER) {
563 buf += put_accounting(buf);
564 }
565#endif
566 buf += snprintf(buf, MAX_BUFFER, " \"frame\": %d,\n", decoded_frame_count);
567 buf += snprintf(buf, MAX_BUFFER, " \"showFrame\": %d,\n",
568 frame_data.show_frame);
569 buf += snprintf(buf, MAX_BUFFER, " \"frameType\": %d,\n",
570 frame_data.frame_type);
571 buf += snprintf(buf, MAX_BUFFER, " \"baseQIndex\": %d,\n",
572 frame_data.base_qindex);
Michael Bebenita2c2e5612017-04-06 22:19:04 -0400573 buf += snprintf(buf, MAX_BUFFER, " \"tileCols\": %d,\n",
574 frame_data.tile_mi_cols);
575 buf += snprintf(buf, MAX_BUFFER, " \"tileRows\": %d,\n",
576 frame_data.tile_mi_rows);
Yushin Choc24351c2017-10-24 14:59:08 -0700577 buf += snprintf(buf, MAX_BUFFER, " \"deltaQPresentFlag\": %d,\n",
578 frame_data.delta_q_present_flag);
579 buf += snprintf(buf, MAX_BUFFER, " \"deltaQRes\": %d,\n",
580 frame_data.delta_q_res);
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800581 buf += put_str(buf, " \"config\": {");
582 buf += put_map(buf, config_map);
583 buf += put_str(buf, "},\n");
Michael Bebenita4aee17d2017-07-05 14:03:36 -0700584 buf += put_str(buf, " \"configString\": \"");
585 buf += put_str_with_escape(buf, aom_codec_build_config());
586 buf += put_str(buf, "\"\n");
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800587 decoded_frame_count++;
588 buf += put_str(buf, "},\n");
589 *(buf++) = 0;
590 on_frame_decoded_dump(buffer);
591 aom_free(buffer);
592}
593
594void ifd_init_cb() {
595 aom_inspect_init ii;
596 ii.inspect_cb = inspect;
597 ii.inspect_ctx = NULL;
598 aom_codec_control(&codec, AV1_SET_INSPECTION_CALLBACK, &ii);
599}
600
601EMSCRIPTEN_KEEPALIVE
602int open_file(char *file) {
603 if (file == NULL) {
604 // The JS analyzer puts the .ivf file at this location.
605 file = "/tmp/input.ivf";
606 }
607 reader = aom_video_reader_open(file);
608 if (!reader) die("Failed to open %s for reading.", file);
609 info = aom_video_reader_get_info(reader);
610 const AvxInterface *decoder = get_aom_decoder_by_fourcc(info->codec_fourcc);
611 if (!decoder) die("Unknown input codec.");
612 fprintf(stderr, "Using %s\n",
613 aom_codec_iface_name(decoder->codec_interface()));
614 if (aom_codec_dec_init(&codec, decoder->codec_interface(), NULL, 0))
615 die_codec(&codec, "Failed to initialize decoder.");
616 ifd_init(&frame_data, info->frame_width, info->frame_height);
617 ifd_init_cb();
618 return EXIT_SUCCESS;
619}
620
621EMSCRIPTEN_KEEPALIVE
622int read_frame() {
623 if (!aom_video_reader_read_frame(reader)) return EXIT_FAILURE;
624 img = NULL;
625 aom_codec_iter_t iter = NULL;
626 size_t frame_size = 0;
627 const unsigned char *frame = aom_video_reader_get_frame(reader, &frame_size);
Sean DuBois47cc2552018-01-23 07:44:16 +0000628 if (aom_codec_decode(&codec, frame, (unsigned int)frame_size, NULL) !=
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800629 AOM_CODEC_OK) {
630 die_codec(&codec, "Failed to decode frame.");
631 }
632 img = aom_codec_get_frame(&codec, &iter);
633 if (img == NULL) {
634 return EXIT_FAILURE;
635 }
636 ++frame_count;
637 return EXIT_SUCCESS;
638}
639
640EMSCRIPTEN_KEEPALIVE
641const char *get_aom_codec_build_config() { return aom_codec_build_config(); }
642
643EMSCRIPTEN_KEEPALIVE
644int get_bit_depth() { return img->bit_depth; }
645
646EMSCRIPTEN_KEEPALIVE
Michael Bebenitabf1f9ee2017-06-16 15:54:08 -0700647int get_bits_per_sample() { return img->bps; }
648
649EMSCRIPTEN_KEEPALIVE
650int get_image_format() { return img->fmt; }
651
652EMSCRIPTEN_KEEPALIVE
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800653unsigned char *get_plane(int plane) { return img->planes[plane]; }
654
655EMSCRIPTEN_KEEPALIVE
656int get_plane_stride(int plane) { return img->stride[plane]; }
657
658EMSCRIPTEN_KEEPALIVE
659int get_plane_width(int plane) { return aom_img_plane_width(img, plane); }
660
661EMSCRIPTEN_KEEPALIVE
662int get_plane_height(int plane) { return aom_img_plane_height(img, plane); }
663
664EMSCRIPTEN_KEEPALIVE
665int get_frame_width() { return info->frame_width; }
666
667EMSCRIPTEN_KEEPALIVE
668int get_frame_height() { return info->frame_height; }
669
670static void parse_args(char **argv) {
671 char **argi, **argj;
672 struct arg arg;
673 (void)dump_accounting_arg;
Alex Converse0ec34d22017-04-03 14:54:07 -0700674 (void)dump_cdef_arg;
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800675 for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step) {
676 arg.argv_step = 1;
677 if (arg_match(&arg, &dump_block_size_arg, argi)) layers |= BLOCK_SIZE_LAYER;
678#if CONFIG_ACCOUNTING
679 else if (arg_match(&arg, &dump_accounting_arg, argi))
680 layers |= ACCOUNTING_LAYER;
681#endif
682 else if (arg_match(&arg, &dump_transform_size_arg, argi))
683 layers |= TRANSFORM_SIZE_LAYER;
684 else if (arg_match(&arg, &dump_transform_type_arg, argi))
685 layers |= TRANSFORM_TYPE_LAYER;
686 else if (arg_match(&arg, &dump_mode_arg, argi))
687 layers |= MODE_LAYER;
Luc Trudeau0be435a2017-04-07 23:38:52 -0400688 else if (arg_match(&arg, &dump_uv_mode_arg, argi))
689 layers |= UV_MODE_LAYER;
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800690 else if (arg_match(&arg, &dump_skip_arg, argi))
691 layers |= SKIP_LAYER;
692 else if (arg_match(&arg, &dump_filter_arg, argi))
693 layers |= FILTER_LAYER;
694 else if (arg_match(&arg, &dump_cdef_arg, argi))
695 layers |= CDEF_LAYER;
Luc Trudeauf89056a2017-04-28 16:07:22 -0400696 else if (arg_match(&arg, &dump_cfl_arg, argi))
697 layers |= CFL_LAYER;
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800698 else if (arg_match(&arg, &dump_reference_frame_arg, argi))
699 layers |= REFERENCE_FRAME_LAYER;
700 else if (arg_match(&arg, &dump_motion_vectors_arg, argi))
701 layers |= MOTION_VECTORS_LAYER;
Ankur Saxena6e6b6972017-10-20 22:10:10 -0700702 else if (arg_match(&arg, &dump_dual_filter_type_arg, argi))
703 layers |= DUAL_FILTER_LAYER;
Yushin Choc24351c2017-10-24 14:59:08 -0700704 else if (arg_match(&arg, &dump_delta_q_arg, argi))
705 layers |= Q_INDEX_LAYER;
Yushin Cho4be87e02017-10-25 16:27:04 -0700706 else if (arg_match(&arg, &dump_seg_id_arg, argi))
707 layers |= SEGMENT_ID_LAYER;
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800708 else if (arg_match(&arg, &dump_all_arg, argi))
709 layers |= ALL_LAYERS;
Michael Bebenitaf1207b62017-04-14 22:30:56 -0700710 else if (arg_match(&arg, &compress_arg, argi))
711 compress = 1;
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800712 else if (arg_match(&arg, &usage_arg, argi))
713 usage_exit();
714 else if (arg_match(&arg, &limit_arg, argi))
715 stop_after = arg_parse_uint(&arg);
716 else
717 argj++;
718 }
719}
720
721static const char *exec_name;
722
723void usage_exit(void) {
724 fprintf(stderr, "Usage: %s src_filename <options>\n", exec_name);
725 fprintf(stderr, "\nOptions:\n");
726 arg_show_usage(stderr, main_args);
727 exit(EXIT_FAILURE);
728}
729
730EMSCRIPTEN_KEEPALIVE
731int main(int argc, char **argv) {
732 exec_name = argv[0];
733 parse_args(argv);
734 if (argc >= 2) {
735 open_file(argv[1]);
736 printf("[\n");
737 while (1) {
738 if (stop_after && (decoded_frame_count >= stop_after)) break;
739 if (read_frame()) break;
740 }
741 printf("null\n");
742 printf("]");
743 } else {
744 usage_exit();
745 }
746}
747
748EMSCRIPTEN_KEEPALIVE
749void quit() {
750 if (aom_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec");
751 aom_video_reader_close(reader);
752}
753
754EMSCRIPTEN_KEEPALIVE
755void set_layers(LayerType v) { layers = v; }
Michael Bebenitaf1207b62017-04-14 22:30:56 -0700756
757EMSCRIPTEN_KEEPALIVE
758void set_compress(int v) { compress = v; }