static void unpack_vectors(Vp3DecodeContext *s, GetBitContext *gb) { int i, j, k; int coding_mode; int motion_x[6]; int motion_y[6]; int last_motion_x = 0; int last_motion_y = 0; int prior_last_motion_x = 0; int prior_last_motion_y = 0; int current_macroblock; int current_fragment; debug_vp3(" vp3: unpacking motion vectors\n"); if (s->keyframe) { debug_vp3(" keyframe-- there are no motion vectors\n"); } else { memset(motion_x, 0, 6 * sizeof(int)); memset(motion_y, 0, 6 * sizeof(int)); /* coding mode 0 is the VLC scheme; 1 is the fixed code scheme */ coding_mode = get_bits(gb, 1); debug_vectors(" using %s scheme for unpacking motion vectors\n", (coding_mode == 0) ? "VLC" : "fixed-length"); /* iterate through all of the macroblocks that contain 1 or more * coded fragments */ for (i = 0; i < s->u_superblock_start; i++) { for (j = 0; j < 4; j++) { current_macroblock = s->superblock_macroblocks[i * 4 + j]; if ((current_macroblock == -1) || (!s->macroblock_coded[current_macroblock])) continue; current_fragment = s->macroblock_fragments[current_macroblock * 6]; switch (s->all_fragments[current_fragment].coding_method) { case MODE_INTER_PLUS_MV: case MODE_GOLDEN_MV: /* all 6 fragments use the same motion vector */ if (coding_mode == 0) { motion_x[0] = get_motion_vector_vlc(gb); motion_y[0] = get_motion_vector_vlc(gb); } else { motion_x[0] = get_motion_vector_fixed(gb); motion_y[0] = get_motion_vector_fixed(gb); } for (k = 1; k < 6; k++) { motion_x[k] = motion_x[0]; motion_y[k] = motion_y[0]; } /* vector maintenance, only on MODE_INTER_PLUS_MV */ if (s->all_fragments[current_fragment].coding_method == MODE_INTER_PLUS_MV) { prior_last_motion_x = last_motion_x; prior_last_motion_y = last_motion_y; last_motion_x = motion_x[0]; last_motion_y = motion_y[0]; } break; case MODE_INTER_FOURMV: /* fetch 4 vectors from the bitstream, one for each * Y fragment, then average for the C fragment vectors */ motion_x[4] = motion_y[4] = 0; for (k = 0; k < 4; k++) { if (coding_mode == 0) { motion_x[k] = get_motion_vector_vlc(gb); motion_y[k] = get_motion_vector_vlc(gb); } else { motion_x[k] = get_motion_vector_fixed(gb); motion_y[k] = get_motion_vector_fixed(gb); } motion_x[4] += motion_x[k]; motion_y[4] += motion_y[k]; } if (motion_x[4] >= 0) motion_x[4] = (motion_x[4] + 2) / 4; else motion_x[4] = (motion_x[4] - 2) / 4; motion_x[5] = motion_x[4]; if (motion_y[4] >= 0) motion_y[4] = (motion_y[4] + 2) / 4; else motion_y[4] = (motion_y[4] - 2) / 4; motion_y[5] = motion_y[4]; /* vector maintenance; vector[3] is treated as the * last vector in this case */ prior_last_motion_x = last_motion_x; prior_last_motion_y = last_motion_y; last_motion_x = motion_x[3]; last_motion_y = motion_y[3]; break; case MODE_INTER_LAST_MV: /* all 6 fragments use the last motion vector */ motion_x[0] = last_motion_x; motion_y[0] = last_motion_y; for (k = 1; k < 6; k++) { motion_x[k] = motion_x[0]; motion_y[k] = motion_y[0]; } /* no vector maintenance (last vector remains the * last vector) */ break; case MODE_INTER_PRIOR_LAST: /* all 6 fragments use the motion vector prior to the * last motion vector */ motion_x[0] = prior_last_motion_x; motion_y[0] = prior_last_motion_y; for (k = 1; k < 6; k++) { motion_x[k] = motion_x[0]; motion_y[k] = motion_y[0]; } /* vector maintenance */ prior_last_motion_x = last_motion_x; prior_last_motion_y = last_motion_y; last_motion_x = motion_x[0]; last_motion_y = motion_y[0]; break; } /* assign the motion vectors to the correct fragments */ debug_vectors(" vectors for macroblock starting @ fragment %d (coding method %d):\n", current_fragment, s->all_fragments[current_fragment].coding_method); for (k = 0; k < 6; k++) { current_fragment = s->macroblock_fragments[current_macroblock * 6 + k]; s->all_fragments[current_fragment].motion_x = motion_x[k]; s->all_fragments[current_fragment].motion_x = motion_y[k]; debug_vectors(" vector %d: fragment %d = (%d, %d)\n", k, current_fragment, motion_x[k], motion_y[k]); } } } } }