[CFL] Alpha signaling

Writes and reads alpha to and from the bitstream.

A special case is needed on the encoder side to handle prediction block
skips. Since whether or not a prediction block is skipped during CfL, a
rollback is required if the block was skipped and the alpha index was
not zero. The advantage of this is that no signaling is required when
the prediction block is skipped as it is assumed tha the alpha index is
zero.

A encode facade is added to the intra prediction facade as CfL requires
special encoder side operations.

Change-Id: Ic3b11d0fdbd51389d862112eb09d8785127a6b06
diff --git a/av1/encoder/encodemb.c b/av1/encoder/encodemb.c
index 83bf5bf..37d60e0 100644
--- a/av1/encoder/encodemb.c
+++ b/av1/encoder/encodemb.c
@@ -1435,7 +1435,12 @@
   const int dst_stride = pd->dst.stride;
   uint8_t *dst =
       &pd->dst.buf[(blk_row * dst_stride + blk_col) << tx_size_wide_log2[0]];
+#if CONFIG_CFL
+  av1_predict_intra_block_encoder_facade(xd, plane, block, blk_col, blk_row,
+                                         tx_size);
+#else
   av1_predict_intra_block_facade(xd, plane, block, blk_col, blk_row, tx_size);
+#endif
   av1_subtract_txb(x, plane, plane_bsize, blk_col, blk_row, tx_size);
 
   const ENTROPY_CONTEXT *a = &args->ta[blk_col];
@@ -1464,12 +1469,70 @@
 // Note : *(args->skip) == mbmi->skip
 #endif
 #if CONFIG_CFL
+  MB_MODE_INFO *mbmi = &xd->mi[0]->mbmi;
   if (plane == AOM_PLANE_Y && x->cfl_store_y) {
     cfl_store(xd->cfl, dst, dst_stride, blk_row, blk_col, tx_size);
   }
+
+  if (mbmi->uv_mode == DC_PRED) {
+    // TODO(ltrudeau) find a cleaner way to detect last transform block
+    if (plane == AOM_PLANE_U) {
+      xd->cfl->num_tx_blk[CFL_PRED_U] =
+          (blk_row == 0 && blk_col == 0) ? 1
+                                         : xd->cfl->num_tx_blk[CFL_PRED_U] + 1;
+    }
+
+    if (plane == AOM_PLANE_V) {
+      xd->cfl->num_tx_blk[CFL_PRED_V] =
+          (blk_row == 0 && blk_col == 0) ? 1
+                                         : xd->cfl->num_tx_blk[CFL_PRED_V] + 1;
+
+      if (mbmi->skip &&
+          xd->cfl->num_tx_blk[CFL_PRED_U] == xd->cfl->num_tx_blk[CFL_PRED_V]) {
+        assert(plane_bsize != BLOCK_INVALID);
+        const int block_width = block_size_wide[plane_bsize];
+        const int block_height = block_size_high[plane_bsize];
+
+        // if SKIP is chosen at the block level, and ind != 0, we must change
+        // the prediction
+        if (mbmi->cfl_alpha_ind != 0) {
+          const struct macroblockd_plane *const pd_cb = &xd->plane[AOM_PLANE_U];
+          uint8_t *const dst_cb = pd_cb->dst.buf;
+          const int dst_stride_cb = pd_cb->dst.stride;
+          uint8_t *const dst_cr = pd->dst.buf;
+          const int dst_stride_cr = pd->dst.stride;
+          for (int j = 0; j < block_height; j++) {
+            for (int i = 0; i < block_width; i++) {
+              dst_cb[dst_stride_cb * j + i] =
+                  (uint8_t)(xd->cfl->dc_pred[CFL_PRED_U] + 0.5);
+              dst_cr[dst_stride_cr * j + i] =
+                  (uint8_t)(xd->cfl->dc_pred[CFL_PRED_V] + 0.5);
+            }
+          }
+          mbmi->cfl_alpha_ind = 0;
+          mbmi->cfl_alpha_signs[CFL_PRED_U] = CFL_SIGN_POS;
+          mbmi->cfl_alpha_signs[CFL_PRED_V] = CFL_SIGN_POS;
+        }
+      }
+    }
+  }
 #endif
 }
 
+#if CONFIG_CFL
+void av1_predict_intra_block_encoder_facade(MACROBLOCKD *xd, int plane,
+                                            int block_idx, int blk_col,
+                                            int blk_row, TX_SIZE tx_size) {
+  MB_MODE_INFO *mbmi = &xd->mi[0]->mbmi;
+  mbmi->cfl_alpha_ind = 0;
+  mbmi->cfl_alpha_signs[CFL_PRED_U] = CFL_SIGN_POS;
+  mbmi->cfl_alpha_signs[CFL_PRED_V] = CFL_SIGN_POS;
+
+  av1_predict_intra_block_facade(xd, plane, block_idx, blk_col, blk_row,
+                                 tx_size);
+}
+#endif
+
 void av1_encode_intra_block_plane(AV1_COMMON *cm, MACROBLOCK *x,
                                   BLOCK_SIZE bsize, int plane,
                                   int enable_optimize_b, const int mi_row,