#include "vp9/encoder/vp9_encoder.h"
#include "vp9/encoder/vp9_picklpf.h"
#include "vp9/encoder/vp9_ratectrl.h"
-#include "vp9/encoder/vp9_rdopt.h"
+#include "vp9/encoder/vp9_rd.h"
#include "vp9/encoder/vp9_segmentation.h"
#include "vp9/encoder/vp9_speed_features.h"
#if CONFIG_INTERNAL_STATS
void vp9_coef_tree_initialize();
-#define DEFAULT_INTERP_FILTER SWITCHABLE
-
#define SHARP_FILTER_QTHRESH 0 /* Q threshold for 8-tap sharp filter */
#define ALTREF_HIGH_PRECISION_MV 1 // Whether to use high precision mv
// #define OUTPUT_YUV_REC
+#ifdef OUTPUT_YUV_DENOISED
+FILE *yuv_denoised_file = NULL;
+#endif
#ifdef OUTPUT_YUV_SRC
FILE *yuv_file;
#endif
}
}
-static void set_high_precision_mv(VP9_COMP *cpi, int allow_high_precision_mv) {
+void vp9_set_high_precision_mv(VP9_COMP *cpi, int allow_high_precision_mv) {
MACROBLOCK *const mb = &cpi->mb;
cpi->common.allow_high_precision_mv = allow_high_precision_mv;
if (cpi->common.allow_high_precision_mv) {
}
}
-static void setup_key_frame(VP9_COMP *cpi) {
- vp9_setup_past_independence(&cpi->common);
-
- // All buffers are implicitly updated on key frames.
- cpi->refresh_golden_frame = 1;
- cpi->refresh_alt_ref_frame = 1;
-}
-
-static void setup_inter_frame(VP9_COMMON *cm) {
- if (cm->error_resilient_mode || cm->intra_only)
- vp9_setup_past_independence(cm);
-
- assert(cm->frame_context_idx < FRAME_CONTEXTS);
- cm->fc = cm->frame_contexts[cm->frame_context_idx];
-}
-
static void setup_frame(VP9_COMP *cpi) {
VP9_COMMON *const cm = &cpi->common;
// Set up entropy context depending on frame type. The decoder mandates
// frames where the error_resilient_mode or intra_only flag is set. For
// other inter-frames the encoder currently uses only two contexts;
// context 1 for ALTREF frames and context 0 for the others.
+ if (frame_is_intra_only(cm) || cm->error_resilient_mode) {
+ vp9_setup_past_independence(cm);
+ } else {
+ if (!cpi->use_svc)
+ cm->frame_context_idx = cpi->refresh_alt_ref_frame;
+ }
+
if (cm->frame_type == KEY_FRAME) {
- setup_key_frame(cpi);
+ cpi->refresh_golden_frame = 1;
+ cpi->refresh_alt_ref_frame = 1;
} else {
- if (!cm->intra_only && !cm->error_resilient_mode && !cpi->use_svc)
- cm->frame_context_idx = cpi->refresh_alt_ref_frame;
- setup_inter_frame(cm);
+ cm->fc = cm->frame_contexts[cm->frame_context_idx];
}
}
-
-
void vp9_initialize_enc() {
static int init_done = 0;
if (!init_done) {
vp9_init_neighbors();
- vp9_init_quant_tables();
-
vp9_coef_tree_initialize();
vp9_tokenize_initialize();
vp9_init_me_luts();
vp9_cyclic_refresh_free(cpi->cyclic_refresh);
cpi->cyclic_refresh = NULL;
- vpx_free(cpi->active_map);
- cpi->active_map = NULL;
-
- vp9_free_frame_buffers(cm);
+ vp9_free_ref_frame_buffers(cm);
+ vp9_free_context_buffers(cm);
vp9_free_frame_buffer(&cpi->last_frame_uf);
vp9_free_frame_buffer(&cpi->scaled_source);
vpx_free(cpi->tok);
cpi->tok = 0;
- vp9_free_pc_tree(&cpi->mb);
+ vp9_free_pc_tree(cpi);
for (i = 0; i < cpi->svc.number_spatial_layers; ++i) {
LAYER_CONTEXT *const lc = &cpi->svc.layer_context[i];
lc->rc_twopass_stats_in.buf = NULL;
lc->rc_twopass_stats_in.sz = 0;
}
+
+ if (cpi->source_diff_var != NULL) {
+ vpx_free(cpi->source_diff_var);
+ cpi->source_diff_var = NULL;
+ }
+
+ for (i = 0; i < MAX_LAG_BUFFERS; ++i) {
+ vp9_free_frame_buffer(&cpi->svc.scaled_frames[i]);
+ }
+ vpx_memset(&cpi->svc.scaled_frames[0], 0,
+ MAX_LAG_BUFFERS * sizeof(cpi->svc.scaled_frames[0]));
}
static void save_coding_context(VP9_COMP *cpi) {
// Set rd thresholds based on mode and speed setting
vp9_set_rd_speed_thresholds(cpi);
vp9_set_rd_speed_thresholds_sub8x8(cpi);
-
- cpi->mb.fwd_txm4x4 = vp9_fdct4x4;
- if (cpi->oxcf.lossless || cpi->mb.e_mbd.lossless) {
- cpi->mb.fwd_txm4x4 = vp9_fwht4x4;
- }
}
static void alloc_raw_frame_buffers(VP9_COMP *cpi) {
"Failed to allocate altref buffer");
}
-void vp9_alloc_compressor_data(VP9_COMP *cpi) {
- VP9_COMMON *cm = &cpi->common;
-
- if (vp9_alloc_frame_buffers(cm, cm->width, cm->height))
+static void alloc_ref_frame_buffers(VP9_COMP *cpi) {
+ VP9_COMMON *const cm = &cpi->common;
+ if (vp9_alloc_ref_frame_buffers(cm, cm->width, cm->height))
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
"Failed to allocate frame buffers");
-
- if (vp9_alloc_frame_buffer(&cpi->last_frame_uf,
- cm->width, cm->height,
- cm->subsampling_x, cm->subsampling_y,
- VP9_ENC_BORDER_IN_PIXELS))
- vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
- "Failed to allocate last frame buffer");
-
- if (vp9_alloc_frame_buffer(&cpi->scaled_source,
- cm->width, cm->height,
- cm->subsampling_x, cm->subsampling_y,
- VP9_ENC_BORDER_IN_PIXELS))
- vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
- "Failed to allocate scaled source buffer");
-
- if (vp9_alloc_frame_buffer(&cpi->scaled_last_source,
- cm->width, cm->height,
- cm->subsampling_x, cm->subsampling_y,
- VP9_ENC_BORDER_IN_PIXELS))
- vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
- "Failed to allocate scaled last source buffer");
-
- vpx_free(cpi->tok);
-
- {
- unsigned int tokens = get_token_alloc(cm->mb_rows, cm->mb_cols);
-
- CHECK_MEM_ERROR(cm, cpi->tok, vpx_calloc(tokens, sizeof(*cpi->tok)));
- }
-
- vp9_setup_pc_tree(&cpi->common, &cpi->mb);
}
-static void update_frame_size(VP9_COMP *cpi) {
+static void alloc_util_frame_buffers(VP9_COMP *cpi) {
VP9_COMMON *const cm = &cpi->common;
- MACROBLOCKD *const xd = &cpi->mb.e_mbd;
-
- vp9_update_frame_size(cm);
-
- // Update size of buffers local to this frame
if (vp9_realloc_frame_buffer(&cpi->last_frame_uf,
cm->width, cm->height,
cm->subsampling_x, cm->subsampling_y,
VP9_ENC_BORDER_IN_PIXELS, NULL, NULL, NULL))
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
- "Failed to reallocate last frame buffer");
+ "Failed to allocate last frame buffer");
if (vp9_realloc_frame_buffer(&cpi->scaled_source,
cm->width, cm->height,
cm->subsampling_x, cm->subsampling_y,
VP9_ENC_BORDER_IN_PIXELS, NULL, NULL, NULL))
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
- "Failed to reallocate scaled source buffer");
+ "Failed to allocate scaled source buffer");
if (vp9_realloc_frame_buffer(&cpi->scaled_last_source,
cm->width, cm->height,
cm->subsampling_x, cm->subsampling_y,
VP9_ENC_BORDER_IN_PIXELS, NULL, NULL, NULL))
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
- "Failed to reallocate scaled last source buffer");
+ "Failed to allocate scaled last source buffer");
+}
- {
- int y_stride = cpi->scaled_source.y_stride;
+void vp9_alloc_compressor_data(VP9_COMP *cpi) {
+ VP9_COMMON *cm = &cpi->common;
- if (cpi->sf.search_method == NSTEP) {
- vp9_init3smotion_compensation(&cpi->ss_cfg, y_stride);
- } else if (cpi->sf.search_method == DIAMOND) {
- vp9_init_dsmotion_compensation(&cpi->ss_cfg, y_stride);
- }
+ vp9_alloc_context_buffers(cm, cm->width, cm->height);
+
+ vpx_free(cpi->tok);
+
+ {
+ unsigned int tokens = get_token_alloc(cm->mb_rows, cm->mb_cols);
+ CHECK_MEM_ERROR(cm, cpi->tok, vpx_calloc(tokens, sizeof(*cpi->tok)));
}
+ vp9_setup_pc_tree(&cpi->common, cpi);
+}
+
+static void update_frame_size(VP9_COMP *cpi) {
+ VP9_COMMON *const cm = &cpi->common;
+ MACROBLOCKD *const xd = &cpi->mb.e_mbd;
+
+ vp9_set_mb_mi(cm, cm->width, cm->height);
+ vp9_init_context_buffers(cm);
init_macroblockd(cm, xd);
+
+ if (cpi->use_svc && cpi->svc.number_temporal_layers == 1) {
+ if (vp9_realloc_frame_buffer(&cpi->alt_ref_buffer,
+ cm->width, cm->height,
+ cm->subsampling_x, cm->subsampling_y,
+ VP9_ENC_BORDER_IN_PIXELS, NULL, NULL, NULL))
+ vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
+ "Failed to reallocate alt_ref_buffer");
+ }
}
void vp9_new_framerate(VP9_COMP *cpi, double framerate) {
cm->log2_tile_rows = cpi->oxcf.tile_rows;
}
+static void init_buffer_indices(VP9_COMP *cpi) {
+ cpi->lst_fb_idx = 0;
+ cpi->gld_fb_idx = 1;
+ cpi->alt_fb_idx = 2;
+}
+
static void init_config(struct VP9_COMP *cpi, VP9EncoderConfig *oxcf) {
VP9_COMMON *const cm = &cpi->common;
cm->width = oxcf->width;
cm->height = oxcf->height;
- cm->subsampling_x = 0;
- cm->subsampling_y = 0;
vp9_alloc_compressor_data(cpi);
// Spatial scalability.
cpi->svc.number_temporal_layers = oxcf->ts_number_layers;
if ((cpi->svc.number_temporal_layers > 1 &&
- cpi->oxcf.rc_mode == RC_MODE_CBR) ||
+ cpi->oxcf.rc_mode == VPX_CBR) ||
(cpi->svc.number_spatial_layers > 1 &&
cpi->oxcf.mode == TWO_PASS_SECOND_BEST)) {
vp9_init_layer_context(cpi);
vp9_change_config(cpi, oxcf);
cpi->static_mb_pct = 0;
+ cpi->ref_frame_flags = 0;
- cpi->lst_fb_idx = 0;
- cpi->gld_fb_idx = 1;
- cpi->alt_fb_idx = 2;
+ init_buffer_indices(cpi);
set_tile_limits(cpi);
}
cpi->oxcf = *oxcf;
cpi->pass = get_pass(cpi->oxcf.mode);
- if (cpi->oxcf.mode == REALTIME)
- cpi->oxcf.play_alternate = 0;
-
- cpi->oxcf.lossless = oxcf->lossless;
- if (cpi->oxcf.lossless) {
- // In lossless mode, make sure right quantizer range and correct transform
- // is set.
- cpi->oxcf.worst_allowed_q = 0;
- cpi->oxcf.best_allowed_q = 0;
- cpi->mb.e_mbd.itxm_add = vp9_iwht4x4_add;
- } else {
- cpi->mb.e_mbd.itxm_add = vp9_idct4x4_add;
- }
+
rc->baseline_gf_interval = DEFAULT_GF_INTERVAL;
- cpi->ref_frame_flags = VP9_ALT_FLAG | VP9_GOLD_FLAG | VP9_LAST_FLAG;
cpi->refresh_golden_frame = 0;
cpi->refresh_last_frame = 1;
cm->reset_frame_context = 0;
vp9_reset_segment_features(&cm->seg);
- set_high_precision_mv(cpi, 0);
+ vp9_set_high_precision_mv(cpi, 0);
{
int i;
cpi->encode_breakout = cpi->oxcf.encode_breakout;
// local file playback mode == really big buffer
- if (cpi->oxcf.rc_mode == RC_MODE_VBR) {
- cpi->oxcf.starting_buffer_level = 60000;
- cpi->oxcf.optimal_buffer_level = 60000;
- cpi->oxcf.maximum_buffer_size = 240000;
+ if (cpi->oxcf.rc_mode == VPX_VBR) {
+ cpi->oxcf.starting_buffer_level_ms = 60000;
+ cpi->oxcf.optimal_buffer_level_ms = 60000;
+ cpi->oxcf.maximum_buffer_size_ms = 240000;
}
- // Convert target bandwidth from Kbit/s to Bit/s
- cpi->oxcf.target_bandwidth *= 1000;
-
- cpi->oxcf.starting_buffer_level =
- vp9_rescale(cpi->oxcf.starting_buffer_level,
- cpi->oxcf.target_bandwidth, 1000);
+ rc->starting_buffer_level = vp9_rescale(cpi->oxcf.starting_buffer_level_ms,
+ cpi->oxcf.target_bandwidth, 1000);
// Set or reset optimal and maximum buffer levels.
- if (cpi->oxcf.optimal_buffer_level == 0)
- cpi->oxcf.optimal_buffer_level = cpi->oxcf.target_bandwidth / 8;
+ if (cpi->oxcf.optimal_buffer_level_ms == 0)
+ rc->optimal_buffer_level = cpi->oxcf.target_bandwidth / 8;
else
- cpi->oxcf.optimal_buffer_level =
- vp9_rescale(cpi->oxcf.optimal_buffer_level,
- cpi->oxcf.target_bandwidth, 1000);
+ rc->optimal_buffer_level = vp9_rescale(cpi->oxcf.optimal_buffer_level_ms,
+ cpi->oxcf.target_bandwidth, 1000);
- if (cpi->oxcf.maximum_buffer_size == 0)
- cpi->oxcf.maximum_buffer_size = cpi->oxcf.target_bandwidth / 8;
+ if (cpi->oxcf.maximum_buffer_size_ms == 0)
+ rc->maximum_buffer_size = cpi->oxcf.target_bandwidth / 8;
else
- cpi->oxcf.maximum_buffer_size =
- vp9_rescale(cpi->oxcf.maximum_buffer_size,
- cpi->oxcf.target_bandwidth, 1000);
+ rc->maximum_buffer_size = vp9_rescale(cpi->oxcf.maximum_buffer_size_ms,
+ cpi->oxcf.target_bandwidth, 1000);
// Under a configuration change, where maximum_buffer_size may change,
// keep buffer level clipped to the maximum allowed buffer size.
- rc->bits_off_target = MIN(rc->bits_off_target, cpi->oxcf.maximum_buffer_size);
- rc->buffer_level = MIN(rc->buffer_level, cpi->oxcf.maximum_buffer_size);
+ rc->bits_off_target = MIN(rc->bits_off_target, rc->maximum_buffer_size);
+ rc->buffer_level = MIN(rc->buffer_level, rc->maximum_buffer_size);
// Set up frame rate and related parameters rate control values.
vp9_new_framerate(cpi, cpi->oxcf.framerate);
rc->worst_quality = cpi->oxcf.worst_allowed_q;
rc->best_quality = cpi->oxcf.best_allowed_q;
- cm->interp_filter = DEFAULT_INTERP_FILTER;
+ cm->interp_filter = cpi->sf.default_interp_filter;
cm->display_width = cpi->oxcf.width;
cm->display_height = cpi->oxcf.height;
update_frame_size(cpi);
if ((cpi->svc.number_temporal_layers > 1 &&
- cpi->oxcf.rc_mode == RC_MODE_CBR) ||
+ cpi->oxcf.rc_mode == VPX_CBR) ||
(cpi->svc.number_spatial_layers > 1 && cpi->pass == 2)) {
vp9_update_layer_context_change_config(cpi,
(int)cpi->oxcf.target_bandwidth);
}
-#if CONFIG_MULTIPLE_ARF
- vp9_zero(cpi->alt_ref_source);
-#else
cpi->alt_ref_source = NULL;
-#endif
rc->is_src_frame_alt_ref = 0;
#if 0
cpi->ext_refresh_frame_flags_pending = 0;
cpi->ext_refresh_frame_context_pending = 0;
+
+#if CONFIG_DENOISING
+ if (cpi->oxcf.noise_sensitivity > 0) {
+ vp9_denoiser_alloc(&(cpi->denoiser), cm->width, cm->height,
+ cm->subsampling_x, cm->subsampling_y,
+ VP9_ENC_BORDER_IN_PIXELS);
+ }
+#endif
}
#ifndef M_LOG2_E
VP9_COMP *vp9_create_compressor(VP9EncoderConfig *oxcf) {
- int i, j;
+ unsigned int i, j;
VP9_COMP *const cpi = vpx_memalign(32, sizeof(VP9_COMP));
VP9_COMMON *const cm = cpi != NULL ? &cpi->common : NULL;
cm->current_video_frame = 0;
- // Set reference frame sign bias for ALTREF frame to 1 (for now)
- cm->ref_frame_sign_bias[ALTREF_FRAME] = 1;
-
cpi->gold_is_last = 0;
cpi->alt_is_last = 0;
cpi->gold_is_alt = 0;
+ cpi->skippable_frame = 0;
+
// Create the encoder segmentation map and set all entries to 0
CHECK_MEM_ERROR(cm, cpi->segmentation_map,
vpx_calloc(cm->mi_rows * cm->mi_cols, 1));
CHECK_MEM_ERROR(cm, cpi->coding_context.last_frame_seg_map_copy,
vpx_calloc(cm->mi_rows * cm->mi_cols, 1));
- CHECK_MEM_ERROR(cm, cpi->active_map, vpx_calloc(cm->MBs, 1));
- vpx_memset(cpi->active_map, 1, cm->MBs);
- cpi->active_map_enabled = 0;
-
for (i = 0; i < (sizeof(cpi->mbgraph_stats) /
sizeof(cpi->mbgraph_stats[0])); i++) {
CHECK_MEM_ERROR(cm, cpi->mbgraph_stats[i].mb_stats,
sizeof(*cpi->mbgraph_stats[i].mb_stats), 1));
}
- cpi->refresh_alt_ref_frame = 0;
+#if CONFIG_FP_MB_STATS
+ cpi->use_fp_mb_stats = 0;
+ if (cpi->use_fp_mb_stats) {
+ // a place holder used to store the first pass mb stats in the first pass
+ CHECK_MEM_ERROR(cm, cpi->twopass.frame_mb_stats_buf,
+ vpx_calloc(cm->MBs * sizeof(uint8_t), 1));
+ } else {
+ cpi->twopass.frame_mb_stats_buf = NULL;
+ }
+#endif
-#if CONFIG_MULTIPLE_ARF
- // Turn multiple ARF usage on/off. This is a quick hack for the initial test
- // version. It should eventually be set via the codec API.
- cpi->multi_arf_enabled = 1;
+ cpi->refresh_alt_ref_frame = 0;
- if (cpi->multi_arf_enabled) {
- cpi->sequence_number = 0;
- cpi->frame_coding_order_period = 0;
- vp9_zero(cpi->frame_coding_order);
- vp9_zero(cpi->arf_buffer_idx);
+ // Note that at the moment multi_arf will not work with svc.
+ // For the current check in all the execution paths are defaulted to 0
+ // pending further tuning and testing. The code is left in place here
+ // as a place holder in regard to the required paths.
+ cpi->multi_arf_last_grp_enabled = 0;
+ if (cpi->pass == 2) {
+ if (cpi->use_svc) {
+ cpi->multi_arf_allowed = 0;
+ cpi->multi_arf_enabled = 0;
+ } else {
+ // Disable by default for now.
+ cpi->multi_arf_allowed = 0;
+ cpi->multi_arf_enabled = 0;
+ }
+ } else {
+ cpi->multi_arf_allowed = 0;
+ cpi->multi_arf_enabled = 0;
}
-#endif
cpi->b_calculate_psnr = CONFIG_INTERNAL_STATS;
#if CONFIG_INTERNAL_STATS
cpi->mb.nmvsadcost_hp[1] = &cpi->mb.nmvsadcosts_hp[1][MV_MAX];
cal_nmvsadcosts_hp(cpi->mb.nmvsadcost_hp);
+#if CONFIG_DENOISING
+#ifdef OUTPUT_YUV_DENOISED
+ yuv_denoised_file = fopen("denoised.yuv", "ab");
+#endif
+#endif
#ifdef OUTPUT_YUV_SRC
yuv_file = fopen("bd.yuv", "ab");
#endif
vp9_init_second_pass_spatial_svc(cpi);
} else {
+#if CONFIG_FP_MB_STATS
+ if (cpi->use_fp_mb_stats) {
+ const size_t psz = cpi->common.MBs * sizeof(uint8_t);
+ const int ps = (int)(oxcf->firstpass_mb_stats_in.sz / psz);
+
+ cpi->twopass.firstpass_mb_stats.mb_stats_start =
+ oxcf->firstpass_mb_stats_in.buf;
+ cpi->twopass.firstpass_mb_stats.mb_stats_end =
+ cpi->twopass.firstpass_mb_stats.mb_stats_start +
+ (ps - 1) * cpi->common.MBs * sizeof(uint8_t);
+ }
+#endif
+
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];
set_speed_features(cpi);
+ // Allocate memory to store variances for a frame.
+ CHECK_MEM_ERROR(cm, cpi->source_diff_var,
+ vpx_calloc(cm->MBs, sizeof(diff)));
+ cpi->source_var_thresh = 0;
+ cpi->frames_till_next_var_check = 0;
+
// Default rd threshold factors for mode selection
for (i = 0; i < BLOCK_SIZES; ++i) {
for (j = 0; j < MAX_MODES; ++j)
}
void vp9_remove_compressor(VP9_COMP *cpi) {
- int i;
+ unsigned int i;
if (!cpi)
return;
#endif
}
+#if CONFIG_DENOISING
+ if (cpi->oxcf.noise_sensitivity > 0) {
+ vp9_denoiser_free(&(cpi->denoiser));
+ }
+#endif
+
dealloc_compressor_data(cpi);
vpx_free(cpi->tok);
vpx_free(cpi->mbgraph_stats[i].mb_stats);
}
+#if CONFIG_FP_MB_STATS
+ if (cpi->use_fp_mb_stats) {
+ vpx_free(cpi->twopass.frame_mb_stats_buf);
+ cpi->twopass.frame_mb_stats_buf = NULL;
+ }
+#endif
+
vp9_remove_common(&cpi->common);
vpx_free(cpi);
+#if CONFIG_DENOISING
+#ifdef OUTPUT_YUV_DENOISED
+ fclose(yuv_denoised_file);
+#endif
+#endif
#ifdef OUTPUT_YUV_SRC
fclose(yuv_file);
#endif
}
-#ifdef OUTPUT_YUV_SRC
-void vp9_write_yuv_frame(YV12_BUFFER_CONFIG *s) {
+#if defined(OUTPUT_YUV_SRC)
+void vp9_write_yuv_frame(YV12_BUFFER_CONFIG *s, FILE *f) {
uint8_t *src = s->y_buffer;
int h = s->y_height;
do {
- fwrite(src, s->y_width, 1, yuv_file);
+ fwrite(src, s->y_width, 1, f);
src += s->y_stride;
} while (--h);
h = s->uv_height;
do {
- fwrite(src, s->uv_width, 1, yuv_file);
+ fwrite(src, s->uv_width, 1, f);
src += s->uv_stride;
} while (--h);
h = s->uv_height;
do {
- fwrite(src, s->uv_width, 1, yuv_file);
+ fwrite(src, s->uv_width, 1, f);
src += s->uv_stride;
} while (--h);
}
#endif
+#if CONFIG_DENOISING
+#if defined(OUTPUT_YUV_DENOISED)
+// The denoiser buffer is allocated as a YUV 440 buffer. This function writes it
+// as YUV 420. We simply use the top-left pixels of the UV buffers, since we do
+// not denoise the UV channels at this time. If ever we implement UV channel
+// denoising we will have to modify this.
+void vp9_write_yuv_frame_420(YV12_BUFFER_CONFIG *s, FILE *f) {
+ uint8_t *src = s->y_buffer;
+ int h = s->y_height;
+
+ do {
+ fwrite(src, s->y_width, 1, f);
+ src += s->y_stride;
+ } while (--h);
+
+ src = s->u_buffer;
+ h = s->uv_height / 2;
+
+ do {
+ fwrite(src, s->uv_width / 2, 1, f);
+ src += s->uv_stride + s->uv_width / 2;
+ } while (--h);
+
+ src = s->v_buffer;
+ h = s->uv_height / 2;
+
+ do {
+ fwrite(src, s->uv_width / 2, 1, f);
+ src += s->uv_stride + s->uv_width / 2;
+ } while (--h);
+}
+#endif
+#endif
+
#ifdef OUTPUT_YUV_REC
void vp9_write_yuv_rec_frame(VP9_COMMON *cm) {
YV12_BUFFER_CONFIG *s = cm->frame_to_show;
src += s->uv_stride;
} while (--h);
-#if CONFIG_ALPHA
- if (s->alpha_buffer) {
- src = s->alpha_buffer;
- h = s->alpha_height;
- do {
- fwrite(src, s->alpha_width, 1, yuv_rec_file);
- src += s->alpha_stride;
- } while (--h);
- }
-#endif
-
fflush(yuv_rec_file);
}
#endif
YV12_BUFFER_CONFIG *dst) {
// TODO(dkovalev): replace YV12_BUFFER_CONFIG with vpx_image_t
int i;
- const uint8_t *const srcs[4] = {src->y_buffer, src->u_buffer, src->v_buffer,
- src->alpha_buffer};
- const int src_strides[4] = {src->y_stride, src->uv_stride, src->uv_stride,
- src->alpha_stride};
- const int src_widths[4] = {src->y_crop_width, src->uv_crop_width,
- src->uv_crop_width, src->y_crop_width};
- const int src_heights[4] = {src->y_crop_height, src->uv_crop_height,
- src->uv_crop_height, src->y_crop_height};
- uint8_t *const dsts[4] = {dst->y_buffer, dst->u_buffer, dst->v_buffer,
- dst->alpha_buffer};
- const int dst_strides[4] = {dst->y_stride, dst->uv_stride, dst->uv_stride,
- dst->alpha_stride};
- const int dst_widths[4] = {dst->y_crop_width, dst->uv_crop_width,
- dst->uv_crop_width, dst->y_crop_width};
- const int dst_heights[4] = {dst->y_crop_height, dst->uv_crop_height,
- dst->uv_crop_height, dst->y_crop_height};
+ const uint8_t *const srcs[3] = {src->y_buffer, src->u_buffer, src->v_buffer};
+ const int src_strides[3] = {src->y_stride, src->uv_stride, src->uv_stride};
+ const int src_widths[3] = {src->y_crop_width, src->uv_crop_width,
+ src->uv_crop_width };
+ const int src_heights[3] = {src->y_crop_height, src->uv_crop_height,
+ src->uv_crop_height};
+ uint8_t *const dsts[3] = {dst->y_buffer, dst->u_buffer, dst->v_buffer};
+ const int dst_strides[3] = {dst->y_stride, dst->uv_stride, dst->uv_stride};
+ const int dst_widths[3] = {dst->y_crop_width, dst->uv_crop_width,
+ dst->uv_crop_width};
+ const int dst_heights[3] = {dst->y_crop_height, dst->uv_crop_height,
+ dst->uv_crop_height};
for (i = 0; i < MAX_MB_PLANE; ++i)
vp9_resize_plane(srcs[i], src_heights[i], src_widths[i], src_strides[i],
dsts[i], dst_heights[i], dst_widths[i], dst_strides[i]);
- // TODO(hkuang): Call C version explicitly
- // as neon version only expand border size 32.
- vp8_yv12_extend_frame_borders_c(dst);
+ vp9_extend_frame_borders(dst);
}
static void scale_and_extend_frame(const YV12_BUFFER_CONFIG *src,
const int src_h = src->y_crop_height;
const int dst_w = dst->y_crop_width;
const int dst_h = dst->y_crop_height;
- const uint8_t *const srcs[4] = {src->y_buffer, src->u_buffer, src->v_buffer,
- src->alpha_buffer};
- const int src_strides[4] = {src->y_stride, src->uv_stride, src->uv_stride,
- src->alpha_stride};
- uint8_t *const dsts[4] = {dst->y_buffer, dst->u_buffer, dst->v_buffer,
- dst->alpha_buffer};
- const int dst_strides[4] = {dst->y_stride, dst->uv_stride, dst->uv_stride,
- dst->alpha_stride};
+ const uint8_t *const srcs[3] = {src->y_buffer, src->u_buffer, src->v_buffer};
+ const int src_strides[3] = {src->y_stride, src->uv_stride, src->uv_stride};
+ uint8_t *const dsts[3] = {dst->y_buffer, dst->u_buffer, dst->v_buffer};
+ const int dst_strides[3] = {dst->y_stride, dst->uv_stride, dst->uv_stride};
+ const InterpKernel *const kernel = vp9_get_interp_kernel(EIGHTTAP);
int x, y, i;
for (y = 0; y < dst_h; y += 16) {
uint8_t *dst_ptr = dsts[i] + (y / factor) * dst_stride + (x / factor);
vp9_convolve8(src_ptr, src_stride, dst_ptr, dst_stride,
- vp9_sub_pel_filters_8[x_q4 & 0xf], 16 * src_w / dst_w,
- vp9_sub_pel_filters_8[y_q4 & 0xf], 16 * src_h / dst_h,
+ kernel[x_q4 & 0xf], 16 * src_w / dst_w,
+ kernel[y_q4 & 0xf], 16 * src_h / dst_h,
16 / factor, 16 / factor);
}
}
}
- // TODO(hkuang): Call C version explicitly
- // as neon version only expand border size 32.
- vp8_yv12_extend_frame_borders_c(dst);
-}
-
-static int find_fp_qindex() {
- int i;
-
- for (i = 0; i < QINDEX_RANGE; i++) {
- if (vp9_convert_qindex_to_q(i) >= 30.0) {
- break;
- }
- }
-
- if (i == QINDEX_RANGE)
- i--;
-
- return i;
+ vp9_extend_frame_borders(dst);
}
#define WRITE_RECON_BUFFER 0
if ((rc->projected_frame_size > high_limit && q < maxq) ||
(rc->projected_frame_size < low_limit && q > minq)) {
force_recode = 1;
- } else if (cpi->oxcf.rc_mode == RC_MODE_CONSTRAINED_QUALITY) {
+ } else if (cpi->oxcf.rc_mode == VPX_CQ) {
// Deal with frame undershoot and whether or not we are
// below the automatically set cq level.
if (q > oxcf->cq_level &&
&cm->ref_frame_map[cpi->gld_fb_idx], cm->new_fb_idx);
ref_cnt_fb(cm->frame_bufs,
&cm->ref_frame_map[cpi->alt_fb_idx], cm->new_fb_idx);
- }
-#if CONFIG_MULTIPLE_ARF
- else if (!cpi->multi_arf_enabled && cpi->refresh_golden_frame &&
- !cpi->refresh_alt_ref_frame) {
-#else
- else if (cpi->refresh_golden_frame && !cpi->refresh_alt_ref_frame &&
- !cpi->use_svc) {
-#endif
+ } else if (!cpi->multi_arf_allowed && cpi->refresh_golden_frame &&
+ cpi->rc.is_src_frame_alt_ref && !cpi->use_svc) {
/* Preserve the previously existing golden frame and update the frame in
* the alt ref slot instead. This is highly specific to the current use of
* alt-ref as a forward reference, and this needs to be generalized as
tmp = cpi->alt_fb_idx;
cpi->alt_fb_idx = cpi->gld_fb_idx;
cpi->gld_fb_idx = tmp;
- } else { /* For non key/golden frames */
+ } else { /* For non key/golden frames */
if (cpi->refresh_alt_ref_frame) {
int arf_idx = cpi->alt_fb_idx;
-#if CONFIG_MULTIPLE_ARF
- if (cpi->multi_arf_enabled) {
- arf_idx = cpi->arf_buffer_idx[cpi->sequence_number + 1];
+ if ((cpi->pass == 2) && cpi->multi_arf_allowed) {
+ const GF_GROUP *const gf_group = &cpi->twopass.gf_group;
+ arf_idx = gf_group->arf_update_idx[gf_group->index];
}
-#endif
+
ref_cnt_fb(cm->frame_bufs,
&cm->ref_frame_map[arf_idx], cm->new_fb_idx);
}
ref_cnt_fb(cm->frame_bufs,
&cm->ref_frame_map[cpi->lst_fb_idx], cm->new_fb_idx);
}
+#if CONFIG_DENOISING
+ if (cpi->oxcf.noise_sensitivity > 0) {
+ vp9_denoiser_update_frame_info(&cpi->denoiser,
+ *cpi->Source,
+ cpi->common.frame_type,
+ cpi->refresh_alt_ref_frame,
+ cpi->refresh_golden_frame,
+ cpi->refresh_last_frame);
+ }
+#endif
}
static void loopfilter_frame(VP9_COMP *cpi, VP9_COMMON *cm) {
}
if (lf->filter_level > 0) {
- vp9_loop_filter_frame(cm, xd, lf->filter_level, 0, 0);
+ vp9_loop_filter_frame(cm->frame_to_show, cm, xd, lf->filter_level, 0, 0);
}
vp9_extend_frame_inner_borders(cm->frame_to_show);
void vp9_scale_references(VP9_COMP *cpi) {
VP9_COMMON *cm = &cpi->common;
MV_REFERENCE_FRAME ref_frame;
+ const VP9_REFFRAME ref_mask[3] = {VP9_LAST_FLAG, VP9_GOLD_FLAG, VP9_ALT_FLAG};
for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) {
const int idx = cm->ref_frame_map[get_ref_frame_idx(cpi, ref_frame)];
const YV12_BUFFER_CONFIG *const ref = &cm->frame_bufs[idx].buf;
- if (ref->y_crop_width != cm->width ||
- ref->y_crop_height != cm->height) {
+ // Need to convert from VP9_REFFRAME to index into ref_mask (subtract 1).
+ if ((cpi->ref_frame_flags & ref_mask[ref_frame - 1]) &&
+ (ref->y_crop_width != cm->width || ref->y_crop_height != cm->height)) {
const int new_fb = get_free_fb(cm);
vp9_realloc_frame_buffer(&cm->frame_bufs[new_fb].buf,
cm->width, cm->height,
(cpi->rc.projected_frame_size - cpi->rc.this_frame_target),
cpi->rc.vbr_bits_off_target,
cpi->rc.total_target_vs_actual,
- (cpi->oxcf.starting_buffer_level - cpi->rc.bits_off_target),
+ (cpi->rc.starting_buffer_level - cpi->rc.bits_off_target),
cpi->rc.total_actual_bits, cm->base_qindex,
vp9_convert_qindex_to_q(cm->base_qindex),
(double)vp9_dc_quant(cm->base_qindex, 0) / 4.0,
#endif
static void encode_without_recode_loop(VP9_COMP *cpi,
- size_t *size,
- uint8_t *dest,
int q) {
VP9_COMMON *const cm = &cpi->common;
vp9_clear_system_state();
frame_over_shoot_limit = 1;
}
- if (cpi->oxcf.rc_mode == RC_MODE_CONSTANT_QUALITY) {
+ if (cpi->oxcf.rc_mode == VPX_Q) {
loop = 0;
} else {
if ((cm->frame_type == KEY_FRAME) &&
// 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.
- if (cpi->oxcf.rc_mode == RC_MODE_CONSTRAINED_QUALITY &&
+ if (cpi->oxcf.rc_mode == VPX_CQ &&
q < q_low) {
q_low = q;
}
}
}
+static void configure_skippable_frame(VP9_COMP *cpi) {
+ // If the current frame does not have non-zero motion vector detected in the
+ // first pass, and so do its previous and forward frames, then this frame
+ // can be skipped for partition check, and the partition size is assigned
+ // according to the variance
+
+ SVC *const svc = &cpi->svc;
+ const int is_spatial_svc = (svc->number_spatial_layers > 1) &&
+ (svc->number_temporal_layers == 1);
+ TWO_PASS *const twopass = is_spatial_svc ?
+ &svc->layer_context[svc->spatial_layer_id].twopass
+ : &cpi->twopass;
+
+ cpi->skippable_frame = (!frame_is_intra_only(&cpi->common) &&
+ twopass->stats_in - 2 > twopass->stats_in_start &&
+ twopass->stats_in < twopass->stats_in_end &&
+ (twopass->stats_in - 1)->pcnt_inter - (twopass->stats_in - 1)->pcnt_motion
+ == 1 &&
+ (twopass->stats_in - 2)->pcnt_inter - (twopass->stats_in - 2)->pcnt_motion
+ == 1 &&
+ twopass->stats_in->pcnt_inter - twopass->stats_in->pcnt_motion == 1);
+}
+
+static void set_arf_sign_bias(VP9_COMP *cpi) {
+ VP9_COMMON *const cm = &cpi->common;
+ int arf_sign_bias;
+
+ if ((cpi->pass == 2) && cpi->multi_arf_allowed) {
+ const GF_GROUP *const gf_group = &cpi->twopass.gf_group;
+ arf_sign_bias = cpi->rc.source_alt_ref_active &&
+ (!cpi->refresh_alt_ref_frame ||
+ (gf_group->rf_level[gf_group->index] == GF_ARF_LOW));
+ } else {
+ arf_sign_bias =
+ (cpi->rc.source_alt_ref_active && !cpi->refresh_alt_ref_frame);
+ }
+ cm->ref_frame_sign_bias[ALTREF_FRAME] = arf_sign_bias;
+}
+
static void encode_frame_to_data_rate(VP9_COMP *cpi,
size_t *size,
uint8_t *dest,
cpi->zbin_mode_boost = 0;
cpi->zbin_mode_boost_enabled = 0;
- // Current default encoder behavior for the altref sign bias.
- cm->ref_frame_sign_bias[ALTREF_FRAME] = cpi->rc.source_alt_ref_active;
+ // Set the arf sign bias for this frame.
+ set_arf_sign_bias(cpi);
// Set default state for segment based loop filter update flags.
cm->lf.mode_ref_delta_update = 0;
// Initialize cpi->mv_step_param to default based on max resolution.
- cpi->mv_step_param = vp9_init_search_range(sf, max_mv_def);
+ cpi->mv_step_param = vp9_init_search_range(max_mv_def);
// Initialize cpi->max_mv_magnitude and cpi->mv_step_param if appropriate.
- if (sf->auto_mv_step_size) {
+ if (sf->mv.auto_mv_step_size) {
if (frame_is_intra_only(cm)) {
// Initialize max_mv_magnitude for use in the first INTER frame
// after a key/intra-only frame.
// Allow mv_steps to correspond to twice the max mv magnitude found
// in the previous frame, capped by the default max_mv_magnitude based
// on resolution.
- cpi->mv_step_param = vp9_init_search_range(sf, MIN(max_mv_def, 2 *
+ cpi->mv_step_param = vp9_init_search_range(MIN(max_mv_def, 2 *
cpi->max_mv_magnitude));
cpi->max_mv_magnitude = 0;
}
if (cpi->pass == 2 && cpi->sf.static_segmentation)
configure_static_seg_features(cpi);
+ // Check if the current frame is skippable for the partition search in the
+ // second pass according to the first pass stats
+ if (cpi->pass == 2 &&
+ (!cpi->use_svc || cpi->svc.number_temporal_layers == 1)) {
+ configure_skippable_frame(cpi);
+ }
+
// For 1 pass CBR, check if we are dropping this frame.
// Never drop on key frame.
if (cpi->pass == 0 &&
- cpi->oxcf.rc_mode == RC_MODE_CBR &&
+ cpi->oxcf.rc_mode == VPX_CBR &&
cm->frame_type != KEY_FRAME) {
if (vp9_rc_drop_frame(cpi)) {
vp9_rc_postencode_update_drop_frame(cpi);
vp9_clear_system_state();
- vp9_zero(cpi->rd.tx_select_threshes);
-
#if CONFIG_VP9_POSTPROC
if (cpi->oxcf.noise_sensitivity > 0) {
int l = 0;
#endif
#ifdef OUTPUT_YUV_SRC
- vp9_write_yuv_frame(cpi->Source);
+ vp9_write_yuv_frame(cpi->Source, yuv_file);
#endif
set_speed_features(cpi);
q = vp9_rc_pick_q_and_bounds(cpi, &bottom_index, &top_index);
if (!frame_is_intra_only(cm)) {
- cm->interp_filter = DEFAULT_INTERP_FILTER;
+ cm->interp_filter = cpi->sf.default_interp_filter;
/* TODO: Decide this more intelligently */
- set_high_precision_mv(cpi, q < HIGH_PRECISION_MV_QTHRESH);
+ vp9_set_high_precision_mv(cpi, q < HIGH_PRECISION_MV_QTHRESH);
}
if (cpi->sf.recode_loop == DISALLOW_RECODE) {
- encode_without_recode_loop(cpi, size, dest, q);
+ encode_without_recode_loop(cpi, q);
} else {
encode_with_recode_loop(cpi, size, dest, q, bottom_index, top_index);
}
+#if CONFIG_DENOISING
+#ifdef OUTPUT_YUV_DENOISED
+ if (cpi->oxcf.noise_sensitivity > 0) {
+ vp9_write_yuv_frame_420(&cpi->denoiser.running_avg_y[INTRA_FRAME],
+ yuv_denoised_file);
+ }
+#endif
+#endif
+
+
// Special case code to reduce pulsing when key frames are forced at a
// fixed interval. Note the reconstruction error if it is the frame before
// the force key frame
}
}
-#if 0
- output_frame_level_debug_stats(cpi);
-#endif
if (cpi->refresh_golden_frame == 1)
cpi->frame_flags |= FRAMEFLAGS_GOLDEN;
else
cm->last_frame_type = cm->frame_type;
vp9_rc_postencode_update(cpi, *size);
+#if 0
+ output_frame_level_debug_stats(cpi);
+#endif
+
if (cm->frame_type == KEY_FRAME) {
// Tell the caller that the frame was coded as a key frame
*frame_flags = cpi->frame_flags | FRAMEFLAGS_KEY;
-
-#if CONFIG_MULTIPLE_ARF
- // Reset the sequence number.
- if (cpi->multi_arf_enabled) {
- cpi->sequence_number = 0;
- cpi->frame_coding_order_period = cpi->new_frame_coding_order_period;
- cpi->new_frame_coding_order_period = -1;
- }
-#endif
} else {
*frame_flags = cpi->frame_flags & ~FRAMEFLAGS_KEY;
-
-#if CONFIG_MULTIPLE_ARF
- /* Increment position in the coded frame sequence. */
- if (cpi->multi_arf_enabled) {
- ++cpi->sequence_number;
- if (cpi->sequence_number >= cpi->frame_coding_order_period) {
- cpi->sequence_number = 0;
- cpi->frame_coding_order_period = cpi->new_frame_coding_order_period;
- cpi->new_frame_coding_order_period = -1;
- }
- cpi->this_frame_weight = cpi->arf_weight[cpi->sequence_number];
- assert(cpi->this_frame_weight >= 0);
- }
-#endif
}
// Clear the one shot update flags for segmentation map and mode/ref loop
static void Pass0Encode(VP9_COMP *cpi, size_t *size, uint8_t *dest,
unsigned int *frame_flags) {
- if (cpi->oxcf.rc_mode == RC_MODE_CBR) {
+ if (cpi->oxcf.rc_mode == VPX_CBR) {
vp9_rc_get_one_pass_cbr_params(cpi);
} else {
vp9_rc_get_one_pass_vbr_params(cpi);
encode_frame_to_data_rate(cpi, size, dest, frame_flags);
}
-static void Pass1Encode(VP9_COMP *cpi, size_t *size, uint8_t *dest,
- unsigned int *frame_flags) {
- (void) size;
- (void) dest;
- (void) frame_flags;
-
- vp9_rc_get_first_pass_params(cpi);
- vp9_set_quantizer(&cpi->common, find_fp_qindex());
- vp9_first_pass(cpi);
-}
-
static void Pass2Encode(VP9_COMP *cpi, size_t *size,
uint8_t *dest, unsigned int *frame_flags) {
cpi->allow_encode_breakout = ENCODE_BREAKOUT_ENABLED;
vp9_twopass_postencode_update(cpi);
}
+static void init_motion_estimation(VP9_COMP *cpi) {
+ int y_stride = cpi->scaled_source.y_stride;
+
+ if (cpi->sf.mv.search_method == NSTEP) {
+ vp9_init3smotion_compensation(&cpi->ss_cfg, y_stride);
+ } else if (cpi->sf.mv.search_method == DIAMOND) {
+ vp9_init_dsmotion_compensation(&cpi->ss_cfg, y_stride);
+ }
+}
+
static void check_initial_width(VP9_COMP *cpi, int subsampling_x,
int subsampling_y) {
VP9_COMMON *const cm = &cpi->common;
if (!cpi->initial_width) {
cm->subsampling_x = subsampling_x;
cm->subsampling_y = subsampling_y;
+
alloc_raw_frame_buffers(cpi);
+ alloc_ref_frame_buffers(cpi);
+ alloc_util_frame_buffers(cpi);
+
+ init_motion_estimation(cpi);
+
cpi->initial_width = cm->width;
cpi->initial_height = cm->height;
}
const int subsampling_y = sd->uv_height < sd->y_height;
check_initial_width(cpi, subsampling_x, subsampling_y);
+
vpx_usec_timer_start(&timer);
- if (vp9_lookahead_push(cpi->lookahead,
- sd, time_stamp, end_time, frame_flags))
+
+#if CONFIG_SPATIAL_SVC
+ if (cpi->use_svc && cpi->svc.number_temporal_layers == 1)
+ res = vp9_svc_lookahead_push(cpi, cpi->lookahead, sd, time_stamp, end_time,
+ frame_flags);
+ else
+#endif
+ res = vp9_lookahead_push(cpi->lookahead,
+ sd, time_stamp, end_time, frame_flags);
+ if (res)
res = -1;
vpx_usec_timer_mark(&timer);
cpi->time_receive_data += vpx_usec_timer_elapsed(&timer);
cm->seg.update_data;
}
-#if CONFIG_MULTIPLE_ARF
-int is_next_frame_arf(VP9_COMP *cpi) {
- // Negative entry in frame_coding_order indicates an ARF at this position.
- return cpi->frame_coding_order[cpi->sequence_number + 1] < 0 ? 1 : 0;
-}
-#endif
-
void adjust_frame_rate(VP9_COMP *cpi) {
int64_t this_duration;
int step = 0;
cpi->last_end_time_stamp_seen = cpi->source->ts_end;
}
+// Returns 0 if this is not an alt ref else the offset of the source frame
+// used as the arf midpoint.
+static int get_arf_src_index(VP9_COMP *cpi) {
+ RATE_CONTROL *const rc = &cpi->rc;
+ int arf_src_index = 0;
+ if (is_altref_enabled(cpi)) {
+ if (cpi->pass == 2) {
+ const GF_GROUP *const gf_group = &cpi->twopass.gf_group;
+ if (gf_group->update_type[gf_group->index] == ARF_UPDATE) {
+ arf_src_index = gf_group->arf_src_offset[gf_group->index];
+ }
+ } else if (rc->source_alt_ref_pending) {
+ arf_src_index = rc->frames_till_gf_update_due;
+ }
+ }
+ return arf_src_index;
+}
+
+static void check_src_altref(VP9_COMP *cpi) {
+ RATE_CONTROL *const rc = &cpi->rc;
+
+ if (cpi->pass == 2) {
+ const GF_GROUP *const gf_group = &cpi->twopass.gf_group;
+ rc->is_src_frame_alt_ref =
+ (gf_group->update_type[gf_group->index] == OVERLAY_UPDATE);
+ } else {
+ rc->is_src_frame_alt_ref = cpi->alt_ref_source &&
+ (cpi->source == cpi->alt_ref_source);
+ }
+
+ if (rc->is_src_frame_alt_ref) {
+ // Current frame is an ARF overlay frame.
+ cpi->alt_ref_source = NULL;
+
+ // Don't refresh the last buffer for an ARF overlay frame. It will
+ // become the GF so preserve last as an alternative prediction option.
+ cpi->refresh_last_frame = 0;
+ }
+}
+
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) {
struct vpx_usec_timer cmptimer;
YV12_BUFFER_CONFIG *force_src_buffer = NULL;
MV_REFERENCE_FRAME ref_frame;
+ int arf_src_index;
+ const int is_spatial_svc = cpi->use_svc &&
+ (cpi->svc.number_temporal_layers == 1) &&
+ (cpi->svc.number_spatial_layers > 1);
if (!cpi)
return -1;
- if (cpi->svc.number_spatial_layers > 1 && cpi->pass == 2) {
+ if (is_spatial_svc && cpi->pass == 2) {
+#if CONFIG_SPATIAL_SVC
+ vp9_svc_lookahead_peek(cpi, cpi->lookahead, 0, 1);
+#endif
vp9_restore_layer_context(cpi);
}
cpi->source = NULL;
cpi->last_source = NULL;
- set_high_precision_mv(cpi, ALTREF_HIGH_PRECISION_MV);
+ vp9_set_high_precision_mv(cpi, ALTREF_HIGH_PRECISION_MV);
// Normal defaults
cm->reset_frame_context = 0;
cpi->refresh_golden_frame = 0;
cpi->refresh_alt_ref_frame = 0;
- // Should we code an alternate reference frame.
- if (cpi->oxcf.play_alternate && rc->source_alt_ref_pending) {
- int frames_to_arf;
-
-#if CONFIG_MULTIPLE_ARF
- assert(!cpi->multi_arf_enabled ||
- cpi->frame_coding_order[cpi->sequence_number] < 0);
+ // Should we encode an arf frame.
+ arf_src_index = get_arf_src_index(cpi);
+ if (arf_src_index) {
+ assert(arf_src_index <= rc->frames_to_key);
- if (cpi->multi_arf_enabled && (cpi->pass == 2))
- frames_to_arf = (-cpi->frame_coding_order[cpi->sequence_number])
- - cpi->next_frame_in_order;
+#if CONFIG_SPATIAL_SVC
+ if (is_spatial_svc)
+ cpi->source = vp9_svc_lookahead_peek(cpi, cpi->lookahead,
+ arf_src_index, 0);
else
#endif
- frames_to_arf = rc->frames_till_gf_update_due;
-
- assert(frames_to_arf <= rc->frames_to_key);
-
- if ((cpi->source = vp9_lookahead_peek(cpi->lookahead, frames_to_arf))) {
-#if CONFIG_MULTIPLE_ARF
- cpi->alt_ref_source[cpi->arf_buffered] = cpi->source;
-#else
+ cpi->source = vp9_lookahead_peek(cpi->lookahead, arf_src_index);
+ if (cpi->source != NULL) {
cpi->alt_ref_source = cpi->source;
+
+#if CONFIG_SPATIAL_SVC
+ if (is_spatial_svc && cpi->svc.spatial_layer_id > 0) {
+ int i;
+ // Reference a hidden frame from a lower layer
+ for (i = cpi->svc.spatial_layer_id - 1; i >= 0; --i) {
+ if (cpi->oxcf.ss_play_alternate[i]) {
+ cpi->gld_fb_idx = cpi->svc.layer_context[i].alt_ref_idx;
+ break;
+ }
+ }
+ }
+ cpi->svc.layer_context[cpi->svc.spatial_layer_id].has_alt_frame = 1;
#endif
if (cpi->oxcf.arnr_max_frames > 0) {
// Produce the filtered ARF frame.
- // TODO(agrange) merge these two functions.
- vp9_configure_arnr_filter(cpi, frames_to_arf, rc->gfu_boost);
- vp9_temporal_filter_prepare(cpi, frames_to_arf);
+ vp9_temporal_filter(cpi, arf_src_index);
vp9_extend_frame_borders(&cpi->alt_ref_buffer);
force_src_buffer = &cpi->alt_ref_buffer;
}
cpi->refresh_golden_frame = 0;
cpi->refresh_last_frame = 0;
rc->is_src_frame_alt_ref = 0;
-
-#if CONFIG_MULTIPLE_ARF
- if (!cpi->multi_arf_enabled)
-#endif
- rc->source_alt_ref_pending = 0;
+ rc->source_alt_ref_pending = 0;
} else {
rc->source_alt_ref_pending = 0;
}
}
if (!cpi->source) {
-#if CONFIG_MULTIPLE_ARF
- int i;
-#endif
-
// Get last frame source.
if (cm->current_video_frame > 0) {
- if ((cpi->last_source = vp9_lookahead_peek(cpi->lookahead, -1)) == NULL)
+#if CONFIG_SPATIAL_SVC
+ if (is_spatial_svc)
+ cpi->last_source = vp9_svc_lookahead_peek(cpi, cpi->lookahead, -1, 0);
+ else
+#endif
+ cpi->last_source = vp9_lookahead_peek(cpi->lookahead, -1);
+ if (cpi->last_source == NULL)
return -1;
}
- if ((cpi->source = vp9_lookahead_pop(cpi->lookahead, flush))) {
+ // Read in the source frame.
+#if CONFIG_SPATIAL_SVC
+ if (is_spatial_svc)
+ cpi->source = vp9_svc_lookahead_pop(cpi, cpi->lookahead, flush);
+ else
+#endif
+ cpi->source = vp9_lookahead_pop(cpi->lookahead, flush);
+ if (cpi->source != NULL) {
cm->show_frame = 1;
cm->intra_only = 0;
-#if CONFIG_MULTIPLE_ARF
- // Is this frame the ARF overlay.
- rc->is_src_frame_alt_ref = 0;
- for (i = 0; i < cpi->arf_buffered; ++i) {
- if (cpi->source == cpi->alt_ref_source[i]) {
- rc->is_src_frame_alt_ref = 1;
- cpi->refresh_golden_frame = 1;
- break;
- }
- }
-#else
- rc->is_src_frame_alt_ref = cpi->alt_ref_source &&
- (cpi->source == cpi->alt_ref_source);
-#endif
- if (rc->is_src_frame_alt_ref) {
- // Current frame is an ARF overlay frame.
-#if CONFIG_MULTIPLE_ARF
- cpi->alt_ref_source[i] = NULL;
-#else
- cpi->alt_ref_source = NULL;
-#endif
- // Don't refresh the last buffer for an ARF overlay frame. It will
- // become the GF so preserve last as an alternative prediction option.
- cpi->refresh_last_frame = 0;
- }
-#if CONFIG_MULTIPLE_ARF
- ++cpi->next_frame_in_order;
-#endif
+ // Check to see if the frame should be encoded as an arf overlay.
+ check_src_altref(cpi);
}
}
cpi->un_scaled_source = cpi->Source = force_src_buffer ? force_src_buffer
: &cpi->source->img;
- if (cpi->last_source != NULL) {
- cpi->unscaled_last_source = &cpi->last_source->img;
- } else {
- cpi->unscaled_last_source = NULL;
- }
+ if (cpi->last_source != NULL) {
+ cpi->unscaled_last_source = &cpi->last_source->img;
+ } else {
+ cpi->unscaled_last_source = NULL;
+ }
*time_stamp = cpi->source->ts_start;
*time_end = cpi->source->ts_end;
- *frame_flags = cpi->source->flags;
+ *frame_flags =
+ (cpi->source->flags & VPX_EFLAG_FORCE_KF) ? FRAMEFLAGS_KEY : 0;
-#if CONFIG_MULTIPLE_ARF
- if (cm->frame_type != KEY_FRAME && cpi->pass == 2)
- rc->source_alt_ref_pending = is_next_frame_arf(cpi);
-#endif
} else {
*size = 0;
if (flush && cpi->pass == 1 && !cpi->twopass.first_pass_done) {
cpi->last_end_time_stamp_seen = cpi->source->ts_start;
}
+ // Clear down mmx registers
+ vp9_clear_system_state();
+
// adjust frame rates based on timestamps given
if (cm->show_frame) {
adjust_frame_rate(cpi);
}
if (cpi->svc.number_temporal_layers > 1 &&
- cpi->oxcf.rc_mode == RC_MODE_CBR) {
+ cpi->oxcf.rc_mode == VPX_CBR) {
vp9_update_temporal_layer_framerate(cpi);
vp9_restore_layer_context(cpi);
}
// start with a 0 size frame
*size = 0;
- // Clear down mmx registers
- vp9_clear_system_state();
-
/* find a free buffer for the new frame, releasing the reference previously
* held.
*/
cm->frame_bufs[cm->new_fb_idx].ref_count--;
cm->new_fb_idx = get_free_fb(cm);
-#if CONFIG_MULTIPLE_ARF
- /* Set up the correct ARF frame. */
- if (cpi->refresh_alt_ref_frame) {
- ++cpi->arf_buffered;
- }
- if (cpi->multi_arf_enabled && (cm->frame_type != KEY_FRAME) &&
- (cpi->pass == 2)) {
- cpi->alt_fb_idx = cpi->arf_buffer_idx[cpi->sequence_number];
+ if (!cpi->use_svc && cpi->multi_arf_allowed) {
+ if (cm->frame_type == KEY_FRAME) {
+ init_buffer_indices(cpi);
+ } else if (cpi->pass == 2) {
+ const GF_GROUP *const gf_group = &cpi->twopass.gf_group;
+ cpi->alt_fb_idx = gf_group->arf_ref_idx[gf_group->index];
+ }
}
-#endif
cpi->frame_flags = *frame_flags;
if (cpi->pass == 2 &&
cm->current_video_frame == 0 &&
cpi->oxcf.allow_spatial_resampling &&
- cpi->oxcf.rc_mode == RC_MODE_VBR) {
+ cpi->oxcf.rc_mode == VPX_VBR) {
// Internal scaling is triggered on the first frame.
vp9_set_size_literal(cpi, cpi->oxcf.scaled_frame_width,
cpi->oxcf.scaled_frame_height);
cm->subsampling_x, cm->subsampling_y,
VP9_ENC_BORDER_IN_PIXELS, NULL, NULL, NULL);
+ alloc_util_frame_buffers(cpi);
+ init_motion_estimation(cpi);
+
for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) {
const int idx = cm->ref_frame_map[get_ref_frame_idx(cpi, ref_frame)];
YV12_BUFFER_CONFIG *const buf = &cm->frame_bufs[idx].buf;
if (cpi->pass == 1 &&
(!cpi->use_svc || cpi->svc.number_temporal_layers == 1)) {
- Pass1Encode(cpi, size, dest, frame_flags);
+ const int lossless = is_lossless_requested(&cpi->oxcf);
+ cpi->mb.fwd_txm4x4 = lossless ? vp9_fwht4x4 : vp9_fdct4x4;
+ cpi->mb.itxm_add = lossless ? vp9_iwht4x4_add : vp9_idct4x4_add;
+ vp9_first_pass(cpi);
} else if (cpi->pass == 2 &&
(!cpi->use_svc || cpi->svc.number_temporal_layers == 1)) {
Pass2Encode(cpi, size, dest, frame_flags);
// Save layer specific state.
if ((cpi->svc.number_temporal_layers > 1 &&
- cpi->oxcf.rc_mode == RC_MODE_CBR) ||
+ cpi->oxcf.rc_mode == VPX_CBR) ||
(cpi->svc.number_spatial_layers > 1 && cpi->pass == 2)) {
vp9_save_layer_context(cpi);
}
PSNR_STATS psnr2;
double frame_ssim2 = 0, weight = 0;
#if CONFIG_VP9_POSTPROC
+ // TODO(agrange) Add resizing of post-proc buffer in here when the
+ // encoder is changed to use on-demand buffer allocation.
vp9_deblock(cm->frame_to_show, &cm->post_proc_buffer,
cm->lf.filter_level * 10 / 6);
#endif
int vp9_get_preview_raw_frame(VP9_COMP *cpi, YV12_BUFFER_CONFIG *dest,
vp9_ppflags_t *flags) {
VP9_COMMON *cm = &cpi->common;
+#if !CONFIG_VP9_POSTPROC
+ (void)flags;
+#endif
if (!cm->show_frame) {
return -1;
#if CONFIG_VP9_POSTPROC
ret = vp9_post_proc_frame(cm, dest, flags);
#else
-
if (cm->frame_to_show) {
*dest = *cm->frame_to_show;
dest->y_width = cm->width;
} else {
ret = -1;
}
-
#endif // !CONFIG_VP9_POSTPROC
vp9_clear_system_state();
return ret;
}
}
-int vp9_set_roimap(VP9_COMP *cpi, unsigned char *map, unsigned int rows,
- unsigned int cols, int delta_q[MAX_SEGMENTS],
- int delta_lf[MAX_SEGMENTS],
- unsigned int threshold[MAX_SEGMENTS]) {
- signed char feature_data[SEG_LVL_MAX][MAX_SEGMENTS];
- struct segmentation *seg = &cpi->common.seg;
- const VP9_COMMON *const cm = &cpi->common;
- int i;
-
- if (cm->mb_rows != rows || cm->mb_cols != cols)
- return -1;
-
- if (!map) {
- vp9_disable_segmentation(seg);
- return 0;
- }
-
- vpx_memcpy(cpi->segmentation_map, map, cm->mi_rows * cm->mi_cols);
-
- // Activate segmentation.
- vp9_enable_segmentation(seg);
-
- // Set up the quant, LF and breakout threshold segment data
- for (i = 0; i < MAX_SEGMENTS; i++) {
- feature_data[SEG_LVL_ALT_Q][i] = delta_q[i];
- feature_data[SEG_LVL_ALT_LF][i] = delta_lf[i];
- cpi->segment_encode_breakout[i] = threshold[i];
- }
-
- // Enable the loop and quant changes in the feature mask
- for (i = 0; i < MAX_SEGMENTS; i++) {
- if (delta_q[i])
- vp9_enable_segfeature(seg, i, SEG_LVL_ALT_Q);
- else
- vp9_disable_segfeature(seg, i, SEG_LVL_ALT_Q);
-
- if (delta_lf[i])
- vp9_enable_segfeature(seg, i, SEG_LVL_ALT_LF);
- else
- vp9_disable_segfeature(seg, i, SEG_LVL_ALT_LF);
- }
-
- // Initialize the feature data structure
- // SEGMENT_DELTADATA 0, SEGMENT_ABSDATA 1
- vp9_set_segment_data(seg, &feature_data[0][0], SEGMENT_DELTADATA);
-
- return 0;
-}
-
-int vp9_set_active_map(VP9_COMP *cpi, unsigned char *map,
- unsigned int rows, unsigned int cols) {
+int vp9_set_active_map(VP9_COMP *cpi, unsigned char *map, int rows, int cols) {
if (rows == cpi->common.mb_rows && cols == cpi->common.mb_cols) {
+ const int mi_rows = cpi->common.mi_rows;
+ const int mi_cols = cpi->common.mi_cols;
if (map) {
- vpx_memcpy(cpi->active_map, map, rows * cols);
- cpi->active_map_enabled = 1;
+ int r, c;
+ for (r = 0; r < mi_rows; r++) {
+ for (c = 0; c < mi_cols; c++) {
+ cpi->segmentation_map[r * mi_cols + c] =
+ !map[(r >> 1) * cols + (c >> 1)];
+ }
+ }
+ vp9_enable_segfeature(&cpi->common.seg, 1, SEG_LVL_SKIP);
+ vp9_enable_segmentation(&cpi->common.seg);
} else {
- cpi->active_map_enabled = 0;
+ vp9_disable_segmentation(&cpi->common.seg);
}
-
return 0;
} else {
- // cpi->active_map_enabled = 0;
return -1;
}
}
// always go to the next whole number
cm->width = (hs - 1 + cpi->oxcf.width * hr) / hs;
cm->height = (vs - 1 + cpi->oxcf.height * vr) / vs;
-
assert(cm->width <= cpi->initial_width);
assert(cm->height <= cpi->initial_height);
+
update_frame_size(cpi);
+
return 0;
}
printf("Warning: Desired height too large, changed to %d\n", cm->height);
}
}
-
assert(cm->width <= cpi->initial_width);
assert(cm->height <= cpi->initial_height);
+
update_frame_size(cpi);
+
return 0;
}
int vp9_get_quantizer(VP9_COMP *cpi) {
return cpi->common.base_qindex;
}
+
+void vp9_apply_encoding_flags(VP9_COMP *cpi, vpx_enc_frame_flags_t flags) {
+ if (flags & (VP8_EFLAG_NO_REF_LAST | VP8_EFLAG_NO_REF_GF |
+ VP8_EFLAG_NO_REF_ARF)) {
+ int ref = 7;
+
+ if (flags & VP8_EFLAG_NO_REF_LAST)
+ ref ^= VP9_LAST_FLAG;
+
+ if (flags & VP8_EFLAG_NO_REF_GF)
+ ref ^= VP9_GOLD_FLAG;
+
+ if (flags & VP8_EFLAG_NO_REF_ARF)
+ ref ^= VP9_ALT_FLAG;
+
+ vp9_use_as_reference(cpi, ref);
+ }
+
+ if (flags & (VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF |
+ VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_FORCE_GF |
+ VP8_EFLAG_FORCE_ARF)) {
+ int upd = 7;
+
+ if (flags & VP8_EFLAG_NO_UPD_LAST)
+ upd ^= VP9_LAST_FLAG;
+
+ if (flags & VP8_EFLAG_NO_UPD_GF)
+ upd ^= VP9_GOLD_FLAG;
+
+ if (flags & VP8_EFLAG_NO_UPD_ARF)
+ upd ^= VP9_ALT_FLAG;
+
+ vp9_update_reference(cpi, upd);
+ }
+
+ if (flags & VP8_EFLAG_NO_UPD_ENTROPY) {
+ vp9_update_entropy(cpi, 0);
+ }
+}