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