From 6a819ce4fe9e4cc6bd9eed1d19ee90602651ddf5 Mon Sep 17 00:00:00 2001 From: Yunqing Wang Date: Wed, 14 Mar 2012 10:03:39 -0400 Subject: [PATCH] Add motion search skipping in first pass This change added a motion search skipping mechanism similar to what we did in second pass. For a macroblock that is very similar to the macroblock at same location on last frame, we can set its mv to be zero, and skip motion search. This improves first-pass performance for slide shows and video conferencing clips with a slight PSNR loss. Change-Id: Ic73f9ef5604270ddd6d433170091d20361dfe229 --- vp8/encoder/firstpass.c | 28 +++++++++++++++++++++++----- vp8/encoder/lookahead.c | 34 ++++++++++++++++++++++++++-------- vp8/encoder/lookahead.h | 5 ++++- vp8/encoder/onyx_if.c | 22 ++++++++++++++++------ vp8/encoder/onyx_int.h | 2 ++ vp8/encoder/temporal_filter.c | 3 ++- 6 files changed, 73 insertions(+), 21 deletions(-) diff --git a/vp8/encoder/firstpass.c b/vp8/encoder/firstpass.c index cb8fd3e89..ac83622d5 100644 --- a/vp8/encoder/firstpass.c +++ b/vp8/encoder/firstpass.c @@ -387,7 +387,11 @@ void vp8_end_first_pass(VP8_COMP *cpi) output_stats(cpi, cpi->output_pkt_list, &cpi->twopass.total_stats); } -static void zz_motion_search( VP8_COMP *cpi, MACROBLOCK * x, YV12_BUFFER_CONFIG * recon_buffer, int * best_motion_err, int recon_yoffset ) +static void zz_motion_search( VP8_COMP *cpi, MACROBLOCK * x, + YV12_BUFFER_CONFIG * raw_buffer, + int * raw_motion_err, + YV12_BUFFER_CONFIG * recon_buffer, + int * best_motion_err, int recon_yoffset) { MACROBLOCKD * const xd = & x->e_mbd; BLOCK *b = &x->block[0]; @@ -395,15 +399,22 @@ static void zz_motion_search( VP8_COMP *cpi, MACROBLOCK * x, YV12_BUFFER_CONFIG unsigned char *src_ptr = (*(b->base_src) + b->src); int src_stride = b->src_stride; + unsigned char *raw_ptr; + int raw_stride = raw_buffer->y_stride; unsigned char *ref_ptr; int ref_stride = x->e_mbd.pre.y_stride; + // Set up pointers for this macro block raw buffer + raw_ptr = (unsigned char *)(raw_buffer->y_buffer + recon_yoffset + + d->offset); + vp8_mse16x16 ( src_ptr, src_stride, raw_ptr, raw_stride, + (unsigned int *)(raw_motion_err)); + // Set up pointers for this macro block recon buffer xd->pre.y_buffer = recon_buffer->y_buffer + recon_yoffset; - ref_ptr = (unsigned char *)(xd->pre.y_buffer + d->offset ); - - vp8_mse16x16 ( src_ptr, src_stride, ref_ptr, ref_stride, (unsigned int *)(best_motion_err)); + vp8_mse16x16 ( src_ptr, src_stride, ref_ptr, ref_stride, + (unsigned int *)(best_motion_err)); } static void first_pass_motion_search(VP8_COMP *cpi, MACROBLOCK *x, @@ -595,12 +606,18 @@ void vp8_first_pass(VP8_COMP *cpi) MV tmp_mv = {0, 0}; int tmp_err; int motion_error = INT_MAX; + int raw_motion_error = INT_MAX; // Simple 0,0 motion with no mv overhead - zz_motion_search( cpi, x, lst_yv12, &motion_error, recon_yoffset ); + zz_motion_search( cpi, x, cpi->last_frame_unscaled_source, + &raw_motion_error, lst_yv12, &motion_error, + recon_yoffset ); d->bmi.mv.as_mv.row = 0; d->bmi.mv.as_mv.col = 0; + if (raw_motion_error < cpi->oxcf.encode_breakout) + goto skip_motion_search; + // Test last reference frame using the previous best mv as the // starting point (best reference) for the search first_pass_motion_search(cpi, x, &best_ref_mv, @@ -648,6 +665,7 @@ void vp8_first_pass(VP8_COMP *cpi) xd->pre.v_buffer = lst_yv12->v_buffer + recon_uvoffset; } +skip_motion_search: /* Intra assumed best */ best_ref_mv.as_int = 0; diff --git a/vp8/encoder/lookahead.c b/vp8/encoder/lookahead.c index 3e582e369..4c9228186 100644 --- a/vp8/encoder/lookahead.c +++ b/vp8/encoder/lookahead.c @@ -73,6 +73,9 @@ vp8_lookahead_init(unsigned int width, else if(depth > MAX_LAG_BUFFERS) depth = MAX_LAG_BUFFERS; + /* Keep last frame in lookahead buffer by increasing depth by 1.*/ + depth += 1; + /* Align the buffer dimensions */ width = (width + 15) & ~15; height = (height + 15) & ~15; @@ -110,7 +113,7 @@ vp8_lookahead_push(struct lookahead_ctx *ctx, int mb_rows = (src->y_height + 15) >> 4; int mb_cols = (src->y_width + 15) >> 4; - if(ctx->sz + 1 > ctx->max_sz) + if(ctx->sz + 2 > ctx->max_sz) return 1; ctx->sz++; buf = pop(ctx, &ctx->write_idx); @@ -177,7 +180,7 @@ vp8_lookahead_pop(struct lookahead_ctx *ctx, { struct lookahead_entry* buf = NULL; - if(ctx->sz && (drain || ctx->sz == ctx->max_sz)) + if(ctx->sz && (drain || ctx->sz == ctx->max_sz - 1)) { buf = pop(ctx, &ctx->read_idx); ctx->sz--; @@ -188,18 +191,33 @@ vp8_lookahead_pop(struct lookahead_ctx *ctx, struct lookahead_entry* vp8_lookahead_peek(struct lookahead_ctx *ctx, - unsigned int index) + unsigned int index, + int direction) { struct lookahead_entry* buf = NULL; - assert(index < ctx->max_sz); - if(index < ctx->sz) + if (direction == PEEK_FORWARD) + { + assert(index < ctx->max_sz - 1); + if(index < ctx->sz) + { + index += ctx->read_idx; + if(index >= ctx->max_sz) + index -= ctx->max_sz; + buf = ctx->buf + index; + } + } + else if (direction == PEEK_BACKWARD) { - index += ctx->read_idx; - if(index >= ctx->max_sz) - index -= ctx->max_sz; + assert(index == 1); + + if(ctx->read_idx == 0) + index = ctx->max_sz - 1; + else + index = ctx->read_idx - index; buf = ctx->buf + index; } + return buf; } diff --git a/vp8/encoder/lookahead.h b/vp8/encoder/lookahead.h index 32bafcd63..cf56b75b7 100644 --- a/vp8/encoder/lookahead.h +++ b/vp8/encoder/lookahead.h @@ -82,6 +82,8 @@ vp8_lookahead_pop(struct lookahead_ctx *ctx, int drain); +#define PEEK_FORWARD 1 +#define PEEK_BACKWARD -1 /**\brief Get a future source buffer to encode * * \param[in] ctx Pointer to the lookahead context @@ -92,7 +94,8 @@ vp8_lookahead_pop(struct lookahead_ctx *ctx, */ struct lookahead_entry* vp8_lookahead_peek(struct lookahead_ctx *ctx, - unsigned int index); + unsigned int index, + int direction); /**\brief Get the number of frames currently in the lookahead queue diff --git a/vp8/encoder/onyx_if.c b/vp8/encoder/onyx_if.c index dbb7bb368..607b56a2a 100644 --- a/vp8/encoder/onyx_if.c +++ b/vp8/encoder/onyx_if.c @@ -1106,10 +1106,6 @@ void vp8_alloc_compressor_data(VP8_COMP *cpi) width, height, VP8BORDERINPIXELS)) vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR, "Failed to allocate scaled source buffer"); - - - vpx_free(cpi->tok); - { #if CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING unsigned int tokens = 8 * 24 * 16; /* one MB for each thread */ @@ -2934,7 +2930,6 @@ static void Pass1Encode(VP8_COMP *cpi, unsigned long *size, unsigned char *dest, (void) frame_flags; vp8_set_quantizer(cpi, 26); - scale_and_extend_source(cpi->un_scaled_source, cpi); vp8_first_pass(cpi); } #endif @@ -4721,7 +4716,8 @@ int vp8_get_compressed_data(VP8_COMP *cpi, unsigned int *frame_flags, unsigned l cpi->source_alt_ref_pending) { if ((cpi->source = vp8_lookahead_peek(cpi->lookahead, - cpi->frames_till_gf_update_due))) + cpi->frames_till_gf_update_due, + PEEK_FORWARD))) { cpi->alt_ref_source = cpi->source; if (cpi->oxcf.arnr_max_frames > 0) @@ -4743,6 +4739,15 @@ int vp8_get_compressed_data(VP8_COMP *cpi, unsigned int *frame_flags, unsigned l if (!cpi->source) { + /* Read last frame source if we are encoding first pass. */ + if (cpi->pass == 1 && cm->current_video_frame > 0) + { + if((cpi->last_source = vp8_lookahead_peek(cpi->lookahead, 1, + PEEK_BACKWARD)) == NULL) + return -1; + } + + if ((cpi->source = vp8_lookahead_pop(cpi->lookahead, flush))) { cm->show_frame = 1; @@ -4762,6 +4767,11 @@ int vp8_get_compressed_data(VP8_COMP *cpi, unsigned int *frame_flags, unsigned l *time_stamp = cpi->source->ts_start; *time_end = cpi->source->ts_end; *frame_flags = cpi->source->flags; + + if (cpi->pass == 1 && cm->current_video_frame > 0) + { + cpi->last_frame_unscaled_source = &cpi->last_source->img; + } } else { diff --git a/vp8/encoder/onyx_int.h b/vp8/encoder/onyx_int.h index 4b0060ed6..c7a1de8e8 100644 --- a/vp8/encoder/onyx_int.h +++ b/vp8/encoder/onyx_int.h @@ -316,10 +316,12 @@ typedef struct VP8_COMP struct lookahead_ctx *lookahead; struct lookahead_entry *source; struct lookahead_entry *alt_ref_source; + struct lookahead_entry *last_source; YV12_BUFFER_CONFIG *Source; YV12_BUFFER_CONFIG *un_scaled_source; YV12_BUFFER_CONFIG scaled_source; + YV12_BUFFER_CONFIG *last_frame_unscaled_source; int source_alt_ref_pending; // frame in src_buffers has been identified to be encoded as an alt ref int source_alt_ref_active; // an alt ref frame has been encoded and is usable diff --git a/vp8/encoder/temporal_filter.c b/vp8/encoder/temporal_filter.c index 709f6e2b4..7e7def462 100644 --- a/vp8/encoder/temporal_filter.c +++ b/vp8/encoder/temporal_filter.c @@ -525,7 +525,8 @@ void vp8_temporal_filter_prepare_c { int which_buffer = start_frame - frame; struct lookahead_entry* buf = vp8_lookahead_peek(cpi->lookahead, - which_buffer); + which_buffer, + PEEK_FORWARD); cpi->frames[frames_to_blur-1-frame] = &buf->img; } -- 2.40.0