summaryrefslogtreecommitdiff
path: root/vp9/encoder/vp9_firstpass.c
diff options
context:
space:
mode:
Diffstat (limited to 'vp9/encoder/vp9_firstpass.c')
-rw-r--r--vp9/encoder/vp9_firstpass.c174
1 files changed, 137 insertions, 37 deletions
diff --git a/vp9/encoder/vp9_firstpass.c b/vp9/encoder/vp9_firstpass.c
index 8167d43a8..6d36b7cf5 100644
--- a/vp9/encoder/vp9_firstpass.c
+++ b/vp9/encoder/vp9_firstpass.c
@@ -23,6 +23,7 @@
#include "vp9/common/vp9_reconinter.h" // vp9_setup_dst_planes()
#include "vp9/common/vp9_systemdependent.h"
+#include "vp9/encoder/vp9_aq_variance.h"
#include "vp9/encoder/vp9_block.h"
#include "vp9/encoder/vp9_encodeframe.h"
#include "vp9/encoder/vp9_encodemb.h"
@@ -34,7 +35,6 @@
#include "vp9/encoder/vp9_quantize.h"
#include "vp9/encoder/vp9_ratectrl.h"
#include "vp9/encoder/vp9_rdopt.h"
-#include "vp9/encoder/vp9_vaq.h"
#include "vp9/encoder/vp9_variance.h"
#define OUTPUT_FPF 0
@@ -181,11 +181,13 @@ static void zero_stats(FIRSTPASS_STATS *section) {
section->new_mv_count = 0.0;
section->count = 0.0;
section->duration = 1.0;
+ section->spatial_layer_id = 0;
}
static void accumulate_stats(FIRSTPASS_STATS *section,
const FIRSTPASS_STATS *frame) {
section->frame += frame->frame;
+ section->spatial_layer_id = frame->spatial_layer_id;
section->intra_error += frame->intra_error;
section->coded_error += frame->coded_error;
section->sr_coded_error += frame->sr_coded_error;
@@ -255,12 +257,21 @@ static void avg_stats(FIRSTPASS_STATS *section) {
// harder frames.
static double calculate_modified_err(const VP9_COMP *cpi,
const FIRSTPASS_STATS *this_frame) {
- const struct twopass_rc *const twopass = &cpi->twopass;
- const FIRSTPASS_STATS *const stats = &twopass->total_stats;
- const double av_err = stats->ssim_weighted_pred_err / stats->count;
- double modified_error = av_err * pow(this_frame->ssim_weighted_pred_err /
- DOUBLE_DIVIDE_CHECK(av_err),
- cpi->oxcf.two_pass_vbrbias / 100.0);
+ const struct twopass_rc *twopass = &cpi->twopass;
+ const FIRSTPASS_STATS *stats;
+ double av_err;
+ double modified_error;
+
+ if (cpi->svc.number_spatial_layers > 1 &&
+ cpi->svc.number_temporal_layers == 1) {
+ twopass = &cpi->svc.layer_context[cpi->svc.spatial_layer_id].twopass;
+ }
+
+ stats = &twopass->total_stats;
+ av_err = stats->ssim_weighted_pred_err / stats->count;
+ modified_error = av_err * pow(this_frame->ssim_weighted_pred_err /
+ DOUBLE_DIVIDE_CHECK(av_err),
+ cpi->oxcf.two_pass_vbrbias / 100.0);
return fclamp(modified_error,
twopass->modified_error_min, twopass->modified_error_max);
@@ -342,7 +353,15 @@ void vp9_init_first_pass(VP9_COMP *cpi) {
}
void vp9_end_first_pass(VP9_COMP *cpi) {
- output_stats(&cpi->twopass.total_stats, cpi->output_pkt_list);
+ if (cpi->use_svc && cpi->svc.number_temporal_layers == 1) {
+ int i;
+ for (i = 0; i < cpi->svc.number_spatial_layers; ++i) {
+ output_stats(&cpi->svc.layer_context[i].twopass.total_stats,
+ cpi->output_pkt_list);
+ }
+ } else {
+ output_stats(&cpi->twopass.total_stats, cpi->output_pkt_list);
+ }
}
static vp9_variance_fn_t get_block_variance_fn(BLOCK_SIZE bsize) {
@@ -464,11 +483,11 @@ void vp9_first_pass(VP9_COMP *cpi) {
int recon_yoffset, recon_uvoffset;
YV12_BUFFER_CONFIG *const lst_yv12 = get_ref_frame_buffer(cpi, LAST_FRAME);
- YV12_BUFFER_CONFIG *const gld_yv12 = get_ref_frame_buffer(cpi, GOLDEN_FRAME);
+ YV12_BUFFER_CONFIG *gld_yv12 = get_ref_frame_buffer(cpi, GOLDEN_FRAME);
YV12_BUFFER_CONFIG *const new_yv12 = get_frame_new_buffer(cm);
- const int recon_y_stride = lst_yv12->y_stride;
- const int recon_uv_stride = lst_yv12->uv_stride;
- const int uv_mb_height = 16 >> (lst_yv12->y_height > lst_yv12->uv_height);
+ int recon_y_stride = lst_yv12->y_stride;
+ int recon_uv_stride = lst_yv12->uv_stride;
+ int uv_mb_height = 16 >> (lst_yv12->y_height > lst_yv12->uv_height);
int64_t intra_error = 0;
int64_t coded_error = 0;
int64_t sr_coded_error = 0;
@@ -484,13 +503,43 @@ void vp9_first_pass(VP9_COMP *cpi) {
int new_mv_count = 0;
int sum_in_vectors = 0;
uint32_t lastmv_as_int = 0;
- struct twopass_rc *const twopass = &cpi->twopass;
+ struct twopass_rc *twopass = &cpi->twopass;
const MV zero_mv = {0, 0};
+ const YV12_BUFFER_CONFIG *first_ref_buf = lst_yv12;
vp9_clear_system_state();
+ if (cpi->use_svc && cpi->svc.number_temporal_layers == 1) {
+ MV_REFERENCE_FRAME ref_frame = LAST_FRAME;
+ const YV12_BUFFER_CONFIG *scaled_ref_buf = NULL;
+ twopass = &cpi->svc.layer_context[cpi->svc.spatial_layer_id].twopass;
+
+ vp9_scale_references(cpi);
+
+ // Use either last frame or alt frame for motion search.
+ if (cpi->ref_frame_flags & VP9_LAST_FLAG) {
+ scaled_ref_buf = vp9_get_scaled_ref_frame(cpi, LAST_FRAME);
+ ref_frame = LAST_FRAME;
+ } else if (cpi->ref_frame_flags & VP9_ALT_FLAG) {
+ scaled_ref_buf = vp9_get_scaled_ref_frame(cpi, ALTREF_FRAME);
+ ref_frame = ALTREF_FRAME;
+ }
+
+ if (scaled_ref_buf != NULL) {
+ // Update the stride since we are using scaled reference buffer
+ first_ref_buf = scaled_ref_buf;
+ recon_y_stride = first_ref_buf->y_stride;
+ recon_uv_stride = first_ref_buf->uv_stride;
+ uv_mb_height = 16 >> (first_ref_buf->y_height > first_ref_buf->uv_height);
+ }
+
+ // Disable golden frame for svc first pass for now.
+ gld_yv12 = NULL;
+ set_ref_ptrs(cm, xd, ref_frame, NONE);
+ }
+
vp9_setup_src_planes(x, cpi->Source, 0, 0);
- vp9_setup_pre_planes(xd, 0, lst_yv12, 0, 0, NULL);
+ vp9_setup_pre_planes(xd, 0, first_ref_buf, 0, 0, NULL);
vp9_setup_dst_planes(xd, new_yv12, 0, 0);
xd->mi_8x8 = cm->mi_grid_visible;
@@ -583,7 +632,7 @@ void vp9_first_pass(VP9_COMP *cpi) {
int tmp_err, motion_error;
int_mv mv, tmp_mv;
- xd->plane[0].pre[0].buf = lst_yv12->y_buffer + recon_yoffset;
+ xd->plane[0].pre[0].buf = first_ref_buf->y_buffer + recon_yoffset;
motion_error = zz_motion_search(x);
// Assume 0,0 motion with no mv overhead.
mv.as_int = tmp_mv.as_int = 0;
@@ -615,7 +664,7 @@ void vp9_first_pass(VP9_COMP *cpi) {
}
// Search in an older reference frame.
- if (cm->current_video_frame > 1) {
+ if (cm->current_video_frame > 1 && gld_yv12 != NULL) {
// Assume 0,0 motion with no mv overhead.
int gf_motion_error;
@@ -633,9 +682,9 @@ void vp9_first_pass(VP9_COMP *cpi) {
++second_ref_count;
// Reset to last frame as reference buffer.
- xd->plane[0].pre[0].buf = lst_yv12->y_buffer + recon_yoffset;
- xd->plane[1].pre[0].buf = lst_yv12->u_buffer + recon_uvoffset;
- xd->plane[2].pre[0].buf = lst_yv12->v_buffer + recon_uvoffset;
+ xd->plane[0].pre[0].buf = first_ref_buf->y_buffer + recon_yoffset;
+ xd->plane[1].pre[0].buf = first_ref_buf->u_buffer + recon_uvoffset;
+ xd->plane[2].pre[0].buf = first_ref_buf->v_buffer + recon_uvoffset;
// In accumulating a score for the older reference frame take the
// best of the motion predicted score and the intra coded error
@@ -743,6 +792,7 @@ void vp9_first_pass(VP9_COMP *cpi) {
FIRSTPASS_STATS fps;
fps.frame = cm->current_video_frame;
+ fps.spatial_layer_id = cpi->svc.spatial_layer_id;
fps.intra_error = (double)(intra_error >> 8);
fps.coded_error = (double)(coded_error >> 8);
fps.sr_coded_error = (double)(sr_coded_error >> 8);
@@ -792,20 +842,28 @@ void vp9_first_pass(VP9_COMP *cpi) {
(twopass->this_frame_stats.pcnt_inter > 0.20) &&
((twopass->this_frame_stats.intra_error /
DOUBLE_DIVIDE_CHECK(twopass->this_frame_stats.coded_error)) > 2.0))) {
- vp8_yv12_copy_frame(lst_yv12, gld_yv12);
+ if (gld_yv12 != NULL) {
+ vp8_yv12_copy_frame(lst_yv12, gld_yv12);
+ }
twopass->sr_update_lag = 1;
} else {
++twopass->sr_update_lag;
}
- // Swap frame pointers so last frame refers to the frame we just compressed.
- swap_yv12(lst_yv12, new_yv12);
+
+ if (cpi->use_svc && cpi->svc.number_temporal_layers == 1) {
+ vp9_update_reference_frames(cpi);
+ } else {
+ // Swap frame pointers so last frame refers to the frame we just compressed.
+ swap_yv12(lst_yv12, new_yv12);
+ }
vp9_extend_frame_borders(lst_yv12);
// Special case for the first frame. Copy into the GF buffer as a second
// reference.
- if (cm->current_video_frame == 0)
+ if (cm->current_video_frame == 0 && gld_yv12 != NULL) {
vp8_yv12_copy_frame(lst_yv12, gld_yv12);
+ }
// Use this to see what the first pass reconstruction looks like.
if (0) {
@@ -884,8 +942,15 @@ extern void vp9_new_framerate(VP9_COMP *cpi, double framerate);
void vp9_init_second_pass(VP9_COMP *cpi) {
FIRSTPASS_STATS this_frame;
const FIRSTPASS_STATS *start_pos;
- struct twopass_rc *const twopass = &cpi->twopass;
+ struct twopass_rc *twopass = &cpi->twopass;
const VP9_CONFIG *const oxcf = &cpi->oxcf;
+ const int is_spatial_svc = (cpi->svc.number_spatial_layers > 1) &&
+ (cpi->svc.number_temporal_layers == 1);
+ double frame_rate;
+
+ if (is_spatial_svc) {
+ twopass = &cpi->svc.layer_context[cpi->svc.spatial_layer_id].twopass;
+ }
zero_stats(&twopass->total_stats);
zero_stats(&twopass->total_left_stats);
@@ -896,30 +961,44 @@ void vp9_init_second_pass(VP9_COMP *cpi) {
twopass->total_stats = *twopass->stats_in_end;
twopass->total_left_stats = twopass->total_stats;
+ frame_rate = 10000000.0 * twopass->total_stats.count /
+ twopass->total_stats.duration;
// Each frame can have a different duration, as the frame rate in the source
// isn't guaranteed to be constant. The frame rate prior to the first frame
// encoded in the second pass is a guess. However, the sum duration is not.
// It is calculated based on the actual durations of all frames from the
// first pass.
- vp9_new_framerate(cpi, 10000000.0 * twopass->total_stats.count /
- twopass->total_stats.duration);
+
+ if (is_spatial_svc) {
+ vp9_update_spatial_layer_framerate(cpi, frame_rate);
+ twopass->bits_left =
+ (int64_t)(twopass->total_stats.duration *
+ cpi->svc.layer_context[cpi->svc.spatial_layer_id].target_bandwidth /
+ 10000000.0);
+ } else {
+ vp9_new_framerate(cpi, frame_rate);
+ twopass->bits_left = (int64_t)(twopass->total_stats.duration *
+ oxcf->target_bandwidth / 10000000.0);
+ }
cpi->output_framerate = oxcf->framerate;
- twopass->bits_left = (int64_t)(twopass->total_stats.duration *
- oxcf->target_bandwidth / 10000000.0);
// Calculate a minimum intra value to be used in determining the IIratio
// scores used in the second pass. We have this minimum to make sure
// that clips that are static but "low complexity" in the intra domain
// are still boosted appropriately for KF/GF/ARF.
- twopass->kf_intra_err_min = KF_MB_INTRA_MIN * cpi->common.MBs;
- twopass->gf_intra_err_min = GF_MB_INTRA_MIN * cpi->common.MBs;
+ if (!is_spatial_svc) {
+ // We don't know the number of MBs for each layer at this point.
+ // So we will do it later.
+ twopass->kf_intra_err_min = KF_MB_INTRA_MIN * cpi->common.MBs;
+ twopass->gf_intra_err_min = GF_MB_INTRA_MIN * cpi->common.MBs;
+ }
// This variable monitors how far behind the second ref update is lagging.
twopass->sr_update_lag = 1;
- // Scan the first pass file and calculate an average Intra / Inter error score
- // ratio for the sequence.
+ // Scan the first pass file and calculate an average Intra / Inter error
+ // score ratio for the sequence.
{
double sum_iiratio = 0.0;
start_pos = twopass->stats_in;
@@ -1566,8 +1645,8 @@ static void define_gf_group(VP9_COMP *cpi, FIRSTPASS_STATS *this_frame) {
// Calculate the bits to be allocated to the group as a whole.
if (twopass->kf_group_bits > 0 && twopass->kf_group_error_left > 0) {
- twopass->gf_group_bits = (int64_t)(cpi->twopass.kf_group_bits *
- (gf_group_err / cpi->twopass.kf_group_error_left));
+ twopass->gf_group_bits = (int64_t)(twopass->kf_group_bits *
+ (gf_group_err / twopass->kf_group_error_left));
} else {
twopass->gf_group_bits = 0;
}
@@ -2138,14 +2217,24 @@ void vp9_rc_get_second_pass_params(VP9_COMP *cpi) {
VP9_COMMON *const cm = &cpi->common;
RATE_CONTROL *const rc = &cpi->rc;
struct twopass_rc *const twopass = &cpi->twopass;
- const int frames_left = (int)(twopass->total_stats.count -
- cm->current_video_frame);
+ int frames_left;
FIRSTPASS_STATS this_frame;
FIRSTPASS_STATS this_frame_copy;
double this_frame_intra_error;
double this_frame_coded_error;
int target;
+ LAYER_CONTEXT *lc = NULL;
+ int is_spatial_svc = (cpi->use_svc && cpi->svc.number_temporal_layers == 1);
+
+ if (is_spatial_svc) {
+ lc = &cpi->svc.layer_context[cpi->svc.spatial_layer_id];
+ frames_left = (int)(twopass->total_stats.count -
+ lc->current_video_frame_in_layer);
+ } else {
+ frames_left = (int)(twopass->total_stats.count -
+ cm->current_video_frame);
+ }
if (!twopass->stats_in)
return;
@@ -2158,9 +2247,15 @@ void vp9_rc_get_second_pass_params(VP9_COMP *cpi) {
vp9_clear_system_state();
+ if (is_spatial_svc && twopass->kf_intra_err_min == 0) {
+ twopass->kf_intra_err_min = KF_MB_INTRA_MIN * cpi->common.MBs;
+ twopass->gf_intra_err_min = GF_MB_INTRA_MIN * cpi->common.MBs;
+ }
+
if (cpi->oxcf.end_usage == USAGE_CONSTANT_QUALITY) {
twopass->active_worst_quality = cpi->oxcf.cq_level;
- } else if (cm->current_video_frame == 0) {
+ } else if (cm->current_video_frame == 0 ||
+ (is_spatial_svc && lc->current_video_frame_in_layer == 0)) {
// Special case code for first frame.
const int section_target_bandwidth = (int)(twopass->bits_left /
frames_left);
@@ -2183,6 +2278,11 @@ void vp9_rc_get_second_pass_params(VP9_COMP *cpi) {
// Define next KF group and assign bits to it.
this_frame_copy = this_frame;
find_next_key_frame(cpi, &this_frame_copy);
+ // Don't place key frame in any enhancement layers in spatial svc
+ if (cpi->use_svc && cpi->svc.number_temporal_layers == 1 &&
+ cpi->svc.spatial_layer_id > 0) {
+ cm->frame_type = INTER_FRAME;
+ }
} else {
cm->frame_type = INTER_FRAME;
}