Add motion search skipping in first pass
authorYunqing Wang <yunqingwang@google.com>
Wed, 14 Mar 2012 14:03:39 +0000 (10:03 -0400)
committerYunqing Wang <yunqingwang@google.com>
Fri, 16 Mar 2012 19:59:00 +0000 (15:59 -0400)
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
vp8/encoder/lookahead.c
vp8/encoder/lookahead.h
vp8/encoder/onyx_if.c
vp8/encoder/onyx_int.h
vp8/encoder/temporal_filter.c

index cb8fd3e..ac83622 100644 (file)
@@ -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;
 
index 3e582e3..4c92281 100644 (file)
@@ -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;
 }
 
index 32bafcd..cf56b75 100644 (file)
@@ -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
index dbb7bb3..607b56a 100644 (file)
@@ -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
     {
index 4b0060e..c7a1de8 100644 (file)
@@ -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
index 709f6e2..7e7def4 100644 (file)
@@ -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;
     }