This I don't understand. Michael Niedermayer (the writer of ffmpeg's h264 decoder) sums up the situation quite succinctly, quoting from libavcodec/h264.h:
/* Wow, what a mess, why didn't they simplify the interlacing & intra
* stuff, I can't imagine that these complex rules are worth it. */
First of all, motion vectors from fields to other fields and frames to other
frames aren't changed. However, when predicting from a frame to a field, the fact
that a field has half the vertical resolution of the frame means that the
vertical component of the motion vector will need to be halved to reference the same
spatial areas. Similarly the motion vector from a field to a frame must be
doubled. This is easily achieved with a few bit shifts (good old integer
arithmetic!) as so:
if( h->sh.b_mbaff )
{
#define MAP_MVS\
MAP_F2F(mv, ref, x264_scan8[0] - 1 - 1*8, h->mb.i_mb_topleft_xy)\
MAP_F2F(mv, ref, x264_scan8[0] + 0 - 1*8, top)\
MAP_F2F(mv, ref, x264_scan8[0] + 1 - 1*8, top)\
MAP_F2F(mv, ref, x264_scan8[0] + 2 - 1*8, top)\
MAP_F2F(mv, ref, x264_scan8[0] + 3 - 1*8, top)\
MAP_F2F(mv, ref, x264_scan8[0] + 4 - 1*8, h->mb.i_mb_topright_xy)\
MAP_F2F(mv, ref, x264_scan8[0] - 1 + 0*8, left[0])\
MAP_F2F(mv, ref, x264_scan8[0] - 1 + 1*8, left[0])\
MAP_F2F(mv, ref, x264_scan8[0] - 1 + 2*8, left[1])\
MAP_F2F(mv, ref, x264_scan8[0] - 1 + 3*8, left[1])\
MAP_F2F(topright_mv, topright_ref, 0, left[0])\
MAP_F2F(topright_mv, topright_ref, 1, left[0])\
MAP_F2F(topright_mv, topright_ref, 2, left[1])
if( h->mb.b_interlaced )
{
#define MAP_F2F(varmv, varref, index, macroblock)\
if( h->mb.cache.varref[l][index] >= 0 && !h->mb.field[macroblock] )\
{\
h->mb.cache.varref[l][index] <<= 1;\
h->mb.cache.varmv[l][index][1] /= 2;\
h->mb.cache.mvd[l][index][1] >>= 1;\
}
MAP_MVS
#undef MAP_F2F
}
else
{
#define MAP_F2F(varmv, varref, index, macroblock)\
if( h->mb.cache.varref[l][index] >= 0 && h->mb.field[macroblock] )\
{\
h->mb.cache.varref[l][index] >>= 1;\
h->mb.cache.varmv[l][index][1] <<= 1;\
h->mb.cache.mvd[l][index][1] <<= 1;\
}
MAP_MVS
#undef MAP_F2F
}
Here you can see I use a macro to simplify the repeated code, this is actually
inspired by ffmpeg so thanks for the good ideas guys!
Diagonal motion vectors are bizarre to say the least. Top left motion vectors,
in some situations, are required to come from the middle of the macroblock as
opposed to the usual bottom right location. This was the source of much
frustration for a while. Top right motion vectors, for certain partitions, and
when the top right is unavailable, are taken from strange places in the top left
macroblock.