1 /*
2 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
3 *
4 * This source code is subject to the terms of the BSD 2 Clause License and
5 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6 * was not distributed with this source code in the LICENSE file, you can
7 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8 * Media Patent License 1.0 was not distributed with this source code in the
9 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
10 */
11
12 // Inspect Decoder
13 // ================
14 //
15 // This is a simple decoder loop that writes JSON stats to stdout. This tool
16 // can also be compiled with Emscripten and used as a library.
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21
22 #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"
30 #include "./aom_config.h"
31 #if CONFIG_ACCOUNTING
32 #include "../av1/decoder/accounting.h"
33 #endif
34 #include "../av1/decoder/inspection.h"
35 #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"
41
42 #include "../video_common.h"
43
44 // Max JSON buffer size.
45 const int MAX_BUFFER = 1024 * 1024 * 32;
46
47 typedef enum {
48 ACCOUNTING_LAYER = 1,
49 BLOCK_SIZE_LAYER = 1 << 1,
50 TRANSFORM_SIZE_LAYER = 1 << 2,
51 TRANSFORM_TYPE_LAYER = 1 << 3,
52 MODE_LAYER = 1 << 4,
53 SKIP_LAYER = 1 << 5,
54 FILTER_LAYER = 1 << 6,
55 CDEF_LAYER = 1 << 7,
56 REFERENCE_FRAME_LAYER = 1 << 8,
57 MOTION_VECTORS_LAYER = 1 << 9,
58 UV_MODE_LAYER = 1 << 10,
59 CFL_LAYER = 1 << 11,
60 ALL_LAYERS = (1 << 12) - 1
61 } LayerType;
62
63 static LayerType layers = 0;
64
65 static int stop_after = 0;
66 static int compress = 0;
67
68 static const arg_def_t limit_arg =
69 ARG_DEF(NULL, "limit", 1, "Stop decoding after n frames");
70 static const arg_def_t dump_all_arg = ARG_DEF("A", "all", 0, "Dump All");
71 static const arg_def_t compress_arg =
72 ARG_DEF("x", "compress", 0, "Compress JSON using RLE");
73 static const arg_def_t dump_accounting_arg =
74 ARG_DEF("a", "accounting", 0, "Dump Accounting");
75 static const arg_def_t dump_block_size_arg =
76 ARG_DEF("bs", "blockSize", 0, "Dump Block Size");
77 static const arg_def_t dump_motion_vectors_arg =
78 ARG_DEF("mv", "motionVectors", 0, "Dump Motion Vectors");
79 static const arg_def_t dump_transform_size_arg =
80 ARG_DEF("ts", "transformSize", 0, "Dump Transform Size");
81 static const arg_def_t dump_transform_type_arg =
82 ARG_DEF("tt", "transformType", 0, "Dump Transform Type");
83 static const arg_def_t dump_mode_arg = ARG_DEF("m", "mode", 0, "Dump Mode");
84 static const arg_def_t dump_uv_mode_arg =
85 ARG_DEF("uvm", "uv_mode", 0, "Dump UV Intra Prediction Modes");
86 static const arg_def_t dump_skip_arg = ARG_DEF("s", "skip", 0, "Dump Skip");
87 static const arg_def_t dump_filter_arg =
88 ARG_DEF("f", "filter", 0, "Dump Filter");
89 static const arg_def_t dump_cdef_arg = ARG_DEF("c", "cdef", 0, "Dump CDEF");
90 #if CONFIG_CFL
91 static const arg_def_t dump_cfl_arg =
92 ARG_DEF("cfl", "chroma_from_luma", 0, "Dump Chroma from Luma Alphas");
93 #endif
94 static const arg_def_t dump_reference_frame_arg =
95 ARG_DEF("r", "referenceFrame", 0, "Dump Reference Frame");
96 static const arg_def_t usage_arg = ARG_DEF("h", "help", 0, "Help");
97
98 static const arg_def_t *main_args[] = { &limit_arg,
99 &dump_all_arg,
100 &compress_arg,
101 #if CONFIG_ACCOUNTING
102 &dump_accounting_arg,
103 #endif
104 &dump_block_size_arg,
105 &dump_transform_size_arg,
106 &dump_transform_type_arg,
107 &dump_mode_arg,
108 &dump_uv_mode_arg,
109 &dump_skip_arg,
110 &dump_filter_arg,
111 #if CONFIG_CDEF
112 &dump_cdef_arg,
113 #endif
114 #if CONFIG_CFL
115 &dump_cfl_arg,
116 #endif
117 &dump_reference_frame_arg,
118 &dump_motion_vectors_arg,
119 &usage_arg,
120 NULL };
121 #define ENUM(name) \
122 { #name, name }
123 #define LAST_ENUM \
124 { NULL, 0 }
125 typedef struct map_entry {
126 const char *name;
127 int value;
128 } map_entry;
129
130 const map_entry refs_map[] = { ENUM(INTRA_FRAME), ENUM(LAST_FRAME),
131 #if CONFIG_EXT_REFS
132 ENUM(LAST2_FRAME), ENUM(LAST3_FRAME),
133 ENUM(GOLDEN_FRAME), ENUM(BWDREF_FRAME),
134 ENUM(ALTREF_FRAME),
135 #else
136 ENUM(GOLDEN_FRAME), ENUM(ALTREF_FRAME),
137 #endif
138 LAST_ENUM };
139
140 const map_entry block_size_map[] = {
141 #if CONFIG_CHROMA_2X2 || CONFIG_CHROMA_SUB8X8
142 ENUM(BLOCK_2X2), ENUM(BLOCK_2X4), ENUM(BLOCK_4X2),
143 #endif
144 ENUM(BLOCK_4X4), ENUM(BLOCK_4X8), ENUM(BLOCK_8X4),
145 ENUM(BLOCK_8X8), ENUM(BLOCK_8X16), ENUM(BLOCK_16X8),
146 ENUM(BLOCK_16X16), ENUM(BLOCK_16X32), ENUM(BLOCK_32X16),
147 ENUM(BLOCK_32X32), ENUM(BLOCK_32X64), ENUM(BLOCK_64X32),
148 ENUM(BLOCK_64X64),
149 #if CONFIG_EXT_PARTITION
150 ENUM(BLOCK_64X128), ENUM(BLOCK_128X64), ENUM(BLOCK_128X128),
151 #endif
152 ENUM(BLOCK_4X16), ENUM(BLOCK_16X4), ENUM(BLOCK_8X32),
153 ENUM(BLOCK_32X8), ENUM(BLOCK_16X64), ENUM(BLOCK_64X16),
154 #if CONFIG_EXT_PARTITION
155 ENUM(BLOCK_32X128), ENUM(BLOCK_128X32),
156 #endif
157 LAST_ENUM
158 };
159
160 const map_entry tx_size_map[] = {
161 #if CONFIG_CHROMA_2X2
162 ENUM(TX_2X2),
163 #endif
164 ENUM(TX_4X4), ENUM(TX_8X8), ENUM(TX_16X16), ENUM(TX_32X32),
165 #if CONFIG_TX64X64
166 ENUM(TX_64X64),
167 #endif
168 ENUM(TX_4X8), ENUM(TX_8X4), ENUM(TX_8X16), ENUM(TX_16X8),
169 ENUM(TX_16X32), ENUM(TX_32X16),
170 #if CONFIG_TX64X64
171 ENUM(TX_32X64), ENUM(TX_64X32),
172 #endif // CONFIG_TX64X64
173 ENUM(TX_4X16), ENUM(TX_16X4), ENUM(TX_8X32), ENUM(TX_32X8),
174 LAST_ENUM
175 };
176
177 const map_entry tx_type_map[] = { ENUM(DCT_DCT),
178 ENUM(ADST_DCT),
179 ENUM(DCT_ADST),
180 ENUM(ADST_ADST),
181 #if CONFIG_EXT_TX
182 ENUM(FLIPADST_DCT),
183 ENUM(DCT_FLIPADST),
184 ENUM(FLIPADST_FLIPADST),
185 ENUM(ADST_FLIPADST),
186 ENUM(FLIPADST_ADST),
187 ENUM(IDTX),
188 ENUM(V_DCT),
189 ENUM(H_DCT),
190 ENUM(V_ADST),
191 ENUM(H_ADST),
192 ENUM(V_FLIPADST),
193 ENUM(H_FLIPADST),
194 #endif
195 LAST_ENUM };
196
197 const map_entry prediction_mode_map[] = {
198 ENUM(DC_PRED), ENUM(V_PRED), ENUM(H_PRED),
199 ENUM(D45_PRED), ENUM(D135_PRED), ENUM(D117_PRED),
200 ENUM(D153_PRED), ENUM(D207_PRED), ENUM(D63_PRED),
201 ENUM(SMOOTH_PRED),
202 #if CONFIG_SMOOTH_HV
203 ENUM(SMOOTH_V_PRED), ENUM(SMOOTH_H_PRED),
204 #endif // CONFIG_SMOOTH_HV
205 ENUM(TM_PRED), ENUM(NEARESTMV), ENUM(NEARMV),
206 ENUM(ZEROMV), ENUM(NEWMV), ENUM(NEAREST_NEARESTMV),
207 ENUM(NEAR_NEARMV), ENUM(NEAREST_NEWMV), ENUM(NEW_NEARESTMV),
208 ENUM(NEAR_NEWMV), ENUM(NEW_NEARMV), ENUM(ZERO_ZEROMV),
209 ENUM(NEW_NEWMV), ENUM(INTRA_INVALID), LAST_ENUM
210 };
211
212 #if CONFIG_CFL
213 const map_entry uv_prediction_mode_map[] = {
214 ENUM(UV_DC_PRED), ENUM(UV_V_PRED),
215 ENUM(UV_H_PRED), ENUM(UV_D45_PRED),
216 ENUM(UV_D135_PRED), ENUM(UV_D117_PRED),
217 ENUM(UV_D153_PRED), ENUM(UV_D207_PRED),
218 ENUM(UV_D63_PRED), ENUM(UV_SMOOTH_PRED),
219 #if CONFIG_SMOOTH_HV
220 ENUM(UV_SMOOTH_V_PRED), ENUM(UV_SMOOTH_H_PRED),
221 #endif // CONFIG_SMOOTH_HV
222 ENUM(UV_TM_PRED),
223 #if CONFIG_CFL
224 ENUM(UV_CFL_PRED),
225 #endif
226 ENUM(UV_MODE_INVALID), LAST_ENUM
227 };
228 #else
229 #define uv_prediction_mode_map prediction_mode_map
230 #endif
231 #define NO_SKIP 0
232 #define SKIP 1
233
234 const map_entry skip_map[] = { ENUM(SKIP), ENUM(NO_SKIP), LAST_ENUM };
235
236 const map_entry config_map[] = { ENUM(MI_SIZE), LAST_ENUM };
237
238 static const char *exec_name;
239
240 insp_frame_data frame_data;
241 int frame_count = 0;
242 int decoded_frame_count = 0;
243 aom_codec_ctx_t codec;
244 AvxVideoReader *reader = NULL;
245 const AvxVideoInfo *info = NULL;
246 aom_image_t *img = NULL;
247
on_frame_decoded_dump(char * json)248 void on_frame_decoded_dump(char *json) {
249 #ifdef __EMSCRIPTEN__
250 EM_ASM_({ Module.on_frame_decoded_json($0); }, json);
251 #else
252 printf("%s", json);
253 #endif
254 }
255
256 // Writing out the JSON buffer using snprintf is very slow, especially when
257 // compiled with emscripten, these functions speed things up quite a bit.
put_str(char * buffer,const char * str)258 int put_str(char *buffer, const char *str) {
259 int i;
260 for (i = 0; str[i] != '\0'; i++) {
261 buffer[i] = str[i];
262 }
263 return i;
264 }
265
put_str_with_escape(char * buffer,const char * str)266 int put_str_with_escape(char *buffer, const char *str) {
267 int i;
268 int j = 0;
269 for (i = 0; str[i] != '\0'; i++) {
270 if (str[i] < ' ') {
271 continue;
272 } else if (str[i] == '"' || str[i] == '\\') {
273 buffer[j++] = '\\';
274 }
275 buffer[j++] = str[i];
276 }
277 return j;
278 }
279
put_num(char * buffer,char prefix,int num,char suffix)280 int put_num(char *buffer, char prefix, int num, char suffix) {
281 int i = 0;
282 char *buf = buffer;
283 int is_neg = 0;
284 if (prefix) {
285 buf[i++] = prefix;
286 }
287 if (num == 0) {
288 buf[i++] = '0';
289 } else {
290 if (num < 0) {
291 num = -num;
292 is_neg = 1;
293 }
294 int s = i;
295 while (num != 0) {
296 buf[i++] = '0' + (num % 10);
297 num = num / 10;
298 }
299 if (is_neg) {
300 buf[i++] = '-';
301 }
302 int e = i - 1;
303 while (s < e) {
304 int t = buf[s];
305 buf[s] = buf[e];
306 buf[e] = t;
307 s++;
308 e--;
309 }
310 }
311 if (suffix) {
312 buf[i++] = suffix;
313 }
314 return i;
315 }
316
put_map(char * buffer,const map_entry * map)317 int put_map(char *buffer, const map_entry *map) {
318 char *buf = buffer;
319 const map_entry *entry = map;
320 while (entry->name != NULL) {
321 *(buf++) = '"';
322 buf += put_str(buf, entry->name);
323 *(buf++) = '"';
324 buf += put_num(buf, ':', entry->value, 0);
325 entry++;
326 if (entry->name != NULL) {
327 *(buf++) = ',';
328 }
329 }
330 return buf - buffer;
331 }
332
put_reference_frame(char * buffer)333 int put_reference_frame(char *buffer) {
334 const int mi_rows = frame_data.mi_rows;
335 const int mi_cols = frame_data.mi_cols;
336 char *buf = buffer;
337 int r, c, t;
338 buf += put_str(buf, " \"referenceFrameMap\": {");
339 buf += put_map(buf, refs_map);
340 buf += put_str(buf, "},\n");
341 buf += put_str(buf, " \"referenceFrame\": [");
342 for (r = 0; r < mi_rows; ++r) {
343 *(buf++) = '[';
344 for (c = 0; c < mi_cols; ++c) {
345 insp_mi_data *mi = &frame_data.mi_grid[r * mi_cols + c];
346 buf += put_num(buf, '[', mi->ref_frame[0], 0);
347 buf += put_num(buf, ',', mi->ref_frame[1], ']');
348 if (compress) { // RLE
349 for (t = c + 1; t < mi_cols; ++t) {
350 insp_mi_data *next_mi = &frame_data.mi_grid[r * mi_cols + t];
351 if (mi->ref_frame[0] != next_mi->ref_frame[0] ||
352 mi->ref_frame[1] != next_mi->ref_frame[1]) {
353 break;
354 }
355 }
356 if (t - c > 1) {
357 *(buf++) = ',';
358 buf += put_num(buf, '[', t - c - 1, ']');
359 c = t - 1;
360 }
361 }
362 if (c < mi_cols - 1) *(buf++) = ',';
363 }
364 *(buf++) = ']';
365 if (r < mi_rows - 1) *(buf++) = ',';
366 }
367 buf += put_str(buf, "],\n");
368 return buf - buffer;
369 }
370
put_motion_vectors(char * buffer)371 int put_motion_vectors(char *buffer) {
372 const int mi_rows = frame_data.mi_rows;
373 const int mi_cols = frame_data.mi_cols;
374 char *buf = buffer;
375 int r, c, t;
376 buf += put_str(buf, " \"motionVectors\": [");
377 for (r = 0; r < mi_rows; ++r) {
378 *(buf++) = '[';
379 for (c = 0; c < mi_cols; ++c) {
380 insp_mi_data *mi = &frame_data.mi_grid[r * mi_cols + c];
381 buf += put_num(buf, '[', mi->mv[0].col, 0);
382 buf += put_num(buf, ',', mi->mv[0].row, 0);
383 buf += put_num(buf, ',', mi->mv[1].col, 0);
384 buf += put_num(buf, ',', mi->mv[1].row, ']');
385 if (compress) { // RLE
386 for (t = c + 1; t < mi_cols; ++t) {
387 insp_mi_data *next_mi = &frame_data.mi_grid[r * mi_cols + t];
388 if (mi->mv[0].col != next_mi->mv[0].col ||
389 mi->mv[0].row != next_mi->mv[0].row ||
390 mi->mv[1].col != next_mi->mv[1].col ||
391 mi->mv[1].row != next_mi->mv[1].row) {
392 break;
393 }
394 }
395 if (t - c > 1) {
396 *(buf++) = ',';
397 buf += put_num(buf, '[', t - c - 1, ']');
398 c = t - 1;
399 }
400 }
401 if (c < mi_cols - 1) *(buf++) = ',';
402 }
403 *(buf++) = ']';
404 if (r < mi_rows - 1) *(buf++) = ',';
405 }
406 buf += put_str(buf, "],\n");
407 return buf - buffer;
408 }
409
put_block_info(char * buffer,const map_entry * map,const char * name,size_t offset)410 int put_block_info(char *buffer, const map_entry *map, const char *name,
411 size_t offset) {
412 const int mi_rows = frame_data.mi_rows;
413 const int mi_cols = frame_data.mi_cols;
414 char *buf = buffer;
415 int r, c, t, v;
416 if (map) {
417 buf += snprintf(buf, MAX_BUFFER, " \"%sMap\": {", name);
418 buf += put_map(buf, map);
419 buf += put_str(buf, "},\n");
420 }
421 buf += snprintf(buf, MAX_BUFFER, " \"%s\": [", name);
422 for (r = 0; r < mi_rows; ++r) {
423 *(buf++) = '[';
424 for (c = 0; c < mi_cols; ++c) {
425 insp_mi_data *curr_mi = &frame_data.mi_grid[r * mi_cols + c];
426 v = *(((int8_t *)curr_mi) + offset);
427 buf += put_num(buf, 0, v, 0);
428 if (compress) { // RLE
429 for (t = c + 1; t < mi_cols; ++t) {
430 insp_mi_data *next_mi = &frame_data.mi_grid[r * mi_cols + t];
431 if (v != *(((int8_t *)next_mi) + offset)) {
432 break;
433 }
434 }
435 if (t - c > 1) {
436 *(buf++) = ',';
437 buf += put_num(buf, '[', t - c - 1, ']');
438 c = t - 1;
439 }
440 }
441 if (c < mi_cols - 1) *(buf++) = ',';
442 }
443 *(buf++) = ']';
444 if (r < mi_rows - 1) *(buf++) = ',';
445 }
446 buf += put_str(buf, "],\n");
447 return buf - buffer;
448 }
449
450 #if CONFIG_ACCOUNTING
put_accounting(char * buffer)451 int put_accounting(char *buffer) {
452 char *buf = buffer;
453 int i;
454 const Accounting *accounting = frame_data.accounting;
455 if (accounting == NULL) {
456 printf("XXX\n");
457 return 0;
458 }
459 const int num_syms = accounting->syms.num_syms;
460 const int num_strs = accounting->syms.dictionary.num_strs;
461 buf += put_str(buf, " \"symbolsMap\": [");
462 for (i = 0; i < num_strs; i++) {
463 buf += snprintf(buf, MAX_BUFFER, "\"%s\"",
464 accounting->syms.dictionary.strs[i]);
465 if (i < num_strs - 1) *(buf++) = ',';
466 }
467 buf += put_str(buf, "],\n");
468 buf += put_str(buf, " \"symbols\": [\n ");
469 AccountingSymbolContext context;
470 context.x = -2;
471 context.y = -2;
472 AccountingSymbol *sym;
473 for (i = 0; i < num_syms; i++) {
474 sym = &accounting->syms.syms[i];
475 if (memcmp(&context, &sym->context, sizeof(AccountingSymbolContext)) != 0) {
476 buf += put_num(buf, '[', sym->context.x, 0);
477 buf += put_num(buf, ',', sym->context.y, ']');
478 } else {
479 buf += put_num(buf, '[', sym->id, 0);
480 buf += put_num(buf, ',', sym->bits, 0);
481 buf += put_num(buf, ',', sym->samples, ']');
482 }
483 context = sym->context;
484 if (i < num_syms - 1) *(buf++) = ',';
485 }
486 buf += put_str(buf, "],\n");
487 return buf - buffer;
488 }
489 #endif
490
inspect(void * pbi,void * data)491 void inspect(void *pbi, void *data) {
492 /* Fetch frame data. */
493 ifd_inspect(&frame_data, pbi);
494 (void)data;
495 // We allocate enough space and hope we don't write out of bounds. Totally
496 // unsafe but this speeds things up, especially when compiled to Javascript.
497 char *buffer = aom_malloc(MAX_BUFFER);
498 char *buf = buffer;
499 buf += put_str(buf, "{\n");
500 if (layers & BLOCK_SIZE_LAYER) {
501 buf += put_block_info(buf, block_size_map, "blockSize",
502 offsetof(insp_mi_data, sb_type));
503 }
504 if (layers & TRANSFORM_SIZE_LAYER) {
505 buf += put_block_info(buf, tx_size_map, "transformSize",
506 offsetof(insp_mi_data, tx_size));
507 }
508 if (layers & TRANSFORM_TYPE_LAYER) {
509 buf += put_block_info(buf, tx_type_map, "transformType",
510 offsetof(insp_mi_data, tx_type));
511 }
512 if (layers & MODE_LAYER) {
513 buf += put_block_info(buf, prediction_mode_map, "mode",
514 offsetof(insp_mi_data, mode));
515 }
516 if (layers & UV_MODE_LAYER) {
517 buf += put_block_info(buf, uv_prediction_mode_map, "uv_mode",
518 offsetof(insp_mi_data, uv_mode));
519 }
520 if (layers & SKIP_LAYER) {
521 buf += put_block_info(buf, skip_map, "skip", offsetof(insp_mi_data, skip));
522 }
523 if (layers & FILTER_LAYER) {
524 buf += put_block_info(buf, NULL, "filter", offsetof(insp_mi_data, filter));
525 }
526 #if CONFIG_CDEF
527 if (layers & CDEF_LAYER) {
528 buf += put_block_info(buf, NULL, "cdef_level",
529 offsetof(insp_mi_data, cdef_level));
530 buf += put_block_info(buf, NULL, "cdef_strength",
531 offsetof(insp_mi_data, cdef_strength));
532 }
533 #endif
534 #if CONFIG_CFL
535 if (layers & CFL_LAYER) {
536 buf += put_block_info(buf, NULL, "cfl_alpha_idx",
537 offsetof(insp_mi_data, cfl_alpha_idx));
538 buf += put_block_info(buf, NULL, "cfl_alpha_sign",
539 offsetof(insp_mi_data, cfl_alpha_sign));
540 }
541 #endif
542 if (layers & MOTION_VECTORS_LAYER) {
543 buf += put_motion_vectors(buf);
544 }
545 if (layers & REFERENCE_FRAME_LAYER) {
546 buf += put_reference_frame(buf);
547 }
548 #if CONFIG_ACCOUNTING
549 if (layers & ACCOUNTING_LAYER) {
550 buf += put_accounting(buf);
551 }
552 #endif
553 buf += snprintf(buf, MAX_BUFFER, " \"frame\": %d,\n", decoded_frame_count);
554 buf += snprintf(buf, MAX_BUFFER, " \"showFrame\": %d,\n",
555 frame_data.show_frame);
556 buf += snprintf(buf, MAX_BUFFER, " \"frameType\": %d,\n",
557 frame_data.frame_type);
558 buf += snprintf(buf, MAX_BUFFER, " \"baseQIndex\": %d,\n",
559 frame_data.base_qindex);
560 buf += snprintf(buf, MAX_BUFFER, " \"tileCols\": %d,\n",
561 frame_data.tile_mi_cols);
562 buf += snprintf(buf, MAX_BUFFER, " \"tileRows\": %d,\n",
563 frame_data.tile_mi_rows);
564 buf += put_str(buf, " \"config\": {");
565 buf += put_map(buf, config_map);
566 buf += put_str(buf, "},\n");
567 buf += put_str(buf, " \"configString\": \"");
568 buf += put_str_with_escape(buf, aom_codec_build_config());
569 buf += put_str(buf, "\"\n");
570 decoded_frame_count++;
571 buf += put_str(buf, "},\n");
572 *(buf++) = 0;
573 on_frame_decoded_dump(buffer);
574 aom_free(buffer);
575 }
576
ifd_init_cb()577 void ifd_init_cb() {
578 aom_inspect_init ii;
579 ii.inspect_cb = inspect;
580 ii.inspect_ctx = NULL;
581 aom_codec_control(&codec, AV1_SET_INSPECTION_CALLBACK, &ii);
582 }
583
584 EMSCRIPTEN_KEEPALIVE
open_file(char * file)585 int open_file(char *file) {
586 if (file == NULL) {
587 // The JS analyzer puts the .ivf file at this location.
588 file = "/tmp/input.ivf";
589 }
590 reader = aom_video_reader_open(file);
591 if (!reader) die("Failed to open %s for reading.", file);
592 info = aom_video_reader_get_info(reader);
593 const AvxInterface *decoder = get_aom_decoder_by_fourcc(info->codec_fourcc);
594 if (!decoder) die("Unknown input codec.");
595 fprintf(stderr, "Using %s\n",
596 aom_codec_iface_name(decoder->codec_interface()));
597 if (aom_codec_dec_init(&codec, decoder->codec_interface(), NULL, 0))
598 die_codec(&codec, "Failed to initialize decoder.");
599 ifd_init(&frame_data, info->frame_width, info->frame_height);
600 ifd_init_cb();
601 return EXIT_SUCCESS;
602 }
603
604 EMSCRIPTEN_KEEPALIVE
read_frame()605 int read_frame() {
606 if (!aom_video_reader_read_frame(reader)) return EXIT_FAILURE;
607 img = NULL;
608 aom_codec_iter_t iter = NULL;
609 size_t frame_size = 0;
610 const unsigned char *frame = aom_video_reader_get_frame(reader, &frame_size);
611 if (aom_codec_decode(&codec, frame, (unsigned int)frame_size, NULL, 0) !=
612 AOM_CODEC_OK) {
613 die_codec(&codec, "Failed to decode frame.");
614 }
615 img = aom_codec_get_frame(&codec, &iter);
616 if (img == NULL) {
617 return EXIT_FAILURE;
618 }
619 ++frame_count;
620 return EXIT_SUCCESS;
621 }
622
623 EMSCRIPTEN_KEEPALIVE
get_aom_codec_build_config()624 const char *get_aom_codec_build_config() { return aom_codec_build_config(); }
625
626 EMSCRIPTEN_KEEPALIVE
get_bit_depth()627 int get_bit_depth() { return img->bit_depth; }
628
629 EMSCRIPTEN_KEEPALIVE
get_bits_per_sample()630 int get_bits_per_sample() { return img->bps; }
631
632 EMSCRIPTEN_KEEPALIVE
get_image_format()633 int get_image_format() { return img->fmt; }
634
635 EMSCRIPTEN_KEEPALIVE
get_plane(int plane)636 unsigned char *get_plane(int plane) { return img->planes[plane]; }
637
638 EMSCRIPTEN_KEEPALIVE
get_plane_stride(int plane)639 int get_plane_stride(int plane) { return img->stride[plane]; }
640
641 EMSCRIPTEN_KEEPALIVE
get_plane_width(int plane)642 int get_plane_width(int plane) { return aom_img_plane_width(img, plane); }
643
644 EMSCRIPTEN_KEEPALIVE
get_plane_height(int plane)645 int get_plane_height(int plane) { return aom_img_plane_height(img, plane); }
646
647 EMSCRIPTEN_KEEPALIVE
get_frame_width()648 int get_frame_width() { return info->frame_width; }
649
650 EMSCRIPTEN_KEEPALIVE
get_frame_height()651 int get_frame_height() { return info->frame_height; }
652
parse_args(char ** argv)653 static void parse_args(char **argv) {
654 char **argi, **argj;
655 struct arg arg;
656 (void)dump_accounting_arg;
657 (void)dump_cdef_arg;
658 for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step) {
659 arg.argv_step = 1;
660 if (arg_match(&arg, &dump_block_size_arg, argi)) layers |= BLOCK_SIZE_LAYER;
661 #if CONFIG_ACCOUNTING
662 else if (arg_match(&arg, &dump_accounting_arg, argi))
663 layers |= ACCOUNTING_LAYER;
664 #endif
665 else if (arg_match(&arg, &dump_transform_size_arg, argi))
666 layers |= TRANSFORM_SIZE_LAYER;
667 else if (arg_match(&arg, &dump_transform_type_arg, argi))
668 layers |= TRANSFORM_TYPE_LAYER;
669 else if (arg_match(&arg, &dump_mode_arg, argi))
670 layers |= MODE_LAYER;
671 else if (arg_match(&arg, &dump_uv_mode_arg, argi))
672 layers |= UV_MODE_LAYER;
673 else if (arg_match(&arg, &dump_skip_arg, argi))
674 layers |= SKIP_LAYER;
675 else if (arg_match(&arg, &dump_filter_arg, argi))
676 layers |= FILTER_LAYER;
677 #if CONFIG_CDEF
678 else if (arg_match(&arg, &dump_cdef_arg, argi))
679 layers |= CDEF_LAYER;
680 #endif
681 #if CONFIG_CFL
682 else if (arg_match(&arg, &dump_cfl_arg, argi))
683 layers |= CFL_LAYER;
684 #endif
685 else if (arg_match(&arg, &dump_reference_frame_arg, argi))
686 layers |= REFERENCE_FRAME_LAYER;
687 else if (arg_match(&arg, &dump_motion_vectors_arg, argi))
688 layers |= MOTION_VECTORS_LAYER;
689 else if (arg_match(&arg, &dump_all_arg, argi))
690 layers |= ALL_LAYERS;
691 else if (arg_match(&arg, &compress_arg, argi))
692 compress = 1;
693 else if (arg_match(&arg, &usage_arg, argi))
694 usage_exit();
695 else if (arg_match(&arg, &limit_arg, argi))
696 stop_after = arg_parse_uint(&arg);
697 else
698 argj++;
699 }
700 }
701
702 static const char *exec_name;
703
usage_exit(void)704 void usage_exit(void) {
705 fprintf(stderr, "Usage: %s src_filename <options>\n", exec_name);
706 fprintf(stderr, "\nOptions:\n");
707 arg_show_usage(stderr, main_args);
708 exit(EXIT_FAILURE);
709 }
710
711 EMSCRIPTEN_KEEPALIVE
main(int argc,char ** argv)712 int main(int argc, char **argv) {
713 exec_name = argv[0];
714 parse_args(argv);
715 if (argc >= 2) {
716 open_file(argv[1]);
717 printf("[\n");
718 while (1) {
719 if (stop_after && (decoded_frame_count >= stop_after)) break;
720 if (read_frame()) break;
721 }
722 printf("null\n");
723 printf("]");
724 } else {
725 usage_exit();
726 }
727 }
728
729 EMSCRIPTEN_KEEPALIVE
quit()730 void quit() {
731 if (aom_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec");
732 aom_video_reader_close(reader);
733 }
734
735 EMSCRIPTEN_KEEPALIVE
set_layers(LayerType v)736 void set_layers(LayerType v) { layers = v; }
737
738 EMSCRIPTEN_KEEPALIVE
set_compress(int v)739 void set_compress(int v) { compress = v; }
740