Commit aa7335e6 authored by Yunqing Wang's avatar Yunqing Wang

Multiple-resolution encoder

The example encoder down-samples the input video frames a number of
times with a down-sampling factor, and then encodes and outputs
bitstreams with different resolutions.

Support arbitrary down-sampling factor, and down-sampling factor
can be different for each encoding level.

For example, the encoder can be tested as follows.
1. Configure with multi-resolution encoding enabled:
../libvpx/configure --target=x86-linux-gcc --disable-codecs
--enable-vp8 --enable-runtime_cpu_detect --enable-debug
--disable-install-docs --enable-error-concealment
--enable-multi-res-encoding
2. Run make
3. Encode:
If input video is 1280x720, run:
./vp8_multi_resolution_encoder 1280 720 input.yuv 1.ivf 2.ivf 3.ivf 1
(output: 1.ivf(1280x720); 2.ivf(640x360); 3.ivf(320x180).
The last parameter is set to 1/0 to show/not show PSNR.)
4. Decode:
./simple_decoder 1.ivf 1.yuv
./simple_decoder 2.ivf 2.yuv
./simple_decoder 3.ivf 3.yuv
5. View video:
mplayer 1.yuv -demuxer rawvideo -rawvideo w=1280:h=720 -loop 0 -fps 30
mplayer 2.yuv -demuxer rawvideo -rawvideo w=640:h=360 -loop 0 -fps 30
mplayer 3.yuv -demuxer rawvideo -rawvideo w=320:h=180 -loop 0 -fps 30

The encoding parameters can be modified in vp8_multi_resolution_encoder.c,
for example, target bitrate, frame rate...

Modified API. John helped a lot with that. Thanks!

Change-Id: I03be9a51167eddf94399f92d269599fb3f3d54f5
parent 6127af60
......@@ -35,7 +35,7 @@ Advanced options:
${toggle_internal_stats} output of encoder internal stats for debug, if supported (encoders)
${toggle_mem_tracker} track memory usage
${toggle_postproc} postprocessing
${toggle_multithread} multithreaded encoding and decoding.
${toggle_multithread} multithreaded encoding and decoding
${toggle_spatial_resampling} spatial sampling (scaling) support
${toggle_realtime_only} enable this option while building for real-time encoding
${toggle_error_concealment} enable this option to get a decoder which is able to conceal losses
......@@ -44,6 +44,7 @@ Advanced options:
${toggle_static} static library support
${toggle_small} favor smaller size over speed
${toggle_postproc_visualizer} macro block / block level visualizers
${toggle_multi_res_encoding} enable multiple-resolution encoding
Codecs:
Codecs can be selectively enabled or disabled individually, or by family:
......@@ -262,6 +263,7 @@ CONFIG_LIST="
postproc_visualizer
os_support
unit_tests
multi_res_encoding
"
CMDLINE_SELECT="
extra_warnings
......@@ -304,6 +306,7 @@ CMDLINE_SELECT="
small
postproc_visualizer
unit_tests
multi_res_encoding
"
process_cmdline() {
......
......@@ -96,6 +96,16 @@ GEN_EXAMPLES-$(CONFIG_VP8_ENCODER) += vp8cx_set_ref.c
vp8cx_set_ref.GUID = C5E31F7F-96F6-48BD-BD3E-10EBF6E8057A
vp8cx_set_ref.DESCRIPTION = VP8 set encoder reference frame
# C file is provided, not generated automatically.
GEN_EXAMPLES-$(CONFIG_MULTI_RES_ENCODING) += vp8_multi_resolution_encoder.c
vp8_multi_resolution_encoder.SRCS \
+= third_party/libyuv/include/libyuv/basic_types.h \
third_party/libyuv/include/libyuv/cpu_id.h \
third_party/libyuv/include/libyuv/scale.h \
third_party/libyuv/source/scale.c \
third_party/libyuv/source/cpu_id.c
vp8_multi_resolution_encoder.GUID = 04f8738e-63c8-423b-90fa-7c2703a374de
vp8_multi_resolution_encoder.DESCRIPTION = VP8 Multiple-resolution Encoding
# Handle extra library flags depending on codec configuration
......
Name: libyuv
URL: http://code.google.com/p/libyuv/
Version: 90
License: BSD
License File: LICENSE
Description:
libyuv is an open source project that includes YUV conversion and scaling
functionality.
The optimized scaler in libyuv is used in multiple resolution encoder example,
which down-samples the original input video (f.g. 1280x720) a number of times
in order to encode multiple resolution bit streams.
Local Modifications:
Modified the original scaler code from C++ to C to fit in our current build
system. This is a temporal solution, and will be improved later.
\ No newline at end of file
/*
* Copyright (c) 2011 The LibYuv project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef INCLUDE_LIBYUV_BASIC_TYPES_H_
#define INCLUDE_LIBYUV_BASIC_TYPES_H_
#include <stddef.h> // for NULL, size_t
#ifndef WIN32
#include <stdint.h> // for uintptr_t
#endif
#ifndef INT_TYPES_DEFINED
#define INT_TYPES_DEFINED
#ifdef COMPILER_MSVC
typedef __int64 int64;
#else
typedef long long int64;
#endif /* COMPILER_MSVC */
typedef int int32;
typedef short int16;
typedef char int8;
#ifdef COMPILER_MSVC
typedef unsigned __int64 uint64;
typedef __int64 int64;
#ifndef INT64_C
#define INT64_C(x) x ## I64
#endif
#ifndef UINT64_C
#define UINT64_C(x) x ## UI64
#endif
#define INT64_F "I64"
#else
typedef unsigned long long uint64;
//typedef long long int64;
#ifndef INT64_C
#define INT64_C(x) x ## LL
#endif
#ifndef UINT64_C
#define UINT64_C(x) x ## ULL
#endif
#define INT64_F "ll"
#endif /* COMPILER_MSVC */
typedef unsigned int uint32;
typedef unsigned short uint16;
typedef unsigned char uint8;
#endif // INT_TYPES_DEFINED
// Detect compiler is for x86 or x64.
#if defined(__x86_64__) || defined(_M_X64) || \
defined(__i386__) || defined(_M_IX86)
#define CPU_X86 1
#endif
#define IS_ALIGNED(p, a) (0==((uintptr_t)(p) & ((a)-1)))
#define ALIGNP(p, t) \
((uint8*)((((uintptr_t)(p) + \
((t)-1)) & ~((t)-1))))
#endif // INCLUDE_LIBYUV_BASIC_TYPES_H_
/*
* Copyright (c) 2011 The LibYuv project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef INCLUDE_LIBYUV_CPU_ID_H_
#define INCLUDE_LIBYUV_CPU_ID_H_
//namespace libyuv {
// These flags are only valid on x86 processors
static const int kCpuHasSSE2 = 1;
static const int kCpuHasSSSE3 = 2;
// SIMD support on ARM processors
static const int kCpuHasNEON = 4;
// Detect CPU has SSE2 etc.
int TestCpuFlag(int flag);
// For testing, allow CPU flags to be disabled.
void MaskCpuFlagsForTest(int enable_flags);
//} // namespace libyuv
#endif // INCLUDE_LIBYUV_CPU_ID_H_
/*
* Copyright (c) 2011 The LibYuv project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef INCLUDE_LIBYUV_SCALE_H_
#define INCLUDE_LIBYUV_SCALE_H_
#include "third_party/libyuv/include/libyuv/basic_types.h"
//namespace libyuv {
// Supported filtering
typedef enum {
kFilterNone = 0, // Point sample; Fastest
kFilterBilinear = 1, // Faster than box, but lower quality scaling down.
kFilterBox = 2 // Highest quality
}FilterMode;
// Scales a YUV 4:2:0 image from the src width and height to the
// dst width and height.
// If filtering is kFilterNone, a simple nearest-neighbor algorithm is
// used. This produces basic (blocky) quality at the fastest speed.
// If filtering is kFilterBilinear, interpolation is used to produce a better
// quality image, at the expense of speed.
// If filtering is kFilterBox, averaging is used to produce ever better
// quality image, at further expense of speed.
// Returns 0 if successful.
int I420Scale(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
int src_width, int src_height,
uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int dst_width, int dst_height,
FilterMode filtering);
// Legacy API
// If dst_height_offset is non-zero, the image is offset by that many pixels
// and stretched to (dst_height - dst_height_offset * 2) pixels high,
// instead of dst_height.
int Scale_1(const uint8* src, int src_width, int src_height,
uint8* dst, int dst_width, int dst_height, int dst_height_offset,
int interpolate);
// Same, but specified src terms of each plane location and stride.
int Scale_2(const uint8* src_y, const uint8* src_u, const uint8* src_v,
int src_stride_y, int src_stride_u, int src_stride_v,
int src_width, int src_height,
uint8* dst_y, uint8* dst_u, uint8* dst_v,
int dst_stride_y, int dst_stride_u, int dst_stride_v,
int dst_width, int dst_height,
int interpolate);
// For testing, allow disabling of optimizations.
void SetUseReferenceImpl(int use);
//} // namespace libyuv
#endif // INCLUDE_LIBYUV_SCALE_H_
/*
* Copyright (c) 2011 The LibYuv project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "third_party/libyuv/include/libyuv/cpu_id.h"
#include "third_party/libyuv/include/libyuv/basic_types.h" // for CPU_X86
#ifdef _MSC_VER
#include <intrin.h>
#endif
// TODO(fbarchard): Use cpuid.h when gcc 4.4 is used on OSX and Linux.
#if (defined(__pic__) || defined(__APPLE__)) && defined(__i386__)
static inline void __cpuid(int cpu_info[4], int info_type) {
__asm__ volatile (
"mov %%ebx, %%edi\n"
"cpuid\n"
"xchg %%edi, %%ebx\n"
: "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
: "a"(info_type)
);
}
#elif defined(__i386__) || defined(__x86_64__)
static inline void __cpuid(int cpu_info[4], int info_type) {
__asm__ volatile (
"cpuid\n"
: "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
: "a"(info_type)
);
}
#endif
//namespace libyuv {
// CPU detect function for SIMD instruction sets.
static int cpu_info_initialized_ = 0;
static int cpu_info_ = 0;
// Global lock for cpu initialization.
static void InitCpuFlags() {
#ifdef CPU_X86
int cpu_info[4];
__cpuid(cpu_info, 1);
cpu_info_ = (cpu_info[2] & 0x00000200 ? kCpuHasSSSE3 : 0) |
(cpu_info[3] & 0x04000000 ? kCpuHasSSE2 : 0);
#elif defined(__ARM_NEON__)
// gcc -mfpu=neon defines __ARM_NEON__
// if code is specifically built for Neon-only, enable the flag.
cpu_info_ |= kCpuHasNEON;
#else
cpu_info_ = 0;
#endif
cpu_info_initialized_ = 1;
}
void MaskCpuFlagsForTest(int enable_flags) {
InitCpuFlags();
cpu_info_ &= enable_flags;
}
int TestCpuFlag(int flag) {
if (!cpu_info_initialized_) {
InitCpuFlags();
}
return cpu_info_ & flag ? 1 : 0;
}
//} // namespace libyuv
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -82,6 +82,7 @@
The available initialization methods are:
\if encoder - #vpx_codec_enc_init (calls vpx_codec_enc_init_ver()) \endif
\if multi-encoder - #vpx_codec_enc_init_multi (calls vpx_codec_enc_init_multi_ver()) \endif
\if decoder - #vpx_codec_dec_init (calls vpx_codec_dec_init_ver()) \endif
......
/*! \page usage_encode Encode
The vpx_codec_encode() function is at the core of the decode loop. It
The vpx_codec_encode() function is at the core of the encode loop. It
processes raw images passed by the application, producing packets of
compressed data. The <code>deadline</code> parameter controls the amount
of time in microseconds the encoder should spend working on the frame. For
......@@ -10,5 +10,4 @@
\ref samples
*/
......@@ -170,6 +170,18 @@ typedef struct
union b_mode_info bmi[16];
} MODE_INFO;
#if CONFIG_MULTI_RES_ENCODING
/* The information needed to be stored for higher-resolution encoder */
typedef struct
{
MB_PREDICTION_MODE mode;
MV_REFERENCE_FRAME ref_frame;
int_mv mv;
//union b_mode_info bmi[16];
int dissim; // dissimilarity level of the macroblock
} LOWER_RES_INFO;
#endif
typedef struct
{
short *qcoeff;
......
......@@ -17,6 +17,7 @@ extern "C"
{
#endif
#include "vpx_config.h"
#include "vpx/internal/vpx_codec_internal.h"
#include "vpx/vp8cx.h"
#include "vpx/vpx_encoder.h"
......@@ -207,6 +208,19 @@ extern "C"
unsigned int periodicity;
unsigned int layer_id[MAX_PERIODICITY];
#if CONFIG_MULTI_RES_ENCODING
/* Number of total resolutions encoded */
unsigned int mr_total_resolutions;
/* Current encoder ID */
unsigned int mr_encoder_id;
/* Down-sampling factor */
vpx_rational_t mr_down_sampling_factor;
/* Memory location to store low-resolution encoder's mode info */
void* mr_low_res_mode_info;
#endif
} VP8_CONFIG;
......
......@@ -49,8 +49,8 @@ extern void vp8cx_init_mbrthread_data(VP8_COMP *cpi,
int count);
void vp8_build_block_offsets(MACROBLOCK *x);
void vp8_setup_block_ptrs(MACROBLOCK *x);
int vp8cx_encode_inter_macroblock(VP8_COMP *cpi, MACROBLOCK *x, TOKENEXTRA **t, int recon_yoffset, int recon_uvoffset);
int vp8cx_encode_intra_macro_block(VP8_COMP *cpi, MACROBLOCK *x, TOKENEXTRA **t);
int vp8cx_encode_inter_macroblock(VP8_COMP *cpi, MACROBLOCK *x, TOKENEXTRA **t, int recon_yoffset, int recon_uvoffset, int mb_row, int mb_col);
int vp8cx_encode_intra_macro_block(VP8_COMP *cpi, MACROBLOCK *x, TOKENEXTRA **t, int mb_row, int mb_col);
static void adjust_act_zbin( VP8_COMP *cpi, MACROBLOCK *x );
#ifdef MODE_STATS
......@@ -475,14 +475,14 @@ void encode_mb_row(VP8_COMP *cpi,
if (cm->frame_type == KEY_FRAME)
{
*totalrate += vp8cx_encode_intra_macro_block(cpi, x, tp);
*totalrate += vp8cx_encode_intra_macro_block(cpi, x, tp, mb_row, mb_col);
#ifdef MODE_STATS
y_modes[xd->mbmi.mode] ++;
#endif
}
else
{
*totalrate += vp8cx_encode_inter_macroblock(cpi, x, tp, recon_yoffset, recon_uvoffset);
*totalrate += vp8cx_encode_inter_macroblock(cpi, x, tp, recon_yoffset, recon_uvoffset, mb_row, mb_col);
#ifdef MODE_STATS
inter_y_modes[xd->mbmi.mode] ++;
......@@ -1142,7 +1142,7 @@ static void adjust_act_zbin( VP8_COMP *cpi, MACROBLOCK *x )
#endif
}
int vp8cx_encode_intra_macro_block(VP8_COMP *cpi, MACROBLOCK *x, TOKENEXTRA **t)
int vp8cx_encode_intra_macro_block(VP8_COMP *cpi, MACROBLOCK *x, TOKENEXTRA **t, int mb_row, int mb_col)
{
int rate;
......@@ -1182,7 +1182,8 @@ extern void vp8_fix_contexts(MACROBLOCKD *x);
int vp8cx_encode_inter_macroblock
(
VP8_COMP *cpi, MACROBLOCK *x, TOKENEXTRA **t,
int recon_yoffset, int recon_uvoffset
int recon_yoffset, int recon_uvoffset,
int mb_row, int mb_col
)
{
MACROBLOCKD *const xd = &x->e_mbd;
......@@ -1230,8 +1231,25 @@ int vp8cx_encode_inter_macroblock
}
else
{
#if CONFIG_MULTI_RES_ENCODING
if (cpi->oxcf.mr_encoder_id == 0)
{
/* Lowest-resolution encoding */
vp8_pick_inter_mode(cpi, x, recon_yoffset, recon_uvoffset, &rate,
&distortion, &intra_error);
}else
{
/* Higher-resolution encoding */
vp8_mr_pick_inter_mode(cpi, x, recon_yoffset, recon_uvoffset, &rate,
&distortion, &intra_error, mb_row, mb_col);
}
#else
vp8_pick_inter_mode(cpi, x, recon_yoffset, recon_uvoffset, &rate,
&distortion, &intra_error);
#endif
}
cpi->prediction_error += distortion;
cpi->intra_error += intra_error;
......
......@@ -9,6 +9,7 @@
*/
#include "onyx_int.h"
#include "mcomp.h"
#include "vpx_mem/vpx_mem.h"
#include "vpx_config.h"
......@@ -182,8 +183,6 @@ void vp8_init3smotion_compensation(MACROBLOCK *x, int stride)
#define IFMVCV(r,c,s,e) if ( c >= minc && c <= maxc && r >= minr && r <= maxr) s else e;
#define ERR(r,c) (MVC(r,c)+DIST(r,c)) // returns distortion + motion vector cost
#define CHECK_BETTER(v,r,c) IFMVCV(r,c,{thismse = DIST(r,c); if((v = (MVC(r,c)+thismse)) < besterr) { besterr = v; br=r; bc=c; *distortion = thismse; *sse1 = sse; }}, v=INT_MAX;)// checks if (r,c) has better score than previous best
#define MIN(x,y) (((x)<(y))?(x):(y))
#define MAX(x,y) (((x)>(y))?(x):(y))
int vp8_find_best_sub_pixel_step_iteratively(MACROBLOCK *x, BLOCK *b, BLOCKD *d,
int_mv *bestmv, int_mv *ref_mv,
......@@ -331,8 +330,7 @@ int vp8_find_best_sub_pixel_step_iteratively(MACROBLOCK *x, BLOCK *b, BLOCKD *d,
#undef IFMVCV
#undef ERR
#undef CHECK_BETTER
#undef MIN
#undef MAX
int vp8_find_best_sub_pixel_step(MACROBLOCK *x, BLOCK *b, BLOCKD *d,
int_mv *bestmv, int_mv *ref_mv,
int error_per_bit,
......@@ -854,6 +852,8 @@ int vp8_hex_search
int k = -1;
int all_in;
int best_site = -1;
int hex_range = 127;
int dia_range = 8;
int_mv fcenter_mv;
fcenter_mv.as_mv.row = center_mv->as_mv.row >> 3;
......@@ -873,6 +873,18 @@ int vp8_hex_search
in_what_stride, 0x7fffffff)
+ mvsad_err_cost(&this_mv, &fcenter_mv, mvsadcost, sad_per_bit);
#if CONFIG_MULTI_RES_ENCODING
/* Lower search range based on prediction info */
if (search_param >= 6) goto cal_neighbors;
else if (search_param >= 5) hex_range = 4;
else if (search_param >= 4) hex_range = 6;
else if (search_param >= 3) hex_range = 15;
else if (search_param >= 2) hex_range = 31;
else if (search_param >= 1) hex_range = 63;
dia_range = 8;
#endif
// hex search
//j=0
CHECK_BOUNDS(2)
......@@ -909,7 +921,7 @@ int vp8_hex_search
k = best_site;
}
for (j = 1; j < 127; j++)
for (j = 1; j < hex_range; j++)
{
best_site = -1;
CHECK_BOUNDS(2)
......@@ -951,7 +963,7 @@ int vp8_hex_search
// check 4 1-away neighbors
cal_neighbors:
for (j = 0; j < 32; j++)
for (j = 0; j < dia_range; j++)
{
best_site = -1;
CHECK_BOUNDS(1)
......
/*
* Copyright (c) 2010 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <limits.h>
#include "vpx_config.h"
#include "onyx_int.h"
#include "mr_dissim.h"
#include "vpx_mem/vpx_mem.h"
#include "rdopt.h"
void vp8_cal_low_res_mb_cols(VP8_COMP *cpi)
{
int low_res_w;
/* Support arbitrary down-sampling factor */
unsigned int iw = cpi->oxcf.Width*cpi->oxcf.mr_down_sampling_factor.den
+ cpi->oxcf.mr_down_sampling_factor.num - 1;
low_res_w = iw/cpi->oxcf.mr_down_sampling_factor.num;
cpi->mr_low_res_mb_cols = ((low_res_w + 15) >> 4);
}
#define GET_MV(x) \
if(x->mbmi.ref_frame !=INTRA_FRAME) \
{ \
mvx[cnt] = x->mbmi.mv.as_mv.row; \
mvy[cnt] = x->mbmi.mv.as_mv.col; \
cnt++; \
}
#define GET_MV_SIGN(x) \
if(x->mbmi.ref_frame !=INTRA_FRAME) \
{ \
mvx[cnt] = x->mbmi.mv.as_mv.row; \
mvy[cnt] = x->mbmi.mv.as_mv.col; \
if (cm->ref_frame_sign_bias[x->mbmi.ref_frame] \
!= cm->ref_frame_sign_bias[tmp->mbmi.ref_frame]) \
{ \
mvx[cnt] *= -1; \
mvy[cnt] *= -1; \
} \
cnt++; \
}
void vp8_cal_dissimilarity(VP8_COMP *cpi)
{
VP8_COMMON *cm = &cpi->common;
/* Note: The first row & first column in mip are outside the frame, which
* were initialized to all 0.(ref_frame, mode, mv...)
* Their ref_frame = 0 means they won't be counted in the following
* calculation.
*/
if (cpi->oxcf.mr_total_resolutions >1
&& cpi->oxcf.mr_encoder_id < (cpi->oxcf.mr_total_resolutions - 1))
{
/* Store info for show/no-show frames for supporting alt_ref.
* If parent frame is alt_ref, child has one too.
*/
if(cm->frame_type != KEY_FRAME)
{
int mb_row;
int mb_col;
/* Point to beginning of allocated MODE_INFO arrays. */
MODE_INFO *tmp = cm->mip + cm->mode_info_stride;
LOWER_RES_INFO* store_mode_info
= (LOWER_RES_INFO*)cpi->oxcf.mr_low_res_mode_info;
for (mb_row = 0; mb_row < cm->mb_rows; mb_row ++)
{
tmp++;
for (mb_col = 0; mb_col < cm->mb_cols; mb_col ++)
{
int dissim = INT_MAX;
if(tmp->mbmi.ref_frame !=INTRA_FRAME)
{
int mvx[8];
int mvy[8];
int mmvx;
int mmvy;
int cnt=0;
const MODE_INFO *here = tmp;
const MODE_INFO *above = here - cm->mode_info_stride;
const MODE_INFO *left = here - 1;
const MODE_INFO *aboveleft = above - 1;
const MODE_INFO *aboveright = NULL;
const MODE_INFO *right = NULL;
const MODE_INFO *belowleft = NULL;
const MODE_INFO *below = NULL;
const MODE_INFO *belowright = NULL;
/* If alternate reference frame is used, we have to
* check sign of MV. */
if(cpi->oxcf.play_alternate)
{
/* Gather mv of neighboring MBs */
GET_MV_SIGN(above)
GET_MV_SIGN(left)
GET_MV_SIGN(aboveleft)
if(mb_col < (cm->mb_cols-1))
{
right = here + 1;
aboveright = above + 1;
GET_MV_SIGN(right)
GET_MV_SIGN(aboveright)
}
if(mb_row < (cm->mb_rows-1))
{
below = here + cm->mode_info_stride;
belowleft = below - 1;
GET_MV_SIGN(below)
GET_MV_SIGN(belowleft)
}
if(mb_col < (cm->mb_cols-1)
&& mb_row < (cm->mb_rows-1))
{
belowright = below + 1;
GET_MV_SIGN(belowright)
}
}else
{
/* No alt_ref and gather mv of neighboring MBs */
GET_MV(above)
GET_MV(left)
GET_MV(aboveleft)
if(mb_col < (cm->mb_cols-1))
{
right = here + 1;
aboveright = above + 1;
GET_MV(right)
GET_MV(aboveright)
}
if(mb_row < (cm->mb_rows-1))
{
below = here + cm->mode_info_stride;
belowleft = below - 1;
GET_MV(below)
GET_MV(belowleft)
}
if(mb_col < (cm->mb_cols-1)
&& mb_row < (cm->mb_rows-1))
{
belowright = below + 1;
GET_MV(belowright)
}
}
if (cnt > 0)
{
int max_mvx = mvx[0];
int min_mvx = mvx[0];
int max_mvy = mvy[0];
int min_mvy = mvy[0];
int i;
if (cnt > 1)
{
for (i=1; i< cnt; i++)
{
if (mvx[i] > max_mvx) max_mvx = mvx[i];
else if (mvx[i] < min_mvx) min_mvx = mvx[i];
if (mvy[i] > max_mvy) max_mvy = mvy[i];
else if (mvy[i] < min_mvy) min_mvy = mvy[i];
}
}
mmvx = MAX(abs(min_mvx - here->mbmi.mv.as_mv.row),
abs(max_mvx - here->mbmi.mv.as_mv.row));
mmvy = MAX(abs(min_mvy - here->mbmi.mv.as_mv.col),
abs(max_mvy - here->mbmi.mv.as_mv.col));
dissim = MAX(mmvx, mmvy);
}
}
/* Store mode info for next resolution encoding */
store_mode_info->mode = tmp->mbmi.mode;
store_mode_info->ref_frame = tmp->mbmi.ref_frame;
store_mode_info->mv.as_int = tmp->mbmi.mv.as_int;
store_mode_info->dissim = dissim;
tmp++;
store_mode_info++;
}
}
}
}
}