Allocate missing buffers in error_resilient_mode

(When a frame is marked as error_resilient, the OrderHints of all of its
reference frames are explicitly signalled in the bit stream.)

On the decoder side:

- If a reference frame points to an invalid frame buffer, we allocate a
  new frame buffer with default pixel values and assign it to this
  reference frame instead. The OrderHint (aka cur_frame_offset) of this
  new buffer is set to the value read from the bit stream.

- Otherwise, we assert that the value read from the bit stream matches
  the OrderHint (aka cur_frame_offset) of the buffer.

This is the latter of two patches affecting error_resilient_mode. It is
a non-normative change that improves the ability of the decoder to cope
with invalid bitstreams.

Change-Id: Ic465feb90c6aeb07b732d0bf28ad14ddc5c304f7
diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c
index fef3b1d..ea6f6f0 100644
--- a/av1/decoder/decodeframe.c
+++ b/av1/decoder/decodeframe.c
@@ -62,6 +62,30 @@
 #define MAX_AV1_HEADER_SIZE 80
 #define ACCT_STR __func__
 
+// Use only_chroma = 1 to only set the chroma planes
+static void set_planes_to_neutral_grey(AV1_COMMON *const cm,
+                                       MACROBLOCKD *const xd, int only_chroma) {
+  YV12_BUFFER_CONFIG *cur_buf = (YV12_BUFFER_CONFIG *)xd->cur_buf;
+  const int val = 1 << (cm->bit_depth - 1);
+
+  for (int plane = only_chroma; plane < MAX_MB_PLANE; plane++) {
+    const int is_uv = plane > 0;
+    for (int row_idx = 0; row_idx < cur_buf->crop_heights[is_uv]; row_idx++) {
+      if (cm->use_highbitdepth) {
+        // TODO(yaowu): replace this with aom_memset16() for speed
+        for (int col_idx = 0; col_idx < cur_buf->crop_widths[is_uv];
+             col_idx++) {
+          uint16_t *base = CONVERT_TO_SHORTPTR(cur_buf->buffers[plane]);
+          base[row_idx * cur_buf->strides[is_uv] + col_idx] = val;
+        }
+      } else {
+        memset(&cur_buf->buffers[plane][row_idx * cur_buf->uv_stride], 1 << 7,
+               cur_buf->crop_widths[is_uv]);
+      }
+    }
+  }
+}
+
 static void loop_restoration_read_sb_coeffs(const AV1_COMMON *const cm,
                                             MACROBLOCKD *xd,
                                             aom_reader *const r, int plane,
@@ -2841,14 +2865,30 @@
     // Read all ref frame order hints if error_resilient_mode == 1
     if (cm->error_resilient_mode && cm->seq_params.enable_order_hint) {
       for (int ref_idx = 0; ref_idx < REF_FRAMES; ref_idx++) {
-        // Get buffer index
-        const int buf_idx = cm->ref_frame_map[ref_idx];
-        assert(buf_idx >= 0 && buf_idx < FRAME_BUFFERS);
-
         // Read order hint from bit stream
         unsigned int frame_offset =
             aom_rb_read_literal(rb, cm->seq_params.order_hint_bits_minus1 + 1);
-        if (frame_offset != frame_bufs[buf_idx].cur_frame_offset) assert(0);
+
+        // Get buffer index
+        int buf_idx = cm->ref_frame_map[ref_idx];
+        assert(buf_idx < FRAME_BUFFERS);
+
+        if (buf_idx == -1) {
+          // If no corresponding buffer exists, allocate a new buffer with all
+          // pixels set to neutral grey.
+          buf_idx = get_free_fb(cm);
+          aom_alloc_frame_buffer(
+              &frame_bufs[buf_idx].buf, cm->seq_params.max_frame_width,
+              cm->seq_params.max_frame_height, cm->subsampling_x,
+              cm->subsampling_y, cm->use_highbitdepth, AOM_BORDER_IN_PIXELS,
+              cm->byte_alignment);
+          set_planes_to_neutral_grey(cm, xd, 0);
+
+          cm->ref_frame_map[ref_idx] = buf_idx;
+          frame_bufs[buf_idx].cur_frame_offset = frame_offset;
+        } else {
+          assert(frame_offset == frame_bufs[buf_idx].cur_frame_offset);
+        }
       }
     }
 #endif  // CONFIG_EXPLICIT_ORDER_HINT
@@ -3477,25 +3517,7 @@
 
   const int num_planes = av1_num_planes(cm);
   // If the bit stream is monochrome, set the U and V buffers to a constant.
-  if (num_planes < 3) {
-    YV12_BUFFER_CONFIG *cur_buf = (YV12_BUFFER_CONFIG *)xd->cur_buf;
-    const int val = 1 << (cm->bit_depth - 1);
-
-    for (int buf_idx = 1; buf_idx <= 2; buf_idx++) {
-      for (int row_idx = 0; row_idx < cur_buf->crop_heights[1]; row_idx++) {
-        if (cm->use_highbitdepth) {
-          // TODO(yaowu): replace this with aom_memset16() for speed
-          for (int col_idx = 0; col_idx < cur_buf->crop_widths[1]; col_idx++) {
-            uint16_t *base = CONVERT_TO_SHORTPTR(cur_buf->buffers[buf_idx]);
-            base[row_idx * cur_buf->uv_stride + col_idx] = val;
-          }
-        } else {
-          memset(&cur_buf->buffers[buf_idx][row_idx * cur_buf->uv_stride],
-                 1 << 7, cur_buf->crop_widths[1]);
-        }
-      }
-    }
-  }
+  if (num_planes < 3) set_planes_to_neutral_grey(cm, xd, 1);
 
   if (endTile != cm->tile_rows * cm->tile_cols - 1) {
     return;