blob: ec33bca57283e09d5ef08885fc6ce905e39b56c3 [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
146const map_entry refs_map[] = { ENUM(INTRA_FRAME), ENUM(LAST_FRAME),
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800147 ENUM(LAST2_FRAME), ENUM(LAST3_FRAME),
148 ENUM(GOLDEN_FRAME), ENUM(BWDREF_FRAME),
Sebastien Alaiwan365e6442017-10-16 11:35:00 +0200149 ENUM(ALTREF_FRAME), LAST_ENUM };
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800150
151const map_entry block_size_map[] = {
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800152 ENUM(BLOCK_2X2), ENUM(BLOCK_2X4), ENUM(BLOCK_4X2),
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800153 ENUM(BLOCK_4X4), ENUM(BLOCK_4X8), ENUM(BLOCK_8X4),
154 ENUM(BLOCK_8X8), ENUM(BLOCK_8X16), ENUM(BLOCK_16X8),
155 ENUM(BLOCK_16X16), ENUM(BLOCK_16X32), ENUM(BLOCK_32X16),
156 ENUM(BLOCK_32X32), ENUM(BLOCK_32X64), ENUM(BLOCK_64X32),
157 ENUM(BLOCK_64X64),
158#if CONFIG_EXT_PARTITION
159 ENUM(BLOCK_64X128), ENUM(BLOCK_128X64), ENUM(BLOCK_128X128),
160#endif
Rupert Swarbricka5263752017-09-11 11:59:12 +0100161 ENUM(BLOCK_4X16), ENUM(BLOCK_16X4), ENUM(BLOCK_8X32),
162 ENUM(BLOCK_32X8), ENUM(BLOCK_16X64), ENUM(BLOCK_64X16),
Rupert Swarbrick2fa6e1c2017-09-11 12:38:10 +0100163#if CONFIG_EXT_PARTITION
164 ENUM(BLOCK_32X128), ENUM(BLOCK_128X32),
165#endif
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800166 LAST_ENUM
167};
168
169const map_entry tx_size_map[] = {
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800170 ENUM(TX_4X4), ENUM(TX_8X8), ENUM(TX_16X16), ENUM(TX_32X32),
171#if CONFIG_TX64X64
172 ENUM(TX_64X64),
173#endif
174 ENUM(TX_4X8), ENUM(TX_8X4), ENUM(TX_8X16), ENUM(TX_16X8),
Urvang Joshib2752172017-10-04 17:51:17 -0700175 ENUM(TX_16X32), ENUM(TX_32X16),
176#if CONFIG_TX64X64
177 ENUM(TX_32X64), ENUM(TX_64X32),
178#endif // CONFIG_TX64X64
179 ENUM(TX_4X16), ENUM(TX_16X4), ENUM(TX_8X32), ENUM(TX_32X8),
180 LAST_ENUM
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800181};
182
183const map_entry tx_type_map[] = { ENUM(DCT_DCT),
184 ENUM(ADST_DCT),
185 ENUM(DCT_ADST),
186 ENUM(ADST_ADST),
187#if CONFIG_EXT_TX
188 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),
200#endif
201 LAST_ENUM };
Ankur Saxena6e6b6972017-10-20 22:10:10 -0700202#if CONFIG_DUAL_FILTER
203const map_entry dual_filter_map[] = { ENUM(REG_REG), ENUM(REG_SMOOTH),
204 ENUM(REG_SHARP), ENUM(SMOOTH_REG),
205 ENUM(SMOOTH_SMOOTH), ENUM(SMOOTH_SHARP),
206 ENUM(SHARP_REG), ENUM(SHARP_SMOOTH),
207 ENUM(SHARP_SHARP), LAST_ENUM };
208#endif
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800209
Sebastien Alaiwan0bdea0d2017-10-02 15:15:05 +0200210const map_entry prediction_mode_map[] = {
211 ENUM(DC_PRED), ENUM(V_PRED), ENUM(H_PRED),
212 ENUM(D45_PRED), ENUM(D135_PRED), ENUM(D117_PRED),
213 ENUM(D153_PRED), ENUM(D207_PRED), ENUM(D63_PRED),
214 ENUM(SMOOTH_PRED),
Urvang Joshifea5f402017-05-22 14:46:10 -0700215#if CONFIG_SMOOTH_HV
Sebastien Alaiwan0bdea0d2017-10-02 15:15:05 +0200216 ENUM(SMOOTH_V_PRED), ENUM(SMOOTH_H_PRED),
Urvang Joshifea5f402017-05-22 14:46:10 -0700217#endif // CONFIG_SMOOTH_HV
Urvang Joshi96d1c0a2017-10-10 13:15:32 -0700218 ENUM(PAETH_PRED), ENUM(NEARESTMV), ENUM(NEARMV),
Sebastien Alaiwan0bdea0d2017-10-02 15:15:05 +0200219 ENUM(ZEROMV), ENUM(NEWMV), ENUM(NEAREST_NEARESTMV),
220 ENUM(NEAR_NEARMV), ENUM(NEAREST_NEWMV), ENUM(NEW_NEARESTMV),
221 ENUM(NEAR_NEWMV), ENUM(NEW_NEARMV), ENUM(ZERO_ZEROMV),
222 ENUM(NEW_NEWMV), ENUM(INTRA_INVALID), LAST_ENUM
223};
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800224
Luc Trudeaud6d9eee2017-07-12 12:36:50 -0400225#if CONFIG_CFL
226const map_entry uv_prediction_mode_map[] = {
Luc Trudeau6e1cd782017-06-21 13:52:36 -0400227 ENUM(UV_DC_PRED), ENUM(UV_V_PRED),
228 ENUM(UV_H_PRED), ENUM(UV_D45_PRED),
229 ENUM(UV_D135_PRED), ENUM(UV_D117_PRED),
230 ENUM(UV_D153_PRED), ENUM(UV_D207_PRED),
Urvang Joshi93b543a2017-06-01 17:32:41 -0700231 ENUM(UV_D63_PRED), ENUM(UV_SMOOTH_PRED),
Luc Trudeaud6d9eee2017-07-12 12:36:50 -0400232#if CONFIG_SMOOTH_HV
233 ENUM(UV_SMOOTH_V_PRED), ENUM(UV_SMOOTH_H_PRED),
234#endif // CONFIG_SMOOTH_HV
Urvang Joshi96d1c0a2017-10-10 13:15:32 -0700235 ENUM(UV_PAETH_PRED),
Luc Trudeau6e1cd782017-06-21 13:52:36 -0400236#if CONFIG_CFL
237 ENUM(UV_CFL_PRED),
238#endif
239 ENUM(UV_MODE_INVALID), LAST_ENUM
Luc Trudeaud6d9eee2017-07-12 12:36:50 -0400240};
241#else
242#define uv_prediction_mode_map prediction_mode_map
243#endif
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800244#define NO_SKIP 0
245#define SKIP 1
246
247const map_entry skip_map[] = { ENUM(SKIP), ENUM(NO_SKIP), LAST_ENUM };
248
249const map_entry config_map[] = { ENUM(MI_SIZE), LAST_ENUM };
250
251static const char *exec_name;
252
253insp_frame_data frame_data;
254int frame_count = 0;
255int decoded_frame_count = 0;
256aom_codec_ctx_t codec;
257AvxVideoReader *reader = NULL;
258const AvxVideoInfo *info = NULL;
259aom_image_t *img = NULL;
260
261void on_frame_decoded_dump(char *json) {
262#ifdef __EMSCRIPTEN__
263 EM_ASM_({ Module.on_frame_decoded_json($0); }, json);
264#else
265 printf("%s", json);
266#endif
267}
268
269// Writing out the JSON buffer using snprintf is very slow, especially when
270// compiled with emscripten, these functions speed things up quite a bit.
271int put_str(char *buffer, const char *str) {
272 int i;
273 for (i = 0; str[i] != '\0'; i++) {
274 buffer[i] = str[i];
275 }
276 return i;
277}
278
Michael Bebenita4aee17d2017-07-05 14:03:36 -0700279int put_str_with_escape(char *buffer, const char *str) {
280 int i;
281 int j = 0;
282 for (i = 0; str[i] != '\0'; i++) {
Thomas Daede3a1bd782017-07-21 12:17:10 -0700283 if (str[i] < ' ') {
284 continue;
285 } else if (str[i] == '"' || str[i] == '\\') {
Michael Bebenita4aee17d2017-07-05 14:03:36 -0700286 buffer[j++] = '\\';
287 }
288 buffer[j++] = str[i];
289 }
290 return j;
291}
292
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800293int put_num(char *buffer, char prefix, int num, char suffix) {
294 int i = 0;
295 char *buf = buffer;
296 int is_neg = 0;
297 if (prefix) {
298 buf[i++] = prefix;
299 }
300 if (num == 0) {
301 buf[i++] = '0';
302 } else {
303 if (num < 0) {
304 num = -num;
305 is_neg = 1;
306 }
307 int s = i;
308 while (num != 0) {
309 buf[i++] = '0' + (num % 10);
310 num = num / 10;
311 }
312 if (is_neg) {
313 buf[i++] = '-';
314 }
315 int e = i - 1;
316 while (s < e) {
317 int t = buf[s];
318 buf[s] = buf[e];
319 buf[e] = t;
320 s++;
321 e--;
322 }
323 }
324 if (suffix) {
325 buf[i++] = suffix;
326 }
327 return i;
328}
329
330int put_map(char *buffer, const map_entry *map) {
331 char *buf = buffer;
332 const map_entry *entry = map;
333 while (entry->name != NULL) {
334 *(buf++) = '"';
335 buf += put_str(buf, entry->name);
336 *(buf++) = '"';
337 buf += put_num(buf, ':', entry->value, 0);
338 entry++;
339 if (entry->name != NULL) {
340 *(buf++) = ',';
341 }
342 }
Yushin Chof6741572017-10-24 20:07:46 -0700343 return (int)(buf - buffer);
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800344}
345
346int put_reference_frame(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, " \"referenceFrameMap\": {");
352 buf += put_map(buf, refs_map);
353 buf += put_str(buf, "},\n");
354 buf += put_str(buf, " \"referenceFrame\": [");
355 for (r = 0; r < mi_rows; ++r) {
356 *(buf++) = '[';
357 for (c = 0; c < mi_cols; ++c) {
358 insp_mi_data *mi = &frame_data.mi_grid[r * mi_cols + c];
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800359 buf += put_num(buf, '[', mi->ref_frame[0], 0);
360 buf += put_num(buf, ',', mi->ref_frame[1], ']');
Michael Bebenitaf1207b62017-04-14 22:30:56 -0700361 if (compress) { // RLE
362 for (t = c + 1; t < mi_cols; ++t) {
363 insp_mi_data *next_mi = &frame_data.mi_grid[r * mi_cols + t];
364 if (mi->ref_frame[0] != next_mi->ref_frame[0] ||
365 mi->ref_frame[1] != next_mi->ref_frame[1]) {
366 break;
367 }
368 }
369 if (t - c > 1) {
370 *(buf++) = ',';
371 buf += put_num(buf, '[', t - c - 1, ']');
372 c = t - 1;
373 }
374 }
375 if (c < mi_cols - 1) *(buf++) = ',';
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800376 }
377 *(buf++) = ']';
378 if (r < mi_rows - 1) *(buf++) = ',';
379 }
380 buf += put_str(buf, "],\n");
Yushin Chof6741572017-10-24 20:07:46 -0700381 return (int)(buf - buffer);
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800382}
383
384int put_motion_vectors(char *buffer) {
385 const int mi_rows = frame_data.mi_rows;
386 const int mi_cols = frame_data.mi_cols;
387 char *buf = buffer;
Michael Bebenitaf1207b62017-04-14 22:30:56 -0700388 int r, c, t;
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800389 buf += put_str(buf, " \"motionVectors\": [");
390 for (r = 0; r < mi_rows; ++r) {
391 *(buf++) = '[';
392 for (c = 0; c < mi_cols; ++c) {
393 insp_mi_data *mi = &frame_data.mi_grid[r * mi_cols + c];
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800394 buf += put_num(buf, '[', mi->mv[0].col, 0);
395 buf += put_num(buf, ',', mi->mv[0].row, 0);
396 buf += put_num(buf, ',', mi->mv[1].col, 0);
397 buf += put_num(buf, ',', mi->mv[1].row, ']');
Michael Bebenitaf1207b62017-04-14 22:30:56 -0700398 if (compress) { // RLE
399 for (t = c + 1; t < mi_cols; ++t) {
400 insp_mi_data *next_mi = &frame_data.mi_grid[r * mi_cols + t];
401 if (mi->mv[0].col != next_mi->mv[0].col ||
402 mi->mv[0].row != next_mi->mv[0].row ||
403 mi->mv[1].col != next_mi->mv[1].col ||
404 mi->mv[1].row != next_mi->mv[1].row) {
405 break;
406 }
407 }
408 if (t - c > 1) {
409 *(buf++) = ',';
410 buf += put_num(buf, '[', t - c - 1, ']');
411 c = t - 1;
412 }
413 }
414 if (c < mi_cols - 1) *(buf++) = ',';
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800415 }
416 *(buf++) = ']';
417 if (r < mi_rows - 1) *(buf++) = ',';
418 }
419 buf += put_str(buf, "],\n");
Yushin Chof6741572017-10-24 20:07:46 -0700420 return (int)(buf - buffer);
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800421}
422
423int put_block_info(char *buffer, const map_entry *map, const char *name,
Michael Bebenita14e1b742017-10-24 12:49:15 -0700424 size_t offset, int len) {
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800425 const int mi_rows = frame_data.mi_rows;
426 const int mi_cols = frame_data.mi_cols;
427 char *buf = buffer;
Michael Bebenita14e1b742017-10-24 12:49:15 -0700428 int r, c, t, i;
429 if (compress && len == 1) {
430 die("Can't encode scalars as arrays when RLE compression is enabled.");
431 return -1;
432 }
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800433 if (map) {
434 buf += snprintf(buf, MAX_BUFFER, " \"%sMap\": {", name);
435 buf += put_map(buf, map);
436 buf += put_str(buf, "},\n");
437 }
438 buf += snprintf(buf, MAX_BUFFER, " \"%s\": [", name);
439 for (r = 0; r < mi_rows; ++r) {
440 *(buf++) = '[';
441 for (c = 0; c < mi_cols; ++c) {
Michael Bebenita14e1b742017-10-24 12:49:15 -0700442 insp_mi_data *mi = &frame_data.mi_grid[r * mi_cols + c];
Yushin Choc24351c2017-10-24 14:59:08 -0700443 int16_t *v = (int16_t *)(((int8_t *)mi) + offset);
Michael Bebenita14e1b742017-10-24 12:49:15 -0700444 if (len == 0) {
445 buf += put_num(buf, 0, v[0], 0);
446 } else {
447 buf += put_str(buf, "[");
448 for (i = 0; i < len; i++) {
449 buf += put_num(buf, 0, v[i], 0);
450 if (i < len - 1) {
451 buf += put_str(buf, ",");
452 }
453 }
454 buf += put_str(buf, "]");
455 }
Michael Bebenitaf1207b62017-04-14 22:30:56 -0700456 if (compress) { // RLE
457 for (t = c + 1; t < mi_cols; ++t) {
458 insp_mi_data *next_mi = &frame_data.mi_grid[r * mi_cols + t];
Yushin Choc24351c2017-10-24 14:59:08 -0700459 int16_t *nv = (int16_t *)(((int8_t *)next_mi) + offset);
Michael Bebenita14e1b742017-10-24 12:49:15 -0700460 int same = 0;
461 if (len == 0) {
462 same = v[0] == nv[0];
463 } else {
464 for (i = 0; i < len; i++) {
465 same = v[i] == nv[i];
466 if (!same) {
467 break;
468 }
469 }
470 }
471 if (!same) {
Michael Bebenitaf1207b62017-04-14 22:30:56 -0700472 break;
473 }
474 }
475 if (t - c > 1) {
476 *(buf++) = ',';
477 buf += put_num(buf, '[', t - c - 1, ']');
478 c = t - 1;
479 }
480 }
481 if (c < mi_cols - 1) *(buf++) = ',';
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800482 }
483 *(buf++) = ']';
484 if (r < mi_rows - 1) *(buf++) = ',';
485 }
486 buf += put_str(buf, "],\n");
Yushin Chof6741572017-10-24 20:07:46 -0700487 return (int)(buf - buffer);
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800488}
489
490#if CONFIG_ACCOUNTING
491int put_accounting(char *buffer) {
492 char *buf = buffer;
493 int i;
494 const Accounting *accounting = frame_data.accounting;
495 if (accounting == NULL) {
496 printf("XXX\n");
497 return 0;
498 }
499 const int num_syms = accounting->syms.num_syms;
500 const int num_strs = accounting->syms.dictionary.num_strs;
501 buf += put_str(buf, " \"symbolsMap\": [");
502 for (i = 0; i < num_strs; i++) {
503 buf += snprintf(buf, MAX_BUFFER, "\"%s\"",
504 accounting->syms.dictionary.strs[i]);
505 if (i < num_strs - 1) *(buf++) = ',';
506 }
507 buf += put_str(buf, "],\n");
508 buf += put_str(buf, " \"symbols\": [\n ");
509 AccountingSymbolContext context;
510 context.x = -2;
511 context.y = -2;
512 AccountingSymbol *sym;
513 for (i = 0; i < num_syms; i++) {
514 sym = &accounting->syms.syms[i];
515 if (memcmp(&context, &sym->context, sizeof(AccountingSymbolContext)) != 0) {
516 buf += put_num(buf, '[', sym->context.x, 0);
517 buf += put_num(buf, ',', sym->context.y, ']');
518 } else {
519 buf += put_num(buf, '[', sym->id, 0);
520 buf += put_num(buf, ',', sym->bits, 0);
521 buf += put_num(buf, ',', sym->samples, ']');
522 }
523 context = sym->context;
524 if (i < num_syms - 1) *(buf++) = ',';
525 }
526 buf += put_str(buf, "],\n");
Yushin Chof6741572017-10-24 20:07:46 -0700527 return (int)(buf - buffer);
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800528}
529#endif
530
531void inspect(void *pbi, void *data) {
532 /* Fetch frame data. */
533 ifd_inspect(&frame_data, pbi);
534 (void)data;
535 // We allocate enough space and hope we don't write out of bounds. Totally
536 // unsafe but this speeds things up, especially when compiled to Javascript.
537 char *buffer = aom_malloc(MAX_BUFFER);
538 char *buf = buffer;
539 buf += put_str(buf, "{\n");
540 if (layers & BLOCK_SIZE_LAYER) {
541 buf += put_block_info(buf, block_size_map, "blockSize",
Michael Bebenita14e1b742017-10-24 12:49:15 -0700542 offsetof(insp_mi_data, sb_type), 0);
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800543 }
544 if (layers & TRANSFORM_SIZE_LAYER) {
545 buf += put_block_info(buf, tx_size_map, "transformSize",
Michael Bebenita14e1b742017-10-24 12:49:15 -0700546 offsetof(insp_mi_data, tx_size), 0);
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800547 }
548 if (layers & TRANSFORM_TYPE_LAYER) {
549 buf += put_block_info(buf, tx_type_map, "transformType",
Michael Bebenita14e1b742017-10-24 12:49:15 -0700550 offsetof(insp_mi_data, tx_type), 0);
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800551 }
Ankur Saxena6e6b6972017-10-20 22:10:10 -0700552#if CONFIG_DUAL_FILTER
553 if (layers & DUAL_FILTER_LAYER) {
554 buf += put_block_info(buf, dual_filter_map, "dualFilterType",
Michael Bebenita14e1b742017-10-24 12:49:15 -0700555 offsetof(insp_mi_data, dual_filter_type), 0);
Ankur Saxena6e6b6972017-10-20 22:10:10 -0700556 }
557#endif
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800558 if (layers & MODE_LAYER) {
559 buf += put_block_info(buf, prediction_mode_map, "mode",
Michael Bebenita14e1b742017-10-24 12:49:15 -0700560 offsetof(insp_mi_data, mode), 0);
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800561 }
Luc Trudeau0be435a2017-04-07 23:38:52 -0400562 if (layers & UV_MODE_LAYER) {
Luc Trudeaud6d9eee2017-07-12 12:36:50 -0400563 buf += put_block_info(buf, uv_prediction_mode_map, "uv_mode",
Michael Bebenita14e1b742017-10-24 12:49:15 -0700564 offsetof(insp_mi_data, uv_mode), 0);
Luc Trudeau0be435a2017-04-07 23:38:52 -0400565 }
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800566 if (layers & SKIP_LAYER) {
Michael Bebenita14e1b742017-10-24 12:49:15 -0700567 buf +=
568 put_block_info(buf, skip_map, "skip", offsetof(insp_mi_data, skip), 1);
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800569 }
570 if (layers & FILTER_LAYER) {
Michael Bebenita14e1b742017-10-24 12:49:15 -0700571#if CONFIG_DUAL_FILTER
572 buf +=
573 put_block_info(buf, NULL, "filter", offsetof(insp_mi_data, filter), 2);
574#else
575 buf +=
576 put_block_info(buf, NULL, "filter", offsetof(insp_mi_data, filter), 0);
577#endif
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800578 }
Alex Converse0ec34d22017-04-03 14:54:07 -0700579#if CONFIG_CDEF
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800580 if (layers & CDEF_LAYER) {
Michael Bebenita09558812017-04-01 20:10:53 -0700581 buf += put_block_info(buf, NULL, "cdef_level",
Michael Bebenita14e1b742017-10-24 12:49:15 -0700582 offsetof(insp_mi_data, cdef_level), 0);
Michael Bebenita09558812017-04-01 20:10:53 -0700583 buf += put_block_info(buf, NULL, "cdef_strength",
Michael Bebenita14e1b742017-10-24 12:49:15 -0700584 offsetof(insp_mi_data, cdef_strength), 0);
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800585 }
Alex Converse0ec34d22017-04-03 14:54:07 -0700586#endif
Luc Trudeauf89056a2017-04-28 16:07:22 -0400587#if CONFIG_CFL
588 if (layers & CFL_LAYER) {
Luc Trudeaua9bd85f2017-05-11 14:37:56 -0400589 buf += put_block_info(buf, NULL, "cfl_alpha_idx",
Michael Bebenita14e1b742017-10-24 12:49:15 -0700590 offsetof(insp_mi_data, cfl_alpha_idx), 0);
Luc Trudeau9bab28b2017-05-11 15:23:02 -0400591 buf += put_block_info(buf, NULL, "cfl_alpha_sign",
Michael Bebenita14e1b742017-10-24 12:49:15 -0700592 offsetof(insp_mi_data, cfl_alpha_sign), 0);
Luc Trudeauf89056a2017-04-28 16:07:22 -0400593 }
594#endif
Yushin Choc24351c2017-10-24 14:59:08 -0700595 if (layers & Q_INDEX_LAYER) {
596 buf += put_block_info(buf, NULL, "delta_q",
597 offsetof(insp_mi_data, current_qindex), 0);
598 }
Yushin Cho4be87e02017-10-25 16:27:04 -0700599 if (layers & SEGMENT_ID_LAYER) {
600 buf += put_block_info(buf, NULL, "seg_id",
601 offsetof(insp_mi_data, segment_id), 0);
602 }
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800603 if (layers & MOTION_VECTORS_LAYER) {
604 buf += put_motion_vectors(buf);
605 }
606 if (layers & REFERENCE_FRAME_LAYER) {
Michael Bebenita14e1b742017-10-24 12:49:15 -0700607 buf += put_block_info(buf, refs_map, "referenceFrame",
608 offsetof(insp_mi_data, ref_frame), 2);
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800609 }
610#if CONFIG_ACCOUNTING
611 if (layers & ACCOUNTING_LAYER) {
612 buf += put_accounting(buf);
613 }
614#endif
615 buf += snprintf(buf, MAX_BUFFER, " \"frame\": %d,\n", decoded_frame_count);
616 buf += snprintf(buf, MAX_BUFFER, " \"showFrame\": %d,\n",
617 frame_data.show_frame);
618 buf += snprintf(buf, MAX_BUFFER, " \"frameType\": %d,\n",
619 frame_data.frame_type);
620 buf += snprintf(buf, MAX_BUFFER, " \"baseQIndex\": %d,\n",
621 frame_data.base_qindex);
Michael Bebenita2c2e5612017-04-06 22:19:04 -0400622 buf += snprintf(buf, MAX_BUFFER, " \"tileCols\": %d,\n",
623 frame_data.tile_mi_cols);
624 buf += snprintf(buf, MAX_BUFFER, " \"tileRows\": %d,\n",
625 frame_data.tile_mi_rows);
Yushin Choc24351c2017-10-24 14:59:08 -0700626 buf += snprintf(buf, MAX_BUFFER, " \"deltaQPresentFlag\": %d,\n",
627 frame_data.delta_q_present_flag);
628 buf += snprintf(buf, MAX_BUFFER, " \"deltaQRes\": %d,\n",
629 frame_data.delta_q_res);
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800630 buf += put_str(buf, " \"config\": {");
631 buf += put_map(buf, config_map);
632 buf += put_str(buf, "},\n");
Michael Bebenita4aee17d2017-07-05 14:03:36 -0700633 buf += put_str(buf, " \"configString\": \"");
634 buf += put_str_with_escape(buf, aom_codec_build_config());
635 buf += put_str(buf, "\"\n");
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800636 decoded_frame_count++;
637 buf += put_str(buf, "},\n");
638 *(buf++) = 0;
639 on_frame_decoded_dump(buffer);
640 aom_free(buffer);
641}
642
643void ifd_init_cb() {
644 aom_inspect_init ii;
645 ii.inspect_cb = inspect;
646 ii.inspect_ctx = NULL;
647 aom_codec_control(&codec, AV1_SET_INSPECTION_CALLBACK, &ii);
648}
649
650EMSCRIPTEN_KEEPALIVE
651int open_file(char *file) {
652 if (file == NULL) {
653 // The JS analyzer puts the .ivf file at this location.
654 file = "/tmp/input.ivf";
655 }
656 reader = aom_video_reader_open(file);
657 if (!reader) die("Failed to open %s for reading.", file);
658 info = aom_video_reader_get_info(reader);
659 const AvxInterface *decoder = get_aom_decoder_by_fourcc(info->codec_fourcc);
660 if (!decoder) die("Unknown input codec.");
661 fprintf(stderr, "Using %s\n",
662 aom_codec_iface_name(decoder->codec_interface()));
663 if (aom_codec_dec_init(&codec, decoder->codec_interface(), NULL, 0))
664 die_codec(&codec, "Failed to initialize decoder.");
665 ifd_init(&frame_data, info->frame_width, info->frame_height);
666 ifd_init_cb();
667 return EXIT_SUCCESS;
668}
669
670EMSCRIPTEN_KEEPALIVE
671int read_frame() {
672 if (!aom_video_reader_read_frame(reader)) return EXIT_FAILURE;
673 img = NULL;
674 aom_codec_iter_t iter = NULL;
675 size_t frame_size = 0;
676 const unsigned char *frame = aom_video_reader_get_frame(reader, &frame_size);
677 if (aom_codec_decode(&codec, frame, (unsigned int)frame_size, NULL, 0) !=
678 AOM_CODEC_OK) {
679 die_codec(&codec, "Failed to decode frame.");
680 }
681 img = aom_codec_get_frame(&codec, &iter);
682 if (img == NULL) {
683 return EXIT_FAILURE;
684 }
685 ++frame_count;
686 return EXIT_SUCCESS;
687}
688
689EMSCRIPTEN_KEEPALIVE
690const char *get_aom_codec_build_config() { return aom_codec_build_config(); }
691
692EMSCRIPTEN_KEEPALIVE
693int get_bit_depth() { return img->bit_depth; }
694
695EMSCRIPTEN_KEEPALIVE
Michael Bebenitabf1f9ee2017-06-16 15:54:08 -0700696int get_bits_per_sample() { return img->bps; }
697
698EMSCRIPTEN_KEEPALIVE
699int get_image_format() { return img->fmt; }
700
701EMSCRIPTEN_KEEPALIVE
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800702unsigned char *get_plane(int plane) { return img->planes[plane]; }
703
704EMSCRIPTEN_KEEPALIVE
705int get_plane_stride(int plane) { return img->stride[plane]; }
706
707EMSCRIPTEN_KEEPALIVE
708int get_plane_width(int plane) { return aom_img_plane_width(img, plane); }
709
710EMSCRIPTEN_KEEPALIVE
711int get_plane_height(int plane) { return aom_img_plane_height(img, plane); }
712
713EMSCRIPTEN_KEEPALIVE
714int get_frame_width() { return info->frame_width; }
715
716EMSCRIPTEN_KEEPALIVE
717int get_frame_height() { return info->frame_height; }
718
719static void parse_args(char **argv) {
720 char **argi, **argj;
721 struct arg arg;
722 (void)dump_accounting_arg;
Alex Converse0ec34d22017-04-03 14:54:07 -0700723 (void)dump_cdef_arg;
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800724 for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step) {
725 arg.argv_step = 1;
726 if (arg_match(&arg, &dump_block_size_arg, argi)) layers |= BLOCK_SIZE_LAYER;
727#if CONFIG_ACCOUNTING
728 else if (arg_match(&arg, &dump_accounting_arg, argi))
729 layers |= ACCOUNTING_LAYER;
730#endif
731 else if (arg_match(&arg, &dump_transform_size_arg, argi))
732 layers |= TRANSFORM_SIZE_LAYER;
733 else if (arg_match(&arg, &dump_transform_type_arg, argi))
734 layers |= TRANSFORM_TYPE_LAYER;
735 else if (arg_match(&arg, &dump_mode_arg, argi))
736 layers |= MODE_LAYER;
Luc Trudeau0be435a2017-04-07 23:38:52 -0400737 else if (arg_match(&arg, &dump_uv_mode_arg, argi))
738 layers |= UV_MODE_LAYER;
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800739 else if (arg_match(&arg, &dump_skip_arg, argi))
740 layers |= SKIP_LAYER;
741 else if (arg_match(&arg, &dump_filter_arg, argi))
742 layers |= FILTER_LAYER;
Alex Converse0ec34d22017-04-03 14:54:07 -0700743#if CONFIG_CDEF
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800744 else if (arg_match(&arg, &dump_cdef_arg, argi))
745 layers |= CDEF_LAYER;
Alex Converse0ec34d22017-04-03 14:54:07 -0700746#endif
Luc Trudeauf89056a2017-04-28 16:07:22 -0400747#if CONFIG_CFL
748 else if (arg_match(&arg, &dump_cfl_arg, argi))
749 layers |= CFL_LAYER;
750#endif
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800751 else if (arg_match(&arg, &dump_reference_frame_arg, argi))
752 layers |= REFERENCE_FRAME_LAYER;
753 else if (arg_match(&arg, &dump_motion_vectors_arg, argi))
754 layers |= MOTION_VECTORS_LAYER;
Ankur Saxena6e6b6972017-10-20 22:10:10 -0700755#if CONFIG_DUAL_FILTER
756 else if (arg_match(&arg, &dump_dual_filter_type_arg, argi))
757 layers |= DUAL_FILTER_LAYER;
758#endif
Yushin Choc24351c2017-10-24 14:59:08 -0700759 else if (arg_match(&arg, &dump_delta_q_arg, argi))
760 layers |= Q_INDEX_LAYER;
Yushin Cho4be87e02017-10-25 16:27:04 -0700761 else if (arg_match(&arg, &dump_seg_id_arg, argi))
762 layers |= SEGMENT_ID_LAYER;
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800763 else if (arg_match(&arg, &dump_all_arg, argi))
764 layers |= ALL_LAYERS;
Michael Bebenitaf1207b62017-04-14 22:30:56 -0700765 else if (arg_match(&arg, &compress_arg, argi))
766 compress = 1;
Michael Bebenitaf4f27fe2017-03-02 17:40:44 -0800767 else if (arg_match(&arg, &usage_arg, argi))
768 usage_exit();
769 else if (arg_match(&arg, &limit_arg, argi))
770 stop_after = arg_parse_uint(&arg);
771 else
772 argj++;
773 }
774}
775
776static const char *exec_name;
777
778void usage_exit(void) {
779 fprintf(stderr, "Usage: %s src_filename <options>\n", exec_name);
780 fprintf(stderr, "\nOptions:\n");
781 arg_show_usage(stderr, main_args);
782 exit(EXIT_FAILURE);
783}
784
785EMSCRIPTEN_KEEPALIVE
786int main(int argc, char **argv) {
787 exec_name = argv[0];
788 parse_args(argv);
789 if (argc >= 2) {
790 open_file(argv[1]);
791 printf("[\n");
792 while (1) {
793 if (stop_after && (decoded_frame_count >= stop_after)) break;
794 if (read_frame()) break;
795 }
796 printf("null\n");
797 printf("]");
798 } else {
799 usage_exit();
800 }
801}
802
803EMSCRIPTEN_KEEPALIVE
804void quit() {
805 if (aom_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec");
806 aom_video_reader_close(reader);
807}
808
809EMSCRIPTEN_KEEPALIVE
810void set_layers(LayerType v) { layers = v; }
Michael Bebenitaf1207b62017-04-14 22:30:56 -0700811
812EMSCRIPTEN_KEEPALIVE
813void set_compress(int v) { compress = v; }