#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
#endif // !CONFIG_REALTIME_ONLY
// Test for whether to calculate metrics for the frame.
-static int is_psnr_calc_enabled(VP9_COMP *cpi) {
- VP9_COMMON *const cm = &cpi->common;
+static int is_psnr_calc_enabled(const VP9_COMP *cpi) {
+ const VP9_COMMON *const cm = &cpi->common;
const VP9EncoderConfig *const oxcf = &cpi->oxcf;
return cpi->b_calculate_psnr && (oxcf->pass != 1) && cm->show_frame;
}
CHECK_MEM_ERROR(cm, roi->roi_map, vpx_malloc(rows * cols));
- // Copy to ROI sturcture in the compressor.
+ // Copy to ROI structure 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]));
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;
}
}
}
-static void init_config(struct VP9_COMP *cpi, VP9EncoderConfig *oxcf) {
+static void init_config(struct VP9_COMP *cpi, const VP9EncoderConfig *oxcf) {
VP9_COMMON *const cm = &cpi->common;
cpi->oxcf = *oxcf;
} while (++i <= MV_MAX);
}
-VP9_COMP *vp9_create_compressor(VP9EncoderConfig *oxcf,
+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 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
+ cm->use_highbitdepth != use_highbitdepth ||
+#endif
+ cm->subsampling_x != subsampling_x ||
+ cm->subsampling_y != subsampling_y) {
+ cm->subsampling_x = subsampling_x;
+ cm->subsampling_y = subsampling_y;
+#if CONFIG_VP9_HIGHBITDEPTH
+ cm->use_highbitdepth = use_highbitdepth;
+#endif
+ alloc_util_frame_buffers(cpi);
+ cpi->initial_width = cm->width;
+ cpi->initial_height = cm->height;
+ cpi->initial_mbs = cm->MBs;
+ }
+}
+
+// TODO(angiebird): Check whether we can move this function to vpx_image.c
+static INLINE void vpx_img_chroma_subsampling(vpx_img_fmt_t fmt,
+ unsigned int *subsampling_x,
+ unsigned int *subsampling_y) {
+ switch (fmt) {
+ case VPX_IMG_FMT_I420:
+ case VPX_IMG_FMT_YV12:
+ case VPX_IMG_FMT_I422:
+ case VPX_IMG_FMT_I42016:
+ case VPX_IMG_FMT_I42216: *subsampling_x = 1; break;
+ default: *subsampling_x = 0; break;
+ }
+
+ switch (fmt) {
+ case VPX_IMG_FMT_I420:
+ case VPX_IMG_FMT_I440:
+ case VPX_IMG_FMT_YV12:
+ case VPX_IMG_FMT_I42016:
+ case VPX_IMG_FMT_I44016: *subsampling_y = 1; break;
+ default: *subsampling_y = 0; break;
+ }
+}
+
+// TODO(angiebird): Check whether we can move this function to vpx_image.c
+static INLINE int vpx_img_use_highbitdepth(vpx_img_fmt_t fmt) {
+ return fmt & VPX_IMG_FMT_HIGHBITDEPTH;
+}
+
+#if CONFIG_VP9_TEMPORAL_DENOISING
+static void setup_denoiser_buffer(VP9_COMP *cpi) {
+ VP9_COMMON *const cm = &cpi->common;
+ if (cpi->oxcf.noise_sensitivity > 0 &&
+ !cpi->denoiser.frame_buffer_initialized) {
+ if (vp9_denoiser_alloc(cm, &cpi->svc, &cpi->denoiser, cpi->use_svc,
+ cpi->oxcf.noise_sensitivity, cm->width, cm->height,
+ cm->subsampling_x, cm->subsampling_y,
+#if CONFIG_VP9_HIGHBITDEPTH
+ cm->use_highbitdepth,
+#endif
+ VP9_ENC_BORDER_IN_PIXELS))
+ vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
+ "Failed to allocate denoiser");
+ }
+}
+#endif
+
+void vp9_update_compressor_with_img_fmt(VP9_COMP *cpi, vpx_img_fmt_t img_fmt) {
+ const VP9EncoderConfig *oxcf = &cpi->oxcf;
+ unsigned int subsampling_x, subsampling_y;
+ const int use_highbitdepth = vpx_img_use_highbitdepth(img_fmt);
+ vpx_img_chroma_subsampling(img_fmt, &subsampling_x, &subsampling_y);
+
+ update_initial_width(cpi, use_highbitdepth, subsampling_x, subsampling_y);
+#if CONFIG_VP9_TEMPORAL_DENOISING
+ setup_denoiser_buffer(cpi);
+#endif
+
+ assert(cpi->lookahead == NULL);
+ cpi->lookahead = vp9_lookahead_init(oxcf->width, oxcf->height, subsampling_x,
+ subsampling_y,
+#if CONFIG_VP9_HIGHBITDEPTH
+ use_highbitdepth,
+#endif
+ oxcf->lag_in_frames);
+ alloc_raw_frame_buffers(cpi);
+}
+
+VP9_COMP *vp9_create_compressor(const VP9EncoderConfig *oxcf,
BufferPool *const pool) {
unsigned int i;
VP9_COMP *volatile const cpi = vpx_memalign(32, sizeof(VP9_COMP));
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);
+ cpi->frame_info = vp9_get_frame_info(oxcf);
+
vp9_rc_init(&cpi->oxcf, oxcf->pass, &cpi->rc);
cm->current_video_frame = 0;
const int layer_id = (int)last_packet_for_layer->spatial_layer_id;
const int packets_in_layer = (int)last_packet_for_layer->count + 1;
if (layer_id >= 0 && layer_id < oxcf->ss_number_layers) {
+ int num_frames;
LAYER_CONTEXT *const lc = &cpi->svc.layer_context[layer_id];
vpx_free(lc->rc_twopass_stats_in.buf);
lc->twopass.stats_in = lc->twopass.stats_in_start;
lc->twopass.stats_in_end =
lc->twopass.stats_in_start + packets_in_layer - 1;
+ // Note the last packet is cumulative first pass stats.
+ // So the number of frames is packet number minus one
+ num_frames = packets_in_layer - 1;
+ fps_init_first_pass_info(&lc->twopass.first_pass_info,
+ lc->rc_twopass_stats_in.buf, num_frames);
stats_copy[layer_id] = lc->rc_twopass_stats_in.buf;
}
}
vp9_init_second_pass_spatial_svc(cpi);
} else {
+ int num_frames;
#if CONFIG_FP_MB_STATS
if (cpi->use_fp_mb_stats) {
const size_t psz = cpi->common.MBs * sizeof(uint8_t);
cpi->twopass.stats_in_start = oxcf->two_pass_stats_in.buf;
cpi->twopass.stats_in = cpi->twopass.stats_in_start;
cpi->twopass.stats_in_end = &cpi->twopass.stats_in[packets - 1];
+ // Note the last packet is cumulative first pass stats.
+ // So the number of frames is packet number minus one
+ num_frames = packets - 1;
+ fps_init_first_pass_info(&cpi->twopass.first_pass_info,
+ oxcf->two_pass_stats_in.buf, num_frames);
vp9_init_second_pass(cpi);
}
cpi->kmeans_data_arr_alloc = 0;
#if CONFIG_NON_GREEDY_MV
- cpi->feature_score_loc_alloc = 0;
cpi->tpl_ready = 0;
#endif // CONFIG_NON_GREEDY_MV
for (i = 0; i < MAX_ARF_GOP_SIZE; ++i) cpi->tpl_stats[i].tpl_stats_ptr = NULL;
cm->error.setjmp = 0;
+#if CONFIG_RATE_CTRL
+ encode_command_init(&cpi->encode_command);
+#endif
+
return cpi;
}
#endif
}
-static void generate_psnr_packet(VP9_COMP *cpi) {
- struct vpx_codec_cx_pkt pkt;
- int i;
- PSNR_STATS psnr;
+int vp9_get_psnr(const VP9_COMP *cpi, PSNR_STATS *psnr) {
+ if (is_psnr_calc_enabled(cpi)) {
#if CONFIG_VP9_HIGHBITDEPTH
- vpx_calc_highbd_psnr(cpi->raw_source_frame, cpi->common.frame_to_show, &psnr,
- cpi->td.mb.e_mbd.bd, cpi->oxcf.input_bit_depth);
+ vpx_calc_highbd_psnr(cpi->raw_source_frame, cpi->common.frame_to_show, psnr,
+ cpi->td.mb.e_mbd.bd, cpi->oxcf.input_bit_depth);
#else
- vpx_calc_psnr(cpi->raw_source_frame, cpi->common.frame_to_show, &psnr);
+ vpx_calc_psnr(cpi->raw_source_frame, cpi->common.frame_to_show, psnr);
#endif
-
- for (i = 0; i < 4; ++i) {
- pkt.data.psnr.samples[i] = psnr.samples[i];
- pkt.data.psnr.sse[i] = psnr.sse[i];
- pkt.data.psnr.psnr[i] = psnr.psnr[i];
+ return 1;
+ } else {
+ vp9_zero(*psnr);
+ return 0;
}
- pkt.kind = VPX_CODEC_PSNR_PKT;
- if (cpi->use_svc)
- cpi->svc
- .layer_context[cpi->svc.spatial_layer_id *
- cpi->svc.number_temporal_layers]
- .psnr_pkt = pkt.data.psnr;
- else
- vpx_codec_pkt_list_add(cpi->output_pkt_list, &pkt);
}
int vp9_use_as_reference(VP9_COMP *cpi, int ref_frame_flags) {
#endif // CONFIG_VP9_POSTPROC
}
-#if CONFIG_VP9_TEMPORAL_DENOISING
-static void setup_denoiser_buffer(VP9_COMP *cpi) {
- VP9_COMMON *const cm = &cpi->common;
- if (cpi->oxcf.noise_sensitivity > 0 &&
- !cpi->denoiser.frame_buffer_initialized) {
- if (vp9_denoiser_alloc(cm, &cpi->svc, &cpi->denoiser, cpi->use_svc,
- cpi->oxcf.noise_sensitivity, cm->width, cm->height,
- cm->subsampling_x, cm->subsampling_y,
-#if CONFIG_VP9_HIGHBITDEPTH
- cm->use_highbitdepth,
-#endif
- VP9_ENC_BORDER_IN_PIXELS))
- vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
- "Failed to allocate denoiser");
- }
-}
-#endif
-
static void init_motion_estimation(VP9_COMP *cpi) {
int y_stride = cpi->scaled_source.y_stride;
vp9_scale_references(cpi);
}
+#if CONFIG_RATE_CTRL
+ // TODO(angiebird): This is a hack for making sure the encoder use the
+ // external_quantize_index exactly. Avoid this kind of hack later.
+ if (cpi->encode_command.use_external_quantize_index) {
+ q = cpi->encode_command.external_quantize_index;
+ }
+#endif
+
vp9_set_quantizer(cm, q);
if (loop_count == 0) setup_frame(cpi);
if (frame_over_shoot_limit == 0) frame_over_shoot_limit = 1;
}
+#if CONFIG_RATE_CTRL
+ // This part needs to be after save_coding_context() because
+ // restore_coding_context will be called in the end of this function.
+ // TODO(angiebird): This is a hack for making sure the encoder use the
+ // external_quantize_index exactly. Avoid this kind of hack later.
+ if (cpi->encode_command.use_external_quantize_index) {
+ break;
+ }
+#endif
+
if (oxcf->rc_mode == VPX_Q) {
loop = 0;
} else {
// Special case reset for qlow for constrained quality.
// This should only trigger where there is very substantial
// undershoot on a frame and the auto cq level is above
- // the user passsed in value.
+ // the user passed in value.
if (oxcf->rc_mode == VPX_CQ && q < q_low) {
q_low = q;
}
}
if (cpi->sf.recode_loop >= ALLOW_RECODE_KFARFGF)
- if (loop || !enable_acl) restore_coding_context(cpi);
+ if (loop) restore_coding_context(cpi);
} while (loop);
#ifdef AGGRESSIVE_VBR
// Skip recoding, if model diff is below threshold
const int thresh = compute_context_model_thresh(cpi);
const int diff = compute_context_model_diff(cm);
- if (diff < thresh) {
- vpx_clear_system_state();
- restore_coding_context(cpi);
- return;
+ if (diff >= thresh) {
+ vp9_encode_frame(cpi);
}
-
- vp9_encode_frame(cpi);
+ }
+ if (cpi->sf.recode_loop >= ALLOW_RECODE_KFARFGF) {
vpx_clear_system_state();
restore_coding_context(cpi);
}
}
#ifdef ENABLE_KF_DENOISE
-// Baseline Kernal weights for denoise
+// Baseline kernel weights for denoise
static uint8_t dn_kernal_3[9] = { 1, 2, 1, 2, 4, 2, 1, 2, 1 };
static uint8_t dn_kernal_5[25] = { 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 4,
2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1 };
tmp_ptr += stride;
}
- // Select the kernal size.
+ // Select the kernel size.
if (max_diff > (strength + (strength >> 1))) {
kernal_size = 3;
half_k_size = 1;
}
kernal_ptr = (kernal_size == 3) ? dn_kernal_3 : dn_kernal_5;
- // Apply the kernal
+ // Apply the kernel
tmp_ptr = src_ptr - (stride * half_k_size) - half_k_size;
for (i = 0; i < kernal_size; ++i) {
for (j = 0; j < kernal_size; ++j) {
tmp_ptr += stride;
}
- // Select the kernal size.
+ // Select the kernel size.
if (max_diff > (strength + (strength >> 1))) {
kernal_size = 3;
half_k_size = 1;
}
kernal_ptr = (kernal_size == 3) ? dn_kernal_3 : dn_kernal_5;
- // Apply the kernal
+ // Apply the kernel
tmp_ptr = src_ptr - (stride * half_k_size) - half_k_size;
for (i = 0; i < kernal_size; ++i) {
for (j = 0; j < kernal_size; ++j) {
}
#endif // CONFIG_VP9_HIGHBITDEPTH
-// Apply thresholded spatial noise supression to a given buffer.
+// Apply thresholded spatial noise suppression to a given buffer.
static void spatial_denoise_buffer(VP9_COMP *cpi, uint8_t *buffer,
const int stride, const int width,
const int height, const int strength) {
}
}
-// Apply thresholded spatial noise supression to source.
+// Apply thresholded spatial noise suppression to source.
static void spatial_denoise_frame(VP9_COMP *cpi) {
YV12_BUFFER_CONFIG *src = cpi->Source;
const VP9EncoderConfig *const oxcf = &cpi->oxcf;
}
}
-// Implementation and modifications of C. Yeo, H. L. Tan, and Y. H. Tan, "On
-// rate distortion optimization using SSIM," Circuits and Systems for Video
-// Technology, IEEE Transactions on, vol. 23, no. 7, pp. 1170-1181, 2013.
-// SSIM_VAR_SCALE defines the strength of the bias towards SSIM in RDO.
-// Some sample values are:
-// (for midres test set)
-// SSIM_VAR_SCALE avg_psnr ssim ms_ssim
-// 8.0 9.421 -5.537 -6.898
-// 16.0 4.703 -5.378 -6.238
-// 32.0 1.929 -4.308 -4.807
-#define SSIM_VAR_SCALE 16.0
static void set_mb_ssim_rdmult_scaling(VP9_COMP *cpi) {
VP9_COMMON *cm = &cpi->common;
ThreadData *td = &cpi->td;
double log_sum = 0.0;
int row, col;
- const double c2 = 58.5225 * SSIM_VAR_SCALE; // 58.5225 = (.03*255)^2
-
// Loop through each 64x64 block.
for (row = 0; row < num_rows; ++row) {
for (col = 0; col < num_cols; ++col) {
}
}
var = var / num_of_var / 64.0;
- var = 2.0 * var + c2;
+
+ // Curve fitting with an exponential model on all 16x16 blocks from the
+ // Midres dataset.
+ var = 67.035434 * (1 - exp(-0.0021489 * var)) + 17.492222;
cpi->mi_ssim_rdmult_scaling_factors[index] = var;
log_sum += log(var);
}
mismatch_move_frame_idx_w();
#endif
encode_frame_to_data_rate(cpi, size, dest, frame_flags);
-
- vp9_twopass_postencode_update(cpi);
}
#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) {
- VP9_COMMON *const cm = &cpi->common;
-
- if (!cpi->initial_width ||
-#if CONFIG_VP9_HIGHBITDEPTH
- cm->use_highbitdepth != use_highbitdepth ||
-#endif
- cm->subsampling_x != subsampling_x ||
- cm->subsampling_y != subsampling_y) {
- cm->subsampling_x = subsampling_x;
- cm->subsampling_y = subsampling_y;
-#if CONFIG_VP9_HIGHBITDEPTH
- 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;
- }
-}
-
int vp9_receive_raw_frame(VP9_COMP *cpi, vpx_enc_frame_flags_t frame_flags,
YV12_BUFFER_CONFIG *sd, int64_t time_stamp,
int64_t end_time) {
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,
-#if CONFIG_VP9_HIGHBITDEPTH
- use_highbitdepth,
-#endif // CONFIG_VP9_HIGHBITDEPTH
- frame_flags))
+ use_highbitdepth, frame_flags))
res = -1;
vpx_usec_timer_mark(&timer);
cpi->time_receive_data += vpx_usec_timer_elapsed(&timer);
int step_param;
uint32_t bestsme = UINT_MAX;
const MvLimits tmp_mv_limits = x->mv_limits;
- // lambda is used to adjust the importance of motion vector consitency.
+ // lambda is used to adjust the importance of motion vector consistency.
// TODO(angiebird): Figure out lambda's proper value.
const int lambda = cpi->tpl_stats[frame_idx].lambda;
int_mv nb_full_mvs[NB_MVS_NUM];
assert(kMvPreCheckSize == (kMvPreCheckLines * (kMvPreCheckLines + 1)) >> 1);
// no new mv
- // diagnal scan order
+ // diagonal scan order
tmp_idx = 0;
for (idx = 0; idx < kMvPreCheckLines; ++idx) {
int r;
}
}
-static double get_feature_score(uint8_t *buf, ptrdiff_t stride, int rows,
- int cols) {
- double IxIx = 0;
- double IxIy = 0;
- double IyIy = 0;
- double score;
- int r, c;
- vpx_clear_system_state();
- for (r = 0; r + 1 < rows; ++r) {
- for (c = 0; c + 1 < cols; ++c) {
- int diff_x = buf[r * stride + c] - buf[r * stride + c + 1];
- int diff_y = buf[r * stride + c] - buf[(r + 1) * stride + c];
- IxIx += diff_x * diff_x;
- IxIy += diff_x * diff_y;
- IyIy += diff_y * diff_y;
- }
- }
- IxIx /= (rows - 1) * (cols - 1);
- IxIy /= (rows - 1) * (cols - 1);
- IyIy /= (rows - 1) * (cols - 1);
- score = (IxIx * IyIy - IxIy * IxIy + 0.0001) / (IxIx + IyIy + 0.0001);
- return score;
-}
-
-static int compare_feature_score(const void *a, const void *b) {
- const FEATURE_SCORE_LOC *aa = *(FEATURE_SCORE_LOC *const *)a;
- const FEATURE_SCORE_LOC *bb = *(FEATURE_SCORE_LOC *const *)b;
- if (aa->feature_score < bb->feature_score) {
- return 1;
- } else if (aa->feature_score > bb->feature_score) {
- return -1;
- } else {
- return 0;
- }
-}
-
static void do_motion_search(VP9_COMP *cpi, ThreadData *td,
MotionField *motion_field, int frame_idx,
YV12_BUFFER_CONFIG *ref_frame, BLOCK_SIZE bsize,
}
}
-#define CHANGE_MV_SEARCH_ORDER 1
-#define USE_PQSORT 1
-
-#if CHANGE_MV_SEARCH_ORDER
-#if USE_PQSORT
-static void max_heap_pop(FEATURE_SCORE_LOC **heap, int *size,
- FEATURE_SCORE_LOC **output) {
- if (*size > 0) {
- *output = heap[0];
- --*size;
- if (*size > 0) {
- int p, l, r;
- heap[0] = heap[*size];
- p = 0;
- l = 2 * p + 1;
- r = 2 * p + 2;
- while (l < *size) {
- FEATURE_SCORE_LOC *tmp;
- int c = l;
- if (r < *size && heap[r]->feature_score > heap[l]->feature_score) {
- c = r;
- }
- if (heap[p]->feature_score >= heap[c]->feature_score) {
- break;
- }
- tmp = heap[p];
- heap[p] = heap[c];
- heap[c] = tmp;
- p = c;
- l = 2 * p + 1;
- r = 2 * p + 2;
- }
- }
- } else {
- assert(0);
- }
-}
-
-static void max_heap_push(FEATURE_SCORE_LOC **heap, int *size,
- FEATURE_SCORE_LOC *input) {
- int c, p;
- FEATURE_SCORE_LOC *tmp;
- input->visited = 1;
- heap[*size] = input;
- ++*size;
- c = *size - 1;
- p = c >> 1;
- while (c > 0 && heap[c]->feature_score > heap[p]->feature_score) {
- tmp = heap[p];
- heap[p] = heap[c];
- heap[c] = tmp;
- c = p;
- p >>= 1;
- }
-}
-
-static void add_nb_blocks_to_heap(VP9_COMP *cpi, const TplDepFrame *tpl_frame,
- BLOCK_SIZE bsize, int mi_row, int mi_col,
- int *heap_size) {
- const int mi_unit = num_8x8_blocks_wide_lookup[bsize];
- const int dirs[NB_MVS_NUM][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
- int i;
- for (i = 0; i < NB_MVS_NUM; ++i) {
- int r = dirs[i][0] * mi_unit;
- int c = dirs[i][1] * mi_unit;
- if (mi_row + r >= 0 && mi_row + r < tpl_frame->mi_rows && mi_col + c >= 0 &&
- mi_col + c < tpl_frame->mi_cols) {
- FEATURE_SCORE_LOC *fs_loc =
- &cpi->feature_score_loc_arr[(mi_row + r) * tpl_frame->stride +
- (mi_col + c)];
- if (fs_loc->visited == 0) {
- max_heap_push(cpi->feature_score_loc_heap, heap_size, fs_loc);
- }
- }
- }
-}
-#endif // USE_PQSORT
-#endif // CHANGE_MV_SEARCH_ORDER
-
static void build_motion_field(
- VP9_COMP *cpi, MACROBLOCKD *xd, int frame_idx,
+ VP9_COMP *cpi, int frame_idx,
YV12_BUFFER_CONFIG *ref_frame[MAX_INTER_REF_FRAMES], BLOCK_SIZE bsize) {
VP9_COMMON *cm = &cpi->common;
ThreadData *td = &cpi->td;
const int mi_width = num_8x8_blocks_wide_lookup[bsize];
const int pw = num_4x4_blocks_wide_lookup[bsize] << 2;
const int ph = num_4x4_blocks_high_lookup[bsize] << 2;
- int fs_loc_sort_size;
- int fs_loc_heap_size;
int mi_row, mi_col;
int rf_idx;
tpl_frame->lambda = (pw * ph) >> 2;
assert(pw * ph == tpl_frame->lambda << 2);
- fs_loc_sort_size = 0;
- for (mi_row = 0; mi_row < cm->mi_rows; mi_row += mi_height) {
- for (mi_col = 0; mi_col < cm->mi_cols; mi_col += mi_width) {
- const int mb_y_offset =
- mi_row * MI_SIZE * xd->cur_buf->y_stride + mi_col * MI_SIZE;
- const int bw = 4 << b_width_log2_lookup[bsize];
- const int bh = 4 << b_height_log2_lookup[bsize];
- FEATURE_SCORE_LOC *fs_loc =
- &cpi->feature_score_loc_arr[mi_row * tpl_frame->stride + mi_col];
- fs_loc->feature_score = get_feature_score(
- xd->cur_buf->y_buffer + mb_y_offset, xd->cur_buf->y_stride, bw, bh);
- fs_loc->visited = 0;
- fs_loc->mi_row = mi_row;
- fs_loc->mi_col = mi_col;
- cpi->feature_score_loc_sort[fs_loc_sort_size] = fs_loc;
- ++fs_loc_sort_size;
- }
- }
-
- qsort(cpi->feature_score_loc_sort, fs_loc_sort_size,
- sizeof(*cpi->feature_score_loc_sort), compare_feature_score);
-
- // TODO(angiebird): Clean up this part.
for (rf_idx = 0; rf_idx < MAX_INTER_REF_FRAMES; ++rf_idx) {
- int i;
MotionField *motion_field = vp9_motion_field_info_get_motion_field(
&cpi->motion_field_info, frame_idx, rf_idx, bsize);
if (ref_frame[rf_idx] == NULL) {
continue;
}
vp9_motion_field_reset_mvs(motion_field);
-#if CHANGE_MV_SEARCH_ORDER
-#if !USE_PQSORT
- for (i = 0; i < fs_loc_sort_size; ++i) {
- FEATURE_SCORE_LOC *fs_loc = cpi->feature_score_loc_sort[i];
- do_motion_search(cpi, td, motion_field, frame_idx, ref_frame[rf_idx],
- bsize, fs_loc->mi_row, fs_loc->mi_col);
- }
-#else // !USE_PQSORT
- fs_loc_heap_size = 0;
- max_heap_push(cpi->feature_score_loc_heap, &fs_loc_heap_size,
- cpi->feature_score_loc_sort[0]);
-
- for (i = 0; i < fs_loc_sort_size; ++i) {
- cpi->feature_score_loc_sort[i]->visited = 0;
- }
-
- while (fs_loc_heap_size > 0) {
- FEATURE_SCORE_LOC *fs_loc;
- max_heap_pop(cpi->feature_score_loc_heap, &fs_loc_heap_size, &fs_loc);
-
- do_motion_search(cpi, td, motion_field, frame_idx, ref_frame[rf_idx],
- bsize, fs_loc->mi_row, fs_loc->mi_col);
-
- add_nb_blocks_to_heap(cpi, tpl_frame, bsize, fs_loc->mi_row,
- fs_loc->mi_col, &fs_loc_heap_size);
- }
-#endif // !USE_PQSORT
-#else // CHANGE_MV_SEARCH_ORDER
for (mi_row = 0; mi_row < cm->mi_rows; mi_row += mi_height) {
for (mi_col = 0; mi_col < cm->mi_cols; mi_col += mi_width) {
do_motion_search(cpi, td, motion_field, frame_idx, ref_frame[rf_idx],
bsize, mi_row, mi_col);
}
}
-#endif // CHANGE_MV_SEARCH_ORDER
}
}
#endif // CONFIG_NON_GREEDY_MV
for (square_block_idx = 0; square_block_idx < SQUARE_BLOCK_SIZES;
++square_block_idx) {
BLOCK_SIZE square_bsize = square_block_idx_to_bsize(square_block_idx);
- build_motion_field(cpi, xd, frame_idx, ref_frame, square_bsize);
+ build_motion_field(cpi, frame_idx, ref_frame, square_bsize);
}
for (rf_idx = 0; rf_idx < MAX_INTER_REF_FRAMES; ++rf_idx) {
int ref_frame_idx = gf_picture[frame_idx].ref_frame[rf_idx];
#if CONFIG_NON_GREEDY_MV
int rf_idx;
- if (cpi->feature_score_loc_alloc == 0) {
- // The smallest block size of motion field is 4x4, but the mi_unit is 8x8,
- // therefore the number of units is "mi_rows * mi_cols * 4" here.
- CHECK_MEM_ERROR(
- cm, cpi->feature_score_loc_arr,
- vpx_calloc(mi_rows * mi_cols * 4, sizeof(*cpi->feature_score_loc_arr)));
- CHECK_MEM_ERROR(cm, cpi->feature_score_loc_sort,
- vpx_calloc(mi_rows * mi_cols * 4,
- sizeof(*cpi->feature_score_loc_sort)));
- CHECK_MEM_ERROR(cm, cpi->feature_score_loc_heap,
- vpx_calloc(mi_rows * mi_cols * 4,
- sizeof(*cpi->feature_score_loc_heap)));
-
- cpi->feature_score_loc_alloc = 1;
- }
vpx_free(cpi->select_mv_arr);
CHECK_MEM_ERROR(
cm, cpi->select_mv_arr,
int frame;
#if CONFIG_NON_GREEDY_MV
vp9_free_motion_field_info(&cpi->motion_field_info);
- vpx_free(cpi->feature_score_loc_arr);
- vpx_free(cpi->feature_score_loc_sort);
- vpx_free(cpi->feature_score_loc_heap);
vpx_free(cpi->select_mv_arr);
#endif
for (frame = 0; frame < MAX_ARF_GOP_SIZE; ++frame) {
#endif // CONFIG_NON_GREEDY_MV
}
+static void init_encode_frame_result(ENCODE_FRAME_RESULT *encode_frame_result) {
+ encode_frame_result->show_idx = -1; // Actual encoding doesn't happen.
+}
+
+#if !CONFIG_REALTIME_ONLY
+static void update_encode_frame_result(
+ int show_idx, FRAME_UPDATE_TYPE update_type,
+ const YV12_BUFFER_CONFIG *source_frame,
+ const YV12_BUFFER_CONFIG *coded_frame, int quantize_index,
+ uint32_t bit_depth, uint32_t input_bit_depth,
+ ENCODE_FRAME_RESULT *encode_frame_result) {
+#if CONFIG_RATE_CTRL
+ PSNR_STATS psnr;
+#if CONFIG_VP9_HIGHBITDEPTH
+ vpx_calc_highbd_psnr(source_frame, coded_frame, &psnr, bit_depth,
+ input_bit_depth);
+#else // CONFIG_VP9_HIGHBITDEPTH
+ (void)bit_depth;
+ (void)input_bit_depth;
+ vpx_calc_psnr(source_frame, coded_frame, &psnr);
+#endif // CONFIG_VP9_HIGHBITDEPTH
+ encode_frame_result->psnr = psnr.psnr[0];
+ encode_frame_result->sse = psnr.sse[0];
+#else // CONFIG_RATE_CTRL
+ (void)bit_depth;
+ (void)input_bit_depth;
+ (void)source_frame;
+ (void)coded_frame;
+#endif // CONFIG_RATE_CTRL
+ encode_frame_result->show_idx = show_idx;
+ encode_frame_result->update_type = update_type;
+ encode_frame_result->quantize_index = quantize_index;
+}
+#endif // !CONFIG_REALTIME_ONLY
+
int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags,
size_t *size, uint8_t *dest, int64_t *time_stamp,
- int64_t *time_end, int flush) {
+ int64_t *time_end, int flush,
+ ENCODE_FRAME_RESULT *encode_frame_result) {
const VP9EncoderConfig *const oxcf = &cpi->oxcf;
VP9_COMMON *const cm = &cpi->common;
BufferPool *const pool = cm->buffer_pool;
int arf_src_index;
const int gf_group_index = cpi->twopass.gf_group.index;
int i;
+ init_encode_frame_result(encode_frame_result);
if (is_one_pass_cbr_svc(cpi)) {
vp9_one_pass_cbr_svc_start_layer(cpi);
if (source != NULL) {
cm->show_frame = 1;
cm->intra_only = 0;
- // if the flags indicate intra frame, but if the current picture is for
- // non-zero spatial layer, it should not be an intra picture.
+ // If the flags indicate intra frame, but if the current picture is for
+ // spatial layer above first_spatial_layer_to_encode, it should not be an
+ // intra picture.
if ((source->flags & VPX_EFLAG_FORCE_KF) && cpi->use_svc &&
- cpi->svc.spatial_layer_id > 0) {
+ cpi->svc.spatial_layer_id > cpi->svc.first_spatial_layer_to_encode) {
source->flags &= ~(unsigned int)(VPX_EFLAG_FORCE_KF);
}
*frame_flags = (source->flags & VPX_EFLAG_FORCE_KF) ? FRAMEFLAGS_KEY : 0;
} else {
*size = 0;
-#if !CONFIG_REALTIME_ONLY
- if (flush && oxcf->pass == 1 && !cpi->twopass.first_pass_done) {
- vp9_end_first_pass(cpi); /* get last stats packet */
- cpi->twopass.first_pass_done = 1;
- }
-#endif // !CONFIG_REALTIME_ONLY
return -1;
}
vp9_first_pass(cpi, source);
} else if (oxcf->pass == 2 && !cpi->use_svc) {
Pass2Encode(cpi, size, dest, frame_flags);
+ // update_encode_frame_result() depends on twopass.gf_group.index and
+ // cm->new_fb_idx and cpi->Source are updated for current properly and have
+ // not been updated for the next frame yet.
+ // The update locations are as follows.
+ // 1) twopass.gf_group.index is initialized at define_gf_group by vp9_zero()
+ // for the first frame in the gf_group and is updated for the next frame at
+ // vp9_twopass_postencode_update().
+ // 2) cpi->Source is updated at the beginning of this function, i.e.
+ // vp9_get_compressed_data()
+ // 3) cm->new_fb_idx is updated at the beginning of this function by
+ // get_free_fb(cm)
+ // TODO(angiebird): Improve the codebase to make the update of frame
+ // dependent variables more robust.
+ update_encode_frame_result(
+ source->show_idx,
+ cpi->twopass.gf_group.update_type[cpi->twopass.gf_group.index],
+ cpi->Source, get_frame_new_buffer(cm), vp9_get_quantizer(cpi),
+ cpi->oxcf.input_bit_depth, cm->bit_depth, encode_frame_result);
+ vp9_twopass_postencode_update(cpi);
} else if (cpi->use_svc) {
SvcEncode(cpi, size, dest, frame_flags);
} else {
vpx_usec_timer_mark(&cmptimer);
cpi->time_compress_data += vpx_usec_timer_elapsed(&cmptimer);
- // Should we calculate metrics for the frame.
- if (is_psnr_calc_enabled(cpi)) generate_psnr_packet(cpi);
-
if (cpi->keep_level_stats && oxcf->pass != 1)
update_level_info(cpi, size, arf_src_index);
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) {
return;
}
-int vp9_get_quantizer(VP9_COMP *cpi) { return cpi->common.base_qindex; }
+int vp9_get_quantizer(const VP9_COMP *cpi) { return cpi->common.base_qindex; }
void vp9_apply_encoding_flags(VP9_COMP *cpi, vpx_enc_frame_flags_t flags) {
if (flags &