blob: 6b4b7b466877622d57aef4ca4b0dc29a163c9c22 [file] [log] [blame]
#### 16.3 Mode and Motion Vector Contexts {#h-16-03}
The probability table used to decode the `mv_ref`, along with three
reference motion vectors used by the selected mode, is calculated via
a survey of the already-decoded motion vectors in (up to) 3 nearby
macroblocks.
The algorithm generates a sorted list of distinct motion vectors
adjacent to the search site. The `best_mv` is the vector with the
highest score. The `mv_nearest` is the non-zero vector with the
highest score. The `mv_near` is the non-zero vector with the next
highest score. The number of motion vectors coded using the `SPLITMV`
mode is scored using the same weighting and is returned with the
scores of the best, nearest, and near vectors.
The three adjacent macroblocks above, left, and above-left are
considered in order. If the macroblock is intra-coded, no action is
taken. Otherwise, the motion vector is compared to other previously
found motion vectors to determine if it has been seen before, and if
so contributes its weight to that vector; otherwise, it enters a new
vector in the list. The above and left vectors have twice the weight
of the above-left vector.
As is the case with many contexts used by VP8, it is possible for
macroblocks near the top or left edges of the image to reference
blocks that are outside the visible image. VP8 provides a border of
1 macroblock filled with 0x0 motion vectors left of the left edge,
and a border filled with 0,0 motion vectors of 1 macroblocks above
the top edge.
Much of the process is more easily described in C than in English.
The reference code for this can be found in `modemv.c` (Section 20.11).
The calculation of reference vectors, probability table, and,
finally, the inter-prediction mode itself is implemented as follows.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
typedef union
{
unsigned int as_int;
MV as_mv;
} int_mv; /* facilitates rapid equality tests */
static void mv_bias(MODE_INFO *x,int refframe, int_mv *mvp,
int * ref_frame_sign_bias )
{
MV xmv;
xmv = x->mbmi.mv.as_mv;
if ( ref_frame_sign_bias[x->mbmi.ref_frame] !=
ref_frame_sign_bias[refframe] )
{
xmv.row*=-1;
xmv.col*=-1;
}
mvp->as_mv = xmv;
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
{:lang="c"}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void vp8_clamp_mv(MV *mv, const MACROBLOCKD *xd)
{
if ( mv->col < (xd->mb_to_left_edge - LEFT_TOP_MARGIN) )
mv->col = xd->mb_to_left_edge - LEFT_TOP_MARGIN;
else if ( mv->col > xd->mb_to_right_edge + RIGHT_BOTTOM_MARGIN )
mv->col = xd->mb_to_right_edge + RIGHT_BOTTOM_MARGIN;
if ( mv->row < (xd->mb_to_top_edge - LEFT_TOP_MARGIN) )
mv->row = xd->mb_to_top_edge - LEFT_TOP_MARGIN;
else if ( mv->row > xd->mb_to_bottom_edge + RIGHT_BOTTOM_MARGIN )
mv->row = xd->mb_to_bottom_edge + RIGHT_BOTTOM_MARGIN;
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
{:lang="c"}
In the function `vp8_find_near_mvs()`, the vectors "nearest" and "near"
are used by the corresponding modes.
The vector `best_mv` is used as a base for explicitly coded motion
vectors.
The first three entries in the return value `cnt` are (in order)
weighted census values for "zero", "nearest", and "near" vectors.
The final value indicates the extent to which `SPLITMV` was used by the
neighboring macroblocks. The largest possible "weight" value in each
case is 5.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void vp8_find_near_mvs
(
MACROBLOCKD *xd,
const MODE_INFO *here,
MV *nearest,
MV *near,
MV *best_mv,
int cnt[4],
int refframe,
int * ref_frame_sign_bias
)
{
const MODE_INFO *above = here - xd->mode_info_stride;
const MODE_INFO *left = here - 1;
const MODE_INFO *aboveleft = above - 1;
int_mv near_mvs[4];
int_mv *mv = near_mvs;
int *cntx = cnt;
enum {CNT_ZERO, CNT_NEAREST, CNT_NEAR, CNT_SPLITMV};
/* Zero accumulators */
mv[0].as_int = mv[1].as_int = mv[2].as_int = 0;
cnt[0] = cnt[1] = cnt[2] = cnt[3] = 0;
/* Process above */
if(above->mbmi.ref_frame != INTRA_FRAME) {
if(above->mbmi.mv.as_int) {
(++mv)->as_int = above->mbmi.mv.as_int;
mv_bias(above, refframe, mv, ref_frame_sign_bias);
++cntx;
}
*cntx += 2;
}
/* Process left */
if(left->mbmi.ref_frame != INTRA_FRAME) {
if(left->mbmi.mv.as_int) {
int_mv this_mv;
this_mv.as_int = left->mbmi.mv.as_int;
mv_bias(left, refframe, &this_mv, ref_frame_sign_bias);
if(this_mv.as_int != mv->as_int) {
(++mv)->as_int = this_mv.as_int;
++cntx;
}
*cntx += 2;
} else
cnt[CNT_ZERO] += 2;
}
/* Process above left */
if(aboveleft->mbmi.ref_frame != INTRA_FRAME) {
if(aboveleft->mbmi.mv.as_int) {
int_mv this_mv;
this_mv.as_int = aboveleft->mbmi.mv.as_int;
mv_bias(aboveleft, refframe, &this_mv,
ref_frame_sign_bias);
if(this_mv.as_int != mv->as_int) {
(++mv)->as_int = this_mv.as_int;
++cntx;
}
*cntx += 1;
} else
cnt[CNT_ZERO] += 1;
}
/* If we have three distinct MVs ... */
if(cnt[CNT_SPLITMV]) {
/* See if above-left MV can be merged with NEAREST */
if(mv->as_int == near_mvs[CNT_NEAREST].as_int)
cnt[CNT_NEAREST] += 1;
}
cnt[CNT_SPLITMV] = ((above->mbmi.mode == SPLITMV)
+ (left->mbmi.mode == SPLITMV)) * 2
+ (aboveleft->mbmi.mode == SPLITMV);
/* Swap near and nearest if necessary */
if(cnt[CNT_NEAR] > cnt[CNT_NEAREST]) {
int tmp;
tmp = cnt[CNT_NEAREST];
cnt[CNT_NEAREST] = cnt[CNT_NEAR];
cnt[CNT_NEAR] = tmp;
tmp = near_mvs[CNT_NEAREST].as_int;
near_mvs[CNT_NEAREST].as_int = near_mvs[CNT_NEAR].as_int;
near_mvs[CNT_NEAR].as_int = tmp;
}
/* Use near_mvs[0] to store the "best" MV */
if(cnt[CNT_NEAREST] >= cnt[CNT_ZERO])
near_mvs[CNT_ZERO] = near_mvs[CNT_NEAREST];
/* Set up return values */
*best_mv = near_mvs[0].as_mv;
*nearest = near_mvs[CNT_NEAREST].as_mv;
*near = near_mvs[CNT_NEAR].as_mv;
vp8_clamp_mv(nearest, xd);
vp8_clamp_mv(near, xd);
vp8_clamp_mv(best_mv, xd); //TODO: Move this up before
the copy
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
{:lang="c"}
The `mv_ref` probability table (`mv_ref_p`) is then derived from the
census as follows.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
const int vp8_mode_contexts[6][4] =
{
{ 7, 1, 1, 143, },
{ 14, 18, 14, 107, },
{ 135, 64, 57, 68, },
{ 60, 56, 128, 65, },
{ 159, 134, 128, 34, },
{ 234, 188, 128, 28, },
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
{:lang="c"}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
vp8_prob *vp8_mv_ref_probs(vp8_prob mv_ref_p[VP8_MVREFS-1],
int cnt[4])
{
mv_ref_p[0] = vp8_mode_contexts [cnt[0]] [0];
mv_ref_p[1] = vp8_mode_contexts [cnt[1]] [1];
mv_ref_p[2] = vp8_mode_contexts [cnt[2]] [2];
mv_ref_p[3] = vp8_mode_contexts [cnt[3]] [3];
return p;
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
{:lang="c"}
Once `mv_ref_p` is established, the `mv_ref` is decoded as usual.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
mvr = (mv_ref) treed_read( d, mv_ref_tree, mv_ref_p);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
{:lang="c"}
For the first four inter-coding modes, the same motion vector is used
for all the Y subblocks. The first three modes use an implicit
motion vector.
| Mode | Instruction
| -------------- | ------------------------------------------
| `mv_nearest` | Use the nearest vector returned by `vp8_find_near_mvs`.
| `mv_near` | Use the near vector returned by `vp8_find_near_mvs`.
| `mv_zero` | Use a zero vector; that is, predict the current macroblock from the corresponding macroblock in the prediction frame.
| `NEWMV` | This mode is followed by an explicitly coded motion vector (the format of which is described in the next section) that is added (component-wise) to the `best_mv` reference vector returned by `find_near_mvs` and applied to all 16 subblocks.