WIP:  CONFIG_INSPECTION: fix non show frames

This makes non showable frames - analyzeable and also fixes
display of motion vectors.

Change-Id: Ie286a3d2005a0c5e35d164ed62dd0fe2269b9be6
diff --git a/examples/inspect.c b/examples/inspect.c
index 8c132a6..3ccb6e6 100644
--- a/examples/inspect.c
+++ b/examples/inspect.c
@@ -548,22 +548,51 @@
   return EXIT_SUCCESS;
 }
 
+VpxDecodeReturn adr;
+int have_frame = 0;
+const unsigned char *frame;
+const unsigned char *end_frame;
+size_t frame_size = 0;
+vpx_codec_iter_t iter = NULL;
 EMSCRIPTEN_KEEPALIVE
 int read_frame() {
-  if (!vpx_video_reader_read_frame(reader)) return EXIT_FAILURE;
+  int got_any_frames = 0;
+  struct vpx_ref_frame ref_dec;
   img = NULL;
-  vpx_codec_iter_t iter = NULL;
-  size_t frame_size = 0;
-  const unsigned char *frame = vpx_video_reader_get_frame(reader, &frame_size);
-  if (vpx_codec_decode(&codec, frame, (unsigned int)frame_size, NULL, 0) !=
-      VPX_CODEC_OK) {
-    die_codec(&codec, "Failed to decode frame.");
+
+  // This loop skips over any frames that are show_existing_frames,  as
+  // there is nothing to analyze.
+  do {
+    if (!have_frame) {
+      if (!vpx_video_reader_read_frame(reader)) return EXIT_FAILURE;
+      frame = vpx_video_reader_get_frame(reader, &frame_size);
+
+      have_frame = 1;
+      end_frame = frame + frame_size;
+    }
+
+    if (vpx_codec_decode(&codec, frame, (unsigned int)frame_size, &adr, 0) !=
+        VPX_CODEC_OK) {
+      die_codec(&codec, "Failed to decode frame.");
+    }
+
+    frame = adr.buf;
+    if (adr.finished_superframes) have_frame = 0;
+  } while (adr.show_existing);
+
+  // ref_dec.idx is the index to the reference buffer idx to VP9_GET_REFERENCE
+  // if its -1 the decoder didn't update any reference buffer and the only
+  // way to see the frame is aom_codec_get_frame.
+  ref_dec.frame_type = adr.idx;
+
+  if (!vpx_codec_control(&codec, VP9_GET_REFERENCE, &ref_dec)) {
+    img = &ref_dec.img;
+    ++frame_count;
+    got_any_frames = 1;
   }
-  img = vpx_codec_get_frame(&codec, &iter);
-  if (img == NULL) {
+  if (!got_any_frames) {
     return EXIT_FAILURE;
   }
-  ++frame_count;
   return EXIT_SUCCESS;
 }
 
diff --git a/tools/build_inspector.sh b/tools/build_inspector.sh
index 3cceb60..4619b34 100755
--- a/tools/build_inspector.sh
+++ b/tools/build_inspector.sh
@@ -32,7 +32,7 @@
     --disable-docs \
     --disable-unit-tests \
     --enable-inspection \
-    --extra-cflags="-D_POSIX_SOURCE"
+    --extra-cflags="-D_POSIX_SOURCE -s ALLOW_MEMORY_GROWTH=1"
   cd ..
 fi
 
@@ -43,6 +43,7 @@
   -s TOTAL_MEMORY=134217728 \
   -s MODULARIZE=1 \
   -s EXPORT_NAME="'DecoderModule'" \
+  -s ALLOW_MEMORY_GROWTH=1 \
   --post-js "../inspect-post.js" \
   --memory-init-file 0
 cp inspect.js ../inspect.js
diff --git a/vp9/decoder/inspection.c b/vp9/decoder/inspection.c
index b6b38a5..2be2569 100644
--- a/vp9/decoder/inspection.c
+++ b/vp9/decoder/inspection.c
@@ -43,6 +43,8 @@
   fd->frame_type = cm->frame_type;
   fd->base_qindex = cm->base_qindex;
   // TODO(jimbankoski): copy tile data
+  fd->show_existing_frame = cm->show_existing_frame;
+
   // fd->tile_mi_cols = cm->tile_width;
   // fd->tile_mi_rows = cm->tile_height;
 #if CONFIG_ACCOUNTING
@@ -64,8 +66,14 @@
       // Motion Vectors
       mi->mv[0].row = bmi->mv[0].as_mv.row;
       mi->mv[0].col = bmi->mv[0].as_mv.col;
-      mi->mv[1].row = bmi->mv[1].as_mv.row;
-      mi->mv[1].col = bmi->mv[1].as_mv.col;
+
+      if (bmi->ref_frame[1] == -1) {
+        mi->mv[1].row = 0;
+        mi->mv[1].col = 0;
+      } else {
+        mi->mv[1].row = bmi->mv[1].as_mv.row;
+        mi->mv[1].col = bmi->mv[1].as_mv.col;
+      }
       // Reference Frames
       mi->ref_frame[0] = bmi->ref_frame[0];
       mi->ref_frame[1] = bmi->ref_frame[1];
diff --git a/vp9/decoder/inspection.h b/vp9/decoder/inspection.h
index a3c9807..304e2ee 100644
--- a/vp9/decoder/inspection.h
+++ b/vp9/decoder/inspection.h
@@ -58,6 +58,7 @@
   int show_frame;
   int frame_type;
   int base_qindex;
+  int show_existing_frame;
   int mi_rows;
   int mi_cols;
   int tile_mi_rows;
diff --git a/vp9/vp9_dx_iface.c b/vp9/vp9_dx_iface.c
index 2bf0d78..1f13d87 100644
--- a/vp9/vp9_dx_iface.c
+++ b/vp9/vp9_dx_iface.c
@@ -279,7 +279,10 @@
     set_default_ppflags(&ctx->postproc_cfg);
 
   init_buffer_callbacks(ctx);
-
+#if CONFIG_INSPECTION
+  ctx->frame_count = 0;
+  ctx->which_frame = 0;
+#endif
   return VPX_CODEC_OK;
 }
 
@@ -333,6 +336,68 @@
   return VPX_CODEC_OK;
 }
 
+#if CONFIG_INSPECTION
+// This function enables the inspector to inspect non visible frames.
+static vpx_codec_err_t decoder_inspect(vpx_codec_alg_priv_t *ctx,
+                                       const uint8_t *data, size_t data_sz,
+                                       void *user_priv, int64_t deadline) {
+  vpx_codec_err_t res = VPX_CODEC_OK;
+
+  if (ctx->pbi == NULL) {
+    const vpx_codec_err_t res = init_decoder(ctx);
+    if (res != VPX_CODEC_OK) return res;
+  }
+
+  if (ctx->which_frame >= ctx->frame_count) {
+    int i;
+    const uint8_t *data_start = data;
+    const uint8_t *const data_end = data + data_sz;
+    res = vp9_parse_superframe_index(data, data_sz, ctx->frame_sizes,
+                                     &ctx->frame_count, ctx->decrypt_cb,
+                                     ctx->decrypt_state);
+
+    if (res != VPX_CODEC_OK) return res;
+    if (ctx->svc_decoding && ctx->svc_spatial_layer < ctx->frame_count - 1)
+      ctx->frame_count = ctx->svc_spatial_layer + 1;
+
+    ctx->which_frame = 0;
+
+    // Double check that we don't have problems with the index;
+    for (i = 0; i < ctx->frame_count; ++i) {
+      const uint32_t frame_size = ctx->frame_sizes[i];
+      if (data_start < data || frame_size > (uint32_t)(data_end - data_start)) {
+        set_error_detail(ctx, "Invalid frame size in index");
+        return VPX_CODEC_CORRUPT_FRAME;
+      }
+      data_start += frame_size;
+    }
+  }
+  if (ctx->frame_count == 0) ctx->frame_sizes[0] = data_sz;
+
+  // Decode in serial mode.
+  if (ctx->frame_count >= 0) {
+    int i;
+    vpx_codec_err_t res;
+    VP9_COMMON *const cm = &ctx->pbi->common;
+    VpxDecodeReturn *data2 = (VpxDecodeReturn *)user_priv;
+    const uint8_t *data_start = data;
+
+    res =
+        decode_one(ctx, &data, ctx->frame_sizes[ctx->which_frame], 0, deadline);
+    if (res != VPX_CODEC_OK) return res;
+
+    data2->idx = cm->new_fb_idx;
+
+    data2->buf = data_start + ctx->frame_sizes[ctx->which_frame];
+    data2->show_existing = cm->show_existing_frame;
+    ctx->which_frame++;
+    data2->finished_superframes = (ctx->which_frame >= ctx->frame_count);
+    return res;
+  }
+  return VPX_CODEC_OK;
+}
+#endif
+
 static vpx_codec_err_t decoder_decode(vpx_codec_alg_priv_t *ctx,
                                       const uint8_t *data, unsigned int data_sz,
                                       void *user_priv, long deadline) {
@@ -341,7 +406,11 @@
   vpx_codec_err_t res;
   uint32_t frame_sizes[8];
   int frame_count;
-
+#if CONFIG_INSPECTION
+  if (user_priv != 0) {
+    return decoder_inspect(ctx, data, data_sz, user_priv, deadline);
+  }
+#endif
   if (data == NULL && data_sz == 0) {
     ctx->flushed = 1;
     return VPX_CODEC_OK;
@@ -479,7 +548,11 @@
   vp9_ref_frame_t *data = va_arg(args, vp9_ref_frame_t *);
 
   if (data) {
+#if CONFIG_INSPECTION
+    const int fb_idx = data->idx;
+#else
     const int fb_idx = ctx->pbi->common.cur_show_frame_fb_idx;
+#endif
     YV12_BUFFER_CONFIG *fb = get_buf_frame(&ctx->pbi->common, fb_idx);
     if (fb == NULL) return VPX_CODEC_ERROR;
     yuvconfig2image(&data->img, fb, NULL);
diff --git a/vp9/vp9_dx_iface.h b/vp9/vp9_dx_iface.h
index 7229597..e20aed9 100644
--- a/vp9/vp9_dx_iface.h
+++ b/vp9/vp9_dx_iface.h
@@ -51,6 +51,9 @@
 #if CONFIG_INSPECTION
   vpx_inspect_cb inspect_cb;
   void *inspect_ctx;
+  uint32_t frame_sizes[8];
+  int frame_count;
+  int which_frame;
 #endif
 };
 
diff --git a/vpx/vp8dx.h b/vpx/vp8dx.h
index 5d0e533..e9d479f 100644
--- a/vpx/vp8dx.h
+++ b/vpx/vp8dx.h
@@ -64,6 +64,23 @@
   void *inspect_ctx;
 } vpx_inspect_init;
 
+/*!\brief Structure to hold decoder return.
+ *
+ * Defines a structure to hold the buffer and return an index
+ * when calling decode from inspect. This enables us to decode
+ * non showable sub frames.
+ */
+typedef struct {
+  /*! Pointer for new position in compressed buffer after decoding 1 OBU. */
+  const unsigned char *buf;
+  /*! Index into reference buffer array to see result of decoding 1 OBU. */
+  int idx;
+  /*! Is a show existing frame. */
+  int show_existing;
+  /*! Whether we've decoded all the superframes. */
+  int finished_superframes;
+} VpxDecodeReturn;
+
 /*!\enum vp8_dec_control_id
  * \brief VP8 decoder control functions
  *