blob: fa1dcafea5ee9ef2baa115cb6466c61b98824e2f [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 -040093#if CONFIG_CFL
94static const arg_def_t dump_cfl_arg =
95 ARG_DEF("cfl", "chroma_from_luma", 0, "Dump Chroma from Luma Alphas");
96#endif
Ankur Saxena6e6b6972017-10-20 22:10:10 -070097#if CONFIG_DUAL_FILTER
98static const arg_def_t dump_dual_filter_type_arg =
99 ARG_DEF("df", "dualFilterType", 0, "Dump Dual Filter Type");
100#endif
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800101static const arg_def_t dump_reference_frame_arg =
102 ARG_DEF("r", "referenceFrame", 0, "Dump Reference Frame");
Yushin Choc24351c2017-10-24 14:59:08 -0700103static const arg_def_t dump_delta_q_arg =
104 ARG_DEF("dq", "delta_q", 0, "Dump QIndex");
Yushin Cho4be87e02017-10-25 16:27:04 -0700105static const arg_def_t dump_seg_id_arg =
106 ARG_DEF("si", "seg_id", 0, "Dump Segment ID");
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800107static const arg_def_t usage_arg = ARG_DEF("h", "help", 0, "Help");
108
109static const arg_def_t *main_args[] = { &limit_arg,
110 &dump_all_arg,
Michael Bebenitaf1207b62017-04-14 22:30:56 -0700111 &compress_arg,
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800112#if CONFIG_ACCOUNTING
113 &dump_accounting_arg,
114#endif
115 &dump_block_size_arg,
116 &dump_transform_size_arg,
117 &dump_transform_type_arg,
118 &dump_mode_arg,
Luc Trudeau0be435a2017-04-07 23:38:52 -0400119 &dump_uv_mode_arg,
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800120 &dump_skip_arg,
121 &dump_filter_arg,
Alex Converse0ec34d22017-04-03 14:54:07 -0700122#if CONFIG_CDEF
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800123 &dump_cdef_arg,
Alex Converse0ec34d22017-04-03 14:54:07 -0700124#endif
Ankur Saxena6e6b6972017-10-20 22:10:10 -0700125#if CONFIG_DUAL_FILTER
126 &dump_dual_filter_type_arg,
127#endif
Luc Trudeauf89056a2017-04-28 16:07:22 -0400128#if CONFIG_CFL
129 &dump_cfl_arg,
130#endif
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800131 &dump_reference_frame_arg,
132 &dump_motion_vectors_arg,
Yushin Choc24351c2017-10-24 14:59:08 -0700133 &dump_delta_q_arg,
Yushin Cho4be87e02017-10-25 16:27:04 -0700134 &dump_seg_id_arg,
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800135 &usage_arg,
136 NULL };
137#define ENUM(name) \
138 { #name, name }
139#define LAST_ENUM \
140 { NULL, 0 }
141typedef struct map_entry {
142 const char *name;
143 int value;
144} map_entry;
145
Michael Bebenitab9f52562017-10-30 16:18:18 -0700146const map_entry refs_map[] = {
147 ENUM(INTRA_FRAME), ENUM(LAST_FRAME), ENUM(LAST2_FRAME),
148 ENUM(LAST3_FRAME), ENUM(GOLDEN_FRAME), ENUM(BWDREF_FRAME),
149 ENUM(ALTREF2_FRAME), ENUM(ALTREF_FRAME), LAST_ENUM
150};
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800151
152const map_entry block_size_map[] = {
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800153 ENUM(BLOCK_2X2), ENUM(BLOCK_2X4), ENUM(BLOCK_4X2),
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800154 ENUM(BLOCK_4X4), ENUM(BLOCK_4X8), ENUM(BLOCK_8X4),
155 ENUM(BLOCK_8X8), ENUM(BLOCK_8X16), ENUM(BLOCK_16X8),
156 ENUM(BLOCK_16X16), ENUM(BLOCK_16X32), ENUM(BLOCK_32X16),
157 ENUM(BLOCK_32X32), ENUM(BLOCK_32X64), ENUM(BLOCK_64X32),
158 ENUM(BLOCK_64X64),
159#if CONFIG_EXT_PARTITION
160 ENUM(BLOCK_64X128), ENUM(BLOCK_128X64), ENUM(BLOCK_128X128),
161#endif
Rupert Swarbricka5263752017-09-11 11:59:12 +0100162 ENUM(BLOCK_4X16), ENUM(BLOCK_16X4), ENUM(BLOCK_8X32),
163 ENUM(BLOCK_32X8), ENUM(BLOCK_16X64), ENUM(BLOCK_64X16),
Rupert Swarbrick2fa6e1c2017-09-11 12:38:10 +0100164#if CONFIG_EXT_PARTITION
165 ENUM(BLOCK_32X128), ENUM(BLOCK_128X32),
166#endif
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800167 LAST_ENUM
168};
169
170const map_entry tx_size_map[] = {
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800171 ENUM(TX_4X4), ENUM(TX_8X8), ENUM(TX_16X16), ENUM(TX_32X32),
172#if CONFIG_TX64X64
173 ENUM(TX_64X64),
174#endif
175 ENUM(TX_4X8), ENUM(TX_8X4), ENUM(TX_8X16), ENUM(TX_16X8),
Urvang Joshib2752172017-10-04 17:51:17 -0700176 ENUM(TX_16X32), ENUM(TX_32X16),
177#if CONFIG_TX64X64
178 ENUM(TX_32X64), ENUM(TX_64X32),
179#endif // CONFIG_TX64X64
180 ENUM(TX_4X16), ENUM(TX_16X4), ENUM(TX_8X32), ENUM(TX_32X8),
181 LAST_ENUM
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800182};
183
184const map_entry tx_type_map[] = { ENUM(DCT_DCT),
185 ENUM(ADST_DCT),
186 ENUM(DCT_ADST),
187 ENUM(ADST_ADST),
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800188 ENUM(FLIPADST_DCT),
189 ENUM(DCT_FLIPADST),
190 ENUM(FLIPADST_FLIPADST),
191 ENUM(ADST_FLIPADST),
192 ENUM(FLIPADST_ADST),
193 ENUM(IDTX),
194 ENUM(V_DCT),
195 ENUM(H_DCT),
196 ENUM(V_ADST),
197 ENUM(H_ADST),
198 ENUM(V_FLIPADST),
199 ENUM(H_FLIPADST),
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800200 LAST_ENUM };
Ankur Saxena6e6b6972017-10-20 22:10:10 -0700201#if CONFIG_DUAL_FILTER
202const map_entry dual_filter_map[] = { ENUM(REG_REG), ENUM(REG_SMOOTH),
203 ENUM(REG_SHARP), ENUM(SMOOTH_REG),
204 ENUM(SMOOTH_SMOOTH), ENUM(SMOOTH_SHARP),
205 ENUM(SHARP_REG), ENUM(SHARP_SMOOTH),
206 ENUM(SHARP_SHARP), LAST_ENUM };
207#endif
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800208
Sebastien Alaiwan0bdea0d2017-10-02 15:15:05 +0200209const map_entry prediction_mode_map[] = {
210 ENUM(DC_PRED), ENUM(V_PRED), ENUM(H_PRED),
211 ENUM(D45_PRED), ENUM(D135_PRED), ENUM(D117_PRED),
212 ENUM(D153_PRED), ENUM(D207_PRED), ENUM(D63_PRED),
213 ENUM(SMOOTH_PRED),
Urvang Joshifea5f402017-05-22 14:46:10 -0700214#if CONFIG_SMOOTH_HV
Sebastien Alaiwan0bdea0d2017-10-02 15:15:05 +0200215 ENUM(SMOOTH_V_PRED), ENUM(SMOOTH_H_PRED),
Urvang Joshifea5f402017-05-22 14:46:10 -0700216#endif // CONFIG_SMOOTH_HV
Urvang Joshi96d1c0a2017-10-10 13:15:32 -0700217 ENUM(PAETH_PRED), ENUM(NEARESTMV), ENUM(NEARMV),
Sarah Parker2b9ec2e2017-10-30 17:34:08 -0700218 ENUM(GLOBALMV), ENUM(NEWMV), ENUM(NEAREST_NEARESTMV),
Sebastien Alaiwan0bdea0d2017-10-02 15:15:05 +0200219 ENUM(NEAR_NEARMV), ENUM(NEAREST_NEWMV), ENUM(NEW_NEARESTMV),
Sarah Parker2b9ec2e2017-10-30 17:34:08 -0700220 ENUM(NEAR_NEWMV), ENUM(NEW_NEARMV), ENUM(GLOBAL_GLOBALMV),
Sebastien Alaiwan0bdea0d2017-10-02 15:15:05 +0200221 ENUM(NEW_NEWMV), ENUM(INTRA_INVALID), LAST_ENUM
222};
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800223
Luc Trudeaud6d9eee2017-07-12 12:36:50 -0400224#if CONFIG_CFL
225const map_entry uv_prediction_mode_map[] = {
Luc Trudeau6e1cd782017-06-21 13:52:36 -0400226 ENUM(UV_DC_PRED), ENUM(UV_V_PRED),
227 ENUM(UV_H_PRED), ENUM(UV_D45_PRED),
228 ENUM(UV_D135_PRED), ENUM(UV_D117_PRED),
229 ENUM(UV_D153_PRED), ENUM(UV_D207_PRED),
Urvang Joshi93b543a2017-06-01 17:32:41 -0700230 ENUM(UV_D63_PRED), ENUM(UV_SMOOTH_PRED),
Luc Trudeaud6d9eee2017-07-12 12:36:50 -0400231#if CONFIG_SMOOTH_HV
232 ENUM(UV_SMOOTH_V_PRED), ENUM(UV_SMOOTH_H_PRED),
233#endif // CONFIG_SMOOTH_HV
Urvang Joshi96d1c0a2017-10-10 13:15:32 -0700234 ENUM(UV_PAETH_PRED),
Luc Trudeau6e1cd782017-06-21 13:52:36 -0400235#if CONFIG_CFL
236 ENUM(UV_CFL_PRED),
237#endif
238 ENUM(UV_MODE_INVALID), LAST_ENUM
Luc Trudeaud6d9eee2017-07-12 12:36:50 -0400239};
240#else
241#define uv_prediction_mode_map prediction_mode_map
242#endif
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800243#define NO_SKIP 0
244#define SKIP 1
245
246const map_entry skip_map[] = { ENUM(SKIP), ENUM(NO_SKIP), LAST_ENUM };
247
248const map_entry config_map[] = { ENUM(MI_SIZE), LAST_ENUM };
249
250static const char *exec_name;
251
252insp_frame_data frame_data;
253int frame_count = 0;
254int decoded_frame_count = 0;
255aom_codec_ctx_t codec;
256AvxVideoReader *reader = NULL;
257const AvxVideoInfo *info = NULL;
258aom_image_t *img = NULL;
259
260void on_frame_decoded_dump(char *json) {
261#ifdef __EMSCRIPTEN__
262 EM_ASM_({ Module.on_frame_decoded_json($0); }, json);
263#else
264 printf("%s", json);
265#endif
266}
267
268// Writing out the JSON buffer using snprintf is very slow, especially when
269// compiled with emscripten, these functions speed things up quite a bit.
270int put_str(char *buffer, const char *str) {
271 int i;
272 for (i = 0; str[i] != '\0'; i++) {
273 buffer[i] = str[i];
274 }
275 return i;
276}
277
Michael Bebenita4aee17d2017-07-05 14:03:36 -0700278int put_str_with_escape(char *buffer, const char *str) {
279 int i;
280 int j = 0;
281 for (i = 0; str[i] != '\0'; i++) {
Thomas Daede3a1bd782017-07-21 12:17:10 -0700282 if (str[i] < ' ') {
283 continue;
284 } else if (str[i] == '"' || str[i] == '\\') {
Michael Bebenita4aee17d2017-07-05 14:03:36 -0700285 buffer[j++] = '\\';
286 }
287 buffer[j++] = str[i];
288 }
289 return j;
290}
291
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800292int put_num(char *buffer, char prefix, int num, char suffix) {
293 int i = 0;
294 char *buf = buffer;
295 int is_neg = 0;
296 if (prefix) {
297 buf[i++] = prefix;
298 }
299 if (num == 0) {
300 buf[i++] = '0';
301 } else {
302 if (num < 0) {
303 num = -num;
304 is_neg = 1;
305 }
306 int s = i;
307 while (num != 0) {
308 buf[i++] = '0' + (num % 10);
309 num = num / 10;
310 }
311 if (is_neg) {
312 buf[i++] = '-';
313 }
314 int e = i - 1;
315 while (s < e) {
316 int t = buf[s];
317 buf[s] = buf[e];
318 buf[e] = t;
319 s++;
320 e--;
321 }
322 }
323 if (suffix) {
324 buf[i++] = suffix;
325 }
326 return i;
327}
328
329int put_map(char *buffer, const map_entry *map) {
330 char *buf = buffer;
331 const map_entry *entry = map;
332 while (entry->name != NULL) {
333 *(buf++) = '"';
334 buf += put_str(buf, entry->name);
335 *(buf++) = '"';
336 buf += put_num(buf, ':', entry->value, 0);
337 entry++;
338 if (entry->name != NULL) {
339 *(buf++) = ',';
340 }
341 }
Yushin Chof6741572017-10-24 20:07:46 -0700342 return (int)(buf - buffer);
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800343}
344
345int put_reference_frame(char *buffer) {
346 const int mi_rows = frame_data.mi_rows;
347 const int mi_cols = frame_data.mi_cols;
348 char *buf = buffer;
Michael Bebenitaf1207b62017-04-14 22:30:56 -0700349 int r, c, t;
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800350 buf += put_str(buf, " \"referenceFrameMap\": {");
351 buf += put_map(buf, refs_map);
352 buf += put_str(buf, "},\n");
353 buf += put_str(buf, " \"referenceFrame\": [");
354 for (r = 0; r < mi_rows; ++r) {
355 *(buf++) = '[';
356 for (c = 0; c < mi_cols; ++c) {
357 insp_mi_data *mi = &frame_data.mi_grid[r * mi_cols + c];
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800358 buf += put_num(buf, '[', mi->ref_frame[0], 0);
359 buf += put_num(buf, ',', mi->ref_frame[1], ']');
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->ref_frame[0] != next_mi->ref_frame[0] ||
364 mi->ref_frame[1] != next_mi->ref_frame[1]) {
365 break;
366 }
367 }
368 if (t - c > 1) {
369 *(buf++) = ',';
370 buf += put_num(buf, '[', t - c - 1, ']');
371 c = t - 1;
372 }
373 }
374 if (c < mi_cols - 1) *(buf++) = ',';
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800375 }
376 *(buf++) = ']';
377 if (r < mi_rows - 1) *(buf++) = ',';
378 }
379 buf += put_str(buf, "],\n");
Yushin Chof6741572017-10-24 20:07:46 -0700380 return (int)(buf - buffer);
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800381}
382
383int put_motion_vectors(char *buffer) {
384 const int mi_rows = frame_data.mi_rows;
385 const int mi_cols = frame_data.mi_cols;
386 char *buf = buffer;
Michael Bebenitaf1207b62017-04-14 22:30:56 -0700387 int r, c, t;
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800388 buf += put_str(buf, " \"motionVectors\": [");
389 for (r = 0; r < mi_rows; ++r) {
390 *(buf++) = '[';
391 for (c = 0; c < mi_cols; ++c) {
392 insp_mi_data *mi = &frame_data.mi_grid[r * mi_cols + c];
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800393 buf += put_num(buf, '[', mi->mv[0].col, 0);
394 buf += put_num(buf, ',', mi->mv[0].row, 0);
395 buf += put_num(buf, ',', mi->mv[1].col, 0);
396 buf += put_num(buf, ',', mi->mv[1].row, ']');
Michael Bebenitaf1207b62017-04-14 22:30:56 -0700397 if (compress) { // RLE
398 for (t = c + 1; t < mi_cols; ++t) {
399 insp_mi_data *next_mi = &frame_data.mi_grid[r * mi_cols + t];
400 if (mi->mv[0].col != next_mi->mv[0].col ||
401 mi->mv[0].row != next_mi->mv[0].row ||
402 mi->mv[1].col != next_mi->mv[1].col ||
403 mi->mv[1].row != next_mi->mv[1].row) {
404 break;
405 }
406 }
407 if (t - c > 1) {
408 *(buf++) = ',';
409 buf += put_num(buf, '[', t - c - 1, ']');
410 c = t - 1;
411 }
412 }
413 if (c < mi_cols - 1) *(buf++) = ',';
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800414 }
415 *(buf++) = ']';
416 if (r < mi_rows - 1) *(buf++) = ',';
417 }
418 buf += put_str(buf, "],\n");
Yushin Chof6741572017-10-24 20:07:46 -0700419 return (int)(buf - buffer);
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800420}
421
422int put_block_info(char *buffer, const map_entry *map, const char *name,
Michael Bebenita14e1b742017-10-24 12:49:15 -0700423 size_t offset, int len) {
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800424 const int mi_rows = frame_data.mi_rows;
425 const int mi_cols = frame_data.mi_cols;
426 char *buf = buffer;
Michael Bebenita14e1b742017-10-24 12:49:15 -0700427 int r, c, t, i;
428 if (compress && len == 1) {
429 die("Can't encode scalars as arrays when RLE compression is enabled.");
430 return -1;
431 }
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800432 if (map) {
433 buf += snprintf(buf, MAX_BUFFER, " \"%sMap\": {", name);
434 buf += put_map(buf, map);
435 buf += put_str(buf, "},\n");
436 }
437 buf += snprintf(buf, MAX_BUFFER, " \"%s\": [", name);
438 for (r = 0; r < mi_rows; ++r) {
439 *(buf++) = '[';
440 for (c = 0; c < mi_cols; ++c) {
Michael Bebenita14e1b742017-10-24 12:49:15 -0700441 insp_mi_data *mi = &frame_data.mi_grid[r * mi_cols + c];
Yushin Choc24351c2017-10-24 14:59:08 -0700442 int16_t *v = (int16_t *)(((int8_t *)mi) + offset);
Michael Bebenita14e1b742017-10-24 12:49:15 -0700443 if (len == 0) {
444 buf += put_num(buf, 0, v[0], 0);
445 } else {
446 buf += put_str(buf, "[");
447 for (i = 0; i < len; i++) {
448 buf += put_num(buf, 0, v[i], 0);
449 if (i < len - 1) {
450 buf += put_str(buf, ",");
451 }
452 }
453 buf += put_str(buf, "]");
454 }
Michael Bebenitaf1207b62017-04-14 22:30:56 -0700455 if (compress) { // RLE
456 for (t = c + 1; t < mi_cols; ++t) {
457 insp_mi_data *next_mi = &frame_data.mi_grid[r * mi_cols + t];
Yushin Choc24351c2017-10-24 14:59:08 -0700458 int16_t *nv = (int16_t *)(((int8_t *)next_mi) + offset);
Michael Bebenita14e1b742017-10-24 12:49:15 -0700459 int same = 0;
460 if (len == 0) {
461 same = v[0] == nv[0];
462 } else {
463 for (i = 0; i < len; i++) {
464 same = v[i] == nv[i];
465 if (!same) {
466 break;
467 }
468 }
469 }
470 if (!same) {
Michael Bebenitaf1207b62017-04-14 22:30:56 -0700471 break;
472 }
473 }
474 if (t - c > 1) {
475 *(buf++) = ',';
476 buf += put_num(buf, '[', t - c - 1, ']');
477 c = t - 1;
478 }
479 }
480 if (c < mi_cols - 1) *(buf++) = ',';
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800481 }
482 *(buf++) = ']';
483 if (r < mi_rows - 1) *(buf++) = ',';
484 }
485 buf += put_str(buf, "],\n");
Yushin Chof6741572017-10-24 20:07:46 -0700486 return (int)(buf - buffer);
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800487}
488
489#if CONFIG_ACCOUNTING
490int put_accounting(char *buffer) {
491 char *buf = buffer;
492 int i;
493 const Accounting *accounting = frame_data.accounting;
494 if (accounting == NULL) {
495 printf("XXX\n");
496 return 0;
497 }
498 const int num_syms = accounting->syms.num_syms;
499 const int num_strs = accounting->syms.dictionary.num_strs;
500 buf += put_str(buf, " \"symbolsMap\": [");
501 for (i = 0; i < num_strs; i++) {
502 buf += snprintf(buf, MAX_BUFFER, "\"%s\"",
503 accounting->syms.dictionary.strs[i]);
504 if (i < num_strs - 1) *(buf++) = ',';
505 }
506 buf += put_str(buf, "],\n");
507 buf += put_str(buf, " \"symbols\": [\n ");
508 AccountingSymbolContext context;
509 context.x = -2;
510 context.y = -2;
511 AccountingSymbol *sym;
512 for (i = 0; i < num_syms; i++) {
513 sym = &accounting->syms.syms[i];
514 if (memcmp(&context, &sym->context, sizeof(AccountingSymbolContext)) != 0) {
515 buf += put_num(buf, '[', sym->context.x, 0);
516 buf += put_num(buf, ',', sym->context.y, ']');
517 } else {
518 buf += put_num(buf, '[', sym->id, 0);
519 buf += put_num(buf, ',', sym->bits, 0);
520 buf += put_num(buf, ',', sym->samples, ']');
521 }
522 context = sym->context;
523 if (i < num_syms - 1) *(buf++) = ',';
524 }
525 buf += put_str(buf, "],\n");
Yushin Chof6741572017-10-24 20:07:46 -0700526 return (int)(buf - buffer);
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800527}
528#endif
529
530void inspect(void *pbi, void *data) {
531 /* Fetch frame data. */
532 ifd_inspect(&frame_data, pbi);
533 (void)data;
534 // We allocate enough space and hope we don't write out of bounds. Totally
535 // unsafe but this speeds things up, especially when compiled to Javascript.
536 char *buffer = aom_malloc(MAX_BUFFER);
537 char *buf = buffer;
538 buf += put_str(buf, "{\n");
539 if (layers & BLOCK_SIZE_LAYER) {
540 buf += put_block_info(buf, block_size_map, "blockSize",
Michael Bebenita14e1b742017-10-24 12:49:15 -0700541 offsetof(insp_mi_data, sb_type), 0);
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800542 }
543 if (layers & TRANSFORM_SIZE_LAYER) {
544 buf += put_block_info(buf, tx_size_map, "transformSize",
Michael Bebenita14e1b742017-10-24 12:49:15 -0700545 offsetof(insp_mi_data, tx_size), 0);
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800546 }
547 if (layers & TRANSFORM_TYPE_LAYER) {
548 buf += put_block_info(buf, tx_type_map, "transformType",
Michael Bebenita14e1b742017-10-24 12:49:15 -0700549 offsetof(insp_mi_data, tx_type), 0);
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800550 }
Ankur Saxena6e6b6972017-10-20 22:10:10 -0700551#if CONFIG_DUAL_FILTER
552 if (layers & DUAL_FILTER_LAYER) {
553 buf += put_block_info(buf, dual_filter_map, "dualFilterType",
Michael Bebenita14e1b742017-10-24 12:49:15 -0700554 offsetof(insp_mi_data, dual_filter_type), 0);
Ankur Saxena6e6b6972017-10-20 22:10:10 -0700555 }
556#endif
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800557 if (layers & MODE_LAYER) {
558 buf += put_block_info(buf, prediction_mode_map, "mode",
Michael Bebenita14e1b742017-10-24 12:49:15 -0700559 offsetof(insp_mi_data, mode), 0);
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800560 }
Luc Trudeau0be435a2017-04-07 23:38:52 -0400561 if (layers & UV_MODE_LAYER) {
Luc Trudeaud6d9eee2017-07-12 12:36:50 -0400562 buf += put_block_info(buf, uv_prediction_mode_map, "uv_mode",
Michael Bebenita14e1b742017-10-24 12:49:15 -0700563 offsetof(insp_mi_data, uv_mode), 0);
Luc Trudeau0be435a2017-04-07 23:38:52 -0400564 }
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800565 if (layers & SKIP_LAYER) {
Michael Bebenita14e1b742017-10-24 12:49:15 -0700566 buf +=
Michael Bebenita7a144cd2017-11-07 11:26:34 -0800567 put_block_info(buf, skip_map, "skip", offsetof(insp_mi_data, skip), 0);
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800568 }
569 if (layers & FILTER_LAYER) {
Michael Bebenita14e1b742017-10-24 12:49:15 -0700570#if CONFIG_DUAL_FILTER
571 buf +=
572 put_block_info(buf, NULL, "filter", offsetof(insp_mi_data, filter), 2);
573#else
574 buf +=
575 put_block_info(buf, NULL, "filter", offsetof(insp_mi_data, filter), 0);
576#endif
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800577 }
Alex Converse0ec34d22017-04-03 14:54:07 -0700578#if CONFIG_CDEF
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800579 if (layers & CDEF_LAYER) {
Michael Bebenita09558812017-04-01 20:10:53 -0700580 buf += put_block_info(buf, NULL, "cdef_level",
Michael Bebenita14e1b742017-10-24 12:49:15 -0700581 offsetof(insp_mi_data, cdef_level), 0);
Michael Bebenita09558812017-04-01 20:10:53 -0700582 buf += put_block_info(buf, NULL, "cdef_strength",
Michael Bebenita14e1b742017-10-24 12:49:15 -0700583 offsetof(insp_mi_data, cdef_strength), 0);
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800584 }
Alex Converse0ec34d22017-04-03 14:54:07 -0700585#endif
Luc Trudeauf89056a2017-04-28 16:07:22 -0400586#if CONFIG_CFL
587 if (layers & CFL_LAYER) {
Luc Trudeaua9bd85f2017-05-11 14:37:56 -0400588 buf += put_block_info(buf, NULL, "cfl_alpha_idx",
Michael Bebenita14e1b742017-10-24 12:49:15 -0700589 offsetof(insp_mi_data, cfl_alpha_idx), 0);
Luc Trudeau9bab28b2017-05-11 15:23:02 -0400590 buf += put_block_info(buf, NULL, "cfl_alpha_sign",
Michael Bebenita14e1b742017-10-24 12:49:15 -0700591 offsetof(insp_mi_data, cfl_alpha_sign), 0);
Luc Trudeauf89056a2017-04-28 16:07:22 -0400592 }
593#endif
Yushin Choc24351c2017-10-24 14:59:08 -0700594 if (layers & Q_INDEX_LAYER) {
595 buf += put_block_info(buf, NULL, "delta_q",
596 offsetof(insp_mi_data, current_qindex), 0);
597 }
Yushin Cho4be87e02017-10-25 16:27:04 -0700598 if (layers & SEGMENT_ID_LAYER) {
599 buf += put_block_info(buf, NULL, "seg_id",
600 offsetof(insp_mi_data, segment_id), 0);
601 }
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800602 if (layers & MOTION_VECTORS_LAYER) {
603 buf += put_motion_vectors(buf);
604 }
605 if (layers & REFERENCE_FRAME_LAYER) {
Michael Bebenita14e1b742017-10-24 12:49:15 -0700606 buf += put_block_info(buf, refs_map, "referenceFrame",
607 offsetof(insp_mi_data, ref_frame), 2);
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800608 }
609#if CONFIG_ACCOUNTING
610 if (layers & ACCOUNTING_LAYER) {
611 buf += put_accounting(buf);
612 }
613#endif
614 buf += snprintf(buf, MAX_BUFFER, " \"frame\": %d,\n", decoded_frame_count);
615 buf += snprintf(buf, MAX_BUFFER, " \"showFrame\": %d,\n",
616 frame_data.show_frame);
617 buf += snprintf(buf, MAX_BUFFER, " \"frameType\": %d,\n",
618 frame_data.frame_type);
619 buf += snprintf(buf, MAX_BUFFER, " \"baseQIndex\": %d,\n",
620 frame_data.base_qindex);
Michael Bebenita2c2e5612017-04-06 22:19:04 -0400621 buf += snprintf(buf, MAX_BUFFER, " \"tileCols\": %d,\n",
622 frame_data.tile_mi_cols);
623 buf += snprintf(buf, MAX_BUFFER, " \"tileRows\": %d,\n",
624 frame_data.tile_mi_rows);
Yushin Choc24351c2017-10-24 14:59:08 -0700625 buf += snprintf(buf, MAX_BUFFER, " \"deltaQPresentFlag\": %d,\n",
626 frame_data.delta_q_present_flag);
627 buf += snprintf(buf, MAX_BUFFER, " \"deltaQRes\": %d,\n",
628 frame_data.delta_q_res);
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800629 buf += put_str(buf, " \"config\": {");
630 buf += put_map(buf, config_map);
631 buf += put_str(buf, "},\n");
Michael Bebenita4aee17d2017-07-05 14:03:36 -0700632 buf += put_str(buf, " \"configString\": \"");
633 buf += put_str_with_escape(buf, aom_codec_build_config());
634 buf += put_str(buf, "\"\n");
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800635 decoded_frame_count++;
636 buf += put_str(buf, "},\n");
637 *(buf++) = 0;
638 on_frame_decoded_dump(buffer);
639 aom_free(buffer);
640}
641
642void ifd_init_cb() {
643 aom_inspect_init ii;
644 ii.inspect_cb = inspect;
645 ii.inspect_ctx = NULL;
646 aom_codec_control(&codec, AV1_SET_INSPECTION_CALLBACK, &ii);
647}
648
649EMSCRIPTEN_KEEPALIVE
650int open_file(char *file) {
651 if (file == NULL) {
652 // The JS analyzer puts the .ivf file at this location.
653 file = "/tmp/input.ivf";
654 }
655 reader = aom_video_reader_open(file);
656 if (!reader) die("Failed to open %s for reading.", file);
657 info = aom_video_reader_get_info(reader);
658 const AvxInterface *decoder = get_aom_decoder_by_fourcc(info->codec_fourcc);
659 if (!decoder) die("Unknown input codec.");
660 fprintf(stderr, "Using %s\n",
661 aom_codec_iface_name(decoder->codec_interface()));
662 if (aom_codec_dec_init(&codec, decoder->codec_interface(), NULL, 0))
663 die_codec(&codec, "Failed to initialize decoder.");
664 ifd_init(&frame_data, info->frame_width, info->frame_height);
665 ifd_init_cb();
666 return EXIT_SUCCESS;
667}
668
669EMSCRIPTEN_KEEPALIVE
670int read_frame() {
671 if (!aom_video_reader_read_frame(reader)) return EXIT_FAILURE;
672 img = NULL;
673 aom_codec_iter_t iter = NULL;
674 size_t frame_size = 0;
675 const unsigned char *frame = aom_video_reader_get_frame(reader, &frame_size);
676 if (aom_codec_decode(&codec, frame, (unsigned int)frame_size, NULL, 0) !=
677 AOM_CODEC_OK) {
678 die_codec(&codec, "Failed to decode frame.");
679 }
680 img = aom_codec_get_frame(&codec, &iter);
681 if (img == NULL) {
682 return EXIT_FAILURE;
683 }
684 ++frame_count;
685 return EXIT_SUCCESS;
686}
687
688EMSCRIPTEN_KEEPALIVE
689const char *get_aom_codec_build_config() { return aom_codec_build_config(); }
690
691EMSCRIPTEN_KEEPALIVE
692int get_bit_depth() { return img->bit_depth; }
693
694EMSCRIPTEN_KEEPALIVE
Michael Bebenitabf1f9ee2017-06-16 15:54:08 -0700695int get_bits_per_sample() { return img->bps; }
696
697EMSCRIPTEN_KEEPALIVE
698int get_image_format() { return img->fmt; }
699
700EMSCRIPTEN_KEEPALIVE
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800701unsigned char *get_plane(int plane) { return img->planes[plane]; }
702
703EMSCRIPTEN_KEEPALIVE
704int get_plane_stride(int plane) { return img->stride[plane]; }
705
706EMSCRIPTEN_KEEPALIVE
707int get_plane_width(int plane) { return aom_img_plane_width(img, plane); }
708
709EMSCRIPTEN_KEEPALIVE
710int get_plane_height(int plane) { return aom_img_plane_height(img, plane); }
711
712EMSCRIPTEN_KEEPALIVE
713int get_frame_width() { return info->frame_width; }
714
715EMSCRIPTEN_KEEPALIVE
716int get_frame_height() { return info->frame_height; }
717
718static void parse_args(char **argv) {
719 char **argi, **argj;
720 struct arg arg;
721 (void)dump_accounting_arg;
Alex Converse0ec34d22017-04-03 14:54:07 -0700722 (void)dump_cdef_arg;
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800723 for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step) {
724 arg.argv_step = 1;
725 if (arg_match(&arg, &dump_block_size_arg, argi)) layers |= BLOCK_SIZE_LAYER;
726#if CONFIG_ACCOUNTING
727 else if (arg_match(&arg, &dump_accounting_arg, argi))
728 layers |= ACCOUNTING_LAYER;
729#endif
730 else if (arg_match(&arg, &dump_transform_size_arg, argi))
731 layers |= TRANSFORM_SIZE_LAYER;
732 else if (arg_match(&arg, &dump_transform_type_arg, argi))
733 layers |= TRANSFORM_TYPE_LAYER;
734 else if (arg_match(&arg, &dump_mode_arg, argi))
735 layers |= MODE_LAYER;
Luc Trudeau0be435a2017-04-07 23:38:52 -0400736 else if (arg_match(&arg, &dump_uv_mode_arg, argi))
737 layers |= UV_MODE_LAYER;
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800738 else if (arg_match(&arg, &dump_skip_arg, argi))
739 layers |= SKIP_LAYER;
740 else if (arg_match(&arg, &dump_filter_arg, argi))
741 layers |= FILTER_LAYER;
Alex Converse0ec34d22017-04-03 14:54:07 -0700742#if CONFIG_CDEF
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800743 else if (arg_match(&arg, &dump_cdef_arg, argi))
744 layers |= CDEF_LAYER;
Alex Converse0ec34d22017-04-03 14:54:07 -0700745#endif
Luc Trudeauf89056a2017-04-28 16:07:22 -0400746#if CONFIG_CFL
747 else if (arg_match(&arg, &dump_cfl_arg, argi))
748 layers |= CFL_LAYER;
749#endif
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800750 else if (arg_match(&arg, &dump_reference_frame_arg, argi))
751 layers |= REFERENCE_FRAME_LAYER;
752 else if (arg_match(&arg, &dump_motion_vectors_arg, argi))
753 layers |= MOTION_VECTORS_LAYER;
Ankur Saxena6e6b6972017-10-20 22:10:10 -0700754#if CONFIG_DUAL_FILTER
755 else if (arg_match(&arg, &dump_dual_filter_type_arg, argi))
756 layers |= DUAL_FILTER_LAYER;
757#endif
Yushin Choc24351c2017-10-24 14:59:08 -0700758 else if (arg_match(&arg, &dump_delta_q_arg, argi))
759 layers |= Q_INDEX_LAYER;
Yushin Cho4be87e02017-10-25 16:27:04 -0700760 else if (arg_match(&arg, &dump_seg_id_arg, argi))
761 layers |= SEGMENT_ID_LAYER;
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800762 else if (arg_match(&arg, &dump_all_arg, argi))
763 layers |= ALL_LAYERS;
Michael Bebenitaf1207b62017-04-14 22:30:56 -0700764 else if (arg_match(&arg, &compress_arg, argi))
765 compress = 1;
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800766 else if (arg_match(&arg, &usage_arg, argi))
767 usage_exit();
768 else if (arg_match(&arg, &limit_arg, argi))
769 stop_after = arg_parse_uint(&arg);
770 else
771 argj++;
772 }
773}
774
775static const char *exec_name;
776
777void usage_exit(void) {
778 fprintf(stderr, "Usage: %s src_filename <options>\n", exec_name);
779 fprintf(stderr, "\nOptions:\n");
780 arg_show_usage(stderr, main_args);
781 exit(EXIT_FAILURE);
782}
783
784EMSCRIPTEN_KEEPALIVE
785int main(int argc, char **argv) {
786 exec_name = argv[0];
787 parse_args(argv);
788 if (argc >= 2) {
789 open_file(argv[1]);
790 printf("[\n");
791 while (1) {
792 if (stop_after && (decoded_frame_count >= stop_after)) break;
793 if (read_frame()) break;
794 }
795 printf("null\n");
796 printf("]");
797 } else {
798 usage_exit();
799 }
800}
801
802EMSCRIPTEN_KEEPALIVE
803void quit() {
804 if (aom_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec");
805 aom_video_reader_close(reader);
806}
807
808EMSCRIPTEN_KEEPALIVE
809void set_layers(LayerType v) { layers = v; }
Michael Bebenitaf1207b62017-04-14 22:30:56 -0700810
811EMSCRIPTEN_KEEPALIVE
812void set_compress(int v) { compress = v; }