Commit f8164157 authored by Luc Trudeau's avatar Luc Trudeau

[CFL] Custom block-level DC_PRED

Adds the CfL experiment flag and computes a block-level DC_PRED that is
required by CfL in order to compute alpha_cb and alpha_cr.

The rate-distorsion impact of computing DC_PRED at the prediction block level
for chroma planes is rather small

Subset 1:
master_no_cdef@2017-04-18T20:37:05.712Z
  -> block_DCPRED_no_cdef@2017-04-18T20:38:07.381
  PSNR | PSNR Cb | PSNR Cr | PSNR HVS |   SSIM | MS SSIM | CIEDE 2000
0.0712 |  0.0337 | -0.1692 |   0.0693 | 0.0814 |  0.0710 |    -0.0063
Note: CDEF was disabled because of problematic asserts.

Change-Id: I44d1cde8605b108366f4bd4cedbf5159dbbb5880
parent acaa384f
......@@ -313,6 +313,13 @@ if (CONFIG_PALETTE)
"${AOM_ROOT}/av1/encoder/palette.h")
endif ()
if (CONFIG_CFL)
set(AOM_AV1_COMMON_SOURCES
${AOM_AV1_COMMON_SOURCES}
"${AOM_ROOT}/av1/common/cfl.c"
"${AOM_ROOT}/av1/common/cfl.h")
endif ()
if (CONFIG_PVQ)
set(AOM_AV1_COMMON_SOURCES
${AOM_AV1_COMMON_SOURCES}
......
......@@ -109,6 +109,11 @@ endif
AV1_COMMON_SRCS-yes += common/odintrin.c
AV1_COMMON_SRCS-yes += common/odintrin.h
ifeq ($(CONFIG_CFL),yes)
AV1_COMMON_SRCS-yes += common/cfl.h
AV1_COMMON_SRCS-yes += common/cfl.c
endif
ifeq ($(CONFIG_PVQ),yes)
# PVQ from daala
AV1_COMMON_SRCS-yes += common/pvq.c
......
......@@ -516,6 +516,14 @@ typedef struct RefBuffer {
} RefBuffer;
typedef int16_t EobThresholdMD[TX_SIZES_ALL][TX_TYPES];
#if CONFIG_CFL
typedef struct {
// CfL Performs its own block level DC_PRED for each chromatic plane
int dc_pred[2];
} CFL_CTX;
#endif
typedef struct macroblockd {
struct macroblockd_plane plane[MAX_MB_PLANE];
uint8_t bmode_blocks_wl;
......@@ -604,6 +612,10 @@ typedef struct macroblockd {
#if CONFIG_ADAPT_SCAN
const EobThresholdMD *eob_threshold_md;
#endif
#if CONFIG_CFL
CFL_CTX *cfl;
#endif
} MACROBLOCKD;
static INLINE BLOCK_SIZE get_subsize(BLOCK_SIZE bsize,
......
/*
* 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.
*/
#include "av1/common/cfl.h"
#include "av1/common/common_data.h"
// CfL computes its own block-level DC_PRED. This is required to compute both
// alpha_cb and alpha_cr before the prediction are computed.
void cfl_dc_pred(MACROBLOCKD *const xd, BLOCK_SIZE plane_bsize,
TX_SIZE tx_size) {
const struct macroblockd_plane *const pd_cb = &xd->plane[1];
const struct macroblockd_plane *const pd_cr = &xd->plane[2];
const uint8_t *const dst_cb = pd_cb->dst.buf;
const uint8_t *const dst_cr = pd_cr->dst.buf;
const int dst_cb_stride = pd_cb->dst.stride;
const int dst_cr_stride = pd_cr->dst.stride;
const int block_width = (plane_bsize != BLOCK_INVALID)
? block_size_wide[plane_bsize]
: tx_size_wide[tx_size];
const int block_height = (plane_bsize != BLOCK_INVALID)
? block_size_high[plane_bsize]
: tx_size_high[tx_size];
const int num_pel = block_width + block_height;
int sum_cb = 0;
int sum_cr = 0;
// Match behavior of build_intra_predictors (reconintra.c) at superblock
// boundaries:
//
// 127 127 127 .. 127 127 127 127 127 127
// 129 A B .. Y Z
// 129 C D .. W X
// 129 E F .. U V
// 129 G H .. S T T T T T
// ..
// TODO(ltrudeau) replace this with DC_PRED assembly
if (xd->up_available && xd->mb_to_right_edge >= 0) {
for (int i = 0; i < block_width; i++) {
sum_cb += dst_cb[-dst_cb_stride + i];
sum_cr += dst_cr[-dst_cr_stride + i];
}
} else {
sum_cb = block_width * 127;
sum_cr = block_width * 127;
}
if (xd->left_available && xd->mb_to_bottom_edge >= 0) {
for (int i = 0; i < block_height; i++) {
sum_cb += dst_cb[i * dst_cb_stride - 1];
sum_cr += dst_cr[i * dst_cr_stride - 1];
}
} else {
sum_cb += block_height * 129;
sum_cr += block_height * 129;
}
xd->cfl->dc_pred[0] = (sum_cb + (num_pel >> 1)) / num_pel;
xd->cfl->dc_pred[1] = (sum_cr + (num_pel >> 1)) / num_pel;
}
// Predict the current transform block using CfL.
// it is assumed that dst points at the start of the transform block
void cfl_predict_block(uint8_t *const dst, int dst_stride, TX_SIZE tx_size,
int dc_pred) {
const int tx_block_width = tx_size_wide[tx_size];
const int tx_block_height = tx_size_high[tx_size];
int dst_row = 0;
for (int j = 0; j < tx_block_height; j++) {
for (int i = 0; i < tx_block_width; i++) {
dst[dst_row + i] = dc_pred;
}
dst_row += dst_stride;
}
}
/*
* 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_COMMON_CFL_H_
#define AV1_COMMON_CFL_H_
#include "av1/common/blockd.h"
#include "av1/common/enums.h"
void cfl_dc_pred(MACROBLOCKD *const xd, BLOCK_SIZE plane_bsize,
TX_SIZE tx_size);
void cfl_predict_block(uint8_t *const dst, int dst_stride, TX_SIZE tx_size,
int dc_pred);
#endif // AV1_COMMON_CFL_H_
......@@ -517,6 +517,9 @@ static INLINE int frame_is_intra_only(const AV1_COMMON *const cm) {
static INLINE void av1_init_macroblockd(AV1_COMMON *cm, MACROBLOCKD *xd,
#if CONFIG_PVQ
tran_low_t *pvq_ref_coeff,
#endif
#if CONFIG_CFL
CFL_CTX *cfl,
#endif
tran_low_t *dqcoeff) {
int i;
......@@ -524,6 +527,9 @@ static INLINE void av1_init_macroblockd(AV1_COMMON *cm, MACROBLOCKD *xd,
xd->plane[i].dqcoeff = dqcoeff;
#if CONFIG_PVQ
xd->plane[i].pvq_ref_coeff = pvq_ref_coeff;
#endif
#if CONFIG_CFL
xd->cfl = cfl;
#endif
xd->above_context[i] = cm->above_context[i];
if (xd->plane[i].plane_type == PLANE_TYPE_Y) {
......
......@@ -24,6 +24,9 @@
#include "aom_ports/aom_once.h"
#include "av1/common/reconintra.h"
#include "av1/common/onyxc_int.h"
#if CONFIG_CFL
#include "av1/common/cfl.h"
#endif
enum {
NEED_LEFT = 1 << 1,
......@@ -2159,8 +2162,16 @@ static void build_intra_predictors(const MACROBLOCKD *xd, const uint8_t *ref,
// predict
if (mode == DC_PRED) {
dc_pred[n_left_px > 0][n_top_px > 0][tx_size](dst, dst_stride,
const_above_row, left_col);
#if CONFIG_CFL
// CFL predict its own DC_PRED for Chromatic planes
if (plane == AOM_PLANE_Y) {
#endif
dc_pred[n_left_px > 0][n_top_px > 0][tx_size](dst, dst_stride,
const_above_row, left_col);
#if CONFIG_CFL
}
#endif
} else {
pred[mode][tx_size](dst, dst_stride, const_above_row, left_col);
}
......@@ -2288,6 +2299,19 @@ void av1_predict_intra_block_facade(MACROBLOCKD *xd, int plane, int block_idx,
av1_predict_intra_block(xd, pd->width, pd->height, txsize_to_bsize[tx_size],
mode, dst, dst_stride, dst, dst_stride, blk_col,
blk_row, plane);
#if CONFIG_CFL
if (plane != AOM_PLANE_Y && mbmi->uv_mode == DC_PRED) {
if (plane == AOM_PLANE_U && blk_col == 0 && blk_row == 0) {
// Compute the block-level DC_PRED for both chromatic planes prior to
// processing the first chromatic plane in order to compute alpha_cb and
// alpha_cr. Note: This is not required on the decoder side because alpha
// is signaled.
cfl_dc_pred(xd, get_plane_block_size(block_idx, pd), tx_size);
}
cfl_predict_block(dst, pd->dst.stride, tx_size,
xd->cfl->dc_pred[plane - 1]);
}
#endif
}
void av1_predict_intra_block(const MACROBLOCKD *xd, int wpx, int hpx,
......
......@@ -3459,6 +3459,9 @@ static const uint8_t *decode_tiles(AV1Decoder *pbi, const uint8_t *data,
av1_init_macroblockd(cm, &td->xd,
#if CONFIG_PVQ
td->pvq_ref_coeff,
#endif
#if CONFIG_CFL
&td->cfl,
#endif
td->dqcoeff);
......@@ -3831,6 +3834,9 @@ static const uint8_t *decode_tiles_mt(AV1Decoder *pbi, const uint8_t *data,
av1_init_macroblockd(cm, &twd->xd,
#if CONFIG_PVQ
twd->pvq_ref_coeff,
#endif
#if CONFIG_CFL
&twd->cfl,
#endif
twd->dqcoeff);
#if CONFIG_PVQ
......
......@@ -50,6 +50,9 @@ typedef struct TileData {
/* forward transformed predicted image, a reference for PVQ */
DECLARE_ALIGNED(16, tran_low_t, pvq_ref_coeff[OD_TXSIZE_MAX * OD_TXSIZE_MAX]);
#endif
#if CONFIG_CFL
CFL_CTX cfl;
#endif
#if CONFIG_EC_ADAPT
DECLARE_ALIGNED(16, FRAME_CONTEXT, tctx);
#endif
......@@ -69,6 +72,9 @@ typedef struct TileWorkerData {
/* forward transformed predicted image, a reference for PVQ */
DECLARE_ALIGNED(16, tran_low_t, pvq_ref_coeff[OD_TXSIZE_MAX * OD_TXSIZE_MAX]);
#endif
#if CONFIG_CFL
CFL_CTX cfl;
#endif
#if CONFIG_EC_ADAPT
FRAME_CONTEXT tctx;
#endif
......
......@@ -5017,6 +5017,10 @@ void av1_encode_tile(AV1_COMP *cpi, ThreadData *td, int tile_row,
td->mb.e_mbd.tile_ctx = &this_tile->tctx;
#endif // #if CONFIG_EC_ADAPT
#if CONFIG_CFL
td->mb.e_mbd.cfl = &this_tile->cfl;
#endif
#if CONFIG_PVQ
td->mb.daala_enc.state.adapt = &this_tile->tctx.pvq_context;
#endif // CONFIG_PVQ
......
......@@ -104,6 +104,10 @@ FILE *kf_list;
FILE *keyfile;
#endif
#if CONFIG_CFL
CFL_CTX NULL_CFL;
#endif
#if CONFIG_INTERNAL_STATS
typedef enum { Y, U, V, ALL } STAT_TYPE;
#endif // CONFIG_INTERNAL_STATS
......@@ -931,6 +935,9 @@ static void update_frame_size(AV1_COMP *cpi) {
av1_init_macroblockd(cm, xd,
#if CONFIG_PVQ
NULL,
#endif
#if CONFIG_CFL
&NULL_CFL,
#endif
NULL);
memset(cpi->mbmi_ext_base, 0,
......
......@@ -286,6 +286,9 @@ typedef struct TileDataEnc {
#if CONFIG_PVQ
PVQ_QUEUE pvq_q;
#endif
#if CONFIG_CFL
CFL_CTX cfl;
#endif
#if CONFIG_EC_ADAPT
DECLARE_ALIGNED(16, FRAME_CONTEXT, tctx);
#endif
......
......@@ -290,6 +290,7 @@ EXPERIMENT_LIST="
rawbits
ec_smallmul
pvq
cfl
xiphrc
cb4x4
chroma_2x2
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment