Commit 6a819ce4 authored by Yunqing Wang's avatar Yunqing Wang

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
parent 6b7cf307
...@@ -387,7 +387,11 @@ void vp8_end_first_pass(VP8_COMP *cpi) ...@@ -387,7 +387,11 @@ void vp8_end_first_pass(VP8_COMP *cpi)
output_stats(cpi, cpi->output_pkt_list, &cpi->twopass.total_stats); 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; MACROBLOCKD * const xd = & x->e_mbd;
BLOCK *b = &x->block[0]; BLOCK *b = &x->block[0];
...@@ -395,15 +399,22 @@ static void zz_motion_search( VP8_COMP *cpi, MACROBLOCK * x, YV12_BUFFER_CONFIG ...@@ -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); unsigned char *src_ptr = (*(b->base_src) + b->src);
int src_stride = b->src_stride; int src_stride = b->src_stride;
unsigned char *raw_ptr;
int raw_stride = raw_buffer->y_stride;
unsigned char *ref_ptr; unsigned char *ref_ptr;
int ref_stride = x->e_mbd.pre.y_stride; 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 // Set up pointers for this macro block recon buffer
xd->pre.y_buffer = recon_buffer->y_buffer + recon_yoffset; xd->pre.y_buffer = recon_buffer->y_buffer + recon_yoffset;
ref_ptr = (unsigned char *)(xd->pre.y_buffer + d->offset ); ref_ptr = (unsigned char *)(xd->pre.y_buffer + d->offset );
vp8_mse16x16 ( src_ptr, src_stride, ref_ptr, ref_stride,
vp8_mse16x16 ( src_ptr, src_stride, ref_ptr, ref_stride, (unsigned int *)(best_motion_err)); (unsigned int *)(best_motion_err));
} }
static void first_pass_motion_search(VP8_COMP *cpi, MACROBLOCK *x, static void first_pass_motion_search(VP8_COMP *cpi, MACROBLOCK *x,
...@@ -595,12 +606,18 @@ void vp8_first_pass(VP8_COMP *cpi) ...@@ -595,12 +606,18 @@ void vp8_first_pass(VP8_COMP *cpi)
MV tmp_mv = {0, 0}; MV tmp_mv = {0, 0};
int tmp_err; int tmp_err;
int motion_error = INT_MAX; int motion_error = INT_MAX;
int raw_motion_error = INT_MAX;
// Simple 0,0 motion with no mv overhead // 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.row = 0;
d->bmi.mv.as_mv.col = 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 // Test last reference frame using the previous best mv as the
// starting point (best reference) for the search // starting point (best reference) for the search
first_pass_motion_search(cpi, x, &best_ref_mv, first_pass_motion_search(cpi, x, &best_ref_mv,
...@@ -648,6 +665,7 @@ void vp8_first_pass(VP8_COMP *cpi) ...@@ -648,6 +665,7 @@ void vp8_first_pass(VP8_COMP *cpi)
xd->pre.v_buffer = lst_yv12->v_buffer + recon_uvoffset; xd->pre.v_buffer = lst_yv12->v_buffer + recon_uvoffset;
} }
skip_motion_search:
/* Intra assumed best */ /* Intra assumed best */
best_ref_mv.as_int = 0; best_ref_mv.as_int = 0;
......
...@@ -73,6 +73,9 @@ vp8_lookahead_init(unsigned int width, ...@@ -73,6 +73,9 @@ vp8_lookahead_init(unsigned int width,
else if(depth > MAX_LAG_BUFFERS) else if(depth > MAX_LAG_BUFFERS)
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 */ /* Align the buffer dimensions */
width = (width + 15) & ~15; width = (width + 15) & ~15;
height = (height + 15) & ~15; height = (height + 15) & ~15;
...@@ -110,7 +113,7 @@ vp8_lookahead_push(struct lookahead_ctx *ctx, ...@@ -110,7 +113,7 @@ vp8_lookahead_push(struct lookahead_ctx *ctx,
int mb_rows = (src->y_height + 15) >> 4; int mb_rows = (src->y_height + 15) >> 4;
int mb_cols = (src->y_width + 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; return 1;
ctx->sz++; ctx->sz++;
buf = pop(ctx, &ctx->write_idx); buf = pop(ctx, &ctx->write_idx);
...@@ -177,7 +180,7 @@ vp8_lookahead_pop(struct lookahead_ctx *ctx, ...@@ -177,7 +180,7 @@ vp8_lookahead_pop(struct lookahead_ctx *ctx,
{ {
struct lookahead_entry* buf = NULL; 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); buf = pop(ctx, &ctx->read_idx);
ctx->sz--; ctx->sz--;
...@@ -188,18 +191,33 @@ vp8_lookahead_pop(struct lookahead_ctx *ctx, ...@@ -188,18 +191,33 @@ vp8_lookahead_pop(struct lookahead_ctx *ctx,
struct lookahead_entry* struct lookahead_entry*
vp8_lookahead_peek(struct lookahead_ctx *ctx, vp8_lookahead_peek(struct lookahead_ctx *ctx,
unsigned int index) unsigned int index,
int direction)
{ {
struct lookahead_entry* buf = NULL; struct lookahead_entry* buf = NULL;
assert(index < ctx->max_sz); if (direction == PEEK_FORWARD)
if(index < ctx->sz) {
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; assert(index == 1);
if(index >= ctx->max_sz)
index -= ctx->max_sz; if(ctx->read_idx == 0)
index = ctx->max_sz - 1;
else
index = ctx->read_idx - index;
buf = ctx->buf + index; buf = ctx->buf + index;
} }
return buf; return buf;
} }
......
...@@ -82,6 +82,8 @@ vp8_lookahead_pop(struct lookahead_ctx *ctx, ...@@ -82,6 +82,8 @@ vp8_lookahead_pop(struct lookahead_ctx *ctx,
int drain); int drain);
#define PEEK_FORWARD 1
#define PEEK_BACKWARD -1
/**\brief Get a future source buffer to encode /**\brief Get a future source buffer to encode
* *
* \param[in] ctx Pointer to the lookahead context * \param[in] ctx Pointer to the lookahead context
...@@ -92,7 +94,8 @@ vp8_lookahead_pop(struct lookahead_ctx *ctx, ...@@ -92,7 +94,8 @@ vp8_lookahead_pop(struct lookahead_ctx *ctx,
*/ */
struct lookahead_entry* struct lookahead_entry*
vp8_lookahead_peek(struct lookahead_ctx *ctx, 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 /**\brief Get the number of frames currently in the lookahead queue
......
...@@ -1106,10 +1106,6 @@ void vp8_alloc_compressor_data(VP8_COMP *cpi) ...@@ -1106,10 +1106,6 @@ void vp8_alloc_compressor_data(VP8_COMP *cpi)
width, height, VP8BORDERINPIXELS)) width, height, VP8BORDERINPIXELS))
vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR, vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR,
"Failed to allocate scaled source buffer"); "Failed to allocate scaled source buffer");
vpx_free(cpi->tok);
{ {
#if CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING #if CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING
unsigned int tokens = 8 * 24 * 16; /* one MB for each thread */ 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, ...@@ -2934,7 +2930,6 @@ static void Pass1Encode(VP8_COMP *cpi, unsigned long *size, unsigned char *dest,
(void) frame_flags; (void) frame_flags;
vp8_set_quantizer(cpi, 26); vp8_set_quantizer(cpi, 26);
scale_and_extend_source(cpi->un_scaled_source, cpi);
vp8_first_pass(cpi); vp8_first_pass(cpi);
} }
#endif #endif
...@@ -4721,7 +4716,8 @@ int vp8_get_compressed_data(VP8_COMP *cpi, unsigned int *frame_flags, unsigned l ...@@ -4721,7 +4716,8 @@ int vp8_get_compressed_data(VP8_COMP *cpi, unsigned int *frame_flags, unsigned l
cpi->source_alt_ref_pending) cpi->source_alt_ref_pending)
{ {
if ((cpi->source = vp8_lookahead_peek(cpi->lookahead, 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; cpi->alt_ref_source = cpi->source;
if (cpi->oxcf.arnr_max_frames > 0) 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 ...@@ -4743,6 +4739,15 @@ int vp8_get_compressed_data(VP8_COMP *cpi, unsigned int *frame_flags, unsigned l
if (!cpi->source) 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))) if ((cpi->source = vp8_lookahead_pop(cpi->lookahead, flush)))
{ {
cm->show_frame = 1; cm->show_frame = 1;
...@@ -4762,6 +4767,11 @@ int vp8_get_compressed_data(VP8_COMP *cpi, unsigned int *frame_flags, unsigned l ...@@ -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_stamp = cpi->source->ts_start;
*time_end = cpi->source->ts_end; *time_end = cpi->source->ts_end;
*frame_flags = cpi->source->flags; *frame_flags = cpi->source->flags;
if (cpi->pass == 1 && cm->current_video_frame > 0)
{
cpi->last_frame_unscaled_source = &cpi->last_source->img;
}
} }
else else
{ {
......
...@@ -316,10 +316,12 @@ typedef struct VP8_COMP ...@@ -316,10 +316,12 @@ typedef struct VP8_COMP
struct lookahead_ctx *lookahead; struct lookahead_ctx *lookahead;
struct lookahead_entry *source; struct lookahead_entry *source;
struct lookahead_entry *alt_ref_source; struct lookahead_entry *alt_ref_source;
struct lookahead_entry *last_source;
YV12_BUFFER_CONFIG *Source; YV12_BUFFER_CONFIG *Source;
YV12_BUFFER_CONFIG *un_scaled_source; YV12_BUFFER_CONFIG *un_scaled_source;
YV12_BUFFER_CONFIG 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_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 int source_alt_ref_active; // an alt ref frame has been encoded and is usable
......
...@@ -525,7 +525,8 @@ void vp8_temporal_filter_prepare_c ...@@ -525,7 +525,8 @@ void vp8_temporal_filter_prepare_c
{ {
int which_buffer = start_frame - frame; int which_buffer = start_frame - frame;
struct lookahead_entry* buf = vp8_lookahead_peek(cpi->lookahead, struct lookahead_entry* buf = vp8_lookahead_peek(cpi->lookahead,
which_buffer); which_buffer,
PEEK_FORWARD);
cpi->frames[frames_to_blur-1-frame] = &buf->img; cpi->frames[frames_to_blur-1-frame] = &buf->img;
} }
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment