Merge "Add ROI support for VP9."
This commit is contained in:
commit
c930ea7dcd
@ -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