/* * mc.c: Output of motion compensation * * Written by: Michael Unger * Ullrich Hafner * * This file is part of FIASCO (Fractal Image And Sequence COdec) * Copyright (C) 1994-2000 Ullrich Hafner */ /* * $Date: 2000/06/14 20:50:31 $ * $Author: hafner $ * $Revision: 5.1 $ * $State: Exp $ */ #include "config.h" #include "types.h" #include "macros.h" #include "error.h" #include "wfa.h" #include "bit-io.h" #include "mvcode.h" #include "mc.h" /***************************************************************************** local variables *****************************************************************************/ static unsigned p_frame_codes [4][2] = /* * Code values and bits for P-frame prediction * NONE, FORWARD */ { {1, 1}, {0, 1}, {0, 0}, {0, 0} }; static unsigned b_frame_codes [4][2] = /* * Code values and bits for B-frame prediction * NONE, FORWARD, BACKWARD, INTERPOLATED */ { {1, 1}, {000, 3}, {001, 3}, {01, 2} }; enum vlc_e {CODE = 0, BITS = 1}; /***************************************************************************** prototypes *****************************************************************************/ static void encode_mc_tree (unsigned max_state, frame_type_e frame_type, const wfa_t *wfa, bitfile_t *output); static void encode_mc_coords (unsigned max_state, const wfa_t *wfa, bitfile_t *output); /***************************************************************************** public code *****************************************************************************/ void write_mc (frame_type_e frame_type, const wfa_t *wfa, bitfile_t *output) { unsigned max_state = wfa->wfainfo->color ? wfa->tree[wfa->tree[wfa->root_state][0]][0] : wfa->states; encode_mc_tree (max_state, frame_type, wfa, output); encode_mc_coords (max_state, wfa, output); } /***************************************************************************** private code *****************************************************************************/ static void encode_mc_tree (unsigned max_state, frame_type_e frame_type, const wfa_t *wfa, bitfile_t *output) /* * Write tree of motion compensation decisions to the 'output' stream. * Depending on 'frame_type' different decoding methods are used. * 'max_state' is the last state with motion compensation infos. * * No return value. */ { unsigned label; /* current label */ unsigned state; /* current state */ unsigned total = 0; /* number of motion tree decisions */ unsigned queue [MAXSTATES]; /* state numbers in BFO */ unsigned current; /* current node to process */ unsigned last; /* last node (update every new node) */ mc_type_e type; /* type of motion compensation */ unsigned (*mc_tree_codes)[2]; /* pointer to VLC table */ unsigned bits = bits_processed (output); /* number of bits used */ if (frame_type == P_FRAME) mc_tree_codes = p_frame_codes; /* binary code */ else mc_tree_codes = b_frame_codes; /* variable length code */ /* * Traverse tree in breadth first order (starting at * level 'wfa->p_max_level'). Use a queue to store the children * of each node ('last' is the next free queue element). */ for (last = 0, state = wfa->basis_states; state < max_state; state++) if (wfa->level_of_state [state] - 1 == (int) wfa->wfainfo->p_max_level) queue [last++] = state; /* init level = 'mc_max_level' */ for (current = 0; current < last; current++) for (label = 0; label < MAXLABELS; label++) { state = queue [current]; type = wfa->mv_tree [state][label].type; if (wfa->x [state][label] + width_of_level (wfa->level_of_state [state] - 1) <= wfa->wfainfo->width && wfa->y [state][label] + height_of_level (wfa->level_of_state [state] - 1) <= wfa->wfainfo->height) { put_bits (output, mc_tree_codes [type][CODE], mc_tree_codes [type][BITS]); total++; } if (type == NONE && !isrange (wfa->tree [state][label]) && wfa->level_of_state [state] - 1 >= (int) wfa->wfainfo->p_min_level) queue [last++] = wfa->tree [state][label]; /* append child */ } OUTPUT_BYTE_ALIGN (output); debug_message ("mc-tree: %5d bits. (%5d symbols => %5.2f bps)", bits_processed (output) - bits, total, total > 0 ? ((bits_processed (output) - bits) / (double) total) : 0); } static void encode_mc_coords (unsigned max_state, const wfa_t *wfa, bitfile_t *output) /* * Write motion vector coordinates to the 'output' stream. They are stored * with the static Huffman code of the MPEG and H.263 standards. * 'max_state' is the last state with motion compensation infos. * * No return value. */ { unsigned state; /* current state */ unsigned label; /* current label */ unsigned level_count [MAXLEVEL]; /* number of mv per level */ unsigned level; /* counter */ unsigned ftotal = 0; /* #forward motion tree decisions */ unsigned btotal = 0; /* #backward decisions */ unsigned itotal = 0; /* #interpolated decisions */ unsigned bits = bits_processed (output); /* number of bits used */ unsigned sr = wfa->wfainfo->search_range; /* search range */ for (level = wfa->wfainfo->p_max_level; level >= wfa->wfainfo->p_min_level; level--) level_count [level] = 0; for (state = wfa->basis_states; state < max_state; state++) for (label = 0; label < MAXLABELS; label++) { mv_t *mv = &wfa->mv_tree[state][label]; /* motion vector info */ if (mv->type != NONE) { level_count [wfa->level_of_state [state] - 1]++; switch (mv->type) { case FORWARD: put_bits (output, mv_code_table[(mv->fx + sr)][CODE], mv_code_table[(mv->fx + sr)][BITS]); put_bits (output, mv_code_table[(mv->fy + sr)][CODE], mv_code_table[(mv->fy + sr)][BITS]); ftotal++; break; case BACKWARD: put_bits (output, mv_code_table[(mv->bx + sr)][CODE], mv_code_table[(mv->bx + sr)][BITS]); put_bits (output, mv_code_table[(mv->by + sr)][CODE], mv_code_table[(mv->by + sr)][BITS]); btotal++; break; case INTERPOLATED: put_bits (output, mv_code_table[(mv->fx + sr)][CODE], mv_code_table[(mv->fx + sr)][BITS]); put_bits (output, mv_code_table[(mv->fy + sr)][CODE], mv_code_table[(mv->fy + sr)][BITS]); put_bits (output, mv_code_table[(mv->bx + sr)][CODE], mv_code_table[(mv->bx + sr)][BITS]); put_bits (output, mv_code_table[(mv->by + sr)][CODE], mv_code_table[(mv->by + sr)][BITS]); itotal++; break; default: break; } } } OUTPUT_BYTE_ALIGN (output); debug_message ("Motion compensation: %d forward, %d backward, " "%d interpolated", ftotal, btotal, itotal); for (level = wfa->wfainfo->p_max_level; level >= wfa->wfainfo->p_min_level; level--) debug_message ("Level %d: %d motion vectors", level, level_count[level]); { unsigned total = ftotal * 2 + btotal * 2 + itotal * 4; debug_message ("mv-coord: %5d bits. (%5d symbols => %5.2f bps)", bits_processed (output) - bits, total, total > 0 ? ((bits_processed (output) - bits) / (double) total) : 0); } return; }