ref: 71f9da5c7878d1227eb07d0f6578ac2f8fc72ed6
parent: 03b779e99bd45bfd6aef6184f6f636ed51e3b13d
parent: 2b690d6d13128e83d42a709041ea01974c72954f
author: Angie Chiang <angiebird@google.com>
date: Wed Nov 6 15:07:49 EST 2019
Merge changes I341bd674,Ia9a0d71d,I71c1f906,I2e36e07c,I94ee2e85, ... * changes: Refactor check_initial_width Move noise_sensitivity to set_encoder_config Remove extra function calls in check_initial_width Move init_ref_frame_bufs to vp9_create_compressor Remove bits_left update in encoder_encode() Add vp9_get_encoder_config / vp9_get_frame_info vp9_get_coding_frame_num() Make [min/max]_gf_interval static under rate_ctrl Add rate_ctrl flag
--- a/configure
+++ b/configure
@@ -274,6 +274,7 @@
fp_mb_stats
emulate_hardware
non_greedy_mv
+ rate_ctrl
"
CONFIG_LIST="
dependency_tracking
--- a/vp9/common/vp9_alloccommon.c
+++ b/vp9/common/vp9_alloccommon.c
@@ -17,17 +17,26 @@
#include "vp9/common/vp9_entropymv.h"
#include "vp9/common/vp9_onyxc_int.h"
-void vp9_set_mb_mi(VP9_COMMON *cm, int width, int height) {
+void vp9_set_mi_size(int *mi_rows, int *mi_cols, int *mi_stride, int width,
+ int height) {
const int aligned_width = ALIGN_POWER_OF_TWO(width, MI_SIZE_LOG2);
const int aligned_height = ALIGN_POWER_OF_TWO(height, MI_SIZE_LOG2);
+ *mi_cols = aligned_width >> MI_SIZE_LOG2;
+ *mi_rows = aligned_height >> MI_SIZE_LOG2;
+ *mi_stride = calc_mi_size(*mi_cols);
+}
- cm->mi_cols = aligned_width >> MI_SIZE_LOG2;
- cm->mi_rows = aligned_height >> MI_SIZE_LOG2;
- cm->mi_stride = calc_mi_size(cm->mi_cols);
+void vp9_set_mb_size(int *mb_rows, int *mb_cols, int *mb_num, int mi_rows,
+ int mi_cols) {
+ *mb_cols = (mi_cols + 1) >> 1;
+ *mb_rows = (mi_rows + 1) >> 1;
+ *mb_num = (*mb_rows) * (*mb_cols);
+}
- cm->mb_cols = (cm->mi_cols + 1) >> 1;
- cm->mb_rows = (cm->mi_rows + 1) >> 1;
- cm->MBs = cm->mb_rows * cm->mb_cols;
+void vp9_set_mb_mi(VP9_COMMON *cm, int width, int height) {
+ vp9_set_mi_size(&cm->mi_rows, &cm->mi_cols, &cm->mi_stride, width, height);
+ vp9_set_mb_size(&cm->mb_rows, &cm->mb_cols, &cm->MBs, cm->mi_rows,
+ cm->mi_cols);
}
static int alloc_seg_map(VP9_COMMON *cm, int seg_map_size) {
--- a/vp9/common/vp9_alloccommon.h
+++ b/vp9/common/vp9_alloccommon.h
@@ -33,6 +33,11 @@
int vp9_alloc_state_buffers(struct VP9Common *cm, int width, int height);
void vp9_free_state_buffers(struct VP9Common *cm);
+void vp9_set_mi_size(int *mi_rows, int *mi_cols, int *mi_stride, int width,
+ int height);
+void vp9_set_mb_size(int *mb_rows, int *mb_cols, int *mb_num, int mi_rows,
+ int mi_cols);
+
void vp9_set_mb_mi(struct VP9Common *cm, int width, int height);
void vp9_swap_current_and_last_seg_map(struct VP9Common *cm);
--- a/vp9/encoder/vp9_encoder.c
+++ b/vp9/encoder/vp9_encoder.c
@@ -80,6 +80,7 @@
#include "vp9/encoder/vp9_speed_features.h"
#include "vp9/encoder/vp9_svc_layercontext.h"
#include "vp9/encoder/vp9_temporal_filter.h"
+#include "vp9/vp9_cx_iface.h"
#define AM_SEGMENT_ID_INACTIVE 7
#define AM_SEGMENT_ID_ACTIVE 0
@@ -1456,7 +1457,6 @@
lc->level_index = -1;
lc->max_cpb_size = INT_MAX;
lc->max_frame_size = INT_MAX;
- lc->rc_config_updated = 0;
lc->fail_flag = 0;
}
@@ -2159,6 +2159,18 @@
} while (++i <= MV_MAX);
}
+static void init_ref_frame_bufs(VP9_COMMON *cm) {
+ int i;
+ BufferPool *const pool = cm->buffer_pool;
+ cm->new_fb_idx = INVALID_IDX;
+ for (i = 0; i < REF_FRAMES; ++i) {
+ cm->ref_frame_map[i] = INVALID_IDX;
+ }
+ for (i = 0; i < FRAME_BUFFERS; ++i) {
+ pool->frame_bufs[i].ref_count = 0;
+ }
+}
+
VP9_COMP *vp9_create_compressor(VP9EncoderConfig *oxcf,
BufferPool *const pool) {
unsigned int i;
@@ -2192,11 +2204,12 @@
cpi->resize_buffer_underflow = 0;
cpi->use_skin_detection = 0;
cpi->common.buffer_pool = pool;
+ init_ref_frame_bufs(cm);
cpi->force_update_segmentation = 0;
init_config(cpi, oxcf);
- init_frame_info(&cpi->frame_info, cm);
+ cpi->frame_info = vp9_get_frame_info(oxcf);
vp9_rc_init(&cpi->oxcf, oxcf->pass, &cpi->rc);
@@ -5302,24 +5315,13 @@
}
#endif // !CONFIG_REALTIME_ONLY
-static void init_ref_frame_bufs(VP9_COMMON *cm) {
- int i;
- BufferPool *const pool = cm->buffer_pool;
- cm->new_fb_idx = INVALID_IDX;
- for (i = 0; i < REF_FRAMES; ++i) {
- cm->ref_frame_map[i] = INVALID_IDX;
- }
- for (i = 0; i < FRAME_BUFFERS; ++i) {
- pool->frame_bufs[i].ref_count = 0;
- }
-}
-
-static void check_initial_width(VP9_COMP *cpi,
-#if CONFIG_VP9_HIGHBITDEPTH
- int use_highbitdepth,
-#endif
- int subsampling_x, int subsampling_y) {
+static void update_initial_width(VP9_COMP *cpi, int use_highbitdepth,
+ int subsampling_x, int subsampling_y) {
VP9_COMMON *const cm = &cpi->common;
+#if !CONFIG_VP9_HIGHBITDEPTH
+ (void)use_highbitdepth;
+ assert(use_highbitdepth == 0);
+#endif
if (!cpi->initial_width ||
#if CONFIG_VP9_HIGHBITDEPTH
@@ -5333,12 +5335,6 @@
cm->use_highbitdepth = use_highbitdepth;
#endif
- alloc_raw_frame_buffers(cpi);
- init_ref_frame_bufs(cm);
- alloc_util_frame_buffers(cpi);
-
- init_motion_estimation(cpi); // TODO(agrange) This can be removed.
-
cpi->initial_width = cm->width;
cpi->initial_height = cm->height;
cpi->initial_mbs = cm->MBs;
@@ -5355,23 +5351,17 @@
const int subsampling_y = sd->subsampling_y;
#if CONFIG_VP9_HIGHBITDEPTH
const int use_highbitdepth = (sd->flags & YV12_FLAG_HIGHBITDEPTH) != 0;
-#endif
-
-#if CONFIG_VP9_HIGHBITDEPTH
- check_initial_width(cpi, use_highbitdepth, subsampling_x, subsampling_y);
#else
- check_initial_width(cpi, subsampling_x, subsampling_y);
-#endif // CONFIG_VP9_HIGHBITDEPTH
-
-#if CONFIG_VP9_HIGHBITDEPTH
- // Disable denoiser for high bitdepth since vp9_denoiser_filter only works for
- // 8 bits.
- if (cm->bit_depth > 8) cpi->oxcf.noise_sensitivity = 0;
+ const int use_highbitdepth = 0;
#endif
+ update_initial_width(cpi, use_highbitdepth, subsampling_x, subsampling_y);
#if CONFIG_VP9_TEMPORAL_DENOISING
setup_denoiser_buffer(cpi);
#endif
+
+ alloc_raw_frame_buffers(cpi);
+
vpx_usec_timer_start(&timer);
if (vp9_lookahead_push(cpi->lookahead, sd, time_stamp, end_time,
@@ -7614,15 +7604,15 @@
unsigned int height) {
VP9_COMMON *cm = &cpi->common;
#if CONFIG_VP9_HIGHBITDEPTH
- check_initial_width(cpi, cm->use_highbitdepth, 1, 1);
+ update_initial_width(cpi, cm->use_highbitdepth, 1, 1);
#else
- check_initial_width(cpi, 1, 1);
+ update_initial_width(cpi, 0, 1, 1);
#endif // CONFIG_VP9_HIGHBITDEPTH
#if CONFIG_VP9_TEMPORAL_DENOISING
setup_denoiser_buffer(cpi);
#endif
-
+ alloc_raw_frame_buffers(cpi);
if (width) {
cm->width = width;
if (cm->width > cpi->initial_width) {
--- a/vp9/encoder/vp9_encoder.h
+++ b/vp9/encoder/vp9_encoder.h
@@ -483,7 +483,6 @@
typedef struct {
int8_t level_index;
- uint8_t rc_config_updated;
uint8_t fail_flag;
int max_frame_size; // in bits
double max_cpb_size; // in bits
--- a/vp9/encoder/vp9_firstpass.c
+++ b/vp9/encoder/vp9_firstpass.c
@@ -2580,6 +2580,21 @@
const FRAME_INFO *frame_info, const RATE_CONTROL *rc, int arf_active_or_kf,
int gf_start_show_idx, int active_worst_quality, int last_boosted_qindex) {
RANGE active_gf_interval;
+#if CONFIG_RATE_CTRL
+ (void)frame_info;
+ (void)gf_start_show_idx;
+ (void)active_worst_quality;
+ (void)last_boosted_qindex;
+ active_gf_interval.min = rc->min_gf_interval + arf_active_or_kf + 2;
+
+ active_gf_interval.max = 16 + arf_active_or_kf;
+
+ if ((active_gf_interval.max <= rc->frames_to_key) &&
+ (active_gf_interval.max >= (rc->frames_to_key - rc->min_gf_interval))) {
+ active_gf_interval.min = rc->frames_to_key / 2;
+ active_gf_interval.max = rc->frames_to_key / 2;
+ }
+#else
int int_max_q = (int)(vp9_convert_qindex_to_q(active_worst_quality,
frame_info->bit_depth));
int q_term = (gf_start_show_idx == 0)
@@ -2617,6 +2632,7 @@
}
active_gf_interval.max =
VPXMAX(active_gf_interval.max, active_gf_interval.min);
+#endif
return active_gf_interval;
}
@@ -3614,3 +3630,63 @@
}
}
}
+
+#if CONFIG_RATE_CTRL
+// Under CONFIG_RATE_CTRL, once the first_pass_info is ready, the number of
+// coding frames (including show frame and alt ref) can be determined.
+int vp9_get_coding_frame_num(const struct VP9EncoderConfig *oxcf,
+ const FRAME_INFO *frame_info,
+ const FIRST_PASS_INFO *first_pass_info,
+ int multi_layer_arf, int allow_alt_ref) {
+ int coding_frame_num = 0;
+ RATE_CONTROL rc;
+ RANGE active_gf_interval;
+ int arf_layers;
+ double gop_intra_factor;
+ int use_alt_ref;
+ int gop_coding_frames;
+ int gop_show_frames;
+ int show_idx = 0;
+ int arf_active_or_kf = 1;
+ rc.static_scene_max_gf_interval = 250;
+ vp9_rc_init(oxcf, 1, &rc);
+
+ while (show_idx < first_pass_info->num_frames) {
+ if (rc.frames_to_key == 0) {
+ rc.frames_to_key = get_frames_to_next_key(
+ oxcf, frame_info, first_pass_info, show_idx, rc.min_gf_interval);
+ arf_active_or_kf = 1;
+ } else {
+ }
+
+ {
+ int dummy = 0;
+ active_gf_interval = get_active_gf_inverval_range(
+ frame_info, &rc, arf_active_or_kf, show_idx, dummy, dummy);
+ }
+
+ arf_layers = get_arf_layers(multi_layer_arf, oxcf->enable_auto_arf,
+ active_gf_interval.max);
+ if (multi_layer_arf) {
+ gop_intra_factor = 1.0 + 0.25 * arf_layers;
+ } else {
+ gop_intra_factor = 1.0;
+ }
+
+ gop_coding_frames = get_gop_coding_frame_num(
+ &use_alt_ref, frame_info, first_pass_info, &rc, show_idx,
+ &active_gf_interval, gop_intra_factor, oxcf->lag_in_frames);
+
+ use_alt_ref &= allow_alt_ref;
+
+ rc.source_alt_ref_active = use_alt_ref;
+ arf_active_or_kf = use_alt_ref;
+ gop_show_frames = gop_coding_frames - use_alt_ref;
+ rc.frames_to_key -= gop_show_frames;
+ rc.frames_since_key += gop_show_frames;
+ show_idx += gop_show_frames;
+ coding_frame_num += gop_show_frames + use_alt_ref;
+ }
+ return coding_frame_num;
+}
+#endif
--- a/vp9/encoder/vp9_firstpass.h
+++ b/vp9/encoder/vp9_firstpass.h
@@ -13,6 +13,9 @@
#include <assert.h>
+#if CONFIG_RATE_CTRL
+#include "vp9/common/vp9_onyxc_int.h"
+#endif
#include "vp9/encoder/vp9_lookahead.h"
#include "vp9/encoder/vp9_ratectrl.h"
@@ -244,6 +247,14 @@
void calculate_coded_size(struct VP9_COMP *cpi, int *scaled_frame_width,
int *scaled_frame_height);
+
+#if CONFIG_RATE_CTRL
+struct VP9EncoderConfig;
+int vp9_get_coding_frame_num(const struct VP9EncoderConfig *oxcf,
+ const FRAME_INFO *frame_info,
+ const FIRST_PASS_INFO *first_pass_info,
+ int multi_layer_arf, int allow_alt_ref);
+#endif
#ifdef __cplusplus
} // extern "C"
--- a/vp9/encoder/vp9_ratectrl.c
+++ b/vp9/encoder/vp9_ratectrl.c
@@ -2477,6 +2477,16 @@
// Set Maximum gf/arf interval
rc->max_gf_interval = oxcf->max_gf_interval;
rc->min_gf_interval = oxcf->min_gf_interval;
+#if CONFIG_RATE_CTRL
+ if (rc->min_gf_interval == 0) {
+ rc->min_gf_interval = vp9_rc_get_default_min_gf_interval(
+ oxcf->width, oxcf->height, oxcf->init_framerate);
+ }
+ if (rc->max_gf_interval == 0) {
+ rc->max_gf_interval = vp9_rc_get_default_max_gf_interval(
+ oxcf->init_framerate, rc->min_gf_interval);
+ }
+#else
if (rc->min_gf_interval == 0)
rc->min_gf_interval = vp9_rc_get_default_min_gf_interval(
oxcf->width, oxcf->height, cpi->framerate);
@@ -2483,6 +2493,7 @@
if (rc->max_gf_interval == 0)
rc->max_gf_interval = vp9_rc_get_default_max_gf_interval(
cpi->framerate, rc->min_gf_interval);
+#endif
// Extended max interval for genuinely static scenes like slide shows.
rc->static_scene_max_gf_interval = MAX_STATIC_GF_GROUP_LENGTH;
--- a/vp9/vp9_cx_iface.c
+++ b/vp9/vp9_cx_iface.c
@@ -20,10 +20,12 @@
#include "./vpx_version.h"
#include "vp9/encoder/vp9_encoder.h"
#include "vpx/vp8cx.h"
+#include "vp9/common/vp9_alloccommon.h"
#include "vp9/encoder/vp9_firstpass.h"
+#include "vp9/vp9_cx_iface.h"
#include "vp9/vp9_iface_common.h"
-struct vp9_extracfg {
+typedef struct vp9_extracfg {
int cpu_used; // available cpu percentage in 1/16
unsigned int enable_auto_alt_ref;
unsigned int noise_sensitivity;
@@ -55,7 +57,7 @@
int render_height;
unsigned int row_mt;
unsigned int motion_vector_unit_test;
-};
+} vp9_extracfg;
static struct vp9_extracfg default_extra_cfg = {
0, // cpu_used
@@ -539,7 +541,13 @@
oxcf->speed = abs(extra_cfg->cpu_used);
oxcf->encode_breakout = extra_cfg->static_thresh;
oxcf->enable_auto_arf = extra_cfg->enable_auto_alt_ref;
- oxcf->noise_sensitivity = extra_cfg->noise_sensitivity;
+ if (oxcf->bit_depth == VPX_BITS_8) {
+ oxcf->noise_sensitivity = extra_cfg->noise_sensitivity;
+ } else {
+ // Disable denoiser for high bitdepth since vp9_denoiser_filter only works
+ // for 8 bits.
+ oxcf->noise_sensitivity = 0;
+ }
oxcf->sharpness = extra_cfg->sharpness;
oxcf->two_pass_stats_in = cfg->rc_twopass_stats_in;
@@ -1114,16 +1122,6 @@
if (cpi == NULL) return VPX_CODEC_INVALID_PARAM;
- if (cpi->oxcf.pass == 2 && cpi->level_constraint.level_index >= 0 &&
- !cpi->level_constraint.rc_config_updated) {
- const VP9EncoderConfig *const oxcf = &cpi->oxcf;
- TWO_PASS *const twopass = &cpi->twopass;
- FIRSTPASS_STATS *stats = &twopass->total_stats;
- twopass->bits_left =
- (int64_t)(stats->duration * oxcf->target_bandwidth / 10000000.0);
- cpi->level_constraint.rc_config_updated = 1;
- }
-
if (img != NULL) {
res = validate_img(ctx, img);
if (res == VPX_CODEC_OK) {
@@ -1765,7 +1763,7 @@
VPX_VBR, // rc_end_usage
{ NULL, 0 }, // rc_twopass_stats_in
{ NULL, 0 }, // rc_firstpass_mb_stats_in
- 256, // rc_target_bandwidth
+ 256, // rc_target_bitrate
0, // rc_min_quantizer
63, // rc_max_quantizer
25, // rc_undershoot_pct
@@ -1831,3 +1829,54 @@
NULL // vpx_codec_enc_mr_get_mem_loc_fn_t
}
};
+
+static vpx_codec_enc_cfg_t get_enc_cfg(int frame_width, int frame_height,
+ int target_bitrate,
+ vpx_enc_pass enc_pass) {
+ vpx_codec_enc_cfg_t enc_cfg = encoder_usage_cfg_map[0].cfg;
+ enc_cfg.g_w = frame_width;
+ enc_cfg.g_h = frame_height;
+ enc_cfg.rc_target_bitrate = target_bitrate;
+ enc_cfg.g_pass = enc_pass;
+ // Use the same default setting as the one used in vpxenc.c
+ // The default unit time for the encoder is 1/1000 s.
+ enc_cfg.g_timebase.num = 1;
+ enc_cfg.g_timebase.den = 1000;
+ return enc_cfg;
+}
+
+static vp9_extracfg get_extra_cfg() {
+ vp9_extracfg extra_cfg = default_extra_cfg;
+ // TODO(angiebird) figure out whether we can modify default_extra_cfg
+ // directly.
+ extra_cfg.tile_columns = 0;
+ extra_cfg.frame_parallel_decoding_mode = 0;
+ return extra_cfg;
+}
+
+VP9EncoderConfig vp9_get_encoder_config(int frame_width, int frame_height,
+ int target_bitrate,
+ vpx_enc_pass enc_pass) {
+ VP9EncoderConfig oxcf;
+ vp9_extracfg extra_cfg = get_extra_cfg();
+ vpx_codec_enc_cfg_t enc_cfg =
+ get_enc_cfg(frame_width, frame_height, target_bitrate, enc_pass);
+ set_encoder_config(&oxcf, &enc_cfg, &extra_cfg);
+ return oxcf;
+}
+
+FRAME_INFO vp9_get_frame_info(const VP9EncoderConfig *oxcf) {
+ FRAME_INFO frame_info;
+ int dummy;
+ frame_info.frame_width = oxcf->width;
+ frame_info.frame_height = oxcf->height;
+ frame_info.render_frame_width = oxcf->width;
+ frame_info.render_frame_height = oxcf->height;
+ frame_info.bit_depth = oxcf->bit_depth;
+ vp9_set_mi_size(&frame_info.mi_rows, &frame_info.mi_cols, &dummy,
+ frame_info.frame_width, frame_info.frame_height);
+ vp9_set_mb_size(&frame_info.mb_rows, &frame_info.mb_cols, &frame_info.num_mbs,
+ frame_info.mi_rows, frame_info.mi_cols);
+ // TODO(angiebird): Figure out how to get subsampling_x/y here
+ return frame_info;
+}
--- /dev/null
+++ b/vp9/vp9_cx_iface.h
@@ -1,0 +1,29 @@
+/*
+ * Copyright (c) 2019 The WebM project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef VPX_VP9_VP9_CX_IFACE_H_
+#define VPX_VP9_VP9_CX_IFACE_H_
+#include "vp9/encoder/vp9_encoder.h"
+#include "vp9/common/vp9_onyxc_int.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+VP9EncoderConfig vp9_get_encoder_config(int frame_width, int frame_height,
+ int target_bitrate,
+ vpx_enc_pass enc_pass);
+FRAME_INFO vp9_get_frame_info(const VP9EncoderConfig *oxcf);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // VPX_VP9_VP9_CX_IFACE_H_
--- a/vp9/vp9cx.mk
+++ b/vp9/vp9cx.mk
@@ -16,6 +16,7 @@
VP9_CX_SRCS_REMOVE-no += $(VP9_COMMON_SRCS_REMOVE-no)
VP9_CX_SRCS-yes += vp9_cx_iface.c
+VP9_CX_SRCS-yes += vp9_cx_iface.h
VP9_CX_SRCS-yes += encoder/vp9_bitstream.c
VP9_CX_SRCS-yes += encoder/vp9_context_tree.c
--- a/vpx/vpx_encoder.h
+++ b/vpx/vpx_encoder.h
@@ -221,11 +221,11 @@
} vpx_rational_t; /**< alias for struct vpx_rational */
/*!\brief Multi-pass Encoding Pass */
-enum vpx_enc_pass {
+typedef enum vpx_enc_pass {
VPX_RC_ONE_PASS, /**< Single pass mode */
VPX_RC_FIRST_PASS, /**< First pass of multi-pass mode */
VPX_RC_LAST_PASS /**< Final pass of multi-pass mode */
-};
+} vpx_enc_pass;
/*!\brief Rate control mode */
enum vpx_rc_mode {