DPCM intra coding experiment

Encode a block line by line, horizontally or vertically. In the vertical
mode, each row is predicted by the reconsturcted row above;
in the horizontal mode, each column is predicted by the reconstructed
column to the left.

The DPCM modes are enabled automatically for blocks with horizontal or
vertical prediction mode, and 1D transform types (ext-tx).

Change-Id: I133ab6b537fa24a6e314ee1ef1d2fe9bd9d56c13
diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c
index 85b77ad..06a8efd 100644
--- a/av1/decoder/decodeframe.c
+++ b/av1/decoder/decodeframe.c
@@ -518,6 +518,133 @@
   return row * max_blocks_wide + col * txh_unit;
 }
 
+#if CONFIG_DPCM_INTRA
+static void process_block_dpcm_vert(TX_SIZE tx_size, TX_TYPE_1D tx_type_1d,
+                                    const tran_low_t *dqcoeff, uint8_t *dst,
+                                    int dst_stride) {
+  const int tx1d_width = tx_size_wide[tx_size];
+  const int tx1d_height = tx_size_high[tx_size];
+  dpcm_inv_txfm_add_func inverse_tx =
+      av1_get_dpcm_inv_txfm_add_func(tx1d_width);
+  for (int r = 0; r < tx1d_height; ++r) {
+    if (r > 0) memcpy(dst, dst - dst_stride, tx1d_width * sizeof(dst[0]));
+    inverse_tx(dqcoeff, 1, tx_type_1d, dst);
+    dqcoeff += tx1d_width;
+    dst += dst_stride;
+  }
+}
+
+static void process_block_dpcm_horz(TX_SIZE tx_size, TX_TYPE_1D tx_type_1d,
+                                    const tran_low_t *dqcoeff, uint8_t *dst,
+                                    int dst_stride) {
+  const int tx1d_width = tx_size_wide[tx_size];
+  const int tx1d_height = tx_size_high[tx_size];
+  dpcm_inv_txfm_add_func inverse_tx =
+      av1_get_dpcm_inv_txfm_add_func(tx1d_height);
+  tran_low_t tx_buff[64];
+  for (int c = 0; c < tx1d_width; ++c, ++dqcoeff, ++dst) {
+    for (int r = 0; r < tx1d_height; ++r) {
+      if (c > 0) dst[r * dst_stride] = dst[r * dst_stride - 1];
+      tx_buff[r] = dqcoeff[r * tx1d_width];
+    }
+    inverse_tx(tx_buff, dst_stride, tx_type_1d, dst);
+  }
+}
+
+#if CONFIG_HIGHBITDEPTH
+static void hbd_process_block_dpcm_vert(TX_SIZE tx_size, TX_TYPE_1D tx_type_1d,
+                                        int bd, const tran_low_t *dqcoeff,
+                                        uint8_t *dst8, int dst_stride) {
+  uint16_t *dst = CONVERT_TO_SHORTPTR(dst8);
+  const int tx1d_width = tx_size_wide[tx_size];
+  const int tx1d_height = tx_size_high[tx_size];
+  hbd_dpcm_inv_txfm_add_func inverse_tx =
+      av1_get_hbd_dpcm_inv_txfm_add_func(tx1d_width);
+  for (int r = 0; r < tx1d_height; ++r) {
+    if (r > 0) memcpy(dst, dst - dst_stride, tx1d_width * sizeof(dst[0]));
+    inverse_tx(dqcoeff, 1, tx_type_1d, bd, dst);
+    dqcoeff += tx1d_width;
+    dst += dst_stride;
+  }
+}
+
+static void hbd_process_block_dpcm_horz(TX_SIZE tx_size, TX_TYPE_1D tx_type_1d,
+                                        int bd, const tran_low_t *dqcoeff,
+                                        uint8_t *dst8, int dst_stride) {
+  uint16_t *dst = CONVERT_TO_SHORTPTR(dst8);
+  const int tx1d_width = tx_size_wide[tx_size];
+  const int tx1d_height = tx_size_high[tx_size];
+  hbd_dpcm_inv_txfm_add_func inverse_tx =
+      av1_get_hbd_dpcm_inv_txfm_add_func(tx1d_height);
+  tran_low_t tx_buff[64];
+  switch (tx1d_height) {
+    case 4: inverse_tx = av1_hbd_dpcm_inv_txfm_add_4_c; break;
+    case 8: inverse_tx = av1_hbd_dpcm_inv_txfm_add_8_c; break;
+    case 16: inverse_tx = av1_hbd_dpcm_inv_txfm_add_16_c; break;
+    case 32: inverse_tx = av1_hbd_dpcm_inv_txfm_add_32_c; break;
+    default: assert(0);
+  }
+
+  for (int c = 0; c < tx1d_width; ++c, ++dqcoeff, ++dst) {
+    for (int r = 0; r < tx1d_height; ++r) {
+      if (c > 0) dst[r * dst_stride] = dst[r * dst_stride - 1];
+      tx_buff[r] = dqcoeff[r * tx1d_width];
+    }
+    inverse_tx(tx_buff, dst_stride, tx_type_1d, bd, dst);
+  }
+}
+#endif  // CONFIG_HIGHBITDEPTH
+
+static void inverse_transform_block_dpcm(MACROBLOCKD *xd, int plane,
+                                         PREDICTION_MODE mode, TX_SIZE tx_size,
+                                         TX_TYPE tx_type, uint8_t *dst,
+                                         int dst_stride, int16_t scan_line) {
+  struct macroblockd_plane *const pd = &xd->plane[plane];
+  tran_low_t *const dqcoeff = pd->dqcoeff;
+  TX_TYPE_1D tx_type_1d = DCT_1D;
+  switch (tx_type) {
+    case IDTX: tx_type_1d = IDTX_1D; break;
+    case V_DCT:
+      assert(mode == H_PRED);
+      tx_type_1d = DCT_1D;
+      break;
+    case H_DCT:
+      assert(mode == V_PRED);
+      tx_type_1d = DCT_1D;
+      break;
+    default: assert(0);
+  }
+  switch (mode) {
+    case V_PRED:
+#if CONFIG_HIGHBITDEPTH
+      if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) {
+        hbd_process_block_dpcm_vert(tx_size, tx_type_1d, xd->bd, dqcoeff, dst,
+                                    dst_stride);
+      } else {
+#endif  // CONFIG_HIGHBITDEPTH
+        process_block_dpcm_vert(tx_size, tx_type_1d, dqcoeff, dst, dst_stride);
+#if CONFIG_HIGHBITDEPTH
+      }
+#endif  // CONFIG_HIGHBITDEPTH
+      break;
+    case H_PRED:
+#if CONFIG_HIGHBITDEPTH
+      if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) {
+        hbd_process_block_dpcm_horz(tx_size, tx_type_1d, xd->bd, dqcoeff, dst,
+                                    dst_stride);
+      } else {
+#endif  // CONFIG_HIGHBITDEPTH
+        process_block_dpcm_horz(tx_size, tx_type_1d, dqcoeff, dst, dst_stride);
+#if CONFIG_HIGHBITDEPTH
+      }
+#endif  // CONFIG_HIGHBITDEPTH
+      break;
+    default: assert(0);
+  }
+  memset(dqcoeff, 0, (scan_line + 1) * sizeof(dqcoeff[0]));
+}
+#endif  // CONFIG_DPCM_INTRA
+
 static void predict_and_reconstruct_intra_block(
     AV1_COMMON *cm, MACROBLOCKD *const xd, aom_reader *const r,
     MB_MODE_INFO *const mbmi, int plane, int row, int col, TX_SIZE tx_size) {
@@ -549,8 +676,22 @@
     if (eob) {
       uint8_t *dst =
           &pd->dst.buf[(row * pd->dst.stride + col) << tx_size_wide_log2[0]];
-      inverse_transform_block(xd, plane, tx_type, tx_size, dst, pd->dst.stride,
-                              max_scan_line, eob);
+#if CONFIG_DPCM_INTRA
+      const int block_raster_idx =
+          av1_block_index_to_raster_order(tx_size, block_idx);
+      const PREDICTION_MODE mode = (plane == 0)
+                                       ? get_y_mode(xd->mi[0], block_raster_idx)
+                                       : mbmi->uv_mode;
+      if (av1_use_dpcm_intra(plane, mode, tx_type, mbmi)) {
+        inverse_transform_block_dpcm(xd, plane, mode, tx_size, tx_type, dst,
+                                     pd->dst.stride, max_scan_line);
+      } else {
+#endif  // CONFIG_DPCM_INTRA
+        inverse_transform_block(xd, plane, tx_type, tx_size, dst,
+                                pd->dst.stride, max_scan_line, eob);
+#if CONFIG_DPCM_INTRA
+      }
+#endif  // CONFIG_DPCM_INTRA
     }
 #else
     TX_TYPE tx_type = get_tx_type(plane_type, xd, block_idx, tx_size);