diff options
Diffstat (limited to 'converter/other/fiasco/codec')
35 files changed, 11054 insertions, 0 deletions
diff --git a/converter/other/fiasco/codec/Makefile b/converter/other/fiasco/codec/Makefile new file mode 100644 index 00000000..9a9d502a --- /dev/null +++ b/converter/other/fiasco/codec/Makefile @@ -0,0 +1,27 @@ +ifeq ($(SRCDIR)x,x) + SRCDIR = $(CURDIR)/../../../.. + BUILDDIR = $(SRCDIR) +endif +FIASCOSUBDIR = converter/other/fiasco +SUBDIR = $(FIASCOSUBDIR)/codec +VPATH=.:$(SRCDIR)/$(SUBDIR) + +include $(BUILDDIR)/Makefile.config + +INCLUDES = -I$(SRCDIR)/$(FIASCOSUBDIR) -I$(SRCDIR)/$(FIASCOSUBDIR)/lib \ + -I$(SRCDIR)/$(FIASCOSUBDIR)/input -I$(SRCDIR)/$(FIASCOSUBDIR)/output + +OBJECTS = approx.o bintree.o coder.o coeff.o \ + control.o decoder.o dfiasco.o domain-pool.o ip.o motion.o mwfa.o \ + options.o prediction.o subdivide.o tiling.o wfalib.o + +MERGE_OBJECTS = $(OBJECTS) + +all: libfiasco_codec.a + +include $(SRCDIR)/Makefile.common + +libfiasco_codec.a: $(OBJECTS) + $(AR) -rc $@ $(OBJECTS) + $(RANLIB) $@ + diff --git a/converter/other/fiasco/codec/approx.c b/converter/other/fiasco/codec/approx.c new file mode 100644 index 00000000..72e38cbf --- /dev/null +++ b/converter/other/fiasco/codec/approx.c @@ -0,0 +1,702 @@ +/* + * approx.c: Approximation of range images with matching pursuit + * + * Written by: Ullrich Hafner + * + * This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec) + * Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de> + */ + +/* + * $Date: 2000/06/14 20:50:51 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#include "config.h" + +#include <math.h> + +#include "types.h" +#include "macros.h" +#include "error.h" + +#include "cwfa.h" +#include "ip.h" +#include "rpf.h" +#include "domain-pool.h" +#include "misc.h" +#include "list.h" +#include "approx.h" +#include "coeff.h" +#include "wfalib.h" + +/***************************************************************************** + + local variables + +*****************************************************************************/ + +typedef struct mp +{ + word_t exclude [MAXEDGES]; + word_t indices [MAXEDGES + 1]; + word_t into [MAXEDGES + 1]; + real_t weight [MAXEDGES]; + real_t matrix_bits; + real_t weights_bits; + real_t err; + real_t costs; +} mp_t; + +/***************************************************************************** + + prototypes + +*****************************************************************************/ + +static void +orthogonalize (unsigned index, unsigned n, unsigned level, real_t min_norm, + const word_t *domain_blocks, const coding_t *c); +static void +matching_pursuit (mp_t *mp, bool_t full_search, real_t price, + unsigned max_edges, int y_state, const range_t *range, + const domain_pool_t *domain_pool, const coeff_t *coeff, + const wfa_t *wfa, const coding_t *c); + +/***************************************************************************** + + public code + +*****************************************************************************/ + +real_t +approximate_range (real_t max_costs, real_t price, int max_edges, + int y_state, range_t *range, domain_pool_t *domain_pool, + coeff_t *coeff, const wfa_t *wfa, const coding_t *c) +/* + * Approximate image block 'range' by matching pursuit. This functions + * calls the matching pursuit algorithm several times (with different + * parameters) in order to find the best approximation. Refer to function + * 'matching_pursuit()' for more details about parameters. + * + * Return value: + * approximation costs + */ +{ + mp_t mp; + bool_t success = NO; + + /* + * First approximation attempt: default matching pursuit algorithm. + */ + mp.exclude [0] = NO_EDGE; + matching_pursuit (&mp, c->options.full_search, price, max_edges, + y_state, range, domain_pool, coeff, wfa, c); + + /* + * Next approximation attempt: remove domain block mp->indices [0] + * from domain pool (vector with smallest costs) and run the + * matching pursuit again. + */ + if (c->options.second_domain_block) + { + mp_t tmp_mp = mp; + + tmp_mp.exclude [0] = tmp_mp.indices [0]; + tmp_mp.exclude [1] = NO_EDGE; + + matching_pursuit (&tmp_mp, c->options.full_search, price, max_edges, + y_state, range, domain_pool, coeff, wfa, c); + if (tmp_mp.costs < mp.costs) /* success */ + { + success = YES; + mp = tmp_mp; + } + } + + /* + * Next approximation attempt: check whether some coefficients have + * been quantized to zero. Vectors causing the underflow are + * removed from the domain pool and then the matching pursuit + * algorithm is run again (until underflow doesn't occur anymore). + */ + if (c->options.check_for_underflow) + { + int iteration = -1; + mp_t tmp_mp = mp; + + do + { + int i; + + iteration++; + tmp_mp.exclude [iteration] = NO_EDGE; + + for (i = 0; isdomain (tmp_mp.indices [i]); i++) + if (tmp_mp.weight [i] == 0) + { + tmp_mp.exclude [iteration] = tmp_mp.indices [i]; + break; + } + + if (isdomain (tmp_mp.exclude [iteration])) /* try again */ + { + tmp_mp.exclude [iteration + 1] = NO_EDGE; + + matching_pursuit (&tmp_mp, c->options.full_search, price, + max_edges, y_state, range, domain_pool, + coeff, wfa, c); + if (tmp_mp.costs < mp.costs) /* success */ + { + success = YES; + mp = tmp_mp; + } + } + } while (isdomain (tmp_mp.exclude [iteration]) + && iteration < MAXEDGES - 1); + } + + /* + * Next approximation attempt: check whether some coefficients have + * been quantized to +/- max-value. Vectors causing the overflow are + * removed from the domain pool and then the matching pursuit + * algorithm is run again (until overflow doesn't occur anymore). + */ + if (c->options.check_for_overflow) + { + int iteration = -1; + mp_t tmp_mp = mp; + + do + { + int i; + + iteration++; + tmp_mp.exclude [iteration] = NO_EDGE; + + for (i = 0; isdomain (tmp_mp.indices [i]); i++) + { + rpf_t *rpf = tmp_mp.indices [i] ? coeff->rpf : coeff->dc_rpf; + + if (tmp_mp.weight [i] == btor (rtob (200, rpf), rpf) + || tmp_mp.weight [i] == btor (rtob (-200, rpf), rpf)) + { + tmp_mp.exclude [iteration] = tmp_mp.indices [i]; + break; + } + } + + if (isdomain (tmp_mp.exclude [iteration])) /* try again */ + { + tmp_mp.exclude [iteration + 1] = NO_EDGE; + + matching_pursuit (&tmp_mp, c->options.full_search, price, + max_edges, y_state, range, domain_pool, + coeff, wfa, c); + if (tmp_mp.costs < mp.costs) /* success */ + { + success = YES; + mp = tmp_mp; + } + } + } while (isdomain (tmp_mp.exclude [iteration]) + && iteration < MAXEDGES - 1); + } + + /* + * Finally, check whether the best approximation has costs + * smaller than 'max_costs'. + */ + if (mp.costs < max_costs) + { + int edge; + bool_t overflow = NO; + bool_t underflow = NO; + int new_index, old_index; + + new_index = 0; + for (old_index = 0; isdomain (mp.indices [old_index]); old_index++) + if (mp.weight [old_index] != 0) + { + rpf_t *rpf = mp.indices [old_index] ? coeff->rpf : coeff->dc_rpf; + + if (mp.weight [old_index] == btor (rtob (200, rpf), rpf) + || mp.weight [old_index] == btor (rtob (-200, rpf), rpf)) + overflow = YES; + + mp.indices [new_index] = mp.indices [old_index]; + mp.into [new_index] = mp.into [old_index]; + mp.weight [new_index] = mp.weight [old_index]; + new_index++; + } + else + underflow = YES; + + mp.indices [new_index] = NO_EDGE; + mp.into [new_index] = NO_EDGE; + + /* + * Update of probability models + */ + { + word_t *domain_blocks = domain_pool->generate (range->level, y_state, + wfa, + domain_pool->model); + domain_pool->update (domain_blocks, mp.indices, + range->level, y_state, wfa, domain_pool->model); + coeff->update (mp.weight, mp.into, range->level, coeff); + + Free (domain_blocks); + } + + for (edge = 0; isedge (mp.indices [edge]); edge++) + { + range->into [edge] = mp.into [edge]; + range->weight [edge] = mp.weight [edge]; + } + range->into [edge] = NO_EDGE; + range->matrix_bits = mp.matrix_bits; + range->weights_bits = mp.weights_bits; + range->err = mp.err; + } + else + { + range->into [0] = NO_EDGE; + mp.costs = MAXCOSTS; + } + + return mp.costs; +} + +/***************************************************************************** + + local variables + +*****************************************************************************/ + +static real_t norm_ortho_vector [MAXSTATES]; +/* + * Square-norm of the i-th vector of the orthogonal basis (OB) + * ||o_i||^2; i = 0, ... ,n + */ +static real_t ip_image_ortho_vector [MAXEDGES]; +/* + * Inner product between the i-th vector of the OB and the given range: + * <b, o_i>; i = 0, ... ,n + */ +static real_t ip_domain_ortho_vector [MAXSTATES][MAXEDGES]; +/* + * Inner product between the i-th vector of the OB and the image of domain j: + * <s_j, o_i>; j = 0, ... , wfa->states; i = 0, ... ,n, + */ +static real_t rem_denominator [MAXSTATES]; +static real_t rem_numerator [MAXSTATES]; +/* + * At step n of the orthogonalization the comparitive value + * (numerator_i / denominator_i):= <b, o_n>^2 / ||o_n|| , + * is computed for every domain i, + * where o_n := s_i - \sum(k = 0, ... , n-1) {(<s_i, o_k> / ||o_k||^2) o_k} + * To avoid computing the same values over and over again, + * the constant (remaining) parts of every domain are + * stored in 'rem_numerator' and 'rem_denominator' separately + */ +static bool_t used [MAXSTATES]; +/* + * Shows whether a domain image was already used in a + * linear combination (YES) or not (NO) + */ + +/***************************************************************************** + + private code + +*****************************************************************************/ + +static void +matching_pursuit (mp_t *mp, bool_t full_search, real_t price, + unsigned max_edges, int y_state, const range_t *range, + const domain_pool_t *domain_pool, const coeff_t *coeff, + const wfa_t *wfa, const coding_t *c) +/* + * Find an approximation of the current 'range' with a linear + * combination of vectors of the 'domain_pool'. The linear + * combination is generated step by step with the matching pursuit + * algorithm. If flag 'full_search' is set then compute complete set + * of linear combinations with n = {0, ..., 'max_edges'} vectors and + * return the best one. Otherwise abort the computation as soon as + * costs (LC (n + 1)) exceed costs ( LC (n)) and return the + * sub-optimal solution. 'price' is the langrange multiplier + * weighting rate and distortion. 'band' is the current color band + * and 'y_state' the corresponding state in the Y component at same + * pixel position. 'domain_pool' gives the set of available vectors, + * and 'coeff' the model for the linear factors. The number of + * elements in the linear combination is limited by 'max_edges'. In + * 'mp', vectors may be specified which should be excluded during the + * approximation. + * + * No return value. + * + * Side effects: + * vectors, factors, rate, distortion and costs are stored in 'mp' + */ +{ + unsigned n; /* current vector of the OB */ + int index; /* best fitting domain image */ + unsigned domain; /* counter */ + real_t norm; /* norm of range image */ + real_t additional_bits; /* bits for mc, nd, and tree */ + word_t *domain_blocks; /* current set of domain images */ + const real_t min_norm = 2e-3; /* lower bound of norm */ + unsigned best_n = 0; + unsigned size = size_of_level (range->level); + + /* + * Initialize domain pool and inner product arrays + */ + domain_blocks = domain_pool->generate (range->level, y_state, wfa, + domain_pool->model); + for (domain = 0; domain_blocks [domain] >= 0; domain++) + { + used [domain] = NO; + rem_denominator [domain] /* norm of domain */ + = get_ip_state_state (domain_blocks [domain], domain_blocks [domain], + range->level, c); + if (rem_denominator [domain] / size < min_norm) + used [domain] = YES; /* don't use domains with small norm */ + else + rem_numerator [domain] /* inner product <s_domain, b> */ + = get_ip_image_state (range->image, range->address, + range->level, domain_blocks [domain], c); + if (!used [domain] && fabs (rem_numerator [domain]) < min_norm) + used [domain] = YES; + } + + /* + * Exclude all domain blocks given in array 'mp->exclude' + */ + for (n = 0; isdomain (mp->exclude [n]); n++) + used [mp->exclude [n]] = YES; + + /* + * Compute the approximation costs if 'range' is approximated with + * no linear combination, i.e. the error is equal to the square + * of the image norm and the size of the automaton is determined by + * storing only zero elements in the current matrix row + */ + for (norm = 0, n = 0; n < size; n++) + norm += square (c->pixels [range->address * size + n]); + + additional_bits = range->tree_bits + range->mv_tree_bits + + range->mv_coord_bits + range->nd_tree_bits + + range->nd_weights_bits; + + mp->err = norm; + mp->weights_bits = 0; + mp->matrix_bits = domain_pool->bits (domain_blocks, NULL, range->level, + y_state, wfa, domain_pool->model); + mp->costs = (mp->matrix_bits + mp->weights_bits + + additional_bits) * price + mp->err; + + n = 0; + do + { + /* + * Current approximation is: b = d_0 o_0 + ... + d_(n-1) o_(n-1) + * with corresponding costs 'range->err + range->bits * p'. + * For all remaining state images s_i (used[s_i] == NO) set + * o_n : = s_i - \sum(k = 0, ... , n-1) {(<s_i, o_k> / ||o_k||^2) o_k} + * and try to beat current costs. + * Choose that vector for the next orthogonalization step, + * which has minimal costs: s_index. + * (No progress is indicated by index == -1) + */ + + real_t min_matrix_bits = 0; + real_t min_weights_bits = 0; + real_t min_error = 0; + real_t min_weight [MAXEDGES]; + real_t min_costs = full_search ? MAXCOSTS : mp->costs; + + for (index = -1, domain = 0; domain_blocks [domain] >= 0; domain++) + if (!used [domain]) + { + real_t matrix_bits, weights_bits; + /* + * To speed up the search through the domain images, + * the costs of using domain image 'domain' as next vector + * can be approximated in a first step: + * improvement of image quality + * <= square (rem_numerator[domain]) / rem_denominator[domain] + */ + { + word_t vectors [MAXEDGES + 1]; + word_t states [MAXEDGES + 1]; + real_t weights [MAXEDGES + 1]; + unsigned i, k; + + for (i = 0, k = 0; k < n; k++) + if (mp->weight [k] != 0) + { + vectors [i] = mp->indices [k]; + states [i] = domain_blocks [vectors [i]]; + weights [i] = mp->weight [k]; + i++; + } + vectors [i] = domain; + states [i] = domain_blocks [domain]; + weights [i] = 0.5; + vectors [i + 1] = -1; + states [i + 1] = -1; + + weights_bits = coeff->bits (weights, states, range->level, + coeff); + matrix_bits = domain_pool->bits (domain_blocks, vectors, + range->level, y_state, + wfa, domain_pool->model); + } + if (((matrix_bits + weights_bits + additional_bits) * price + + mp->err - + square (rem_numerator [domain]) / rem_denominator [domain]) + < min_costs) + { + /* + * 1.) Compute the weights (linear factors) c_i of the + * linear combination + * b = c_0 v_0 + ... + c_(n-1) v_(n-1) + c_n v_'domain' + * Use backward substitution to obtain c_i from the linear + * factors of the lin. comb. b = d_0 o_0 + ... + d_n o_n + * of the corresponding orthogonal vectors {o_0, ..., o_n}. + * Vector o_n of the orthogonal basis is obtained by using + * vector 'v_domain' in step n of the Gram Schmidt + * orthogonalization (see above for definition of o_n). + * Recursive formula for the coefficients c_i: + * c_n := <b, o_n> / ||o_n||^2 + * for i = n - 1, ... , 0: + * c_i := <b, o_i> / ||o_i||^2 + + * \sum (k = i + 1, ... , n){ c_k <v_k, o_i> + * / ||o_i||^2 } + * 2.) Because linear factors are stored with reduced precision + * factor c_i is rounded with the given precision in step i + * of the recursive formula. + */ + + unsigned k; /* counter */ + int l; /* counter */ + real_t m_bits; /* number of matrix bits to store */ + real_t w_bits; /* number of weights bits to store */ + real_t r [MAXEDGES]; /* rounded linear factors */ + real_t f [MAXEDGES]; /* linear factors */ + int v [MAXEDGES]; /* mapping of domains to vectors */ + real_t costs; /* current approximation costs */ + real_t m_err; /* current approximation error */ + + f [n] = rem_numerator [domain] / rem_denominator [domain]; + v [n] = domain; /* corresponding mapping */ + for (k = 0; k < n; k++) + { + f [k] = ip_image_ortho_vector [k] / norm_ortho_vector [k]; + v [k] = mp->indices [k]; + } + + for (l = n; l >= 0; l--) + { + rpf_t *rpf = domain_blocks [v [l]] + ? coeff->rpf : coeff->dc_rpf; + + r [l] = f [l] = btor (rtob (f [l], rpf), rpf); + + for (k = 0; k < (unsigned) l; k++) + f [k] -= f [l] * ip_domain_ortho_vector [v [l]][k] + / norm_ortho_vector [k] ; + } + + /* + * Compute the number of output bits of the linear combination + * and store the weights with reduced precision. The + * resulting linear combination is + * b = r_0 v_0 + ... + r_(n-1) v_(n-1) + r_n v_'domain' + */ + { + word_t vectors [MAXEDGES + 1]; + word_t states [MAXEDGES + 1]; + real_t weights [MAXEDGES + 1]; + int i; + + for (i = 0, k = 0; k <= n; k++) + if (f [k] != 0) + { + vectors [i] = v [k]; + states [i] = domain_blocks [v [k]]; + weights [i] = f [k]; + i++; + } + vectors [i] = -1; + states [i] = -1; + + w_bits = coeff->bits (weights, states, range->level, coeff); + m_bits = domain_pool->bits (domain_blocks, vectors, + range->level, y_state, + wfa, domain_pool->model); + } + + /* + * To compute the approximation error, the corresponding + * linear factors of the linear combination + * b = r_0 o_0 + ... + r_(n-1) o_(n-1) + r_n o_'domain' + * with orthogonal vectors must be computed with following + * formula: + * r_i := r_i + + * \sum (k = i + 1, ... , n) { r_k <v_k, o_i> + * / ||o_i||^2 } + */ + for (l = 0; (unsigned) l <= n; l++) + { + /* + * compute <v_n, o_n> + */ + real_t a; + + a = get_ip_state_state (domain_blocks [v [l]], + domain_blocks [domain], + range->level, c); + for (k = 0; k < n; k++) + a -= ip_domain_ortho_vector [v [l]][k] + / norm_ortho_vector [k] + * ip_domain_ortho_vector [domain][k]; + ip_domain_ortho_vector [v [l]][n] = a; + } + norm_ortho_vector [n] = rem_denominator [domain]; + ip_image_ortho_vector [n] = rem_numerator [domain]; + + for (k = 0; k <= n; k++) + for (l = k + 1; (unsigned) l <= n; l++) + r [k] += ip_domain_ortho_vector [v [l]][k] * r [l] + / norm_ortho_vector [k]; + /* + * Compute approximation error: + * error := ||b||^2 + + * \sum (k = 0, ... , n){r_k^2 ||o_k||^2 - 2 r_k <b, o_k>} + */ + m_err = norm; + for (k = 0; k <= n; k++) + m_err += square (r [k]) * norm_ortho_vector [k] + - 2 * r [k] * ip_image_ortho_vector [k]; + if (m_err < 0) /* TODO: return MAXCOSTS */ + warning ("Negative image norm: %f" + " (current domain: %d, level = %d)", + (double) m_err, domain, range->level); + + costs = (m_bits + w_bits + additional_bits) * price + m_err; + if (costs < min_costs) /* found a better approximation */ + { + index = domain; + min_costs = costs; + min_matrix_bits = m_bits; + min_weights_bits = w_bits; + min_error = m_err; + for (k = 0; k <= n; k++) + min_weight [k] = f [k]; + } + } + } + + if (index >= 0) /* found a better approximation */ + { + if (min_costs < mp->costs) + { + unsigned k; + + mp->costs = min_costs; + mp->err = min_error; + mp->matrix_bits = min_matrix_bits; + mp->weights_bits = min_weights_bits; + + for (k = 0; k <= n; k++) + mp->weight [k] = min_weight [k]; + + best_n = n + 1; + } + + mp->indices [n] = index; + mp->into [n] = domain_blocks [index]; + + used [index] = YES; + + /* + * Gram-Schmidt orthogonalization step n + */ + orthogonalize (index, n, range->level, min_norm, domain_blocks, c); + n++; + } + } + while (n < max_edges && index >= 0); + + mp->indices [best_n] = NO_EDGE; + + mp->costs = (mp->matrix_bits + mp->weights_bits + additional_bits) * price + + mp->err; + + Free (domain_blocks); +} + +static void +orthogonalize (unsigned index, unsigned n, unsigned level, real_t min_norm, + const word_t *domain_blocks, const coding_t *c) +/* + * Step 'n' of the Gram-Schmidt orthogonalization procedure: + * vector 'index' is orthogonalized with respect to the set + * {u_[0], ... , u_['n' - 1]}. The size of the image blocks is given by + * 'level'. If the denominator gets smaller than 'min_norm' then + * the corresponding domain is excluded from the list of available + * domain blocks. + * + * No return value. + * + * Side effects: + * The remainder values (numerator and denominator) of + * all 'domain_blocks' are updated. + */ +{ + unsigned domain; + + ip_image_ortho_vector [n] = rem_numerator [index]; + norm_ortho_vector [n] = rem_denominator [index]; + + /* + * Compute inner products between all domain images and + * vector n of the orthogonal basis: + * for (i = 0, ... , wfa->states) + * <s_i, o_n> := <s_i, v_n> - + * \sum (k = 0, ... , n - 1){ <v_n, o_k> <s_i, o_k> / ||o_k||^2} + * Moreover the denominator and numerator parts of the comparitive + * value are updated. + */ + for (domain = 0; domain_blocks [domain] >= 0; domain++) + if (!used [domain]) + { + unsigned k; + real_t tmp = get_ip_state_state (domain_blocks [index], + domain_blocks [domain], level, c); + + for (k = 0; k < n; k++) + tmp -= ip_domain_ortho_vector [domain][k] / norm_ortho_vector [k] + * ip_domain_ortho_vector [index][k]; + ip_domain_ortho_vector [domain][n] = tmp; + rem_denominator [domain] -= square (tmp) / norm_ortho_vector [n]; + rem_numerator [domain] -= ip_image_ortho_vector [n] + / norm_ortho_vector [n] + * ip_domain_ortho_vector [domain][n] ; + + /* + * Exclude vectors with small denominator + */ + if (!used [domain]) + if (rem_denominator [domain] / size_of_level (level) < min_norm) + used [domain] = YES; + } +} + + + diff --git a/converter/other/fiasco/codec/approx.h b/converter/other/fiasco/codec/approx.h new file mode 100644 index 00000000..c54b78c9 --- /dev/null +++ b/converter/other/fiasco/codec/approx.h @@ -0,0 +1,30 @@ +/* + * approx.h + * + * Written by: Ullrich Hafner + * + * This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec) + * Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de> + */ + +/* + * $Date: 2000/06/14 20:50:51 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#ifndef _APPROX_H +#define _APPROX_H + +#include "types.h" +#include "cwfa.h" +#include "domain-pool.h" + +real_t +approximate_range (real_t max_costs, real_t price, int max_edges, + int y_state, range_t *range, domain_pool_t *domain_pool, + coeff_t *coeff, const wfa_t *wfa, const coding_t *c); + +#endif /* not _APPROX_H */ + diff --git a/converter/other/fiasco/codec/bintree.c b/converter/other/fiasco/codec/bintree.c new file mode 100644 index 00000000..ddd74e15 --- /dev/null +++ b/converter/other/fiasco/codec/bintree.c @@ -0,0 +1,94 @@ +/* + * bintree.c: Bintree model of WFA tree + * + * Written by: Ullrich Hafner + * + * This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec) + * Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de> + */ + +/* + * $Date: 2000/06/14 20:50:51 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#include "config.h" + +#include "types.h" +#include "macros.h" +#include "error.h" + +#include <math.h> + +#include "bintree.h" +#include "misc.h" +#include "cwfa.h" + +/***************************************************************************** + + public code + +*****************************************************************************/ + +void +tree_update (bool_t child, unsigned level, tree_t *model) +/* + * Update tree model of given 'level'. + * + * No return value. + * + * Side effects: + * tree model is changed. + */ +{ + if (!child) + model->total [level]++; + else + { + model->counts [level]++; + model->total [level]++; + } +} + +real_t +tree_bits (bool_t child, unsigned level, const tree_t *model) +/* + * Compute number of bits needed for coding element 'child' of the bintree. + * For each 'level' a different context is used. + * + * Return value: + * # bits + */ +{ + real_t prob = model->counts [level] / (real_t) model->total [level]; + + return child ? - log2 (prob) : - log2 (1 - prob); +} + +void +init_tree_model (tree_t *tree_model) +/* + * Initialize the model for the tree. + * Symbol RANGE is synonymous with the '0' symbol and + * symbol NO_RANGE is synonymous with the '1' symbol of the binary coder. + * The 'count' array counts the number of NO_RANGE symbols. + * + * No return value. + */ +{ + unsigned level; + unsigned counts_0 [MAXLEVEL] = {20, 17, 15, 10, 5, 4, 3, + 2, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1 , 1, 1, 1}; + unsigned counts_1 [MAXLEVEL] = {1 , 1, 1, 1, 1, 1, 1, + 1, 1, 2, 3, 5, 10, 15, 20, + 25, 30, 35, 60, 60, 60, 60}; + + for (level = 0; level < MAXLEVEL ; level++) + { + tree_model->counts [level] = counts_1 [level]; + tree_model->total [level] = counts_0 [level] + counts_1 [level]; + } +} diff --git a/converter/other/fiasco/codec/bintree.h b/converter/other/fiasco/codec/bintree.h new file mode 100644 index 00000000..cdb80c94 --- /dev/null +++ b/converter/other/fiasco/codec/bintree.h @@ -0,0 +1,43 @@ +/* + * bintree.h + * + * Written by: Ullrich Hafner + * + * This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec) + * Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de> + */ + +/* + * $Date: 2000/06/14 20:50:51 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#ifndef _BINTREE_H +#define _BINTREE_H + +#include "wfa.h" +#include "types.h" + +typedef struct tree +/* + * Used for estimating the number of bits needed for storing the + * tree array. For each level a different context is used. + * The binary alphabet consists of the two symbols NO_RANGE and RANGE, + * which indicate whether there exists a tree edge or not. + */ +{ + unsigned counts [MAXLEVEL]; /* # NO_RANGE symbols at given level */ + unsigned total [MAXLEVEL]; /* total number of symbols at '' */ +} tree_t; + +real_t +tree_bits (bool_t child, unsigned level, const tree_t *model); +void +init_tree_model (tree_t *tree_model); +void +tree_update (bool_t child, unsigned level, tree_t *model); + +#endif /* not _BINTREE_H */ + diff --git a/converter/other/fiasco/codec/coder.c b/converter/other/fiasco/codec/coder.c new file mode 100644 index 00000000..df878d87 --- /dev/null +++ b/converter/other/fiasco/codec/coder.c @@ -0,0 +1,965 @@ +/* + * coder.c: WFA coder toplevel functions + * + * Written by: Ullrich Hafner + * + * This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec) + * Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de> + */ + +/* + * $Date: 2000/06/14 20:50:51 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#define _BSD_SOURCE 1 /* Make sure strdup() is in string.h */ +#define _XOPEN_SOURCE 500 /* Make sure strdup() is in string.h */ + +#include "config.h" +#include "pnm.h" + +#include <math.h> +#include <ctype.h> + +#include <string.h> + +#include "nstring.h" + +#include "types.h" +#include "macros.h" +#include "error.h" + +#include "fiasco.h" + +#include "cwfa.h" +#include "misc.h" +#include "control.h" +#include "bintree.h" +#include "subdivide.h" +#include "read.h" +#include "write.h" +#include "image.h" +#include "mwfa.h" +#include "list.h" +#include "decoder.h" +#include "motion.h" +#include "wfalib.h" +#include "domain-pool.h" +#include "coeff.h" +#include "coder.h" +#include "rpf.h" + +/***************************************************************************** + + global variables + +*****************************************************************************/ + +const real_t MAXCOSTS = 1e20; + +/***************************************************************************** + + prototypes + +*****************************************************************************/ + +static coding_t * +alloc_coder (char const * const *inputname, const c_options_t *options, + wfa_info_t *wi); +static void +free_coder (coding_t *c); +static char * +get_input_image_name (char const * const *templptr, unsigned ith_image); +static void +video_coder (char const * const *image_template, bitfile_t *output, + wfa_t *wfa, coding_t *c); +static void +frame_coder (wfa_t *wfa, coding_t *c, bitfile_t *output); +static void +print_statistics (char c, real_t costs, const wfa_t *wfa, const image_t *image, + const range_t *range); +static frame_type_e +pattern2type (unsigned frame, const char *pattern); + +/***************************************************************************** + + public code + +*****************************************************************************/ + +int +fiasco_coder (char const * const *inputname, const char *outputname, + float quality, const fiasco_c_options_t *options) +/* + * FIASCO coder. + * Encode image or video frames given by the array of filenames `inputname' + * and write to the outputfile `outputname'. + * If 'inputname' = NULL or + * 'inputname [0]' == NULL or + * 'inputname [0]' == "-", read standard input. + * If 'outputname' == NULL or "-", write on standard output. + * 'quality' defines the approximation quality and is 1 (worst) to 100 (best). + * + * Return value: + * 1 on success + * 0 otherwise + */ +{ + try + { + char const * const default_input [] = {"-", NULL}; + fiasco_c_options_t *default_options = NULL; + const c_options_t *cop; + char const * const *template; + + /* + * Check parameters + */ + if (!inputname || !inputname [0] || streq (inputname [0], "-")) + template = default_input; + else + template = inputname; + + if (quality <= 0) + { + set_error (_("Compression quality has to be positive.")); + return 0; + } + else if (quality >= 100) + { + warning (_("Quality typically is 1 (worst) to 100 (best).\n" + "Be prepared for a long running time.")); + } + + if (options) + { + cop = cast_c_options ((fiasco_c_options_t *) options); + if (!cop) + return 0; + } + else + { + default_options = fiasco_c_options_new (); + cop = cast_c_options (default_options); + } + + /* + * Open output stream and initialize WFA + */ + { + bitfile_t *output = open_bitfile (outputname, "FIASCO_DATA", + WRITE_ACCESS); + if (!output) + { + set_error (_("Can't write outputfile `%s'.\n%s"), + outputname ? outputname : "<stdout>", + get_system_error ()); + if (default_options) + fiasco_c_options_delete (default_options); + return 0; + } + else + { + wfa_t *wfa = alloc_wfa (YES); + coding_t *c = alloc_coder (template, cop, wfa->wfainfo); + + read_basis (cop->basis_name, wfa); + append_basis_states (wfa->basis_states, wfa, c); + + c->price = 128 * 64 / quality; + + video_coder (template, output, wfa, c); + + close_bitfile (output); + free_wfa (wfa); + free_coder (c); + + if (default_options) + fiasco_c_options_delete (default_options); + } + } + return 1; + } + catch + { + return 0; + } +} + +/***************************************************************************** + + private code + +*****************************************************************************/ + +static coding_t * +alloc_coder (char const * const *inputname, const c_options_t *options, + wfa_info_t *wi) +/* + * Coder structure constructor. + * Allocate memory for the FIASCO coder structure and + * fill in default values specified by 'options'. + * + * Return value: + * pointer to the new coder structure or NULL on error + */ +{ + coding_t *c = NULL; + + /* + * Check whether all specified image frames are readable and of same type + */ + { + char *filename; + int width, w = 0, height, h = 0; + bool_t color, c = NO; + unsigned n; + + for (n = 0; (filename = get_input_image_name (inputname, n)); n++) + { + FILE *file; + xelval maxval; + int format; + if (filename == NULL) + file = stdin; + else + file = pm_openr(filename); + pnm_readpnminit(file, &width, &height, &maxval, &format); + color = (PNM_FORMAT_TYPE(format) == PPM_FORMAT) ? TRUE: FALSE; + + pm_close(file); + if (n) + { + if (w != width || h != height || c != color) + { + set_error (_("Format of image frame `%s' doesn't match."), + filename ? filename : "<stdin>"); + return NULL; + } + } + else + { + w = width; + h = height; + c = color; + } + Free (filename); + } + wi->frames = n; + wi->width = w; + wi->height = h; + wi->color = c; + } + + /* + * Levels ... + */ + { + unsigned lx, ly; + + lx = (unsigned) (log2 (wi->width - 1) + 1); + ly = (unsigned) (log2 (wi->height - 1) + 1); + + wi->level = max (lx, ly) * 2 - ((ly == lx + 1) ? 1 : 0); + } + + c = Calloc (1, sizeof (coding_t)); + + c->options = *options; + c->options.lc_min_level = max (options->lc_min_level, 3); + c->options.lc_max_level = min (options->lc_max_level, wi->level - 1); + + c->tiling = alloc_tiling (options->tiling_method, + options->tiling_exponent, wi->level); + + if (wi->frames > 1 && c->tiling->exponent > 0) + { + c->tiling->exponent = 0; + warning (_("Image tiling valid only with still image compression.")); + } + + if (c->options.lc_max_level >= wi->level - c->tiling->exponent) + { + message ("'max_level' changed from %d to %d due to image tiling level.", + c->options.lc_max_level, wi->level - c->tiling->exponent - 1); + c->options.lc_max_level = wi->level - c->tiling->exponent - 1; + } + + if (c->options.lc_min_level > c->options.lc_max_level) + c->options.lc_min_level = c->options.lc_max_level; + + /* + * p_min_level, p_max_level min and max level for ND/MC prediction + * [p_min_level, p_max_level] must be a subset of [min_level, max_level] ! + */ + wi->p_min_level = max (options->p_min_level, c->options.lc_min_level); + wi->p_max_level = min (options->p_max_level, c->options.lc_max_level); + if (wi->p_min_level > wi->p_max_level) + wi->p_min_level = wi->p_max_level; + + c->options.images_level = min (c->options.images_level, + c->options.lc_max_level - 1); + + c->products_level = max (0, ((signed int) c->options.lc_max_level + - (signed int) c->options.images_level - 1)); + c->pixels = Calloc (size_of_level (c->options.lc_max_level), + sizeof (real_t)); + c->images_of_state = Calloc (MAXSTATES, sizeof (real_t *)); + c->ip_images_state = Calloc (MAXSTATES, sizeof (real_t *)); + c->ip_states_state = Calloc (MAXSTATES * MAXLEVEL, sizeof (real_t *)); + + debug_message ("Imageslevel :%d, Productslevel :%d", + c->options.images_level, c->products_level); + debug_message ("Memory : (%d + %d + %d * 'states') * 'states' + %d", + size_of_tree (c->options.images_level) * 4, + size_of_tree (c->products_level) * 4, + (c->options.lc_max_level - c->options.images_level), + size_of_level (c->options.lc_max_level)); + + /* + * Domain pools ... + */ + c->domain_pool = NULL; + c->d_domain_pool = NULL; + + /* + * Coefficients model ... + */ + c->coeff = NULL; + c->d_coeff = NULL; + + /* + * Max. number of states and edges + */ + wi->max_states = max (min (options->max_states, MAXSTATES), 1); + c->options.max_elements = max (min (options->max_elements, MAXEDGES), 1); + + /* + * Title and comment strings + */ + wi->title = strdup (options->title); + wi->comment = strdup (options->comment); + + /* + * Reduced precision format + */ + wi->rpf + = alloc_rpf (options->rpf_mantissa, options->rpf_range); + wi->dc_rpf + = alloc_rpf (options->dc_rpf_mantissa, options->dc_rpf_range); + wi->d_rpf + = alloc_rpf (options->d_rpf_mantissa, options->d_rpf_range); + wi->d_dc_rpf + = alloc_rpf (options->d_dc_rpf_mantissa, options->d_dc_rpf_range); + + /* + * Color image options ... + */ + wi->chroma_max_states = max (1, options->chroma_max_states); + + /* + * Set up motion compensation struct. + * p_min_level, p_max_level are also used for ND prediction + */ + wi->search_range = options->search_range; + wi->fps = options->fps; + wi->half_pixel = options->half_pixel_prediction; + wi->cross_B_search = options->half_pixel_prediction; + wi->B_as_past_ref = options->B_as_past_ref; + wi->smoothing = options->smoothing; + + c->mt = alloc_motion (wi); + + return c; +} + +static void +free_coder (coding_t *c) +/* + * Coder struct destructor: + * Free memory of 'coder' struct. + * + * No return value. + * + * Side effects: + * structure 'coder' is discarded. + */ +{ + free_tiling (c->tiling); + free_motion (c->mt); + + Free (c->pixels); + Free (c->images_of_state); + Free (c->ip_images_state); + Free (c->ip_states_state); + Free (c); +} + +static char * +get_input_image_name (char const * const *templptr, unsigned ith_image) +/* + * Construct the i-th image-name using templates. + * If the template contains a '[' it must be of the form + * "prefix[start-end{+,-}step]suffix" + * where "{+,-}step" is optional. + * Leading zeros of "start" are significant. + * + * Example: + * "image0[12-01-1].pgm" yields image012.pgm, image011.pgm, ..., image001.pgm + * + * Return value: + * ptr to name of image 'ith_image' or NULL if ith_image is out of range. + */ +{ + while (*templptr) + { + const char *template = *templptr++; + char *s; + + if (!(s = strchr (template, '['))) /* no template, just a filename */ + { + if (ith_image == 0) + return strdup (template); + else + ith_image--; + } + else /* template parser */ + { + unsigned n_digits; /* # of digits in image name no. */ + char *s2; + char *suffix; /* characters after template end */ + char prefix [MAXSTRLEN]; /* chars up to the template start */ + unsigned first; /* first image number */ + unsigned last; /* last image number */ + int image_num; /* current image number */ + int increment = 1; + int dummy; + + strcpy (prefix, template); + prefix [s - template] = '\0'; + + for (s2 = ++s, n_digits = 0; ISDIGIT (*s2); s2++, n_digits++) + ; + if (sscanf (s, "%d", &dummy) == 0 || dummy < 0) + error ("Input name template conversion failure.\n" + "Check spelling of template."); + first = (unsigned) dummy; + + if (*s2++ != '-') + error ("Input name template conversion failure.\n" + "Check spelling of template."); + + for (s = s2; ISDIGIT (*s2); s2++) + ; + if (sscanf (s, "%d", &dummy) == 0 || dummy < 0) + error ("Input name template conversion failure.\n" + "Check spelling of template."); + last = (unsigned) dummy; + + if (*s2 == '+' || *s2 == '-') + { + for (s = s2++; ISDIGIT (*s2); s2++) + ; + if (sscanf (s, "%d", &increment) == 0) + error ("Input name template conversion failure.\n" + "Check spelling of template."); + } + if (*s2 != ']') + error ("Input name template conversion failure.\n" + "Check spelling of template."); + suffix = s2 + 1; + + image_num = first + increment * ith_image; + if (image_num < 0) + error ("Input name template conversion failure.\n" + "Check spelling of template."); + + if ((increment > 0 && (unsigned) image_num > last) || + (increment <= 0 && (unsigned) image_num < last)) + { + /* TODO: check this */ + ith_image -= (last - first) / increment + 1; + } + else + { + char formatstr [MAXSTRLEN]; /* format string for image filename */ + char image_name [MAXSTRLEN]; /* image file name to be composed */ + + strcpy (formatstr, "%s%0?d%s"); + formatstr [4] = '0' + (char) n_digits; + sprintf (image_name, formatstr, prefix, image_num, suffix); + return strdup (image_name); + } + } + } + return NULL; +} + +static void +video_coder (char const * const *image_template, bitfile_t *output, + wfa_t *wfa, coding_t *c) +/* + * Toplevel function to encode a sequence of video frames specified + * by 'image_template'. The output is written to stream 'output'. + * Coding options are given by 'c'. + * + * No return value. + */ +{ + unsigned display; /* picture number in display order */ + int future_display; /* number of future reference */ + int frame; /* current frame number */ + char *image_name; /* image name of current frame */ + image_t *reconst = NULL; /* decoded reference image */ + bool_t future_frame = NO; /* YES if last frame was in future */ + + debug_message ("Generating %d WFA's ...", wfa->wfainfo->frames); + + future_display = -1; + frame = -1; + display = 0; + + while ((image_name = get_input_image_name (image_template, display))) + { + frame_type_e type; /* current frame type: I, B, P */ + + /* + * Determine type of next frame. + * Skip already coded frames (future reference!) + */ + if (display == 0 && !c->options.reference_filename) + type = I_FRAME; /* Force first frame to be intra */ + else + type = pattern2type (display, c->options.pattern); + + if (type != I_FRAME && c->options.reference_filename) + /* Load reference from disk */ + { + debug_message ("Reading reference frame `%s'.", + c->options.reference_filename); + reconst = read_image (c->options.reference_filename); + c->options.reference_filename = NULL; + } + if ((int) display == future_display) /* Skip already coded future ref */ + { + display++; + continue; + } + else if (type == B_FRAME && (int) display > future_display) + { + unsigned i = display; + /* + * Search for future reference + */ + while (type == B_FRAME) + { + char *name; /* image name of future frame */ + + i++; + name = get_input_image_name (image_template, i); + + if (!name) /* Force last valid frame to be 'P' */ + { + future_display = i - 1; + type = P_FRAME; + } + else + { + future_display = i; + image_name = name; + type = pattern2type (i, c->options.pattern); + } + frame = future_display; + } + } + else + { + frame = display; + display++; + } + + debug_message ("Coding \'%s\' [%c-frame].", image_name, + type == I_FRAME ? 'I' : (type == P_FRAME ? 'P' : 'B')); + + /* + * Depending on current frame type update past and future frames + * which are needed as reference frames. + */ + c->mt->frame_type = type; + if (type == I_FRAME) + { + if (c->mt->past) /* discard past frame */ + free_image (c->mt->past); + c->mt->past = NULL; + if (c->mt->future) /* discard future frame */ + free_image (c->mt->future); + c->mt->future = NULL; + if (reconst) /* discard current frame */ + free_image (reconst); + reconst = NULL; + } + else if (type == P_FRAME) + { + if (c->mt->past) /* discard past frame */ + free_image (c->mt->past); + c->mt->past = reconst; /* past frame <- current frame */ + reconst = NULL; + if (c->mt->future) /* discard future frame */ + free_image (c->mt->future); + c->mt->future = NULL; + } + else /* B_FRAME */ + { + if (future_frame) /* last frame was future frame */ + { + if (c->mt->future) /* discard future frame */ + free_image (c->mt->future); + c->mt->future = reconst; /* future frame <- current frame */ + reconst = NULL; + } + else + { + if (wfa->wfainfo->B_as_past_ref == YES) + { + if (c->mt->past) /* discard past frame */ + free_image (c->mt->past); + c->mt->past = reconst; /* past frame <- current frame */ + reconst = NULL; + } + else + { + if (reconst) /* discard current frame */ + free_image (reconst); + reconst = NULL; + } + } + } + + /* + * Start WFA coding of current frame + */ + future_frame = frame == future_display; + c->mt->number = frame; + c->mt->original = read_image (image_name); + if (c->tiling->exponent && type == I_FRAME) + perform_tiling (c->mt->original, c->tiling); + + frame_coder (wfa, c, output); + + /* + * Regenerate image: + * 1. Compute approximation of WFA ranges (real image bintree order) + * 2. Generate byte image in rasterscan order + * 3. Apply motion compensation + */ + reconst = decode_image (wfa->wfainfo->width, wfa->wfainfo->height, + FORMAT_4_4_4, NULL, wfa); + + if (type != I_FRAME) + restore_mc (0, reconst, c->mt->past, c->mt->future, wfa); + + if (c->mt->original) + free_image (c->mt->original); + c->mt->original = NULL; + + remove_states (wfa->basis_states, wfa); /* Clear WFA structure */ + } + + if (reconst) + free_image (reconst); + if (c->mt->future) + free_image (c->mt->future); + if (c->mt->past) + free_image (c->mt->past); + if (c->mt->original) + free_image (c->mt->original); +} + +static frame_type_e +pattern2type (unsigned frame, const char *pattern) +{ + int tmp = TOUPPER (pattern [frame % strlen (pattern)]); + frame_type_e retval; + + switch (tmp) + { + case 'I': + retval = I_FRAME; + break; + case 'B': + retval = B_FRAME; + break; + case 'P': + retval = P_FRAME; + break; + default: + error ("Frame type %c not valid. Choose one of I,B or P.", tmp); + } + return retval; +} + +static void +frame_coder (wfa_t *wfa, coding_t *c, bitfile_t *output) +/* + * + * WFA Coding of next frame. All important coding parameters are + * stored in 'c'. The generated 'wfa' is written to stream 'output' + * immediately after coding. + * + * No return value. + */ +{ + unsigned state; + range_t range; /* first range == the entire image */ + real_t costs; /* total costs (minimized quantity) */ + unsigned bits; /* number of bits written on disk */ + clock_t ptimer; + + prg_timer (&ptimer, START); + + bits = bits_processed (output); + + init_tree_model (&c->tree); + init_tree_model (&c->p_tree); + + c->domain_pool + = alloc_domain_pool (c->options.id_domain_pool, + wfa->wfainfo->max_states, + c->options.max_elements, wfa); + c->d_domain_pool + = alloc_domain_pool ((c->options.prediction + || c->mt->frame_type != I_FRAME) + ? c->options.id_d_domain_pool : "constant", + wfa->wfainfo->max_states, + c->options.max_elements, wfa); + + c->coeff = alloc_coeff_model (c->options.id_rpf_model, + wfa->wfainfo->rpf, + wfa->wfainfo->dc_rpf, + c->options.lc_min_level, + c->options.lc_max_level); + c->d_coeff = alloc_coeff_model (c->options.id_d_rpf_model, + wfa->wfainfo->d_rpf, + wfa->wfainfo->d_dc_rpf, + c->options.lc_min_level, + c->options.lc_max_level); + + if (!c->mt->original->color) /* grayscale image */ + { + memset (&range, 0, sizeof (range_t)); + range.level = wfa->wfainfo->level; + + costs = subdivide (MAXCOSTS, GRAY, RANGE, &range, wfa, c, + c->options.prediction || c->mt->frame_type != I_FRAME, + NO); + if (c->options.progress_meter != FIASCO_PROGRESS_NONE) + message (""); + + if (isrange (range.tree)) /* entire image is approx. by lc? */ + error ("No root state generated!"); + else + wfa->root_state = range.tree; + + print_statistics ('\0', costs, wfa, c->mt->original, &range); + } + else + { + int YCb_node = -1; + int tree [3]; /* 3 root states of each color comp. */ + color_e band; + + /* + * When compressing color images, the three color components (YCbCr) + * are copied into a large image: + * [ Y Cr ] + * [ Cb 0 ] + * I.e. the color components of an image are processed in a row. + * After all components are compressed, virtual states are generated + * to describe the large image. + */ + for (band = first_band (YES); band <= last_band (YES) ; band++) + { + debug_message ("Encoding color component %d", band); + tree [band] = RANGE; + if (band == Cb) + { + unsigned min_level; + + c->domain_pool->chroma (wfa->wfainfo->chroma_max_states, wfa, + c->domain_pool->model); + /* + * Don't use a finer partioning for the chrominancy bands than for + * the luminancy band. + */ + for (min_level = MAXLEVEL, state = wfa->basis_states; + state < wfa->states; state++) + { + unsigned lincomb, label; + + for (lincomb = 0, label = 0; label < MAXLABELS; label++) + lincomb += isrange (wfa->tree [state][label]) ? 1 : 0; + if (lincomb) + min_level = min (min_level, + (unsigned) (wfa->level_of_state [state] + - 1)); + } + c->options.lc_min_level = min_level; + if (c->mt->frame_type != I_FRAME) /* subtract mc of luminance */ + subtract_mc (c->mt->original, c->mt->past, c->mt->future, wfa); + } + + memset (&range, 0, sizeof (range_t)); + range.level = wfa->wfainfo->level; + + costs = subdivide (MAXCOSTS, band, tree [Y], &range, wfa, c, + c->mt->frame_type != I_FRAME && band == Y, NO); + if (c->options.progress_meter != FIASCO_PROGRESS_NONE) + message (""); + { + char colors [] = {'Y', 'B', 'R'}; + + print_statistics (colors [band], costs, wfa, + c->mt->original, &range); + } + + if (isrange (range.tree)) /* whole image is approx. by a l.c. */ + error ("No root state generated for color component %d!", band); + else + tree[band] = range.tree; + + if (band == Cb) + { + wfa->tree [wfa->states][0] = tree[Y]; + wfa->tree [wfa->states][1] = tree[Cb]; + YCb_node = wfa->states; + append_state (YES, compute_final_distribution (wfa->states, wfa), + wfa->wfainfo->level + 1, wfa, c); + } + } + /* + * generate two virtual states (*) + * + * * + * / \ + * + * + * / \ / + * Y CbCr + */ + wfa->tree [wfa->states][0] = tree[Cr]; + wfa->tree [wfa->states][1] = RANGE; + append_state (YES, compute_final_distribution (wfa->states, wfa), + wfa->wfainfo->level + 1, wfa, c); + wfa->tree[wfa->states][0] = YCb_node; + wfa->tree[wfa->states][1] = wfa->states - 1; + append_state (YES, compute_final_distribution (wfa->states, wfa), + wfa->wfainfo->level + 2, wfa, c); + + wfa->root_state = wfa->states - 1; + } + + for (state = wfa->basis_states; state < MAXSTATES; state++) + { + unsigned level; + + if (c->images_of_state [state]) + { + Free (c->images_of_state [state]); + c->images_of_state [state] = NULL; + } + if (c->ip_images_state [state]) + { + Free (c->ip_images_state [state]); + c->ip_images_state [state] = NULL; + } + for (level = c->options.images_level + 1; + level <= c->options.lc_max_level; + level++) + if (c->ip_states_state [state][level]) + { + Free (c->ip_states_state [state][level]); + c->ip_states_state [state][level] = NULL; + } + + } + + locate_delta_images (wfa); + write_next_wfa (wfa, c, output); + + bits = bits_processed (output) - bits; + debug_message ("Total number of bits written: %d (%d bytes, %5.3f bpp)", + bits, bits >> 3, + bits / (double) (c->mt->original->height + * c->mt->original->width)); + debug_message ("Total encoding time (real): %d sec", + prg_timer (&ptimer, STOP) / 1000); + + c->domain_pool->free (c->domain_pool); + c->d_domain_pool->free (c->d_domain_pool); + + c->coeff->free (c->coeff); + c->d_coeff->free (c->d_coeff); +} + +static void +print_statistics (char c, real_t costs, const wfa_t *wfa, const image_t *image, + const range_t *range) +{ + unsigned max_level, min_level, state, label, lincomb; + + for (max_level = 0, min_level = MAXLEVEL, state = wfa->basis_states; + state < wfa->states; state++) + { + for (lincomb = 0, label = 0; label < MAXLABELS; label++) + lincomb += isrange(wfa->tree[state][label]) ? 1 : 0; + + if (lincomb) + { + max_level = max (max_level, + (unsigned) (wfa->level_of_state [state] - 1)); + min_level = min (min_level, + (unsigned) (wfa->level_of_state [state] - 1)); + } + } + debug_message ("Image partitioning: maximum level %d , minimum level %d", + max_level, min_level); + debug_message ("WFA contains %d states (%d basis states).", + wfa->states, wfa->basis_states); + debug_message ("Estimated error: %.2f (RMSE: %.2f, PSNR: %.2f dB).", + (double) range->err, + sqrt (range->err / image->width / image->height), + 10 * log ( 255.0 * 255.0 / + (range->err / image->width / image->height)) + / log (10.0)); + debug_message ("Estimated filesize: %.0f bits (%.0f bytes).", + (double) (range->tree_bits + range->matrix_bits + + range->weights_bits + + range->mv_tree_bits + range->mv_coord_bits + + range->nd_tree_bits + range->nd_weights_bits), + (double) (range->tree_bits + range->matrix_bits + + range->weights_bits + range->mv_tree_bits + + range->mv_coord_bits + range->nd_tree_bits + + range->nd_weights_bits) / 8); + if (c) + debug_message ("(%cT: %.0f, %cM: %.0f, %cW: %.0f, %cMC: %.0f, " + "%cMV: %.0f, %cNT: %.0f, %cNW: %.0f.)", + c, (double) range->tree_bits, + c, (double) range->matrix_bits, + c, (double) range->weights_bits, + c, (double) range->mv_tree_bits, + c, (double) range->mv_coord_bits, + c, (double) range->nd_tree_bits, + c, (double) range->nd_weights_bits); + else + debug_message ("(T: %.0f, M: %.0f, W: %.0f, MC: %.0f, MV: %.0f, " + "NT: %.0f, NW: %.0f.)", + (double) range->tree_bits, + (double) range->matrix_bits, + (double) range->weights_bits, + (double) range->mv_tree_bits, + (double) range->mv_coord_bits, + (double) range->nd_tree_bits, + (double) range->nd_weights_bits); + debug_message ("Total costs : %.2f", (double) costs); +} diff --git a/converter/other/fiasco/codec/coder.h b/converter/other/fiasco/codec/coder.h new file mode 100644 index 00000000..c6f4bb7c --- /dev/null +++ b/converter/other/fiasco/codec/coder.h @@ -0,0 +1,24 @@ +/* + * coder.h + * + * Written by: Ullrich Hafner + * + * This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec) + * Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de> + */ + +/* + * $Date: 2000/06/14 20:50:51 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#ifndef _CODER_H +#define _CODER_H + +#include "types.h" +#include "cwfa.h" + +#endif /* not _CODER_H */ + diff --git a/converter/other/fiasco/codec/coeff.c b/converter/other/fiasco/codec/coeff.c new file mode 100644 index 00000000..0cd64f17 --- /dev/null +++ b/converter/other/fiasco/codec/coeff.c @@ -0,0 +1,369 @@ +/* + * coeff.c: Matching pursuit coefficients probability model + * + * Written by: Ullrich Hafner + * + * This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec) + * Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de> + */ + +/* + * $Date: 2000/06/14 20:50:51 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#include <string.h> +#include "config.h" + +#include "types.h" +#include "macros.h" +#include "error.h" + +#include "rpf.h" +#include "misc.h" +#include "coeff.h" + +/* + * Coefficient model interface: + * Implementing the coefficients model interface requires the + * following steps: + * - Add a constructor that initializes the coeff_t structure + * - Allocate new model with default_alloc() + * - Fill the c_array_t coeff_models[] array with constructor and name + * - Write code for methods bits() and update() + * - Either use default functions for remaining methods or override them + * The new model is automatically registered at the command line. + */ + +/***************************************************************************** + uniform distribution coefficients model +*****************************************************************************/ + +static coeff_t * +alloc_uniform_coeff_model (rpf_t *rpf, rpf_t *dc_rpf, + unsigned min_level, unsigned max_level); +static void +uniform_update (const real_t *used_coeff, const word_t *used_states, + unsigned level, coeff_t *coeff); +static real_t +uniform_bits (const real_t *used_coeff, const word_t *used_states, + unsigned level, const coeff_t *coeff); + +/***************************************************************************** + default functions +*****************************************************************************/ + +static void +default_model_free (void *model); +static void * +default_model_duplicate (const coeff_t *coeff, const void *model); +static void +default_free (coeff_t *coeff); +static coeff_t * +default_alloc (rpf_t *rpf, rpf_t *dc_rpf, + unsigned min_level, unsigned max_level); + +/***************************************************************************** + adaptive arithmetic coding model +*****************************************************************************/ + +static coeff_t * +alloc_aac_coeff_model (rpf_t *rpf, rpf_t *dc_rpf, + unsigned min_level, unsigned max_level); +static void +aac_model_free (void *model); +static void * +aac_model_alloc (const coeff_t *coeff); +static void * +aac_model_duplicate (const coeff_t *coeff, const void *model); +static void +aac_update (const real_t *used_coeff, const word_t *used_states, + unsigned level, coeff_t *coeff); +static real_t +aac_bits (const real_t *used_coeff, const word_t *used_states, + unsigned level, const coeff_t *coeff); + +/***************************************************************************** + + public code + +*****************************************************************************/ + +typedef struct c_array +{ + const char *identifier; + coeff_t *(*function) (rpf_t *rpf, rpf_t *dc_rpf, + unsigned min_level, unsigned max_level); +} c_array_t; + +c_array_t coeff_models[] = {{"adaptive", alloc_aac_coeff_model}, + {"uniform", alloc_uniform_coeff_model}, + {NULL, NULL}}; + +coeff_t * +alloc_coeff_model (const char *coeff_model_name, rpf_t *rpf, rpf_t *dc_rpf, + unsigned min_level, unsigned max_level) +/* + * Allocate a new coefficients model which is identified by the string + * 'coeff_model_name'. 'rpf' and 'dc_rpf' define the reduced + * precision formats the should be used to quantize normal and DC + * components, respectively. 'min_level' and 'max_level' define the + * range of range approximations. + * + * Return value: + * pointer to the allocated coefficients model + * + * Note: + * Refer to 'coeff.h' for a short description of the member functions. */ +{ + unsigned n; + + for (n = 0; coeff_models [n].identifier; n++) /* step through all id's */ + if (strcaseeq (coeff_models [n].identifier, coeff_model_name)) + return coeff_models [n].function (rpf, dc_rpf, min_level, max_level); + + warning ("Can't initialize coefficients model '%s'. " + "Using default value '%s'.", + coeff_model_name, coeff_models [0].identifier); + + return coeff_models [0].function (rpf, dc_rpf, min_level, max_level); +} + +/***************************************************************************** + + private code + +*****************************************************************************/ + +/***************************************************************************** + uniform distribution coefficients model +*****************************************************************************/ + +static coeff_t * +alloc_uniform_coeff_model (rpf_t *rpf, rpf_t *dc_rpf, + unsigned min_level, unsigned max_level) +/* + * Underlying probability model: uniform distribution. + * I.e. each coefficient is written as such with + * (1 + exponent_bits + mantissa_bits) bits. + */ +{ + coeff_t *coeff = default_alloc (rpf, dc_rpf, min_level, max_level); + + coeff->bits = uniform_bits; + coeff->update = uniform_update; + + return coeff; +} + +static real_t +uniform_bits (const real_t *used_coeff, const word_t *used_states, + unsigned level, const coeff_t *coeff) +{ + unsigned edge; + real_t bits = 0; /* #bits to store coefficients */ + + for (edge = 0; isedge (used_states [edge]); edge++) + { + rpf_t *rpf = used_states [edge] ? coeff->rpf : coeff->dc_rpf; + + bits += rpf->mantissa_bits + 1; + } + + return bits; +} + +static void +uniform_update (const real_t *used_coeff, const word_t *used_states, + unsigned level, coeff_t *coeff) +{ + return; /* nothing to do */ +} + +/***************************************************************************** + adaptive arithmetic coding model +*****************************************************************************/ + +typedef struct aac_model +{ + word_t *counts; + word_t *totals; +} aac_model_t; + +static coeff_t * +alloc_aac_coeff_model (rpf_t *rpf, rpf_t *dc_rpf, + unsigned min_level, unsigned max_level) +/* + * Underlying probability model: adaptive arithmetic coding using + * the level of a range as context. + */ +{ + coeff_t *coeff = default_alloc (rpf, dc_rpf, min_level, max_level); + + coeff->bits = aac_bits; + coeff->update = aac_update; + coeff->model_free = aac_model_free; + coeff->model_duplicate = aac_model_duplicate; + coeff->model = aac_model_alloc (coeff); + + return coeff; +} + +static real_t +aac_bits (const real_t *used_coeff, const word_t *used_states, + unsigned level, const coeff_t *coeff) +{ + real_t bits = 0; /* # bits to store coefficients */ + unsigned edge; + int state; + word_t *counts; + aac_model_t *model = (aac_model_t *) coeff->model; + + counts = model->counts + + (1 << (1 + coeff->dc_rpf->mantissa_bits)) + + ((level - coeff->min_level) + * (1 << (1 + coeff->rpf->mantissa_bits))); + + for (edge = 0; isedge (state = used_states [edge]); edge++) + if (state) + bits -= log2 (counts [rtob (used_coeff [edge], coeff->rpf)] + / (real_t) model->totals [level + - coeff->min_level + 1]); + else + bits -= log2 (model->counts [rtob (used_coeff [edge], coeff->dc_rpf)] + / (real_t) model->totals [0]); + + return bits; +} + +static void +aac_update (const real_t *used_coeff, const word_t *used_states, + unsigned level, coeff_t *coeff) +{ + unsigned edge; + int state; + word_t *counts; + aac_model_t *model = (aac_model_t *) coeff->model; + + counts = model->counts + + (1 << (1 + coeff->dc_rpf->mantissa_bits)) + + ((level - coeff->min_level) + * (1 << (1 + coeff->rpf->mantissa_bits))); + + for (edge = 0; isedge (state = used_states [edge]); edge++) + if (state) + { + counts [rtob (used_coeff [edge], coeff->rpf)]++; + model->totals [level - coeff->min_level + 1]++; + } + else + { + model->counts [rtob (used_coeff [edge], coeff->dc_rpf)]++; + model->totals [0]++; + } +} + +static void * +aac_model_duplicate (const coeff_t *coeff, const void *model) +{ + aac_model_t *src = (aac_model_t *) model; + aac_model_t *dst = aac_model_alloc (coeff); + + memcpy (dst->counts, src->counts, + sizeof (word_t) * ((coeff->max_level - coeff->min_level + 1) + * (1 << (1 + coeff->rpf->mantissa_bits)) + + (1 << (1 + coeff->dc_rpf->mantissa_bits)))); + memcpy (dst->totals, src->totals, + sizeof (word_t) * (coeff->max_level - coeff->min_level + 1 + 1)); + + return dst; +} + +static void * +aac_model_alloc (const coeff_t *coeff) +{ + aac_model_t *model; + unsigned size = (coeff->max_level - coeff->min_level + 1) + * (1 << (1 + coeff->rpf->mantissa_bits)) + + (1 << (1 + coeff->dc_rpf->mantissa_bits)); + + model = Calloc (1, sizeof (aac_model_t)); + model->counts = Calloc (size, sizeof (word_t)); + model->totals = Calloc (coeff->max_level - coeff->min_level + 1 + 1, + sizeof (word_t)); + /* + * Initialize model + */ + { + unsigned n; + word_t *ptr = model->counts; + + for (n = size; n; n--) + *ptr++ = 1; + model->totals [0] = 1 << (1 + coeff->dc_rpf->mantissa_bits); + for (n = coeff->min_level; n <= coeff->max_level; n++) + model->totals [n - coeff->min_level + 1] + = 1 << (1 + coeff->rpf->mantissa_bits); + } + + return (void *) model; +} + +static void +aac_model_free (void *model) +{ + aac_model_t *aac_model = (aac_model_t *) model; + + if (aac_model) + { + Free (aac_model->counts); + Free (aac_model->totals); + Free (aac_model); + } +} + +/***************************************************************************** + default functions +*****************************************************************************/ + +static coeff_t * +default_alloc (rpf_t *rpf, rpf_t *dc_rpf, + unsigned min_level, unsigned max_level) +{ + coeff_t *coeff = Calloc (1, sizeof (coeff_t)); + + coeff->rpf = rpf; + coeff->dc_rpf = dc_rpf; + coeff->min_level = min_level; + coeff->max_level = max_level; + coeff->model = NULL; + coeff->bits = NULL; + coeff->update = NULL; + coeff->free = default_free; + coeff->model_free = default_model_free; + coeff->model_duplicate = default_model_duplicate; + + return coeff; +} + +static void +default_free (coeff_t *coeff) +{ + coeff->model_free (coeff->model); + Free (coeff); +} + +static void * +default_model_duplicate (const coeff_t *coeff, const void *model) +{ + return NULL; +} + +static void +default_model_free (void *model) +{ + if (model) + Free (model); +} diff --git a/converter/other/fiasco/codec/coeff.h b/converter/other/fiasco/codec/coeff.h new file mode 100644 index 00000000..118cd0fc --- /dev/null +++ b/converter/other/fiasco/codec/coeff.h @@ -0,0 +1,61 @@ +/* + * coeff.h + * + * Written by: Ullrich Hafner + * + * This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec) + * Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de> + */ + +/* + * $Date: 2000/06/14 20:50:51 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#ifndef _COEFF_H +#define _COEFF_H + +#include "types.h" +#include "rpf.h" +#include "wfa.h" + +typedef struct coeff +{ + rpf_t *rpf; /* reduced precision format */ + rpf_t *dc_rpf; /* RPF of DC (state 0) component */ + unsigned min_level, max_level; /* allocate memory for [min,..,max] */ + void *model; /* generic pointer to prob. model */ + real_t (*bits) (const real_t *used_coeff, const word_t *used_domains, + unsigned level, const struct coeff *coeff); + /* + * Compute bit-rate of a range approximation with coefficients given by + * -1 terminated list 'used_domains'. + */ + void (*update) (const real_t *used_coeff, const word_t *used_domains, + unsigned level, struct coeff *coeff); + /* + * Update the probability model according to the chosen approximation. + * (given by the -1 terminated list 'used_domains'). + */ + void (*free) (struct coeff *coeff); + /* + * Discard the given coefficients struct. + */ + void (*model_free) (void *model); + /* + * Free given probability model. + */ + void *(*model_duplicate) (const struct coeff *coeff, const void *model); + /* + * Duplicate the given probability model (i.e. alloc and copy). + */ +} coeff_t; + +coeff_t * +alloc_coeff_model (const char *coeff_model_name, rpf_t *rpf, rpf_t *dc_rpf, + unsigned min_level, unsigned max_level); + +#endif /* not _COEFF_H */ + diff --git a/converter/other/fiasco/codec/control.c b/converter/other/fiasco/codec/control.c new file mode 100644 index 00000000..9af9928b --- /dev/null +++ b/converter/other/fiasco/codec/control.c @@ -0,0 +1,276 @@ +/* + * control.c: Control unit of WFA structure + * + * Written by: Ullrich Hafner + * + * This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec) + * Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de> + */ + +/* + * $Date: 2000/06/14 20:50:51 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#include "config.h" + +#if HAVE_STRING_H +# include <string.h> +#else /* not HAVE_STRING_H */ +# include <strings.h> +#endif /* not HAVE_STRING_H */ + +#include "types.h" +#include "macros.h" +#include "error.h" + +#include "cwfa.h" +#include "ip.h" +#include "misc.h" +#include "wfalib.h" +#include "control.h" + +/***************************************************************************** + + prototypes + +*****************************************************************************/ + +static void +clear_or_alloc (real_t **ptr, size_t size); +static void +compute_images (unsigned from, unsigned to, const wfa_t *wfa, coding_t *c); + +/***************************************************************************** + + public code + +*****************************************************************************/ + +void +append_state (bool_t auxiliary_state, real_t final, unsigned level_of_state, + wfa_t *wfa, coding_t *c) +/* + * Append a 'wfa' state. If 'auxiliary_state' == YES then + * allocate memory for inner products and state images. 'final' is + * the final distribution of the new state. 'level_of_state' is the + * level of the subimage which is represented by this state + * + * No return value. + * + * Side effects: + * The WFA information are updated in structure 'wfa' + * State images are computed and inner products are cleared (in 'c') + */ +{ + wfa->final_distribution [wfa->states] = final; + wfa->level_of_state [wfa->states] = level_of_state; + + if (!auxiliary_state) + { + unsigned level; + + wfa->domain_type [wfa->states] = USE_DOMAIN_MASK; + + /* + * Allocate memory for inner products and for state images + */ + clear_or_alloc (&c->images_of_state [wfa->states], + size_of_tree (c->options.images_level)); + + for (level = c->options.images_level + 1; + level <= c->options.lc_max_level; level++) + clear_or_alloc (&c->ip_states_state [wfa->states][level], + wfa->states + 1); + + clear_or_alloc (&c->ip_images_state [wfa->states], + size_of_tree (c->products_level)); + + /* + * Compute the images of the current state at level 0,..,'imageslevel' + */ + + c->images_of_state [wfa->states][0] = final; + compute_images (wfa->states, wfa->states, wfa, c); + + /* + * Compute the inner products between the current state and the + * old states 0,...,'states'-1 + */ + + compute_ip_states_state (wfa->states, wfa->states, wfa, c); + } + else + { + unsigned level; + + wfa->domain_type [wfa->states] = 0; + + /* + * Free the allocated memory + */ + if (c->images_of_state [wfa->states] != NULL) + { + Free (c->images_of_state [wfa->states]); + c->images_of_state [wfa->states] = NULL; + } + for (level = 0; level <= c->options.lc_max_level; level++) + if (c->ip_states_state [wfa->states][level]) + { + Free (c->ip_states_state [wfa->states][level]); + c->ip_states_state [wfa->states][level] = NULL; + } + if (c->ip_images_state [wfa->states]) + { + Free (c->ip_images_state [wfa->states]); + c->ip_images_state [wfa->states] = NULL; + } + } + + wfa->states++; + if (wfa->states >= MAXSTATES) + error ("Maximum number of states reached!"); +} + +void +append_basis_states (unsigned basis_states, wfa_t *wfa, coding_t *c) +/* + * Append the WFA basis states 0, ... , ('basis_states' - 1). + * + * No return value. + * + * Side effects: + * The WFA information are updated in structure 'wfa' + * State images and inner products are computed (in 'c') + */ +{ + unsigned level, state; + + /* + * Allocate memory + */ + + for (state = 0; state < basis_states; state++) + { + clear_or_alloc (&c->images_of_state [state], + size_of_tree (c->options.images_level)); + + for (level = c->options.images_level + 1; + level <= c->options.lc_max_level; level++) + clear_or_alloc (&c->ip_states_state [state][level], state + 1); + + clear_or_alloc (&c->ip_images_state [state], + size_of_tree (c->products_level)); + + c->images_of_state [state][0] = wfa->final_distribution [state]; + wfa->level_of_state [state] = -1; + } + + compute_images (0, basis_states - 1, wfa, c); + compute_ip_states_state (0, basis_states - 1, wfa, c); + wfa->states = basis_states; + + if (wfa->states >= MAXSTATES) + error ("Maximum number of states reached!"); +} + +void +append_transitions (unsigned state, unsigned label, const real_t *weight, + const word_t *into, wfa_t *wfa) +/* + * Append the 'wfa' transitions (given by the arrays 'weight' and 'into') + * of the range ('state','label'). + * + * No return value. + * + * Side effects: + * new 'wfa' edges are appended + */ +{ + unsigned edge; + + wfa->y_column [state][label] = 0; + for (edge = 0; isedge (into [edge]); edge++) + { + append_edge (state, into [edge], weight [edge], label, wfa); + if (into [edge] == wfa->y_state [state][label]) + wfa->y_column [state][label] = 1; + } +} + +/***************************************************************************** + + private code + +*****************************************************************************/ + +static void +compute_images (unsigned from, unsigned to, const wfa_t *wfa, coding_t *c) +/* + * Computes the images of the given states 'from', ... , 'to' + * at level 0,...,'c->imagelevel'. + * Uses the fact that each state image is a linear combination of state + * images, i.e. s_i := c_0 s_0 + ... + c_i s_i. + */ +{ + unsigned label, level, state; + + /* + * Compute the images Phi(state) + * # level = 0 + * ## level = 1 + * #### level = 2 + * ######## level = 3 + * ... + * ########...## level = imageslevel + */ + + for (level = 1; level <= c->options.images_level; level++) + for (state = from; state <= to; state++) + for (label = 0; label < MAXLABELS; label++) + { + real_t *dst, *src; + unsigned edge; + int domain; /* current domain */ + + if (ischild (domain = wfa->tree[state][label])) + { + dst = c->images_of_state [state] + address_of_level (level) + + label * size_of_level (level - 1); + src = c->images_of_state [domain] + + address_of_level (level - 1); + memcpy (dst, src, size_of_level (level - 1) * sizeof (real_t)); + } + for (edge = 0; isedge (domain = wfa->into[state][label][edge]); + edge++) + { + unsigned n; + real_t weight = wfa->weight [state][label][edge]; + + dst = c->images_of_state [state] + address_of_level (level) + + label * size_of_level (level - 1); + src = c->images_of_state [domain] + + address_of_level (level - 1); + + for (n = size_of_level (level - 1); n; n--) + *dst++ += *src++ * weight; + } + } + +} + +static void +clear_or_alloc (real_t **ptr, size_t size) +/* + * if *ptr == NULL allocate memory with Calloc + * otherwise fill the real_t-array ptr[] with 0 + */ +{ + if (*ptr == NULL) + *ptr = Calloc (size, sizeof (real_t)); + else + memset (*ptr, 0, size * sizeof (real_t)); + +} diff --git a/converter/other/fiasco/codec/control.h b/converter/other/fiasco/codec/control.h new file mode 100644 index 00000000..f601d8b8 --- /dev/null +++ b/converter/other/fiasco/codec/control.h @@ -0,0 +1,33 @@ +/* + * control.h + * + * Written by: Ullrich Hafner + * + * This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec) + * Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de> + */ + +/* + * $Date: 2000/06/14 20:50:51 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#ifndef _CONTROL_H +#define _CONTROL_H + +#include "cwfa.h" +#include "types.h" + +void +append_transitions (unsigned state, unsigned label, const real_t *weight, + const word_t *into, wfa_t *wfa); +void +append_basis_states (unsigned basis_states, wfa_t *wfa, coding_t *c); +void +append_state (bool_t auxiliary_state, real_t final, unsigned level_of_state, + wfa_t *wfa, coding_t *c); + +#endif /* not _CONTROL_H */ + diff --git a/converter/other/fiasco/codec/cwfa.h b/converter/other/fiasco/codec/cwfa.h new file mode 100644 index 00000000..9c4e7fee --- /dev/null +++ b/converter/other/fiasco/codec/cwfa.h @@ -0,0 +1,107 @@ +/* + * cwfa.h + * + * Written by: Ullrich Hafner + * + * This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec) + * Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de> + */ + +/* + * $Date: 2000/10/28 17:39:30 $ + * $Author: hafner $ + * $Revision: 5.3 $ + * $State: Exp $ + */ + +#ifndef _CWFA_H +#define _CWFA_H + +#include "wfa.h" +#include "types.h" +#include "tiling.h" +#include "rpf.h" +#include "domain-pool.h" +#include "bintree.h" +#include "coeff.h" +#include "list.h" +#include "wfalib.h" +#include "options.h" + +extern const real_t MAXCOSTS; + +typedef struct motion +{ + image_t *original; /* Current image */ + image_t *past; /* Preceeding image */ + image_t *future; /* Succeeding image */ + frame_type_e frame_type; /* frame type: B_, P_ I_FRAME */ + unsigned number; /* display number of frame */ + real_t *xbits; /* # bits for mv x-component */ + real_t *ybits; /* # bits for mv y-component */ + real_t **mc_forward_norms; /* norms of mcpe */ + real_t **mc_backward_norms; /* norms of mcpe */ +} motion_t; + +typedef struct range +/* + * Information about current range in the original image. + * Approximation data (error, encoding bits, approximation type and factors + * of the linear combination) are also saved. + */ +{ + unsigned global_address; /* We need absolute image addresses + for distance calculations. */ + unsigned x, y; /* Coordinates of upper left corner */ + unsigned image; /* Position in the tree */ + unsigned address; /* Address of the pixel data */ + unsigned level; /* Level of the range */ + real_t weight [MAXEDGES + 1]; /* coeff. of the approximation */ + word_t into [MAXEDGES + 1]; /* used domains of the approximation */ + int tree; /* == domain : range is approximated + with new state 'domain' + == RANGE : + with a linear comb. */ + real_t err; /* approximation error */ + real_t tree_bits; /* # bits to encode tree */ + real_t matrix_bits; /* # bits to encode matrices */ + real_t weights_bits; /* # bits to encode weights */ + mv_t mv; /* motion vector */ + real_t mv_tree_bits; /* # bits to encode mv tree */ + real_t mv_coord_bits; /* # bits to encode mv coordinates */ + real_t nd_tree_bits; /* # bits to encode nd tree */ + real_t nd_weights_bits; /* # bits to encode nd factors */ + bool_t prediction; /* range is predicted? */ +} range_t; + +typedef struct coding +/* + * All parameters and variables that must be accessible through the coding + * process. + */ +{ + real_t price; /* determines quality of approx. */ + real_t **images_of_state; /* image of state i at level + 0, ... , imageslevel */ + real_t *(*ip_states_state)[MAXLEVEL]; /* inner products between state i + and states 0, ... , i + at all image levels */ + real_t **ip_images_state; /* inner products between all + ranges and state i */ + real_t *pixels; /* current image pixels stored in tree + order (only leaves are stored) */ + unsigned products_level; /* inner products are stored up to + this level */ + tiling_t *tiling; /* tiling of the entire image */ + tree_t tree; /* probability model */ + tree_t p_tree; /* prediction probability model */ + motion_t *mt; /* motion compensation information */ + coeff_t *coeff; + coeff_t *d_coeff; + domain_pool_t *domain_pool; + domain_pool_t *d_domain_pool; + c_options_t options; /* global options */ +} coding_t; + +#endif /* not _CWFA_H */ + diff --git a/converter/other/fiasco/codec/decoder.c b/converter/other/fiasco/codec/decoder.c new file mode 100644 index 00000000..9474c1e7 --- /dev/null +++ b/converter/other/fiasco/codec/decoder.c @@ -0,0 +1,1532 @@ +/* + * decode.c: Decoding of an image represented by a WFA + * + * Written by: Ullrich Hafner + * Michael Unger + * + * This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec) + * Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de> + */ + +/* + * $Date: 2000/10/22 10:44:48 $ + * $Author: hafner $ + * $Revision: 5.3 $ + * $State: Exp $ + */ + +#include "config.h" + +#if HAVE_STRING_H +# include <string.h> +#else /* not HAVE_STRING_H */ +# include <strings.h> +#endif /* not HAVE_STRING_H */ + +#include "types.h" +#include "macros.h" +#include "error.h" + +#include "wfa.h" +#include "image.h" +#include "misc.h" +#include "motion.h" +#include "read.h" +#include "wfalib.h" +#include "decoder.h" + +/***************************************************************************** + + prototypes + +*****************************************************************************/ + +static void +compute_state_images (unsigned frame_level, word_t **simg, + const u_word_t *offset, const wfa_t *wfa); +static void +free_state_images (unsigned max_level, bool_t color, word_t **state_image, + u_word_t *offset, const unsigned *root_state, + unsigned range_state, format_e format, const wfa_t *wfa); +static void +alloc_state_images (word_t ***images, u_word_t **offsets, const image_t *frame, + const unsigned *root_state, unsigned range_state, + unsigned max_level, format_e format, const wfa_t *wfa); +static void +compute_actual_size (unsigned luminance_root, + unsigned *width, unsigned *height, const wfa_t *wfa); +static void +enlarge_image (int enlarge_factor, format_e format, unsigned y_root, + wfa_t *wfa); +static word_t * +duplicate_state_image (const word_t *domain, unsigned offset, unsigned level); + +/***************************************************************************** + + public code + +*****************************************************************************/ + +video_t * +alloc_video (bool_t store_wfa) +/* + * Video struct constructor: + * Initialize video structure and allocate memory for current, past + * and future WFA if flag 'store_wfa' is TRUE. + * + * Return value: + * pointer to the new video structure + */ +{ + video_t *video = Calloc (1, sizeof (video_t)); + + video->future_display = -1; + video->display = 0; + + video->future = video->sfuture = video->past + = video->frame = video->sframe = NULL; + + if (store_wfa) + { + video->wfa = alloc_wfa (NO); + video->wfa_past = alloc_wfa (NO); + video->wfa_future = alloc_wfa (NO); + } + else + video->wfa = video->wfa_past = video->wfa_future = NULL; + + return video; +} + +void +free_video (video_t *video) +/* + * Video struct destructor: + * Free memory of given 'video' struct. + * + * No return value. + * + * Side effects: + * 'video' struct is discarded. + */ +{ + if (video->past) + free_image (video->past); + if (video->future) + free_image (video->future); + if (video->sfuture) + free_image (video->sfuture); + if (video->frame) + free_image (video->frame); + if (video->sframe) + free_image (video->sframe); + if (video->wfa) + free_wfa (video->wfa); + if (video->wfa_past) + free_wfa (video->wfa_past); + if (video->wfa_future) + free_wfa (video->wfa_future); + + Free (video); +} + +image_t * +get_next_frame (bool_t store_wfa, int enlarge_factor, + int smoothing, const char *reference_frame, + format_e format, video_t *video, dectimer_t *timer, + wfa_t *orig_wfa, bitfile_t *input) +/* + * Get next frame of the WFA 'video' from stream 'input'. + * 'orig_wfa' is the constant part of the WFA used by all frames. + * Depending on values of 'enlarge_factor' and 'smoothing' enlarge and + * smooth image, respectively. + * If 'store_wfa' is TRUE, then store WFA structure of reference frames + * (used by analysis tool xwfa). + * If 'reference_frame' is not NULL, then load image 'reference_frame' + * from disk. + * 'format' gives the color format to be used (either 4:2:0 or 4:4:4). + * If 'timer' is not NULL, then accumulate running time statistics. + * + * Return value: + * pointer to decoded frame + * + * Side effects: + * 'video' and 'timer' struct are modified. + */ +{ + image_t *frame = NULL; /* current frame */ + image_t *sframe = NULL; /* current smoothed frame */ + bool_t current_frame_is_future_frame = NO; + + if (video->future_display == video->display) + { + /* + * Future frame is already computed since it has been used + * as reference frame. So just return the stored frame. + */ + if (video->frame) /* discard current frame */ + free_image (video->frame); + video->frame = video->future; + video->future = NULL; + + if (video->sframe) /* discard current (smoothed) frame */ + free_image (video->sframe); + video->sframe = video->sfuture; + video->sfuture = NULL; + + if (store_wfa) + copy_wfa (video->wfa, video->wfa_future); + + video->display++; + + if (!store_wfa) + video->wfa = NULL; + } + else + { + do /* compute next frame(s) */ + { + unsigned frame_number; /* current frame number */ + clock_t ptimer; + unsigned int stop_timer [3]; + wfa_t *tmp_wfa = NULL; + + if (!store_wfa) + video->wfa = orig_wfa; + else + { + tmp_wfa = alloc_wfa (NO); + copy_wfa (tmp_wfa, video->wfa); + copy_wfa (video->wfa, orig_wfa); + } + + /* + * First step: read WFA from disk + */ + prg_timer (&ptimer, START); + frame_number = read_next_wfa (video->wfa, input); + stop_timer [0] = prg_timer (&ptimer, STOP); + if (timer) + { + timer->input [video->wfa->frame_type] += stop_timer [0]; + timer->frames [video->wfa->frame_type]++; + } + + /* + * Read reference frame from disk if required + * (i.e., 1st frame is of type B or P) + */ + if (video->display == 0 && video->wfa->frame_type != I_FRAME) + { + if (!reference_frame) + error ("First frame is %c-frame but no " + "reference frame is given.", + video->wfa->frame_type == B_FRAME ? 'B' : 'P'); + + video->frame = read_image (reference_frame); + video->sframe = NULL; + } + + /* + * Depending on current frame type update past and future frames + */ + if (video->wfa->frame_type == I_FRAME) + { + if (video->past) /* discard past frame */ + free_image (video->past); + video->past = NULL; + if (video->future) /* discard future frame */ + free_image (video->future); + video->future = NULL; + if (video->sfuture) /* discard (smoothed) future frame */ + free_image (video->sfuture); + video->sfuture = NULL; + if (video->frame) /* discard current frame */ + free_image (video->frame); + video->frame = NULL; + if (video->sframe) /* discard current (smoothed) frame */ + free_image (video->sframe); + video->sframe = NULL; + } + else if (video->wfa->frame_type == P_FRAME) + { + if (video->past) /* discard past frame */ + free_image (video->past); + video->past = video->frame; /* past <- current frame */ + video->frame = NULL; + if (video->sframe) /* discard current (smoothed) frame */ + free_image (video->sframe); + video->sframe = NULL; + if (store_wfa) + copy_wfa (video->wfa_past, tmp_wfa); + if (video->future) /* discard future frame */ + free_image (video->future); + video->future = NULL; + if (video->sfuture) /* discard (smoothed) future frame */ + free_image (video->sfuture); + video->sfuture = NULL; + } + else /* B_FRAME */ + { + if (current_frame_is_future_frame) + { + if (video->future) /* discard future frame */ + free_image (video->future); + video->future = frame; /* future <- current frame */ + if (video->sfuture) /* discard (smoothed) future frame */ + free_image (video->sfuture); + video->sfuture = sframe; /* future <- current (smoothed) */ + if (store_wfa) + copy_wfa (video->wfa_future, tmp_wfa); + if (video->frame) /* discard current frame */ + free_image (video->frame); + video->frame = NULL; + if (video->sframe) /* discard current (smoothed) frame */ + free_image (video->sframe); + video->sframe = NULL; + frame = NULL; + sframe = NULL; + } + else + { + if (video->wfa->wfainfo->B_as_past_ref == YES) + { + if (video->past) /* discard past frame */ + free_image (video->past); + video->past = video->frame; /* past <- current frame */ + video->frame = NULL; + if (video->sframe) /* discard current (smoothed) frame */ + free_image (video->sframe); + video->sframe = NULL; + if (store_wfa) + copy_wfa (video->wfa_past, tmp_wfa); + } + else + { + if (video->frame) /* discard current */ + free_image (video->frame); + video->frame = NULL; + if (video->sframe) /* discard current (smoothed) frame */ + free_image (video->sframe); + video->sframe = NULL; + } + } + } + if (tmp_wfa) + free_wfa (tmp_wfa); + + current_frame_is_future_frame = NO; + /* + * Second step: decode image + * Optionally enlarge image if specified by option 'enlarge_factor'. + */ + { + unsigned orig_width, orig_height; + + stop_timer [0] = stop_timer [1] = stop_timer [2] = 0; + + enlarge_image (enlarge_factor, format, + (video->wfa->wfainfo->color + && format == FORMAT_4_2_0) + ? video->wfa->tree [video->wfa->tree [video->wfa->root_state][0]][0] : -1, video->wfa); + + if (enlarge_factor > 0) + { + orig_width = video->wfa->wfainfo->width << enlarge_factor; + orig_height = video->wfa->wfainfo->height << enlarge_factor; + } + else + { + orig_width = video->wfa->wfainfo->width >> - enlarge_factor; + orig_height = video->wfa->wfainfo->height >> - enlarge_factor; + if (orig_width & 1) + orig_width++; + if (orig_height & 1) + orig_height++; + } + + frame = decode_image (orig_width, orig_height, format, + timer != NULL ? stop_timer : NULL, + video->wfa); + if (timer) + { + timer->preprocessing [video->wfa->frame_type] += stop_timer [0]; + timer->decoder [video->wfa->frame_type] += stop_timer [1]; + timer->cleanup [video->wfa->frame_type] += stop_timer [2]; + } + } + + /* + * Third step: restore motion compensation + */ + if (video->wfa->frame_type != I_FRAME) + { + prg_timer (&ptimer, START); + restore_mc (enlarge_factor, frame, video->past, video->future, + video->wfa); + stop_timer [0] = prg_timer (&ptimer, STOP); + if (timer) + timer->motion [video->wfa->frame_type] += stop_timer [0]; + } + + /* + * Fourth step: smooth image along partitioning borders + */ + prg_timer (&ptimer, START); + if (smoothing < 0) /* smoothing not changed by user */ + smoothing = video->wfa->wfainfo->smoothing; + if (smoothing > 0 && smoothing <= 100) + { + sframe = clone_image (frame); + smooth_image (smoothing, video->wfa, sframe); + } + else + sframe = NULL; + + stop_timer [0] = prg_timer (&ptimer, STOP); + if (timer) + timer->smooth [video->wfa->frame_type] += stop_timer [0]; + + if (frame_number == video->display) + { + video->display++; + video->frame = frame; + video->sframe = sframe; + frame = NULL; + sframe = NULL; + } + else if (frame_number > video->display) + { + video->future_display = frame_number; + current_frame_is_future_frame = YES; + } + + if (!store_wfa) + remove_states (video->wfa->basis_states, video->wfa); + } while (!video->frame); + + if (!store_wfa) + video->wfa = NULL; + } + + return video->sframe ? video->sframe : video->frame; +} + +image_t * +decode_image (unsigned orig_width, unsigned orig_height, format_e format, + unsigned *dec_timer, const wfa_t *wfa) +/* + * Compute image which is represented by the given 'wfa'. + * 'orig_width'x'orig_height' gives the resolution of the image at + * coding time. Use 4:2:0 subsampling or 4:4:4 'format' for color images. + * If 'dec_timer' is given, accumulate running time statistics. + * + * Return value: + * pointer to decoded image + * + * Side effects: + * '*dectimer' is changed if 'dectimer' != NULL. + */ +{ + unsigned root_state [3]; /* root of bintree for each band */ + unsigned width, height; /* computed image size */ + image_t *frame; /* regenerated frame */ + word_t **images; /* pointer to array of pointers + to state images */ + u_word_t *offsets; /* pointer to array of state image + offsets */ + unsigned max_level; /* max. level of state with approx. */ + unsigned state; + clock_t ptimer; + + prg_timer (&ptimer, START); + + /* + * Compute root of bintree for each color band + */ + if (wfa->wfainfo->color) + { + root_state [Y] = wfa->tree [wfa->tree [wfa->root_state][0]][0]; + root_state [Cb] = wfa->tree [wfa->tree [wfa->root_state][0]][1]; + root_state [Cr] = wfa->tree [wfa->tree [wfa->root_state][1]][0]; + } + else + root_state [GRAY] = wfa->root_state; + + /* + * Compute maximum level of a linear combination + */ + for (max_level = 0, state = wfa->basis_states; state < wfa->states; state++) + if (isedge (wfa->into [state][0][0]) || isedge (wfa->into [state][1][0])) + max_level = max (max_level, wfa->level_of_state [state]); + + + /* + * Allocate frame buffer for decoded image + */ + compute_actual_size (format == FORMAT_4_2_0 ? root_state [Y] : MAXSTATES, + &width, &height, wfa); + width = max (width, orig_width); + height = max (height, orig_height); + frame = alloc_image (width, height, wfa->wfainfo->color, format); + + /* + * Allocate buffers for intermediate state images + */ + if (wfa->wfainfo->color) + { + wfa->level_of_state [wfa->root_state] = 128; + wfa->level_of_state [wfa->tree[wfa->root_state][0]] = 128; + wfa->level_of_state [wfa->tree[wfa->root_state][1]] = 128; + } + alloc_state_images (&images, &offsets, frame, root_state, 0, max_level, + format, wfa); + + if (dec_timer) + dec_timer [0] += prg_timer (&ptimer, STOP); + + /* + * Decode all state images, forming the complete image. + */ + prg_timer (&ptimer, START); + compute_state_images (max_level, images, offsets, wfa); + if (dec_timer) + dec_timer [1] += prg_timer (&ptimer, STOP); + + /* + * Cleanup buffers used for intermediate state images + */ + prg_timer (&ptimer, START); + free_state_images (max_level, frame->color, images, offsets, root_state, 0, + format, wfa); + + /* + * Crop decoded image if the image size differs. + */ + if (orig_width != width || orig_height != height) + { + frame->height = orig_height; + frame->width = orig_width; + if (orig_width != width) + { + color_e band; /* current color band */ + word_t *src, *dst; /* source and destination pointers */ + unsigned y; /* current row */ + + for (band = first_band (frame->color); + band <= last_band (frame->color); band++) + { + src = dst = frame->pixels [band]; + for (y = orig_height; y; y--) + { + memmove (dst, src, orig_width * sizeof (word_t)); + dst += orig_width; + src += width; + } + if (format == FORMAT_4_2_0 && band == Y) + { + orig_width >>= 1; + orig_height >>= 1; + width >>= 1; + } + } + } + } + if (dec_timer) + dec_timer [2] += prg_timer (&ptimer, STOP); + + return frame; +} + +image_t * +decode_state (unsigned state, unsigned level, wfa_t *wfa) +/* + * Decode 'state' image of 'wfa' at given 'level'. + * + * Return value. + * pointer to decoded state image + * + * Side effects: + * 'wfa' states > 'state' are removed. + */ +{ + word_t *domains [2]; + image_t *img = Calloc (1, sizeof (image_t)); + + /* + * Generate a new state with a 1.0 transition to 'state' + */ + remove_states (state + 1, wfa); + append_edge (state + 1, state, 1.0, 0, wfa); + wfa->states = state + 2; + + img->color = NO; + img->width = width_of_level (level); + img->height = height_of_level (level); + img->format = FORMAT_4_4_4; + img->pixels [GRAY] = decode_range (state + 1, 0, level, domains, wfa); + + /* + * Copy decoded range to the frame buffer + */ + { + word_t *src, *dst; + unsigned y; + + src = domains [0]; + dst = img->pixels [GRAY]; + for (y = img->height; y; y--) + { + memcpy (dst, src, width_of_level (level) * sizeof (word_t)); + src += width_of_level (level); + dst += img->width; + } + Free (domains [0]); + } + + return img; +} + +word_t * +decode_range (unsigned range_state, unsigned range_label, unsigned range_level, + word_t **domain, wfa_t *wfa) +/* + * Compute 'wfa' image of range (identified by 'state' and 'label') + * at 'range_level (works as function decode_image()). + * + * Return value: + * pointer to the pixels in SHORT format + * + * Side effects: + * if 'domain' != NULL then also the domain blocks + * of the corresponding range blocks are generated + * and returned in domain[] + * 'wfa->level_of_state []' is changed + */ +{ + unsigned root_state [3]; /* dummy (for alloc_state_images) */ + image_t *state_image; /* regenerated state image */ + word_t **images; /* pointer to array of pointers + to state images */ + u_word_t *offsets; /* pointer to array of state image + offsets */ + word_t *range; + + enlarge_image (range_level - (wfa->level_of_state [range_state] - 1), + FORMAT_4_4_4, -1, wfa); + root_state [0] = range_state; + state_image = alloc_image (width_of_level (range_level + 1), + height_of_level (range_level + 1), + NO, FORMAT_4_4_4); + alloc_state_images (&images, &offsets, state_image, NULL, range_state, + range_level + 1, NO, wfa); + compute_state_images (range_level + 1, images, offsets, wfa); + + range = Calloc (size_of_level (range_level), sizeof (word_t)); + + if ((range_level & 1) == 0) /* square image */ + { + memcpy (range, + images [range_state + (range_level + 1) * wfa->states] + + range_label * size_of_level (range_level), + size_of_level (range_level) * sizeof (word_t)); + } + else /* rectangle */ + { + word_t *src, *dst; + unsigned y; + + src = images [range_state + (range_level + 1) * wfa->states] + + range_label * width_of_level (range_level); + dst = range; + for (y = height_of_level (range_level); y; y--) + { + memcpy (dst, src, width_of_level (range_level) * sizeof (word_t)); + dst += width_of_level (range_level); + src += width_of_level (range_level + 1); + } + } + + if (domain != NULL) /* copy domain images */ + { + int s; /* domain state */ + unsigned edge; /* counter */ + + if (ischild (s = wfa->tree [range_state][range_label])) + *domain++ = duplicate_state_image (images [s + (range_level) + * wfa->states], + offsets [s + (range_level) + * wfa->states], + range_level); + for (edge = 0; isedge (s = wfa->into[range_state][range_label][edge]); + edge++) + *domain++ = duplicate_state_image (images [s + (range_level) + * wfa->states], + offsets [s + (range_level) + * wfa->states], + range_level); + *domain = NULL; + } + + free_state_images (range_level + 1, NO, images, offsets, NULL, range_state, + NO, wfa); + free_image (state_image); + + return range; +} + +void +smooth_image (unsigned sf, const wfa_t *wfa, image_t *image) +/* + * Smooth 'image' along the partitioning boundaries of the 'wfa' + * with factor 's'. + * + * No return value. + * + * Side effects: + * pixel values of the 'image' are modified with respect to 's' + */ +{ + int is, inegs; /* integer factors of s and 1 - s*/ + unsigned state; + unsigned img_width = image->width; + unsigned img_height = image->height; + real_t s = 1.0 - sf / 200.0; + + if (s < 0.5 || s >= 1) /* value out of range */ + return; + + is = s * 512 + .5; /* integer representation of s */ + inegs = (1 - s) * 512 + .5; /* integer representation of 1 - s */ + + for (state = wfa->basis_states; + state < (wfa->wfainfo->color + ? wfa->tree [wfa->root_state][0] + : wfa->states); state++) + { + word_t *bptr = image->pixels [Y]; /* pointer to right or + lower line */ + unsigned level = wfa->level_of_state[state]; /* level of state image */ + unsigned width = width_of_level (level); /* size of state image */ + unsigned height = height_of_level (level); /* size of state image */ + + if (wfa->y [state][1] >= img_height || wfa->x [state][1] >= img_width) + continue; /* outside visible area */ + + if (level % 2) /* horizontal smoothing */ + { + unsigned i; /* line counter */ + word_t *img1; /* pointer to left or upper line */ + word_t *img2; /* pointer to right or lower line */ + + img1 = bptr + (wfa->y [state][1] - 1) * img_width + + wfa->x [state][1]; + img2 = bptr + wfa->y [state][1] * img_width + wfa->x [state][1]; + + for (i = min (width, img_width - wfa->x [state][1]); i; + i--, img1++, img2++) + { + int tmp = *img1; + +#ifdef HAVE_SIGNED_SHIFT + *img1 = (((is * tmp) >> 10) << 1) + + (((inegs * (int) *img2) >> 10) << 1); + *img2 = (((is * (int) *img2) >> 10) << 1) + + (((inegs * tmp) >> 10) << 1); +#else /* not HAVE_SIGNED_SHIFT */ + *img1 = (((is * tmp) / 1024) * 2) + + (((inegs * (int) *img2) / 1024) * 2); + *img2 = (((is * (int) *img2) / 1024) * 2) + + (((inegs * tmp) / 1024) *2); +#endif /* not HAVE_SIGNED_SHIFT */ + } + } + else /* vertical smoothing */ + { + unsigned i; /* line counter */ + word_t *img1; /* pointer to left or upper line */ + word_t *img2; /* pointer to right or lower line */ + + img1 = bptr + wfa->y [state][1] * img_width + wfa->x [state][1] - 1; + img2 = bptr + wfa->y [state][1] * img_width + wfa->x [state][1]; + + for (i = min (height, img_height - wfa->y [state][1]); i; + i--, img1 += img_width, img2 += img_width) + { + int tmp = *img1; + +#ifdef HAVE_SIGNED_SHIFT + *img1 = (((is * tmp) >> 10) << 1) + + (((inegs * (int) *img2) >> 10) << 1); + *img2 = (((is * (int) *img2) >> 10) << 1) + + (((inegs * tmp) >> 10) << 1); +#else /* not HAVE_SIGNED_SHIFT */ + *img1 = (((is * tmp) / 1024) * 2) + + (((inegs * (int) *img2) / 1024) * 2); + *img2 = (((is * (int) *img2) / 1024) * 2) + + (((inegs * tmp) / 1024) *2); +#endif /* not HAVE_SIGNED_SHIFT */ + } + } + } +} + +/***************************************************************************** + + private code + +*****************************************************************************/ + +static void +enlarge_image (int enlarge_factor, format_e format, unsigned y_root, + wfa_t *wfa) +/* + * Enlarge or reduce size of state images by factor 2^'enlarge_factor'. + * Use 4:2:0 subsampling if specified by 'format', else use 4:4:4 format. + * 'wfa' root state of the first chroma band is given by 'y_root' + 1. + * + * No return value. + * + * Side effects: + * coordinates of ranges and motion blocks in the WFA structure 'wfa' + * are modified. + */ +{ + + if (enlarge_factor != 0 || format == FORMAT_4_2_0) + { + unsigned state; + + if (enlarge_factor == 0) + { + state = y_root + 1; + enlarge_factor = -1; + } + else + state = wfa->basis_states; + + for (; state < wfa->states; state++) + { + unsigned label, n; + + wfa->level_of_state [state] + = max (wfa->level_of_state [state] + enlarge_factor * 2, 0); + + for (label = 0; label < MAXLABELS; label++) + if (enlarge_factor > 0) + { + wfa->x [state][label] <<= enlarge_factor; + wfa->y [state][label] <<= enlarge_factor; + for (n = enlarge_factor; n; n--) + { + wfa->mv_tree [state][label].fx *= 2; + wfa->mv_tree [state][label].fy *= 2; + wfa->mv_tree [state][label].bx *= 2; + wfa->mv_tree [state][label].by *= 2; + } + } + else /* enlarge_factor < 0 */ + { + wfa->x [state][label] >>= - enlarge_factor; + wfa->y [state][label] >>= - enlarge_factor; + for (n = - enlarge_factor; n; n--) + { + wfa->mv_tree [state][label].fx /= 2; + wfa->mv_tree [state][label].fy /= 2; + wfa->mv_tree [state][label].bx /= 2; + wfa->mv_tree [state][label].by /= 2; + } + } + if (format == FORMAT_4_2_0 && state == y_root) + enlarge_factor--; + } + } +} + +static void +compute_actual_size (unsigned luminance_root, + unsigned *width, unsigned *height, const wfa_t *wfa) +/* + * Compute actual size of the frame represented by the given 'wfa'. + * (The reconstructed frame may get larger than the original due + * to the bintree partitioning.) + * If 'luminance_root' < MAXSTATES then the size of chroma ranges (4:2:0). + * + * Return values: + * actual 'width' and 'height' of the decoded frame. + */ +{ + unsigned x = 0, y = 0; /* maximum coordinates */ + unsigned state; /* counter */ + + for (state = wfa->basis_states; state < wfa->states; state++) + if (isedge (wfa->into [state][0][0]) || isedge (wfa->into [state][1][0])) + { + unsigned mult = state > luminance_root ? 2 : 1; + + x = max ((wfa->x [state][0] + + width_of_level (wfa->level_of_state [state])) * mult, x); + y = max ((wfa->y [state][0] + + height_of_level (wfa->level_of_state [state])) * mult, y); + } + + if (x & 1) /* ensure that image size is even */ + x++; + if (y & 1) + y++; + *width = x; + *height = y; +} + +static void +alloc_state_images (word_t ***images, u_word_t **offsets, const image_t *frame, + const unsigned *root_state, unsigned range_state, + unsigned max_level, format_e format, const wfa_t *wfa) +/* + * Generate list of 'wfa' state images which have to be computed for + * each level to obtain the decoded 'frame'. 'root_state[]' denotes the + * state images of the three color bands. + * 'max_level' fives the max. level of a linear combination. + * Memory is allocated for every required state image. + * Use 4:2:0 subsampling or 4:4:4 'format' for color images. + * If 'range_state' > 0 then rather compute image of 'range_state' than + * image of 'wfa->root_state'. + * + * Return values: + * '*images' Pointer to array of state image pointers + * '*offsets' Pointer to array of state image offsets. + * + * Side effects: + * The arrays given above are filled with useful values. + */ +{ + word_t **simg; /* ptr to list of state image ptr's */ + u_word_t *offs; /* ptr to list of offsets */ + unsigned level; /* counter */ + + simg = Calloc (wfa->states * (max_level + 1), sizeof (word_t *)); + offs = Calloc (wfa->states * (max_level + 1), sizeof (u_word_t)); + + /* + * Initialize buffers for those state images which are at 'max_level'. + */ + if (range_state > 0) /* a range is given */ + { + simg [range_state + max_level * wfa->states] = frame->pixels [GRAY]; + offs [range_state + max_level * wfa->states] = frame->width; + } + else + { + unsigned state; + + for (state = wfa->basis_states; state <= root_state [Y]; state++) + if (wfa->level_of_state [state] == max_level) + { + simg [state + max_level * wfa->states] + = (frame->pixels [Y] + wfa->y [state][0] * frame->width + + wfa->x [state][0]); + offs [state + max_level * wfa->states] = frame->width; + } + if (frame->color) + { + unsigned width = format == FORMAT_4_2_0 ? + (frame->width >> 1) : frame->width; + for (; state < wfa->states; state++) + if (wfa->level_of_state [state] == max_level) + { + simg [state + max_level * wfa->states] + = (frame->pixels [state > root_state [Cb] ? Cr : Cb] + + wfa->y [state][0] * width + wfa->x [state][0]); + offs [state + max_level * wfa->states] = width; + } + } + } + + /* + * Generate list of state images which must be computed at each level + */ + for (level = max_level; level > 0; level--) + { + int child, domain; + unsigned state, label, edge; + + /* + * Range approximation with child. + */ + for (state = 1; state < (range_state > 0 ? + range_state + 1 : wfa->states); state++) + if (simg [state + level * wfa->states]) + for (label = 0; label < MAXLABELS; label++) + if (ischild (child = wfa->tree[state][label])) + { + if (isedge (wfa->into[state][label][0])) + { + /* + * Allocate new image block. + */ + simg [child + (level - 1) * wfa->states] + = Calloc (size_of_level (level - 1), sizeof (word_t)); + offs [child + (level - 1) * wfa->states] + = width_of_level (level - 1); + } + else + { + /* + * Use image block and offset of parent. + */ + if (level & 1) /* split vertically */ + { + simg [child + (level - 1) * wfa->states] + = (simg [state + level * wfa->states] + + label * (height_of_level (level - 1) + * offs [state + + level * wfa->states])); + } + else /* split horizontally */ + { + simg [child + (level - 1) * wfa->states] + = (simg [state + level * wfa->states] + + label * width_of_level (level - 1)); + } + offs [child + (level - 1) * wfa->states] + = offs [state + level * wfa->states]; + } + } + /* + * Range approximation with linear combination + */ + for (state = 1; state < (range_state > 0 ? + range_state + 1 : wfa->states); state++) + if (simg [state + level * wfa->states]) + for (label = 0; label < MAXLABELS; label++) + for (edge = 0; isedge (domain = wfa->into[state][label][edge]); + edge++) + { + if (domain > 0 /* don't allocate memory for state 0 */ + && !simg [domain + (level - 1) * wfa->states]) + { + simg [domain + (level - 1) * wfa->states] + = Calloc (size_of_level (level - 1), sizeof (word_t)); + offs [domain + (level - 1) * wfa->states] + = width_of_level (level - 1); + } + } + + } + + *images = simg; + *offsets = offs; +} + +static void +free_state_images (unsigned max_level, bool_t color, word_t **state_image, + u_word_t *offset, const unsigned *root_state, + unsigned range_state, format_e format, const wfa_t *wfa) +/* + * Free memory of state images. + * For more details refer to the inverse function 'alloc_state_images()'. + * + * No return value. + * + * Side effects: + * arrays 'state_image' and 'offset' are discarded. + */ +{ + word_t marker; /* ptr is required as a marker */ + unsigned level; + + if (range_state > 0) + { + state_image [range_state + max_level * wfa->states] = ▮ + } + else + { + unsigned state; + + /* + * Initialize state image array with states at 'max_level' + */ + for (state = wfa->basis_states; state <= root_state [Y]; state++) + if (wfa->level_of_state [state] == max_level) + state_image [state + max_level * wfa->states] = ▮ + + if (color) + { + if (format == FORMAT_4_2_0) + level = max_level - 2; + else + level = max_level; + + for (; state < wfa->states; state++) + if (wfa->level_of_state [state] == level) + state_image [state + level * wfa->states] = ▮ + } + } + + for (level = max_level; level > 0; level--) + { + int domain, child; + unsigned state, label, edge; + /* + * Range approximation with child. + */ + for (state = 1; state < (range_state > 0 ? + range_state + 1 : wfa->states); state++) + if (state_image [state + level * wfa->states]) + for (label = 0; label < MAXLABELS; label++) + if (ischild (child = wfa->tree[state][label])) + { + if (isedge (wfa->into[state][label][0]) + && (state_image [child + (level - 1) * wfa->states] + != &marker)) + Free (state_image [child + (level - 1) * wfa->states]); + state_image [child + (level - 1) * wfa->states] = ▮ + } + /* + * Range approximation with linear combination + */ + for (state = 1; state < (range_state > 0 ? + range_state + 1 : wfa->states); + state++) + if (state_image [state + level * wfa->states]) + for (label = 0; label < MAXLABELS; label++) + for (edge = 0; isedge (domain = wfa->into[state][label][edge]); + edge++) + if (domain > 0 + && (state_image [domain + (level - 1) * wfa->states] + != NULL) + && (state_image [domain + (level - 1) * wfa->states] + != &marker)) + { + Free (state_image [domain + (level - 1) * wfa->states]); + state_image [domain + (level - 1) * wfa->states] + = ▮ + } + } + Free (state_image); + Free (offset); +} + +static void +compute_state_images (unsigned max_level, word_t **simg, + const u_word_t *offset, const wfa_t *wfa) +/* + * Compute all state images of the 'wfa' at level {1, ... , 'max_level'} + * which are marked in the array 'simg' (offsets of state images + * are given by 'offset'). + * + * Warning: Several optimizations are used in this function making + * it difficult to understand. + * + * No return value. + * + * Side effects: + * state images (given by pointers in the array 'state_image') + * are computed. + */ +{ + unsigned level, state; + + /* + * Copy one-pixel images in case state_image pointer != &final distr. + */ + + for (state = 1; state < wfa->states; state++) + if (simg [state] != NULL) /* compute image at level 0 */ + *simg [state] = (int) (wfa->final_distribution[state] * 8 + .5) * 2; + + /* + * Compute images of states + * Integer arithmetics are used rather than floating point operations. + * 'weight' gives the weight in integer notation + * 'src', 'dst', and 'idst' are pointers to the source and + * destination pixels (short or integer format), respectively. + * Short format : one operation per register (16 bit mode). + * Integer format : two operations per register (32 bit mode). + * 'src_offset', 'dst_offset', and 'dst_offset' give the number of + * pixels which have to be omitted when jumping to the next image row. + */ + for (level = 1; level <= max_level; level++) + { + unsigned label; + unsigned width = width_of_level (level - 1); + unsigned height = height_of_level (level - 1); + + for (state = 1; state < wfa->states; state++) + if (simg [state + level * wfa->states] != NULL) + for (label = 0; label < MAXLABELS; label++) + if (isedge (wfa->into [state][label][0])) + { + unsigned edge; + int domain; + word_t *range; /* address of current range */ + bool_t prediction_used; /* ND prediction found ? */ + + /* + * Compute address of range image + */ + if (level & 1) /* split vertically */ + { + range = simg [state + level * wfa->states] + + label * (height_of_level (level - 1) + * offset [state + + level * wfa->states]); + } + else /* split horizontally */ + { + range = simg [state + level * wfa->states] + + label * width_of_level (level - 1); + } + + /* + * Generate the state images by adding the corresponding + * weighted state images: + * subimage [label] = + * weight_1 * image_1 + ... + weight_n * image_n + */ + if (!ischild (domain = wfa->tree[state][label])) + prediction_used = NO; + else + { + unsigned y; + word_t *src; + word_t *dst; + unsigned src_offset; + unsigned dst_offset; + + prediction_used = YES; + /* + * Copy child image + */ + src = simg [domain + (level - 1) * wfa->states]; + src_offset = offset [domain + (level - 1) * wfa->states] ; + dst = range; + dst_offset = offset [state + level * wfa->states]; + for (y = height; y; y--) + { + memcpy (dst, src, width * sizeof (word_t)); + src += src_offset; + dst += dst_offset; + } + } + + if (!prediction_used + && isedge (domain = wfa->into[state][label][0])) + { + /* + * If prediction is not used then the range is + * filled with the first domain. No addition is needed. + */ + edge = 0; + if (domain != 0) + { + int weight; + word_t *src; + unsigned src_offset; + + src = simg [domain + ((level - 1) + * wfa->states)]; + src_offset = offset [domain + ((level - 1) + * wfa->states)] - width; + weight = wfa->int_weight [state][label][edge]; + + if (width == 1) /* can't add two-pixels in a row */ + { + word_t *dst; + unsigned dst_offset; + + dst = range; + dst_offset = offset [state + level * wfa->states] + - width; +#ifdef HAVE_SIGNED_SHIFT + *dst++ = ((weight * (int) *src++) >> 10) << 1; +#else /* not HAVE_SIGNED_SHIFT */ + *dst++ = ((weight * (int) *src++) / 1024) * 2; +#endif /* not HAVE_SIGNED_SHIFT */ + if (height == 2) + { + src += src_offset; + dst += dst_offset; +#ifdef HAVE_SIGNED_SHIFT + *dst++ = ((weight * (int) *src++) >> 10) << 1; +#else /* not HAVE_SIGNED_SHIFT */ + *dst++ = ((weight * (int) *src++) / 1024) * 2; +#endif /* not HAVE_SIGNED_SHIFT */ + } + } + else + { + unsigned y; + int *idst; + unsigned idst_offset; + + idst = (int *) range; + idst_offset = (offset [state + level * wfa->states] + - width) / 2; + for (y = height; y; y--) + { + int *comp_dst = idst + (width >> 1); + + for (; idst != comp_dst; ) + { + int tmp; /* temp. value of adjacent pixels */ +#ifdef HAVE_SIGNED_SHIFT +# ifndef WORDS_BIGENDIAN + tmp = (((weight * (int) src [1]) >> 10) << 17) + | (((weight * (int) src [0]) >> 9) + & 0xfffe); +# else /* not WORDS_BIGENDIAN */ + tmp = (((weight * (int) src [0]) >> 10) << 17) + | (((weight * (int) src [1]) >> 9) + & 0xfffe); +# endif /* not WORDS_BIGENDIAN */ +#else /* not HAVE_SIGNED_SHIFT */ +# ifndef WORDS_BIGENDIAN + tmp = (((weight * (int) src [1]) / 1024) + * 131072) + | (((weight * (int) src [0])/ 512) + & 0xfffe); +# else /* not WORDS_BIGENDIAN */ + tmp = (((weight * (int) src [0]) / 1024) + * 131072) + | (((weight * (int) src [1]) / 512) + & 0xfffe); +# endif /* not WORDS_BIGENDIAN */ +#endif /* not HAVE_SIGNED_SHIFT */ + src += 2; + *idst++ = tmp & 0xfffefffe; + } + src += src_offset; + idst += idst_offset; + } + } + } + else + { + int weight = (int) (wfa->weight[state][label][edge] + * wfa->final_distribution[0] + * 8 + .5) * 2; + /* + * Range needs domain 0 + * (the constant function f(x, y) = 1), + * hence a faster algorithm is used. + */ + if (width == 1) /* can't add two-pixels in a row */ + { + word_t *dst; + unsigned dst_offset; + + dst = range; + dst_offset = offset [state + level * wfa->states] + - width; + + *dst++ = weight; + if (height == 2) + { + dst += dst_offset; + *dst++ = weight; + } + } + else + { + unsigned x, y; + int *idst; + unsigned idst_offset; + + weight = (weight * 65536) | (weight & 0xffff); + idst = (int *) range; + idst_offset = offset [state + level * wfa->states] + / 2; + for (x = width >> 1; x; x--) + *idst++ = weight & 0xfffefffe; + idst += (offset [state + level * wfa->states] + - width) / 2; + + for (y = height - 1; y; y--) + { + memcpy (idst, idst - idst_offset, + width * sizeof (word_t)); + idst += idst_offset; + } + } + } + edge = 1; + } + else + edge = 0; + + /* + * Add remaining weighted domain images to current range + */ + for (; isedge (domain = wfa->into[state][label][edge]); + edge++) + { + if (domain != 0) + { + word_t *src; + unsigned src_offset; + int weight; + + src = simg [domain + (level - 1) * wfa->states]; + src_offset = offset [domain + ((level - 1) + * wfa->states)] - width; + weight = wfa->int_weight [state][label][edge]; + + if (width == 1) /* can't add two-pixels in a row */ + { + word_t *dst; + unsigned dst_offset; + + dst = range; + dst_offset = offset [state + level * wfa->states] + - width; + +#ifdef HAVE_SIGNED_SHIFT + *dst++ += ((weight * (int) *src++) >> 10) << 1; +#else /* not HAVE_SIGNED_SHIFT */ + *dst++ += ((weight * (int) *src++) / 1024) * 2; +#endif /* not HAVE_SIGNED_SHIFT */ + if (height == 2) + { + src += src_offset; + dst += dst_offset; +#ifdef HAVE_SIGNED_SHIFT + *dst++ += ((weight * (int) *src++) >> 10) << 1; +#else /* not HAVE_SIGNED_SHIFT */ + *dst++ += ((weight * (int) *src++) / 1024) * 2; +#endif /* not HAVE_SIGNED_SHIFT */ + } + } + else + { + int *idst; + unsigned idst_offset; + unsigned y; + + idst = (int *) range; + idst_offset = (offset [state + level * wfa->states] + - width) / 2; + + for (y = height; y; y--) + { + int *comp_dst = idst + (width >> 1); + + for (; idst != comp_dst;) + { + int tmp; /* temp. value of adjacent pixels */ +#ifdef HAVE_SIGNED_SHIFT +# ifndef WORDS_BIGENDIAN + tmp = (((weight * (int) src [1]) >> 10) << 17) + | (((weight * (int) src [0]) >> 9) + & 0xfffe); +# else /* not WORDS_BIGENDIAN */ + tmp = (((weight * (int)src [0]) >> 10) << 17) + | (((weight * (int)src [1]) >> 9) + & 0xfffe); +# endif /* not WORDS_BIGENDIAN */ +#else /* not HAVE_SIGNED_SHIFT */ +# ifndef WORDS_BIGENDIAN + tmp = (((weight * (int) src [1]) / 1024) + * 131072) + | (((weight * (int) src [0])/ 512) + & 0xfffe); +# else /* not WORDS_BIGENDIAN */ + tmp = (((weight * (int) src [0]) / 1024) + * 131072) + | (((weight * (int) src [1])/ 512) + & 0xfffe); +# endif /* not WORDS_BIGENDIAN */ +#endif /* not HAVE_SIGNED_SHIFT */ + src += 2; + *idst = (*idst + tmp) & 0xfffefffe; + idst++; + } + src += src_offset; + idst += idst_offset; + } + } + } + else + { + int weight = (int) (wfa->weight[state][label][edge] + * wfa->final_distribution[0] + * 8 + .5) * 2; + /* + * Range needs domain 0 + * (the constant function f(x, y) = 1), + * hence a faster algorithm is used. + */ + if (width == 1) /* can't add two-pixels in a row */ + { + word_t *dst; + unsigned dst_offset; + + dst = range; + dst_offset = offset [state + level * wfa->states] + - width; + + *dst++ += weight; + if (height == 2) + { + dst += dst_offset; + *dst++ += weight; + } + } + else + { + int *idst; + unsigned idst_offset; + unsigned y; + + weight = (weight * 65536) | (weight & 0xffff); + idst = (int *) range; + idst_offset = (offset [state + level * wfa->states] + - width) /2; + + for (y = height; y; y--) + { + int *comp_dst = idst + (width >> 1); + + for (; idst != comp_dst; ) + { + *idst = (*idst + weight) & 0xfffefffe; + idst++; + } + idst += idst_offset; + } + } + } + } + } + } +} + +static word_t * +duplicate_state_image (const word_t *domain, unsigned offset, unsigned level) +/* + * Allocate new memory block 'pixels' and copy pixel values of 'domain' + * (size and pixel offset are given by 'level' and 'offset') + * to the lock 'pixels'. + * + * Return value: + * pointer to the new domain block + */ +{ + word_t *dst, *pixels; + int y, n; + + dst = pixels = Calloc (size_of_level (level), sizeof (word_t)); + + if (domain) + for (y = height_of_level (level); y; y--) + { + memcpy (dst, domain, width_of_level (level) * sizeof (word_t)); + dst += width_of_level (level); + domain += offset; + } + else /* state 0 */ + for (n = size_of_level (level); n; n--) + *dst++ = (int) (128 * 8 + .5) * 2; + + return pixels; +} diff --git a/converter/other/fiasco/codec/decoder.h b/converter/other/fiasco/codec/decoder.h new file mode 100644 index 00000000..8cd211e0 --- /dev/null +++ b/converter/other/fiasco/codec/decoder.h @@ -0,0 +1,70 @@ +/* + * decode.h + * + * Written by: Ullrich Hafner + * + * This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec) + * Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de> + */ + +/* + * $Date: 2000/10/22 10:44:48 $ + * $Author: hafner $ + * $Revision: 5.3 $ + * $State: Exp $ + */ + +#ifndef _DECODE_H +#define _DECODE_H + +#include "types.h" +#include "image.h" +#include "wfa.h" + +typedef struct video +{ + unsigned future_display; /* number of a future frame */ + unsigned display; /* current display number */ + image_t *frame; /* current frame */ + image_t *sframe; /* current smoothed frame */ + image_t *future; /* future reference */ + image_t *sfuture; /* future (smmothed) reference */ + image_t *past ; /* past reference */ + wfa_t *wfa; /* current wfa */ + wfa_t *wfa_future; /* future wfa */ + wfa_t *wfa_past; /* past wfa */ +} video_t; + +typedef struct dectimer +{ + unsigned int input [3]; + unsigned int preprocessing [3]; + unsigned int decoder [3]; + unsigned int cleanup [3]; + unsigned int motion [3]; + unsigned int smooth [3]; + unsigned int display [3]; + unsigned int frames [3]; +} dectimer_t; + +image_t * +get_next_frame (bool_t store_wfa, int enlarge_factor, + int smoothing, const char *reference_frame, + format_e format, video_t *video, dectimer_t *timer, + wfa_t *orig_wfa, bitfile_t *input); +image_t * +decode_image (unsigned orig_width, unsigned orig_height, format_e format, + unsigned *dec_timer, const wfa_t *wfa); +word_t * +decode_range (unsigned range_state, unsigned range_label, unsigned range_level, + word_t **domain, wfa_t *wfa); +image_t * +decode_state (unsigned state, unsigned level, wfa_t *wfa); +void +smooth_image (unsigned sf, const wfa_t *wfa, image_t *image); +video_t * +alloc_video (bool_t store_wfa); +void +free_video (video_t *video); + +#endif /* not _DECODE_H */ diff --git a/converter/other/fiasco/codec/dfiasco.c b/converter/other/fiasco/codec/dfiasco.c new file mode 100644 index 00000000..1cdfc672 --- /dev/null +++ b/converter/other/fiasco/codec/dfiasco.c @@ -0,0 +1,398 @@ +/* + * dfiasco.c: Decoder public interface + * + * Written by: Ullrich Hafner + * + * This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec) + * Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de> + */ + +/* + * $Date: 2000/10/28 17:39:30 $ + * $Author: hafner $ + * $Revision: 5.7 $ + * $State: Exp $ + */ + +#include <string.h> + +#include "config.h" + +#include "types.h" +#include "macros.h" +#include "error.h" + +#include "dfiasco.h" +#include "wfa.h" +#include "read.h" +#include "misc.h" +#include "bit-io.h" +#include "decoder.h" +#include "options.h" +#include "wfalib.h" + +/***************************************************************************** + + prototypes + +*****************************************************************************/ + +static dfiasco_t * +cast_dfiasco (fiasco_decoder_t *dfiasco); +static void +free_dfiasco (dfiasco_t *dfiasco); +static dfiasco_t * +alloc_dfiasco (wfa_t *wfa, video_t *video, bitfile_t *input, + int enlarge_factor, int smoothing, format_e image_format); + +/***************************************************************************** + + public code + +*****************************************************************************/ + +fiasco_decoder_t * +fiasco_decoder_new (const char *filename, const fiasco_d_options_t *options) +{ + try + { + bitfile_t *input; /* pointer to WFA FIASCO stream */ + wfa_t *wfa; /* wfa structure */ + video_t *video; /* information about decoder state */ + const d_options_t *dop; /* decoder additional options */ + dfiasco_t *dfiasco; /* decoder internal state */ + fiasco_decoder_t *decoder; /* public interface to decoder */ + fiasco_d_options_t *default_options = NULL; + + if (options) + { + dop = cast_d_options ((fiasco_d_options_t *) options); + if (!dop) + return NULL; + } + else + { + default_options = fiasco_d_options_new (); + dop = cast_d_options (default_options); + } + + wfa = alloc_wfa (NO); + video = alloc_video (NO); + input = open_wfa (filename, wfa->wfainfo); + read_basis (wfa->wfainfo->basis_name, wfa); + + decoder = Calloc (1, sizeof (fiasco_decoder_t)); + decoder->delete = fiasco_decoder_delete; + decoder->write_frame = fiasco_decoder_write_frame; + decoder->get_frame = fiasco_decoder_get_frame; + decoder->get_length = fiasco_decoder_get_length; + decoder->get_rate = fiasco_decoder_get_rate; + decoder->get_width = fiasco_decoder_get_width; + decoder->get_height = fiasco_decoder_get_height; + decoder->get_title = fiasco_decoder_get_title; + decoder->get_comment = fiasco_decoder_get_comment; + decoder->is_color = fiasco_decoder_is_color; + + decoder->private = dfiasco + = alloc_dfiasco (wfa, video, input, + dop->magnification, + dop->smoothing, + dop->image_format); + + if (default_options) + fiasco_d_options_delete (default_options); + if (dfiasco->enlarge_factor >= 0) + { + int n; + unsigned long pixels = wfa->wfainfo->width * wfa->wfainfo->height; + + for (n = 1; n <= (int) dfiasco->enlarge_factor; n++) + { + if (pixels << (n << 1) > 2048 * 2048) + { + set_error (_("Magnifaction factor `%d' is too large. " + "Maximium value is %d."), + dfiasco->enlarge_factor, max (0, n - 1)); + fiasco_decoder_delete (decoder); + return NULL; + } + } + } + else + { + int n; + + for (n = 0; n <= (int) - dfiasco->enlarge_factor; n++) + { + if (wfa->wfainfo->width >> n < 32 + || wfa->wfainfo->height >> n < 32) + { + set_error (_("Magnifaction factor `%d' is too small. " + "Minimum value is %d."), + dfiasco->enlarge_factor, - max (0, n - 1)); + fiasco_decoder_delete (decoder); + return NULL; + } + } + } + return (fiasco_decoder_t *) decoder; + } + catch + { + return NULL; + } +} + +int +fiasco_decoder_write_frame (fiasco_decoder_t *decoder, + const char *filename) +{ + dfiasco_t *dfiasco = cast_dfiasco (decoder); + + if (!dfiasco) + return 0; + else + { + try + { + image_t *frame = get_next_frame (NO, dfiasco->enlarge_factor, + dfiasco->smoothing, NULL, + FORMAT_4_4_4, dfiasco->video, NULL, + dfiasco->wfa, dfiasco->input); + write_image (filename, frame); + } + catch + { + return 0; + } + return 1; + } +} + +fiasco_image_t * +fiasco_decoder_get_frame (fiasco_decoder_t *decoder) +{ + dfiasco_t *dfiasco = cast_dfiasco (decoder); + + if (!dfiasco) + return NULL; + else + { + try + { + fiasco_image_t *image = Calloc (1, sizeof (fiasco_image_t)); + image_t *frame = get_next_frame (NO, dfiasco->enlarge_factor, + dfiasco->smoothing, NULL, + dfiasco->image_format, + dfiasco->video, NULL, + dfiasco->wfa, dfiasco->input); + + frame->reference_count++; /* for motion compensation */ + image->private = frame; + image->delete = fiasco_image_delete; + image->get_width = fiasco_image_get_width; + image->get_height = fiasco_image_get_height; + image->is_color = fiasco_image_is_color; + + return image; + } + catch + { + return NULL; + } + } +} + +unsigned +fiasco_decoder_get_length (fiasco_decoder_t *decoder) +{ + dfiasco_t *dfiasco = cast_dfiasco (decoder); + + if (!dfiasco) + return 0; + else + return dfiasco->wfa->wfainfo->frames; +} + +unsigned +fiasco_decoder_get_rate (fiasco_decoder_t *decoder) +{ + dfiasco_t *dfiasco = cast_dfiasco (decoder); + + if (!dfiasco) + return 0; + else + return dfiasco->wfa->wfainfo->fps; +} + +unsigned +fiasco_decoder_get_width (fiasco_decoder_t *decoder) +{ + dfiasco_t *dfiasco = cast_dfiasco (decoder); + + if (!dfiasco) + return 0; + else + { + unsigned width; + + if (dfiasco->enlarge_factor >= 0) + width = dfiasco->wfa->wfainfo->width << dfiasco->enlarge_factor; + else + width = dfiasco->wfa->wfainfo->width >> - dfiasco->enlarge_factor; + + return width & 1 ? width + 1 : width; + } +} + +unsigned +fiasco_decoder_get_height (fiasco_decoder_t *decoder) +{ + dfiasco_t *dfiasco = cast_dfiasco (decoder); + + if (!dfiasco) + return 0; + else + { + unsigned height; + + if (dfiasco->enlarge_factor >= 0) + height = dfiasco->wfa->wfainfo->height << dfiasco->enlarge_factor; + else + height = dfiasco->wfa->wfainfo->height >> - dfiasco->enlarge_factor; + + return height & 1 ? height + 1 : height; + } +} + +const char * +fiasco_decoder_get_title (fiasco_decoder_t *decoder) +{ + dfiasco_t *dfiasco = cast_dfiasco (decoder); + + if (!dfiasco) + return NULL; + else + return dfiasco->wfa->wfainfo->title; +} + +const char * +fiasco_decoder_get_comment (fiasco_decoder_t *decoder) +{ + dfiasco_t *dfiasco = cast_dfiasco (decoder); + + if (!dfiasco) + return NULL; + else + return dfiasco->wfa->wfainfo->comment; +} + +int +fiasco_decoder_is_color (fiasco_decoder_t *decoder) +{ + dfiasco_t *dfiasco = cast_dfiasco (decoder); + + if (!dfiasco) + return 0; + else + return dfiasco->wfa->wfainfo->color; +} + +int +fiasco_decoder_delete (fiasco_decoder_t *decoder) +{ + dfiasco_t *dfiasco = cast_dfiasco (decoder); + + if (!dfiasco) + return 1; + + try + { + free_wfa (dfiasco->wfa); + free_video (dfiasco->video); + close_bitfile (dfiasco->input); + strcpy (dfiasco->id, " "); + free_dfiasco(dfiasco); + Free (decoder); + } + catch + { + return 0; + } + + return 1; +} + +/***************************************************************************** + + private code + +*****************************************************************************/ + +static dfiasco_t * +alloc_dfiasco (wfa_t *wfa, video_t *video, bitfile_t *input, + int enlarge_factor, int smoothing, format_e image_format) +/* + * FIASCO decoder constructor: + * Initialize decoder structure. + * + * Return value: + * pointer to the new decoder structure + */ +{ + dfiasco_t *dfiasco = Calloc (1, sizeof (dfiasco_t)); + + strcpy (dfiasco->id, "DFIASCO"); + + dfiasco->wfa = wfa; + dfiasco->video = video; + dfiasco->input = input; + dfiasco->enlarge_factor = enlarge_factor; + dfiasco->smoothing = smoothing; + dfiasco->image_format = image_format; + + return dfiasco; +} + +static void +free_dfiasco (dfiasco_t *dfiasco) +/* + * FIASCO decoder destructor: + * Free memory of given 'decoder' struct. + * + * No return value. + * + * Side effects: + * 'video' struct is discarded. + */ +{ + Free (dfiasco); +} + +static dfiasco_t * +cast_dfiasco (fiasco_decoder_t *dfiasco) +/* + * Cast pointer `dfiasco' to type dfiasco_t. + * Check whether `dfiasco' is a valid object of type dfiasco_t. + * + * Return value: + * pointer to dfiasco_t struct on success + * NULL otherwise + */ +{ + dfiasco_t *this = (dfiasco_t *) dfiasco->private; + if (this) + { + if (!streq (this->id, "DFIASCO")) + { + set_error (_("Parameter `dfiasco' doesn't match required type.")); + return NULL; + } + } + else + { + set_error (_("Parameter `%s' not defined (NULL)."), "dfiasco"); + } + + return this; +} diff --git a/converter/other/fiasco/codec/dfiasco.h b/converter/other/fiasco/codec/dfiasco.h new file mode 100644 index 00000000..bcc3c7f9 --- /dev/null +++ b/converter/other/fiasco/codec/dfiasco.h @@ -0,0 +1,38 @@ +/* + * dfiasco.h + * + * Written by: Ullrich Hafner + * + * This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec) + * Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de> + */ + +/* + * $Date: 2000/07/15 18:00:53 $ + * $Author: hafner $ + * $Revision: 5.2 $ + * $State: Exp $ + */ + +#ifndef _DFIASCO_H +#define _DFIASCO_H + +#include "types.h" +#include "bit-io.h" +#include "decoder.h" +#include "image.h" +#include "wfa.h" + +typedef struct dfiasco +{ + char id [8]; + wfa_t *wfa; + video_t *video; + bitfile_t *input; + int enlarge_factor; + int smoothing; + format_e image_format; +} dfiasco_t; + +#endif /* not _DFIASCO_H */ + diff --git a/converter/other/fiasco/codec/domain-pool.c b/converter/other/fiasco/codec/domain-pool.c new file mode 100644 index 00000000..09f854a6 --- /dev/null +++ b/converter/other/fiasco/codec/domain-pool.c @@ -0,0 +1,986 @@ +/* + * domain-pool.c: Domain pool management (probability model) + * + * Written by: Ullrich Hafner + * + * This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec) + * Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de> + */ + +/* + * $Date: 2000/06/14 20:50:51 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#include "config.h" + +#include <math.h> + +#if STDC_HEADERS +# include <stdlib.h> +#endif /* not STDC_HEADERS */ + +#if HAVE_STRING_H +# include <string.h> +#else /* not HAVE_STRING_H */ +# include <strings.h> +#endif /* not HAVE_STRING_H */ + +#include "types.h" +#include "macros.h" +#include "error.h" + +#include "misc.h" +#include "cwfa.h" +#include "wfalib.h" +#include "domain-pool.h" + +/* + * Domain pool model interface: + * Implementing the domain pool model interface requires the + * following steps: + * - Add a constructor that initializes the domain_pool_t structure + * - Allocate new model with default_alloc() + * - Fill the dp_array_t domain_pools array with constructor and name + * - Write code for methods bits() and generate() + * - Either use default functions for remaining methods or override them + * The new model is automatically registered at the command line. + */ + +/***************************************************************************** + + local variables + +*****************************************************************************/ + +static real_t *matrix_0 = NULL; +static real_t *matrix_1 = NULL; + +/***************************************************************************** + non-adaptive domain pool +*****************************************************************************/ + +static void +qac_chroma (unsigned max_domains, const wfa_t *wfa, void *model); +static bool_t +qac_append (unsigned new_state, unsigned level, const wfa_t *wfa, void *model); +static void +qac_update (const word_t *domains, const word_t *used_domains, + unsigned level, int y_state, const wfa_t *wfa, void *model); +static real_t +qac_bits (const word_t *domains, const word_t *used_domains, + unsigned level, int y_state, const wfa_t *wfa, const void *model); +static word_t * +qac_generate (unsigned level, int y_state, const wfa_t *wfa, + const void *model); +static void * +qac_model_duplicate (const void *src); +static void +qac_model_free (void *model); +static void * +qac_model_alloc (unsigned max_domains); +static domain_pool_t * +alloc_qac_domain_pool (unsigned max_domains, unsigned max_edges, + const wfa_t *wfa); + +/***************************************************************************** + run length encoding pool +*****************************************************************************/ + +static domain_pool_t * +alloc_rle_no_chroma_domain_pool (unsigned max_domains, unsigned max_edges, + const wfa_t *wfa); +static void +rle_chroma (unsigned max_domains, const wfa_t *wfa, void *model); +static bool_t +rle_append (unsigned new_state, unsigned level, const wfa_t *wfa, void *model); +static void +rle_update (const word_t *domains, const word_t *used_domains, + unsigned level, int y_state, const wfa_t *wfa, void *model); +static real_t +rle_bits (const word_t *domains, const word_t *used_domains, + unsigned level, int y_state, const wfa_t *wfa, const void *model); +static word_t * +rle_generate (unsigned level, int y_state, const wfa_t *wfa, + const void *model); +static void * +rle_model_duplicate (const void *src); +static void +rle_model_free (void *model); +static void * +rle_model_alloc (unsigned max_domains); +static domain_pool_t * +alloc_rle_domain_pool (unsigned max_domains, unsigned max_edges, + const wfa_t *wfa); + +/***************************************************************************** + const domain pool +*****************************************************************************/ + +static real_t +const_bits (const word_t *domains, const word_t *used_domains, + unsigned level, int y_state, const wfa_t *wfa, const void *model); +static word_t * +const_generate (unsigned level, int y_state, const wfa_t *wfa, + const void *model); +static domain_pool_t * +alloc_const_domain_pool (unsigned max_domains, unsigned max_edges, + const wfa_t *wfa); + +/***************************************************************************** + basis domain pool +*****************************************************************************/ + +static domain_pool_t * +alloc_basis_domain_pool (unsigned max_domains, unsigned max_edges, + const wfa_t *wfa); + +/***************************************************************************** + uniform distribution pool +*****************************************************************************/ + +static real_t +uniform_bits (const word_t *domains, const word_t *used_domains, + unsigned level, int y_state, const wfa_t *wfa, + const void *model); +static word_t * +uniform_generate (unsigned level, int y_state, const wfa_t *wfa, + const void *model); +static domain_pool_t * +alloc_uniform_domain_pool (unsigned max_domains, unsigned max_edges, + const wfa_t *wfa); + +/***************************************************************************** + default functions +*****************************************************************************/ + +static void +init_matrix_probabilities (void); +static void +default_chroma (unsigned max_domains, const wfa_t *wfa, void *model); +static bool_t +default_append (unsigned new_state, unsigned level, + const wfa_t *wfa, void *model); +static void +default_update (const word_t *domains, const word_t *used_domains, + unsigned level, int y_state, const wfa_t *wfa, void *model); +static void +default_free (domain_pool_t *pool); +static void +default_model_free (void *model); +static void * +default_model_alloc (unsigned max_domains); +static void * +default_model_duplicate (const void *src); +static domain_pool_t * +default_alloc (void); + +/***************************************************************************** + + public code + +*****************************************************************************/ + +typedef struct dp_array +{ + const char *identifier; + domain_pool_t *(*function) (unsigned max_domains, unsigned max_edges, + const wfa_t *wfa); +} dp_array_t; + +dp_array_t const domain_pools[] = {{"adaptive", alloc_qac_domain_pool}, + {"constant", alloc_const_domain_pool}, + {"basis", alloc_basis_domain_pool}, + {"uniform", alloc_uniform_domain_pool}, + {"rle", alloc_rle_domain_pool}, + {"rle-no-chroma", alloc_rle_no_chroma_domain_pool}, + {NULL, NULL}}; + +domain_pool_t * +alloc_domain_pool (const char *domain_pool_name, unsigned max_domains, + unsigned max_edges, const wfa_t *wfa) +/* + * Allocate a new domain pool identified by the string + * 'domain_pool_name'. Maximum number of domain images (each one + * represented by one state of the given 'wfa') is specified by + * 'max_domains'. + * + * Return value: + * pointer to the allocated domain pool + * + * Note: + * refer to 'domain-pool.h' for a short description of the member functions. + */ +{ + unsigned n; + + if (!max_domains) + { + warning ("Can't generate empty domain pool. " + "Using at least DC component."); + max_domains = 1; + } + + for (n = 0; domain_pools [n].identifier; n++) /* step through all id's */ + if (strcaseeq (domain_pools [n].identifier, domain_pool_name)) + return domain_pools [n].function (max_domains, max_edges, wfa); + + warning ("Can't initialize domain pool '%s'. Using default value '%s'.", + domain_pool_name, domain_pools [0].identifier); + + return domain_pools [0].function (max_domains, max_edges, wfa); +} + +/***************************************************************************** + + private code + +*****************************************************************************/ + +/***************************************************************************** + adaptive domain pool +*****************************************************************************/ + +typedef struct qac_model +{ + word_t *index; /* probability of domains */ + word_t *states; /* mapping states -> domains */ + u_word_t y_index; /* pointer to prob of Y domain */ + u_word_t n; /* number of domains in the pool */ + u_word_t max_domains; /* max. number of domains */ +} qac_model_t; + +static domain_pool_t * +alloc_qac_domain_pool (unsigned max_domains, unsigned max_edges, + const wfa_t *wfa) +/* + * Domain pool with state images {0, ..., 'max_domains'). + * Underlying probability model: quasi arithmetic coding of columns. + */ +{ + domain_pool_t *pool; + unsigned state; + + pool = default_alloc (); + pool->model = qac_model_alloc (max_domains); + pool->generate = qac_generate; + pool->bits = qac_bits; + pool->update = qac_update; + pool->append = qac_append; + pool->chroma = qac_chroma; + pool->model_free = qac_model_free; + pool->model_duplicate = qac_model_duplicate; + + for (state = 0; state < wfa->basis_states; state++) + if (usedomain (state, wfa)) + qac_append (state, -1, wfa, pool->model); + + return pool; +} + +static void * +qac_model_alloc (unsigned max_domains) +{ + qac_model_t *model; + + init_matrix_probabilities (); + + model = Calloc (1, sizeof (qac_model_t)); + model->index = Calloc (max_domains, sizeof (word_t)); + model->states = Calloc (max_domains, sizeof (word_t)); + model->y_index = 0; + model->n = 0; + model->max_domains = max_domains; + + return model; +} + +static void +qac_model_free (void *model) +{ + Free (((qac_model_t *) model)->index); + Free (((qac_model_t *) model)->states); + Free (model); +} + +static void * +qac_model_duplicate (const void *src) +{ + qac_model_t *qdst; + const qac_model_t *qsrc = (qac_model_t *) src; + + qdst = qac_model_alloc (qsrc->max_domains); + qdst->y_index = qsrc->y_index; + qdst->n = qsrc->n; + + memcpy (qdst->index, qsrc->index, qsrc->n * sizeof (word_t)); + memcpy (qdst->states, qsrc->states, qsrc->n * sizeof (word_t)); + + return qdst; +} + +static word_t * +qac_generate (unsigned level, int y_state, const wfa_t *wfa, const void *model) +{ + word_t *domains; + unsigned n; + qac_model_t *qac_model = (qac_model_t *) model; + bool_t y_state_is_domain = NO; + + if (y_state >= 0 && !usedomain (y_state, wfa)) /* don't use y-state */ + y_state = -1; + + domains = Calloc (qac_model->n + 2, sizeof (word_t)); + + memcpy (domains, qac_model->states, qac_model->n * sizeof (word_t)); + + for (n = 0; n < qac_model->n; n++) + if (domains [n] == y_state) /* match */ + y_state_is_domain = YES; + + if (y_state_is_domain) + domains [qac_model->n] = -1; /* end marker */ + else + { + domains [qac_model->n] = y_state; /* additional y-state */ + domains [qac_model->n + 1] = -1; /* end marker */ + } + + return domains; +} + +static real_t +qac_bits (const word_t *domains, const word_t *used_domains, + unsigned level, int y_state, const wfa_t *wfa, const void *model) +{ + int domain; /* counter */ + real_t bits = 0; /* bit rate R */ + qac_model_t *qac_model = (qac_model_t *) model; /* probability model */ + + if (y_state >= 0 && !usedomain (y_state, wfa)) /* don't use y-state */ + y_state = -1; + + for (domain = 0; domain < qac_model->n; domain++) + if (qac_model->states [domain] != y_state) + bits += matrix_0 [qac_model->index [domain]]; + if (y_state >= 0) + bits += matrix_0 [qac_model->y_index]; + + if (used_domains != NULL) + { + unsigned edge; + + for (edge = 0; isedge (domain = used_domains [edge]); edge++) + if (domains [domain] == y_state) + { + bits -= matrix_0 [qac_model->y_index]; + bits += matrix_1 [qac_model->y_index]; + } + else + { + bits -= matrix_0 [qac_model->index [domain]]; + bits += matrix_1 [qac_model->index [domain]]; + } + } + + return bits; +} + +static void +qac_update (const word_t *domains, const word_t *used_domains, + unsigned level, int y_state, const wfa_t *wfa, void *model) +{ + int domain; + unsigned edge; + bool_t used_y_state = NO; + qac_model_t *qac_model = (qac_model_t *) model; + bool_t y_state_is_domain = NO; + + if (y_state >= 0 && !usedomain (y_state, wfa)) /* don't use y-state */ + y_state = -1; + + for (domain = 0; domain < qac_model->n; domain++) + { + qac_model->index [domain]++; /* mark domains unused. */ + if (qac_model->states [domain] == y_state) /* match */ + y_state_is_domain = YES; + } + + for (edge = 0; isedge (domain = used_domains [edge]); edge++) + if (domains [domain] == y_state) /* chroma coding */ + { + if (y_state_is_domain) + qac_model->index [domain]--; /* undo */ + qac_model->y_index >>= 1; + used_y_state = YES; + } + else /* luminance coding */ + { + qac_model->index [used_domains [edge]]--; /* undo */ + qac_model->index [used_domains [edge]] >>= 1; + } + + if (y_state >= 0 && !used_y_state) + qac_model->y_index++; /* update y-state model */ + + for (domain = 0; domain < qac_model->n; domain++) + if (qac_model->index [domain] > 1020) /* check for overflow */ + qac_model->index [domain] = 1020; + if (qac_model->y_index > 1020) /* check for overflow */ + qac_model->y_index = 1020; +} + +static bool_t +qac_append (unsigned new_state, unsigned level, const wfa_t *wfa, void *model) +{ + qac_model_t *qac_model = (qac_model_t *) model; /* probability model */ + + if (qac_model->n >= qac_model->max_domains) + return NO; /* don't use state in domain pool */ + else + { + qac_model->index [qac_model->n] + = qac_model->n > 0 ? qac_model->index [qac_model->n - 1] : 0; + qac_model->states [qac_model->n] = new_state; + qac_model->n++; + + return YES; /* state will be used in domain pool */ + } +} + +static void +qac_chroma (unsigned max_domains, const wfa_t *wfa, void *model) +{ + qac_model_t *qac_model = (qac_model_t *) model; /* probability model */ + + if (max_domains < qac_model->n) /* choose most probable domains */ + { + word_t *domains; + unsigned n, new, old; + word_t *states = Calloc (max_domains, sizeof (word_t)); + word_t *index = Calloc (max_domains, sizeof (word_t)); + + domains = compute_hits (wfa->basis_states, wfa->states - 1, + max_domains, wfa); + for (n = 0; n < max_domains && domains [n] >= 0; n++) + states [n] = domains [n]; + max_domains = min (max_domains, n); + Free (domains); + + for (old = 0, new = 0; new < max_domains && old < qac_model->n; old++) + if (qac_model->states [old] == states [new]) + index [new++] = qac_model->index [old]; + + Free (qac_model->states); + Free (qac_model->index); + qac_model->states = states; + qac_model->index = index; + qac_model->n = max_domains; + qac_model->max_domains = max_domains; + } + qac_model->y_index = 0; + qac_model->max_domains = qac_model->n; +} + +/***************************************************************************** + const domain pool +*****************************************************************************/ + +static domain_pool_t * +alloc_const_domain_pool (unsigned max_domains, unsigned max_edges, + const wfa_t *wfa) +/* + * Domain pool with state image 0 (constant function f(x, y) = 1). + * No probability model is used. + */ +{ + domain_pool_t *pool; + + pool = default_alloc (); + pool->generate = const_generate; + pool->bits = const_bits; + + return pool; +} + +static word_t * +const_generate (unsigned level, int y_state, const wfa_t *wfa, + const void *model) +{ + word_t *domains = Calloc (2, sizeof (word_t)); + + domains [0] = 0; + domains [1] = -1; + + return domains; +} + +static real_t +const_bits (const word_t *domains, const word_t *used_domains, + unsigned level, int y_state, const wfa_t *wfa, const void *model) +{ + return 0; /* 0 bits, + either we have a lc or not */ +} + +/***************************************************************************** + basis domain pool +*****************************************************************************/ + +static domain_pool_t * +alloc_basis_domain_pool (unsigned max_domains, unsigned max_edges, + const wfa_t *wfa) +/* + * Domain pool with state images {0, ..., 'basis_states' - 1). + * Underlying probability model: quasi arithmetic coding of columns. + * I.e. domain pool = qac_domainpool ('max_domains' == wfa->basis_states) + */ +{ + return alloc_qac_domain_pool (wfa->basis_states, max_edges, wfa); +} + +/***************************************************************************** + uniform-distribution pool +*****************************************************************************/ + +static domain_pool_t * +alloc_uniform_domain_pool (unsigned max_domains, unsigned max_edges, + const wfa_t *wfa) +/* + * Domain pool with state images {0, ..., 'max_domains'). + * Underlying probability model: uniform distribution. + */ +{ + domain_pool_t *pool; + + pool = default_alloc (); + pool->generate = uniform_generate; + pool->bits = uniform_bits; + + return pool; +} + +static word_t * +uniform_generate (unsigned level, int y_state, const wfa_t *wfa, + const void *model) +{ + unsigned state, n; + word_t *domains = Calloc (wfa->states + 1, sizeof (word_t)); + + for (state = 0, n = 0; state < wfa->states; state++) + if (usedomain (state, wfa)) + domains [n++] = state; + domains [n] = -1; + + return domains; +} + +static real_t +uniform_bits (const word_t *domains, const word_t *used_domains, + unsigned level, int y_state, const wfa_t *wfa, const void *model) +{ + unsigned state, n; + real_t bits = 0; + + for (state = 0, n = 0; state < wfa->states; state++) + if (usedomain (state, wfa)) + n++; + + bits = - n * log2 ((n - 1) / (real_t) n); + + if (used_domains != NULL) + { + int edge; + + for (edge = 0; isedge (used_domains [edge]); edge++) + bits -= log2 (1.0 / n); + } + + return bits; +} + +/***************************************************************************** + run length encoding pool +*****************************************************************************/ + +typedef struct rle_model +{ + word_t count [MAXEDGES + 1]; + u_word_t total; + u_word_t n; + u_word_t max_domains; + u_word_t y_index; /* pointer to prob of Y domain */ + word_t *states; /* mapping states -> domains */ + qac_model_t *domain_0; +} rle_model_t; + +static domain_pool_t * +alloc_rle_domain_pool (unsigned max_domains, unsigned max_edges, + const wfa_t *wfa) +/* + * Domain pool with state images {0, ..., 'max_domains'). + * Underlying probability model: rle + */ +{ + domain_pool_t *pool; + unsigned state; + + pool = default_alloc (); + pool->model = rle_model_alloc (max_domains); + pool->model_free = rle_model_free; + pool->model_duplicate = rle_model_duplicate; + pool->generate = rle_generate; + pool->update = rle_update; + pool->bits = rle_bits; + pool->append = rle_append; + pool->chroma = rle_chroma; + + for (state = 0; state < wfa->basis_states; state++) + if (usedomain (state, wfa)) + rle_append (state, -1, wfa, pool->model); + + return pool; +} + +static void * +rle_model_alloc (unsigned max_domains) +{ + unsigned m; + rle_model_t *model = Calloc (1, sizeof (rle_model_t)); + + for (m = model->total = 0; m < MAXEDGES + 1; m++, model->total++) + model->count [m] = 1; + + model->domain_0 = qac_model_alloc (1); + model->states = Calloc (max_domains, sizeof (word_t)); + model->n = 0; + model->y_index = 0; + model->max_domains = max_domains; + + return model; +} + +static void +rle_model_free (void *model) +{ + qac_model_free (((rle_model_t *) model)->domain_0); + Free (((rle_model_t *) model)->states); + Free (model); +} + +static void * +rle_model_duplicate (const void *src) +{ + const rle_model_t *rle_src = (rle_model_t *) src; + rle_model_t *model = Calloc (1, sizeof (rle_model_t)); + + model->domain_0 = qac_model_duplicate (rle_src->domain_0); + model->n = rle_src->n; + model->max_domains = rle_src->max_domains; + model->states = Calloc (model->max_domains, sizeof (word_t)); + model->total = rle_src->total; + model->y_index = rle_src->y_index; + + memcpy (model->states, rle_src->states, + model->max_domains * sizeof (word_t)); + memcpy (model->count, rle_src->count, + (MAXEDGES + 1) * sizeof (word_t)); + + return model; +} + +static word_t * +rle_generate (unsigned level, int y_state, const wfa_t *wfa, const void *model) +{ + word_t *domains; + unsigned n; + rle_model_t *rle_model = (rle_model_t *) model; + bool_t y_state_is_domain = NO; + + if (y_state >= 0 && !usedomain (y_state, wfa)) /* don't use y-state */ + y_state = -1; + + domains = Calloc (rle_model->n + 2, sizeof (word_t)); + + memcpy (domains, rle_model->states, rle_model->n * sizeof (word_t)); + + for (n = 0; n < rle_model->n; n++) + if (domains [n] == y_state) /* match */ + y_state_is_domain = YES; + + if (y_state_is_domain) + domains [rle_model->n] = -1; /* end marker */ + else + { + domains [rle_model->n] = y_state; /* additional y-state */ + domains [rle_model->n + 1] = -1; /* end marker */ + } + + return domains; +} + +static real_t +rle_bits (const word_t *domains, const word_t *used_domains, + unsigned level, int y_state, const wfa_t *wfa, const void *model) +{ + unsigned edge; + unsigned n = 0; + real_t bits = 0; + word_t sorted [MAXEDGES + 1]; + rle_model_t *rle_model = (rle_model_t *) model; + unsigned last; + int into; + + if (y_state >= 0 && !usedomain (y_state, wfa)) /* don't use y-state */ + y_state = -1; + + if (used_domains) + { + word_t domain; + + if (y_state >= 0) + bits += matrix_0 [rle_model->y_index]; + + for (edge = n = 0; isedge (domain = used_domains [edge]); edge++) + if (domains [domain] != y_state) + sorted [n++] = used_domains [edge]; + else + { + bits -= matrix_0 [rle_model->y_index]; + bits += matrix_1 [rle_model->y_index]; + } + + if (n > 1) + qsort (sorted, n, sizeof (word_t), sort_asc_word); + } + + bits = - log2 (rle_model->count [n] / (real_t) rle_model->total); + if (used_domains && n && sorted [0] == 0) + { + word_t array0 [2] = {0, NO_EDGE}; + bits += qac_bits (array0, array0, level, y_state, wfa, rle_model->domain_0); + } + else + { + word_t array0 [2] = {NO_EDGE}; + bits += qac_bits (array0, array0, level, y_state, wfa, rle_model->domain_0); + } + + last = 1; + for (edge = 0; edge < n; edge++) + if ((into = sorted [edge]) && rle_model->n - 1 - last) + { + bits += bits_bin_code (into - last, rle_model->n - 1 - last); + last = into + 1; + } + + return bits; +} + +static void +rle_update (const word_t *domains, const word_t *used_domains, + unsigned level, int y_state, const wfa_t *wfa, void *model) +{ + rle_model_t *rle_model = (rle_model_t *) model; + bool_t state_0 = NO, state_y = NO; + word_t array0 [2] = {0, NO_EDGE}; + unsigned edge = 0; + + if (y_state >= 0 && !usedomain (y_state, wfa)) /* don't use y-state */ + y_state = -1; + + if (used_domains) + { + word_t domain; + + for (edge = 0; isedge (domain = used_domains [edge]); edge++) + if (domains [domain] == 0) + state_0 = YES; + else if (domains [domain] == y_state) + state_y = YES; + } + + rle_model->count [edge]++; + rle_model->total++; + + qac_update (array0, array0 + (state_0 ? 0 : 1), level, y_state, wfa, + rle_model->domain_0); + + if (state_y) + rle_model->y_index >>= 1; + else + rle_model->y_index++; + if (rle_model->y_index > 1020) /* check for overflow */ + rle_model->y_index = 1020; +} + +static bool_t +rle_append (unsigned new_state, unsigned level, const wfa_t *wfa, void *model) +{ + rle_model_t *rle_model = (rle_model_t *) model; /* probability model */ + + if (rle_model->n >= rle_model->max_domains) + return NO; /* don't use state in domain pool */ + else + { + rle_model->states [rle_model->n] = new_state; + rle_model->n++; + + if (new_state == 0) + { + assert (rle_model->n == 1); + qac_append (0, -1, wfa, rle_model->domain_0); + } + + return YES; /* state will be used in domain pool */ + } +} + +static void +rle_chroma (unsigned max_domains, const wfa_t *wfa, void *model) +{ + rle_model_t *rle_model = (rle_model_t *) model; /* probability model */ + + if (max_domains < rle_model->n) /* choose most probable domains */ + { + unsigned n; + word_t *states = Calloc (max_domains, sizeof (word_t)); + word_t *domains = compute_hits (wfa->basis_states, wfa->states - 1, + max_domains, wfa); + + for (n = 0; n < max_domains && domains [n] >= 0; n++) + states [n] = domains [n]; + + assert (states [0] == 0); + max_domains = min (max_domains, n); + Free (domains); + + Free (rle_model->states); + rle_model->states = states; + rle_model->n = max_domains; + } + rle_model->y_index = 0; + rle_model->max_domains = rle_model->n; +} + +/***************************************************************************** + run length encoding pool no special chroma pool +*****************************************************************************/ + +static domain_pool_t * +alloc_rle_no_chroma_domain_pool (unsigned max_domains, unsigned max_edges, + const wfa_t *wfa) +/* + * Domain pool with state images {0, ..., 'max_domains'). + * Underlying probability model: rle + * Domain pool is not changed for chroma bands + */ +{ + domain_pool_t *pool = alloc_rle_domain_pool (max_domains, max_edges, wfa); + + pool->chroma = default_chroma; + + return pool; +} + +/***************************************************************************** + default functions (see domain-pool.h) +*****************************************************************************/ + +static domain_pool_t * +default_alloc (void) +{ + domain_pool_t *pool; + + pool = Calloc (1, sizeof (domain_pool_t)); + pool->model = default_model_alloc(0); + pool->generate = NULL; + pool->bits = NULL; + pool->update = default_update; + pool->append = default_append; + pool->chroma = default_chroma; + pool->free = default_free; + pool->model_free = default_model_free; + pool->model_duplicate = default_model_duplicate; + + return pool; +} + +static void * +default_model_duplicate (const void *src) +{ + return NULL; +} + +static void * +default_model_alloc (unsigned max_domains) +{ + return NULL; +} + +static void +default_model_free (void *model) +{ + if (model) + Free (model); +} + +static void +default_free (domain_pool_t *pool) +{ + pool->model_free (pool->model); + Free (pool); +} + +static void +default_update (const word_t *domains, const word_t *used_domains, + unsigned level, int y_state, const wfa_t *wfa, void *model) +{ + return; /* nothing to do */ +} + +static bool_t +default_append (unsigned new_state, unsigned level, + const wfa_t *wfa, void *model) +{ + return YES; /* use every state in lin comb */ +} + +static void +default_chroma (unsigned max_domains, const wfa_t *wfa, void *model) +{ + return; /* don't alter domain pool */ +} + +static void +init_matrix_probabilities (void) +/* + * Compute the information contents of matrix element '0' and '1' for + * each possible probability index 0, ... , 1023. These values are + * obtained from the probability model in the quasi arithmetic + * coding module. + * + * No return value. + * + * Side effects: + * local arrays matrix_0 and matrix_1 are initialized if not already done. + */ +{ + if (matrix_0 == NULL || matrix_1 == NULL) + { + unsigned index; + unsigned n, exp; + + matrix_0 = Calloc (1 << (MAX_PROB + 1), sizeof (real_t)); + matrix_1 = Calloc (1 << (MAX_PROB + 1), sizeof (real_t)); + + for (index = 0, n = MIN_PROB; n <= MAX_PROB; n++) + for (exp = 0; exp < (unsigned) 1 << n; exp++, index++) + { + matrix_1 [index] = -log2 (1 / (real_t) (1 << n)); + matrix_0 [index] = -log2 (1 - 1 / (real_t) (1 << n)); + } + } +} diff --git a/converter/other/fiasco/codec/domain-pool.h b/converter/other/fiasco/codec/domain-pool.h new file mode 100644 index 00000000..d1488779 --- /dev/null +++ b/converter/other/fiasco/codec/domain-pool.h @@ -0,0 +1,75 @@ +/* + * domain-pool.h + * + * Written by: Ullrich Hafner + * + * This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec) + * Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de> + */ + +/* + * $Date: 2000/06/14 20:50:51 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#ifndef _DOMAIN_POOL_H +#define _DOMAIN_POOL_H + +#include "cwfa.h" +#include "types.h" + +typedef struct domain_pool +{ + void *model; /* probability model */ + word_t *(*generate) (unsigned level, int y_state, const wfa_t *wfa, + const void *model); + /* + * Generate set of domain images which may be used for an approximation. + * Use parameters 'level', 'y_state' and 'wfa' to make the decision. + */ + real_t (*bits) (const word_t *domains, const word_t *used_domains, + unsigned level, int y_state, const wfa_t *wfa, + const void *model); + /* + * Compute bit-rate of a range approximation with domains given by + * the -1 terminated list 'used_domains'. + */ + void (*update) (const word_t *domains, const word_t *used_domains, + unsigned level, int y_state, const wfa_t *wfa, + void *model); + /* + * Update the probability model according to the chosen approximation. + * (given by the -1 terminated list 'used_domains'). + */ + bool_t (*append) (unsigned state, unsigned level, const wfa_t *wfa, + void *model); + /* + * Try to append a new state to the domain pool. + */ + void (*chroma) (unsigned max_domains, const wfa_t *wfa, void *model); + /* + * Derive a new domain pool that will be used for chroma channel + * coding + */ + void (*free) (struct domain_pool *pool); + /* + * Discard the given domain pool struct. + */ + void (*model_free) (void *model); + /* + * Free given probability model. + */ + void *(*model_duplicate) (const void *src); + /* + * Duplicate the given probability model (i.e. alloc and copy). + */ +} domain_pool_t; + +domain_pool_t * +alloc_domain_pool (const char *domain_pool_name, unsigned max_domains, + unsigned max_edges, const wfa_t *wfa); + +#endif /* not _DOMAIN_POOL_H */ + diff --git a/converter/other/fiasco/codec/ip.c b/converter/other/fiasco/codec/ip.c new file mode 100644 index 00000000..caa97baf --- /dev/null +++ b/converter/other/fiasco/codec/ip.c @@ -0,0 +1,324 @@ +/* + * ip.c: Computation of inner products + * + * Written by: Ullrich Hafner + * + * This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec) + * Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de> + */ + +/* + * $Date: 2000/06/14 20:50:51 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#include "config.h" + +#include "types.h" +#include "macros.h" +#include "error.h" + +#include "cwfa.h" +#include "control.h" +#include "ip.h" + +/***************************************************************************** + + prototypes + +*****************************************************************************/ + +static real_t +standard_ip_image_state (unsigned address, unsigned level, unsigned domain, + const coding_t *c); +static real_t +standard_ip_state_state (unsigned domain1, unsigned domain2, unsigned level, + const coding_t *c); + +/***************************************************************************** + + public code + +*****************************************************************************/ + +real_t +get_ip_image_state (unsigned image, unsigned address, unsigned level, + unsigned domain, const coding_t *c) +/* + * Return value: + * Inner product between 'image' ('address') and + * 'domain' at given 'level' + */ +{ + if (level <= c->options.images_level) + { + /* + * Compute the inner product in the standard way by multiplying + * the pixel-values of the given domain and range image. + */ + return standard_ip_image_state (address, level, domain, c); + } + else + { + /* + * Use the already computed inner products stored in 'ip_images_states' + */ + return c->ip_images_state [domain][image]; + } +} + +void +compute_ip_images_state (unsigned image, unsigned address, unsigned level, + unsigned n, unsigned from, + const wfa_t *wfa, coding_t *c) +/* + * Compute the inner products between all states + * 'from', ... , 'wfa->max_states' and the range images 'image' + * (and childs) up to given level. + * + * No return value. + * + * Side effects: + * inner product tables 'c->ip_images_states' are updated + */ +{ + if (level > c->options.images_level) + { + unsigned state, label; + + if (level > c->options.images_level + 1) /* recursive computation */ + compute_ip_images_state (MAXLABELS * image + 1, address * MAXLABELS, + level - 1, MAXLABELS * n, from, wfa, c); + + /* + * Compute inner product <f, Phi_i> + */ + for (label = 0; label < MAXLABELS; label++) + for (state = from; state < wfa->states; state++) + if (need_image (state, wfa)) + { + unsigned edge, count; + int domain; + real_t *dst, *src; + + if (ischild (domain = wfa->tree [state][label])) + { + if (level > c->options.images_level + 1) + { + dst = c->ip_images_state [state] + image; + src = c->ip_images_state [domain] + + image * MAXLABELS + label + 1; + for (count = n; count; count--, src += MAXLABELS) + *dst++ += *src; + } + else + { + unsigned newadr = address * MAXLABELS + label; + + dst = c->ip_images_state [state] + image; + + for (count = n; count; count--, newadr += MAXLABELS) + *dst++ += standard_ip_image_state (newadr, level - 1, + domain, c); + } + } + for (edge = 0; isedge (domain = wfa->into [state][label][edge]); + edge++) + { + real_t weight = wfa->weight [state][label][edge]; + + if (level > c->options.images_level + 1) + { + dst = c->ip_images_state [state] + image; + src = c->ip_images_state [domain] + + image * MAXLABELS + label + 1; + for (count = n; count; count--, src += MAXLABELS) + *dst++ += *src * weight; + } + else + { + unsigned newadr = address * MAXLABELS + label; + + dst = c->ip_images_state [state] + image; + + for (count = n; count; count--, newadr += MAXLABELS) + *dst++ += weight * + standard_ip_image_state (newadr, level - 1, + domain, c); + } + } + } + } +} + +real_t +get_ip_state_state (unsigned domain1, unsigned domain2, unsigned level, + const coding_t *c) +/* + * Return value: + * Inner product between 'domain1' and 'domain2' at given 'level'. + */ +{ + if (level <= c->options.images_level) + { + /* + * Compute the inner product in the standard way by multiplying + * the pixel-values of both state-images + */ + return standard_ip_state_state (domain1, domain2, level, c); + } + else + { + /* + * Use already computed inner products stored in 'ip_images_states' + */ + if (domain2 < domain1) + return c->ip_states_state [domain1][level][domain2]; + else + return c->ip_states_state [domain2][level][domain1]; + } +} + +void +compute_ip_states_state (unsigned from, unsigned to, + const wfa_t *wfa, coding_t *c) +/* + * Computes the inner products between the current state 'state1' and the + * old states 0,...,'state1'-1 + * + * No return value. + * + * Side effects: + * inner product tables 'c->ip_states_state' are computed. + */ +{ + unsigned level; + unsigned state1, state2; + + /* + * Compute inner product <Phi_state1, Phi_state2> + */ + + for (level = c->options.images_level + 1; + level <= c->options.lc_max_level; level++) + for (state1 = from; state1 <= to; state1++) + for (state2 = 0; state2 <= state1; state2++) + if (need_image (state2, wfa)) + { + unsigned label; + real_t ip = 0; + + for (label = 0; label < MAXLABELS; label++) + { + int domain1, domain2; + unsigned edge1, edge2; + real_t sum, weight2; + + if (ischild (domain1 = wfa->tree [state1][label])) + { + sum = 0; + if (ischild (domain2 = wfa->tree [state2][label])) + sum = get_ip_state_state (domain1, domain2, + level - 1, c); + + for (edge2 = 0; + isedge (domain2 = wfa->into [state2][label][edge2]); + edge2++) + { + weight2 = wfa->weight [state2][label][edge2]; + sum += weight2 * get_ip_state_state (domain1, domain2, + level - 1, c); + } + ip += sum; + } + for (edge1 = 0; + isedge (domain1 = wfa->into [state1][label][edge1]); + edge1++) + { + real_t weight1 = wfa->weight [state1][label][edge1]; + + sum = 0; + if (ischild (domain2 = wfa->tree [state2][label])) + sum = get_ip_state_state (domain1, domain2, + level - 1, c); + + for (edge2 = 0; + isedge (domain2 = wfa->into [state2][label][edge2]); + edge2++) + { + weight2 = wfa->weight [state2][label][edge2]; + sum += weight2 * get_ip_state_state (domain1, domain2, + level - 1, c); + } + ip += weight1 * sum; + } + } + c->ip_states_state [state1][level][state2] = ip; + } +} + +/***************************************************************************** + + private code + +*****************************************************************************/ + +static real_t +standard_ip_image_state (unsigned address, unsigned level, unsigned domain, + const coding_t *c) +/* + * Returns the inner product between the subimage 'address' and the + * state image 'domain' at given 'level'. The stored state images + * and the image tree are used to compute the inner product in the + * standard way by multiplying the corresponding pixel values. + * + * Return value: + * computed inner product + */ +{ + unsigned i; + real_t ip = 0, *imageptr, *stateptr; + + if (level > c->options.images_level) + error ("Level %d not supported.", level); + + imageptr = &c->pixels [address * size_of_level (level)]; + + stateptr = c->images_of_state [domain] + address_of_level (level); + + for (i = size_of_level (level); i; i--) + ip += *imageptr++ * *stateptr++; + + return ip; +} + +static real_t +standard_ip_state_state (unsigned domain1, unsigned domain2, unsigned level, + const coding_t *c) +/* + * Returns the inner product between the subimage 'address' and the + * state image 'state' at given 'level'. The stored state images are + * used to compute the inner product in the standard way by + * multiplying the corresponding pixel values. + * + * Return value: + * computed inner product + */ +{ + unsigned i; + real_t ip = 0, *state1ptr, *state2ptr; + + if (level > c->options.images_level) + error ("Level %d not supported.", level); + + state1ptr = c->images_of_state [domain1] + address_of_level (level); + state2ptr = c->images_of_state [domain2] + address_of_level (level); + + for (i = size_of_level (level); i; i--) + ip += *state1ptr++ * *state2ptr++; + + return ip; +} + diff --git a/converter/other/fiasco/codec/ip.h b/converter/other/fiasco/codec/ip.h new file mode 100644 index 00000000..e5e4dd65 --- /dev/null +++ b/converter/other/fiasco/codec/ip.h @@ -0,0 +1,37 @@ +/* + * ip.h + * + * Written by: Ullrich Hafner + * + * This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec) + * Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de> + */ + +/* + * $Date: 2000/06/14 20:50:51 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#ifndef _IP_H +#define _IP_H + +#include "cwfa.h" + +void +compute_ip_states_state (unsigned from, unsigned to, + const wfa_t *wfa, coding_t *c); +real_t +get_ip_state_state (unsigned domain1, unsigned domain2, unsigned level, + const coding_t *c); +void +compute_ip_images_state (unsigned image, unsigned address, unsigned level, + unsigned n, unsigned from, + const wfa_t *wfa, coding_t *c); +real_t +get_ip_image_state (unsigned image, unsigned address, unsigned level, + unsigned domain, const coding_t *c); + +#endif /* not _IP_H */ + diff --git a/converter/other/fiasco/codec/motion.c b/converter/other/fiasco/codec/motion.c new file mode 100644 index 00000000..92951281 --- /dev/null +++ b/converter/other/fiasco/codec/motion.c @@ -0,0 +1,338 @@ +/* + * motion.c: Motion compensation code + * + * Written by: Ullrich Hafner + * Michael Unger + * + * This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec) + * Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de> + */ + +/* + * $Date: 2000/06/14 20:50:51 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#include "config.h" + +#if HAVE_STRING_H +# include <string.h> +#else /* not HAVE_STRING_H */ +# include <strings.h> +#endif /* not HAVE_STRING_H */ + +#include "types.h" +#include "macros.h" +#include "error.h" + +#include "image.h" +#include "misc.h" +#include "motion.h" + +/***************************************************************************** + + public code + +*****************************************************************************/ + +void +restore_mc (int enlarge_factor, image_t *image, const image_t *past, + const image_t *future, const wfa_t *wfa) +/* + * Restore motion compensated prediction of 'image' represented by 'wfa'. + * If 'enlarge_factor' != 0 then enlarge image by given amount. + * Reference frames are given by 'past' and 'future'. + * + * No return values. + */ +{ + unsigned state, label; + unsigned root_state; + word_t *mcblock1, *mcblock2; /* MC blocks */ + +#define FX(v) ((image->format == FORMAT_4_2_0) && band != Y ? ((v) / 2) : v) + + mcblock1 = Calloc (size_of_level (max ((int) wfa->wfainfo->p_max_level + + 2 * enlarge_factor, 0)), + sizeof (word_t)); + mcblock2 = Calloc (size_of_level (max ((int) wfa->wfainfo->p_max_level + + 2 * enlarge_factor, 0)), + sizeof (word_t)); + + if (!image->color) + root_state = wfa->root_state; + else + root_state = wfa->tree [wfa->tree [wfa->root_state][0]][0]; + + for (state = wfa->basis_states; state <= root_state; state++) + for (label = 0; label < MAXLABELS; label++) + if (wfa->mv_tree[state][label].type != NONE) + { + color_e band; + unsigned level = wfa->level_of_state [state] - 1; + unsigned width = width_of_level (level); + unsigned height = height_of_level (level); + unsigned offset = image->width - width; + + switch (wfa->mv_tree [state][label].type) + { + case FORWARD: + for (band = first_band (image->color); + band <= last_band (image->color); band++) + { + extract_mc_block (mcblock1, FX (width), FX (height), + past->pixels [band], FX (past->width), + wfa->wfainfo->half_pixel, + FX (wfa->x [state][label]), + FX (wfa->y [state][label]), + FX (wfa->mv_tree [state][label].fx), + FX (wfa->mv_tree [state][label].fy)); + { + word_t *mc1; /* current pixel in MC block */ + word_t *orig; /* current pixel in original image */ + unsigned x, y; /* pixel coordinates */ + + mc1 = mcblock1; + orig = (word_t *) image->pixels [band] + + FX (wfa->x[state][label]) + + FX (wfa->y[state][label]) * FX (image->width); + + for (y = FX (height); y; y--) + { + for (x = FX (width); x; x--) + *orig++ += *mc1++; + + orig += FX (offset); + } + } + } + break; + case BACKWARD: + for (band = first_band (image->color); + band <= last_band (image->color); band++) + { + extract_mc_block (mcblock1, FX (width), FX (height), + future->pixels [band], + FX (future->width), + wfa->wfainfo->half_pixel, + FX (wfa->x [state][label]), + FX (wfa->y [state][label]), + FX (wfa->mv_tree [state][label].bx), + FX (wfa->mv_tree [state][label].by)); + { + word_t *mc1; /* current pixel in MC block 1 */ + word_t *orig; /* current pixel in original image */ + unsigned x, y; /* pixel coordinates */ + + mc1 = mcblock1; + orig = (word_t *) image->pixels [band] + + FX (wfa->x[state][label]) + + FX (wfa->y[state][label]) * FX (image->width); + + for (y = FX (height); y; y--) + { + for (x = FX (width); x; x--) + *orig++ += *mc1++; + + orig += FX (offset); + } + } + } + break; + case INTERPOLATED: + for (band = first_band (image->color); + band <= last_band (image->color); band++) + { + extract_mc_block (mcblock1, FX (width), FX (height), + past->pixels [band], FX (past->width), + wfa->wfainfo->half_pixel, + FX (wfa->x[state][label]), + FX (wfa->y[state][label]), + FX (wfa->mv_tree[state][label].fx), + FX (wfa->mv_tree[state][label].fy)); + extract_mc_block (mcblock2, FX (width), FX (height), + future->pixels [band], + FX (future->width), + wfa->wfainfo->half_pixel, + FX (wfa->x[state][label]), + FX (wfa->y[state][label]), + FX (wfa->mv_tree[state][label].bx), + FX (wfa->mv_tree[state][label].by)); + { + word_t *mc1; /* current pixel in MC block 1 */ + word_t *mc2; /* current pixel in MC block 1 */ + word_t *orig; /* current pixel in original image */ + unsigned x, y; /* pixel coordinates */ + + mc1 = mcblock1; + mc2 = mcblock2; + orig = (word_t *) image->pixels [band] + + FX (wfa->x[state][label]) + + FX (wfa->y[state][label]) * FX (image->width); + + for (y = FX (height); y; y--) + { + for (x = FX (width); x; x--) +#ifdef HAVE_SIGNED_SHIFT + *orig++ += (*mc1++ + *mc2++) >> 1; +#else /* not HAVE_SIGNED_SHIFT */ + *orig++ += (*mc1++ + *mc2++) / 2; +#endif /* not HAVE_SIGNED_SHIFT */ + + orig += FX (offset); + } + } + } + break; + default: + break; + } + } + + if (image->color) + { + unsigned n; + word_t *ptr; + static int *clipping = NULL; + unsigned shift = image->format == FORMAT_4_2_0 ? 2 : 0; + + if (!clipping) /* initialize clipping table */ + { + int i; + + clipping = Calloc (256 * 3, sizeof (int)); + for (i = -128; i < 128; i++) + clipping [256 + i + 128] = i; + for (i = 0; i < 256; i++) + clipping [i] = clipping [256]; + for (i = 512; i < 512 + 256; i++) + clipping [i] = clipping [511]; + clipping += 256 + 128; + } + + ptr = image->pixels [Cb]; + for (n = (image->width * image->height) >> shift; n; n--, ptr++) +#ifdef HAVE_SIGNED_SHIFT + *ptr = clipping [*ptr >> 4] << 4; +#else /* not HAVE_SIGNED_SHIFT */ + *ptr = clipping [*ptr / 16] * 16; +#endif /* not HAVE_SIGNED_SHIFT */ + ptr = image->pixels [Cr]; + for (n = (image->width * image->height) >> shift; n; n--, ptr++) +#ifdef HAVE_SIGNED_SHIFT + *ptr = clipping [*ptr >> 4] << 4; +#else /* not HAVE_SIGNED_SHIFT */ + *ptr = clipping [*ptr / 16] * 16; +#endif /* not HAVE_SIGNED_SHIFT */ + } + + Free (mcblock1); + Free (mcblock2); +} + +void +extract_mc_block (word_t *mcblock, unsigned width, unsigned height, + const word_t *reference, unsigned ref_width, + bool_t half_pixel, unsigned xo, unsigned yo, + unsigned mx, unsigned my) +/* + * Extract motion compensation image 'mcblock' of size 'width'x'height' + * from 'reference' image (width is given by 'ref_width'). + * Coordinates of reference block are given by ('xo' + 'mx', 'yo' + 'my'). + * Use 'half_pixel' precision if specified. + * + * No return value. + * + * Side effects: + * 'mcblock[]' MCPE block is filled with reference pixels + */ +{ + if (!half_pixel) /* Fullpixel precision */ + { + const word_t *rblock; /* pointer to reference image */ + unsigned y; /* current row */ + + rblock = reference + (yo + my) * ref_width + (xo + mx); + for (y = height; y; y--) + { + memcpy (mcblock, rblock, width * sizeof (word_t)); + + mcblock += width; + rblock += ref_width; + } + } + else /* Halfpixel precision */ + { + unsigned x, y; /* current coordinates */ + unsigned offset; /* remaining pixels in row */ + const word_t *rblock; /* pointer to reference image */ + const word_t *ryblock; /* pointer to next line */ + const word_t *rxblock; /* pointer to next column */ + const word_t *rxyblock; /* pointer to next column & row */ + + rblock = reference + (yo + my / 2) * ref_width + (xo + mx / 2); + ryblock = rblock + ref_width; /* pixel in next row */ + rxblock = rblock + 1; /* pixel in next column */ + rxyblock = ryblock + 1; /* pixel in next row & column */ + offset = ref_width - width; + + if ((mx & 1) == 0) + { + if ((my & 1) == 0) /* Don't use halfpixel refinement */ + for (y = height; y; y--) + { + memcpy (mcblock, rblock, width * sizeof (word_t)); + + mcblock += width; + rblock += ref_width; + } + else /* Halfpixel in y direction */ + for (y = height; y; y--) + { + for (x = width; x; x--) +#ifdef HAVE_SIGNED_SHIFT + *mcblock++ = (*rblock++ + *ryblock++) >> 1; +#else /* not HAVE_SIGNED_SHIFT */ + *mcblock++ = (*rblock++ + *ryblock++) / 2; +#endif /* not HAVE_SIGNED_SHIFT */ + + rblock += offset; + ryblock += offset; + } + } + else + { + if ((my & 1) == 0) /* Halfpixel in x direction */ + for (y = height; y; y--) + { + for (x = width; x; x--) +#ifdef HAVE_SIGNED_SHIFT + *mcblock++ = (*rblock++ + *rxblock++) >> 1; +#else /* not HAVE_SIGNED_SHIFT */ + *mcblock++ = (*rblock++ + *rxblock++) / 2; +#endif /* not HAVE_SIGNED_SHIFT */ + + rblock += offset; + rxblock += offset; + } + else /* Halfpixel in xy direction */ + for (y = height; y; y--) + { + for (x = width; x; x--) +#ifdef HAVE_SIGNED_SHIFT + *mcblock++ = (*rblock++ + *rxblock++ + + *ryblock++ + *rxyblock++) >> 2; +#else /* not HAVE_SIGNED_SHIFT */ + *mcblock++ = (*rblock++ + *rxblock++ + + *ryblock++ + *rxyblock++) / 4; +#endif /* not HAVE_SIGNED_SHIFT */ + rblock += offset; + ryblock += offset; + rxblock += offset; + rxyblock += offset; + } + } + } +} diff --git a/converter/other/fiasco/codec/motion.h b/converter/other/fiasco/codec/motion.h new file mode 100644 index 00000000..2ea382f7 --- /dev/null +++ b/converter/other/fiasco/codec/motion.h @@ -0,0 +1,35 @@ +/* + * motion.h + * + * Written by: Ullrich Hafner + * Michael Unger + * + * This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec) + * Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de> + */ + +/* + * $Date: 2000/06/14 20:50:51 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#ifndef _MOTION_H +#define _MOTION_H + +#include "wfa.h" +#include "types.h" +#include "image.h" + +void +restore_mc (int enlarge_factor, image_t *image, const image_t *past, + const image_t *future, const wfa_t *wfa); +void +extract_mc_block (word_t *mcblock, unsigned width, unsigned height, + const word_t *reference, unsigned ref_width, + bool_t half_pixel, unsigned xo, unsigned yo, + unsigned mx, unsigned my); + +#endif /* not _MOTION_H */ + diff --git a/converter/other/fiasco/codec/mwfa.c b/converter/other/fiasco/codec/mwfa.c new file mode 100644 index 00000000..6f0af8be --- /dev/null +++ b/converter/other/fiasco/codec/mwfa.c @@ -0,0 +1,864 @@ +/* + * mwfa.c: Initialization of MWFA coder + * + * Written by: Michael Unger + * Ullrich Hafner + * + * This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec) + * Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de> + */ + +/* + * $Date: 2000/06/14 20:50:51 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#include "config.h" + +#include <ctype.h> + +#if HAVE_STRING_H +# include <string.h> +#else /* not HAVE_STRING_H */ +# include <strings.h> +#endif /* not HAVE_STRING_H */ + +#include "types.h" +#include "macros.h" +#include "error.h" + +#include "misc.h" +#include "cwfa.h" +#include "image.h" +#include "mvcode.h" +#include "motion.h" +#include "mwfa.h" + + +static const unsigned local_range = 6; + +/***************************************************************************** + + prototypes + +*****************************************************************************/ + +static void +get_mcpe (word_t *mcpe, const image_t *original, + unsigned x0, unsigned y0, unsigned width, unsigned height, + const word_t *mcblock1, const word_t *mcblock2); +static real_t +mcpe_norm (const image_t *original, unsigned x0, unsigned y0, unsigned width, + unsigned height, const word_t *mcblock1, const word_t *mcblock2); +static real_t +find_best_mv (real_t price, const image_t *original, const image_t *reference, + unsigned x0, unsigned y0, unsigned width, unsigned height, + real_t *bits, int *mx, int *my, const real_t *mc_norms, + const wfa_info_t *wi, const motion_t *mt); +static real_t +find_second_mv (real_t price, const image_t *original, + const image_t *reference, const word_t *mcblock1, + unsigned xr, unsigned yr, unsigned width, unsigned height, + real_t *bits, int *mx, int *my, const wfa_info_t *wi, + const motion_t *mt); + +/***************************************************************************** + + public code + +*****************************************************************************/ + +motion_t * +alloc_motion (const wfa_info_t *wi) +/* + * Motion structure constructor. + * Allocate memory for the motion structure and + * fill in default values specified by 'wi'. + * + * Return value: + * pointer to the new option structure or NULL on error + */ +{ + int dx; /* motion vector coordinate */ + unsigned level; + unsigned range_size = wi->half_pixel + ? square (wi->search_range) + : square (2 * wi->search_range); + motion_t *mt = Calloc (1, sizeof (motion_t)); + + mt->original = NULL; + mt->past = NULL; + mt->future = NULL; + mt->xbits = Calloc (2 * wi->search_range, sizeof (real_t)); + mt->ybits = Calloc (2 * wi->search_range, sizeof (real_t)); + + for (dx = -wi->search_range; dx < (int) wi->search_range; dx++) + { + mt->xbits [dx + wi->search_range] + = mt->ybits [dx + wi->search_range] + = mv_code_table [dx + wi->search_range][1]; + } + + mt->mc_forward_norms = Calloc (MAXLEVEL, sizeof (real_t *)); + mt->mc_backward_norms = Calloc (MAXLEVEL, sizeof (real_t *)); + + for (level = wi->p_min_level; level <= wi->p_max_level; level++) + { + mt->mc_forward_norms [level] = Calloc (range_size, sizeof (real_t)); + mt->mc_backward_norms [level] = Calloc (range_size, sizeof (real_t)); + } + + return mt; +} + +void +free_motion (motion_t *mt) +/* + * Motion struct destructor: + * Free memory of 'motion' struct. + * + * No return value. + * + * Side effects: + * structure 'motion' is discarded. + */ +{ + unsigned level; + + Free (mt->xbits); + Free (mt->ybits); + for (level = 0; level < MAXLEVEL; level++) + { + if (mt->mc_forward_norms [level]) + Free (mt->mc_forward_norms [level]); + if (mt->mc_backward_norms [level]) + Free (mt->mc_backward_norms [level]); + } + Free (mt->mc_forward_norms); + Free (mt->mc_backward_norms); + Free (mt); +} + +void +subtract_mc (image_t *image, const image_t *past, const image_t *future, + const wfa_t *wfa) +/* + * Subtract motion compensation from chrom channels of 'image'. + * Reference frames are given by 'past' and 'future'. + * + * No return values. + */ +{ + unsigned state, label; + word_t *mcblock1 = Calloc (size_of_level (wfa->wfainfo->p_max_level), + sizeof (word_t)); + word_t *mcblock2 = Calloc (size_of_level (wfa->wfainfo->p_max_level), + sizeof (word_t)); + + for (state = wfa->basis_states; state < wfa->states; state++) + for (label = 0; label < MAXLABELS; label++) + if (wfa->mv_tree [state][label].type != NONE) + { + color_e band; /* current color band */ + unsigned width, height; /* size of mcblock */ + unsigned offset; /* remaining pixels in original */ + + width = width_of_level (wfa->level_of_state [state] - 1); + height = height_of_level (wfa->level_of_state [state] - 1); + offset = image->width - width; + + switch (wfa->mv_tree [state][label].type) + { + case FORWARD: + for (band = first_band (image->color) + 1; + band <= last_band (image->color); band++) + { + unsigned y; /* row of block */ + word_t *mc1; /* pixel in MC block 1 */ + word_t *orig; /* pixel in original image */ + + extract_mc_block (mcblock1, width, height, + past->pixels [band], past->width, + wfa->wfainfo->half_pixel, + wfa->x [state][label], + wfa->y [state][label], + (wfa->mv_tree [state][label].fx / 2) + * 2, + (wfa->mv_tree [state][label].fy / 2) + * 2); + mc1 = mcblock1; + orig = image->pixels [band] + wfa->x [state][label] + + wfa->y [state][label] * image->width; + + for (y = height; y; y--) + { + unsigned x; /* column of block */ + + for (x = width; x; x--) + *orig++ -= *mc1++; + + orig += offset; + } + } + break; + case BACKWARD: + for (band = first_band (image->color) + 1; + band <= last_band (image->color); band++) + { + unsigned y; /* row of block */ + word_t *mc1; /* pixel in MC block 1 */ + word_t *orig; /* pixel in original image */ + + extract_mc_block (mcblock1, width, height, + future->pixels [band], future->width, + wfa->wfainfo->half_pixel, + wfa->x [state][label], + wfa->y [state][label], + (wfa->mv_tree [state][label].bx / 2) + * 2, + (wfa->mv_tree [state][label].by / 2) + * 2); + mc1 = mcblock1; + orig = image->pixels [band] + wfa->x [state][label] + + wfa->y [state][label] * image->width; + + for (y = height; y; y--) + { + unsigned x; /* column of block */ + + for (x = width; x; x--) + *orig++ -= *mc1++; + + orig += offset; + } + } + break; + case INTERPOLATED: + for (band = first_band (image->color) + 1; + band <= last_band (image->color); band++) + { + unsigned y; /* row of block */ + word_t *mc1; /* pixel in MC block 1 */ + word_t *mc2; /* pixel in MC block 2 */ + word_t *orig; /* pixel in original image */ + + extract_mc_block (mcblock1, width, height, + past->pixels [band], past->width, + wfa->wfainfo->half_pixel, + wfa->x [state][label], + wfa->y [state][label], + (wfa->mv_tree[state][label].fx / 2) + * 2, + (wfa->mv_tree[state][label].fy / 2) + * 2); + extract_mc_block (mcblock2, width, height, + future->pixels [band], future->width, + wfa->wfainfo->half_pixel, + wfa->x [state][label], + wfa->y [state][label], + (wfa->mv_tree[state][label].bx / 2) + * 2, + (wfa->mv_tree[state][label].by / 2) + * 2); + mc1 = mcblock1; + mc2 = mcblock2; + orig = image->pixels [band] + wfa->x [state][label] + + wfa->y [state][label] * image->width; + + for (y = height; y; y--) + { + unsigned x; /* column of block */ + + for (x = width; x; x--) + *orig++ -= (*mc1++ + *mc2++) / 2; + + orig += offset; + } + } + break; + default: + break; + } + } + + Free (mcblock1); + Free (mcblock2); +} + +void +find_P_frame_mc (word_t *mcpe, real_t price, range_t *range, + const wfa_info_t *wi, const motion_t *mt) +/* + * Determine best motion vector for P-frame. + * + * No return value. + * + * Side effects: + * range->mvt_bits (# of mv-tree bits) + * range->mvxybits (# of bits for vector components) + * mt->mcpe (MCPE in scan-order) + */ +{ + unsigned width = width_of_level (range->level); + unsigned height = height_of_level (range->level); + word_t *mcblock = Calloc (width * height, sizeof (word_t)); + + range->mv_tree_bits = 1; + range->mv.type = FORWARD; + + /* + * Find best matching forward prediction + */ + find_best_mv (price, mt->original, mt->past, range->x, range->y, + width, height, &range->mv_coord_bits, &range->mv.fx, + &range->mv.fy, mt->mc_forward_norms [range->level], wi, mt); + + /* + * Compute MCPE + */ + extract_mc_block (mcblock, width, height, mt->past->pixels [GRAY], + mt->past->width, wi->half_pixel, range->x, range->y, + range->mv.fx, range->mv.fy); + get_mcpe (mcpe, mt->original, range->x, range->y, width, height, + mcblock, NULL); + + Free (mcblock); +} + +void +find_B_frame_mc (word_t *mcpe, real_t price, range_t *range, + const wfa_info_t *wi, const motion_t *mt) +/* + * Determines best motion compensation for B-frame. + * Steps: + * 1) find best forward motion vector + * 2) find best backward motion vector + * 3) try both motion vectors together (interpolation) + * 4) choose best mode (FORWARD, BACKWARD or INTERPOLATED) + * Bitcodes: + * FORWARD 000 + * BACKWARD 001 + * INTERPOLATED 01 + * + * Return values: + * range->mvt_bits (# of mv-tree bits) + * range->mvxybits (# of bits for vector components) + * mt->mcpe (MCPE in scan-order) + */ +{ + mc_type_e mctype; /* type of motion compensation */ + real_t forward_costs; /* costs of FORWARD mc */ + real_t backward_costs; /* costs of BACKWARD mc */ + real_t interp_costs; /* costs of INTERPOLATED mc */ + real_t forward_bits; /* bits for FORWARD mc */ + real_t backward_bits; /* bits for BACKWARD mc */ + real_t interp_bits; /* bits for INTERPOLATED mc */ + int fx, fy; /* coordinates FORWARD mc */ + int bx, by; /* coordinates BACKWARD mc */ + int ifx, ify; /* coordinates forw. INTERPOLATED mc */ + int ibx, iby; /* coordinates back. INTERPOLATED mc */ + unsigned width = width_of_level (range->level); + unsigned height = height_of_level (range->level); + word_t *mcblock1 = Calloc (width * height, sizeof (word_t)); + word_t *mcblock2 = Calloc (width * height, sizeof (word_t)); + + /* + * Forward interpolation: use past frame as reference + */ + forward_costs = find_best_mv (price, mt->original, mt->past, + range->x, range->y, width, height, + &forward_bits, &fx, &fy, + mt->mc_forward_norms [range->level], wi, mt) + + 3 * price; /* code 000 */ + + /* + * Backward interpolation: use future frame as reference + */ + backward_costs = find_best_mv (price, mt->original, mt->future, + range->x, range->y, width, height, + &backward_bits, &bx, &by, + mt->mc_backward_norms [range->level], wi, mt) + + 3 * price; /* code 001 */ + + /* + * Bidirectional interpolation: use both past and future frame as reference + */ + if (wi->cross_B_search) + { + real_t icosts1; /* costs interpolation alternative 1 */ + real_t icosts2; /* costs interpolation alternative 2 */ + real_t ibackward_bits; /* additional bits alternative 1 */ + real_t iforward_bits; /* additional bits alternative 1 */ + + /* + * Alternative 1: keep forward mv and vary backward mv locally + */ + extract_mc_block (mcblock1, width, height, mt->past->pixels [GRAY], + mt->past->width, wi->half_pixel, + range->x, range->y, fx, fy); + + ibx = bx; /* start with backward coordinates */ + iby = by; + icosts1 = find_second_mv (price, mt->original, mt->future, + mcblock1, range->x, range->y, width, height, + &ibackward_bits, &ibx, &iby, wi, mt) + + (forward_bits + 2) * price; /* code 01 */ + + /* + * Alternative 2: Keep backward mv and vary forward mv locally + */ + extract_mc_block (mcblock1, width, height, mt->future->pixels [GRAY], + mt->future->width, wi->half_pixel, + range->x, range->y, bx, by); + + ifx = fx; + ify = fy; + icosts2 = find_second_mv (price, mt->original, mt->past, + mcblock1, range->x, range->y, width, height, + &iforward_bits, &ifx, &ify, wi, mt) + + (backward_bits + 2) * price; /* code 01 */ + + /* + * Choose best alternative + */ + if (icosts1 < icosts2) + { + ifx = fx; + ify = fy; + interp_bits = forward_bits + ibackward_bits; + interp_costs = icosts1; + } + else + { + ibx = bx; + iby = by; + interp_bits = iforward_bits + backward_bits; + interp_costs = icosts2; + } + } + else /* local exhaustive search */ + { + /* + * Keep forward and backward mv due to time constraints + */ + + ifx = fx; + ify = fy; + ibx = bx; + iby = by; + interp_bits = forward_bits + backward_bits; + + extract_mc_block (mcblock1, width, height, mt->past->pixels [GRAY], + mt->past->width, wi->half_pixel, + range->x, range->y, fx, fy); + extract_mc_block (mcblock2, width, height, mt->future->pixels [GRAY], + mt->future->width, wi->half_pixel, + range->x, range->y, bx, by); + interp_costs = mcpe_norm (mt->original, range->x, range->y, + width, height, mcblock1, mcblock2) + + (interp_bits + 2) * price; /* code 01 */ + } + + /* + * Choose alternative with smallest costs + */ + if (forward_costs <= interp_costs) + { + if (forward_costs <= backward_costs) + mctype = FORWARD; + else + mctype = BACKWARD; + } + else + { + if (backward_costs <= interp_costs) + mctype = BACKWARD; + else + mctype = INTERPOLATED; + } + + switch (mctype) + { + case FORWARD: + range->mv_tree_bits = 3; + range->mv_coord_bits = forward_bits; + range->mv.type = FORWARD; + range->mv.fx = fx; + range->mv.fy = fy; + extract_mc_block (mcblock1, width, height, mt->past->pixels [GRAY], + mt->past->width, wi->half_pixel, + range->x, range->y, range->mv.fx, range->mv.fy); + get_mcpe (mcpe, mt->original, range->x, range->y, width, height, + mcblock1, NULL); + break; + case BACKWARD: + range->mv_tree_bits = 3; + range->mv_coord_bits = backward_bits; + range->mv.type = BACKWARD; + range->mv.bx = bx; + range->mv.by = by; + extract_mc_block (mcblock1, width, height, mt->future->pixels [GRAY], + mt->future->width, wi->half_pixel, + range->x, range->y, range->mv.bx, range->mv.by); + get_mcpe (mcpe, mt->original, range->x, range->y, width, height, + mcblock1, NULL); + break; + case INTERPOLATED: + range->mv_tree_bits = 2; + range->mv_coord_bits = interp_bits; + range->mv.type = INTERPOLATED; + range->mv.fx = ifx; + range->mv.fy = ify; + range->mv.bx = ibx; + range->mv.by = iby; + extract_mc_block (mcblock1, width, height, mt->past->pixels [GRAY], + mt->past->width, wi->half_pixel, + range->x, range->y, range->mv.fx, range->mv.fy); + extract_mc_block (mcblock2, width, height, mt->future->pixels [GRAY], + mt->future->width, wi->half_pixel, + range->x, range->y, range->mv.bx, range->mv.by); + get_mcpe (mcpe, mt->original, range->x, range->y, width, height, + mcblock1, mcblock2); + break; + default: + break; + } + + Free (mcblock1); + Free (mcblock2); +} + +void +fill_norms_table (unsigned x0, unsigned y0, unsigned level, + const wfa_info_t *wi, motion_t *mt) +/* + * Compute norms of difference images for all possible displacements + * in 'mc_forward_norm' and 'mc_backward_norm'. + * + * No return value. + * + * Side effects: + * 'mt->mc_backward_norms' are computed + * 'mt->mc_forward_norms' are computed + */ +{ + int mx, my; /* coordinates of motion vector */ + unsigned sr; /* mv search range +-'sr' pixels */ + unsigned index = 0; /* index of motion vector */ + unsigned width = width_of_level (level); + unsigned height = height_of_level (level); + word_t *mcblock = Calloc (width * height, sizeof (word_t)); + + sr = wi->half_pixel ? wi->search_range / 2 : wi->search_range; + + for (my = -sr; my < (int) sr; my++) + for (mx = -sr; mx < (int) sr; mx++, index++) + { + if ((int) x0 + mx < 0 || /* block outside visible area */ + x0 + mx + width > mt->original->width || + (int) y0 + my < 0 || + y0 + my + height > mt->original->height) + { + mt->mc_forward_norms [level][index] = 0.0; + mt->mc_backward_norms [level][index] = 0.0; + } + else + { + extract_mc_block (mcblock, width, height, mt->past->pixels [GRAY], + mt->past->width, wi->half_pixel, + x0, y0, mx, my); + mt->mc_forward_norms [level][index] + = mcpe_norm (mt->original, x0, y0, width, height, + mcblock, NULL); + + if (mt->frame_type == B_FRAME) + { + extract_mc_block (mcblock, width, height, + mt->future->pixels [GRAY], + mt->future->width, wi->half_pixel, + x0, y0, mx, my); + mt->mc_backward_norms[level][index] + = mcpe_norm (mt->original, x0, y0, width, height, + mcblock, NULL); + } + } + } + + Free (mcblock); +} + +/***************************************************************************** + + private code + +*****************************************************************************/ + +static void +get_mcpe (word_t *mcpe, const image_t *original, unsigned x0, unsigned y0, + unsigned width, unsigned height, const word_t *mcblock1, + const word_t *mcblock2) +/* + * Compute MCPE image 'original' - reference. The reference is either + * composed of 'mcblock1' or of ('mcblock1' + 'mcblock2') / 2 (if + * 'mcblock2' != NULL). Coordinates of original block are given by + * 'x0', 'y0', 'width', and 'height'. + * + * No return value. + * + * Side effects: + * 'mcpe []' is filled with the delta image + */ +{ + const word_t *oblock; /* pointer to original image */ + + assert (mcpe); + + oblock = original->pixels [GRAY] + y0 * original->width + x0; + + if (mcblock2 != NULL) /* interpolated prediction */ + { + unsigned x, y; /* current coordinates */ + + for (y = height; y; y--) + { + for (x = width; x; x--) + *mcpe++ = *oblock++ - (*mcblock1++ + *mcblock2++) / 2; + + oblock += original->width - width; + } + } + else /* forward or backward prediction */ + { + unsigned x, y; /* current coordinates */ + + for (y = height; y; y--) + { + for (x = width; x; x--) + *mcpe++ = *oblock++ - *mcblock1++; + + oblock += original->width - width; + } + } +} + +static real_t +mcpe_norm (const image_t *original, unsigned x0, unsigned y0, unsigned width, + unsigned height, const word_t *mcblock1, const word_t *mcblock2) +/* + * Compute norm of motion compensation prediction error. + * Coordinates of 'original' block are given by ('x0', 'y0') + * and 'width', 'height'. + * Reference blocks are stored in 'mcimage1' and 'mcimage2'. + * + * Return value: + * square of norm of difference image + */ +{ + unsigned n; + real_t norm = 0; + word_t *mcpe = Calloc (width * height, sizeof (word_t)); + word_t *ptr = mcpe; + + get_mcpe (mcpe, original, x0, y0, width, height, mcblock1, mcblock2); + + for (n = height * width; n; n--, ptr++) + norm += square (*ptr / 16); + + Free (mcpe); + + return norm; +} + +static real_t +find_best_mv (real_t price, const image_t *original, const image_t *reference, + unsigned x0, unsigned y0, unsigned width, unsigned height, + real_t *bits, int *mx, int *my, const real_t *mc_norms, + const wfa_info_t *wi, const motion_t *mt) +/* + * Find best matching motion vector in image 'reference' to predict + * the block ('x0', 'y0') of size 'width'x'height in image 'original'. + * + * Return values: + * prediction costs + * + * Side effects: + * 'mx', 'my' coordinates of motion vector + * 'bits' number of bits to encode mv + */ +{ + unsigned sr; /* mv search range +/- 'sr' pixels */ + unsigned index; /* index of motion vector */ + int x, y; /* coordinates of motion vector */ + real_t costs; /* costs arising if mv is chosen */ + real_t mincosts = MAXCOSTS; /* best costs so far */ + unsigned bitshift; /* half_pixel coordinates multiplier */ + + *mx = *my = 0; + + /* + * Find best fitting motion vector: + * Use exhaustive search in the interval x,y +- sr (no halfpixel accuracy) + * or x,y +- sr/2 (halfpixel accuracy) + */ + sr = wi->half_pixel ? wi->search_range / 2 : wi->search_range; + bitshift = (wi->half_pixel ? 2 : 1); /* bit0 reserved for halfpixel pred. */ + + for (index = 0, y = -sr; y < (int) sr; y++) + for (x = -sr; x < (int) sr; x++, index++) + if ((int) x0 + x >= 0 && (int) y0 + y >= 0 && + x0 + x + width <= original->width && + y0 + y + height <= original->height) + { + /* + * Block is inside visible area. + * Compare current costs with 'mincosts' + */ + costs = mc_norms [index] + + (mt->xbits [(x + sr) * bitshift] + + mt->ybits [(y + sr) * bitshift]) * price; + + if (costs < mincosts) + { + mincosts = costs; + *mx = x * bitshift; + *my = y * bitshift; + } + } + + /* + * Halfpixel prediction: + * Compare all nine combinations (-1, y), (0, y), (+1, y) for y = -1,0,+1 + */ + if (wi->half_pixel) + { + int rx, ry; /* halfpixel refinement */ + unsigned bestrx, bestry; /* coordinates of best mv */ + word_t *mcblock = Calloc (width * height, sizeof (word_t)); + + bestrx = bestry = 0; + for (rx = -1; rx <= 1; rx++) + for (ry = -1; ry <= 1; ry++) + { + /* + * Check if the new motion vector is in allowed area + */ + if (rx == 0 && ry == 0) /* already tested */ + continue; + if ((int) x0 + (*mx / 2) + rx < 0 || /* outside visible area */ + x0 + (*mx / 2) + rx + width > original->width || + (int) y0 + (*my / 2) + ry < 0 || + y0 + (*my / 2) + ry + height > original->height) + continue; + if (*mx + rx < (int) -sr || *mx + rx >= (int) sr || + *my + ry < (int) -sr || *my + ry >= (int) sr) + continue; /* out of bounds */ + + /* + * Compute costs of new motion compensation + */ + extract_mc_block (mcblock, width, height, + reference->pixels [GRAY], + reference->width, wi->half_pixel, + x0, y0, *mx + rx, *my + ry); + costs = mcpe_norm (mt->original, x0, y0, width, height, mcblock, + NULL) + + (mt->xbits [*mx + rx + sr * bitshift] + + mt->ybits [*my + ry + sr * bitshift]) * price; + if (costs < mincosts) + { + bestrx = rx; + bestry = ry; + mincosts = costs; + } + } + + *mx += bestrx; + *my += bestry; + + Free (mcblock); + } /* halfpixel */ + + *bits = mt->xbits [*mx + sr * bitshift] + mt->ybits [*my + sr * bitshift]; + + return mincosts; +} + +static real_t +find_second_mv (real_t price, const image_t *original, + const image_t *reference, const word_t *mcblock1, + unsigned xr, unsigned yr, unsigned width, unsigned height, + real_t *bits, int *mx, int *my, const wfa_info_t *wi, + const motion_t *mt) +/* + * Search local area (*mx,*my) for best additional mv. + * Overwrite mt->tmpblock. + * TODO check sr = search_range + * + * Return values: + * prediction costs + * + * Side effects: + * 'mx','my' coordinates of mv + * 'bits' number of bits to encode mv + */ +{ + real_t mincosts = MAXCOSTS; /* best costs so far */ + unsigned sr; /* MV search range +/- 'sr' pixels */ + int x, y; /* coordinates of motion vector */ + int y0, y1, x0, x1; /* start/end coord. of search range */ + unsigned bitshift; /* half_pixel coordinates multiplier */ + word_t *mcblock2 = Calloc (width * height, sizeof (word_t)); + + sr = wi->search_range; + + y0 = max ((int) -sr, *my - (int) local_range); + y1 = min ((int) sr, *my + (int) local_range); + x0 = max ((int) -sr, *mx - (int) local_range); + x1 = min ((int) sr, *mx + (int) local_range); + + *mx = *my = 0; + + bitshift = (wi->half_pixel ? 2 : 1); /* bit0 reserved for halfpixel pred. */ + + + for (y = y0; y < y1; y++) + for (x = x0; x < x1; x++) + { + real_t costs; /* costs arising if mv is chosen */ + + /* + * Test each mv ('x', 'y') in the given search range: + * Get the new motion compensation image from 'reference' and compute + * the norm of the motion compensation prediction error + * 'original' - 0.5 * ('firstmc' + 'reference') + */ + if ((int) (xr * bitshift) + x < 0 || /* outside visible area */ + xr * bitshift + x > (original->width - width) * bitshift || + (int) (yr * bitshift) + y < 0 || + yr * bitshift + y > (original->height - height) * bitshift) + continue; + + extract_mc_block (mcblock2, width, height, + reference->pixels [GRAY], reference->width, + wi->half_pixel, x0, y0, x, y); + + costs = mcpe_norm (mt->original, x0, y0, width, height, + mcblock1, mcblock2) + + (mt->xbits [x + sr] + mt->ybits [y + sr]) * price; + + if (costs < mincosts) + { + mincosts = costs; + *mx = x; + *my = y; + } + } + + *bits = mt->xbits [*mx + sr] + mt->ybits [*my + sr]; + + Free (mcblock2); + + return mincosts; +} diff --git a/converter/other/fiasco/codec/mwfa.h b/converter/other/fiasco/codec/mwfa.h new file mode 100644 index 00000000..52f41866 --- /dev/null +++ b/converter/other/fiasco/codec/mwfa.h @@ -0,0 +1,44 @@ +/* + * mwfa.h + * + * Written by: Michael Unger + * Ullrich Hafner + * + * This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec) + * Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de> + */ + +/* + * $Date: 2000/06/14 20:50:51 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#ifndef _MWFA_H +#define _MWFA_H + +#include "types.h" +#include "image.h" +#include "wfa.h" +#include "cwfa.h" + +void +fill_norms_table (unsigned x0, unsigned y0, unsigned level, + const wfa_info_t *wi, motion_t *mt); +void +find_B_frame_mc (word_t *mcpe, real_t price, range_t *range, + const wfa_info_t *wi, const motion_t *mt); +void +find_P_frame_mc (word_t *mcpe, real_t price, range_t *range, + const wfa_info_t *wi, const motion_t *mt); +void +subtract_mc (image_t *image, const image_t *past, const image_t *future, + const wfa_t *wfa); +void +free_motion (motion_t *mt); +motion_t * +alloc_motion (const wfa_info_t *wi); + +#endif /* not _MWFA_H */ + diff --git a/converter/other/fiasco/codec/options.c b/converter/other/fiasco/codec/options.c new file mode 100644 index 00000000..77dbaf00 --- /dev/null +++ b/converter/other/fiasco/codec/options.c @@ -0,0 +1,894 @@ +/* + * options.c: FIASCO options handling + * + * Written by: Ullrich Hafner + * + * This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec) + * Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de> + */ + +/* + * $Date: 2000/10/28 17:39:31 $ + * $Author: hafner $ + * $Revision: 5.5 $ + * $State: Exp $ + */ + +#define _BSD_SOURCE 1 /* Make sure strdup() is in string.h */ +#define _XOPEN_SOURCE 500 /* Make sure strdup() is in string.h */ + +#include "config.h" + +#include <string.h> +#if STDC_HEADERS +# include <stdlib.h> +#endif /* not STDC_HEADERS */ + +#include <stdio.h> + +#include "types.h" +#include "macros.h" +#include "error.h" + +#include "wfa.h" +#include "misc.h" +#include "bit-io.h" +#include "fiasco.h" +#include "options.h" + +fiasco_c_options_t * +fiasco_c_options_new (void) +/* + * FIASCO options constructor. + * Allocate memory for the FIASCO coder options structure and + * fill in default values. + * + * Return value: + * pointer to the new option structure + */ +{ + c_options_t *options = calloc (1, sizeof (c_options_t)); + fiasco_c_options_t *public = calloc (1, sizeof (fiasco_c_options_t)); + + if (!options || !public) + { + set_error (_("Out of memory.")); + return NULL; + } + public->private = options; + public->delete = fiasco_c_options_delete; + public->set_tiling = fiasco_c_options_set_tiling; + public->set_frame_pattern = fiasco_c_options_set_frame_pattern; + public->set_basisfile = fiasco_c_options_set_basisfile; + public->set_chroma_quality = fiasco_c_options_set_chroma_quality; + public->set_optimizations = fiasco_c_options_set_optimizations; + public->set_video_param = fiasco_c_options_set_video_param; + public->set_quantization = fiasco_c_options_set_quantization; + public->set_progress_meter = fiasco_c_options_set_progress_meter; + public->set_smoothing = fiasco_c_options_set_smoothing; + public->set_title = fiasco_c_options_set_title; + public->set_comment = fiasco_c_options_set_comment; + + strcpy (options->id, "COFIASCO"); + + /* + * Set default value of fiasco options + */ + options->basis_name = strdup ("small.fco"); + options->lc_min_level = 4; + options->lc_max_level = 12; + options->p_min_level = 8; + options->p_max_level = 10; + options->images_level = 5; + options->max_states = MAXSTATES; + options->chroma_max_states = 40; + options->max_elements = MAXEDGES; + options->tiling_exponent = 4; + options->tiling_method = FIASCO_TILING_VARIANCE_DSC; + options->id_domain_pool = strdup ("rle"); + options->id_d_domain_pool = strdup ("rle"); + options->id_rpf_model = strdup ("adaptive"); + options->id_d_rpf_model = strdup ("adaptive"); + options->rpf_mantissa = 3; + options->rpf_range = FIASCO_RPF_RANGE_1_50; + options->dc_rpf_mantissa = 5; + options->dc_rpf_range = FIASCO_RPF_RANGE_1_00; + options->d_rpf_mantissa = 3; + options->d_rpf_range = FIASCO_RPF_RANGE_1_50; + options->d_dc_rpf_mantissa = 5; + options->d_dc_rpf_range = FIASCO_RPF_RANGE_1_00; + options->chroma_decrease = 2.0; + options->prediction = NO; + options->delta_domains = YES; + options->normal_domains = YES; + options->search_range = 16; + options->fps = 25; + options->pattern = strdup ("IPPPPPPPPP"); + options->reference_filename = NULL; + options->half_pixel_prediction = NO; + options->cross_B_search = YES; + options->B_as_past_ref = YES; + options->check_for_underflow = NO; + options->check_for_overflow = NO; + options->second_domain_block = NO; + options->full_search = NO; + options->progress_meter = FIASCO_PROGRESS_NONE; + options->smoothing = 70; + options->comment = strdup (""); + options->title = strdup (""); + + return public; +} + +void +fiasco_c_options_delete (fiasco_c_options_t *options) +/* + * FIASCO options destructor. + * Free memory of FIASCO options struct. + * + * No return value. + * + * Side effects: + * structure 'options' is discarded. + */ +{ + c_options_t *this = cast_c_options (options); + + if (!this) + return; + + Free (this->id_domain_pool); + Free (this->id_d_domain_pool); + Free (this->id_rpf_model); + Free (this->id_d_rpf_model); + Free (this->pattern); + Free (this->comment); + Free (this->title); + + Free (this); + + return; +} + +int +fiasco_c_options_set_tiling (fiasco_c_options_t *options, + fiasco_tiling_e method, unsigned exponent) +/* + * Set tiling `method' and `exponent'. + * See type `fiasco_tiling_e' for a list of valid tiling `methods'. + * The image is subdivied into 2^`exponent' tiles + * + * Return value: + * 1 on success + * 0 otherwise + */ +{ + c_options_t *this = (c_options_t *) cast_c_options (options); + + if (!this) + { + return 0; + } + switch (method) + { + case FIASCO_TILING_SPIRAL_ASC: + case FIASCO_TILING_SPIRAL_DSC: + case FIASCO_TILING_VARIANCE_ASC: + case FIASCO_TILING_VARIANCE_DSC: + this->tiling_method = method; + break; + default: + set_error (_("Invalid tiling method `%d' specified " + "(valid methods are 0, 1, 2, or 3)."), method); + return 0; + } + this->tiling_exponent = exponent; + + return 1; +} + +int +fiasco_c_options_set_frame_pattern (fiasco_c_options_t *options, + const char *pattern) +/* + * Set `pattern' of input frames. + * `pattern' has to be a sequence of the following + * characters (case insensitive): + * 'i' intra frame + * 'p' predicted frame + * 'b' bidirectional predicted frame + * E.g. pattern = 'IBBPBBPBB' + * + * When coding video frames the prediction type of input frame N is determined + * by reading `pattern' [N] (`pattern' is periodically extended). + * + * Return value: + * 1 on success + * 0 otherwise + */ +{ + c_options_t *this = (c_options_t *) cast_c_options (options); + + if (!this) + { + return 0; + } + else if (!pattern) + { + set_error (_("Parameter `%s' not defined (NULL)."), "pattern"); + return 0; + } + else if (strlen (pattern) < 1) + { + set_error (_("Frame type pattern doesn't contain any character.")); + return 0; + } + else + { + const char *str; + bool_t parse_error = NO; + int c = 0; + + for (str = pattern; *str && !parse_error; str++) + switch (*str) + { + case 'i': + case 'I': + case 'b': + case 'B': + case 'p': + case 'P': + break; + default: + c = *str; + parse_error = YES; + } + + if (parse_error) + { + set_error (_("Frame type pattern contains invalid character `%c' " + "(choose I, B or P)."), c); + return 0; + } + else + { + Free (this->pattern); + this->pattern = strdup (pattern); + + return 1; + } + } +} + +int +fiasco_c_options_set_basisfile (fiasco_c_options_t *options, + const char *filename) +/* + * Set `filename' of FIASCO initial basis. + * + * Return value: + * 1 on success (if the file is readable) + * 0 otherwise + */ +{ + c_options_t *this = (c_options_t *) cast_c_options (options); + + if (!this) + { + return 0; + } + else if (!filename) + { + set_error (_("Parameter `%s' not defined (NULL)."), "filename"); + return 0; + } + else + { + /* Skip this because basis file may be linked with program, not + in a separate file. See get_linked_basis(). NETPBM + FILE *file = open_file (filename, "FIASCO_DATA", READ_ACCESS); + if (file) + { + fclose (file); + return 1; + } + else + { + set_error (_("Can't read basis file `%s'.\n%s."), filename, + get_system_error ()); + return 0; + } + */ return 1; + } +} + +int +fiasco_c_options_set_chroma_quality (fiasco_c_options_t *options, + float quality_factor, + unsigned dictionary_size) +/* + * Set color compression parameters. + * When coding chroma channels (Cb and Cr) + * - approximation quality is given by `quality_factor' * `Y quality' and + * - `dictionary_size' gives the number of dictionary elements. + * + * If 'quality' <= 0 then the luminancy coding quality is also during + * chroma channel coding. + * + * Return value: + * 1 on success + * 0 otherwise + */ +{ + c_options_t *this = (c_options_t *) cast_c_options (options); + + if (!this) + { + return 0; + } + else if (!dictionary_size) + { + set_error (_("Size of chroma compression dictionary has to be " + "a positive number.")); + return 0; + } + else if (quality_factor <= 0) + { + set_error (_("Quality of chroma channel compression has to be " + "positive value.")); + return 0; + } + else + { + this->chroma_decrease = quality_factor; + this->chroma_max_states = dictionary_size; + + return 1; + } +} + +int +fiasco_c_options_set_optimizations (fiasco_c_options_t *options, + unsigned min_block_level, + unsigned max_block_level, + unsigned max_elements, + unsigned dictionary_size, + unsigned optimization_level) +/* + * Set various optimization parameters. + * - During compression only image blocks of size + * {`min_block_level', ... ,`max_block_level'} are considered. + * The smaller this set of blocks is the faster the coder runs + * and the worse the image quality will be. + * - An individual approximation may use at most `max_elements' + * elements of the dictionary which itself contains at most + * `dictionary_size' elements. The smaller these values are + * the faster the coder runs and the worse the image quality will be. + * - `optimization_level' enables some additional low level optimizations. + * 0: standard approximation method + * 1: significantly increases the approximation quality, + * running time is twice as high as with the standard method + * 2: hardly increases the approximation quality of method 1, + * running time is twice as high as with method 1 + * (this method just remains for completeness) + * + * Return value: + * 1 on success + * 0 otherwise + */ +{ + c_options_t *this = (c_options_t *) cast_c_options (options); + + if (!this) + { + return 0; + } + else if (!dictionary_size) + { + set_error (_("Size of dictionary has to be a positive number.")); + return 0; + } + else if (!max_elements) + { + set_error (_("At least one dictionary element has to be used " + "in an approximation.")); + return 0; + } + else if (max_block_level < 4) + { + set_error (_("Maximum image block size has to be at least level 4.")); + return 0; + } + else if (min_block_level < 4) + { + set_error (_("Minimum image block size has to be at least level 4.")); + return 0; + } + else if (max_block_level < min_block_level) + { + set_error (_("Maximum block size has to be larger or " + "equal minimum block size.")); + return 0; + } + else + { + this->lc_min_level = min_block_level; + this->lc_max_level = max_block_level; + this->max_states = dictionary_size; + this->max_elements = max_elements; + this->second_domain_block = optimization_level > 0 ? YES : NO; + this->check_for_overflow = optimization_level > 1 ? YES : NO; + this->check_for_underflow = optimization_level > 1 ? YES : NO; + this->full_search = optimization_level > 1 ? YES : NO; + + return 1; + } +} + +int +fiasco_c_options_set_prediction (fiasco_c_options_t *options, + int intra_prediction, + unsigned min_block_level, + unsigned max_block_level) +/* + * Set minimum and maximum size of image block prediction to + * `min_block_level' and `max_block_level'. + * (For either motion compensated prediction of inter frames + * or DC based prediction of intra frames) + * Prediction of intra frames is only used if `intra_prediction' != 0. + * + * Return value: + * 1 on success + * 0 otherwise + */ +{ + c_options_t *this = (c_options_t *) cast_c_options (options); + + if (!this) + { + return 0; + } + else if (max_block_level < 6) + { + set_error (_("Maximum prediction block size has to be " + "at least level 6")); + return 0; + } + else if (min_block_level < 6) + { + set_error (_("Minimum prediction block size has to be " + "at least level 6")); + return 0; + } + else if (max_block_level < min_block_level) + { + set_error (_("Maximum prediction block size has to be larger or " + "equal minimum block size.")); + return 0; + } + else + { + this->p_min_level = min_block_level; + this->p_max_level = max_block_level; + this->prediction = intra_prediction; + + return 1; + } +} + +int +fiasco_c_options_set_video_param (fiasco_c_options_t *options, + unsigned frames_per_second, + int half_pixel_prediction, + int cross_B_search, + int B_as_past_ref) +/* + * Set various parameters used for video compensation. + * 'frames_per_second' defines the frame rate which should be + * used when the video is decoded. This value has no effect during coding, + * it is just passed to the FIASCO output file. + * If 'half_pixel_prediction' is not 0 then half pixel precise + * motion compensated prediction is used. + * If 'cross_B_search' is not 0 then the fast Cross-B-Search algorithm is + * used to determine the motion vectors of interpolated prediction. Otherwise + * exhaustive search (in the given search range) is used. + * If 'B_as_past_ref' is not 0 then B frames are allowed to be used + * for B frame predicion. + * + * Return value: + * 1 on success + * 0 otherwise + */ +{ + c_options_t *this = (c_options_t *) cast_c_options (options); + + if (!this) + { + return 0; + } + else + { + this->fps = frames_per_second; + this->half_pixel_prediction = half_pixel_prediction; + this->cross_B_search = cross_B_search; + this->B_as_past_ref = B_as_past_ref; + + return 1; + } +} + +int +fiasco_c_options_set_quantization (fiasco_c_options_t *options, + unsigned mantissa, + fiasco_rpf_range_e range, + unsigned dc_mantissa, + fiasco_rpf_range_e dc_range) +/* + * Set accuracy of coefficients quantization. + * DC coefficients (of the constant dictionary vector f(x,y) = 1) + * are quantized to values of the interval [-`dc_range', `dc_range'] using + * #`dc_mantissa' bits. All other quantized coefficients are quantized in + * an analogous way using the parameters `range' and `mantissa'. + * + * Return value: + * 1 on success + * 0 otherwise + */ +{ + c_options_t *this = (c_options_t *) cast_c_options (options); + + if (!this) + { + return 0; + } + else if (mantissa < 2 || mantissa > 8 || dc_mantissa < 2 || dc_mantissa > 8) + { + set_error (_("Number of RPF mantissa bits `%d', `%d' have to be in " + "the interval [2,8]."), mantissa, dc_mantissa); + return 0; + } + else + { + if ((range == FIASCO_RPF_RANGE_0_75 + || range == FIASCO_RPF_RANGE_1_00 + || range == FIASCO_RPF_RANGE_1_50 + || range == FIASCO_RPF_RANGE_2_00) + && + (dc_range == FIASCO_RPF_RANGE_0_75 + || dc_range == FIASCO_RPF_RANGE_1_00 + || dc_range == FIASCO_RPF_RANGE_1_50 + || dc_range == FIASCO_RPF_RANGE_2_00)) + { + this->rpf_range = range; + this->dc_rpf_range = dc_range; + this->rpf_mantissa = mantissa; + this->dc_rpf_mantissa = dc_mantissa; + + return 1; + } + else + { + set_error (_("Invalid RPF ranges `%d', `%d' specified."), + range, dc_range); + return 0; + } + } +} + +int +fiasco_c_options_set_progress_meter (fiasco_c_options_t *options, + fiasco_progress_e type) +/* + * Set type of progress meter. + * + * Return value: + * 1 on success + * 0 otherwise + */ +{ + c_options_t *this = (c_options_t *) cast_c_options (options); + + if (!this) + { + return 0; + } + switch (type) + { + case FIASCO_PROGRESS_BAR: + case FIASCO_PROGRESS_PERCENT: + case FIASCO_PROGRESS_NONE: + this->progress_meter = type; + break; + default: + set_error (_("Invalid progress meter `%d' specified " + "(valid values are 0, 1, or 2)."), type); + return 0; + } + return 1; +} + +int +fiasco_c_options_set_smoothing (fiasco_c_options_t *options, int smoothing) +/* + * Define `smoothing'-percentage along partitioning borders. + * + * Return value: + * 1 on success + * 0 otherwise + */ +{ + c_options_t *this = (c_options_t *) cast_c_options (options); + + if (!this) + { + return 0; + } + else if (smoothing < -1 || smoothing > 100) + { + set_error (_("Smoothing percentage must be in the range [-1, 100].")); + return 0; + } + else + { + this->smoothing = smoothing; + return 1; + } +} + +int +fiasco_c_options_set_comment (fiasco_c_options_t *options, const char *comment) +/* + * Define `comment' of FIASCO stream. + * + * Return value: + * 1 on success + * 0 otherwise + */ +{ + c_options_t *this = (c_options_t *) cast_c_options (options); + + if (!this) + { + return 0; + } + else if (!comment) + { + set_error (_("Parameter `%s' not defined (NULL)."), "title"); + return 0; + } + else + { + this->comment = strdup (comment); + return 1; + } +} + +int +fiasco_c_options_set_title (fiasco_c_options_t *options, const char *title) +/* + * Define `title' of FIASCO stream. + * + * Return value: + * 1 on success + * 0 otherwise + */ +{ + c_options_t *this = (c_options_t *) cast_c_options (options); + + if (!this) + { + return 0; + } + else if (!title) + { + set_error (_("Parameter `%s' not defined (NULL)."), "title"); + return 0; + } + else + { + this->title = strdup (title); + return 1; + } +} + +c_options_t * +cast_c_options (fiasco_c_options_t *options) +/* + * Cast generic pointer `options' to type c_options_t. + * Check whether `options' is a valid object of type c_options_t. + * + * Return value: + * pointer to options struct on success + * NULL otherwise + */ +{ + c_options_t *this = (c_options_t *) options->private; + if (this) + { + if (!streq (this->id, "COFIASCO")) + { + set_error (_("Parameter `options' doesn't match required type.")); + return NULL; + } + } + else + { + set_error (_("Parameter `%s' not defined (NULL)."), "options"); + } + + return this; +} + +/************************************************************************** +*************************************************************************** + DECODER +*************************************************************************** +**************************************************************************/ + +fiasco_d_options_t * +fiasco_d_options_new (void) +/* + * FIASCO options constructor. + * Allocate memory for the FIASCO coder options structure and + * fill in default values. + * + * Return value: + * pointer to the new option structure + */ +{ + d_options_t *options = calloc (1, sizeof (d_options_t)); + fiasco_d_options_t *public = calloc (1, sizeof (fiasco_d_options_t)); + + if (!options || !public) + { + set_error (_("Out of memory.")); + return NULL; + } + public->private = options; + public->delete = fiasco_d_options_delete; + public->set_smoothing = fiasco_d_options_set_smoothing; + public->set_magnification = fiasco_d_options_set_magnification; + public->set_4_2_0_format = fiasco_d_options_set_4_2_0_format; + + strcpy (options->id, "DOFIASCO"); + + /* + * Set default value of fiasco decoder options + */ + options->smoothing = 70; + options->magnification = 0; + options->image_format = FORMAT_4_4_4; + + return public; +} + +void +fiasco_d_options_delete (fiasco_d_options_t *options) +/* + * FIASCO options destructor. + * Free memory of FIASCO options struct. + * + * No return value. + * + * Side effects: + * structure 'options' is discarded. + */ +{ + d_options_t *this = cast_d_options (options); + + if (!this) + return; + + Free (this); + + return; +} + +int +fiasco_d_options_set_smoothing (fiasco_d_options_t *options, int smoothing) +/* + * Define `smoothing'-percentage along partitioning borders. + * + * Return value: + * 1 on success + * 0 otherwise + */ +{ + d_options_t *this = (d_options_t *) cast_d_options (options); + + if (!this) + { + return 0; + } + else if (smoothing < -1 || smoothing > 100) + { + set_error (_("Smoothing percentage must be in the range [-1, 100].")); + return 0; + } + else + { + this->smoothing = smoothing; + return 1; + } +} + +int +fiasco_d_options_set_magnification (fiasco_d_options_t *options, int level) +/* + * Set magnification-'level' of decoded image. + * 0: width x height of original image + * 1: (2 * width) x (2 * height) of original image + * -1: (width / 2 ) x (height / 2) of original image + * etc. + * + * Return value: + * 1 on success + * 0 otherwise + */ +{ + d_options_t *this = (d_options_t *) cast_d_options (options); + + if (!this) + { + return 0; + } + else + { + this->magnification = level; + return 1; + } +} + +int +fiasco_d_options_set_4_2_0_format (fiasco_d_options_t *options, int format) +/* + * Set image format to 4:2:0 or 4:4:4. + * + * Return value: + * 1 on success + * 0 otherwise + */ +{ + d_options_t *this = (d_options_t *) cast_d_options (options); + + if (!this) + { + return 0; + } + else + { + this->image_format = format ? FORMAT_4_2_0 : FORMAT_4_4_4; + return 1; + } +} + +d_options_t * +cast_d_options (fiasco_d_options_t *options) +/* + * Cast generic pointer `options' to type d_options_t. + * Check whether `options' is a valid object of type d_options_t. + * + * Return value: + * pointer to options struct on success + * NULL otherwise + */ +{ + d_options_t *this = (d_options_t *) options->private; + + if (this) + { + if (!streq (this->id, "DOFIASCO")) + { + set_error (_("Parameter `options' doesn't match required type.")); + return NULL; + } + } + else + { + set_error (_("Parameter `%s' not defined (NULL)."), "options"); + } + + return this; +} + + diff --git a/converter/other/fiasco/codec/options.h b/converter/other/fiasco/codec/options.h new file mode 100644 index 00000000..3af6be01 --- /dev/null +++ b/converter/other/fiasco/codec/options.h @@ -0,0 +1,80 @@ +/* + * options.h + * + * Written by: Ullrich Hafner + * + * This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec) + * Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de> + */ + +/* + * $Date: 2000/10/28 17:39:31 $ + * $Author: hafner $ + * $Revision: 5.4 $ + * $State: Exp $ + */ + +#ifndef _OPTIONS_H +#define _OPTIONS_H + +typedef struct c_options +{ + char id [9]; + char *basis_name; + unsigned lc_min_level; + unsigned lc_max_level; + unsigned p_min_level; + unsigned p_max_level; + unsigned images_level; + unsigned max_states; + unsigned chroma_max_states; + unsigned max_elements; + unsigned tiling_exponent; + fiasco_tiling_e tiling_method; + char *id_domain_pool; + char *id_d_domain_pool; + char *id_rpf_model; + char *id_d_rpf_model; + unsigned rpf_mantissa; + real_t rpf_range; + unsigned dc_rpf_mantissa; + fiasco_rpf_range_e dc_rpf_range; + unsigned d_rpf_mantissa; + fiasco_rpf_range_e d_rpf_range; + unsigned d_dc_rpf_mantissa; + fiasco_rpf_range_e d_dc_rpf_range; + real_t chroma_decrease; + bool_t prediction; + bool_t delta_domains; + bool_t normal_domains; + unsigned search_range; + unsigned fps; + char *pattern; + char *reference_filename; + bool_t half_pixel_prediction; + bool_t cross_B_search; + bool_t B_as_past_ref; + bool_t check_for_underflow; + bool_t check_for_overflow; + bool_t second_domain_block; + bool_t full_search; + fiasco_progress_e progress_meter; + char *title; + char *comment; + unsigned smoothing; +} c_options_t; + +typedef struct d_options +{ + char id [9]; + unsigned smoothing; + unsigned magnification; + format_e image_format; +} d_options_t; + +c_options_t * +cast_c_options (fiasco_c_options_t *options); +d_options_t * +cast_d_options (fiasco_d_options_t *options); + +#endif /* not _OPTIONS_H */ diff --git a/converter/other/fiasco/codec/prediction.c b/converter/other/fiasco/codec/prediction.c new file mode 100644 index 00000000..351ba9df --- /dev/null +++ b/converter/other/fiasco/codec/prediction.c @@ -0,0 +1,629 @@ +/* + * prediction.c: Range image prediction with MC or ND + * + * Written by: Ullrich Hafner + * Michael Unger + * + * This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec) + * Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de> + */ + +/* + * $Date: 2000/06/14 20:50:51 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#include "config.h" + +#if HAVE_STRING_H +# include <string.h> +#else /* not HAVE_STRING_H */ +# include <strings.h> +#endif /* not HAVE_STRING_H */ + +#include "types.h" +#include "macros.h" +#include "error.h" + +#include "cwfa.h" +#include "ip.h" +#include "control.h" +#include "misc.h" +#include "subdivide.h" +#include "bintree.h" +#include "domain-pool.h" +#include "approx.h" +#include "wfalib.h" +#include "mwfa.h" +#include "prediction.h" + +#include "decoder.h" + + +/***************************************************************************** + + local variables + +*****************************************************************************/ + +typedef struct state_data +{ + real_t final_distribution; + byte_t level_of_state; + byte_t domain_type; + + real_t *images_of_state; + real_t *inner_products; + real_t *ip_states_state [MAXLEVEL]; + + word_t tree [MAXLABELS]; + mv_t mv_tree [MAXLABELS]; + word_t y_state [MAXLABELS]; + byte_t y_column [MAXLABELS]; + byte_t prediction [MAXLABELS]; + + u_word_t x [MAXLABELS]; + u_word_t y [MAXLABELS]; + + real_t weight [MAXLABELS][MAXEDGES + 1]; + word_t int_weight [MAXLABELS][MAXEDGES + 1]; + word_t into [MAXLABELS][MAXEDGES + 1]; +} state_data_t; + +/***************************************************************************** + + prototypes + +*****************************************************************************/ + +static real_t +nd_prediction (real_t max_costs, real_t price, unsigned band, int y_state, + range_t *range, wfa_t *wfa, coding_t *c); +static real_t +mc_prediction (real_t max_costs, real_t price, unsigned band, int y_state, + range_t *range, wfa_t *wfa, coding_t *c); +static state_data_t * +store_state_data (unsigned from, unsigned to, unsigned max_level, + wfa_t *wfa, coding_t *c); +static void +restore_state_data (unsigned from, unsigned to, unsigned max_level, + state_data_t *data, wfa_t *wfa, coding_t *c); + +/***************************************************************************** + + public code + +*****************************************************************************/ + +real_t +predict_range (real_t max_costs, real_t price, range_t *range, wfa_t *wfa, + coding_t *c, unsigned band, int y_state, unsigned states, + const tree_t *tree_model, const tree_t *p_tree_model, + const void *domain_model, const void *d_domain_model, + const void *coeff_model, const void *d_coeff_model) +{ + unsigned state; /* counter */ + void *rec_domain_model; /* domain model after recursion */ + void *rec_d_domain_model; /* p domain model after recursion */ + void *rec_coeff_model; /* coeff model after recursion */ + void *rec_d_coeff_model; /* d coeff model after recursion */ + tree_t rec_tree_model; /* tree_model after '' */ + tree_t rec_p_tree_model; /* p_tree_model after '' */ + unsigned rec_states; /* wfa->states after '' */ + real_t *rec_pixels; /* c->pixels after '' */ + state_data_t *rec_state_data; /* state_data struct after '' */ + real_t costs; /* current approximation costs */ + unsigned level; /* counter */ + state_data_t *sd; /* pointer to state_data field */ + + /* + * Store WFA data from state 'lc_states' to 'wfa->states' - 1 and + * current state of probability models. + */ + rec_domain_model = c->domain_pool->model; + rec_d_domain_model = c->d_domain_pool->model; + rec_coeff_model = c->coeff->model; + rec_d_coeff_model = c->d_coeff->model; + rec_tree_model = c->tree; + rec_p_tree_model = c->p_tree; + rec_states = wfa->states; + rec_pixels = c->pixels; + rec_state_data = store_state_data (states, rec_states - 1, + c->options.lc_max_level, wfa, c); + + /* + * Restore probability models to the state before the recursive subdivision + * has been started. + */ + wfa->states = states; + c->tree = *tree_model; + c->p_tree = *p_tree_model; + c->domain_pool->model = c->domain_pool->model_duplicate (domain_model); + c->d_domain_pool->model = c->d_domain_pool->model_duplicate (d_domain_model); + c->coeff->model = c->coeff->model_duplicate (c->coeff, coeff_model); + c->d_coeff->model = c->d_coeff->model_duplicate (c->d_coeff, + d_coeff_model); + + if (c->mt->frame_type == I_FRAME) + costs = nd_prediction (max_costs, price, band, y_state, range, wfa, c); + else + costs = mc_prediction (max_costs, price, band, y_state, range, wfa, c); + + c->pixels = rec_pixels; + + if (costs < MAXCOSTS) + { + /* + * Free the memory used by the state_data struct + */ + for (state = states; state < rec_states; state++) + { + sd = &rec_state_data [state - states]; + for (level = c->options.images_level + 1; + level <= c->options.lc_max_level; level++) + if (sd->ip_states_state [level] != NULL) + Free (sd->ip_states_state [level]); + if (sd->images_of_state != NULL) + Free (sd->images_of_state); + if (sd->inner_products != NULL) + Free (sd->inner_products); + } + if (states < rec_states) + Free (rec_state_data); + c->domain_pool->model_free (rec_domain_model); + c->d_domain_pool->model_free (rec_d_domain_model); + c->coeff->model_free (rec_coeff_model); + c->d_coeff->model_free (rec_d_coeff_model); + + costs = (range->tree_bits + range->matrix_bits + range->weights_bits + + range->mv_tree_bits + range->mv_coord_bits + + range->nd_tree_bits + range->nd_weights_bits) * price + + range->err; + } + else + { + /* + * Restore WFA to state before function was called + */ + c->domain_pool->model_free (c->domain_pool->model); + c->d_domain_pool->model_free (c->d_domain_pool->model); + c->coeff->model_free (c->coeff->model); + c->d_coeff->model_free (c->d_coeff->model); + + c->domain_pool->model = rec_domain_model; + c->d_domain_pool->model = rec_d_domain_model; + c->coeff->model = rec_coeff_model; + c->d_coeff->model = rec_d_coeff_model; + c->tree = rec_tree_model; + c->p_tree = rec_p_tree_model; + + range->prediction = NO; + + if (wfa->states != states) + remove_states (states, wfa); + restore_state_data (states, rec_states - 1, c->options.lc_max_level, + rec_state_data, wfa, c); + costs = MAXCOSTS; + } + + return costs; +} + +void +clear_norms_table (unsigned level, const wfa_info_t *wi, motion_t *mt) +/* + * Clear norms arrays. + * + * No return value. + */ +{ + unsigned range_size = wi->half_pixel + ? square (wi->search_range) + : square (2 * wi->search_range); + + if (level > wi->p_min_level) + { + memset (mt->mc_forward_norms [level], 0, range_size * sizeof(real_t)); + memset (mt->mc_backward_norms [level], 0, range_size * sizeof(real_t)); + } +} + +void +update_norms_table (unsigned level, const wfa_info_t *wi, motion_t *mt) +/* + * Norms table of levels larger than the bottom level are computed + * by summing up previously calculated displacement costs of lower levels. + * + * No return value. + */ +{ + unsigned range_size = wi->half_pixel + ? square (wi->search_range) + : square (2 * wi->search_range); + + if (level > wi->p_min_level) + { + unsigned index; /* index of motion vector */ + + for (index = 0; index < range_size; index++) + mt->mc_forward_norms [level][index] + += mt->mc_forward_norms [level - 1][index]; + if (mt->frame_type == B_FRAME) + for (index = 0; index < range_size; index++) + mt->mc_backward_norms [level][index] + += mt->mc_backward_norms [level - 1][index]; + } +} + +/***************************************************************************** + + private code + +*****************************************************************************/ + +static real_t +mc_prediction (real_t max_costs, real_t price, unsigned band, int y_state, + range_t *range, wfa_t *wfa, coding_t *c) +{ + real_t costs; /* current approximation costs */ + range_t prange = *range; + unsigned width = width_of_level (range->level); + unsigned height = height_of_level (range->level); + word_t *mcpe = Calloc (width * height, sizeof (word_t)); + + /* + * If we are at the bottom level of the mc tree: + * Fill in the norms table + */ + if (prange.level == wfa->wfainfo->p_min_level) + fill_norms_table (prange.x, prange.y, prange.level, wfa->wfainfo, c->mt); + /* + * Predict 'range' with motion compensation according to frame type. + * MCPE is returned in 'c->mcpe' + */ + if (c->mt->frame_type == P_FRAME) + find_P_frame_mc (mcpe, price, &prange, wfa->wfainfo, c->mt); + else + find_B_frame_mc (mcpe, price, &prange, wfa->wfainfo, c->mt); + + costs = (prange.mv_tree_bits + prange.mv_coord_bits) * price; + + if (costs < max_costs) /* motion vector not too expensive */ + { + unsigned last_state; /* last WFA state before recursion */ + real_t *ipi [MAXSTATES]; /* inner products pointers */ + unsigned state; + real_t mvt, mvc; + + c->pixels = Calloc (width * height, sizeof (real_t)); + cut_to_bintree (c->pixels, mcpe, width, height, 0, 0, width, height); + + /* + * Approximate MCPE recursively. + */ + last_state = wfa->states - 1; + for (state = 0; state <= last_state; state++) + if (need_image (state, wfa)) + { + ipi [state] = c->ip_images_state[state]; + c->ip_images_state[state] + = Calloc (size_of_tree (c->products_level), sizeof (real_t)); + } + + mvc = prange.mv_coord_bits; + mvt = prange.mv_tree_bits; + + prange.image = 0; + prange.address = 0; + prange.tree_bits = 0; + prange.matrix_bits = 0; + prange.weights_bits = 0; + prange.mv_coord_bits = 0; + prange.mv_tree_bits = 0; + prange.nd_weights_bits = 0; + prange.nd_tree_bits = 0; + + compute_ip_images_state (prange.image, prange.address, prange.level, + 1, 0, wfa, c); + costs += subdivide (max_costs - costs, band, y_state, &prange, + wfa, c, NO, YES); + + if (costs < max_costs) /* use motion compensation */ + { + unsigned img, adr; /* temp. values */ + + img = range->image; + adr = range->address; + *range = prange; + range->image = img; + range->address = adr; + range->mv_coord_bits = mvc; + range->mv_tree_bits = mvt; + range->prediction = YES; + + for (state = last_state + 1; state < wfa->states; state++) + if (need_image (state, wfa)) + memset (c->ip_images_state [state], 0, + size_of_tree (c->products_level) * sizeof (real_t)); + + costs = (range->tree_bits + range->matrix_bits + range->weights_bits + + range->mv_tree_bits + range->mv_coord_bits + + range->nd_tree_bits + range->nd_weights_bits) * price + + range->err; + } + else + costs = MAXCOSTS; + + for (state = 0; state <= last_state; state++) + if (need_image (state, wfa)) + { + Free (c->ip_images_state[state]); + c->ip_images_state[state] = ipi [state]; + } + Free (c->pixels); + } + else + costs = MAXCOSTS; + + Free (mcpe); + + return costs; +} + +static real_t +nd_prediction (real_t max_costs, real_t price, unsigned band, int y_state, + range_t *range, wfa_t *wfa, coding_t *c) +{ + real_t costs; /* current approximation costs */ + range_t lrange = *range; + + /* + * Predict 'range' with DC component approximation + */ + { + real_t x = get_ip_image_state (range->image, range->address, + range->level, 0, c); + real_t y = get_ip_state_state (0, 0, range->level, c); + real_t w = btor (rtob (x / y, c->coeff->dc_rpf), c->coeff->dc_rpf); + word_t s [2] = {0, -1}; + + lrange.into [0] = 0; + lrange.into [1] = NO_EDGE; + lrange.weight [0] = w; + lrange.mv_coord_bits = 0; + lrange.mv_tree_bits = 0; + lrange.nd_tree_bits = tree_bits (LEAF, lrange.level, &c->p_tree); + lrange.nd_weights_bits = 0; + lrange.tree_bits = 0; + lrange.matrix_bits = 0; + lrange.weights_bits = c->coeff->bits (&w, s, range->level, c->coeff); + } + costs = price * (lrange.weights_bits + lrange.nd_tree_bits); + + /* + * Recursive aproximation of difference image + */ + if (costs < max_costs) + { + unsigned state; + range_t rrange; /* range: recursive subdivision */ + unsigned last_state; /* last WFA state before recursion */ + real_t *ipi [MAXSTATES]; /* inner products pointers */ + unsigned width = width_of_level (range->level); + unsigned height = height_of_level (range->level); + real_t *pixels; + + /* + * Generate difference image original - approximation + */ + { + unsigned n; + real_t *src, *dst; /* pointers to image data */ + real_t w = - lrange.weight [0] * c->images_of_state [0][0]; + + src = c->pixels + range->address * size_of_level (range->level); + dst = c->pixels = pixels = Calloc (width * height, sizeof (real_t)); + + for (n = width * height; n; n--) + *dst++ = *src++ + w; + } + + /* + * Approximate difference recursively. + */ + rrange = *range; + rrange.tree_bits = 0; + rrange.matrix_bits = 0; + rrange.weights_bits = 0; + rrange.mv_coord_bits = 0; + rrange.mv_tree_bits = 0; + rrange.nd_tree_bits = 0; + rrange.nd_weights_bits = 0; + rrange.image = 0; + rrange.address = 0; + + last_state = wfa->states - 1; + for (state = 0; state <= last_state; state++) + if (need_image (state, wfa)) + { + ipi [state] = c->ip_images_state[state]; + c->ip_images_state[state] + = Calloc (size_of_tree (c->products_level), sizeof (real_t)); + } + + compute_ip_images_state (rrange.image, rrange.address, rrange.level, + 1, 0, wfa, c); + + costs += subdivide (max_costs - costs, band, y_state, &rrange, wfa, c, + NO, YES); + + Free (pixels); + + if (costs < max_costs && ischild (rrange.tree)) /* use prediction */ + { + unsigned img, adr; + unsigned edge; + + img = range->image; + adr = range->address; + *range = rrange; + range->image = img; + range->address = adr; + range->nd_tree_bits += lrange.nd_tree_bits; + range->nd_weights_bits += lrange.weights_bits; + + for (edge = 0; isedge (lrange.into [edge]); edge++) + { + range->into [edge] = lrange.into [edge]; + range->weight [edge] = lrange.weight [edge]; + } + range->into [edge] = NO_EDGE; + range->prediction = edge; + + for (state = last_state + 1; state < wfa->states; state++) + if (need_image (state, wfa)) + memset (c->ip_images_state [state], 0, + size_of_tree (c->products_level) * sizeof (real_t)); + } + else + costs = MAXCOSTS; + + for (state = 0; state <= last_state; state++) + if (need_image (state, wfa)) + { + Free (c->ip_images_state [state]); + c->ip_images_state [state] = ipi [state]; + } + } + else + costs = MAXCOSTS; + + return costs; +} + +static state_data_t * +store_state_data (unsigned from, unsigned to, unsigned max_level, + wfa_t *wfa, coding_t *c) +/* + * Save and remove all states starting from state 'from'. + * + * Return value: + * pointer to array of state_data structs + */ +{ + state_data_t *data; /* array of savestates */ + state_data_t *sd; /* pointer to current savestates */ + unsigned state, label, level; + + if (to < from) + return NULL; /* nothing to do */ + + data = Calloc (to - from + 1, sizeof (state_data_t)); + + for (state = from; state <= to; state++) + { + sd = &data [state - from]; + + sd->final_distribution = wfa->final_distribution [state]; + sd->level_of_state = wfa->level_of_state [state]; + sd->domain_type = wfa->domain_type [state]; + sd->images_of_state = c->images_of_state [state]; + sd->inner_products = c->ip_images_state [state]; + + wfa->domain_type [state] = 0; + c->images_of_state [state] = NULL; + c->ip_images_state [state] = NULL; + + for (label = 0; label < MAXLABELS; label++) + { + sd->tree [label] = wfa->tree [state][label]; + sd->y_state [label] = wfa->y_state [state][label]; + sd->y_column [label] = wfa->y_column [state][label]; + sd->mv_tree [label] = wfa->mv_tree [state][label]; + sd->x [label] = wfa->x [state][label]; + sd->y [label] = wfa->y [state][label]; + sd->prediction [label] = wfa->prediction [state][label]; + + memcpy (sd->weight [label], wfa->weight [state][label], + sizeof (real_t) * (MAXEDGES + 1)); + memcpy (sd->int_weight [label], wfa->int_weight [state][label], + sizeof (word_t) * (MAXEDGES + 1)); + memcpy (sd->into [label], wfa->into [state][label], + sizeof (word_t) * (MAXEDGES + 1)); + + wfa->into [state][label][0] = NO_EDGE; + wfa->tree [state][label] = RANGE; + wfa->y_state [state][label] = RANGE; + } + for (level = c->options.images_level + 1; level <= max_level; + level++) + { + sd->ip_states_state [level] = c->ip_states_state [state][level]; + c->ip_states_state [state][level] = NULL; + } + } + + return data; +} + +static void +restore_state_data (unsigned from, unsigned to, unsigned max_level, + state_data_t *data, wfa_t *wfa, coding_t *c) +/* + * Restore all state data starting from state 'from'. + * + * No return value. + */ +{ + state_data_t *sd; /* pointer to state_data item */ + unsigned state, label, level; + + if (to < from) + return; /* nothing to do */ + + for (state = from; state <= to; state++) + { + sd = &data [state - from]; + + wfa->final_distribution [state] = sd->final_distribution; + wfa->level_of_state [state] = sd->level_of_state; + wfa->domain_type [state] = sd->domain_type; + + if (c->images_of_state [state] != NULL) + Free (c->images_of_state [state]); + c->images_of_state [state] = sd->images_of_state; + if (c->ip_images_state [state] != NULL) + Free (c->ip_images_state [state]); + c->ip_images_state [state] = sd->inner_products; + + for (label = 0; label < MAXLABELS; label++) + { + wfa->tree [state][label] = sd->tree [label]; + wfa->y_state [state][label] = sd->y_state [label]; + wfa->y_column [state][label] = sd->y_column [label]; + wfa->mv_tree [state][label] = sd->mv_tree [label]; + wfa->x [state][label] = sd->x [label]; + wfa->y [state][label] = sd->y [label]; + wfa->prediction [state][label] = sd->prediction [label]; + + memcpy (wfa->weight [state][label], sd->weight [label], + sizeof(real_t) * (MAXEDGES + 1)); + memcpy (wfa->int_weight [state][label], sd->int_weight [label], + sizeof(word_t) * (MAXEDGES + 1)); + memcpy (wfa->into [state][label], sd->into [label], + sizeof(word_t) * (MAXEDGES + 1)); + } + for (level = c->options.images_level + 1; level <= max_level; + level++) + { + if (c->ip_states_state [state][level] != NULL) + Free (c->ip_states_state [state][level]); + c->ip_states_state [state][level] = sd->ip_states_state [level]; + } + } + + Free (data); + wfa->states = to + 1; +} diff --git a/converter/other/fiasco/codec/prediction.h b/converter/other/fiasco/codec/prediction.h new file mode 100644 index 00000000..1068501a --- /dev/null +++ b/converter/other/fiasco/codec/prediction.h @@ -0,0 +1,36 @@ +/* + * prediction.h + * + * Written by: Ullrich Hafner + * Michael Unger + * + * This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec) + * Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de> + */ + +/* + * $Date: 2000/06/14 20:50:51 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#ifndef _PREDICTION_H +#define _PREDICTION_H + +#include "types.h" +#include "cwfa.h" + +real_t +predict_range (real_t max_costs, real_t price, range_t *range, wfa_t *wfa, + coding_t *c, unsigned band, int y_state, unsigned states, + const tree_t *tree_model, const tree_t *p_tree_model, + const void *domain_model, const void *d_domain_model, + const void *coeff_model, const void *d_coeff_model); +void +update_norms_table (unsigned level, const wfa_info_t *wi, motion_t *mt); +void +clear_norms_table (unsigned level, const wfa_info_t *wi, motion_t *mt); + +#endif /* not _PREDICTION_H */ + diff --git a/converter/other/fiasco/codec/subdivide.c b/converter/other/fiasco/codec/subdivide.c new file mode 100644 index 00000000..b7982716 --- /dev/null +++ b/converter/other/fiasco/codec/subdivide.c @@ -0,0 +1,650 @@ +/* + * subdivide.c: Recursive subdivision of range images + * + * Written by: Ullrich Hafner + * + * This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec) + * Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de> + */ + +/* + * $Date: 2000/07/15 17:59:31 $ + * $Author: hafner $ + * $Revision: 5.4 $ + * $State: Exp $ + */ + +#include "config.h" + +#if HAVE_STRING_H +# include <string.h> +#else /* not HAVE_STRING_H */ +# include <strings.h> +#endif /* not HAVE_STRING_H */ + +#include "types.h" +#include "macros.h" +#include "error.h" + +#include "image.h" +#include "cwfa.h" +#include "approx.h" +#include "ip.h" +#include "bintree.h" +#include "control.h" +#include "prediction.h" +#include "domain-pool.h" +#include "mwfa.h" +#include "misc.h" +#include "subdivide.h" +#include "list.h" +#include "coeff.h" +#include "wfalib.h" + +/***************************************************************************** + + prototypes + +*****************************************************************************/ + +static void +init_new_state (bool_t auxiliary_state, bool_t delta, range_t *range, + const range_t *child, const int *y_state, + wfa_t *wfa, coding_t *c); +static void +init_range (range_t *range, const image_t *image, unsigned band, + const wfa_t *wfa, coding_t *c); + +/***************************************************************************** + + public code + +*****************************************************************************/ + +real_t +subdivide (real_t max_costs, unsigned band, int y_state, range_t *range, + wfa_t *wfa, coding_t *c, bool_t prediction, bool_t delta) +/* + * Subdivide the current 'range' recursively and decide whether + * a linear combination, a recursive subdivision, or a prediction is + * the best choice of approximation. + * 'band' is the current color band, 'y_state' is the corresponding + * state of the Y color component (color image compression only). + * If 'prediction' is TRUE then also test motion compensation or + * nondeterministic approximation. + * If 'delta' is TRUE then current range is already predicted. + * + * Return value: + * costs of the best approximation or MAXCOSTS if costs exceed 'max_costs' + * + * Side effects: + * 'range' factors and costs of linear combination are modified + * 'wfa' new transitions and prediction coefficients are added + * 'c' pixels and inner products are updated + */ +{ + real_t subdivide_costs; /* Costs arising from approx. the current + range with two childs */ + real_t lincomb_costs; /* Costs arising from approx. the current + range with a linear combination */ + int new_y_state [MAXLABELS]; /* Corresponding state of Y */ + real_t price; /* Approximation costs multiplier */ + bool_t try_mc; /* YES: try MC prediction */ + bool_t try_nd; /* YES: try ND prediction */ + unsigned states; /* Number of states before the + recursive subdivision starts */ + void *domain_model; /* copy of domain pool model */ + void *d_domain_model; /* copy of delta domain pool model */ + void *lc_domain_model; /* copy of domain pool model */ + void *lc_d_domain_model; /* copy of delta domain pool model */ + void *coeff_model; /* copy of coefficients model */ + void *d_coeff_model; /* copy of delta coefficients model */ + void *lc_coeff_model; /* copy of coefficients model */ + void *lc_d_coeff_model; /* copy of delta coefficients model */ + tree_t tree_model; /* copy of tree model */ + tree_t p_tree_model; /* copy of pred. tree model */ + range_t lrange; /* range of lin. comb. approx. */ + range_t rrange; /* range of recursive approx. */ + range_t child [MAXLABELS]; /* new childs of the current range */ + static unsigned percent = 0; /* status of progress meter */ + + if (wfa->wfainfo->level == range->level) + percent = 0; + + range->into [0] = NO_EDGE; /* default approximation: empty */ + range->tree = RANGE; + + if (range->level < 3) /* Don't process small ranges */ + return MAXCOSTS; + + /* + * If image permutation (tiling) is performed and the tiling level + * is reached then get coordinates of the new block. + */ + if (c->tiling->exponent + && range->level == wfa->wfainfo->level - c->tiling->exponent) + { + unsigned width, height; /* size of range (dummies)*/ + + if (c->tiling->vorder [range->global_address] < 0) + return 0; /* nothing to do */ + else + locate_subimage (wfa->wfainfo->level, range->level, + c->tiling->vorder [range->global_address], + &range->x, &range->y, &width, &height); + } + + if (range->x >= c->mt->original->width || + range->y >= c->mt->original->height) + return 0; /* range is not visible */ + + /* + * Check whether prediction is allowed or not + * mc == motion compensation, nd == nondeterminism + */ + try_mc = (prediction && c->mt->frame_type != I_FRAME + && range->level >= wfa->wfainfo->p_min_level + && range->level <= wfa->wfainfo->p_max_level + && (range->x + width_of_level (range->level) + <= c->mt->original->width) + && (range->y + height_of_level (range->level) + <= c->mt->original->height)); + + try_nd = (prediction && c->mt->frame_type == I_FRAME + && range->level >= wfa->wfainfo->p_min_level + && range->level <= wfa->wfainfo->p_max_level); + + if (try_mc) + clear_norms_table (range->level, wfa->wfainfo, c->mt); + + + /* + * Check if current range must be initialized. I.e. range pixels must + * be copied from entire image to bintree pixel buffer. Moreover, + * all inner products tables must be initialized. + */ + if (range->level == c->options.lc_max_level) + init_range (range, c->mt->original, band, wfa, c); + + price = c->price; + if (band != Y) + price *= c->options.chroma_decrease; /* less quality for chroma bands */ + + /* + * Compute childs of corresponding state in Y band + */ + if (band != Y) /* Cb and Cr bands only */ + { + unsigned label; + + for (label = 0; label < MAXLABELS; label++) + if (ischild (y_state)) + new_y_state [label] = wfa->tree [y_state][label]; + else + new_y_state [label] = RANGE; + } + else + new_y_state [0] = new_y_state [1] = RANGE; + + /* + * Store contents of all models that may get modified during recursion + */ + domain_model = c->domain_pool->model_duplicate (c->domain_pool->model); + d_domain_model = c->d_domain_pool->model_duplicate (c->d_domain_pool->model); + coeff_model = c->coeff->model_duplicate (c->coeff, c->coeff->model); + d_coeff_model = c->d_coeff->model_duplicate (c->d_coeff, c->d_coeff->model); + tree_model = c->tree; + p_tree_model = c->p_tree; + states = wfa->states; + + /* + * First alternative of range approximation: + * Compute costs of linear combination. + */ + if (range->level <= c->options.lc_max_level) /* range is small enough */ + { + lrange = *range; + lrange.tree = RANGE; + lrange.tree_bits = tree_bits (LEAF, lrange.level, &c->tree); + lrange.matrix_bits = 0; + lrange.weights_bits = 0; + lrange.mv_tree_bits = try_mc ? 1 : 0; /* mc allowed but not used */ + lrange.mv_coord_bits = 0; + lrange.nd_tree_bits = 0; + lrange.nd_weights_bits = 0; + lrange.prediction = NO; + + lincomb_costs + = approximate_range (max_costs, price, c->options.max_elements, + y_state, &lrange, + (delta ? c->d_domain_pool : c->domain_pool), + (delta ? c->d_coeff : c->coeff), wfa, c); + } + else + lincomb_costs = MAXCOSTS; + + /* + * Store contents of models that have been modified + * by approximate_range () above ... + */ + lc_domain_model = c->domain_pool->model; + lc_d_domain_model = c->d_domain_pool->model; + lc_coeff_model = c->coeff->model; + lc_d_coeff_model = c->d_coeff->model; + /* + * ... and restore them with values before lc + */ + c->domain_pool->model = c->domain_pool->model_duplicate (domain_model); + c->d_domain_pool->model = c->d_domain_pool->model_duplicate (d_domain_model); + c->coeff->model = c->coeff->model_duplicate (c->coeff, coeff_model); + c->d_coeff->model = c->d_coeff->model_duplicate (c->d_coeff, + d_coeff_model); + + /* + * Second alternative of range approximation: + * Compute costs of recursive subdivision. + */ + if (range->level > c->options.lc_min_level) /* range is large enough */ + { + unsigned label; + + memset (&child [0], 0, 2 * sizeof (range_t)); /* initialize childs */ + + /* + * Initialize a new range for recursive approximation + */ + rrange = *range; + rrange.tree_bits = tree_bits (CHILD, rrange.level, &c->tree); + rrange.matrix_bits = 0; + rrange.weights_bits = 0; + rrange.err = 0; + rrange.mv_tree_bits = try_mc ? 1 : 0; /* mc allowed but not used */ + rrange.mv_coord_bits = 0; + rrange.nd_tree_bits = try_nd ? + tree_bits (CHILD, lrange.level, &c->p_tree): 0; + rrange.nd_weights_bits = 0; + rrange.prediction = NO; + + /* + * Initialize the cost function and subdivide the current range. + * Every child is approximated by a recursive call of subdivide() + */ + subdivide_costs = (rrange.tree_bits + rrange.weights_bits + + rrange.matrix_bits + rrange.mv_tree_bits + + rrange.mv_coord_bits + rrange.nd_tree_bits + + rrange.nd_weights_bits) * price; + + for (label = 0; label < MAXLABELS; label++) + { + real_t remaining_costs; /* upper limit for next recursion */ + + child[label].image = rrange.image * MAXLABELS + label + 1; + child[label].address = rrange.address * MAXLABELS + label; + child[label].global_address = rrange.global_address * MAXLABELS + + label; + child[label].level = rrange.level - 1; + child[label].x = rrange.level & 1 + ? rrange.x + : (rrange.x + + label * width_of_level (rrange.level - 1)); + child[label].y = rrange.level & 1 + ? (rrange.y + + label * height_of_level (rrange.level - 1)) + : rrange.y; + + /* + * If neccessary compute the inner products of the new states + * (generated during the recursive approximation of child [0]) + */ + if (label && rrange.level <= c->options.lc_max_level) + compute_ip_images_state (child[label].image, child[label].address, + child[label].level, 1, states, wfa, c); + /* + * Call subdivide() for both childs. + * Abort the recursion if 'subdivide_costs' exceed 'lincomb_costs' + * or 'max_costs'. + */ + remaining_costs = min (lincomb_costs, max_costs) - subdivide_costs; + + if (remaining_costs > 0) /* still a way for improvement */ + { + subdivide_costs += subdivide (remaining_costs, band, + new_y_state [label], &child [label], + wfa, c, prediction, delta); + } + else if (try_mc && child[label].level >= wfa->wfainfo->p_min_level) + { + fill_norms_table (child[label].x, child[label].y, + child[label].level, wfa->wfainfo, c->mt); + } + + if (try_mc) + update_norms_table (rrange.level, wfa->wfainfo, c->mt); + + /* + * Update of progress meter + */ + if (c->options.progress_meter != FIASCO_PROGRESS_NONE) + { + if (c->options.progress_meter == FIASCO_PROGRESS_PERCENT) + { + unsigned new_percent; /* new status of progress meter */ + + new_percent = (child[label].global_address + 1) * 100.0 + / (1 << (wfa->wfainfo->level - child[label].level)); + if (new_percent > percent) + { + percent = new_percent; + info ("%3d%% \r", percent); + } + } + else if (c->options.progress_meter == FIASCO_PROGRESS_BAR) + { + unsigned new_percent; /* new status of progress meter */ + + new_percent = (child[label].global_address + 1) * 50.0 + / (1 << (wfa->wfainfo->level + - child[label].level)); + for (; new_percent > percent; percent++) + { + info ("#"); + } + } + } + + /* + * If costs of subdivision exceed costs of linear combination + * then abort recursion. + */ + if (subdivide_costs >= min (lincomb_costs, max_costs)) + { + subdivide_costs = MAXCOSTS; + break; + } + rrange.err += child [label].err; + rrange.tree_bits += child [label].tree_bits; + rrange.matrix_bits += child [label].matrix_bits; + rrange.weights_bits += child [label].weights_bits; + rrange.mv_tree_bits += child [label].mv_tree_bits; + rrange.mv_coord_bits += child [label].mv_coord_bits; + rrange.nd_weights_bits += child [label].nd_weights_bits; + rrange.nd_tree_bits += child [label].nd_tree_bits; + + tree_update (ischild (child [label].tree) ? CHILD : LEAF, + child [label].level, &c->tree); + tree_update (child [label].prediction ? LEAF : CHILD, + child [label].level, &c->p_tree); + } + } + else + subdivide_costs = MAXCOSTS; + + /* + * Third alternative of range approximation: + * Predict range via motion compensation or nondeterminism and + * approximate delta image. + */ + if (try_mc || try_nd) /* try prediction */ + { + real_t prediction_costs; /* Costs arising from approx. the current + range with prediction */ + + prediction_costs + = predict_range (min (min (lincomb_costs, subdivide_costs), + max_costs), + price, range, wfa, c, band, y_state, states, + &tree_model, &p_tree_model, domain_model, + d_domain_model, coeff_model, d_coeff_model); + if (prediction_costs < MAXCOSTS) /* prediction has smallest costs */ + { + c->domain_pool->model_free (domain_model); + c->d_domain_pool->model_free (d_domain_model); + c->domain_pool->model_free (lc_domain_model); + c->d_domain_pool->model_free (lc_d_domain_model); + c->coeff->model_free (coeff_model); + c->d_coeff->model_free (d_coeff_model); + c->coeff->model_free (lc_coeff_model); + c->d_coeff->model_free (lc_d_coeff_model); + + return prediction_costs; + } + } + + if (lincomb_costs >= MAXCOSTS && subdivide_costs >= MAXCOSTS) + { + /* + * Return MAXCOSTS if neither a linear combination nor a recursive + * subdivision yield costs less than 'max_costs' + */ + c->domain_pool->model_free (c->domain_pool->model); + c->d_domain_pool->model_free (c->d_domain_pool->model); + c->domain_pool->model_free (lc_domain_model); + c->d_domain_pool->model_free (lc_d_domain_model); + + c->coeff->model_free (c->coeff->model); + c->d_coeff->model_free (c->d_coeff->model); + c->coeff->model_free (lc_coeff_model); + c->d_coeff->model_free (lc_d_coeff_model); + + c->domain_pool->model = domain_model; + c->d_domain_pool->model = d_domain_model; + c->coeff->model = coeff_model; + c->d_coeff->model = d_coeff_model; + c->tree = tree_model; + c->p_tree = p_tree_model; + + if (wfa->states != states) + remove_states (states, wfa); + + return MAXCOSTS; + } + else if (lincomb_costs < subdivide_costs) + { + /* + * Use the linear combination: The factors of the linear combination + * are stored already in 'range', so revert the probability models + * only. + */ + c->domain_pool->model_free (c->domain_pool->model); + c->d_domain_pool->model_free (c->d_domain_pool->model); + c->domain_pool->model_free (domain_model); + c->d_domain_pool->model_free (d_domain_model); + + c->coeff->model_free (c->coeff->model); + c->d_coeff->model_free (c->d_coeff->model); + c->coeff->model_free (coeff_model); + c->d_coeff->model_free (d_coeff_model); + + c->domain_pool->model = lc_domain_model; + c->d_domain_pool->model = lc_d_domain_model; + c->coeff->model = lc_coeff_model; + c->d_coeff->model = lc_d_coeff_model; + c->tree = tree_model; + c->p_tree = p_tree_model; + + *range = lrange; + + if (wfa->states != states) + remove_states (states, wfa); + + return lincomb_costs; + } + else + { + /* + * Use the recursive subdivision: Generate a new state with transitions + * given in child[]. + * Don't use state in linear combinations in any of the following cases: + * - if color component is Cb or Cr + * - if level of state > tiling level + * - if state is (partially) outside image geometry + */ + if (band > Y + || (c->tiling->exponent + && rrange.level > wfa->wfainfo->level - c->tiling->exponent) + || (range->x + width_of_level (range->level) + > c->mt->original->width) + || (range->y + height_of_level (range->level) + > c->mt->original->height)) + init_new_state (YES, delta, &rrange, child, new_y_state, wfa, c); + else + init_new_state (NO, delta, &rrange, child, new_y_state, wfa, c); + + *range = rrange; + + c->domain_pool->model_free (domain_model); + c->d_domain_pool->model_free (d_domain_model); + c->domain_pool->model_free (lc_domain_model); + c->d_domain_pool->model_free (lc_d_domain_model); + c->coeff->model_free (coeff_model); + c->d_coeff->model_free (d_coeff_model); + c->coeff->model_free (lc_coeff_model); + c->d_coeff->model_free (lc_d_coeff_model); + + return subdivide_costs; + } +} + +void +cut_to_bintree (real_t *dst, const word_t *src, + unsigned src_width, unsigned src_height, + unsigned x0, unsigned y0, unsigned width, unsigned height) +/* + * Cut region ('x0', 'y0', 'width', 'height') of the pixel array 'src'. + * Size of image is given by 'src_width' x 'src_height'. + * 'dst' pixels are converted to bintree order and real format. + * + * No return value. + * + * Side effects: + * 'dst []' is filled with corresponding region. + */ +{ + const unsigned mask01 = 0x555555; /* binary ...010101010101 */ + const unsigned mask10 = 0xaaaaaa; /* binary ...101010101010 */ + const unsigned mask01plus1 = mask01 + 1; /* binary ...010101010110 */ + const unsigned mask10plus1 = mask10 + 1; /* binary ...101010101011 */ + unsigned x, y; /* pixel coordinates */ + unsigned xmask, ymask; /* address conversion */ + + if (width != height && width != (height >> 1)) + error ("Bintree cutting requires special type of images."); + + ymask = 0; + for (y = y0; y < y0 + height; y++, ymask = (ymask + mask10plus1) & mask01) + { + xmask = 0; + for (x = x0; x < x0 + width; x++, xmask = (xmask + mask01plus1) & mask10) + { + if (y >= src_height || x >= src_width) + dst [xmask | ymask] = 0; + else + dst [xmask | ymask] = src [y * src_width + x] / 16; + } + } +} + +/***************************************************************************** + + private code + +*****************************************************************************/ + +static void +init_new_state (bool_t auxiliary_state, bool_t delta, range_t *range, + const range_t *child, const int *y_state, + wfa_t *wfa, coding_t *c) +/* + * Initializes a new state with all parameters needed for the encoding step. + * If flag 'auxiliary_state' is set then don't insert state into domain pools. + * If flag 'delta' is set then state represents a delta image (prediction via + * nondeterminism or motion compensation). + * 'range' the current range image, + * 'child []' the left and right childs of 'range'. + * + * No return value. + * + * Side effects: + * New state is appended to 'wfa' (and also its inner products and images + * are computed and stored in 'c') + */ +{ + unsigned label; + bool_t state_is_domain = NO; + + if (!auxiliary_state) + { + if (!delta || c->options.delta_domains) + state_is_domain = c->domain_pool->append (wfa->states, range->level, + wfa, c->domain_pool->model); + if (delta || c->options.normal_domains) + state_is_domain = c->d_domain_pool->append (wfa->states, range->level, + wfa, + c->d_domain_pool->model) + || state_is_domain; + } + else + state_is_domain = NO; + + range->into [0] = NO_EDGE; + range->tree = wfa->states; + + for (label = 0; label < MAXLABELS; label++) + { + wfa->tree [wfa->states][label] = child [label].tree; + wfa->y_state [wfa->states][label] = y_state [label]; + wfa->mv_tree [wfa->states][label] = child [label].mv; + wfa->x [wfa->states][label] = child [label].x; + wfa->y [wfa->states][label] = child [label].y; + wfa->prediction [wfa->states][label] = child [label].prediction; + + append_transitions (wfa->states, label, child [label].weight, + child [label].into, wfa); + } + wfa->delta_state [wfa->states] = delta; + + if (range->err < 0) + warning ("Negative image norm: %f, %f", child [0].err, child [1].err); + +/* state_is_domain = YES; */ + + append_state (!state_is_domain, + compute_final_distribution (wfa->states, wfa), + range->level, wfa, c); +} + +static void +init_range (range_t *range, const image_t *image, unsigned band, + const wfa_t *wfa, coding_t *c) +/* + * Read a new 'range' of the image 'image_name' (current color component + * is 'band') and compute the new inner product arrays. + * + * No return value. + * + * Side effects: + * 'c->pixels' are filled with pixel values of image block + * 'c->ip_images_state' are computed with respect to new image block + * 'range->address' and 'range->image' are initialized with zero + */ +{ + unsigned state; + + /* + * Clear already computed products + */ + for (state = 0; state < wfa->states; state++) + if (need_image (state, wfa)) + memset (c->ip_images_state[state], 0, + size_of_tree (c->products_level) * sizeof(real_t)); + + cut_to_bintree (c->pixels, image->pixels [band], + image->width, image->height, + range->x, range->y, width_of_level (range->level), + height_of_level (range->level)); + + range->address = range->image = 0; + compute_ip_images_state (0, 0, range->level, 1, 0, wfa, c); +} + + diff --git a/converter/other/fiasco/codec/subdivide.h b/converter/other/fiasco/codec/subdivide.h new file mode 100644 index 00000000..b6840e58 --- /dev/null +++ b/converter/other/fiasco/codec/subdivide.h @@ -0,0 +1,33 @@ +/* + * subdivide.h + * + * Written by: Ullrich Hafner + * + * This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec) + * Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de> + */ + +/* + * $Date: 2000/06/14 20:50:51 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#ifndef _SUBDIVIDE_H +#define _SUBDIVIDE_H + +#include "types.h" +#include "cwfa.h" + +real_t +subdivide (real_t max_costs, unsigned band, int y_state, range_t *range, + wfa_t *wfa, coding_t *c, bool_t prediction, bool_t delta); +void +cut_to_bintree (real_t *dst, const word_t *src, + unsigned src_width, unsigned src_height, + unsigned x0, unsigned y0, unsigned width, unsigned height); + +#endif /* not _SUBDIVIDE_H */ + + diff --git a/converter/other/fiasco/codec/tiling.c b/converter/other/fiasco/codec/tiling.c new file mode 100644 index 00000000..e820f7fb --- /dev/null +++ b/converter/other/fiasco/codec/tiling.c @@ -0,0 +1,239 @@ +/* + * tiling.c: Subimage permutation + * + * Written by: Ullrich Hafner + * + * This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec) + * Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de> + */ + +/* + * $Date: 2000/06/14 20:50:51 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#include "config.h" + +#if STDC_HEADERS +# include <stdlib.h> +#endif /* not STDC_HEADERS */ + +#include "types.h" +#include "macros.h" +#include "error.h" + +#include "image.h" +#include "misc.h" +#include "wfalib.h" +#include "tiling.h" + +/***************************************************************************** + + prototypes + +*****************************************************************************/ + +static int +cmpdecvar (const void *value1, const void *value2); +static int +cmpincvar (const void *value1, const void *value2); + +/***************************************************************************** + + public code + +*****************************************************************************/ + +typedef struct var_list +{ + int address; /* bintree address */ + real_t variance; /* variance of tile */ +} var_list_t; + +tiling_t * +alloc_tiling (fiasco_tiling_e method, unsigned tiling_exponent, + unsigned image_level) +/* + * Image tiling constructor. + * Allocate memory for the tiling_t structure. + * `method' defines the tiling method (spiral or variance, + * ascending or descending). + * In case of invalid parameters, a structure with tiling.exponent == 0 is + * returned. + * + * Return value + * pointer to the new tiling structure on success + */ +{ + tiling_t *tiling = Calloc (1, sizeof (tiling_t)); + + if ((int) image_level - (int) tiling_exponent < 6) + { + tiling_exponent = 6; + warning (_("Image tiles must be at least 8x8 pixels large.\n" + "Setting tiling size to 8x8 pixels.")); + } + + switch (method) + { + case FIASCO_TILING_SPIRAL_ASC: + case FIASCO_TILING_SPIRAL_DSC: + case FIASCO_TILING_VARIANCE_ASC: + case FIASCO_TILING_VARIANCE_DSC: + tiling_exponent = tiling_exponent; + break; + default: + warning (_("Invalid tiling method specified. Disabling tiling.")); + tiling_exponent = 0; + break; + } + + return tiling; +} + +void +free_tiling (tiling_t *tiling) +/* + * Tiling struct destructor: + * Free memory of 'tiling' struct. + * + * No return value. + * + * Side effects: + * structure 'tiling' is discarded. + */ +{ + if (tiling->vorder) + Free (tiling->vorder); + Free (tiling); +} + +void +perform_tiling (const image_t *image, tiling_t *tiling) +/* + * Compute image tiling permutation. + * The image is split into 2**'tiling->exponent' tiles. + * Depending on 'tiling->method', the following algorithms are used: + * "VARIANCE_ASC" : Tiles are sorted by variance. + * The first tile has the lowest variance + * "VARIANCE_DSC" : Tiles are sorted by variance. + * The first tile has the largest variance + * "SPIRAL_ASC" : Tiles are sorted like a spiral starting + * in the middle of the image. + * "SPIRAL_DSC" : Tiles are sorted like a spiral starting + * in the upper left corner. + * + * No return value. + * + * Side effects: + * The tiling permutation is stored in 'tiling->vorder'. + */ +{ + if (tiling->exponent) + { + unsigned tiles = 1 << tiling->exponent; /* number of image tiles */ + bool_t *tile_valid; /* tile i is in valid range ? */ + + tiling->vorder = Calloc (tiles, sizeof (int)); + tile_valid = Calloc (tiles, sizeof (bool_t)); + + if (tiling->method == FIASCO_TILING_VARIANCE_ASC + || tiling->method == FIASCO_TILING_VARIANCE_DSC) + { + unsigned address; /* bintree address of tile */ + unsigned number; /* number of image tiles */ + unsigned lx = log2 (image->width - 1) + 1; /* x level */ + unsigned ly = log2 (image->height - 1) + 1; /* y level */ + unsigned level = max (lx, ly) * 2 - ((ly == lx + 1) ? 1 : 0); + var_list_t *var_list = Calloc (tiles, sizeof (var_list_t)); + + /* + * Compute variances of image tiles + */ + for (number = 0, address = 0; address < tiles; address++) + { + unsigned width, height; /* size of image tile */ + unsigned x0, y0; /* NW corner of image tile */ + + locate_subimage (level, level - tiling->exponent, address, + &x0, &y0, &width, &height); + if (x0 < image->width && y0 < image->height) /* valid range */ + { + if (x0 + width > image->width) /* outside image area */ + width = image->width - x0; + if (y0 + height > image->height) /* outside image area */ + height = image->height - y0; + + var_list [number].variance + = variance (image->pixels [GRAY], x0, y0, + width, height, image->width); + var_list [number].address = address; + number++; + tile_valid [address] = YES; + } + else + tile_valid [address] = NO; + } + + /* + * Sort image tiles according to sign of 'tiling->exp' + */ + if (tiling->method == FIASCO_TILING_VARIANCE_DSC) + qsort (var_list, number, sizeof (var_list_t), cmpdecvar); + else + qsort (var_list, number, sizeof (var_list_t), cmpincvar); + + for (number = 0, address = 0; address < tiles; address++) + if (tile_valid [address]) + { + tiling->vorder [address] = var_list [number].address; + number++; + debug_message ("tile number %d has original address %d", + number, tiling->vorder [address]); + } + else + tiling->vorder [address] = -1; + + Free (var_list); + } + else if (tiling->method == FIASCO_TILING_SPIRAL_DSC + || tiling->method == FIASCO_TILING_SPIRAL_ASC) + { + compute_spiral (tiling->vorder, image->width, image->height, + tiling->exponent, + tiling->method == FIASCO_TILING_SPIRAL_ASC); + } + else + { + warning ("Unsupported image tiling method.\n" + "Skipping image tiling step."); + tiling->exponent = 0; + } + } +} + +/***************************************************************************** + + private code + +*****************************************************************************/ + +static int +cmpincvar (const void *value1, const void *value2) +/* + * Sorts by increasing variances (quicksort sorting function). + */ +{ + return ((var_list_t *) value1)->variance - ((var_list_t *) value2)->variance; +} + +static int +cmpdecvar (const void *value1, const void *value2) +/* + * Sorts by decreasing variances (quicksort sorting function). + */ +{ + return ((var_list_t *) value2)->variance - ((var_list_t *) value1)->variance; +} diff --git a/converter/other/fiasco/codec/tiling.h b/converter/other/fiasco/codec/tiling.h new file mode 100644 index 00000000..2eb04fe0 --- /dev/null +++ b/converter/other/fiasco/codec/tiling.h @@ -0,0 +1,40 @@ +/* + * tiling.h + * + * Written by: Ullrich Hafner + * + * This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec) + * Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de> + */ + +/* + * $Date: 2000/06/14 20:50:51 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#ifndef _TILING_H +#define _TILING_H + +#include "image.h" +#include "fiasco.h" + +typedef struct tiling +{ + unsigned exponent; /* Image is split in 2^exp tiles */ + fiasco_tiling_e method; /* Method of Image tiling */ + int *vorder; /* Block permutation (size = 2^exp) + -1 indicates empty block */ +} tiling_t; + +void +perform_tiling (const image_t *image, tiling_t *tiling); +tiling_t * +alloc_tiling (fiasco_tiling_e method, unsigned tiling_exponent, + unsigned image_level); +void +free_tiling (tiling_t *tiling); + +#endif /* not _TILING_H */ + diff --git a/converter/other/fiasco/codec/wfa.h b/converter/other/fiasco/codec/wfa.h new file mode 100644 index 00000000..8b9793f2 --- /dev/null +++ b/converter/other/fiasco/codec/wfa.h @@ -0,0 +1,141 @@ +/* + * wfa.h + * + * Written by: Ullrich Hafner + * + * This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec) + * Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de> + */ + +/* + * $Date: 2000/07/18 15:44:57 $ + * $Author: hafner $ + * $Revision: 5.3 $ + * $State: Exp $ + */ + +#ifndef _WFA_H +#define _WFA_H + +#define MAXEDGES 5 +#define MAXSTATES 6000 +#define MAXLABELS 2 /* only bintree supported anymore */ +#define MAXLEVEL 22 + +#define FIASCO_BINFILE_RELEASE 2 +#define FIASCO_MAGIC "FIASCO" /* FIASCO magic number */ +#define FIASCO_BASIS_MAGIC "Fiasco" /* FIASCO initial basis */ + +#define NO_EDGE -1 +#define RANGE -1 +#define NO_RANGE 0 + +#define CHILD 1 +#define LEAF 0 + +#define MAX_PROB 9 +#define MIN_PROB 1 + +/* + * WFA state types: + * 0: state is not allowed to be used in an + * approximation and it's image is not needed + * for ip computations. + * AUXILIARY_MASK: state is required for computation of ip's but is not + * allowed to be used in an approximation. + * USE_DOMAIN_MASK: state is allowed to be used in an approximation. + */ +enum state_types {AUXILIARY_MASK = 1 << 0, USE_DOMAIN_MASK = 1 << 1}; + +#define isedge(x) ((x) != NO_EDGE) +#define isdomain(x) ((x) != NO_EDGE) +#define isrange(x) ((x) == RANGE) +#define ischild(x) ((x) != RANGE) +#define isauxiliary(d,wfa) ((wfa)->domain_type[d] & AUXILIARY_MASK) +#define usedomain(d, wfa) ((wfa)->domain_type[d] & USE_DOMAIN_MASK) +#define need_image(d,wfa) (isauxiliary ((d), (wfa)) || usedomain ((d), (wfa))) + +typedef enum mc_type {NONE, FORWARD, BACKWARD, INTERPOLATED} mc_type_e; +typedef enum frame_type {I_FRAME, P_FRAME, B_FRAME} frame_type_e; +typedef enum header {HEADER_END, HEADER_TITLE, HEADER_COMMENT} header_type_e; + +typedef struct mv +/* + * Motion vector components + */ +{ + mc_type_e type; /* motion compensation type */ + int fx, fy; /* forward vector coordinates */ + int bx, by; /* backward vector coordinates */ +} mv_t; + +typedef struct range_info +{ + unsigned x, y; /* coordinates of upper left corner */ + unsigned level; /* bintree level of range */ +} range_info_t; + +#include "image.h" +#include "rpf.h" +#include "bit-io.h" + +typedef struct wfa_info +{ + char *wfa_name; /* filename of the WFA */ + char *basis_name; /* filename of the initial basis */ + char *title; /* title of FIASCO stream */ + char *comment; /* comment for FIASCO stream */ + + unsigned max_states; /* max. cardinality of domain pool */ + unsigned chroma_max_states; /* max. cardinality of domain pool for + chroma band coding */ + bool_t color; /* color image */ + unsigned width; /* image width */ + unsigned height; /* image height */ + unsigned level; /* image level */ + rpf_t *rpf; /* Standard reduced precision format */ + rpf_t *dc_rpf; /* DC reduced precision format */ + rpf_t *d_rpf; /* Delta reduced precision format */ + rpf_t *d_dc_rpf; /* Delta DC reduced precision format */ + unsigned frames; /* number of frames in the video */ + unsigned fps; /* number of frames per second */ + unsigned p_min_level; /* min. level of prediction */ + unsigned p_max_level; /* max. level of prediction */ + unsigned search_range; /* motion vector interval */ + bool_t half_pixel; /* usage of half pixel precision */ + bool_t cross_B_search; /* usage of Cross-B-Search */ + bool_t B_as_past_ref; /* usage of B frames as ref's */ + unsigned smoothing; /* smoothing of image along borders */ + unsigned release; /* FIASCO file format release */ +} wfa_info_t; + +typedef struct wfa +/* + * Used to store all informations and data structures of a WFA + */ +{ + wfa_info_t *wfainfo; /* misc. information about the WFA */ + frame_type_e frame_type; /* intra, predicted, bi-directional */ + unsigned states; /* number of states */ + unsigned basis_states; /* number of states in the basis */ + unsigned root_state; /* root of the tree */ + real_t *final_distribution; /* one pixel images */ + byte_t *level_of_state; /* level of the image part which is + represented by the current state */ + byte_t *domain_type; /* Bit_0==1: auxilliary state + Bit_1==1: used for Y compr */ + mv_t (*mv_tree)[MAXLABELS]; /* motion vectors */ + word_t (*tree)[MAXLABELS]; /* bintree partitioning */ + u_word_t (*x)[MAXLABELS]; /* range coordinate */ + u_word_t (*y)[MAXLABELS]; /* range coordinate */ + word_t (*into)[MAXLABELS][MAXEDGES + 1]; /* domain references */ + real_t (*weight)[MAXLABELS][MAXEDGES + 1]; /* lin.comb. coefficients */ + word_t (*int_weight)[MAXLABELS][MAXEDGES + 1]; /* bin. representation */ + word_t (*y_state)[MAXLABELS]; /* bintree of Y component */ + byte_t (*y_column)[MAXLABELS]; /* array for Y component references */ + byte_t (*prediction)[MAXLABELS]; /* DC prediction */ + bool_t (*delta_state); /* delta state */ +} wfa_t; + +#endif /* not _WFA_H */ + diff --git a/converter/other/fiasco/codec/wfalib.c b/converter/other/fiasco/codec/wfalib.c new file mode 100644 index 00000000..a3acb975 --- /dev/null +++ b/converter/other/fiasco/codec/wfalib.c @@ -0,0 +1,774 @@ +/* + * wfalib.c: Library functions both for encoding and decoding + * + * Written by: Ullrich Hafner + * + * This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec) + * Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de> + */ + +/* + * $Date: 2000/07/18 15:57:28 $ + * $Author: hafner $ + * $Revision: 5.5 $ + * $State: Exp $ + */ + +#define _BSD_SOURCE 1 /* Make sure strdup() is in string.h */ +#define _XOPEN_SOURCE 500 /* Make sure strdup() is in string.h */ + +#include "config.h" + +#if STDC_HEADERS +# include <stdlib.h> +#endif /* not STDC_HEADERS */ + +#include <string.h> + +#include "types.h" +#include "macros.h" +#include "error.h" + +#include "wfa.h" +#include "misc.h" +#include "wfalib.h" + +/***************************************************************************** + + prototypes + +*****************************************************************************/ + +static unsigned +xy_to_address (unsigned x, unsigned y, unsigned level, unsigned n); + +/***************************************************************************** + + public code + +*****************************************************************************/ + +wfa_t * +alloc_wfa (bool_t coding) +/* + * WFA constructor: + * Initialize the WFA structure 'wfa' and allocate memory. + * Flag 'coding' indicates whether WFA is used for coding or decoding. + * + * Return value: + * pointer to the new WFA structure + */ +{ + wfa_t *wfa = Calloc (1, sizeof (wfa_t)); + + /* + * Allocate memory + */ + wfa->final_distribution = Calloc (MAXSTATES, sizeof (real_t)); + wfa->level_of_state = Calloc (MAXSTATES, sizeof (byte_t)); + wfa->domain_type = Calloc (MAXSTATES, sizeof (byte_t)); + wfa->delta_state = Calloc (MAXSTATES, sizeof (bool_t)); + wfa->tree = Calloc (MAXSTATES * MAXLABELS, sizeof (word_t)); + wfa->x = Calloc (MAXSTATES * MAXLABELS, sizeof (word_t)); + wfa->y = Calloc (MAXSTATES * MAXLABELS, sizeof (word_t)); + wfa->mv_tree = Calloc (MAXSTATES * MAXLABELS, sizeof (mv_t)); + wfa->y_state = Calloc (MAXSTATES * MAXLABELS, sizeof (word_t)); + wfa->into = Calloc (MAXSTATES * MAXLABELS * (MAXEDGES + 1), + sizeof (word_t)); + wfa->weight = Calloc (MAXSTATES * MAXLABELS * (MAXEDGES + 1), + sizeof (real_t)); + wfa->int_weight = Calloc (MAXSTATES * MAXLABELS * (MAXEDGES + 1), + sizeof (word_t)); + wfa->wfainfo = Calloc (1, sizeof (wfa_info_t));; + wfa->prediction = Calloc (MAXSTATES * MAXLABELS, sizeof (byte_t)); + + wfa->wfainfo->wfa_name = NULL; + wfa->wfainfo->basis_name = NULL; + wfa->wfainfo->title = strdup (""); + wfa->wfainfo->comment = strdup (""); + + /* + * Initialize structure + */ + { + unsigned state, label; + + wfa->states = 0; + wfa->basis_states = 0; + wfa->root_state = 0; + for (state = 0; state < MAXSTATES; state++) + { + wfa->final_distribution [state] = 0; + wfa->domain_type [state] = 0; + for (label = 0; label < MAXLABELS; label++) + { + wfa->into [state][label][0] = NO_EDGE; + wfa->tree [state][label] = RANGE; + wfa->y_state [state][label] = RANGE; + } + } + } + + if (coding) /* initialize additional variables */ + wfa->y_column = Calloc (MAXSTATES * MAXLABELS, sizeof (byte_t)); + else + wfa->y_column = NULL; + + return wfa; +} + +void +free_wfa (wfa_t *wfa) +/* + * WFA destructor: + * Free memory of given 'wfa'. + * + * No return value. + * + * Side effects: + * 'wfa' struct is discarded. + */ +{ + if (wfa->wfainfo->wfa_name) + Free (wfa->wfainfo->wfa_name); + if (wfa->wfainfo->basis_name) + Free (wfa->wfainfo->basis_name); + if (wfa->wfainfo->title) + Free (wfa->wfainfo->title); + if (wfa->wfainfo->comment) + Free (wfa->wfainfo->comment); + + Free (wfa->final_distribution); + Free (wfa->level_of_state); + Free (wfa->domain_type); + Free (wfa->tree); + Free (wfa->x); + Free (wfa->y); + Free (wfa->mv_tree); + Free (wfa->y_state); + Free (wfa->into); + Free (wfa->weight); + Free (wfa->int_weight); + Free (wfa->wfainfo); + Free (wfa->prediction); + Free (wfa->delta_state); + if (wfa->y_column) + Free (wfa->y_column); + Free (wfa); +} + +real_t +compute_final_distribution (unsigned state, const wfa_t *wfa) +/* + * Compute the final distribution of the given 'state'. + * Uses the fact that the generated 'wfa' is average preserving. + * + * Return value: + * final distribution + */ +{ + unsigned label; + real_t final = 0; + + for (label = 0; label < MAXLABELS; label++) + { + unsigned edge; + int domain; + + if (ischild (domain = wfa->tree [state][label])) + final += wfa->final_distribution [domain]; + for (edge = 0; isedge (domain = wfa->into [state][label][edge]); edge++) + final += wfa->weight [state][label][edge] + * wfa->final_distribution [domain]; + } + + return final / MAXLABELS; +} + +word_t * +compute_hits (unsigned from, unsigned to, unsigned n, const wfa_t *wfa) +/* + * Selects the 'n' most popular domain images of the given 'wfa'. + * Consider only linear combinations of state images + * {i | 'from' <= i <= 'to'}. I.e. domains are in {i | from <= i < 'to'} + * Always ensure that state 0 is among selected states even though from + * may be > 0. + * + * Return value: + * pointer to array of the most popular state images + * sorted by increasing state numbers and terminated by -1 + */ +{ + word_t *domains; + unsigned state, label, edge; + int domain; + pair_t *hits = Calloc (to, sizeof (pair_t)); + + for (domain = 0; domain < (int) to; domain++) + { + hits [domain].value = domain; + hits [domain].key = 0; + } + + for (state = from; state <= to; state++) + for (label = 0; label < MAXLABELS; label++) + for (edge = 0; isedge (domain = wfa->into [state][label][edge]); + edge++) + hits [domain].key++; + + qsort (hits + 1, to - 1, sizeof (pair_t), sort_desc_pair); + + n = min (to, n); + domains = Calloc (n + 1, sizeof (word_t)); + + for (domain = 0; domain < (int) n && (!domain || hits [domain].key); + domain++) + domains [domain] = hits [domain].value; + if (n != domain) + debug_message ("Only %d domains have been used in the luminance.", + domain); + n = domain; + qsort (domains, n, sizeof (word_t), sort_asc_word); + domains [n] = -1; + + Free (hits); + + return domains; +} + +void +append_edge (unsigned from, unsigned into, real_t weight, + unsigned label, wfa_t *wfa) +/* + * Append an edge from state 'from' to state 'into' with + * the given 'label' and 'weight' to the 'wfa'. + * + * No return value. + * + * Side effects: + * 'wfa' structure is changed. + */ +{ + unsigned new; /* position of the new edge */ + unsigned edge; + + /* + * First look where to insert the new edge: + * edges are sorted by increasing 'into' values + */ + for (new = 0; (isedge (wfa->into [from][label][new]) + && wfa->into [from][label][new] < (int) into); new++) + ; + /* + * Move the edges 'n' to position 'n+1', for n = max, ..., 'new' + */ + for (edge = new; isedge (wfa->into [from][label][edge]); edge++) + ; + for (edge++; edge != new; edge--) + { + wfa->into [from][label][edge] = wfa->into [from][label][edge - 1]; + wfa->weight [from][label][edge] = wfa->weight [from][label][edge - 1]; + wfa->int_weight [from][label][edge] + = wfa->int_weight [from][label][edge - 1]; + } + /* + * Insert the new edge + */ + wfa->into [from][label][edge] = into; + wfa->weight [from][label][edge] = weight; + wfa->int_weight [from][label][edge] = weight * 512 + 0.5; +} + +void +remove_states (unsigned from, wfa_t *wfa) +/* + * Remove 'wfa' states 'wfa->basis_states',...,'wfa->states' - 1. + * + * No return value. + * + * Side effects: + * 'wfa' structure is cleared for the given states. + */ +{ + unsigned state; + + for (state = from; state < wfa->states; state++) + { + unsigned label; + + for (label = 0; label < MAXLABELS; label++) + { + wfa->into [state][label][0] = NO_EDGE; + wfa->tree [state][label] = RANGE; + wfa->prediction [state][label] = FALSE; + wfa->y_state [state][label] = RANGE; + wfa->mv_tree [state][label].type = NONE; + wfa->mv_tree [state][label].fx = 0; + wfa->mv_tree [state][label].fy = 0; + wfa->mv_tree [state][label].bx = 0; + wfa->mv_tree [state][label].by = 0; + } + wfa->domain_type [state] = 0; + wfa->delta_state [state] = FALSE; + } + + wfa->states = from; +} + +void +copy_wfa (wfa_t *dst, const wfa_t *src) +/* + * Copy WFA struct 'src' to WFA struct 'dst'. + * + * No return value. + * + * Side effects: + * 'dst' is filled with same data as 'src' + * + * NOTE: size of WFA 'dst' must be at least size of WFA 'src' + */ +{ + unsigned state; + + memset (dst->final_distribution, 0, MAXSTATES * sizeof (real_t)); + memset (dst->level_of_state, 0, MAXSTATES * sizeof (byte_t)); + memset (dst->domain_type, 0, MAXSTATES * sizeof (byte_t)); + memset (dst->mv_tree, 0, MAXSTATES * MAXLABELS * sizeof (mv_t)); + memset (dst->tree, 0, MAXSTATES * MAXLABELS * sizeof (word_t)); + memset (dst->x, 0, MAXSTATES * MAXLABELS * sizeof (word_t)); + memset (dst->y, 0, MAXSTATES * MAXLABELS * sizeof (word_t)); + memset (dst->y_state, 0, MAXSTATES * MAXLABELS * sizeof (word_t)); + memset (dst->into, NO_EDGE, + MAXSTATES * MAXLABELS * (MAXEDGES + 1) * sizeof (word_t)); + memset (dst->weight, 0, + MAXSTATES * MAXLABELS * (MAXEDGES + 1) * sizeof (real_t)); + memset (dst->int_weight, 0, + MAXSTATES * MAXLABELS * (MAXEDGES + 1) * sizeof (word_t)); + memset (dst->prediction, 0, MAXSTATES * MAXLABELS * sizeof (byte_t)); + memset (dst->delta_state, 0, MAXSTATES * sizeof (bool_t)); + if (dst->y_column) + memset (dst->y_column, 0, MAXSTATES * MAXLABELS * sizeof (byte_t)); + + for (state = 0; state < MAXSTATES; state++) /* clear WFA struct */ + { + unsigned label; + + for (label = 0; label < MAXLABELS; label++) + { + dst->into [state][label][0] = NO_EDGE; + dst->tree [state][label] = RANGE; + dst->mv_tree [state][label].type = NONE; + dst->y_state[state][label] = RANGE; + } + dst->delta_state [state] = NO; + dst->domain_type [state] = 0; + } + + dst->frame_type = src->frame_type; + dst->states = src->states; + dst->basis_states = src->basis_states; + dst->root_state = src->root_state; + + memcpy (dst->wfainfo, src->wfainfo, sizeof (wfa_info_t)); + + if (dst->states == 0) /* nothing to do */ + return; + + memcpy (dst->final_distribution, src->final_distribution, + src->states * sizeof (real_t)); + memcpy (dst->level_of_state, src->level_of_state, + src->states * sizeof (byte_t)); + memcpy (dst->domain_type, src->domain_type, + src->states * sizeof (byte_t)); + memcpy (dst->delta_state, src->delta_state, + src->states * sizeof (bool_t)); + memcpy (dst->mv_tree, src->mv_tree, + src->states * MAXLABELS * sizeof (mv_t)); + memcpy (dst->tree, src->tree, + src->states * MAXLABELS * sizeof (word_t)); + memcpy (dst->x, src->x, + src->states * MAXLABELS * sizeof (word_t)); + memcpy (dst->y, src->y, + src->states * MAXLABELS * sizeof (word_t)); + memcpy (dst->y_state, src->y_state, + src->states * MAXLABELS * sizeof (word_t)); + memcpy (dst->into, src->into, + src->states * MAXLABELS * (MAXEDGES + 1) * sizeof (word_t)); + memcpy (dst->weight, src->weight, + src->states * MAXLABELS * (MAXEDGES + 1) * sizeof (real_t)); + memcpy (dst->int_weight, src->int_weight, + src->states * MAXLABELS * (MAXEDGES + 1) * sizeof (word_t)); + memcpy (dst->prediction, src->prediction, + src->states * MAXLABELS * sizeof (byte_t)); + if (dst->y_column) + memcpy (dst->y_column, src->y_column, + src->states * MAXLABELS * sizeof (byte_t)); +} + +void +locate_subimage (unsigned orig_level, unsigned level, unsigned bintree, + unsigned *x, unsigned *y, unsigned *width, unsigned *height) +/* + * Compute pixel coordinates of the subimage which 'bintree' address is given. + * The level of the original image is 'orig_level' and the level of the + * subimage is 'level'. + * + * No return value. + * + * Side effects: + * '*x', '*y' coordinates of the upper left corner + * '*width', '*height' size of image + */ +{ + /* + * Compute coordinates of the subimage + */ + *x = *y = 0; /* start at NW corner */ + *width = width_of_level (level); + *height = height_of_level (level); + + if (level > orig_level) + { + error ("size of tile must be less or equal than image size."); + return; + } + else if (bintree >= (unsigned) (1 << (orig_level - level))) + { + error ("address out of bounds."); + return; + } + else if (level < orig_level) + { + unsigned mask; /* mask for bintree -> xy conversion */ + bool_t hor; /* 1 next subdivision is horizontal + 0 next subdivision is vertical */ + unsigned l = orig_level - 1; /* current level */ + + hor = orig_level % 2; /* start with vertival subdivision + for square image and vice versa */ + + for (mask = 1 << (orig_level - level - 1); mask; mask >>= 1, hor = !hor) + { + if (bintree & mask) /* change coordinates */ + { + if (hor) /* horizontal subdivision */ + *y += height_of_level (l); + else /* vertical subdivision */ + *x += width_of_level (l); + } + l--; + } + } +} + +void +compute_spiral (int *vorder, unsigned image_width, unsigned image_height, + unsigned tiling_exp, bool_t inc_spiral) +/* + * Compute image tiling with spiral order. + * 'inc_spiral' specifies whether the spiral starts in the middle + * of the image (TRUE) or at the border (FALSE). + * 'image_width'x'image_height' define the size of the image. + * The image is split into 'tiling->exp' tiles. + * + * No return value. + * + * Side effects: + * vorder[] is filled with tiling permutation + */ +{ + unsigned x, y; /* current position */ + unsigned xmin, xmax, ymin, ymax; /* boundaries for current line */ + unsigned width, height; /* offset for each tile */ + unsigned lx, ly, level; /* level x and y */ + unsigned tiles; /* total number of tiles */ + unsigned address; /* bintree address */ + + lx = log2 (image_width - 1) + 1; + ly = log2 (image_height - 1) + 1; + level = max (lx, ly) * 2 - ((ly == lx + 1) ? 1 : 0); + tiles = 1 << tiling_exp; /* Number of image tiles */ + width = width_of_level (level - tiling_exp); + height = height_of_level (level - tiling_exp); + for (address = 0; address < tiles; address++) + { + unsigned x0, y0, width, height; + + locate_subimage (level, level - tiling_exp, address, + &x0, &y0, &width, &height); + vorder [address] = (x0 < image_width && y0 < image_height) ? 0 : -1; + } + + xmin = 0; + xmax = width_of_level (level); + ymin = 0; + ymax = height_of_level (level); + address = 0; + + /* + * 1234 + * CDE5 Traverse image in spiral order + * BGF6 starting at the top left corner + * A987 + */ + while (TRUE) + { + for (x = xmin, y = ymin; x < xmax; x += width) /* W>E */ + { + while (vorder [address] == -1) + address++; + if (x < image_width && y < image_height) /* valid range */ + vorder [address++] = xy_to_address (x, y, level, tiling_exp); + while (address < tiles && vorder [address] == -1) + address++; + } + ymin += height; + + if (address >= tiles) + break; + + for (x = xmax - width, y = ymin; y < ymax; y += height) /* N>S */ + { + while (vorder [address] == -1) + address++; + if (x <= image_width && y <= image_height) /* valid range */ + vorder [address++] = xy_to_address (x, y, level, tiling_exp); + while (address < tiles && vorder [address] == -1) + address++; + } + xmax -= width; + + if (address >= tiles) + break; + + for (x = xmax - width, y = ymax - width; x >= xmin; x -= width) /* E<W */ + { + while (vorder [address] == -1) + address++; + if (x <= image_width && y <= image_height) /* valid range */ + vorder [address++] = xy_to_address (x, y, level, tiling_exp); + while (address < tiles && vorder [address] == -1) + address++; + } + ymax -= height; + + if (address >= tiles) + break; + + for (x = xmin, y = ymax - height; y >= ymin; y -= height) /* S>N */ + { + while (vorder [address] == -1) + address++; + if (x <= image_width && y <= image_height) /* valid range */ + vorder [address++] = xy_to_address (x, y, level, tiling_exp); + while (address < tiles && vorder [address] == -1) + address++; + } + xmin += width; + + if (address >= tiles) + break; + } + + if (inc_spiral) + { + int i = 0, j = tiles - 1; + + while (i < j) + { + int tmp; + + while (vorder [i] == -1) + i++; + while (vorder [j] == -1) + j--; + + tmp = vorder [i]; + vorder [i] = vorder [j]; + vorder [j] = tmp; + i++; + j--; + } + } + /* + * Print tiling info + */ + { + unsigned number; + + for (number = 0, address = 0; address < tiles; address++) + if (vorder [address] != -1) + debug_message ("number %d: address %d", + number++, vorder [address]); + } +} + +bool_t +find_range (unsigned x, unsigned y, unsigned band, + const wfa_t *wfa, unsigned *range_state, unsigned *range_label) +/* + * Find a range ('*range_state', '*range_label') that contains + * pixel ('x', 'y') in the iven color 'band'. + * + * Return value: + * TRUE on success, or FALSE if there is no such range + * + * Side effects: + * '*range_state' and '*range_label' are modified on success. + */ +{ + unsigned state, label; + unsigned first_state, last_state; + bool_t success = NO; + + first_state = wfa->basis_states; + last_state = wfa->states; + if (wfa->wfainfo->color) + switch (band) + { + case Y: + first_state = wfa->basis_states; + last_state = wfa->tree [wfa->tree [wfa->root_state][0]][0]; + break; + case Cb: + first_state = wfa->tree [wfa->tree [wfa->root_state][0]][0] + 1; + last_state = wfa->tree [wfa->tree [wfa->root_state][0]][1]; + break; + case Cr: + first_state = wfa->tree [wfa->tree [wfa->root_state][0]][1] + 1; + last_state = wfa->states; + break; + default: + error ("unknown color component."); + } + + for (state = first_state; state < last_state; state++) + for (label = 0; label < MAXLABELS; label++) + if (isrange (wfa->tree [state][label])) + if (x >= wfa->x [state][label] && y >= wfa->y [state][label] + && x < (unsigned) (wfa->x [state][label] + + width_of_level (wfa->level_of_state [state] - 1)) + && y < (unsigned) (wfa->y [state][label] + + height_of_level (wfa->level_of_state [state] - 1))) + { + success = YES; + *range_state = state; + *range_label = label; + + return success; + } + + return success; +} + +void +sort_ranges (unsigned state, unsigned *domain, + range_sort_t *rs, const wfa_t *wfa) +/* + * Generate list of ranges in coder order. + * 'state' is the current state of the call tree while 'domain' is the + * index of the last added WFA state. + * + * Side effects: + * 'domain' is incremented after recursion returns + * 'rs' is filled accordingly + * + * No return value. + */ +{ + unsigned label; + + for (label = 0; label < MAXLABELS; label++) + { + if (isrange (wfa->tree [state][label])) + rs->range_subdivided [rs->range_no] = NO; + else + { + sort_ranges (wfa->tree [state][label], domain, rs, wfa); + rs->range_subdivided [rs->range_no] = YES; + } + + rs->range_state [rs->range_no] = state; + rs->range_label [rs->range_no] = label; + rs->range_max_domain [rs->range_no] = *domain; + while (!usedomain (rs->range_max_domain [rs->range_no], wfa)) + rs->range_max_domain [rs->range_no]--; + + if (label == 1 || !rs->range_subdivided [rs->range_no]) + rs->range_no++; + } + + (*domain)++; +} + +bool_t +locate_delta_images (wfa_t *wfa) +/* + * Locate all WFA states that are part of a delta approximation. + * I.e., these states are assigned to ranges that have been predicted + * via MC or ND. + * + * Return value: + * TRUE at least one state is part of a delta approximation + * FALSE no delta approximations in this WFA + * + * Side effects: + * 'wfa->delta [state][label]' is set accordingly. + */ +{ + unsigned state, label; + bool_t delta = NO; + + for (state = wfa->root_state; state >= wfa->basis_states; state--) + wfa->delta_state [state] = NO; + + for (state = wfa->root_state; state >= wfa->basis_states; state--) + for (label = 0; label < MAXLABELS; label++) + if (ischild (wfa->tree [state][label])) + if (wfa->mv_tree [state][label].type != NONE + || isedge (wfa->into [state][label][0]) + || wfa->delta_state [state]) + { + delta = YES; + wfa->delta_state [wfa->tree [state][label]] = YES; + } + + return delta; +} + +/***************************************************************************** + + private code + +******************************************************************************/ + +static unsigned +xy_to_address (unsigned x, unsigned y, unsigned level, unsigned n) +/* + * Compute bintree address of subimage at coordinates ('x', 'y'). + * Size of original image is determined by 'level'. + * 'n' specifies number of iterations. + * + * Return value: + * address of subimage + */ +{ + unsigned address = 0; + + while (n--) + { + address <<= 1; + if (--level % 2) + { + if (x & width_of_level (level)) + address++; + } + else + { + if (y & height_of_level (level)) + address++; + } + } + + return address; +} diff --git a/converter/other/fiasco/codec/wfalib.h b/converter/other/fiasco/codec/wfalib.h new file mode 100644 index 00000000..4622fcd2 --- /dev/null +++ b/converter/other/fiasco/codec/wfalib.h @@ -0,0 +1,66 @@ +/* + * wfalib.h + * + * Written by: Ullrich Hafner + * + * This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec) + * Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de> + */ + +/* + * $Date: 2000/06/14 20:50:51 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#ifndef _WFALIB_H +#define _WFALIB_H + +#include "types.h" +#include "wfa.h" +#include "list.h" + +typedef struct range_sort +{ + u_word_t *range_state; + byte_t *range_label; + u_word_t *range_max_domain; + bool_t *range_subdivided; + unsigned range_no; +} range_sort_t; + +bool_t +locate_delta_images (wfa_t *wfa); +void +sort_ranges (unsigned state, unsigned *domain, + range_sort_t *rs, const wfa_t *wfa); +bool_t +find_range (unsigned x, unsigned y, unsigned band, + const wfa_t *wfa, unsigned *range_state, unsigned *range_label); +void +compute_spiral (int *vorder, unsigned image_width, unsigned image_height, + unsigned tiling_exp, bool_t inc_spiral); +void +locate_subimage (unsigned orig_level, unsigned level, unsigned bintree, + unsigned *x, unsigned *y, unsigned *width, unsigned *height); +void +copy_wfa (wfa_t *dst, const wfa_t *src); +void +remove_states (unsigned from, wfa_t *wfa); +void +append_edge (unsigned from, unsigned into, real_t weight, + unsigned label, wfa_t *wfa); +word_t * +compute_hits (unsigned from, unsigned to, unsigned n, const wfa_t *wfa); +real_t +compute_final_distribution (unsigned state, const wfa_t *wfa); +wfa_t * +alloc_wfa (bool_t coding); +void +free_wfa (wfa_t *wfa); +bool_t +locate_delta_images (wfa_t *wfa); + +#endif /* not _WFALIB_H */ + |