Film grain synthesis algorithm

Change-Id: I7758fc79c1b6709c630f5641705dfd07fc4478e8
diff --git a/av1/av1.cmake b/av1/av1.cmake
index 74122c9..dca4f5f 100644
--- a/av1/av1.cmake
+++ b/av1/av1.cmake
@@ -126,6 +126,7 @@
     "${AOM_ROOT}/av1/encoder/extend.h"
     "${AOM_ROOT}/av1/encoder/firstpass.c"
     "${AOM_ROOT}/av1/encoder/firstpass.h"
+    "${AOM_ROOT}/av1/encoder/grain_test_vectors.h"
     "${AOM_ROOT}/av1/encoder/hash.c"
     "${AOM_ROOT}/av1/encoder/hash.h"
     "${AOM_ROOT}/av1/encoder/hybrid_fwd_txfm.c"
diff --git a/av1/av1_cx_iface.c b/av1/av1_cx_iface.c
index 2eb0344..43e5361 100644
--- a/av1/av1_cx_iface.c
+++ b/av1/av1_cx_iface.c
@@ -102,6 +102,9 @@
   unsigned int single_tile_decoding;
 #endif  // CONFIG_EXT_TILE
 
+#if CONFIG_FILM_GRAIN
+  int film_grain_test_vector;
+#endif
   unsigned int motion_vector_unit_test;
 };
 
@@ -178,6 +181,9 @@
   0,    // Single tile decoding is off by default.
 #endif  // CONFIG_EXT_TILE
 
+#if CONFIG_FILM_GRAIN
+  0,
+#endif
   0,  // motion_vector_unit_test
 };
 
@@ -434,6 +440,10 @@
   RANGE_CHECK(extra_cfg, timing_info, AOM_TIMING_UNSPECIFIED, AOM_TIMING_EQUAL);
 #endif
 
+#if CONFIG_FILM_GRAIN
+  RANGE_CHECK(extra_cfg, film_grain_test_vector, 0, 16);
+#endif
+
   if (extra_cfg->lossless) {
     if (extra_cfg->aq_mode != 0)
       ERROR("Only --aq_mode=0 can be used with --lossless=1.");
@@ -671,6 +681,9 @@
   oxcf->superblock_size = extra_cfg->superblock_size;
 #endif  // CONFIG_EXT_PARTITION
 
+#if CONFIG_FILM_GRAIN
+  oxcf->film_grain_test_vector = extra_cfg->film_grain_test_vector;
+#endif
 #if CONFIG_EXT_TILE
   oxcf->large_scale_tile = cfg->large_scale_tile;
   oxcf->single_tile_decoding =
@@ -1049,6 +1062,16 @@
   return update_extra_cfg(ctx, &extra_cfg);
 }
 
+#if CONFIG_FILM_GRAIN
+static aom_codec_err_t ctrl_set_film_grain_test_vector(
+    aom_codec_alg_priv_t *ctx, va_list args) {
+  struct av1_extracfg extra_cfg = ctx->extra_cfg;
+  extra_cfg.film_grain_test_vector =
+      CAST(AV1E_SET_FILM_GRAIN_TEST_VECTOR, args);
+  return update_extra_cfg(ctx, &extra_cfg);
+}
+#endif
+
 #if CONFIG_EXT_DELTA_Q
 static aom_codec_err_t ctrl_set_deltaq_mode(aom_codec_alg_priv_t *ctx,
                                             va_list args) {
@@ -1755,6 +1778,10 @@
 #if CONFIG_EXT_TILE
   { AV1E_SET_SINGLE_TILE_DECODING, ctrl_set_single_tile_decoding },
 #endif  // CONFIG_EXT_TILE
+#if CONFIG_FILM_GRAIN
+  { AV1E_SET_FILM_GRAIN_TEST_VECTOR, ctrl_set_film_grain_test_vector },
+#endif  // CONFIG_FILM_GRAIN
+
   { AV1E_ENABLE_MOTION_VECTOR_UNIT_TEST, ctrl_enable_motion_vector_unit_test },
 
   // Getters
diff --git a/av1/av1_dx_iface.c b/av1/av1_dx_iface.c
index 5dfc526..8b2d254 100644
--- a/av1/av1_dx_iface.c
+++ b/av1/av1_dx_iface.c
@@ -38,6 +38,9 @@
 typedef struct cache_frame {
   int fb_idx;
   aom_image_t img;
+#if CONFIG_FILM_GRAIN
+  aom_film_grain_t film_grain_params;
+#endif
 } cache_frame;
 
 struct aom_codec_alg_priv {
@@ -66,6 +69,9 @@
   int next_output_worker_id;
   int available_threads;
   cache_frame frame_cache[FRAME_CACHE_SIZE];
+#if CONFIG_FILM_GRAIN
+  aom_image_t *image_with_grain;
+#endif
   int frame_cache_write;
   int frame_cache_read;
   int num_cache_frames;
@@ -111,6 +117,9 @@
       priv->cfg = *ctx->config.dec;
       ctx->config.dec = &priv->cfg;
     }
+#if CONFIG_FILM_GRAIN
+    priv->image_with_grain = NULL;
+#endif
   }
 
   return AOM_CODEC_OK;
@@ -152,6 +161,9 @@
 
   aom_free(ctx->frame_workers);
   aom_free(ctx->buffer_pool);
+#if CONFIG_FILM_GRAIN
+  if (ctx->image_with_grain) aom_img_free(ctx->image_with_grain);
+#endif
   aom_free(ctx);
   return AOM_CODEC_OK;
 }
@@ -723,6 +735,10 @@
                     frame_worker_data->user_priv);
     ctx->frame_cache[ctx->frame_cache_write].img.fb_priv =
         frame_bufs[cm->new_fb_idx].raw_frame_buffer.priv;
+#if CONFIG_FILM_GRAIN
+    memcpy(&ctx->frame_cache[ctx->frame_cache_write].film_grain_params,
+           &cm->film_grain_params, sizeof(aom_film_grain_t));
+#endif
     ctx->frame_cache_write = (ctx->frame_cache_write + 1) % FRAME_CACHE_SIZE;
     ++ctx->num_cache_frames;
   }
@@ -856,6 +872,28 @@
   }
 }
 
+#if CONFIG_FILM_GRAIN
+aom_image_t *add_grain_if_needed(aom_image_t *img, aom_image_t *grain_img_buf,
+                                 aom_film_grain_t *grain_params) {
+  if (!grain_params->apply_grain) return img;
+
+  if (grain_img_buf &&
+      (img->d_w != grain_img_buf->d_w || img->d_h != grain_img_buf->d_h ||
+       img->fmt != grain_img_buf->fmt)) {
+    aom_img_free(grain_img_buf);
+    grain_img_buf = NULL;
+  }
+  if (!grain_img_buf) {
+    grain_img_buf = aom_img_alloc(NULL, img->fmt, img->d_w, img->d_h, 16);
+    grain_img_buf->bit_depth = img->bit_depth;
+  }
+
+  av1_add_film_grain(grain_params, img, grain_img_buf);
+
+  return grain_img_buf;
+}
+#endif
+
 static aom_image_t *decoder_get_frame(aom_codec_alg_priv_t *ctx,
                                       aom_codec_iter_t *iter) {
   aom_image_t *img = NULL;
@@ -875,7 +913,13 @@
     img = &ctx->frame_cache[ctx->frame_cache_read].img;
     ctx->frame_cache_read = (ctx->frame_cache_read + 1) % FRAME_CACHE_SIZE;
     --ctx->num_cache_frames;
+#if CONFIG_FILM_GRAIN
+    return add_grain_if_needed(
+        img, ctx->image_with_grain,
+        &ctx->frame_cache[ctx->frame_cache_read].film_grain_params);
+#else
     return img;
+#endif
   }
 
   // iter acts as a flip flop, so an image is only returned on the first
@@ -945,7 +989,13 @@
 
           ctx->img.fb_priv = frame_bufs[cm->new_fb_idx].raw_frame_buffer.priv;
           img = &ctx->img;
+#if CONFIG_FILM_GRAIN
+          return add_grain_if_needed(
+              img, ctx->image_with_grain,
+              &frame_worker_data->pbi->common.film_grain_params);
+#else
           return img;
+#endif
         }
       } else {
         // Decoding failed. Release the worker thread.
diff --git a/av1/common/onyxc_int.h b/av1/common/onyxc_int.h
index 10e0dcb..4179ec7 100644
--- a/av1/common/onyxc_int.h
+++ b/av1/common/onyxc_int.h
@@ -33,6 +33,9 @@
 // TODO(youzhou@microsoft.com): Encoder only. Move it out of common
 #include "av1/encoder/hash_motion.h"
 #endif
+#if CONFIG_FILM_GRAIN
+#include "aom_dsp/grain_synthesis.h"
+#endif
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -156,6 +159,9 @@
   int width;
   int height;
   WarpedMotionParams global_motion[TOTAL_REFS_PER_FRAME];
+#if CONFIG_FILM_GRAIN
+  aom_film_grain_t film_grain_params;
+#endif
   aom_codec_frame_buffer_t raw_frame_buffer;
   YV12_BUFFER_CONFIG buf;
 #if CONFIG_HASH_ME
@@ -547,6 +553,10 @@
   TXFM_CONTEXT left_txfm_context[MAX_MB_PLANE][2 * MAX_MIB_SIZE];
   int above_context_alloc_cols;
   WarpedMotionParams global_motion[TOTAL_REFS_PER_FRAME];
+#if CONFIG_FILM_GRAIN
+  int film_grain_params_present;
+  aom_film_grain_t film_grain_params;
+#endif
   BLOCK_SIZE sb_size;  // Size of the superblock used for this frame
   int mib_size;        // Size of the superblock in units of MI blocks
   int mib_size_log2;   // Log 2 of above.
diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c
index 9933049..e97d018 100644
--- a/av1/decoder/decodeframe.c
+++ b/av1/decoder/decodeframe.c
@@ -2175,6 +2175,98 @@
   return;
 }
 
+#if CONFIG_FILM_GRAIN
+void av1_read_film_grain_params(AV1_COMMON *cm,
+                                struct aom_read_bit_buffer *rb) {
+  aom_film_grain_t *pars = &cm->film_grain_params;
+
+  pars->apply_grain = aom_rb_read_bit(rb);
+  if (!pars->apply_grain) return;
+
+  pars->random_seed = aom_rb_read_literal(rb, 16);
+
+  pars->update_parameters = aom_rb_read_bit(rb);
+  if (!pars->update_parameters) return;
+
+  // Scaling functions parameters
+
+  pars->num_y_points = aom_rb_read_literal(rb, 4);  // max 14
+  for (int i = 0; i < pars->num_y_points; i++) {
+    pars->scaling_points_y[i][0] = aom_rb_read_literal(rb, 8);
+    pars->scaling_points_y[i][1] = aom_rb_read_literal(rb, 8);
+  }
+
+  pars->chroma_scaling_from_luma = aom_rb_read_bit(rb);
+
+  if (!pars->chroma_scaling_from_luma) {
+    pars->num_cb_points = aom_rb_read_literal(rb, 4);  // max 10
+    for (int i = 0; i < pars->num_cb_points; i++) {
+      pars->scaling_points_cb[i][0] = aom_rb_read_literal(rb, 8);
+      pars->scaling_points_cb[i][1] = aom_rb_read_literal(rb, 8);
+    }
+
+    pars->num_cr_points = aom_rb_read_literal(rb, 4);  // max 10
+    for (int i = 0; i < pars->num_cr_points; i++) {
+      pars->scaling_points_cr[i][0] = aom_rb_read_literal(rb, 8);
+      pars->scaling_points_cr[i][1] = aom_rb_read_literal(rb, 8);
+    }
+  }
+
+  pars->scaling_shift = aom_rb_read_literal(rb, 2) + 8;  // 8 + value
+
+  // AR coefficients
+  // Only sent if the corresponsing scaling function has
+  // more than 0 points
+
+  pars->ar_coeff_lag = aom_rb_read_literal(rb, 2);
+
+  int num_pos_luma = 2 * pars->ar_coeff_lag * (pars->ar_coeff_lag + 1);
+  int num_pos_chroma = num_pos_luma + 1;
+
+  if (pars->num_y_points)
+    for (int i = 0; i < num_pos_luma; i++)
+      pars->ar_coeffs_y[i] = aom_rb_read_literal(rb, 8) - 128;
+
+  if (pars->num_cb_points || pars->chroma_scaling_from_luma)
+    for (int i = 0; i < num_pos_chroma; i++)
+      pars->ar_coeffs_cb[i] = aom_rb_read_literal(rb, 8) - 128;
+
+  if (pars->num_cr_points || pars->chroma_scaling_from_luma)
+    for (int i = 0; i < num_pos_chroma; i++)
+      pars->ar_coeffs_cr[i] = aom_rb_read_literal(rb, 8) - 128;
+
+  pars->ar_coeff_shift = aom_rb_read_literal(rb, 2) + 6;  // 6 + value
+
+  if (pars->num_cb_points) {
+    pars->cb_mult = aom_rb_read_literal(rb, 8);
+    pars->cb_luma_mult = aom_rb_read_literal(rb, 8);
+    pars->cb_offset = aom_rb_read_literal(rb, 9);
+  }
+
+  if (pars->num_cr_points) {
+    pars->cr_mult = aom_rb_read_literal(rb, 8);
+    pars->cr_luma_mult = aom_rb_read_literal(rb, 8);
+    pars->cr_offset = aom_rb_read_literal(rb, 9);
+  }
+
+  pars->overlap_flag = aom_rb_read_bit(rb);
+
+  pars->clip_to_restricted_range = aom_rb_read_bit(rb);
+}
+
+static void av1_read_film_grain(AV1_COMMON *cm,
+                                struct aom_read_bit_buffer *rb) {
+  if (cm->film_grain_params_present) {
+    av1_read_film_grain_params(cm, rb);
+  } else {
+    memset(&cm->film_grain_params, 0, sizeof(cm->film_grain_params));
+  }
+  cm->film_grain_params.bit_depth = cm->bit_depth;
+  memcpy(&cm->cur_frame->film_grain_params, &cm->film_grain_params,
+         sizeof(aom_film_grain_t));
+}
+#endif
+
 void av1_read_bitdepth_colorspace_sampling(AV1_COMMON *cm,
                                            struct aom_read_bit_buffer *rb,
                                            int allow_lowbitdepth) {
@@ -2594,6 +2686,10 @@
 #endif
     cm->show_frame = 1;
 
+#if CONFIG_FILM_GRAIN
+    av1_read_film_grain(cm, rb);
+#endif
+
 #if CONFIG_FWD_KF
     cm->reset_decoder_state = aom_rb_read_bit(rb);
     if (cm->reset_decoder_state) {
@@ -2688,7 +2784,10 @@
 #if !CONFIG_OBU
     av1_read_bitdepth_colorspace_sampling(cm, rb, pbi->allow_lowbitdepth);
 #if CONFIG_TIMING_INFO_IN_SEQ_HEADERS
-    av1_read_time_info_header(cm, rb);
+    av1_read_timing_info_header(cm, rb);
+#endif
+#if CONFIG_FILM_GRAIN
+    cm->film_grain_params_present = aom_rb_read_bit(rb);
 #endif
 #endif
     pbi->refresh_frame_flags = (1 << REF_FRAMES) - 1;
@@ -2760,6 +2859,9 @@
 #if CONFIG_TIMING_INFO_IN_SEQ_HEADERS
       av1_read_timing_info_header(cm, rb);
 #endif
+#if CONFIG_FILM_GRAIN
+      cm->film_grain_params_present = aom_rb_read_bit(rb);
+#endif
 #endif
 
       pbi->refresh_frame_flags = aom_rb_read_literal(rb, REF_FRAMES);
@@ -3181,6 +3283,12 @@
 
   if (!frame_is_intra_only(cm)) read_global_motion(cm, rb);
 
+#if CONFIG_FILM_GRAIN
+  if (cm->show_frame) {
+    av1_read_film_grain(cm, rb);
+  }
+#endif
+
 #if !CONFIG_TILE_INFO_FIRST
   read_tile_info(pbi, rb);
 #endif
diff --git a/av1/decoder/obu.c b/av1/decoder/obu.c
index ef183b9..89e9eeb 100644
--- a/av1/decoder/obu.c
+++ b/av1/decoder/obu.c
@@ -60,6 +60,10 @@
   av1_read_timing_info_header(cm, rb);
 #endif
 
+#if CONFIG_FILM_GRAIN
+  cm->film_grain_params_present = aom_rb_read_bit(rb);
+#endif
+
   return ((rb->bit_offset - saved_bit_offset + 7) >> 3);
 }
 
diff --git a/av1/encoder/bitstream.c b/av1/encoder/bitstream.c
index 05df695..3f78182 100644
--- a/av1/encoder/bitstream.c
+++ b/av1/encoder/bitstream.c
@@ -3311,6 +3311,90 @@
 }
 #endif  // CONFIG_TIMING_INFO_IN_SEQ_HEADERS
 
+#if CONFIG_FILM_GRAIN
+static void write_film_grain_params(AV1_COMMON *const cm,
+                                    struct aom_write_bit_buffer *wb) {
+  aom_film_grain_t *pars = &cm->film_grain_params;
+
+  aom_wb_write_bit(wb, pars->apply_grain);
+  if (!pars->apply_grain) return;
+
+  aom_wb_write_literal(wb, pars->random_seed, 16);
+
+  pars->random_seed += 3245;  // For film grain test vectors purposes
+  if (!pars->random_seed)     // Random seed should not be zero
+    pars->random_seed += 1735;
+
+  aom_wb_write_bit(wb, pars->update_parameters);
+  if (!pars->update_parameters) return;
+
+  // Scaling functions parameters
+
+  aom_wb_write_literal(wb, pars->num_y_points, 4);  // max 14
+  for (int i = 0; i < pars->num_y_points; i++) {
+    aom_wb_write_literal(wb, pars->scaling_points_y[i][0], 8);
+    aom_wb_write_literal(wb, pars->scaling_points_y[i][1], 8);
+  }
+
+  aom_wb_write_bit(wb, pars->chroma_scaling_from_luma);
+
+  if (!pars->chroma_scaling_from_luma) {
+    aom_wb_write_literal(wb, pars->num_cb_points, 4);  // max 10
+    for (int i = 0; i < pars->num_cb_points; i++) {
+      aom_wb_write_literal(wb, pars->scaling_points_cb[i][0], 8);
+      aom_wb_write_literal(wb, pars->scaling_points_cb[i][1], 8);
+    }
+
+    aom_wb_write_literal(wb, pars->num_cr_points, 4);  // max 10
+    for (int i = 0; i < pars->num_cr_points; i++) {
+      aom_wb_write_literal(wb, pars->scaling_points_cr[i][0], 8);
+      aom_wb_write_literal(wb, pars->scaling_points_cr[i][1], 8);
+    }
+  }
+
+  aom_wb_write_literal(wb, pars->scaling_shift - 8, 2);  // 8 + value
+
+  // AR coefficients
+  // Only sent if the corresponsing scaling function has
+  // more than 0 points
+
+  aom_wb_write_literal(wb, pars->ar_coeff_lag, 2);
+
+  int num_pos_luma = 2 * pars->ar_coeff_lag * (pars->ar_coeff_lag + 1);
+  int num_pos_chroma = num_pos_luma + 1;
+
+  if (pars->num_y_points)
+    for (int i = 0; i < num_pos_luma; i++)
+      aom_wb_write_literal(wb, pars->ar_coeffs_y[i] + 128, 8);
+
+  if (pars->num_cb_points || pars->chroma_scaling_from_luma)
+    for (int i = 0; i < num_pos_chroma; i++)
+      aom_wb_write_literal(wb, pars->ar_coeffs_cb[i] + 128, 8);
+
+  if (pars->num_cr_points || pars->chroma_scaling_from_luma)
+    for (int i = 0; i < num_pos_chroma; i++)
+      aom_wb_write_literal(wb, pars->ar_coeffs_cr[i] + 128, 8);
+
+  aom_wb_write_literal(wb, pars->ar_coeff_shift - 6, 2);  // 8 + value
+
+  if (pars->num_cb_points) {
+    aom_wb_write_literal(wb, pars->cb_mult, 8);
+    aom_wb_write_literal(wb, pars->cb_luma_mult, 8);
+    aom_wb_write_literal(wb, pars->cb_offset, 9);
+  }
+
+  if (pars->num_cr_points) {
+    aom_wb_write_literal(wb, pars->cr_mult, 8);
+    aom_wb_write_literal(wb, pars->cr_luma_mult, 8);
+    aom_wb_write_literal(wb, pars->cr_offset, 9);
+  }
+
+  aom_wb_write_bit(wb, pars->overlap_flag);
+
+  aom_wb_write_bit(wb, pars->clip_to_restricted_range);
+}
+#endif  // CONFIG_FILM_GRAIN
+
 #if CONFIG_REFERENCE_BUFFER || CONFIG_OBU
 void write_sequence_header(AV1_COMP *cpi, struct aom_write_bit_buffer *wb) {
   AV1_COMMON *const cm = &cpi->common;
@@ -3515,6 +3599,10 @@
     }
 #endif  // CONFIG_REFERENCE_BUFFER
 
+#if CONFIG_FILM_GRAIN
+    if (cm->film_grain_params_present) write_film_grain_params(cm, wb);
+#endif
+
 #if CONFIG_FWD_KF
     if (cm->reset_decoder_state && !frame_bufs[frame_to_show].intra_only) {
       aom_internal_error(
@@ -3573,6 +3661,9 @@
     // timing_info
     write_timing_info_header(cm, wb);
 #endif
+#if CONFIG_FILM_GRAIN
+    aom_wb_write_bit(wb, cm->film_grain_params_present);
+#endif
 #if CONFIG_FRAME_SIZE
     write_frame_size(cm, frame_size_override_flag, wb);
 #else
@@ -3617,6 +3708,9 @@
       write_timing_info_header(cm, wb);
 #endif
 
+#if CONFIG_FILM_GRAIN
+      aom_wb_write_bit(wb, cm->film_grain_params_present);
+#endif
       aom_wb_write_literal(wb, cpi->refresh_frame_mask, REF_FRAMES);
 #if CONFIG_FRAME_SIZE
       write_frame_size(cm, frame_size_override_flag, wb);
@@ -3805,6 +3899,11 @@
 
   if (!frame_is_intra_only(cm)) write_global_motion(cpi, wb);
 
+#if CONFIG_FILM_GRAIN
+  if (cm->film_grain_params_present && cm->show_frame)
+    write_film_grain_params(cm, wb);
+#endif
+
 #if !CONFIG_TILE_INFO_FIRST
   write_tile_info(cm, wb);
 #endif
@@ -3849,6 +3948,21 @@
     }
 #endif  // CONFIG_REFERENCE_BUFFER
 
+#if CONFIG_FILM_GRAIN
+    if (cm->film_grain_params_present && cm->show_frame) {
+      int flip_back_update_parameters_flag = 0;
+      if (cm->frame_type == KEY_FRAME &&
+          cm->film_grain_params.update_parameters == 0) {
+        cm->film_grain_params.update_parameters = 1;
+        flip_back_update_parameters_flag = 1;
+      }
+      write_film_grain_params(cm, wb);
+
+      if (flip_back_update_parameters_flag)
+        cm->film_grain_params.update_parameters = 0;
+    }
+#endif
+
 #if CONFIG_FWD_KF
     if (cm->reset_decoder_state && !frame_bufs[frame_to_show].intra_only) {
       aom_internal_error(
@@ -4186,6 +4300,21 @@
 
   if (!frame_is_intra_only(cm)) write_global_motion(cpi, wb);
 
+#if CONFIG_FILM_GRAIN
+  if (cm->film_grain_params_present && cm->show_frame) {
+    int flip_back_update_parameters_flag = 0;
+    if (cm->frame_type == KEY_FRAME &&
+        cm->film_grain_params.update_parameters == 0) {
+      cm->film_grain_params.update_parameters = 1;
+      flip_back_update_parameters_flag = 1;
+    }
+    write_film_grain_params(cm, wb);
+
+    if (flip_back_update_parameters_flag)
+      cm->film_grain_params.update_parameters = 0;
+  }
+#endif
+
 #if !CONFIG_TILE_INFO_FIRST
   write_tile_info(cm, wb);
 
@@ -4402,6 +4531,10 @@
   write_timing_info_header(cm, &wb);
 #endif
 
+#if CONFIG_FILM_GRAIN
+  aom_wb_write_bit(&wb, cm->film_grain_params_present);
+#endif
+
   size = aom_wb_bytes_written(&wb);
   return size;
 }
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index 1ffb462..3ad0c21 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -62,6 +62,9 @@
 #if CONFIG_INTERNAL_STATS
 #include "aom_dsp/ssim.h"
 #endif
+#if CONFIG_FILM_GRAIN
+#include "av1/encoder/grain_test_vectors.h"
+#endif
 #include "aom_dsp/aom_dsp_common.h"
 #include "aom_dsp/aom_filter.h"
 #include "aom_ports/aom_timer.h"
@@ -479,6 +482,31 @@
                   aom_calloc(mi_size, sizeof(*cpi->mbmi_ext_base)));
 }
 
+#if CONFIG_FILM_GRAIN
+static void update_film_grain_parameters(struct AV1_COMP *cpi,
+                                         const AV1EncoderConfig *oxcf) {
+  AV1_COMMON *const cm = &cpi->common;
+  cpi->oxcf = *oxcf;
+
+  if (oxcf->film_grain_test_vector) {
+    cm->film_grain_params_present = 1;
+    if (cm->frame_type == KEY_FRAME) {
+      memcpy(&cm->film_grain_params,
+             film_grain_test_vectors + oxcf->film_grain_test_vector - 1,
+             sizeof(cm->film_grain_params));
+
+      cm->film_grain_params.bit_depth = cm->bit_depth;
+      if (cm->color_range == AOM_CR_FULL_RANGE) {
+        cm->film_grain_params.clip_to_restricted_range = 0;
+      }
+    }
+  } else {
+    cm->film_grain_params_present = 0;
+    memset(&cm->film_grain_params, 0, sizeof(cm->film_grain_params));
+  }
+}
+#endif
+
 static void dealloc_compressor_data(AV1_COMP *cpi) {
   AV1_COMMON *const cm = &cpi->common;
   const int num_planes = av1_num_planes(cm);
@@ -1079,6 +1107,9 @@
   cm->height = oxcf->height;
   set_sb_size(cm, select_sb_size(cpi));  // set sb size before allocations
   alloc_compressor_data(cpi);
+#if CONFIG_FILM_GRAIN
+  update_film_grain_parameters(cpi, oxcf);
+#endif
 
   // Single thread case: use counts in common.
   cpi->td.counts = &cm->counts;
@@ -3117,6 +3148,10 @@
   cm->num_ticks_per_picture = oxcf->num_ticks_per_picture;
 #endif
 
+#if CONFIG_FILM_GRAIN
+  update_film_grain_parameters(cpi, oxcf);
+#endif
+
   cpi->oxcf = *oxcf;
   x->e_mbd.bd = (int)cm->bit_depth;
   x->e_mbd.global_motion = cm->global_motion;
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index 3793c6c..c975f2b 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -302,6 +302,9 @@
   int equal_picture_interval;
   uint32_t num_ticks_per_picture;
 #endif
+#if CONFIG_FILM_GRAIN
+  int film_grain_test_vector;
+#endif
 
 #if CONFIG_EXT_PARTITION
   aom_superblock_size_t superblock_size;
diff --git a/av1/encoder/grain_test_vectors.h b/av1/encoder/grain_test_vectors.h
new file mode 100644
index 0000000..c85f74c
--- /dev/null
+++ b/av1/encoder/grain_test_vectors.h
@@ -0,0 +1,847 @@
+/*
+ * Copyright (c) 2016, Alliance for Open Media. All rights reserved
+ *
+ * This source code is subject to the terms of the BSD 2 Clause License and
+ * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
+ * was not distributed with this source code in the LICENSE file, you can
+ * obtain it at www.aomedia.org/license/software. If the Alliance for Open
+ * Media Patent License 1.0 was not distributed with this source code in the
+ * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
+ */
+#ifndef AV1_GRAIN_TEST_VECTORS_H_
+#define AV1_GRAIN_TEST_VECTORS_H_
+
+/* Test vectors for emulation of different film grain types.
+ * Note that bit depth would be derived from the bitstream and
+ * not signaled in film grain metadata. The parameters are valid
+ * for any bit depth.
+ */
+static aom_film_grain_t film_grain_test_vectors[16] = {
+  /* Test 1 */
+  {
+      1 /* apply_grain */,
+      1 /* update_parameters */,
+      { { 16, 0 },
+        { 25, 136 },
+        { 33, 144 },
+        { 41, 160 },
+        { 48, 168 },
+        { 56, 136 },
+        { 67, 128 },
+        { 82, 144 },
+        { 97, 152 },
+        { 113, 144 },
+        { 128, 176 },
+        { 143, 168 },
+        { 158, 176 },
+        { 178, 184 } },
+      14 /* num_points_y */,
+      { { 16, 0 },
+        { 20, 64 },
+        { 28, 88 },
+        { 60, 104 },
+        { 90, 136 },
+        { 105, 160 },
+        { 134, 168 },
+        { 168, 208 } },
+      8 /* num_cb_points */,
+      { { 16, 0 },
+        { 28, 96 },
+        { 56, 80 },
+        { 66, 96 },
+        { 80, 104 },
+        { 108, 96 },
+        { 122, 112 },
+        { 137, 112 },
+        { 169, 176 } },
+      9 /* num_cr_points */,
+      11 /* scaling_shift */,
+      2 /* ar_coeff_lag */,
+      { 0, 0, -58, 0, 0, 0, -76, 100, -43, 0, -51, 82 },
+      { 0, 0, -49, 0, 0, 0, -36, 22, -30, 0, -38, 7, 39 },
+      { 0, 0, -47, 0, 0, 0, -31, 31, -25, 0, -32, 13, -100 },
+      8 /* ar_coeff_shift */,
+      247 /* cb_mult */,
+      192 /* cb_luma_mult */,
+      18 /* cb_offset */,
+      229 /* cr_mult */,
+      192 /* cr_luma_mult */,
+      54 /* cr_offset */,
+      0 /* overlap_flag */,
+      1 /* clip_to_restricted_range */,
+      8 /* bit_depth */,
+      0 /* chroma_scaling_from_luma*/,
+      45231 /* random_seed */
+  },
+  /* Test 2 */
+  {
+      1 /* apply_grain */,
+      1 /* update_parameters */,
+      {
+          { 0, 96 }, { 255, 96 },
+      },
+      2 /* num_points_y */,
+      {
+          { 0, 64 }, { 255, 64 },
+      },
+      2 /* num_cb_points */,
+      {
+          { 0, 64 }, { 255, 64 },
+      },
+      2 /* num_cr_points */,
+      11 /* scaling_shift */,
+      3 /* ar_coeff_lag */,
+      {
+          4, 1,   3, 0,   1,  -3, 8,  -3, 7,  -23, 1, -25,
+          0, -10, 6, -17, -4, 53, 36, 5,  -5, -17, 8, 66,
+      },
+      {
+          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   0,
+          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127,
+      },
+      {
+          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   0,
+          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127,
+      },
+      7 /* ar_coeff_shift */,
+      128 /* cb_mult */,
+      192 /* cb_luma_mult */,
+      256 /* cb_offset */,
+      128 /* cr_mult */,
+      192 /* cr_luma_mult */,
+      256 /* cr_offset */,
+      1 /* overlap_flag */,
+      0 /* clip_to_restricted_range */,
+      8 /* bit_depth */,
+      0 /*chroma_scaling_from_luma*/,
+      45231 /* random_seed */
+  },
+  /* Test 3 */
+  {
+      1 /* apply_grain */,
+      1 /* update_parameters */,
+      {
+          { 0, 96 }, { 255, 96 },
+      },
+      2 /* num_points_y */,
+      {
+          { 0, 64 }, { 255, 64 },
+      },
+      2 /* num_cb_points */,
+      {
+          { 0, 64 }, { 255, 64 },
+      },
+      2 /* num_cr_points */,
+      11 /* scaling_shift */,
+      3 /* ar_coeff_lag */,
+      {
+          4, 1,   3, 0,   1,  -3, 8,  -3, 7,  -23, 1, -25,
+          0, -10, 6, -17, -4, 53, 36, 5,  -5, -17, 8, 66,
+      },
+      {
+          4,   -7, 2,  4,   12, -12, 5,   -8, 6,  8,   -19, -16, 19,
+          -10, -2, 17, -42, 58, -2,  -13, 9,  14, -36, 67,  0,
+      },
+      {
+          4,   -7, 2,  4,   12, -12, 5,   -8, 6,  8,   -19, -16, 19,
+          -10, -2, 17, -42, 58, -2,  -13, 9,  14, -36, 67,  0,
+      },
+      7 /* ar_coeff_shift */,
+      128 /* cb_mult */,
+      192 /* cb_luma_mult */,
+      256 /* cb_offset */,
+      128 /* cr_mult */,
+      192 /* cr_luma_mult */,
+      256 /* cr_offset */,
+      1 /* overlap_flag */,
+      1 /* clip_to_restricted_range */,
+      8 /* bit_depth */,
+      0 /*chroma_scaling_from_luma*/,
+      45231 /* random_seed */
+  },
+  /* Test 4 */
+  {
+      1 /* apply_grain */,
+      1 /* update_parameters */,
+      {
+          { 16, 0 },
+          { 24, 137 },
+          { 53, 146 },
+          { 63, 155 },
+          { 78, 155 },
+          { 107, 150 },
+          { 122, 147 },
+          { 136, 147 },
+          { 166, 153 },
+      },
+      9 /* num_points_y */,
+      {
+          { 16, 0 },
+          { 20, 72 },
+          { 27, 82 },
+          { 33, 91 },
+          { 69, 121 },
+          { 95, 143 },
+          { 108, 154 },
+          { 134, 169 },
+          { 147, 177 },
+      },
+      9 /* num_cb_points */,
+      {
+          { 16, 0 },
+          { 24, 95 },
+          { 54, 93 },
+          { 65, 94 },
+          { 79, 98 },
+          { 109, 107 },
+          { 124, 119 },
+          { 139, 136 },
+          { 169, 170 },
+      },
+      9 /* num_cr_points */,
+      11 /* scaling_shift */,
+      3 /* ar_coeff_lag */,
+      {
+          7,  -9,  2, 4,   7, -12, 7,  -18, 18, -30, -27, -42,
+          13, -20, 7, -18, 6, 107, 55, -2,  -4, -9,  -22, 113,
+      },
+      {
+          -3, -1, -4,  3,   -6,  -2,  3,  1,  -4, -10, -10, -5, -5,
+          -3, -1, -13, -28, -25, -31, -6, -4, 14, -64, 66,  0,
+      },
+      {
+          0,  4, -3, 13,  0,  1,   -3, 0,  -3, -10, -68, -4, -2,
+          -5, 2, -3, -20, 62, -31, 0,  -4, -1, -8,  -29, 0,
+      },
+      8 /* ar_coeff_shift */,
+      128 /* cb_mult */,
+      192 /* cb_luma_mult */,
+      256 /* cb_offset */,
+      128 /* cr_mult */,
+      192 /* cr_luma_mult */,
+      256 /* cr_offset */,
+      1 /* overlap_flag */,
+      0 /* clip_to_restricted_range */,
+      8 /* bit_depth */,
+      0 /*chroma_scaling_from_luma*/,
+      45231 /* random_seed */
+  },
+  /* Test 5 */
+  {
+      1 /* apply_grain */,
+      0 /* update_parameters */,
+      {
+          { 0, 64 }, { 255, 64 },
+      },
+      2 /* num_points_y */,
+      {
+          { 0, 96 },
+          { 32, 90 },
+          { 64, 83 },
+          { 96, 76 },
+          { 128, 68 },
+          { 159, 59 },
+          { 191, 48 },
+          { 223, 34 },
+          { 255, 0 },
+      },
+      9 /* num_cb_points */,
+      {
+          { 0, 0 },
+          { 32, 34 },
+          { 64, 48 },
+          { 96, 59 },
+          { 128, 68 },
+          { 159, 76 },
+          { 191, 83 },
+          { 223, 90 },
+          { 255, 96 },
+      },
+      9 /* num_cr_points */,
+      11 /* scaling_shift */,
+      3 /* ar_coeff_lag */,
+      {
+          4, 1,   3, 0,   1,  -3, 8,  -3, 7,  -23, 1, -25,
+          0, -10, 6, -17, -4, 53, 36, 5,  -5, -17, 8, 66,
+      },
+      {
+          -2, 2,  -5, 7,   -6, 4,   -2, -1, 1,  -2,  0,  -2, 2,
+          -3, -5, 13, -13, 6,  -14, 8,  -1, 18, -36, 58, 0,
+      },
+      {
+          -2, -1, -3, 14, -4, -1, -3, 0, -1, 7, -31, 7, 2,
+          0,  1,  0,  -7, 50, -8, -2, 2, 2,  2, -4,  0,
+      },
+      7 /* ar_coeff_shift */,
+      128 /* cb_mult */,
+      192 /* cb_luma_mult */,
+      256 /* cb_offset */,
+      128 /* cr_mult */,
+      192 /* cr_luma_mult */,
+      256 /* cr_offset */,
+      1 /* overlap_flag */,
+      1 /* clip_to_restricted_range */,
+      8 /* bit_depth */,
+      0 /*chroma_scaling_from_luma*/,
+      1063 /* random_seed */
+  },
+  /* Test 6 */
+  {
+      1 /* apply_grain */,
+      1 /* update_parameters */,
+      {
+          { 0, 96 },
+          { 20, 92 },
+          { 39, 88 },
+          { 59, 84 },
+          { 78, 80 },
+          { 98, 75 },
+          { 118, 70 },
+          { 137, 65 },
+          { 157, 60 },
+          { 177, 53 },
+          { 196, 46 },
+          { 216, 38 },
+          { 235, 27 },
+          { 255, 0 },
+      },
+      14 /* num_points_y */,
+      {},
+      0 /* num_cb_points */,
+      {},
+      0 /* num_cr_points */,
+      11 /* scaling_shift */,
+      3 /* ar_coeff_lag */,
+      {
+          4, 1,   3, 0,   1,  -3, 8,  -3, 7,  -23, 1, -25,
+          0, -10, 6, -17, -4, 53, 36, 5,  -5, -17, 8, 66,
+      },
+      {
+          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+      },
+      {
+          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+      },
+      7 /* ar_coeff_shift */,
+      128 /* cb_mult */,
+      192 /* cb_luma_mult */,
+      256 /* cb_offset */,
+      128 /* cr_mult */,
+      192 /* cr_luma_mult */,
+      256 /* cr_offset */,
+      1 /* overlap_flag */,
+      1 /* clip_to_restricted_range */,
+      8 /* bit_depth */,
+      0 /*chroma_scaling_from_luma*/,
+      2754 /* random_seed */
+  },
+  /* Test 7 */
+  {
+      1 /* apply_grain */,
+      1 /* update_parameters */,
+      {
+          { 0, 0 },
+          { 20, 27 },
+          { 39, 38 },
+          { 59, 46 },
+          { 78, 53 },
+          { 98, 60 },
+          { 118, 65 },
+          { 137, 70 },
+          { 157, 75 },
+          { 177, 80 },
+          { 196, 84 },
+          { 216, 88 },
+          { 235, 92 },
+          { 255, 96 },
+      },
+      14 /* num_points_y */,
+      {
+          { 0, 0 }, { 255, 0 },
+      },
+      2 /* num_cb_points */,
+      {
+          { 0, 0 }, { 255, 0 },
+      },
+      2 /* num_cr_points */,
+      11 /* scaling_shift */,
+      3 /* ar_coeff_lag */,
+      {
+          4, 1,   3, 0,   1,  -3, 8,  -3, 7,  -23, 1, -25,
+          0, -10, 6, -17, -4, 53, 36, 5,  -5, -17, 8, 66,
+      },
+      {
+          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+      },
+      {
+          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+      },
+      7 /* ar_coeff_shift */,
+      128 /* cb_mult */,
+      192 /* cb_luma_mult */,
+      256 /* cb_offset */,
+      128 /* cr_mult */,
+      192 /* cr_luma_mult */,
+      256 /* cr_offset */,
+      1 /* overlap_flag */,
+      1 /* clip_to_restricted_range */,
+      8 /* bit_depth */,
+      0 /*chroma_scaling_from_luma*/,
+      45231 /* random_seed */
+  },
+  /* Test 8 */
+  {
+      1 /* apply_grain */,
+      1 /* update_parameters */,
+      {
+          { 0, 96 }, { 255, 96 },
+      },
+      2 /* num_points_y */,
+      {
+          { 0, 62 }, { 255, 62 },
+      },
+      2 /* num_cb_points */,
+      {
+          { 0, 62 }, { 255, 62 },
+      },
+      2 /* num_cr_points */,
+      11 /* scaling_shift */,
+      3 /* ar_coeff_lag */,
+      {
+          4, 1,   3, 0,   1,  -3, 8,  -3, 7,  -23, 1, -25,
+          0, -10, 6, -17, -4, 53, 36, 5,  -5, -17, 8, 66,
+      },
+      {
+          0,  -2, -2, 8,   5,  -1, 1,   -1, 5,  16,  -33, -9,  6,
+          -1, -3, 10, -47, 63, 0,  -15, 3,  11, -42, 75,  -69,
+      },
+      {
+          1,  -1, -1, 9,   5,  0, 1,   -1, 5,  15,  -32, -10, 8,
+          -2, -4, 11, -46, 62, 1, -16, 3,  13, -43, 75,  -55,
+      },
+      7 /* ar_coeff_shift */,
+      128 /* cb_mult */,
+      192 /* cb_luma_mult */,
+      256 /* cb_offset */,
+      128 /* cr_mult */,
+      192 /* cr_luma_mult */,
+      256 /* cr_offset */,
+      1 /* overlap_flag */,
+      0 /* clip_to_restricted_range */,
+      8 /* bit_depth */,
+      0 /*chroma_scaling_from_luma*/,
+      45231 /* random_seed */
+  },
+  /* Test 9 */
+  {
+      1 /* apply_grain */,
+      0 /* update_parameters */,
+      {
+          { 0, 48 }, { 255, 48 },
+      },
+      2 /* num_points_y */,
+      {
+          { 0, 32 }, { 255, 32 },
+      },
+      2 /* num_cb_points */,
+      {
+          { 0, 32 }, { 255, 32 },
+      },
+      2 /* num_cr_points */,
+      10 /* scaling_shift */,
+      2 /* ar_coeff_lag */,
+      {
+          10, -30, -20, -39, 1, -24, 12, 103, 60, -9, -24, 113,
+      },
+      {
+          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127,
+      },
+      {
+          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127,
+      },
+      8 /* ar_coeff_shift */,
+      128 /* cb_mult */,
+      192 /* cb_luma_mult */,
+      256 /* cb_offset */,
+      128 /* cr_mult */,
+      192 /* cr_luma_mult */,
+      256 /* cr_offset */,
+      1 /* overlap_flag */,
+      0 /* clip_to_restricted_range */,
+      8 /* bit_depth */,
+      0 /*chroma_scaling_from_luma*/,
+      45231 /* random_seed */
+  },
+  /* Test 10 */
+  {
+      1 /* apply_grain */,
+      1 /* update_parameters */,
+      {
+          { 0, 48 }, { 255, 48 },
+      },
+      2 /* num_points_y */,
+      {
+          { 0, 32 }, { 255, 32 },
+      },
+      2 /* num_cb_points */,
+      {
+          { 0, 32 }, { 255, 32 },
+      },
+      2 /* num_cr_points */,
+      10 /* scaling_shift */,
+      2 /* ar_coeff_lag */,
+      {
+          10, -30, -20, -39, 1, -24, 12, 103, 60, -9, -24, 113,
+      },
+      {
+          -7, -6, -48, -22, 2, -3, -45, 73, -11, -26, -52, 76, 0,
+      },
+      {
+          -7, -6, -48, -22, 2, -3, -45, 73, -11, -26, -52, 76, 0,
+      },
+      8 /* ar_coeff_shift */,
+      128 /* cb_mult */,
+      192 /* cb_luma_mult */,
+      256 /* cb_offset */,
+      128 /* cr_mult */,
+      192 /* cr_luma_mult */,
+      256 /* cr_offset */,
+      1 /* overlap_flag */,
+      0 /* clip_to_restricted_range */,
+      8 /* bit_depth */,
+      0 /*chroma_scaling_from_luma*/,
+      45231 /* random_seed */
+  },
+  /* Test 11 */
+  {
+      1 /* apply_grain */,
+      0 /* update_parameters */,
+      {
+          { 0, 32 }, { 255, 32 },
+      },
+      2 /* num_points_y */,
+      {
+          { 0, 48 },
+          { 32, 45 },
+          { 64, 42 },
+          { 96, 38 },
+          { 128, 34 },
+          { 159, 29 },
+          { 191, 24 },
+          { 223, 17 },
+          { 255, 0 },
+      },
+      9 /* num_cb_points */,
+      {
+          { 0, 0 },
+          { 32, 17 },
+          { 64, 24 },
+          { 96, 29 },
+          { 128, 34 },
+          { 159, 38 },
+          { 191, 42 },
+          { 223, 45 },
+          { 255, 48 },
+      },
+      9 /* num_cr_points */,
+      10 /* scaling_shift */,
+      3 /* ar_coeff_lag */,
+      {
+          7,  -9,  2, 4,   7, -12, 7,  -18, 18, -30, -27, -42,
+          13, -20, 7, -18, 6, 107, 55, -2,  -4, -9,  -22, 113,
+      },
+      {
+          -3, -1, -4,  3,   -6,  -2,  3,  1,  -4, -10, -10, -5, -5,
+          -3, -1, -13, -28, -25, -31, -6, -4, 14, -64, 66,  0,
+      },
+      {
+          0,  4, -3, 13,  0,  1,   -3, 0,  -3, -10, -68, -4, -2,
+          -5, 2, -3, -20, 62, -31, 0,  -4, -1, -8,  -29, 0,
+      },
+      8 /* ar_coeff_shift */,
+      128 /* cb_mult */,
+      192 /* cb_luma_mult */,
+      256 /* cb_offset */,
+      128 /* cr_mult */,
+      192 /* cr_luma_mult */,
+      256 /* cr_offset */,
+      1 /* overlap_flag */,
+      1 /* clip_to_restricted_range */,
+      8 /* bit_depth */,
+      0 /*chroma_scaling_from_luma*/,
+      1357 /* random_seed */
+  },
+  /* Test 12 */
+  {
+      1 /* apply_grain */,
+      1 /* update_parameters */,
+      {
+          { 16, 0 },
+          { 24, 49 },
+          { 39, 69 },
+          { 46, 84 },
+          { 53, 91 },
+          { 63, 100 },
+          { 78, 114 },
+          { 92, 134 },
+          { 164, 139 },
+      },
+      9 /* num_points_y */,
+      {
+          { 16, 0 },
+          { 20, 31 },
+          { 26, 42 },
+          { 33, 54 },
+          { 40, 65 },
+          { 47, 72 },
+          { 56, 85 },
+          { 84, 123 },
+          { 152, 157 },
+      },
+      9 /* num_cb_points */,
+      {
+          { 16, 0 },
+          { 25, 14 },
+          { 39, 33 },
+          { 47, 40 },
+          { 54, 47 },
+          { 64, 62 },
+          { 79, 76 },
+          { 94, 83 },
+          { 167, 101 },
+      },
+      9 /* num_cr_points */,
+      10 /* scaling_shift */,
+      2 /* ar_coeff_lag */,
+      { 0, 0, -58, 0, 0, 0, -76, 100, -43, 0, -51, 82 },
+      { 0, 0, -49, 0, 0, 0, -36, 22, -30, 0, -38, 7, 39 },
+      { 0, 0, -47, 0, 0, 0, -31, 31, -25, 0, -32, 13, -100 },
+      8 /* ar_coeff_shift */,
+      128 /* cb_mult */,
+      192 /* cb_luma_mult */,
+      256 /* cb_offset */,
+      128 /* cr_mult */,
+      192 /* cr_luma_mult */,
+      256 /* cr_offset */,
+      0 /* overlap_flag */,
+      0 /* clip_to_restricted_range */,
+      8 /* bit_depth */,
+      0 /*chroma_scaling_from_luma*/,
+      45231 /* random_seed */
+  },
+  /* Test 13 */
+  {
+      1 /* apply_grain */,
+      1 /* update_parameters */,
+      {
+          { 0, 48 },
+          { 20, 46 },
+          { 39, 44 },
+          { 59, 42 },
+          { 78, 40 },
+          { 98, 38 },
+          { 118, 35 },
+          { 137, 33 },
+          { 157, 30 },
+          { 177, 27 },
+          { 196, 23 },
+          { 216, 19 },
+          { 235, 13 },
+          { 255, 0 },
+      },
+      14 /* num_points_y */,
+      {
+          { 0, 0 }, { 255, 0 },
+      },
+      0 /* num_cb_points */,
+      {
+          { 0, 0 }, { 255, 0 },
+      },
+      0 /* num_cr_points */,
+      10 /* scaling_shift */,
+      2 /* ar_coeff_lag */,
+      {
+          10, -30, -20, -39, 1, -24, 12, 103, 60, -9, -24, 113,
+      },
+      {
+          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+      },
+      {
+          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+      },
+      8 /* ar_coeff_shift */,
+      128 /* cb_mult */,
+      192 /* cb_luma_mult */,
+      256 /* cb_offset */,
+      128 /* cr_mult */,
+      192 /* cr_luma_mult */,
+      256 /* cr_offset */,
+      1 /* overlap_flag */,
+      0 /* clip_to_restricted_range */,
+      8 /* bit_depth */,
+      0 /*chroma_scaling_from_luma*/,
+      45231 /* random_seed */
+  },
+  /* Test 14 */
+  {
+      1 /* apply_grain */,
+      1 /* update_parameters */,
+      {
+          { 0, 0 },
+          { 20, 13 },
+          { 39, 19 },
+          { 59, 23 },
+          { 78, 27 },
+          { 98, 30 },
+          { 118, 33 },
+          { 137, 35 },
+          { 157, 38 },
+          { 177, 40 },
+          { 196, 42 },
+          { 216, 44 },
+          { 235, 46 },
+          { 255, 48 },
+      },
+      14 /* num_points_y */,
+      {
+          { 0, 0 }, { 255, 0 },
+      },
+      0 /* num_cb_points */,
+      {
+          { 0, 0 }, { 255, 0 },
+      },
+      0 /* num_cr_points */,
+      10 /* scaling_shift */,
+      2 /* ar_coeff_lag */,
+      {
+          10, -30, -20, -39, 1, -24, 12, 103, 60, -9, -24, 113,
+      },
+      {
+          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+      },
+      {
+          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+      },
+      8 /* ar_coeff_shift */,
+      128 /* cb_mult */,
+      192 /* cb_luma_mult */,
+      256 /* cb_offset */,
+      128 /* cr_mult */,
+      192 /* cr_luma_mult */,
+      256 /* cr_offset */,
+      1 /* overlap_flag */,
+      1 /* clip_to_restricted_range */,
+      8 /* bit_depth */,
+      0 /*chroma_scaling_from_luma*/,
+      45231 /* random_seed */
+  },
+  /* Test 15 */
+  {
+      1 /* apply_grain */,
+      1 /* update_parameters */,
+      {
+          { 0, 96 }, { 255, 96 },
+      },
+      1 /* num_points_y */,
+      {
+          { 0, 96 }, { 255, 96 },
+      },
+      0 /* num_cb_points */,
+      {
+          { 0, 96 }, { 255, 96 },
+      },
+      0 /* num_cr_points */,
+      11 /* scaling_shift */,
+      2 /* ar_coeff_lag */,
+      {
+          5, -15, -10, -19, 0, -12, 6, 51, 30, -5, -12, 56,
+      },
+      {
+          2, 2, -24, -5, 1, 1, -18, 37, -2, 0, -15, 39, -70,
+      },
+      {
+          2, 3, -24, -5, -1, 0, -18, 38, -2, 0, -15, 39, -55,
+      },
+      7 /* ar_coeff_shift */,
+      128 /* cb_mult */,
+      192 /* cb_luma_mult */,
+      256 /* cb_offset */,
+      128 /* cr_mult */,
+      192 /* cr_luma_mult */,
+      256 /* cr_offset */,
+      1 /* overlap_flag */,
+      0 /* clip_to_restricted_range */,
+      8 /* bit_depth */,
+      1 /*chroma_scaling_from_luma*/,
+      45231 /* random_seed */
+  },
+  /* Test 16 */
+  {
+      1 /* apply_grain */,
+      1 /* update_parameters */,
+      {
+          { 16, 0 },
+          { 58, 126 },
+          { 87, 120 },
+          { 97, 122 },
+          { 112, 125 },
+          { 126, 131 },
+          { 141, 139 },
+          { 199, 153 },
+      },
+      8 /* num_points_y */,
+      {
+          { 16, 0 },
+          { 59, 68 },
+          { 66, 76 },
+          { 73, 82 },
+          { 79, 85 },
+          { 86, 86 },
+          { 151, 95 },
+          { 192, 101 },
+      },
+      8 /* num_cb_points */,
+      {
+          { 16, 0 },
+          { 59, 64 },
+          { 89, 80 },
+          { 99, 86 },
+          { 114, 90 },
+          { 129, 93 },
+          { 144, 97 },
+          { 203, 85 },
+      },
+      8 /* num_cr_points */,
+      11 /* scaling_shift */,
+      3 /* ar_coeff_lag */,
+      {
+          4, 1,   3, 0,   1,  -3, 8,  -3, 7,  -23, 1, -25,
+          0, -10, 6, -17, -4, 53, 36, 5,  -5, -17, 8, 66,
+      },
+      {
+          0,  -2, -2, 8,   5,  -1, 1,   -1, 5,  16,  -33, -9,  6,
+          -1, -3, 10, -47, 63, 0,  -15, 3,  11, -42, 75,  -69,
+      },
+      {
+          1,  -1, -1, 9,   5,  0, 1,   -1, 5,  15,  -32, -10, 8,
+          -2, -4, 11, -46, 62, 1, -16, 3,  13, -43, 75,  -55,
+      },
+      7 /* ar_coeff_shift */,
+      128 /* cb_mult */,
+      192 /* cb_luma_mult */,
+      256 /* cb_offset */,
+      128 /* cr_mult */,
+      192 /* cr_luma_mult */,
+      256 /* cr_offset */,
+      1 /* overlap_flag */,
+      0 /* clip_to_restricted_range */,
+      8 /* bit_depth */,
+      0 /*chroma_scaling_from_luma*/,
+      45231 /* random_seed */
+  },
+};
+#endif  // AV1_GRAIN_TEST_VECTORS_H_