summaryrefslogtreecommitdiff
path: root/vp9
diff options
context:
space:
mode:
Diffstat (limited to 'vp9')
-rw-r--r--vp9/common/vp9_blockd.h4
-rw-r--r--vp9/common/vp9_thread_common.c6
-rw-r--r--vp9/decoder/vp9_decodeframe.c382
-rw-r--r--vp9/encoder/vp9_denoiser.c33
-rw-r--r--vp9/encoder/vp9_denoiser.h5
-rw-r--r--vp9/encoder/vp9_encoder.c4
-rw-r--r--vp9/encoder/vp9_noise_estimate.c4
-rw-r--r--vp9/encoder/vp9_pickmode.c8
-rw-r--r--vp9/encoder/vp9_ratectrl.c92
-rw-r--r--vp9/encoder/vp9_rdopt.c2
-rw-r--r--vp9/encoder/vp9_svc_layercontext.c10
-rw-r--r--vp9/encoder/vp9_svc_layercontext.h4
12 files changed, 483 insertions, 71 deletions
diff --git a/vp9/common/vp9_blockd.h b/vp9/common/vp9_blockd.h
index 65db065a6..f0887157e 100644
--- a/vp9/common/vp9_blockd.h
+++ b/vp9/common/vp9_blockd.h
@@ -131,6 +131,8 @@ struct macroblockd_plane {
// encoder
const int16_t *dequant;
+
+ int *eob;
};
#define BLOCK_OFFSET(x, i) ((x) + (i)*16)
@@ -194,6 +196,8 @@ typedef struct macroblockd {
int corrupted;
struct vpx_internal_error_info *error_info;
+
+ PARTITION_TYPE *partition;
} MACROBLOCKD;
static INLINE PLANE_TYPE get_plane_type(int plane) {
diff --git a/vp9/common/vp9_thread_common.c b/vp9/common/vp9_thread_common.c
index 36530fae6..ba9aa69d0 100644
--- a/vp9/common/vp9_thread_common.c
+++ b/vp9/common/vp9_thread_common.c
@@ -8,6 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
+#include <limits.h>
#include "./vpx_config.h"
#include "vpx_dsp/vpx_dsp_common.h"
#include "vpx_mem/vpx_mem.h"
@@ -402,6 +403,11 @@ static int get_next_row(VP9_COMMON *cm, VP9LfSync *lf_sync) {
pthread_mutex_unlock(&lf_sync->recon_done_mutex[cur_row]);
pthread_mutex_lock(&lf_sync->lf_mutex);
if (lf_sync->corrupted) {
+ int row = return_val >> MI_BLOCK_SIZE_LOG2;
+ pthread_mutex_lock(&lf_sync->mutex[row]);
+ lf_sync->cur_sb_col[row] = INT_MAX;
+ pthread_cond_signal(&lf_sync->cond[row]);
+ pthread_mutex_unlock(&lf_sync->mutex[row]);
return_val = -1;
}
pthread_mutex_unlock(&lf_sync->lf_mutex);
diff --git a/vp9/decoder/vp9_decodeframe.c b/vp9/decoder/vp9_decodeframe.c
index bc0fc6197..c9c85053d 100644
--- a/vp9/decoder/vp9_decodeframe.c
+++ b/vp9/decoder/vp9_decodeframe.c
@@ -45,6 +45,12 @@
#define MAX_VP9_HEADER_SIZE 80
+typedef int (*predict_recon_func)(TileWorkerData *twd, MODE_INFO *const mi,
+ int plane, int row, int col, TX_SIZE tx_size);
+
+typedef void (*intra_recon_func)(TileWorkerData *twd, MODE_INFO *const mi,
+ int plane, int row, int col, TX_SIZE tx_size);
+
static int read_is_valid(const uint8_t *start, size_t len, const uint8_t *end) {
return len != 0 && len <= (size_t)(end - start);
}
@@ -325,6 +331,59 @@ static void predict_and_reconstruct_intra_block(TileWorkerData *twd,
}
}
+static void parse_intra_block_row_mt(TileWorkerData *twd, MODE_INFO *const mi,
+ int plane, int row, int col,
+ TX_SIZE tx_size) {
+ MACROBLOCKD *const xd = &twd->xd;
+ PREDICTION_MODE mode = (plane == 0) ? mi->mode : mi->uv_mode;
+
+ if (mi->sb_type < BLOCK_8X8)
+ if (plane == 0) mode = xd->mi[0]->bmi[(row << 1) + col].as_mode;
+
+ if (!mi->skip) {
+ struct macroblockd_plane *const pd = &xd->plane[plane];
+ const TX_TYPE tx_type =
+ (plane || xd->lossless) ? DCT_DCT : intra_mode_to_tx_type_lookup[mode];
+ const scan_order *sc = (plane || xd->lossless)
+ ? &vp9_default_scan_orders[tx_size]
+ : &vp9_scan_orders[tx_size][tx_type];
+ *pd->eob = vp9_decode_block_tokens(twd, plane, sc, col, row, tx_size,
+ mi->segment_id);
+ /* Keep the alignment to 16 */
+ pd->dqcoeff += (16 << (tx_size << 1));
+ pd->eob++;
+ }
+}
+
+static void predict_and_reconstruct_intra_block_row_mt(TileWorkerData *twd,
+ MODE_INFO *const mi,
+ int plane, int row,
+ int col,
+ TX_SIZE tx_size) {
+ MACROBLOCKD *const xd = &twd->xd;
+ struct macroblockd_plane *const pd = &xd->plane[plane];
+ PREDICTION_MODE mode = (plane == 0) ? mi->mode : mi->uv_mode;
+ uint8_t *dst = &pd->dst.buf[4 * row * pd->dst.stride + 4 * col];
+
+ if (mi->sb_type < BLOCK_8X8)
+ if (plane == 0) mode = xd->mi[0]->bmi[(row << 1) + col].as_mode;
+
+ vp9_predict_intra_block(xd, pd->n4_wl, tx_size, mode, dst, pd->dst.stride,
+ dst, pd->dst.stride, col, row, plane);
+
+ if (!mi->skip) {
+ const TX_TYPE tx_type =
+ (plane || xd->lossless) ? DCT_DCT : intra_mode_to_tx_type_lookup[mode];
+ if (*pd->eob > 0) {
+ inverse_transform_block_intra(xd, plane, tx_type, tx_size, dst,
+ pd->dst.stride, *pd->eob);
+ }
+ /* Keep the alignment to 16 */
+ pd->dqcoeff += (16 << (tx_size << 1));
+ pd->eob++;
+ }
+}
+
static int reconstruct_inter_block(TileWorkerData *twd, MODE_INFO *const mi,
int plane, int row, int col,
TX_SIZE tx_size) {
@@ -342,6 +401,41 @@ static int reconstruct_inter_block(TileWorkerData *twd, MODE_INFO *const mi,
return eob;
}
+static int parse_inter_block_row_mt(TileWorkerData *twd, MODE_INFO *const mi,
+ int plane, int row, int col,
+ TX_SIZE tx_size) {
+ MACROBLOCKD *const xd = &twd->xd;
+ struct macroblockd_plane *const pd = &xd->plane[plane];
+ const scan_order *sc = &vp9_default_scan_orders[tx_size];
+ const int eob = vp9_decode_block_tokens(twd, plane, sc, col, row, tx_size,
+ mi->segment_id);
+
+ *pd->eob = eob;
+ pd->dqcoeff += (16 << (tx_size << 1));
+ pd->eob++;
+
+ return eob;
+}
+
+static int reconstruct_inter_block_row_mt(TileWorkerData *twd,
+ MODE_INFO *const mi, int plane,
+ int row, int col, TX_SIZE tx_size) {
+ MACROBLOCKD *const xd = &twd->xd;
+ struct macroblockd_plane *const pd = &xd->plane[plane];
+ const int eob = *pd->eob;
+
+ (void)mi;
+ if (eob > 0) {
+ inverse_transform_block_inter(
+ xd, plane, tx_size, &pd->dst.buf[4 * row * pd->dst.stride + 4 * col],
+ pd->dst.stride, eob);
+ }
+ pd->dqcoeff += (16 << (tx_size << 1));
+ pd->eob++;
+
+ return eob;
+}
+
static void build_mc_border(const uint8_t *src, int src_stride, uint8_t *dst,
int dst_stride, int x, int y, int b_w, int b_h,
int w, int h) {
@@ -689,6 +783,25 @@ static void set_plane_n4(MACROBLOCKD *const xd, int bw, int bh, int bwl,
}
}
+static MODE_INFO *set_offsets_recon(VP9_COMMON *const cm, MACROBLOCKD *const xd,
+ int mi_row, int mi_col, int bw, int bh,
+ int bwl, int bhl) {
+ const int offset = mi_row * cm->mi_stride + mi_col;
+ const TileInfo *const tile = &xd->tile;
+ xd->mi = cm->mi_grid_visible + offset;
+
+ set_plane_n4(xd, bw, bh, bwl, bhl);
+
+ set_skip_context(xd, mi_row, mi_col);
+
+ // Distance of Mb to the various image edges. These are specified to 8th pel
+ // as they are always compared to values that are in 1/8th pel units
+ set_mi_row_col(xd, tile, mi_row, bh, mi_col, bw, cm->mi_rows, cm->mi_cols);
+
+ vp9_setup_dst_planes(xd->plane, get_frame_new_buffer(cm), mi_row, mi_col);
+ return xd->mi[0];
+}
+
static MODE_INFO *set_offsets(VP9_COMMON *const cm, MACROBLOCKD *const xd,
BLOCK_SIZE bsize, int mi_row, int mi_col, int bw,
int bh, int x_mis, int y_mis, int bwl, int bhl) {
@@ -718,6 +831,66 @@ static MODE_INFO *set_offsets(VP9_COMMON *const cm, MACROBLOCKD *const xd,
return xd->mi[0];
}
+static INLINE int predict_recon_inter(MACROBLOCKD *xd, MODE_INFO *mi,
+ TileWorkerData *twd,
+ predict_recon_func func) {
+ int eobtotal = 0;
+ int plane;
+ for (plane = 0; plane < MAX_MB_PLANE; ++plane) {
+ const struct macroblockd_plane *const pd = &xd->plane[plane];
+ const TX_SIZE tx_size = plane ? get_uv_tx_size(mi, pd) : mi->tx_size;
+ const int num_4x4_w = pd->n4_w;
+ const int num_4x4_h = pd->n4_h;
+ const int step = (1 << tx_size);
+ int row, col;
+ const int max_blocks_wide =
+ num_4x4_w + (xd->mb_to_right_edge >= 0
+ ? 0
+ : xd->mb_to_right_edge >> (5 + pd->subsampling_x));
+ const int max_blocks_high =
+ num_4x4_h + (xd->mb_to_bottom_edge >= 0
+ ? 0
+ : xd->mb_to_bottom_edge >> (5 + pd->subsampling_y));
+
+ xd->max_blocks_wide = xd->mb_to_right_edge >= 0 ? 0 : max_blocks_wide;
+ xd->max_blocks_high = xd->mb_to_bottom_edge >= 0 ? 0 : max_blocks_high;
+
+ for (row = 0; row < max_blocks_high; row += step)
+ for (col = 0; col < max_blocks_wide; col += step)
+ eobtotal += func(twd, mi, plane, row, col, tx_size);
+ }
+ return eobtotal;
+}
+
+static INLINE void predict_recon_intra(MACROBLOCKD *xd, MODE_INFO *mi,
+ TileWorkerData *twd,
+ intra_recon_func func) {
+ int plane;
+ for (plane = 0; plane < MAX_MB_PLANE; ++plane) {
+ const struct macroblockd_plane *const pd = &xd->plane[plane];
+ const TX_SIZE tx_size = plane ? get_uv_tx_size(mi, pd) : mi->tx_size;
+ const int num_4x4_w = pd->n4_w;
+ const int num_4x4_h = pd->n4_h;
+ const int step = (1 << tx_size);
+ int row, col;
+ const int max_blocks_wide =
+ num_4x4_w + (xd->mb_to_right_edge >= 0
+ ? 0
+ : xd->mb_to_right_edge >> (5 + pd->subsampling_x));
+ const int max_blocks_high =
+ num_4x4_h + (xd->mb_to_bottom_edge >= 0
+ ? 0
+ : xd->mb_to_bottom_edge >> (5 + pd->subsampling_y));
+
+ xd->max_blocks_wide = xd->mb_to_right_edge >= 0 ? 0 : max_blocks_wide;
+ xd->max_blocks_high = xd->mb_to_bottom_edge >= 0 ? 0 : max_blocks_high;
+
+ for (row = 0; row < max_blocks_high; row += step)
+ for (col = 0; col < max_blocks_wide; col += step)
+ func(twd, mi, plane, row, col, tx_size);
+ }
+}
+
static void decode_block(TileWorkerData *twd, VP9Decoder *const pbi, int mi_row,
int mi_col, BLOCK_SIZE bsize, int bwl, int bhl) {
VP9_COMMON *const cm = &pbi->common;
@@ -818,6 +991,81 @@ static void decode_block(TileWorkerData *twd, VP9Decoder *const pbi, int mi_row,
}
}
+static void recon_block(TileWorkerData *twd, VP9Decoder *const pbi, int mi_row,
+ int mi_col, BLOCK_SIZE bsize, int bwl, int bhl) {
+ VP9_COMMON *const cm = &pbi->common;
+ const int bw = 1 << (bwl - 1);
+ const int bh = 1 << (bhl - 1);
+ MACROBLOCKD *const xd = &twd->xd;
+
+ MODE_INFO *mi = set_offsets_recon(cm, xd, mi_row, mi_col, bw, bh, bwl, bhl);
+
+ if (bsize >= BLOCK_8X8 && (cm->subsampling_x || cm->subsampling_y)) {
+ const BLOCK_SIZE uv_subsize =
+ ss_size_lookup[bsize][cm->subsampling_x][cm->subsampling_y];
+ if (uv_subsize == BLOCK_INVALID)
+ vpx_internal_error(xd->error_info, VPX_CODEC_CORRUPT_FRAME,
+ "Invalid block size.");
+ }
+
+ if (!is_inter_block(mi)) {
+ predict_recon_intra(xd, mi, twd,
+ predict_and_reconstruct_intra_block_row_mt);
+ } else {
+ // Prediction
+ dec_build_inter_predictors_sb(pbi, xd, mi_row, mi_col);
+
+ // Reconstruction
+ if (!mi->skip) {
+ predict_recon_inter(xd, mi, twd, reconstruct_inter_block_row_mt);
+ }
+ }
+
+ vp9_build_mask(cm, mi, mi_row, mi_col, bw, bh);
+}
+
+static void parse_block(TileWorkerData *twd, VP9Decoder *const pbi, int mi_row,
+ int mi_col, BLOCK_SIZE bsize, int bwl, int bhl) {
+ VP9_COMMON *const cm = &pbi->common;
+ const int less8x8 = bsize < BLOCK_8X8;
+ const int bw = 1 << (bwl - 1);
+ const int bh = 1 << (bhl - 1);
+ const int x_mis = VPXMIN(bw, cm->mi_cols - mi_col);
+ const int y_mis = VPXMIN(bh, cm->mi_rows - mi_row);
+ vpx_reader *r = &twd->bit_reader;
+ MACROBLOCKD *const xd = &twd->xd;
+
+ MODE_INFO *mi = set_offsets(cm, xd, bsize, mi_row, mi_col, bw, bh, x_mis,
+ y_mis, bwl, bhl);
+
+ if (bsize >= BLOCK_8X8 && (cm->subsampling_x || cm->subsampling_y)) {
+ const BLOCK_SIZE uv_subsize =
+ ss_size_lookup[bsize][cm->subsampling_x][cm->subsampling_y];
+ if (uv_subsize == BLOCK_INVALID)
+ vpx_internal_error(xd->error_info, VPX_CODEC_CORRUPT_FRAME,
+ "Invalid block size.");
+ }
+
+ vp9_read_mode_info(twd, pbi, mi_row, mi_col, x_mis, y_mis);
+
+ if (mi->skip) {
+ dec_reset_skip_context(xd);
+ }
+
+ if (!is_inter_block(mi)) {
+ predict_recon_intra(xd, mi, twd, parse_intra_block_row_mt);
+ } else {
+ if (!mi->skip) {
+ const int eobtotal =
+ predict_recon_inter(xd, mi, twd, parse_inter_block_row_mt);
+
+ if (!less8x8 && eobtotal == 0) mi->skip = 1; // skip loopfilter
+ }
+ }
+
+ xd->corrupted |= vpx_reader_has_error(r);
+}
+
static INLINE int dec_partition_plane_context(TileWorkerData *twd, int mi_row,
int mi_col, int bsl) {
const PARTITION_CONTEXT *above_ctx = twd->xd.above_seg_context + mi_col;
@@ -924,6 +1172,118 @@ static void decode_partition(TileWorkerData *twd, VP9Decoder *const pbi,
dec_update_partition_context(twd, mi_row, mi_col, subsize, num_8x8_wh);
}
+static void recon_partition(TileWorkerData *twd, VP9Decoder *const pbi,
+ int mi_row, int mi_col, BLOCK_SIZE bsize,
+ int n4x4_l2) {
+ VP9_COMMON *const cm = &pbi->common;
+ const int n8x8_l2 = n4x4_l2 - 1;
+ const int num_8x8_wh = 1 << n8x8_l2;
+ const int hbs = num_8x8_wh >> 1;
+ PARTITION_TYPE partition;
+ BLOCK_SIZE subsize;
+ const int has_rows = (mi_row + hbs) < cm->mi_rows;
+ const int has_cols = (mi_col + hbs) < cm->mi_cols;
+ MACROBLOCKD *const xd = &twd->xd;
+
+ if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols) return;
+
+ partition = *xd->partition;
+ xd->partition++;
+
+ subsize = get_subsize(bsize, partition);
+ if (!hbs) {
+ // calculate bmode block dimensions (log 2)
+ xd->bmode_blocks_wl = 1 >> !!(partition & PARTITION_VERT);
+ xd->bmode_blocks_hl = 1 >> !!(partition & PARTITION_HORZ);
+ recon_block(twd, pbi, mi_row, mi_col, subsize, 1, 1);
+ } else {
+ switch (partition) {
+ case PARTITION_NONE:
+ recon_block(twd, pbi, mi_row, mi_col, subsize, n4x4_l2, n4x4_l2);
+ break;
+ case PARTITION_HORZ:
+ recon_block(twd, pbi, mi_row, mi_col, subsize, n4x4_l2, n8x8_l2);
+ if (has_rows)
+ recon_block(twd, pbi, mi_row + hbs, mi_col, subsize, n4x4_l2,
+ n8x8_l2);
+ break;
+ case PARTITION_VERT:
+ recon_block(twd, pbi, mi_row, mi_col, subsize, n8x8_l2, n4x4_l2);
+ if (has_cols)
+ recon_block(twd, pbi, mi_row, mi_col + hbs, subsize, n8x8_l2,
+ n4x4_l2);
+ break;
+ case PARTITION_SPLIT:
+ recon_partition(twd, pbi, mi_row, mi_col, subsize, n8x8_l2);
+ recon_partition(twd, pbi, mi_row, mi_col + hbs, subsize, n8x8_l2);
+ recon_partition(twd, pbi, mi_row + hbs, mi_col, subsize, n8x8_l2);
+ recon_partition(twd, pbi, mi_row + hbs, mi_col + hbs, subsize, n8x8_l2);
+ break;
+ default: assert(0 && "Invalid partition type");
+ }
+ }
+}
+
+static void parse_partition(TileWorkerData *twd, VP9Decoder *const pbi,
+ int mi_row, int mi_col, BLOCK_SIZE bsize,
+ int n4x4_l2) {
+ VP9_COMMON *const cm = &pbi->common;
+ const int n8x8_l2 = n4x4_l2 - 1;
+ const int num_8x8_wh = 1 << n8x8_l2;
+ const int hbs = num_8x8_wh >> 1;
+ PARTITION_TYPE partition;
+ BLOCK_SIZE subsize;
+ const int has_rows = (mi_row + hbs) < cm->mi_rows;
+ const int has_cols = (mi_col + hbs) < cm->mi_cols;
+ MACROBLOCKD *const xd = &twd->xd;
+
+ if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols) return;
+
+ *xd->partition =
+ read_partition(twd, mi_row, mi_col, has_rows, has_cols, n8x8_l2);
+
+ partition = *xd->partition;
+ xd->partition++;
+
+ subsize = get_subsize(bsize, partition);
+ if (!hbs) {
+ // calculate bmode block dimensions (log 2)
+ xd->bmode_blocks_wl = 1 >> !!(partition & PARTITION_VERT);
+ xd->bmode_blocks_hl = 1 >> !!(partition & PARTITION_HORZ);
+ parse_block(twd, pbi, mi_row, mi_col, subsize, 1, 1);
+ } else {
+ switch (partition) {
+ case PARTITION_NONE:
+ parse_block(twd, pbi, mi_row, mi_col, subsize, n4x4_l2, n4x4_l2);
+ break;
+ case PARTITION_HORZ:
+ parse_block(twd, pbi, mi_row, mi_col, subsize, n4x4_l2, n8x8_l2);
+ if (has_rows)
+ parse_block(twd, pbi, mi_row + hbs, mi_col, subsize, n4x4_l2,
+ n8x8_l2);
+ break;
+ case PARTITION_VERT:
+ parse_block(twd, pbi, mi_row, mi_col, subsize, n8x8_l2, n4x4_l2);
+ if (has_cols)
+ parse_block(twd, pbi, mi_row, mi_col + hbs, subsize, n8x8_l2,
+ n4x4_l2);
+ break;
+ case PARTITION_SPLIT:
+ parse_partition(twd, pbi, mi_row, mi_col, subsize, n8x8_l2);
+ parse_partition(twd, pbi, mi_row, mi_col + hbs, subsize, n8x8_l2);
+ parse_partition(twd, pbi, mi_row + hbs, mi_col, subsize, n8x8_l2);
+ parse_partition(twd, pbi, mi_row + hbs, mi_col + hbs, subsize, n8x8_l2);
+ break;
+ default: assert(0 && "Invalid partition type");
+ }
+ }
+
+ // update partition context
+ if (bsize >= BLOCK_8X8 &&
+ (bsize == BLOCK_8X8 || partition != PARTITION_SPLIT))
+ dec_update_partition_context(twd, mi_row, mi_col, subsize, num_8x8_wh);
+}
+
static void setup_token_decoder(const uint8_t *data, const uint8_t *data_end,
size_t read_size,
struct vpx_internal_error_info *error_info,
@@ -1406,7 +1766,27 @@ static const uint8_t *decode_tiles(VP9Decoder *pbi, const uint8_t *data,
vp9_zero(tile_data->xd.left_seg_context);
for (mi_col = tile.mi_col_start; mi_col < tile.mi_col_end;
mi_col += MI_BLOCK_SIZE) {
- decode_partition(tile_data, pbi, mi_row, mi_col, BLOCK_64X64, 4);
+ if (pbi->row_mt == 1) {
+ int plane;
+ RowMTWorkerData *const row_mt_worker_data = pbi->row_mt_worker_data;
+ for (plane = 0; plane < MAX_MB_PLANE; ++plane) {
+ tile_data->xd.plane[plane].eob = row_mt_worker_data->eob[plane];
+ tile_data->xd.plane[plane].dqcoeff =
+ row_mt_worker_data->dqcoeff[plane];
+ }
+ tile_data->xd.partition = row_mt_worker_data->partition;
+ parse_partition(tile_data, pbi, mi_row, mi_col, BLOCK_64X64, 4);
+
+ for (plane = 0; plane < MAX_MB_PLANE; ++plane) {
+ tile_data->xd.plane[plane].eob = row_mt_worker_data->eob[plane];
+ tile_data->xd.plane[plane].dqcoeff =
+ row_mt_worker_data->dqcoeff[plane];
+ }
+ tile_data->xd.partition = row_mt_worker_data->partition;
+ recon_partition(tile_data, pbi, mi_row, mi_col, BLOCK_64X64, 4);
+ } else {
+ decode_partition(tile_data, pbi, mi_row, mi_col, BLOCK_64X64, 4);
+ }
}
pbi->mb.corrupted |= tile_data->xd.corrupted;
if (pbi->mb.corrupted)
diff --git a/vp9/encoder/vp9_denoiser.c b/vp9/encoder/vp9_denoiser.c
index b70890e68..2820b71b4 100644
--- a/vp9/encoder/vp9_denoiser.c
+++ b/vp9/encoder/vp9_denoiser.c
@@ -692,6 +692,7 @@ int vp9_denoiser_alloc(VP9_COMMON *cm, struct SVC *svc, VP9_DENOISER *denoiser,
denoiser->denoising_level = kDenLow;
denoiser->prev_denoising_level = kDenLow;
denoiser->reset = 0;
+ denoiser->current_denoiser_frame = 0;
return 0;
}
@@ -716,13 +717,29 @@ void vp9_denoiser_free(VP9_DENOISER *denoiser) {
vpx_free_frame_buffer(&denoiser->last_source);
}
-void vp9_denoiser_set_noise_level(VP9_DENOISER *denoiser, int noise_level) {
+static void force_refresh_longterm_ref(VP9_COMP *const cpi) {
+ SVC *const svc = &cpi->svc;
+ // If long term reference is used, force refresh of that slot, so
+ // denoiser buffer for long term reference stays in sync.
+ if (svc->use_gf_temporal_ref_current_layer) {
+ int index = svc->spatial_layer_id;
+ if (svc->number_spatial_layers == 3) index = svc->spatial_layer_id - 1;
+ assert(index >= 0);
+ cpi->alt_fb_idx = svc->buffer_gf_temporal_ref[index].idx;
+ cpi->refresh_alt_ref_frame = 1;
+ }
+}
+
+void vp9_denoiser_set_noise_level(VP9_COMP *const cpi, int noise_level) {
+ VP9_DENOISER *const denoiser = &cpi->denoiser;
denoiser->denoising_level = noise_level;
if (denoiser->denoising_level > kDenLowLow &&
- denoiser->prev_denoising_level == kDenLowLow)
+ denoiser->prev_denoising_level == kDenLowLow) {
denoiser->reset = 1;
- else
+ force_refresh_longterm_ref(cpi);
+ } else {
denoiser->reset = 0;
+ }
denoiser->prev_denoising_level = denoiser->denoising_level;
}
@@ -754,14 +771,24 @@ int64_t vp9_scale_acskip_thresh(int64_t threshold,
return threshold;
}
+void vp9_denoiser_reset_on_first_frame(VP9_COMP *const cpi) {
+ if (vp9_denoise_svc_non_key(cpi) &&
+ cpi->denoiser.current_denoiser_frame == 0) {
+ cpi->denoiser.reset = 1;
+ force_refresh_longterm_ref(cpi);
+ }
+}
+
void vp9_denoiser_update_ref_frame(VP9_COMP *const cpi) {
VP9_COMMON *const cm = &cpi->common;
SVC *const svc = &cpi->svc;
+
if (cpi->oxcf.noise_sensitivity > 0 && denoise_svc(cpi) &&
cpi->denoiser.denoising_level > kDenLowLow) {
int svc_refresh_denoiser_buffers = 0;
int denoise_svc_second_layer = 0;
FRAME_TYPE frame_type = cm->intra_only ? KEY_FRAME : cm->frame_type;
+ cpi->denoiser.current_denoiser_frame++;
if (cpi->use_svc) {
const int svc_buf_shift =
svc->number_spatial_layers - svc->spatial_layer_id == 2
diff --git a/vp9/encoder/vp9_denoiser.h b/vp9/encoder/vp9_denoiser.h
index 2362c4f50..1973e9898 100644
--- a/vp9/encoder/vp9_denoiser.h
+++ b/vp9/encoder/vp9_denoiser.h
@@ -50,6 +50,7 @@ typedef struct vp9_denoiser {
int reset;
int num_ref_frames;
int num_layers;
+ unsigned int current_denoiser_frame;
VP9_DENOISER_LEVEL denoising_level;
VP9_DENOISER_LEVEL prev_denoising_level;
} VP9_DENOISER;
@@ -111,7 +112,9 @@ static INLINE int total_adj_strong_thresh(BLOCK_SIZE bs,
void vp9_denoiser_free(VP9_DENOISER *denoiser);
-void vp9_denoiser_set_noise_level(VP9_DENOISER *denoiser, int noise_level);
+void vp9_denoiser_set_noise_level(struct VP9_COMP *const cpi, int noise_level);
+
+void vp9_denoiser_reset_on_first_frame(struct VP9_COMP *const cpi);
int64_t vp9_scale_part_thresh(int64_t threshold, VP9_DENOISER_LEVEL noise_level,
int content_state, int temporal_layer_id);
diff --git a/vp9/encoder/vp9_encoder.c b/vp9/encoder/vp9_encoder.c
index 746f234e2..a73185623 100644
--- a/vp9/encoder/vp9_encoder.c
+++ b/vp9/encoder/vp9_encoder.c
@@ -3815,6 +3815,10 @@ static int encode_without_recode_loop(VP9_COMP *cpi, size_t *size,
cm->mi_rows * cm->mi_cols * sizeof(*cpi->consec_zero_mv));
}
+#if CONFIG_VP9_TEMPORAL_DENOISING
+ if (cpi->oxcf.noise_sensitivity > 0 && cpi->use_svc)
+ vp9_denoiser_reset_on_first_frame(cpi);
+#endif
vp9_update_noise_estimate(cpi);
// Scene detection is always used for VBR mode or screen-content case.
diff --git a/vp9/encoder/vp9_noise_estimate.c b/vp9/encoder/vp9_noise_estimate.c
index 8c9a40f55..fc189dbb1 100644
--- a/vp9/encoder/vp9_noise_estimate.c
+++ b/vp9/encoder/vp9_noise_estimate.c
@@ -159,7 +159,7 @@ void vp9_update_noise_estimate(VP9_COMP *const cpi) {
#if CONFIG_VP9_TEMPORAL_DENOISING
if (cpi->oxcf.noise_sensitivity > 0 && noise_est_svc(cpi) &&
cpi->svc.current_superframe > 1) {
- vp9_denoiser_set_noise_level(&cpi->denoiser, ne->level);
+ vp9_denoiser_set_noise_level(cpi, ne->level);
copy_frame(&cpi->denoiser.last_source, cpi->Source);
}
#endif
@@ -269,7 +269,7 @@ void vp9_update_noise_estimate(VP9_COMP *const cpi) {
ne->level = vp9_noise_estimate_extract_level(ne);
#if CONFIG_VP9_TEMPORAL_DENOISING
if (cpi->oxcf.noise_sensitivity > 0 && noise_est_svc(cpi))
- vp9_denoiser_set_noise_level(&cpi->denoiser, ne->level);
+ vp9_denoiser_set_noise_level(cpi, ne->level);
#endif
}
}
diff --git a/vp9/encoder/vp9_pickmode.c b/vp9/encoder/vp9_pickmode.c
index 1324b5bc8..fe8f24444 100644
--- a/vp9/encoder/vp9_pickmode.c
+++ b/vp9/encoder/vp9_pickmode.c
@@ -1815,13 +1815,7 @@ void vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x, TileDataEnc *tile_data,
#if CONFIG_VP9_TEMPORAL_DENOISING
if (cpi->oxcf.noise_sensitivity > 0) {
- if (cpi->use_svc) {
- int layer =
- LAYER_IDS_TO_IDX(svc->spatial_layer_id, svc->temporal_layer_id,
- svc->number_temporal_layers);
- LAYER_CONTEXT *lc = &svc->layer_context[layer];
- denoise_svc_pickmode = denoise_svc(cpi) && !lc->is_key_frame;
- }
+ if (cpi->use_svc) denoise_svc_pickmode = vp9_denoise_svc_non_key(cpi);
if (cpi->denoiser.denoising_level > kDenLowLow && denoise_svc_pickmode)
vp9_denoiser_reset_frame_stats(ctx);
}
diff --git a/vp9/encoder/vp9_ratectrl.c b/vp9/encoder/vp9_ratectrl.c
index ac8fda496..b5c002aea 100644
--- a/vp9/encoder/vp9_ratectrl.c
+++ b/vp9/encoder/vp9_ratectrl.c
@@ -570,10 +570,25 @@ int post_encode_drop_cbr(VP9_COMP *cpi, size_t *size) {
cpi->last_frame_dropped = 1;
cpi->ext_refresh_frame_flags_pending = 0;
if (cpi->use_svc) {
- cpi->svc.last_layer_dropped[cpi->svc.spatial_layer_id] = 1;
- cpi->svc.drop_spatial_layer[cpi->svc.spatial_layer_id] = 1;
- cpi->svc.drop_count[cpi->svc.spatial_layer_id]++;
- cpi->svc.skip_enhancement_layer = 1;
+ SVC *svc = &cpi->svc;
+ int sl = 0;
+ int tl = 0;
+ svc->last_layer_dropped[svc->spatial_layer_id] = 1;
+ svc->drop_spatial_layer[svc->spatial_layer_id] = 1;
+ svc->drop_count[svc->spatial_layer_id]++;
+ svc->skip_enhancement_layer = 1;
+ // Postencode drop is only checked on base spatial layer,
+ // for now if max-q is set on base we force it on all layers.
+ for (sl = 0; sl < svc->number_spatial_layers; ++sl) {
+ for (tl = 0; tl < svc->number_temporal_layers; ++tl) {
+ const int layer =
+ LAYER_IDS_TO_IDX(sl, tl, svc->number_temporal_layers);
+ LAYER_CONTEXT *lc = &svc->layer_context[layer];
+ RATE_CONTROL *lrc = &lc->rc;
+ lrc->force_max_q = 1;
+ lrc->avg_frame_qindex[INTER_FRAME] = cpi->rc.worst_quality;
+ }
+ }
}
return 1;
}
@@ -1394,16 +1409,7 @@ static int rc_pick_q_and_bounds_two_pass(const VP9_COMP *cpi, int *bottom_index,
return rc_constant_q(cpi, bottom_index, top_index, gf_group_index);
if (frame_is_intra_only(cm)) {
- if (rc->frames_to_key == 1 && oxcf->rc_mode == VPX_Q) {
- // If the next frame is also a key frame or the current frame is the
- // only frame in the sequence in AOM_Q mode, just use the cq_level
- // as q.
- active_best_quality = cq_level;
- active_worst_quality = cq_level;
- } else {
- pick_kf_q_bound_two_pass(cpi, &active_best_quality,
- &active_worst_quality);
- }
+ pick_kf_q_bound_two_pass(cpi, &active_best_quality, &active_worst_quality);
} else if (!rc->is_src_frame_alt_ref &&
(cpi->refresh_golden_frame || cpi->refresh_alt_ref_frame)) {
// Use the lower of active_worst_quality and recent
@@ -1434,54 +1440,31 @@ static int rc_pick_q_and_bounds_two_pass(const VP9_COMP *cpi, int *bottom_index,
((layer_depth - 1) * q + active_best_quality + layer_depth / 2) /
layer_depth;
}
- } else if (oxcf->rc_mode == VPX_Q) {
- if (!cpi->refresh_alt_ref_frame) {
- active_best_quality = cq_level;
- } else {
- active_best_quality = get_gf_active_quality(cpi, q, cm->bit_depth);
-
- // Modify best quality for second level arfs. For mode VPX_Q this
- // becomes the baseline frame q.
- if (gf_group->rf_level[gf_group_index] == GF_ARF_LOW) {
- const int layer_depth = gf_group->layer_depth[gf_group_index];
- // linearly fit the frame q depending on the layer depth index from
- // the base layer ARF.
- active_best_quality = ((layer_depth - 1) * cq_level +
- active_best_quality + layer_depth / 2) /
- layer_depth;
- }
- }
} else {
active_best_quality = get_gf_active_quality(cpi, q, cm->bit_depth);
}
} else {
- if (oxcf->rc_mode == VPX_Q) {
- active_best_quality = cq_level;
- } else {
- active_best_quality = inter_minq[active_worst_quality];
+ active_best_quality = inter_minq[active_worst_quality];
- // For the constrained quality mode we don't want
- // q to fall below the cq level.
- if ((oxcf->rc_mode == VPX_CQ) && (active_best_quality < cq_level)) {
- active_best_quality = cq_level;
- }
+ // For the constrained quality mode we don't want
+ // q to fall below the cq level.
+ if ((oxcf->rc_mode == VPX_CQ) && (active_best_quality < cq_level)) {
+ active_best_quality = cq_level;
}
}
// Extension to max or min Q if undershoot or overshoot is outside
// the permitted range.
- if (cpi->oxcf.rc_mode != VPX_Q) {
- if (frame_is_intra_only(cm) ||
- (!rc->is_src_frame_alt_ref &&
- (cpi->refresh_golden_frame || cpi->refresh_alt_ref_frame))) {
- active_best_quality -=
- (cpi->twopass.extend_minq + cpi->twopass.extend_minq_fast);
- active_worst_quality += (cpi->twopass.extend_maxq / 2);
- } else {
- active_best_quality -=
- (cpi->twopass.extend_minq + cpi->twopass.extend_minq_fast) / 2;
- active_worst_quality += cpi->twopass.extend_maxq;
- }
+ if (frame_is_intra_only(cm) ||
+ (!rc->is_src_frame_alt_ref &&
+ (cpi->refresh_golden_frame || cpi->refresh_alt_ref_frame))) {
+ active_best_quality -=
+ (cpi->twopass.extend_minq + cpi->twopass.extend_minq_fast);
+ active_worst_quality += (cpi->twopass.extend_maxq / 2);
+ } else {
+ active_best_quality -=
+ (cpi->twopass.extend_minq + cpi->twopass.extend_minq_fast) / 2;
+ active_worst_quality += cpi->twopass.extend_maxq;
}
// For normal frames do not allow an active minq lower than the q used for
@@ -1517,10 +1500,7 @@ static int rc_pick_q_and_bounds_two_pass(const VP9_COMP *cpi, int *bottom_index,
active_worst_quality =
clamp(active_worst_quality, active_best_quality, rc->worst_quality);
- if (oxcf->rc_mode == VPX_Q) {
- q = active_best_quality;
- // Special case code to try and match quality with forced key frames.
- } else if (frame_is_intra_only(cm) && rc->this_key_frame_forced) {
+ if (frame_is_intra_only(cm) && rc->this_key_frame_forced) {
// If static since last kf use better of last boosted and last kf q.
if (cpi->twopass.last_kfgroup_zeromotion_pct >= STATIC_MOTION_THRESH) {
q = VPXMIN(rc->last_kf_qindex, rc->last_boosted_qindex);
diff --git a/vp9/encoder/vp9_rdopt.c b/vp9/encoder/vp9_rdopt.c
index 2e1aa1d30..b55e2ddb4 100644
--- a/vp9/encoder/vp9_rdopt.c
+++ b/vp9/encoder/vp9_rdopt.c
@@ -2461,7 +2461,7 @@ static void single_motion_search(VP9_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bsize,
#if CONFIG_NON_GREEDY_MV
this_me = vp9_full_pixel_diamond_new(
cpi, x, &mvp_full, VPXMAX(step_param, MAX_MVSEARCH_STEPS - step),
- lambda, 1, &cpi->fn_ptr[bsize], nb_full_mvs, &tmp_mv->as_mv, &mv_dist,
+ lambda, 1, &cpi->fn_ptr[bsize], nb_full_mvs, &this_mv, &mv_dist,
&mv_cost);
#else // CONFIG_NON_GREEDY_MV
this_me = vp9_full_pixel_search(
diff --git a/vp9/encoder/vp9_svc_layercontext.c b/vp9/encoder/vp9_svc_layercontext.c
index 21b920f11..510087580 100644
--- a/vp9/encoder/vp9_svc_layercontext.c
+++ b/vp9/encoder/vp9_svc_layercontext.c
@@ -1106,6 +1106,16 @@ void vp9_svc_assert_constraints_pattern(VP9_COMP *const cpi) {
}
}
+#if CONFIG_VP9_TEMPORAL_DENOISING
+int vp9_denoise_svc_non_key(VP9_COMP *const cpi) {
+ int layer =
+ LAYER_IDS_TO_IDX(cpi->svc.spatial_layer_id, cpi->svc.temporal_layer_id,
+ cpi->svc.number_temporal_layers);
+ LAYER_CONTEXT *lc = &cpi->svc.layer_context[layer];
+ return denoise_svc(cpi) && !lc->is_key_frame;
+}
+#endif
+
void vp9_svc_check_spatial_layer_sync(VP9_COMP *const cpi) {
SVC *const svc = &cpi->svc;
// Only for superframes whose base is not key, as those are
diff --git a/vp9/encoder/vp9_svc_layercontext.h b/vp9/encoder/vp9_svc_layercontext.h
index 945312044..f1f2457b2 100644
--- a/vp9/encoder/vp9_svc_layercontext.h
+++ b/vp9/encoder/vp9_svc_layercontext.h
@@ -235,6 +235,10 @@ struct lookahead_entry *vp9_svc_lookahead_pop(struct VP9_COMP *const cpi,
// Start a frame and initialize svc parameters
int vp9_svc_start_frame(struct VP9_COMP *const cpi);
+#if CONFIG_VP9_TEMPORAL_DENOISING
+int vp9_denoise_svc_non_key(struct VP9_COMP *const cpi);
+#endif
+
void vp9_copy_flags_ref_update_idx(struct VP9_COMP *const cpi);
int vp9_one_pass_cbr_svc_start_layer(struct VP9_COMP *const cpi);