Reland "Add ROI support for VP9."
Extended ROI struct suitable for VP9. ROI input from user is passed into internal struct and applied on every frame (except key frame). Enabled usage of all 4 VP9 segment features (delta_qp, delta_lf, skip, ref_frame) via the ROI map input. Made changes to nonrd_pickmode for the ref_frame feature. Only works for realtime speed >= 5. AQ_MODE needs to be turned off for ROI to take effect. Change example in the sample encoder: vpx_temporal_svc_encoder.c to be suitable for VP9. Add datarate test. Bump up ABI version. BUG=webm:1470 Change-Id: I663b8c89862328646f4cc6119752b66efc5dc9ac
This commit is contained in:
parent
0fe4371cc0
commit
46adbc4af8
@ -26,7 +26,9 @@
|
||||
#include "../tools_common.h"
|
||||
#include "../video_writer.h"
|
||||
|
||||
#define VP8_ROI_MAP 0
|
||||
#define ROI_MAP 0
|
||||
|
||||
#define zero(Dest) memset(&Dest, 0, sizeof(Dest));
|
||||
|
||||
static const char *exec_name;
|
||||
|
||||
@ -165,38 +167,60 @@ static void printout_rate_control_summary(struct RateControlMetrics *rc,
|
||||
die("Error: Number of input frames not equal to output! \n");
|
||||
}
|
||||
|
||||
#if VP8_ROI_MAP
|
||||
static void vp8_set_roi_map(vpx_codec_enc_cfg_t *cfg, vpx_roi_map_t *roi) {
|
||||
#if ROI_MAP
|
||||
static void set_roi_map(const char *enc_name, vpx_codec_enc_cfg_t *cfg,
|
||||
vpx_roi_map_t *roi) {
|
||||
unsigned int i, j;
|
||||
memset(roi, 0, sizeof(*roi));
|
||||
int block_size = 0;
|
||||
uint8_t is_vp8 = strncmp(enc_name, "vp8", 3) == 0 ? 1 : 0;
|
||||
uint8_t is_vp9 = strncmp(enc_name, "vp9", 3) == 0 ? 1 : 0;
|
||||
if (!is_vp8 && !is_vp9) {
|
||||
die("unsupported codec.");
|
||||
}
|
||||
zero(*roi);
|
||||
|
||||
block_size = is_vp9 && !is_vp8 ? 16 : 8;
|
||||
|
||||
// ROI is based on the segments (4 for vp8, 8 for vp9), smallest unit for
|
||||
// segment is 16x16 for vp8, 8x8 for vp9.
|
||||
roi->rows = (cfg->g_h + 15) / 16;
|
||||
roi->cols = (cfg->g_w + 15) / 16;
|
||||
roi->rows = (cfg->g_h + block_size - 1) / block_size;
|
||||
roi->cols = (cfg->g_w + block_size - 1) / block_size;
|
||||
|
||||
// Applies delta QP on the segment blocks, varies from -63 to 63.
|
||||
// Setting to negative means lower QP (better quality).
|
||||
// Below we set delta_q to the extreme (-63) to show strong effect.
|
||||
roi->delta_q[0] = 0;
|
||||
// VP8 uses the first 4 segments. VP9 uses all 8 segments.
|
||||
zero(roi->delta_qp);
|
||||
roi->delta_q[1] = -63;
|
||||
roi->delta_q[2] = 0;
|
||||
roi->delta_q[3] = 0;
|
||||
|
||||
// Applies delta loopfilter strength on the segment blocks, varies from -63 to
|
||||
// 63. Setting to positive means stronger loopfilter.
|
||||
roi->delta_lf[0] = 0;
|
||||
roi->delta_lf[1] = 0;
|
||||
roi->delta_lf[2] = 0;
|
||||
roi->delta_lf[3] = 0;
|
||||
// 63. Setting to positive means stronger loopfilter. VP8 uses the first 4
|
||||
// segments. VP9 uses all 8 segments.
|
||||
zero(roi->delta_lf);
|
||||
|
||||
// Applies skip encoding threshold on the segment blocks, varies from 0 to
|
||||
// UINT_MAX. Larger value means more skipping of encoding is possible.
|
||||
// This skip threshold only applies on delta frames.
|
||||
roi->static_threshold[0] = 0;
|
||||
roi->static_threshold[1] = 0;
|
||||
roi->static_threshold[2] = 0;
|
||||
roi->static_threshold[3] = 0;
|
||||
if (is_vp8) {
|
||||
// Applies skip encoding threshold on the segment blocks, varies from 0 to
|
||||
// UINT_MAX. Larger value means more skipping of encoding is possible.
|
||||
// This skip threshold only applies on delta frames.
|
||||
zero(roi->static_threshold);
|
||||
}
|
||||
|
||||
if (is_vp9) {
|
||||
// Apply skip segment. Setting to 1 means this block will be copied from
|
||||
// previous frame.
|
||||
zero(roi->skip);
|
||||
}
|
||||
|
||||
if (is_vp9) {
|
||||
// Apply ref frame segment.
|
||||
// -1 : Do not apply this segment.
|
||||
// 0 : Froce using intra.
|
||||
// 1 : Force using last.
|
||||
// 2 : Force using golden.
|
||||
// 3 : Force using alfref but not used in non-rd pickmode for 0 lag.
|
||||
memset(roi->ref_frame, -1, sizeof(roi->ref_frame));
|
||||
roi->ref_frame[1] = 1;
|
||||
}
|
||||
|
||||
// Use 2 states: 1 is center square, 0 is the rest.
|
||||
roi->roi_map =
|
||||
@ -564,7 +588,7 @@ int main(int argc, char **argv) {
|
||||
int layering_mode = 0;
|
||||
int layer_flags[VPX_TS_MAX_PERIODICITY] = { 0 };
|
||||
int flag_periodicity = 1;
|
||||
#if VP8_ROI_MAP
|
||||
#if ROI_MAP
|
||||
vpx_roi_map_t roi;
|
||||
#endif
|
||||
vpx_svc_layer_id_t layer_id = { 0, 0 };
|
||||
@ -767,8 +791,8 @@ int main(int argc, char **argv) {
|
||||
vpx_codec_control(&codec, VP8E_SET_NOISE_SENSITIVITY, kVp8DenoiserOff);
|
||||
vpx_codec_control(&codec, VP8E_SET_STATIC_THRESHOLD, 1);
|
||||
vpx_codec_control(&codec, VP8E_SET_GF_CBR_BOOST_PCT, 0);
|
||||
#if VP8_ROI_MAP
|
||||
vp8_set_roi_map(&cfg, &roi);
|
||||
#if ROI_MAP
|
||||
set_roi_map(&cfg, &roi, encoder);
|
||||
if (vpx_codec_control(&codec, VP8E_SET_ROI_MAP, &roi))
|
||||
die_codec(&codec, "Failed to set ROI map");
|
||||
#endif
|
||||
@ -785,6 +809,12 @@ int main(int argc, char **argv) {
|
||||
vpx_codec_control(&codec, VP8E_SET_STATIC_THRESHOLD, 1);
|
||||
vpx_codec_control(&codec, VP9E_SET_TUNE_CONTENT, 0);
|
||||
vpx_codec_control(&codec, VP9E_SET_TILE_COLUMNS, (cfg.g_threads >> 1));
|
||||
#if ROI_MAP
|
||||
set_roi_map(&cfg, &roi, encoder);
|
||||
if (vpx_codec_control(&codec, VP9E_SET_ROI_MAP, &roi))
|
||||
die_codec(&codec, "Failed to set ROI map");
|
||||
vpx_codec_control(&codec, VP9E_SET_AQ_MODE, 0);
|
||||
#endif
|
||||
// TODO(marpan/jianj): There is an issue with row-mt for low resolutons at
|
||||
// high speed settings, disable its use for those cases for now.
|
||||
if (cfg.g_threads > 1 && ((cfg.g_w > 320 && cfg.g_h > 240) || speed < 7))
|
||||
@ -912,5 +942,8 @@ int main(int argc, char **argv) {
|
||||
for (i = 0; i < cfg.ts_number_layers; ++i) vpx_video_writer_close(outfile[i]);
|
||||
|
||||
vpx_img_free(&raw);
|
||||
#if ROI_MAP
|
||||
free(roi.roi_map);
|
||||
#endif
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
@ -621,6 +621,10 @@ class DatarateTestVP9Large
|
||||
encoder->Control(VP9E_SET_FRAME_PARALLEL_DECODING,
|
||||
frame_parallel_decoding_mode_);
|
||||
|
||||
if (use_roi_) {
|
||||
encoder->Control(VP9E_SET_ROI_MAP, &roi_);
|
||||
}
|
||||
|
||||
if (cfg_.ts_number_layers > 1) {
|
||||
if (video->frame() == 0) {
|
||||
encoder->Control(VP9E_SET_SVC, 1);
|
||||
@ -701,6 +705,8 @@ class DatarateTestVP9Large
|
||||
int denoiser_offon_test_;
|
||||
int denoiser_offon_period_;
|
||||
int frame_parallel_decoding_mode_;
|
||||
bool use_roi_;
|
||||
vpx_roi_map_t roi_;
|
||||
};
|
||||
|
||||
// Check basic rate targeting for VBR mode with 0 lag.
|
||||
@ -1073,6 +1079,68 @@ TEST_P(DatarateTestVP9Large, BasicRateTargeting3TemporalLayersFrameDropping) {
|
||||
}
|
||||
}
|
||||
|
||||
class DatarateTestVP9RealTime : public DatarateTestVP9Large {
|
||||
public:
|
||||
virtual ~DatarateTestVP9RealTime() {}
|
||||
};
|
||||
|
||||
// Check VP9 region of interest feature.
|
||||
TEST_P(DatarateTestVP9RealTime, RegionOfInterest) {
|
||||
if (deadline_ != VPX_DL_REALTIME || set_cpu_used_ < 5) return;
|
||||
cfg_.rc_buf_initial_sz = 500;
|
||||
cfg_.rc_buf_optimal_sz = 500;
|
||||
cfg_.rc_buf_sz = 1000;
|
||||
cfg_.rc_dropframe_thresh = 0;
|
||||
cfg_.rc_min_quantizer = 0;
|
||||
cfg_.rc_max_quantizer = 63;
|
||||
cfg_.rc_end_usage = VPX_CBR;
|
||||
cfg_.g_lag_in_frames = 0;
|
||||
|
||||
::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
|
||||
30, 1, 0, 300);
|
||||
|
||||
cfg_.rc_target_bitrate = 450;
|
||||
cfg_.g_w = 352;
|
||||
cfg_.g_h = 288;
|
||||
|
||||
ResetModel();
|
||||
|
||||
// Set ROI parameters
|
||||
use_roi_ = true;
|
||||
memset(&roi_, 0, sizeof(roi_));
|
||||
|
||||
roi_.rows = (cfg_.g_h + 7) / 8;
|
||||
roi_.cols = (cfg_.g_w + 7) / 8;
|
||||
|
||||
roi_.delta_q[1] = -20;
|
||||
roi_.delta_lf[1] = -20;
|
||||
memset(roi_.ref_frame, -1, sizeof(roi_.ref_frame));
|
||||
roi_.ref_frame[1] = 1;
|
||||
|
||||
// Use 2 states: 1 is center square, 0 is the rest.
|
||||
roi_.roi_map = reinterpret_cast<uint8_t *>(
|
||||
calloc(roi_.rows * roi_.cols, sizeof(*roi_.roi_map)));
|
||||
ASSERT_TRUE(roi_.roi_map != NULL);
|
||||
|
||||
for (unsigned int i = 0; i < roi_.rows; ++i) {
|
||||
for (unsigned int j = 0; j < roi_.cols; ++j) {
|
||||
if (i > (roi_.rows >> 2) && i < ((roi_.rows * 3) >> 2) &&
|
||||
j > (roi_.cols >> 2) && j < ((roi_.cols * 3) >> 2)) {
|
||||
roi_.roi_map[i * roi_.cols + j] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
|
||||
ASSERT_GE(cfg_.rc_target_bitrate, effective_datarate_[0] * 0.90)
|
||||
<< " The datarate for the file exceeds the target!";
|
||||
|
||||
ASSERT_LE(cfg_.rc_target_bitrate, effective_datarate_[0] * 1.4)
|
||||
<< " The datarate for the file missed the target!";
|
||||
|
||||
free(roi_.roi_map);
|
||||
}
|
||||
|
||||
#if CONFIG_VP9_TEMPORAL_DENOISING
|
||||
class DatarateTestVP9LargeDenoiser : public DatarateTestVP9Large {
|
||||
public:
|
||||
@ -2083,6 +2151,9 @@ VP9_INSTANTIATE_TEST_CASE(DatarateTestVP9Large,
|
||||
::testing::Values(::libvpx_test::kOnePassGood,
|
||||
::libvpx_test::kRealTime),
|
||||
::testing::Range(2, 9));
|
||||
VP9_INSTANTIATE_TEST_CASE(DatarateTestVP9RealTime,
|
||||
::testing::Values(::libvpx_test::kRealTime),
|
||||
::testing::Range(5, 9));
|
||||
#if CONFIG_VP9_TEMPORAL_DENOISING
|
||||
VP9_INSTANTIATE_TEST_CASE(DatarateTestVP9LargeDenoiser,
|
||||
::testing::Values(::libvpx_test::kRealTime),
|
||||
|
@ -142,15 +142,12 @@ class Encoder {
|
||||
const vpx_codec_err_t res = vpx_codec_control_(&encoder_, ctrl_id, arg);
|
||||
ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CONFIG_VP8_ENCODER
|
||||
void Control(int ctrl_id, vpx_roi_map_t *arg) {
|
||||
const vpx_codec_err_t res = vpx_codec_control_(&encoder_, ctrl_id, arg);
|
||||
ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
|
||||
}
|
||||
#endif
|
||||
|
||||
void Config(const vpx_codec_enc_cfg_t *cfg) {
|
||||
const vpx_codec_err_t res = vpx_codec_enc_config_set(&encoder_, cfg);
|
||||
ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
|
||||
|
@ -547,6 +547,74 @@ static void apply_active_map(VP9_COMP *cpi) {
|
||||
}
|
||||
}
|
||||
|
||||
static void apply_roi_map(VP9_COMP *cpi) {
|
||||
VP9_COMMON *cm = &cpi->common;
|
||||
struct segmentation *const seg = &cm->seg;
|
||||
vpx_roi_map_t *roi = &cpi->roi;
|
||||
const int *delta_q = roi->delta_q;
|
||||
const int *delta_lf = roi->delta_lf;
|
||||
const int *skip = roi->skip;
|
||||
int ref_frame[8];
|
||||
int internal_delta_q[MAX_SEGMENTS];
|
||||
int i;
|
||||
static const int flag_list[4] = { 0, VP9_LAST_FLAG, VP9_GOLD_FLAG,
|
||||
VP9_ALT_FLAG };
|
||||
|
||||
// TODO(jianj): Investigate why ROI not working in speed < 5 or in non
|
||||
// realtime mode.
|
||||
if (cpi->oxcf.mode != REALTIME || cpi->oxcf.speed < 5) return;
|
||||
if (!roi->enabled) return;
|
||||
|
||||
memcpy(&ref_frame, roi->ref_frame, sizeof(ref_frame));
|
||||
|
||||
vp9_enable_segmentation(seg);
|
||||
vp9_clearall_segfeatures(seg);
|
||||
// Select delta coding method;
|
||||
seg->abs_delta = SEGMENT_DELTADATA;
|
||||
|
||||
memcpy(cpi->segmentation_map, roi->roi_map, (cm->mi_rows * cm->mi_cols));
|
||||
|
||||
for (i = 0; i < MAX_SEGMENTS; ++i) {
|
||||
// Translate the external delta q values to internal values.
|
||||
internal_delta_q[i] = vp9_quantizer_to_qindex(abs(delta_q[i]));
|
||||
if (delta_q[i] < 0) internal_delta_q[i] = -internal_delta_q[i];
|
||||
vp9_disable_segfeature(seg, i, SEG_LVL_ALT_Q);
|
||||
vp9_disable_segfeature(seg, i, SEG_LVL_ALT_LF);
|
||||
if (internal_delta_q[i] != 0) {
|
||||
vp9_enable_segfeature(seg, i, SEG_LVL_ALT_Q);
|
||||
vp9_set_segdata(seg, i, SEG_LVL_ALT_Q, internal_delta_q[i]);
|
||||
}
|
||||
if (delta_lf[i] != 0) {
|
||||
vp9_enable_segfeature(seg, i, SEG_LVL_ALT_LF);
|
||||
vp9_set_segdata(seg, i, SEG_LVL_ALT_LF, delta_lf[i]);
|
||||
}
|
||||
if (skip[i] != 0) {
|
||||
vp9_enable_segfeature(seg, i, SEG_LVL_SKIP);
|
||||
vp9_set_segdata(seg, i, SEG_LVL_SKIP, skip[i]);
|
||||
}
|
||||
if (ref_frame[i] >= 0) {
|
||||
int valid_ref = 1;
|
||||
// ALTREF is not used as reference for nonrd_pickmode with 0 lag.
|
||||
if (ref_frame[i] == ALTREF_FRAME && cpi->sf.use_nonrd_pick_mode)
|
||||
valid_ref = 0;
|
||||
// If GOLDEN is selected, make sure it's set as reference.
|
||||
if (ref_frame[i] == GOLDEN_FRAME &&
|
||||
!(cpi->ref_frame_flags & flag_list[ref_frame[i]])) {
|
||||
valid_ref = 0;
|
||||
}
|
||||
// GOLDEN was updated in previous encoded frame, so GOLDEN and LAST are
|
||||
// same reference.
|
||||
if (ref_frame[i] == GOLDEN_FRAME && cpi->rc.frames_since_golden == 0)
|
||||
ref_frame[i] = LAST_FRAME;
|
||||
if (valid_ref) {
|
||||
vp9_enable_segfeature(seg, i, SEG_LVL_REF_FRAME);
|
||||
vp9_set_segdata(seg, i, SEG_LVL_REF_FRAME, ref_frame[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
roi->enabled = 1;
|
||||
}
|
||||
|
||||
static void init_level_info(Vp9LevelInfo *level_info) {
|
||||
Vp9LevelStats *const level_stats = &level_info->level_stats;
|
||||
Vp9LevelSpec *const level_spec = &level_info->level_spec;
|
||||
@ -557,6 +625,13 @@ static void init_level_info(Vp9LevelInfo *level_info) {
|
||||
level_spec->min_altref_distance = INT_MAX;
|
||||
}
|
||||
|
||||
static int check_seg_range(int seg_data[8], int range) {
|
||||
return !(abs(seg_data[0]) > range || abs(seg_data[1]) > range ||
|
||||
abs(seg_data[2]) > range || abs(seg_data[3]) > range ||
|
||||
abs(seg_data[4]) > range || abs(seg_data[5]) > range ||
|
||||
abs(seg_data[6]) > range || abs(seg_data[7]) > range);
|
||||
}
|
||||
|
||||
VP9_LEVEL vp9_get_level(const Vp9LevelSpec *const level_spec) {
|
||||
int i;
|
||||
const Vp9LevelSpec *this_level;
|
||||
@ -583,6 +658,61 @@ VP9_LEVEL vp9_get_level(const Vp9LevelSpec *const level_spec) {
|
||||
return (i == VP9_LEVELS) ? LEVEL_UNKNOWN : vp9_level_defs[i].level;
|
||||
}
|
||||
|
||||
int vp9_set_roi_map(VP9_COMP *cpi, unsigned char *map, unsigned int rows,
|
||||
unsigned int cols, int delta_q[8], int delta_lf[8],
|
||||
int skip[8], int ref_frame[8]) {
|
||||
VP9_COMMON *cm = &cpi->common;
|
||||
vpx_roi_map_t *roi = &cpi->roi;
|
||||
const int range = 63;
|
||||
const int ref_frame_range = 3; // Alt-ref
|
||||
const int skip_range = 1;
|
||||
const int frame_rows = cpi->common.mi_rows;
|
||||
const int frame_cols = cpi->common.mi_cols;
|
||||
|
||||
// Check number of rows and columns match
|
||||
if (frame_rows != (int)rows || frame_cols != (int)cols) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!check_seg_range(delta_q, range) || !check_seg_range(delta_lf, range) ||
|
||||
!check_seg_range(ref_frame, ref_frame_range) ||
|
||||
!check_seg_range(skip, skip_range))
|
||||
return -1;
|
||||
|
||||
// Also disable segmentation if no deltas are specified.
|
||||
if (!map ||
|
||||
(!(delta_q[0] | delta_q[1] | delta_q[2] | delta_q[3] | delta_q[4] |
|
||||
delta_q[5] | delta_q[6] | delta_q[7] | delta_lf[0] | delta_lf[1] |
|
||||
delta_lf[2] | delta_lf[3] | delta_lf[4] | delta_lf[5] | delta_lf[6] |
|
||||
delta_lf[7] | skip[0] | skip[1] | skip[2] | skip[3] | skip[4] |
|
||||
skip[5] | skip[6] | skip[7]) &&
|
||||
(ref_frame[0] == -1 && ref_frame[1] == -1 && ref_frame[2] == -1 &&
|
||||
ref_frame[3] == -1 && ref_frame[4] == -1 && ref_frame[5] == -1 &&
|
||||
ref_frame[6] == -1 && ref_frame[7] == -1))) {
|
||||
vp9_disable_segmentation(&cm->seg);
|
||||
cpi->roi.enabled = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (roi->roi_map) {
|
||||
vpx_free(roi->roi_map);
|
||||
roi->roi_map = NULL;
|
||||
}
|
||||
CHECK_MEM_ERROR(cm, roi->roi_map, vpx_malloc(rows * cols));
|
||||
|
||||
// Copy to ROI sturcture in the compressor.
|
||||
memcpy(roi->roi_map, map, rows * cols);
|
||||
memcpy(&roi->delta_q, delta_q, MAX_SEGMENTS * sizeof(delta_q[0]));
|
||||
memcpy(&roi->delta_lf, delta_lf, MAX_SEGMENTS * sizeof(delta_lf[0]));
|
||||
memcpy(&roi->skip, skip, MAX_SEGMENTS * sizeof(skip[0]));
|
||||
memcpy(&roi->ref_frame, ref_frame, MAX_SEGMENTS * sizeof(ref_frame[0]));
|
||||
roi->enabled = 1;
|
||||
roi->rows = rows;
|
||||
roi->cols = cols;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vp9_set_active_map(VP9_COMP *cpi, unsigned char *new_map_16x16, int rows,
|
||||
int cols) {
|
||||
if (rows == cpi->common.mb_rows && cols == cpi->common.mb_cols) {
|
||||
@ -817,6 +947,9 @@ static void dealloc_compressor_data(VP9_COMP *cpi) {
|
||||
vpx_free(cpi->active_map.map);
|
||||
cpi->active_map.map = NULL;
|
||||
|
||||
vpx_free(cpi->roi.roi_map);
|
||||
cpi->roi.roi_map = NULL;
|
||||
|
||||
vpx_free(cpi->consec_zero_mv);
|
||||
cpi->consec_zero_mv = NULL;
|
||||
|
||||
@ -3632,6 +3765,8 @@ static void encode_without_recode_loop(VP9_COMP *cpi, size_t *size,
|
||||
// it may be pretty bad for rate-control,
|
||||
// and I should handle it somehow
|
||||
vp9_alt_ref_aq_setup_map(cpi->alt_ref_aq, cpi);
|
||||
} else if (cpi->roi.enabled && cm->frame_type != KEY_FRAME) {
|
||||
apply_roi_map(cpi);
|
||||
}
|
||||
|
||||
apply_active_map(cpi);
|
||||
|
@ -723,6 +723,8 @@ typedef struct VP9_COMP {
|
||||
|
||||
uint8_t *count_arf_frame_usage;
|
||||
uint8_t *count_lastgolden_frame_usage;
|
||||
|
||||
vpx_roi_map_t roi;
|
||||
} VP9_COMP;
|
||||
|
||||
void vp9_initialize_enc(void);
|
||||
@ -937,6 +939,10 @@ static INLINE int log_tile_cols_from_picsize_level(uint32_t width,
|
||||
|
||||
VP9_LEVEL vp9_get_level(const Vp9LevelSpec *const level_spec);
|
||||
|
||||
int vp9_set_roi_map(VP9_COMP *cpi, unsigned char *map, unsigned int rows,
|
||||
unsigned int cols, int delta_q[8], int delta_lf[8],
|
||||
int skip[8], int ref_frame[8]);
|
||||
|
||||
void vp9_new_framerate(VP9_COMP *cpi, double framerate);
|
||||
|
||||
void vp9_set_row_mt(VP9_COMP *cpi);
|
||||
|
@ -1495,6 +1495,7 @@ void vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x, TileDataEnc *tile_data,
|
||||
#endif
|
||||
INTERP_FILTER filter_gf_svc = EIGHTTAP;
|
||||
MV_REFERENCE_FRAME best_second_ref_frame = NONE;
|
||||
const struct segmentation *const seg = &cm->seg;
|
||||
int comp_modes = 0;
|
||||
int num_inter_modes = (cpi->use_svc) ? RT_INTER_MODES_SVC : RT_INTER_MODES;
|
||||
int flag_svc_subpel = 0;
|
||||
@ -1648,6 +1649,16 @@ void vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x, TileDataEnc *tile_data,
|
||||
cpi->sf.use_compound_nonrd_pickmode && usable_ref_frame == ALTREF_FRAME)
|
||||
comp_modes = 2;
|
||||
|
||||
// If the segment reference frame feature is enabled and it's set to GOLDEN
|
||||
// reference, then make sure we don't skip checking GOLDEN, this is to
|
||||
// prevent possibility of not picking any mode.
|
||||
if (segfeature_active(seg, mi->segment_id, SEG_LVL_REF_FRAME) &&
|
||||
get_segdata(seg, mi->segment_id, SEG_LVL_REF_FRAME) == GOLDEN_FRAME) {
|
||||
usable_ref_frame = GOLDEN_FRAME;
|
||||
skip_ref_find_pred[GOLDEN_FRAME] = 0;
|
||||
thresh_svc_skip_golden = 0;
|
||||
}
|
||||
|
||||
for (ref_frame = LAST_FRAME; ref_frame <= usable_ref_frame; ++ref_frame) {
|
||||
if (!skip_ref_find_pred[ref_frame]) {
|
||||
find_predictors(cpi, x, ref_frame, frame_mv, const_motion,
|
||||
@ -1709,6 +1720,12 @@ void vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x, TileDataEnc *tile_data,
|
||||
if (ref_frame > usable_ref_frame) continue;
|
||||
if (skip_ref_find_pred[ref_frame]) continue;
|
||||
|
||||
// If the segment reference frame feature is enabled then do nothing if the
|
||||
// current ref frame is not allowed.
|
||||
if (segfeature_active(seg, mi->segment_id, SEG_LVL_REF_FRAME) &&
|
||||
get_segdata(seg, mi->segment_id, SEG_LVL_REF_FRAME) != (int)ref_frame)
|
||||
continue;
|
||||
|
||||
if (flag_svc_subpel && ref_frame == GOLDEN_FRAME) {
|
||||
force_gf_mv = 1;
|
||||
// Only test mode if NEARESTMV/NEARMV is (svc_mv_col, svc_mv_row),
|
||||
@ -1723,7 +1740,6 @@ void vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x, TileDataEnc *tile_data,
|
||||
}
|
||||
|
||||
if (comp_pred) {
|
||||
const struct segmentation *const seg = &cm->seg;
|
||||
if (!cpi->allow_comp_inter_inter) continue;
|
||||
// Skip compound inter modes if ARF is not available.
|
||||
if (!(cpi->ref_frame_flags & flag_list[second_ref_frame])) continue;
|
||||
@ -1795,28 +1811,34 @@ void vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x, TileDataEnc *tile_data,
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sf->reference_masking && !(frame_mv[this_mode][ref_frame].as_int == 0 &&
|
||||
ref_frame == LAST_FRAME)) {
|
||||
if (usable_ref_frame < ALTREF_FRAME) {
|
||||
if (!force_skip_low_temp_var && usable_ref_frame > LAST_FRAME) {
|
||||
i = (ref_frame == LAST_FRAME) ? GOLDEN_FRAME : LAST_FRAME;
|
||||
if ((cpi->ref_frame_flags & flag_list[i]))
|
||||
if (x->pred_mv_sad[ref_frame] > (x->pred_mv_sad[i] << 1))
|
||||
ref_frame_skip_mask |= (1 << ref_frame);
|
||||
// Disable this drop out case if the ref frame segment level feature is
|
||||
// enabled for this segment. This is to prevent the possibility that we end
|
||||
// up unable to pick any mode.
|
||||
if (!segfeature_active(seg, mi->segment_id, SEG_LVL_REF_FRAME)) {
|
||||
if (sf->reference_masking &&
|
||||
!(frame_mv[this_mode][ref_frame].as_int == 0 &&
|
||||
ref_frame == LAST_FRAME)) {
|
||||
if (usable_ref_frame < ALTREF_FRAME) {
|
||||
if (!force_skip_low_temp_var && usable_ref_frame > LAST_FRAME) {
|
||||
i = (ref_frame == LAST_FRAME) ? GOLDEN_FRAME : LAST_FRAME;
|
||||
if ((cpi->ref_frame_flags & flag_list[i]))
|
||||
if (x->pred_mv_sad[ref_frame] > (x->pred_mv_sad[i] << 1))
|
||||
ref_frame_skip_mask |= (1 << ref_frame);
|
||||
}
|
||||
} else if (!cpi->rc.is_src_frame_alt_ref &&
|
||||
!(frame_mv[this_mode][ref_frame].as_int == 0 &&
|
||||
ref_frame == ALTREF_FRAME)) {
|
||||
int ref1 = (ref_frame == GOLDEN_FRAME) ? LAST_FRAME : GOLDEN_FRAME;
|
||||
int ref2 = (ref_frame == ALTREF_FRAME) ? LAST_FRAME : ALTREF_FRAME;
|
||||
if (((cpi->ref_frame_flags & flag_list[ref1]) &&
|
||||
(x->pred_mv_sad[ref_frame] > (x->pred_mv_sad[ref1] << 1))) ||
|
||||
((cpi->ref_frame_flags & flag_list[ref2]) &&
|
||||
(x->pred_mv_sad[ref_frame] > (x->pred_mv_sad[ref2] << 1))))
|
||||
ref_frame_skip_mask |= (1 << ref_frame);
|
||||
}
|
||||
} else if (!cpi->rc.is_src_frame_alt_ref &&
|
||||
!(frame_mv[this_mode][ref_frame].as_int == 0 &&
|
||||
ref_frame == ALTREF_FRAME)) {
|
||||
int ref1 = (ref_frame == GOLDEN_FRAME) ? LAST_FRAME : GOLDEN_FRAME;
|
||||
int ref2 = (ref_frame == ALTREF_FRAME) ? LAST_FRAME : ALTREF_FRAME;
|
||||
if (((cpi->ref_frame_flags & flag_list[ref1]) &&
|
||||
(x->pred_mv_sad[ref_frame] > (x->pred_mv_sad[ref1] << 1))) ||
|
||||
((cpi->ref_frame_flags & flag_list[ref2]) &&
|
||||
(x->pred_mv_sad[ref_frame] > (x->pred_mv_sad[ref2] << 1))))
|
||||
ref_frame_skip_mask |= (1 << ref_frame);
|
||||
}
|
||||
if (ref_frame_skip_mask & (1 << ref_frame)) continue;
|
||||
}
|
||||
if (ref_frame_skip_mask & (1 << ref_frame)) continue;
|
||||
|
||||
// Select prediction reference frames.
|
||||
for (i = 0; i < MAX_MB_PLANE; i++) {
|
||||
@ -2225,6 +2247,13 @@ void vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x, TileDataEnc *tile_data,
|
||||
if (cpi->oxcf.lag_in_frames > 0 && cpi->oxcf.rc_mode == VPX_VBR &&
|
||||
cpi->rc.is_src_frame_alt_ref)
|
||||
perform_intra_pred = 0;
|
||||
|
||||
// If the segment reference frame feature is enabled and set then
|
||||
// skip the intra prediction.
|
||||
if (segfeature_active(seg, mi->segment_id, SEG_LVL_REF_FRAME) &&
|
||||
get_segdata(seg, mi->segment_id, SEG_LVL_REF_FRAME) > 0)
|
||||
perform_intra_pred = 0;
|
||||
|
||||
// Perform intra prediction search, if the best SAD is above a certain
|
||||
// threshold.
|
||||
if (best_rdc.rdcost == INT64_MAX ||
|
||||
|
@ -1415,11 +1415,21 @@ static vpx_image_t *encoder_get_preview(vpx_codec_alg_priv_t *ctx) {
|
||||
|
||||
static vpx_codec_err_t ctrl_set_roi_map(vpx_codec_alg_priv_t *ctx,
|
||||
va_list args) {
|
||||
(void)ctx;
|
||||
(void)args;
|
||||
vpx_roi_map_t *data = va_arg(args, vpx_roi_map_t *);
|
||||
|
||||
// TODO(yaowu): Need to re-implement and test for VP9.
|
||||
return VPX_CODEC_INVALID_PARAM;
|
||||
if (data) {
|
||||
vpx_roi_map_t *roi = (vpx_roi_map_t *)data;
|
||||
|
||||
if (!vp9_set_roi_map(ctx->cpi, roi->roi_map, roi->rows, roi->cols,
|
||||
roi->delta_q, roi->delta_lf, roi->skip,
|
||||
roi->ref_frame)) {
|
||||
return VPX_CODEC_OK;
|
||||
} else {
|
||||
return VPX_CODEC_INVALID_PARAM;
|
||||
}
|
||||
} else {
|
||||
return VPX_CODEC_INVALID_PARAM;
|
||||
}
|
||||
}
|
||||
|
||||
static vpx_codec_err_t ctrl_set_active_map(vpx_codec_alg_priv_t *ctx,
|
||||
@ -1609,7 +1619,7 @@ static vpx_codec_ctrl_fn_map_t encoder_ctrl_maps[] = {
|
||||
// Setters
|
||||
{ VP8_SET_REFERENCE, ctrl_set_reference },
|
||||
{ VP8_SET_POSTPROC, ctrl_set_previewpp },
|
||||
{ VP8E_SET_ROI_MAP, ctrl_set_roi_map },
|
||||
{ VP9E_SET_ROI_MAP, ctrl_set_roi_map },
|
||||
{ VP8E_SET_ACTIVEMAP, ctrl_set_active_map },
|
||||
{ VP8E_SET_SCALEMODE, ctrl_set_scale_mode },
|
||||
{ VP8E_SET_CPUUSED, ctrl_set_cpuused },
|
||||
|
28
vpx/vp8cx.h
28
vpx/vp8cx.h
@ -125,7 +125,7 @@ extern vpx_codec_iface_t *vpx_codec_vp9_cx(void);
|
||||
enum vp8e_enc_control_id {
|
||||
/*!\brief Codec control function to pass an ROI map to encoder.
|
||||
*
|
||||
* Supported in codecs: VP8, VP9
|
||||
* Supported in codecs: VP8
|
||||
*/
|
||||
VP8E_SET_ROI_MAP = 8,
|
||||
|
||||
@ -423,6 +423,12 @@ enum vp8e_enc_control_id {
|
||||
*/
|
||||
VP9E_SET_SVC,
|
||||
|
||||
/*!\brief Codec control function to pass an ROI map to encoder.
|
||||
*
|
||||
* Supported in codecs: VP9
|
||||
*/
|
||||
VP9E_SET_ROI_MAP,
|
||||
|
||||
/*!\brief Codec control function to set parameters for SVC.
|
||||
* \note Parameters contain min_q, max_q, scaling factor for each of the
|
||||
* SVC layers.
|
||||
@ -643,16 +649,20 @@ typedef enum vp9e_temporal_layering_mode {
|
||||
*/
|
||||
|
||||
typedef struct vpx_roi_map {
|
||||
/*! An id between 0 and 3 for each 16x16 region within a frame. */
|
||||
/*! If ROI is enabled. */
|
||||
uint8_t enabled;
|
||||
/*! An id between 0-3 (0-7 for vp9) for each 16x16 (8x8 for VP9)
|
||||
* region within a frame. */
|
||||
unsigned char *roi_map;
|
||||
unsigned int rows; /**< Number of rows. */
|
||||
unsigned int cols; /**< Number of columns. */
|
||||
// TODO(paulwilkins): broken for VP9 which has 8 segments
|
||||
// q and loop filter deltas for each segment
|
||||
// (see MAX_MB_SEGMENTS)
|
||||
int delta_q[4]; /**< Quantizer deltas. */
|
||||
int delta_lf[4]; /**< Loop filter deltas. */
|
||||
/*! Static breakout threshold for each segment. */
|
||||
/*! VP8 only uses the first 4 segments. VP9 uses 8 segments. */
|
||||
int delta_q[8]; /**< Quantizer deltas. */
|
||||
int delta_lf[8]; /**< Loop filter deltas. */
|
||||
/*! skip and ref frame segment is only used in VP9. */
|
||||
int skip[8]; /**< Skip this block. */
|
||||
int ref_frame[8]; /**< Reference frame for this block. */
|
||||
/*! Static breakout threshold for each segment. Only used in VP8. */
|
||||
unsigned int static_threshold[4];
|
||||
} vpx_roi_map_t;
|
||||
|
||||
@ -749,6 +759,8 @@ VPX_CTRL_USE_TYPE(VP8E_SET_TEMPORAL_LAYER_ID, int)
|
||||
#define VPX_CTRL_VP8E_SET_TEMPORAL_LAYER_ID
|
||||
VPX_CTRL_USE_TYPE(VP8E_SET_ROI_MAP, vpx_roi_map_t *)
|
||||
#define VPX_CTRL_VP8E_SET_ROI_MAP
|
||||
VPX_CTRL_USE_TYPE(VP9E_SET_ROI_MAP, vpx_roi_map_t *)
|
||||
#define VPX_CTRL_VP9E_SET_ROI_MAP
|
||||
VPX_CTRL_USE_TYPE(VP8E_SET_ACTIVEMAP, vpx_active_map_t *)
|
||||
#define VPX_CTRL_VP8E_SET_ACTIVEMAP
|
||||
VPX_CTRL_USE_TYPE(VP8E_SET_SCALEMODE, vpx_scaling_mode_t *)
|
||||
|
@ -63,7 +63,7 @@ extern "C" {
|
||||
* fields to structures
|
||||
*/
|
||||
#define VPX_ENCODER_ABI_VERSION \
|
||||
(7 + VPX_CODEC_ABI_VERSION) /**<\hideinitializer*/
|
||||
(8 + VPX_CODEC_ABI_VERSION) /**<\hideinitializer*/
|
||||
|
||||
/*! \brief Encoder capabilities bitfield
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user