/*
* 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 childs
* 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;
}