diff options
Diffstat (limited to 'converter/other/fiasco')
165 files changed, 27650 insertions, 0 deletions
diff --git a/converter/other/fiasco/Makefile b/converter/other/fiasco/Makefile new file mode 100644 index 00000000..0dd945ed --- /dev/null +++ b/converter/other/fiasco/Makefile @@ -0,0 +1,59 @@ +ifeq ($(SRCDIR)x,x) + SRCDIR = $(CURDIR)/../../.. + BUILDDIR = $(SRCDIR) +endif +SUBDIR = converter/other/fiasco +VPATH=.:$(SRCDIR)/$(SUBDIR) + +include $(BUILDDIR)/Makefile.config + +INCLUDES = \ + -I$(SRCDIR)/$(SUBDIR)/codec -I$(SRCDIR)/$(SUBDIR)/input \ + -I$(SRCDIR)/$(SUBDIR)/output -I$(SRCDIR)/$(SUBDIR)/lib \ + +BINARIES = pnmtofiasco fiascotopnm + +MERGEBINARIES = $(BINARIES) + +SCRIPTS = + +all: $(BINARIES) + +FIASCOLIBS = codec/libfiasco_codec.a \ + input/libfiasco_input.a \ + output/libfiasco_output.a \ + lib/libfiasco_lib.a + +COMMON_OBJECTS = binerror.o getopt.o getopt1.o params.o + +OBJECTS = $(BINARIES:%=%.o) $(COMMON_OBJECTS) + +MERGE_OBJECTS = $(BINARIES:%=%.o2) $(COMMON_OBJECTS) $(FIASCOLIBS) + +SUBDIRS = codec input output lib + +include $(SRCDIR)/Makefile.common + +$(BINARIES):%:%.o $(COMMON_OBJECTS) $(FIASCOLIBS) $(NETPBMLIB) \ + $(LIBOPT) + $(LD) $(LDFLAGS) -o $@ $< $(COMMON_OBJECTS) \ + $(shell $(LIBOPT) $(FIASCOLIBS) $(NETPBMLIB)) $(MATHLIB) $(LDLIBS) \ + $(RPATH) $(LADD) + +codec/libfiasco_codec.a: $(BUILDDIR)/$(SUBDIR)/codec FORCE + $(MAKE) -C codec -f $(SRCDIR)/$(SUBDIR)/codec/Makefile \ + libfiasco_codec.a SRCDIR=$(SRCDIR) BUILDDIR=$(BUILDDIR) + +input/libfiasco_input.a: $(BUILDDIR)/$(SUBDIR)/input FORCE + $(MAKE) -C input -f $(SRCDIR)/$(SUBDIR)/input/Makefile \ + libfiasco_input.a SRCDIR=$(SRCDIR) BUILDDIR=$(BUILDDIR) + +output/libfiasco_output.a: $(BUILDDIR)/$(SUBDIR)/output FORCE + $(MAKE) -C output -f $(SRCDIR)/$(SUBDIR)/output/Makefile \ + libfiasco_output.a SRCDIR=$(SRCDIR) BUILDDIR=$(BUILDDIR) + +lib/libfiasco_lib.a: $(BUILDDIR)/$(SUBDIR)/lib FORCE + $(MAKE) -C lib -f $(SRCDIR)/$(SUBDIR)/lib/Makefile \ + libfiasco_lib.a SRCDIR=$(SRCDIR) BUILDDIR=$(BUILDDIR) + + diff --git a/converter/other/fiasco/README.netpbm b/converter/other/fiasco/README.netpbm new file mode 100644 index 00000000..4f4019ad --- /dev/null +++ b/converter/other/fiasco/README.netpbm @@ -0,0 +1,41 @@ +The 'fiasco' subdirectory of the Netpbm source tree is primarily a copy +of the source distribution of the Fiasco package by Ullrich Hafner. +Bryan Henderson adapted fiasco-1.0 on July 6, 2000 to netpbm, and then +merged in all the updates from fiasco-1.3 on February 9, 2001. + +The changes are: + +- Uses Netpbm libraries for input and output of Netpbm format images. + +- Works with maxvals other than 255 in Netpbm input images. This change + also makes a minor correction to the maxval 255 case. Where the Fiasco + package multiplies by 16 to convert from 8 bit to 12 bit intensity, + the correct factor is 4095/255. + +- Does not issue warning when system configuration file not found. + The location of that file is a compile-time option in 'fiasco', but + fixed at /etc in Netpbm. The expectation is that Netpbm users will + never have a system configuration file. + +- Does not fail if basis file small.fco is not found. The Fiasco code + already contained facilities for defaulting to a built-in version of + small.fco, but it was disabled by an early check for existence of + the basis file as an actual file. In Netpbm, that check for + existence is simply removed. + +- Remove WINDOWS config.h configuration macro, which determined whether + files would be open with "b" flag (binary). Use "b" flag unconditionally. + +- Rename internal "log2" function to "Log2" to avoid conflict with existing + "log2" macro or function. The original package has conditional compilation + to allow it to use the existing log2 when configured for a system that has + it. In Netpbm, we always use the private version. + +- Compilation warnings fixed. + +- 'bin' subdirectory moved to top level directory. + +- man pages for programs moved from doc subdirectory to top level directory. + +- man page of pnmpsnr created. + diff --git a/converter/other/fiasco/binerror.c b/converter/other/fiasco/binerror.c new file mode 100644 index 00000000..8a41a214 --- /dev/null +++ b/converter/other/fiasco/binerror.c @@ -0,0 +1,143 @@ +/* + * error.c: Error handling + * + * Written by: Stefan Frank + * Ullrich Hafner + * + * Credits: Modelled after variable argument routines from Jef + * Poskanzer's pbmplus package. + * + * 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/03/20 21:29:59 $ + * $Author: hafner $ + * $Revision: 4.3 $ + * $State: Exp $ + */ + +#define _BSD_SOURCE 1 /* Make sure strdup() is in string.h */ +#define _XOPEN_SOURCE 500 /* Make sure strdup() is in string.h */ +#define _ERROR_C + +#include "config.h" + +#include <stdlib.h> +#include <stdio.h> + +#if STDC_HEADERS +# include <stdarg.h> +# define VA_START(args, lastarg) va_start(args, lastarg) +#else /* not STDC_HEADERS */ +# include <varargs.h> +# define VA_START(args, lastarg) va_start(args) +#endif /* not STDC_HEADERS */ +#include <string.h> + +#if HAVE_SETJMP_H +# include <setjmp.h> +#endif /* HAVE_SETJMP_H */ + +#include "fiasco.h" +#include "binerror.h" + +/***************************************************************************** + + global variables + +*****************************************************************************/ + +int error_line = 0; +const char *error_file = NULL; + +/***************************************************************************** + + local variables + +*****************************************************************************/ + +static const char *executable = "(name not initialized)"; + +/***************************************************************************** + + public code + +*****************************************************************************/ + +void +init_error_handling (const char *name) +/* + * Initialize filename of executable. + * + * No return value. + */ +{ + if (name) + executable = strdup (name); +} + +void +_error (const char *format, ...) +/* + * Print error message and exit. + * + * No return value. + */ +{ + va_list args; + + VA_START (args, format); + + fprintf (stderr, "%s: %s: line %d:\nError: ", + executable, error_file, error_line); +#if HAVE_VPRINTF + vfprintf (stderr, format, args); +#elif HAVE_DOPRNT + _doprnt (format, args, stderr); +#endif /* HAVE_DOPRNT */ + fputc ('\n', stderr); + va_end(args); + + exit (1); +} + +void +_file_error (const char *filename) +/* + * Print file error message and exit. + * + * No return value. + */ +{ + fprintf (stderr, "%s: %s: line %d:\nError: ", + executable, error_file, error_line); + perror (filename); + + exit (2); +} + +void +_warning (const char *format, ...) +/* + * Issue a warning and continue execution. + * + * No return value. + */ +{ + va_list args; + + VA_START (args, format); + + fprintf (stderr, "%s: %s: line %d:\nWarning: ", + executable, error_file, error_line); +#if HAVE_VPRINTF + vfprintf (stderr, format, args); +#elif HAVE_DOPRNT + _doprnt (format, args, stderr); +#endif /* HAVE_DOPRNT */ + fputc ('\n', stderr); + + va_end (args); +} diff --git a/converter/other/fiasco/binerror.h b/converter/other/fiasco/binerror.h new file mode 100644 index 00000000..e7ff43c9 --- /dev/null +++ b/converter/other/fiasco/binerror.h @@ -0,0 +1,50 @@ +/* + * error.h + * + * Written by: Stefan Frank + * 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/03/20 21:29:59 $ + * $Author: hafner $ + * $Revision: 4.3 $ + * $State: Exp $ + */ + +#ifndef _ERROR_H +#define _ERROR_H + +#define error error_line=__LINE__,error_file=__FILE__,_error +#define warning error_line=__LINE__,error_file=__FILE__,_warning +#define file_error(fn) error_line=__LINE__,error_file=__FILE__,_file_error(fn) + +#ifdef _ERROR_C +#define _EXTERN_TYPE +#else +#define _EXTERN_TYPE extern +#endif + +_EXTERN_TYPE int error_line; +_EXTERN_TYPE const char *error_file; + +void +init_error_handling (const char *name); +void +_error (const char *format, ...); +void +_warning (const char *format, ...); +void +_file_error (const char *filename); + +#if HAVE_ASSERT_H +# include <assert.h> +#else /* not HAVE_ASSERT_H */ +# define assert(exp) {if (!(exp)) error ("Assertion `" #exp " != NULL' failed.");} +#endif /* not HAVE_ASSERT_H */ + +#endif /* not _ERROR_H */ + diff --git a/converter/other/fiasco/buttons.c b/converter/other/fiasco/buttons.c new file mode 100644 index 00000000..82ed18cd --- /dev/null +++ b/converter/other/fiasco/buttons.c @@ -0,0 +1,510 @@ +/* + * buttons.c: Draw MWFA player buttons in X11 window + * + * 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/15 17:23:11 $ + * $Author: hafner $ + * $Revision: 5.2 $ + * $State: Exp $ + */ + +#include "config.h" + +#ifndef X_DISPLAY_MISSING + +#include <X11/Xlib.h> +#include <X11/Intrinsic.h> +#include <X11/StringDefs.h> + +#if STDC_HEADERS +# include <stdlib.h> +#endif /* not STDC_HEADERS */ + +#include "types.h" +#include "macros.h" + +#include "display.h" +#include "binerror.h" +#include "buttons.h" + +/***************************************************************************** + + local variables + +*****************************************************************************/ + +static const int EVENT_MASK = (KeyPressMask | ButtonPressMask | + ButtonReleaseMask | ExposureMask); + +/***************************************************************************** + + prototypes + +*****************************************************************************/ + +static void +draw_progress_bar (x11_info_t *xinfo, binfo_t *binfo, unsigned n, + unsigned n_frames); +static void +draw_button (x11_info_t *xinfo, binfo_t *binfo, + buttons_t button, bool_t pressed); +static void +draw_control_panel (x11_info_t *xinfo, binfo_t *binfo, + unsigned n, unsigned n_frames); + +/***************************************************************************** + + public code + +*****************************************************************************/ + +binfo_t * +init_buttons (x11_info_t *xinfo, unsigned n, unsigned n_frames, + unsigned buttons_height, unsigned progbar_height) +/* + * Initialize a toolbar with the typical collection of video player + * buttons (pause, play, record, next, etc.) in the window given by 'xinfo'. + * 'n' gives the current frame, 'whereas' n_frames is the total number of + * frames of the video stream. + * The size of the button toolbar is given by 'buttons_height', + * the size of the progressbar is given by 'progbar_height'. + * + * Return value: + * struct managing the toolbar and progressbar information + */ +{ + XGCValues values; + XEvent event; + Colormap cmap; + XColor gray, dgray, lgray, red; + XColor graye, dgraye, lgraye, rede; + buttons_t button; /* counter */ + binfo_t *binfo = calloc (1, sizeof (binfo_t)); + + if (!binfo) + error ("Out of memory."); + + binfo->width = xinfo->ximage->width; + binfo->height = buttons_height; + binfo->progbar_height = progbar_height; + binfo->record_is_rewind = NO; + + /* + * Generate sub-window for control panel + */ + binfo->window = XCreateSimpleWindow (xinfo->display, xinfo->window, + 0, xinfo->ximage->height, + binfo->width, binfo->height, 0, + BlackPixel (xinfo->display, + xinfo->screen), + WhitePixel (xinfo->display, + xinfo->screen)); + XSelectInput(xinfo->display, binfo->window, StructureNotifyMask); + XMapWindow (xinfo->display, binfo->window); + do + { + XNextEvent (xinfo->display, &event); + } + while (event.type != MapNotify || event.xmap.event != binfo->window); + XSelectInput (xinfo->display, binfo->window, EVENT_MASK); + + /* + * Generate graphic contexts for different colors. + */ + cmap = DefaultColormap (xinfo->display, xinfo->screen); + XAllocNamedColor (xinfo->display, cmap, "#404040", &dgray, &dgraye); + XAllocNamedColor (xinfo->display, cmap, "white", &lgray, &lgraye); + XAllocNamedColor (xinfo->display, cmap, "#a8a8a8", &gray, &graye); + XAllocNamedColor (xinfo->display, cmap, "red", &red, &rede); + + values.foreground = BlackPixel (xinfo->display, xinfo->screen); + values.background = WhitePixel (xinfo->display, xinfo->screen); + binfo->gc [BLACK] = XCreateGC (xinfo->display, + RootWindow (xinfo->display, xinfo->screen), + (GCForeground | GCBackground), &values); + values.foreground = BlackPixel (xinfo->display, xinfo->screen); + values.background = WhitePixel (xinfo->display, xinfo->screen); + values.line_width = 3; + values.join_style = JoinRound; + binfo->gc [THICKBLACK] = XCreateGC (xinfo->display, + RootWindow (xinfo->display, + xinfo->screen), + (GCForeground | GCBackground + | GCLineWidth | GCJoinStyle), &values); + values.foreground = gray.pixel; + values.background = WhitePixel (xinfo->display, xinfo->screen); + binfo->gc [NGRAY] = XCreateGC (xinfo->display, + RootWindow (xinfo->display, xinfo->screen), + (GCForeground | GCBackground), &values); + values.foreground = lgray.pixel; + values.background = WhitePixel (xinfo->display, xinfo->screen); + binfo->gc [LGRAY] = XCreateGC (xinfo->display, + RootWindow (xinfo->display, xinfo->screen), + (GCForeground | GCBackground), &values); + values.foreground = dgray.pixel; + values.background = WhitePixel (xinfo->display, xinfo->screen); + binfo->gc [DGRAY] = XCreateGC (xinfo->display, + RootWindow (xinfo->display, xinfo->screen), + (GCForeground | GCBackground), &values); + values.foreground = red.pixel; + values.background = WhitePixel (xinfo->display, xinfo->screen); + binfo->gc [RED] = XCreateGC (xinfo->display, + RootWindow (xinfo->display, xinfo->screen), + (GCForeground | GCBackground), &values); + + for (button = 0; button < NO_BUTTON; button++) + binfo->pressed [button] = NO; + + draw_control_panel (xinfo, binfo, n, n_frames); + + return binfo; +} + +void +wait_for_input (x11_info_t *xinfo) +/* + * Wait for key press or mouse click in window 'xinfo'. + * Redraw 'image' if event other then ButtonPress or KeyPress occurs. + * Enlarge or reduce size of image by factor 2^'enlarge_factor'. + * + * No return value. + * + * Side effect: + * program is terminated after key press or mouse click. + */ +{ + bool_t leave_loop = NO; + + XSelectInput (xinfo->display, xinfo->window, EVENT_MASK); + + while (!leave_loop) + { + XEvent event; + + XMaskEvent (xinfo->display, EVENT_MASK, &event); + switch (event.type) + { + case ButtonPress: + case KeyPress: + leave_loop = YES; + break; + default: + display_image (0, 0, xinfo); + break; + } + } +} + +void +check_events (x11_info_t *xinfo, binfo_t *binfo, unsigned n, unsigned n_frames) +/* + * Check the X11 event loop. If the PAUSE buttonin the of panel 'binfo' + * is activated wait until next event occurs. + * Redraw 'image' if event other then ButtonPress or ButtonRelease occurs. + * Enlarge or reduce size of image by factor 2^'enlarge_factor'. + * 'n' gives the current frame, 'whereas' n_frames is the total number of + * frames of the video stream. + * + * No return values. + * + * Side effects: + * status of buttons (binfo->pressed [button]) is changed accordingly. + */ +{ + bool_t leave_eventloop; + + leave_eventloop = (!binfo->pressed [PAUSE_BUTTON] + && binfo->pressed [PLAY_BUTTON]) + || (!binfo->pressed [PAUSE_BUTTON] + && binfo->record_is_rewind + && binfo->pressed [RECORD_BUTTON]) + || binfo->pressed [RECORD_BUTTON]; + draw_progress_bar (xinfo, binfo, n, n_frames); + + if (binfo->pressed [PAUSE_BUTTON] && binfo->pressed [PLAY_BUTTON]) + { + XFlush (xinfo->display); + draw_button (xinfo, binfo, PLAY_BUTTON, NO); /* clear PLAY mode */ + XFlush (xinfo->display); + } + if (binfo->pressed [PAUSE_BUTTON] + && binfo->record_is_rewind && binfo->pressed [RECORD_BUTTON]) + { + XFlush (xinfo->display); + draw_button (xinfo, binfo, RECORD_BUTTON, NO); /* clear PLAY mode */ + XFlush (xinfo->display); + } + + if (binfo->pressed [STOP_BUTTON]) + { + XFlush (xinfo->display); + draw_button (xinfo, binfo, STOP_BUTTON, NO); /* clear STOP button */ + XFlush (xinfo->display); + } + + do + { + XEvent event; + int button; + bool_t wait_release = NO; + + + if (XCheckMaskEvent (xinfo->display, EVENT_MASK, &event)) + { + switch (event.type) + { + case ButtonPress: + wait_release = NO; + if (!(binfo->pressed [RECORD_BUTTON] && + !binfo->record_is_rewind)) + for (button = 0; button < NO_BUTTON; button++) + { + int x0, y0, x1, y1; /* button coordinates */ + + x0 = button * (binfo->width / NO_BUTTON); + y0 = binfo->progbar_height; + x1 = x0 + binfo->width / NO_BUTTON; + y1 = y0 + binfo->height - binfo->progbar_height - 1; + if (event.xbutton.x > x0 && event.xbutton.x < x1 + && event.xbutton.y > y0 && event.xbutton.y < y1) + { + draw_button (xinfo, binfo, button, + !binfo->pressed [button]); + wait_release = YES; + break; + } + } + break; + case ButtonRelease: + wait_release = NO; + break; + default: + wait_release = NO; + draw_control_panel (xinfo, binfo, n, n_frames); + display_image (0, 0, xinfo); + break; + } + leave_eventloop = !wait_release + && (binfo->pressed [PLAY_BUTTON] + || binfo->pressed [STOP_BUTTON] + || binfo->pressed [RECORD_BUTTON] + || binfo->pressed [QUIT_BUTTON]); + } + } while (!leave_eventloop); + + if ((binfo->pressed [RECORD_BUTTON] && !binfo->record_is_rewind) + && n == n_frames - 1) + { + binfo->record_is_rewind = YES; + draw_button (xinfo, binfo, RECORD_BUTTON, NO); + } +} + +/***************************************************************************** + + private code + +*****************************************************************************/ + +static void +draw_control_panel (x11_info_t *xinfo, binfo_t *binfo, + unsigned n, unsigned n_frames) +/* + * Draw control panel 'binfo' with all buttons and progressbar in + * the given 'window'. + * 'n' gives the current frame, 'whereas' n_frames is the total number of + * frames of the video stream. + * + * No return value. + */ +{ + buttons_t button; + + XFillRectangle (xinfo->display, binfo->window, binfo->gc [NGRAY], + 0, 0, binfo->width, binfo->height); + draw_progress_bar (xinfo, binfo, n, n_frames); + for (button = 0; button < NO_BUTTON; button++) + draw_button (xinfo, binfo, button, binfo->pressed [button]); +} + +static void +draw_progress_bar (x11_info_t *xinfo, binfo_t *binfo, unsigned n, + unsigned n_frames) +/* + * Draw progressbar of control panel 'binfo' in the given 'window'. + * 'n' gives the current frame, whereas 'n_frames' is the total number of + * frames of the video stream. + * + * No return value. + */ +{ + unsigned x, y, width, height; + + x = 2; + y = 1; + width = binfo->width - 5; + height = binfo->progbar_height - 3; + + XDrawLine (xinfo->display, binfo->window, binfo->gc [DGRAY], + x, y, x + width, y); + XDrawLine (xinfo->display, binfo->window, binfo->gc [DGRAY], + x, y, x, y + height - 1); + XDrawLine (xinfo->display, binfo->window, binfo->gc [LGRAY], + x + width, y + 1, x + width, y + height); + XDrawLine (xinfo->display, binfo->window, binfo->gc [LGRAY], + x, y + height, x + width, y + height); + + x++; y++; width -= 2; height -= 2; + XFillRectangle (xinfo->display, binfo->window, binfo->gc [NGRAY], + x, y, width, height); + + XFillRectangle (xinfo->display, binfo->window, binfo->gc [BLACK], + x + n * max (1, width / n_frames), y, + max (1, width / n_frames), height); +} + +static void +draw_button (x11_info_t *xinfo, binfo_t *binfo, + buttons_t button, bool_t pressed) +/* + * Draw 'button' of control panel 'binfo' in the given 'window'. + * 'pressed' indicates whether the button is pressed or not. + * + * No return value. + */ +{ + grayscale_t top, bottom; /* index of GC */ + unsigned x, y, width, height; /* coordinates of button */ + + x = button * (binfo->width / NO_BUTTON); + y = binfo->progbar_height; + width = binfo->width / NO_BUTTON; + height = binfo->height - binfo->progbar_height - 1; + + if (width < 4 || height < 4) + return; + + if (pressed) + { + top = DGRAY; + bottom = LGRAY; + } + else + { + top = LGRAY; + bottom = DGRAY; + } + + x += 2; + width -= 4; + + XDrawLine (xinfo->display, binfo->window, binfo->gc [top], + x, y, x + width, y); + XDrawLine (xinfo->display, binfo->window, binfo->gc [top], + x, y, x, y + height - 1); + XDrawLine (xinfo->display, binfo->window, binfo->gc [bottom], + x + width, y + 1, x + width, y + height); + XDrawLine (xinfo->display, binfo->window, binfo->gc [bottom], + x, y + height, x + width, y + height); + + x++; y++; width -= 2; height -= 2; + XFillRectangle (xinfo->display, binfo->window, binfo->gc [NGRAY], + x, y, width, height); + + switch (button) + { + case STOP_BUTTON: + XFillRectangle (xinfo->display, binfo->window, binfo->gc [BLACK], + x + width / 2 - 6, y + height / 2 - 4, 11, 11); + if (pressed && !binfo->pressed [STOP_BUTTON]) + { + draw_button (xinfo, binfo, PLAY_BUTTON, NO); + draw_button (xinfo, binfo, PAUSE_BUTTON, NO); + draw_button (xinfo, binfo, RECORD_BUTTON, NO); + } + break; + case PAUSE_BUTTON: + XFillRectangle (xinfo->display, binfo->window, binfo->gc [BLACK], + x + width / 2 - 6, y + height / 2 - 4, 5, 11); + XFillRectangle (xinfo->display, binfo->window, binfo->gc [BLACK], + x + width / 2 + 1, y + height / 2 - 4, 5, 11); + break; + case PLAY_BUTTON: + { + XPoint triangle [3]; + + triangle [0].x = x + width / 2 - 5; + triangle [0].y = y + height / 2 - 5; + triangle [1].x = 10; + triangle [1].y = 6; + triangle [2].x = -10; + triangle [2].y = 6; + + XFillPolygon (xinfo->display, binfo->window, binfo->gc [BLACK], + triangle, 3, Convex, CoordModePrevious); + if (pressed && !binfo->pressed [PLAY_BUTTON] + && binfo->pressed [RECORD_BUTTON]) + draw_button (xinfo, binfo, RECORD_BUTTON, NO); + } + break; + case RECORD_BUTTON: + if (!binfo->record_is_rewind) + { + XFillArc (xinfo->display, binfo->window, binfo->gc [RED], + x + width / 2 - 5, y + height / 2 - 5, 11, 11, 0, + 360 * 64); + if (pressed && !binfo->pressed [RECORD_BUTTON]) + { + draw_button (xinfo, binfo, STOP_BUTTON, YES); + draw_button (xinfo, binfo, PLAY_BUTTON, NO); + draw_button (xinfo, binfo, PAUSE_BUTTON, NO); + } + } + else + { + XPoint triangle [3]; + + triangle [0].x = x + width / 2 + 5; + triangle [0].y = y + height / 2 - 5; + triangle [1].x = -10; + triangle [1].y = 6; + triangle [2].x = 10; + triangle [2].y = 6; + + XFillPolygon (xinfo->display, binfo->window, binfo->gc [BLACK], + triangle, 3, Convex, CoordModePrevious); + if (pressed && !binfo->pressed [RECORD_BUTTON] + && binfo->pressed [PLAY_BUTTON]) + draw_button (xinfo, binfo, PLAY_BUTTON, NO); + } + break; + case QUIT_BUTTON: + { + XPoint triangle [3]; + + triangle [0].x = x + width / 2 - 6; + triangle [0].y = y + height / 2 + 2; + triangle [1].x = 6; + triangle [1].y = -7; + triangle [2].x = 6; + triangle [2].y = 7; + + XFillPolygon (xinfo->display, binfo->window, binfo->gc [BLACK], + triangle, 3, Convex, CoordModePrevious); + XFillRectangle (xinfo->display, binfo->window, binfo->gc [BLACK], + x + width / 2 - 5, y + height / 2 + 4, 11, 3); + } + break; + default: + break; + } + binfo->pressed [button] = pressed; +} + +#endif /* not X_DISPLAY_MISSING */ diff --git a/converter/other/fiasco/buttons.h b/converter/other/fiasco/buttons.h new file mode 100644 index 00000000..a09f3423 --- /dev/null +++ b/converter/other/fiasco/buttons.h @@ -0,0 +1,50 @@ +/* + * buttons.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:51:17 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#ifndef _BUTTONS_H +#define _BUTTONS_H + +#ifndef X_DISPLAY_MISSING + +typedef enum grayscale_e {BLACK, NGRAY, LGRAY, DGRAY, RED, + THICKBLACK, NO_GC} grayscale_t; +typedef enum buttons_e {STOP_BUTTON, PLAY_BUTTON, PAUSE_BUTTON, RECORD_BUTTON, + QUIT_BUTTON, NO_BUTTON} buttons_t; + +typedef struct buttoninfo +{ + Window window; + bool_t pressed [NO_BUTTON]; + GC gc [NO_GC]; + unsigned width; + unsigned height; + unsigned progbar_height; + bool_t record_is_rewind; +} binfo_t; + +void +check_events (x11_info_t *xinfo, binfo_t *binfo, unsigned n, + unsigned n_frames); +void +wait_for_input (x11_info_t *xinfo); +binfo_t * +init_buttons (x11_info_t *xinfo, unsigned n, unsigned n_frames, + unsigned buttons_height, unsigned progbar_height); + +#endif /* not X_DISPLAY_MISSING */ + +#endif /* not _BUTTONS_H */ + 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 */ + diff --git a/converter/other/fiasco/config.h b/converter/other/fiasco/config.h new file mode 100644 index 00000000..d6b15a84 --- /dev/null +++ b/converter/other/fiasco/config.h @@ -0,0 +1,96 @@ +/* config.h. Generated automatically by configure. */ +/* But then manually maintained as part of Netpbm! */ + +/* config.h.in. Generated automatically from configure.in by autoheader. */ + +/* Define to empty if the keyword does not work. */ +/* #undef const */ + +/* Define if you don't have vprintf but do have _doprnt. */ +/* #undef HAVE_DOPRNT */ + +/* Define if you have the vprintf function. */ +#define HAVE_VPRINTF 1 + +/* Define to `unsigned' if <sys/types.h> doesn't define. */ +/* #undef size_t */ + +/* Define if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define if you can safely include both <sys/time.h> and <time.h>. */ +#define TIME_WITH_SYS_TIME 1 + +/* Define if your processor stores words with the most significant + byte first (like Motorola and SPARC, unlike Intel and VAX). */ +/* #undef WORDS_BIGENDIAN */ + +/* Define if the X Window System is missing or not being used. */ +#define X_DISPLAY_MISSING 1 + +/* Define if shifting of signed integers works */ +#define HAVE_SIGNED_SHIFT 1 + +/* Define if you don't have the CLOCKS_PER_SEC define in <time.h>. */ +/* #undef CLOCKS_PER_SEC */ + +/* The number of bytes in a char. */ +#define SIZEOF_CHAR 1 + +/* The number of bytes in a int. */ +#define SIZEOF_INT 4 + +/* The number of bytes in a short. */ +#define SIZEOF_SHORT 2 + +/* Define if you have the log2 function. */ +/* #undef HAVE_LOG2 */ +/* For Netpbm, we won't use log2() because it might not exist. In + Netpbm, misc.c contains Log2(), so we just define log2 as Log2 here. + But first, we include <math.h> because if we don't it may get included + after config.h, and then there could be a redefinition issue with log2. +*/ +#include <math.h> +#undef log2 +#define log2 Log2 + +/* Define if you have the memmove function. */ +#define HAVE_MEMMOVE 1 + +/* Define if you have the strcasecmp function. */ +#define HAVE_STRCASECMP 1 + +/* Define if you have the strdup function. */ +#define HAVE_STRDUP 1 + +/* Define if you have the <X11/extensions/XShm.h> header file. */ +/* #undef HAVE_X11_EXTENSIONS_XSHM_H */ + +/* Define if you have the <assert.h> header file. */ +#define HAVE_ASSERT_H 1 + +/* Define if you have the <features.h> header file. */ +#define HAVE_FEATURES_H 1 + +/* Define if you have the <setjmp.h> header file. */ +#define HAVE_SETJMP_H 1 + +/* Define if you have the <string.h> header file. */ +#define HAVE_STRING_H 1 + +/* Define if you have the <sys/time.h> header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define if you have the <unistd.h> header file. */ +#define HAVE_UNISTD_H 1 + +/* Define if you have the m library (-lm). */ +#define HAVE_LIBM 1 + +/* Name of package */ +#define PACKAGE "fiasco" + +/* Version number of package */ +#define VERSION "1.0" + +#define FIASCO_SHARE "/etc/" diff --git a/converter/other/fiasco/display.c b/converter/other/fiasco/display.c new file mode 100644 index 00000000..9e531149 --- /dev/null +++ b/converter/other/fiasco/display.c @@ -0,0 +1,422 @@ +/* + * display.c: X11 display of frames + * + * 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> + * + * Based on mpeg2decode, (C) 1994, MPEG Software Simulation Group + * and mpeg2play, (C) 1994 Stefan Eckart + * <stefan@lis.e-technik.tu-muenchen.de> + * and tmndec (C) 1995, 1996 Telenor R&D, Norway + */ + +/* + * $Date: 2000/07/03 19:35:59 $ + * $Author: hafner $ + * $Revision: 5.2 $ + * $State: Exp $ + */ + +#include "config.h" + +#ifndef X_DISPLAY_MISSING + +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/keysym.h> + +#if STDC_HEADERS +# include <stdlib.h> +# include <string.h> +#else /* not STDC_HEADERS */ +# if HAVE_STRING_H +# include <string.h> +# else /* not HAVE_STRING_H */ +# include <strings.h> +# endif /* not HAVE_STRING_H */ +#endif /* not STDC_HEADERS */ + +#include "types.h" +#include "macros.h" +#include "display.h" +#include "binerror.h" + +/***************************************************************************** + + shared memory functions (if USE_SHM is defined) + +*****************************************************************************/ + +#ifdef USE_SHM + +#ifdef HAVE_FEATURES_H +#include <features.h> +#endif + +#include <sys/types.h> +#include <sys/ipc.h> +#include <sys/shm.h> +#include <X11/extensions/XShm.h> + +int +XShmQueryExtension (Display *dpy); +int +XShmGetEventBase (Display *dpy); + +static int +HandleXError (Display *dpy, XErrorEvent *event); +static void +InstallXErrorHandler (x11_info_t *xinfo); +static void +DeInstallXErrorHandler (x11_info_t *xinfo); + +static int shmem_flag; +static XShmSegmentInfo shminfo1, shminfo2; +static int gXErrorFlag; +static int CompletionType = -1; + +static int +HandleXError (Display *dpy, XErrorEvent *event) +{ + gXErrorFlag = 1; + + return 0; +} + +static void +InstallXErrorHandler (x11_info_t *xinfo) +{ + XSetErrorHandler (HandleXError); + XFlush (xinfo->display); +} + +static void +DeInstallXErrorHandler (x11_info_t *xinfo) +{ + XSetErrorHandler (NULL); + XFlush (xinfo->display); +} + +#endif /* USE_SHM */ + +/***************************************************************************** + + public code + +*****************************************************************************/ + +void +display_image (unsigned x0, unsigned y0, x11_info_t *xinfo) +/* + * Display 'image' at pos ('x0', 'y0') in the current window + * (given by 'xinfo->window'). + * + * No return value. + */ +{ + int byte_order_check = 1; + + /* + * Always work in native bit and byte order. This tells Xlib to + * reverse bit and byte order if necessary when crossing a + * network. Frankly, this part of XImages is somewhat + * underdocumented, so this may not be exactly correct. + */ + if (*(char *) & byte_order_check == 1) + { + xinfo->ximage->byte_order = LSBFirst; + xinfo->ximage->bitmap_bit_order = LSBFirst; + } + else + { + xinfo->ximage->byte_order = MSBFirst; + xinfo->ximage->bitmap_bit_order = MSBFirst; + } + + /* Display dithered image */ +#ifdef USE_SHM + if (shmem_flag) + { + XEvent xev; + + XShmPutImage (xinfo->display, xinfo->window, xinfo->gc, xinfo->ximage, + 0, 0, x0, y0, xinfo->ximage->width, xinfo->ximage->height, + True); + XFlush (xinfo->display); + + while (!XCheckTypedEvent (xinfo->display, CompletionType, &xev)) + ; + } + else +#endif /* USE_SHM */ + { + xinfo->ximage->data = (char *) xinfo->pixels; + XPutImage (xinfo->display, xinfo->window, xinfo->gc, xinfo->ximage, 0, 0, + x0, y0, xinfo->ximage->width, xinfo->ximage->height); + } +} + +void +close_window (x11_info_t *xinfo) +{ +#ifdef USE_SHM + if (shmem_flag && xinfo->ximage) + { + XShmDetach (xinfo->display, &shminfo1); + XDestroyImage (xinfo->ximage); + xinfo->ximage = NULL; + shmdt (shminfo1.shmaddr); + } + else +#endif /* USE_SHM */ + if (xinfo->ximage) + { + XDestroyImage (xinfo->ximage); + xinfo->ximage = NULL; + } + if (xinfo->display) + { + XCloseDisplay (xinfo->display); + xinfo->display = NULL; + } +} + +x11_info_t * +open_window (const char *titlename, const char *iconname, + unsigned width, unsigned height) +/* + * Open a X11 window of size 'width'x'height'. + * If 'color' is false then allocate a colormap with grayscales. + * Window and icon titles are given by 'titlename' and 'iconname', + * respectively. + * + * Return value: + * X11 info struct containing display, gc, window ID and colormap. + */ +{ + XVisualInfo visual_template; /* template for XGetVisualInfo() */ + XVisualInfo visual_info; /* return value of XGetVisualInfo() */ + int visual_n; /* # of matches of XGetVisualInfo */ + XEvent xev; + XSizeHints hint; + XSetWindowAttributes xswa; + unsigned int fg, bg; /* foreground and background color */ + unsigned int mask; /* event mask */ + x11_info_t *xinfo = calloc (1, sizeof (x11_info_t)); + long visual_mask; + + if (!xinfo) + error ("Out of memory"); + /* + * Initialization of display + */ + xinfo->display = XOpenDisplay (NULL); + if (xinfo->display == NULL) + error ("Can't open display.\n" + "Make sure that your environment variable DISPLAY " + "is set correctly."); + + xinfo->screen = DefaultScreen (xinfo->display); + xinfo->gc = DefaultGC (xinfo->display, xinfo->screen); + + { + unsigned depth [] = {32, 24, 16}; + int class [] = {TrueColor, PseudoColor}; + const char *class_text [] = {"TrueColor", "PseudoColor"}; + Status found = 0; + unsigned d, c; + + for (d = 0; !found && d < sizeof (depth) / sizeof (unsigned); d++) + for (c = 0; !found && c < sizeof (class) / sizeof (int); c++) + { + found = XMatchVisualInfo (xinfo->display, xinfo->screen, + depth [d], class [c], &visual_info); + if (found) + fprintf (stderr, "%s : %d bit colordepth.\n", + class_text [c], depth [d]); + } + if (!found && fiasco_get_verbosity ()) + error ("Can't find a 16/24/32 bit TrueColor/DirectColor display"); + } + + /* Width and height of the display window */ + hint.x = hint.y = 0; + hint.min_width = hint.max_width = hint.width = width; + hint.min_height = hint.max_height = hint.height = height; + hint.flags = PSize | PMinSize | PMaxSize; + + /* Get some colors */ + bg = WhitePixel (xinfo->display, xinfo->screen); + fg = BlackPixel (xinfo->display, xinfo->screen); + + /* Make the window */ + mask = CWBackPixel | CWBorderPixel; + if (visual_info.depth >= 16) + { + mask |= CWColormap; + xswa.colormap = XCreateColormap (xinfo->display, + DefaultRootWindow (xinfo->display), + visual_info.visual, AllocNone); + } + xswa.background_pixel = bg; + xswa.border_pixel = fg; + xinfo->window = XCreateWindow (xinfo->display, + DefaultRootWindow (xinfo->display), 0, 0, + width, height, 1, visual_info.depth, + InputOutput, visual_info.visual, + mask, &xswa); + + XSelectInput (xinfo->display, xinfo->window, StructureNotifyMask); + + /* Tell other applications about this window */ + XSetStandardProperties (xinfo->display, xinfo->window, titlename, iconname, + None, NULL, 0, &hint); + + /* Map window. */ + XMapWindow (xinfo->display, xinfo->window); + + /* Wait for map. */ + do + { + XNextEvent (xinfo->display, &xev); + } + while (xev.type != MapNotify || xev.xmap.event != xinfo->window); + + /* Allocate colors */ + + return xinfo; +} + +void +alloc_ximage (x11_info_t *xinfo, unsigned width, unsigned height) +/* + * Allocate ximage of size 'width'x'height'. + * If USE_SHM is defined then use shared memory extensions. + * + * No return value. + * + * Side effects: + * 'ximage->ximage' and 'ximage->pixels' are set to useful values. + */ +{ + char dummy; + +#ifdef USE_SHM + if (XShmQueryExtension(xinfo->display)) + { + if (fiasco_get_verbosity ()) + fprintf (stderr, "Trying shared memory.\n"); + shmem_flag = 1; + } + else + { + shmem_flag = 0; + if (fiasco_get_verbosity ()) + fprintf (stderr, + "Shared memory not supported\nReverting to normal Xlib.\n"); + } + + if (shmem_flag) + CompletionType = XShmGetEventBase (xinfo->display) + ShmCompletion; + + InstallXErrorHandler (xinfo); + + if (shmem_flag) + { + xinfo->ximage = XShmCreateImage (xinfo->display, + DefaultVisual (xinfo->display, + xinfo->screen), + DefaultDepth (xinfo->display, + xinfo->screen), ZPixmap, + NULL, &shminfo1, width, height); + + /* If no go, then revert to normal Xlib calls. */ + + if (xinfo->ximage == NULL) + { + if (fiasco_get_verbosity ()) + fprintf (stderr, + "Shared memory error, disabling (Ximage error).\n"); + goto shmemerror; + } + + /* Success here, continue. */ + + shminfo1.shmid = shmget (IPC_PRIVATE, xinfo->ximage->bytes_per_line + * xinfo->ximage->height, IPC_CREAT | 0777); + + if (shminfo1.shmid < 0) + { + XDestroyImage (xinfo->ximage); + if (fiasco_get_verbosity ()) + fprintf (stderr, + "Shared memory error, disabling (seg id error).\n"); + goto shmemerror; + } + + shminfo1.shmaddr = (char *) shmat (shminfo1.shmid, 0, 0); + shminfo2.shmaddr = (char *) shmat (shminfo2.shmid, 0, 0); + + if (shminfo1.shmaddr == ((char *) -1)) + { + XDestroyImage (xinfo->ximage); + if (shminfo1.shmaddr != ((char *) -1)) + shmdt (shminfo1.shmaddr); + if (fiasco_get_verbosity ()) + fprintf (stderr, + "Shared memory error, disabling (address error).\n"); + goto shmemerror; + } + + xinfo->ximage->data = shminfo1.shmaddr; + xinfo->pixels = (byte_t *) xinfo->ximage->data; + shminfo1.readOnly = False; + + XShmAttach (xinfo->display, &shminfo1); + XSync (xinfo->display, False); + + if (gXErrorFlag) + { + /* Ultimate failure here. */ + XDestroyImage (xinfo->ximage); + shmdt (shminfo1.shmaddr); + if (fiasco_get_verbosity ()) + fprintf (stderr, "Shared memory error, disabling.\n"); + gXErrorFlag = 0; + goto shmemerror; + } + else + shmctl (shminfo1.shmid, IPC_RMID, 0); + if (fiasco_get_verbosity ()) + fprintf (stderr, "Sharing memory.\n"); + } + else + { + shmemerror: + shmem_flag = 0; +#endif /* USE_SHM */ + + xinfo->ximage = XCreateImage (xinfo->display, + DefaultVisual (xinfo->display, + xinfo->screen), + DefaultDepth (xinfo->display, + xinfo->screen), + ZPixmap, 0, &dummy, width, height, 8, 0); + xinfo->pixels = calloc (width * height, + xinfo->ximage->depth <= 8 + ? sizeof (byte_t) + : (xinfo->ximage->depth <= 16 + ? sizeof (u_word_t) : sizeof (unsigned int))); + if (!xinfo->pixels) + error ("Out of memory."); + +#ifdef USE_SHM + } + + DeInstallXErrorHandler (xinfo); +#endif /* USE_SHM */ +} + +#endif /* not X_DISPLAY_MISSING */ diff --git a/converter/other/fiasco/display.h b/converter/other/fiasco/display.h new file mode 100644 index 00000000..5f30b117 --- /dev/null +++ b/converter/other/fiasco/display.h @@ -0,0 +1,49 @@ +/* + * display.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:51:17 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#ifndef _DISPLAY_H +#define _DISPLAY_H + +#ifndef X_DISPLAY_MISSING + +#include <X11/Xlib.h> + +#include "types.h" +#include "image.h" + +typedef struct x11_info +{ + Display *display; + int screen; /* default screen number */ + Window window; + XImage *ximage; + GC gc; + byte_t *pixels; +} x11_info_t; + +void +display_image (unsigned x0, unsigned y0, x11_info_t *xinfo); +void +close_window (x11_info_t *xinfo); +x11_info_t * +open_window (const char *titlename, const char *iconname, + unsigned width, unsigned height); +void +alloc_ximage (x11_info_t *xinfo, unsigned width, unsigned height); + +#endif /* X_DISPLAY_MISSING */ + +#endif /* not _DISPLAY_H */ diff --git a/converter/other/fiasco/doc/README.LIB b/converter/other/fiasco/doc/README.LIB new file mode 100644 index 00000000..4bf8c382 --- /dev/null +++ b/converter/other/fiasco/doc/README.LIB @@ -0,0 +1,51 @@ +--------------------------------------------------------------------------- + FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec) + Copyright (C) 1994-2000 + Ullrich Hafner <hafner@bigfoot.de>, http://ulli.linuxave.net + Version 1.0 +--------------------------------------------------------------------------- + +FIASCO is an image and video compression system based on fractal +coding which outperforms the well known JPEG and MPEG +standards. FIASCO has been developed during my Ph.D. thesis "Low +Bit-Rate Image and Video Coding with Weighted Finite Automata", Mensch +& Buch Verlag, ISBN 3-89820-002-7. + +Some information about the FIASCO compression library: +The library consists of the five "classes" + + - fiasco_coder: used to encode a still image or a sequence of + frames to a FIASCO stream, see fiasco_coder(3) or the file + bin/cwfa.c for details. + + - fiasco_decoder: used to decode the individual frames step by + step, see fiasco_decoder(3) or the file bin/dwfa.c for + details. + + - fiasco_image: internal representation of an decoded FIASCO + image, see fiasco_image(3) or the file bin/dwfa.c for + details. + + - fiasco_renderer: used to render the generated image object + to one of the supported X11 output formats, see + fiasco_render(3) or the files bin/dwfa.c or bin/pnmpsnr.c for + details. + + - fiasco_options: used to control various decoder and encoder + options, see fiasco_options(3) or the files bin/cwfa.c, + bin/dwfa.c or bin/pnmpsnr.c for details. + + +Since the coder doesn't store any internal information, the only +method of this class is the function fiasco_coder (). + +For all other classes, a new object is created with the +fiasco_[object]_new () function, e.g., fiasco_decoder_new () creates a +new fiasco_decoder_t object. Each object has to be deleted manually by +calling the destructor fiasco_[object]_delete () (or by calling the +method object->delete (object)). If you prefer C++ calls: every +function of the type fiasco_[object]_[method] can be called via +[object]->[method] ([object], args), too. + +Note: PLEASE use only functions, which are noted in the fiasco.h file +(i.e., all functions and types with the prefix fiasco_)! diff --git a/converter/other/fiasco/doc/fiasco_c_options.3 b/converter/other/fiasco/doc/fiasco_c_options.3 new file mode 100644 index 00000000..58b2da44 --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_c_options.3 @@ -0,0 +1 @@ +.so man3/fiasco_c_options_new.3 diff --git a/converter/other/fiasco/doc/fiasco_c_options_delete.3 b/converter/other/fiasco/doc/fiasco_c_options_delete.3 new file mode 100644 index 00000000..58b2da44 --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_c_options_delete.3 @@ -0,0 +1 @@ +.so man3/fiasco_c_options_new.3 diff --git a/converter/other/fiasco/doc/fiasco_c_options_new.3 b/converter/other/fiasco/doc/fiasco_c_options_new.3 new file mode 100644 index 00000000..52efb86c --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_c_options_new.3 @@ -0,0 +1,432 @@ +.\" $Id: fiasco_c_options_new.3,v 1.1 2000/10/28 17:35:06 hafner Exp $ +.TH fiasco 3 "April, 2000" "FIASCO" "Fractal Image And Sequence COdec" + +.SH NAME +.B fiasco_c_options_new, fiasco_c_options_delete, +.B fiasco_c_options_set_progress_meter, fiasco_c_options_set_basisfile, +.B fiasco_c_options_set_smoothing, fiasco_c_options_set_tiling, +.B fiasco_c_options_set_chroma_quality, fiasco_c_options_set_optimizations, +.B fiasco_c_options_set_prediction, fiasco_c_options_set_video_param, +.B fiasco_c_options_set_quantization, fiasco_c_options_set_frame_pattern +.B fiasco_c_options_set_title, fiasco_c_options_set_comment +\- define additional options of FIASCO coder and decoder + +.SH SYNOPSIS +.B #include <fiasco.h> +.sp +.BI "fiasco_c_options_t *" +.fi +.BI "fiasco_c_options_new" +.fi +.BI " (void);" +.sp +.BI "void" +.fi +.BI "fiasco_c_options_delete" +.fi +.BI " (fiasco_c_options_t * "options ); +.sp +.BI "int" +.fi +.BI "fiasco_c_options_set_basisfile" +.fi +.BI " (fiasco_c_options_t * "options , +.fi +.BI " const char * "filename ); +.sp +.BI "int" +.fi +.BI "fiasco_c_options_set_chroma_quality" +.fi +.BI " (fiasco_c_options_t * "options , +.fi +.BI " float "quality_factor , +.fi +.BI " unsigned "dictionary_size ); +.sp +.BI "int" +.fi +.BI "fiasco_c_options_set_comment" +.fi +.BI " (fiasco_c_options_t * "options , +.fi +.BI " const char * "comment ); +.sp +.BI "int" +.fi +.BI "fiasco_c_options_set_frame_pattern" +.fi +.BI " (fiasco_c_options_t * "options , +.fi +.BI " const char * "pattern ); +.sp +.BI "int" +.fi +.BI "fiasco_c_options_set_optimizations" +.fi +.BI " (fiasco_c_options_t * "options , +.fi +.BI " unsigned "min_block_level , +.fi +.BI " unsigned "max_block_level , +.fi +.BI " unsigned "max_elements , +.fi +.BI " unsigned "dictionary_size , +.fi +.BI " unsigned "optimization_level ); +.sp +.BI "int" +.fi +.BI "fiasco_c_options_set_quantization" +.fi +.BI " (fiasco_c_options_t * "options , +.fi +.BI " unsigned "mantissa , +.fi +.BI " fiasco_rpf_range_e "range , +.fi +.BI " unsigned "dc_mantissa , +.fi +.BI " fiasco_rpf_range_e "dc_range ); +.sp +.BI "int" +.fi +.BI "fiasco_c_options_set_prediction" +.fi +.BI " (fiasco_c_options_t * "options , +.fi +.BI " int "intra_prediction , +.fi +.BI " unsigned "min_block_level , +.fi +.BI " unsigned "max_block_level ); +.sp +.BI "int" +.fi +.BI "fiasco_c_options_set_progress_meter" +.fi +.BI " (fiasco_c_options_t * "options , +.fi +.BI " fiasco_progress_e "type ); +.sp +.BI "int" +.fi +.BI "fiasco_c_options_set_smoothing" +.fi +.BI " (fiasco_c_options_t * "options , +.fi +.BI " unsigned "smoothing ); +.sp +.BI "int" +.fi +.BI "fiasco_c_options_set_tiling" +.fi +.BI " (fiasco_c_options_t * "options , +.fi +.BI " fiasco_tiling_e "method , +.fi +.BI " unsigned "exponent ); +.sp +.BI "int" +.fi +.BI "fiasco_c_options_set_title" +.fi +.BI " (fiasco_c_options_t * "options , +.fi +.BI " const char * "title ); +.sp +.BI "int" +.fi +.BI "fiasco_c_options_set_video_param" +.fi +.BI " (fiasco_c_options_t * "options , +.fi +.BI " unsigned "frames_per_second , +.fi +.BI " int "half_pixel_prediction , +.fi +.BI " int "cross_B_search , +.fi +.BI " int "B_as_past_ref ); +.fi + +.SH DESCRIPTION +The \fBfiasco_c_options_new()\fP function allocates and initializes a +FIASCO options object which is used to control additional compression + parameters. + +Conversely, the function \fBfiasco_c_options_delete()\fP discards the +given FIASCO coder options object. + +Several member functions are available to modify the default behavior +of the FIASCO coder. + +\fBfiasco_c_options_set_smoothing()\fP sets the +\fIsmoothing\fP-percentage along partitioning borders when the image +is regenerated; default is 70. This value is stored in the FIASCO file +and is used as default smoothing percentage in the decoder. + +\fBfiasco_c_options_set_frame_pattern()\fP sets the type of inter frame +compression which should be applied to individual frames of a video +stream; default is "IPPPPPPPPP". + +\fBfiasco_c_options_set_tiling()\fP sets \fImethod\fP and \fIexponent\fP +of the image tiling algorithm which runs as initial step of the +encoder; by default the image is subdivided into 16 tiles which +are sorted by decreasing variance. + +\fBfiasco_c_options_set_basisfile()\fP sets the \fIfilename\fP of +the FIASCO initial basis (codebook of dictionary vectors); default is +"small.fco". + +\fBfiasco_c_options_set_chroma_quality()\fP sets the quality used when +coding the chroma channels of a color image to the term "\fIquality\fP +of luminance / \fIquality_factor\fP"; default is 2. Moreover, the size +of the codebook is limited by \fIdictionary_size\fP; default is 40 +elements. + +\fBfiasco_c_options_set_comment()\fP sets a \fIcomment\fP string to be +stored in the FIASCO file; default is the empty string. + +\fBfiasco_c_options_set_title()\fP sets a \fItitle\fP string to be +stored in the FIASCO file; default is the empty string. + +\fBfiasco_c_options_set_optimizations()\fP toggles various coding +optimizations. E.g., the size of the dictionary (default is 10000), +the subset of dictionary elements to use for an individual +approximation (default is 5), the size of the image blocks to consider +(4x4, ..., 64x64), and some additional low level +optimizations (default level is 1). + +\fBfiasco_c_options_set_prediction()\fP enables an additional intra +block prediction by using a DC component approximation. By giving +levels \fImin_block_level\fP and \fImax_block_level\fP the prediction +can be limited to a small range of blocks only. By default, this +method is disabled. + +\fBfiasco_c_options_set_video_param()\fP defines the framerate (default +is 25) and toggles whether to use half pixel precise motion +compensated prediction (disabled by default), whether to determine +motion vectors of interpolated prediction with the Cross-B-Search +algorithm (disabled by default), and whether to allow B frames to be +used for B frame predicion (disabled by default). + +\fBfiasco_c_options_set_quantization()\fP defines the quantization +parameters of the approximation coefficients. By default the range of +DC coefficients is [-1,+1] using a mantissa of 5 bits (and one sign +bit). By default, all other coefficients are quantized with 3 mantissa +bits in the interval [-1.5,+1.5]. + +\fBfiasco_c_options_set_progress_meter()\fP sets the type of progress +meter to be used during coding. By default, an RPM style progress bar +using 50 hash marks (####) is used. + +.SH ARGUMENTS +.TP +options +This object encapsulates various coding parameters. + +.TP +smoothing +This percentage (range is 0 - i.e., no smoothing - to 100) defines how +much the regenerated image is smoothed along the partitioning borders. + +.TP +method +Defines the algorithm which should be used to sort the image tiles +which are generated in the initial coding step. If \fImethod\fP is +\fBFIASCO_VARIANCE_ASC\fP then the tiles are sorted by variance - the +first tile has the lowest variance. Conversely, when using +\fBFIASCO_VARIANCE_DSC\fP the first tile has the largest variance. If +\fImethod\fP is \fBFIASCO_SPIRAL_ASC\fP then the tiles are sorted like +a spiral starting in the middle of the image. Conversely, when using +\fBFIASCO_SPIRAL_DSC\fP the tiles are sorted like a spiral starting in +the upper left corner. + +.TP +exponent +This value sets the number of image tiles - which are generated in the +initial step of the encoder - to 2^\fIexponent\fP. + +.TP +title +This value is the title string of the FIASCO file. It is displayed, e.g., +in the window title of the decoder. + +.TP +comment +This value defines an optional comment to be stored in the FIASCO file. + +.TP +pattern +This string defines the sequence of frame types. Character \fIn\fP of +the string defines the type of frame \fIn\fP (\fIpattern\fP is +periodically extended). Three different frame types are available +(case insensitive): choose 'i' for intra-frames (no inter frame +prediction is used), 'p' for predicted frames (a frame of the +past is used for prediction), or 'b' for bi-directional predicted +frames (both a frame of the past and the future is used for +prediction). + +.TP +filename +The initial basis (codebook) of the coder is loaded from this +(ASCII) file. Files that already come with FIASCO are "small.fco" (3 elements), +"medium.fco" (132 elements), and "large.fco" (219 elements). + +.TP +quality_factor +When coding chroma channels (Cb and Cr band) the approximation quality +is determined by the term `quality of Y component' / \fIquality_factor\fP. + +.TP +dictionary_size +FIASCO uses a dictionary (codebook) of variable size to approximate +individual image blocks. The size of the codebook can be limited by +\fIdictionary_size\fP to reduce the coding time, however, at the cost +of decreasing quality. + +.TP +min_block_level +During coding only those image blocks are considered for approximation +(or prediction) which binary tree level is larger than +\fImin_block_level\fP (minimum value is 3). (Since FIASCO internally +works with binary trees, the size of an image block is determined by +the \fIlevel\fP of the corresponding binary tree). Refer to following +table to convert these values: + +.ce +level | width | height +.fi +------+-------+-------- +.fi + 0 | 1 | 1 +.fi + 1 | 1 | 2 +.fi + 2 | 2 | 2 +.fi + 3 | 2 | 4 +.fi + 4 | 4 | 4 +.fi + 5 | 4 | 8 +.fi + 6 | 8 | 8 +.fi + 7 | 8 | 16 +.fi +------+-------+-------- +.fi +The larger this value is the faster the coder runs but the worse the +image quality will be. + +.TP +max_block_level +During coding only those image blocks are considered for approximation +(or prediction) which binary tree level is smaller than +\fImax_block_level\fP. The smaller this value is the faster the coder +runs but the worse the image quality will be. + +.TP +max_elements +This value defines how many dictionary elements can be +used to approximate an individual image block. The smaller this positive +value (range is 1 to 5) is the faster the coder runs but the worse the +image quality will be. + +.TP +optimization_level +Additional low level optimizations are available by setting +\fIoptimization_level\fP to one of the following values: +.fi +0 standard approximation method +.fi +1 slightly increases the approximation quality, running time is +twice as high as with the standard method +.fi +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) +.fi + +.TP +intra_prediction +If \fIintra_prediction\fP is set to a non-zero value then an +additional block prediction of intra-frames is enabled. For some +images, the image quality is slightly improved, however, at the cost of +a significantly increased running time of the coder. + +.TP +frames_per_second +This value defines the frame rate, i.e., how many frames per second +should be displayed. This value has no effect during coding, it is just +passed to the FIASCO output file where it is read and used by the +decoder. + +.TP +half_pixel_prediction +A non-zero value enables half pixel precise motion compensated +prediction. + +.TP +cross_B_search +A non-zero value enables the fast Cross-B-Search algorithm to determine +the motion vectors of an interpolated prediction. Otherwise, +exhaustive search (in the given search range) is used. + +.TP +B_as_past_ref +A non-zero value allows not only I- and P-frames but also B-frames to be +used for a forward or bi-directional predicion. + +.TP +mantissa, range +Approximation coefficients are quantized to a small number of +values (in fixed point format) in the interval [-\fIrange\fP, ++\fIrange\fP]. The number of \fImantissa\fP bits defines the accuracy of +quantization. + +.TP +dc_mantissa, dc_range +Approximation coefficients of the DC component are quantized in a +different way: the number of mantissa bits is given by +\fIdc_mantissa\fP whereas the quantization interval is given by +[-\fIdc_range\fP, +\fBdc_range\fP]. + +.TP +type +This value sets the \fItype\fP of progress meter which should be used +during coding. The following types are available: +.fi +\fBFIASCO_PROGRESS_NONE\fP: no output at all +.fi +\fBFIASCO_PROGRESS_BAR\fP: print hash marks (###) +\fBFIASCO_PROGRESS_PERCENT\fP: percentage meter (50%) + +.SH RETURN VALUES +The function \fBfiasco_c_options_new()\fP returns a pointer to the +newly allocated coder option object. If an error has been catched, a +NULL pointer is returned. + +All set functions return 1 on success and 0 if an error has been +catched. + +In case of an error, use the function fiasco_get_error_message(3) to +get a string with the last error message of FIASCO. + +.SH "SEE ALSO" +.br +.BR fiasco_decoder "(3), " fiasco_coder (3) + +Ullrich Hafner, Juergen Albert, Stefan Frank, and Michael Unger. +\fBWeighted Finite Automata for Video Compression\fP, IEEE Journal on +Selected Areas In Communications, January 1998 +.br +Ullrich Hafner. \fBLow Bit-Rate Image and Video Coding with Weighted +Finite Automata\fP, Ph.D. thesis, Mensch & Buch Verlag, ISBN +3-89820-002-7, October 1999. + +.SH AUTHOR +Ullrich Hafner <hafner@bigfoot.de> diff --git a/converter/other/fiasco/doc/fiasco_c_options_set_basisfile.3 b/converter/other/fiasco/doc/fiasco_c_options_set_basisfile.3 new file mode 100644 index 00000000..58b2da44 --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_c_options_set_basisfile.3 @@ -0,0 +1 @@ +.so man3/fiasco_c_options_new.3 diff --git a/converter/other/fiasco/doc/fiasco_c_options_set_chroma_quality.3 b/converter/other/fiasco/doc/fiasco_c_options_set_chroma_quality.3 new file mode 100644 index 00000000..58b2da44 --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_c_options_set_chroma_quality.3 @@ -0,0 +1 @@ +.so man3/fiasco_c_options_new.3 diff --git a/converter/other/fiasco/doc/fiasco_c_options_set_comment.3 b/converter/other/fiasco/doc/fiasco_c_options_set_comment.3 new file mode 100644 index 00000000..58b2da44 --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_c_options_set_comment.3 @@ -0,0 +1 @@ +.so man3/fiasco_c_options_new.3 diff --git a/converter/other/fiasco/doc/fiasco_c_options_set_frame_pattern.3 b/converter/other/fiasco/doc/fiasco_c_options_set_frame_pattern.3 new file mode 100644 index 00000000..58b2da44 --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_c_options_set_frame_pattern.3 @@ -0,0 +1 @@ +.so man3/fiasco_c_options_new.3 diff --git a/converter/other/fiasco/doc/fiasco_c_options_set_optimizations.3 b/converter/other/fiasco/doc/fiasco_c_options_set_optimizations.3 new file mode 100644 index 00000000..58b2da44 --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_c_options_set_optimizations.3 @@ -0,0 +1 @@ +.so man3/fiasco_c_options_new.3 diff --git a/converter/other/fiasco/doc/fiasco_c_options_set_prediction.3 b/converter/other/fiasco/doc/fiasco_c_options_set_prediction.3 new file mode 100644 index 00000000..58b2da44 --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_c_options_set_prediction.3 @@ -0,0 +1 @@ +.so man3/fiasco_c_options_new.3 diff --git a/converter/other/fiasco/doc/fiasco_c_options_set_progress_meter.3 b/converter/other/fiasco/doc/fiasco_c_options_set_progress_meter.3 new file mode 100644 index 00000000..58b2da44 --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_c_options_set_progress_meter.3 @@ -0,0 +1 @@ +.so man3/fiasco_c_options_new.3 diff --git a/converter/other/fiasco/doc/fiasco_c_options_set_quantization.3 b/converter/other/fiasco/doc/fiasco_c_options_set_quantization.3 new file mode 100644 index 00000000..58b2da44 --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_c_options_set_quantization.3 @@ -0,0 +1 @@ +.so man3/fiasco_c_options_new.3 diff --git a/converter/other/fiasco/doc/fiasco_c_options_set_smoothing.3 b/converter/other/fiasco/doc/fiasco_c_options_set_smoothing.3 new file mode 100644 index 00000000..58b2da44 --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_c_options_set_smoothing.3 @@ -0,0 +1 @@ +.so man3/fiasco_c_options_new.3 diff --git a/converter/other/fiasco/doc/fiasco_c_options_set_tiling.3 b/converter/other/fiasco/doc/fiasco_c_options_set_tiling.3 new file mode 100644 index 00000000..58b2da44 --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_c_options_set_tiling.3 @@ -0,0 +1 @@ +.so man3/fiasco_c_options_new.3 diff --git a/converter/other/fiasco/doc/fiasco_c_options_set_title.3 b/converter/other/fiasco/doc/fiasco_c_options_set_title.3 new file mode 100644 index 00000000..58b2da44 --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_c_options_set_title.3 @@ -0,0 +1 @@ +.so man3/fiasco_c_options_new.3 diff --git a/converter/other/fiasco/doc/fiasco_c_options_set_video_param.3 b/converter/other/fiasco/doc/fiasco_c_options_set_video_param.3 new file mode 100644 index 00000000..58b2da44 --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_c_options_set_video_param.3 @@ -0,0 +1 @@ +.so man3/fiasco_c_options_new.3 diff --git a/converter/other/fiasco/doc/fiasco_coder.3 b/converter/other/fiasco/doc/fiasco_coder.3 new file mode 100644 index 00000000..3d1c6b87 --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_coder.3 @@ -0,0 +1,106 @@ +.\" $Id: fiasco_coder.3,v 1.2 2000/10/28 17:39:32 hafner Exp $ +.TH fiasco 3 "April, 2000" "FIASCO" "Fractal Image And Sequence COdec" + +.SH NAME +.B fiasco_coder +\- compress image files to a FIASCO file + +.SH SYNOPSIS +.B #include <fiasco.h> +.sp +.BI "int " +.fi +.BI "fiasco_coder (char const * const * "image_names , +.fi +.BI " const char * "fiasco_name , +.fi +.BI " float "quality , +.fi +.BI " const fiasco_c_options_t * "options ); +.fi + +.SH DESCRIPTION +The \fBfiasco-coder()\fP function compresses the image file(s) given +by the list of \fIimage_names\fP and creates the new FIASCO output file +\fIfiasco_name\fP. Besides the approximation \fIquality\fP, several +compression parameters can be adjusted by the class \fBoptions\fP (see +fiasco_c_options_new(3)). + +.SH ARGUMENTS + +.TP +image_names +NULL terminated array of image filenames to process. If the first +array element is "-" or a NULL pointer then FIASCO reads the image +from standard input. Each array element either has to be an image +filename or a template of the form: + +.ce +prefix[start-end{+,-}step]suffix + +Templates are useful when compressing video streams: e.g., if the template +"img0[12-01-2].pgm" is given as array element, then FIASCO compresses the +images img012.pgm, img010.pgm, ..., img002.pgm (in this order). + +If a filename is a relative path then the images are searched for in +the current directory and in the (colon-separated) list of directories +given by the environment variable \fBFIASCO_IMAGES\fP. + +.TP +fiasco_name +Name of the FIASCO output file. If the name is "-" or NULL then the +file is produced on standard output. + +If \fIfiasco_name\fP is a relative path and the environment variable +\fBFIASCO_DATA\fP is a (colon-separated) list of directories, then the +output file is written to the first (writable) directory of this +list. Otherwise, the current directory is used to store the output +file. + +.TP +quality +Defines the quality of compression. Quality has to be a positive +value, its typical range is 1.0 (worst) to 100.0 (best). Larger values +are also allowed - at the cost of exploding encoding times. + +.TP +options +This "class" encapsulates the various coding and decoding +parameters. Use the functions fiasco_c_options_new(3) and +fiasco_c_options_delete(3) to create and delete an object of this +class. Several member functions (see fiasco_c_options(3)) are +available to change the default values. + +.SH RETURN VALUE +The function \fBfiasco_coder()\fP returns 1 if the FIASCO file has +been successfully written. If an error has been catched during +compression, 0 is returned - use the function +fiasco_get_error_message(3) to get the last error message of FIASCO. + +.SH ENVIRONMENT +.PD 0 +.TP +.B FIASCO_IMAGES +Search path for image files. Default is "./". +.TP +.B FIASCO_DATA +Search and save path for FIASCO files. Default is "./". +.PD + +.SH "SEE ALSO" +.br +.BR fiasco_c_options_new "(3), " fiasco_c_options_delete (3), +.br +.BR fiasco_c_options "(3), " fiasco_get_error_message (3) +.br + +Ullrich Hafner, Juergen Albert, Stefan Frank, and Michael Unger. +\fBWeighted Finite Automata for Video Compression\fP, IEEE Journal on +Selected Areas In Communications, January 1998 +.br +Ullrich Hafner. \fBLow Bit-Rate Image and Video Coding with Weighted +Finite Automata\fP, Ph.D. thesis, Mensch & Buch Verlag, ISBN +3-89820-002-7, October 1999. + +.SH AUTHOR +Ullrich Hafner <hafner@bigfoot.de> diff --git a/converter/other/fiasco/doc/fiasco_d_options.3 b/converter/other/fiasco/doc/fiasco_d_options.3 new file mode 100644 index 00000000..21f1db63 --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_d_options.3 @@ -0,0 +1 @@ +.so man3/fiasco_d_options_new.3 diff --git a/converter/other/fiasco/doc/fiasco_d_options_delete.3 b/converter/other/fiasco/doc/fiasco_d_options_delete.3 new file mode 100644 index 00000000..21f1db63 --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_d_options_delete.3 @@ -0,0 +1 @@ +.so man3/fiasco_d_options_new.3 diff --git a/converter/other/fiasco/doc/fiasco_d_options_new.3 b/converter/other/fiasco/doc/fiasco_d_options_new.3 new file mode 100644 index 00000000..4294330a --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_d_options_new.3 @@ -0,0 +1,122 @@ +.\" $Id: fiasco_d_options_new.3,v 1.1 2000/10/28 17:35:12 hafner Exp $ +.TH fiasco 3 "April, 2000" "FIASCO" "Fractal Image And Sequence COdec" + +.SH NAME +.B fiasco_d_options_new, fiasco_d_options_set_magnification, +.B fiasco_d_options_delete, fiasco_d_options_set_smoothing +.B fiasco_d_options_set_4_2_0_format +\- define additional options of FIASCO decoder + +.SH SYNOPSIS +.B #include <fiasco.h> +.sp +.BI "fiasco_d_options_t *" +.fi +.BI "fiasco_d_options_new" +.fi +.BI " (void);" +.sp +.BI "void" +.fi +.BI "fiasco_d_options_delete" +.fi +.BI " (fiasco_d_options_t * "options ); +.sp +.BI "int" +.fi +.BI "fiasco_d_options_set_4_2_0_format" +.fi +.BI " (fiasco_d_options_t * "options , +.fi +.BI " int "format ); +.sp +.BI "int" +.fi +.BI "fiasco_d_options_set_magnification" +.fi +.BI " (fiasco_d_options_t * "options , +.fi +.BI " int "level ); +.sp +.BI "int" +.fi +.BI "fiasco_d_options_set_smoothing" +.fi +.BI " (fiasco_d_options_t * "options , +.fi +.BI " unsigned "smoothing ); +.fi + +.SH DESCRIPTION +The \fBfiasco_d_options_new()\fP function allocates and initializes a +FIASCO options object which is used to control additional +decompression parameters. + +Conversely, the function \fBfiasco_d_options_delete()\fP discards the +given FIASCO decoder options object. + +Several member functions are available to modify the default behavior +of the FIASCO decoder. + +\fBfiasco_d_options_set_smoothing()\fP sets the +\fIsmoothing\fP-percentage along partitioning borders when the images +are regenerated; default is 70. + +\fBfiasco_d_options_set_magnification()\fP sets the \fImagnification\fP +of the regenerated image; default is 0, i.e., the image geometry is +not changed. + +\fBfiasco_d_options_set_4_2_0_format()\fP defines whether the decoder +should use the default 4:4:4 format or the 4:2:0 format. The latter +one significantly reduces the decoding time at the cost of some +additional blocking artefacts. + +.SH ARGUMENTS +.TP +options +This object encapsulates various decoding parameters. + +.TP +smoothing +This percentage (range is 0 - i.e., no smoothing - to 100) defines how +much the regenerated image is smoothed along the partitioning borders. + +.TP +level +This value gives the magnification of the decoded image with respect +to the original size. Positive values increase and negative values +decrease the width and height of the image by a factor of +2^abs(\fIlevel\fP). + +.TP +format +If \fIformat\fP is 0 then the 4:4:4 color image format is used, i.e., +the chroma channel are of the same size as the luminance. Otherwise, +the 4:2:0 format is used. Then, width and height of each chroma +channel is only one half of the width and height of the luminance. + +.SH RETURN VALUES +The function \fBfiasco_d_options_new()\fP returns a pointer to the +newly allocated decoder option object. If an error has been catched, a +NULL pointer is returned. + +All set functions return 1 on success and 0 if an error has been +catched. + +In case of an error, use the function fiasco_get_error_message(3) to +get a string with the last error message of FIASCO. + +.SH "SEE ALSO" +.br +.BR fiasco_decoder "(3), " fiasco_coder (3) + +Ullrich Hafner, Juergen Albert, Stefan Frank, and Michael Unger. +\fBWeighted Finite Automata for Video Compression\fP, IEEE Journal on +Selected Areas In Communications, January 1998 +.br +Ullrich Hafner. \fBLow Bit-Rate Image and Video Coding with Weighted +Finite Automata\fP, Ph.D. thesis, Mensch & Buch Verlag, ISBN +3-89820-002-7, October 1999. + +.SH AUTHOR +Ullrich Hafner <hafner@bigfoot.de> diff --git a/converter/other/fiasco/doc/fiasco_d_options_set_4_2_0_format.3 b/converter/other/fiasco/doc/fiasco_d_options_set_4_2_0_format.3 new file mode 100644 index 00000000..21f1db63 --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_d_options_set_4_2_0_format.3 @@ -0,0 +1 @@ +.so man3/fiasco_d_options_new.3 diff --git a/converter/other/fiasco/doc/fiasco_d_options_set_magnification.3 b/converter/other/fiasco/doc/fiasco_d_options_set_magnification.3 new file mode 100644 index 00000000..21f1db63 --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_d_options_set_magnification.3 @@ -0,0 +1 @@ +.so man3/fiasco_d_options_new.3 diff --git a/converter/other/fiasco/doc/fiasco_d_options_set_smoothing.3 b/converter/other/fiasco/doc/fiasco_d_options_set_smoothing.3 new file mode 100644 index 00000000..21f1db63 --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_d_options_set_smoothing.3 @@ -0,0 +1 @@ +.so man3/fiasco_d_options_new.3 diff --git a/converter/other/fiasco/doc/fiasco_decoder.3 b/converter/other/fiasco/doc/fiasco_decoder.3 new file mode 100644 index 00000000..33c0d21b --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_decoder.3 @@ -0,0 +1 @@ +.so man3/fiasco_decoder_new.3 diff --git a/converter/other/fiasco/doc/fiasco_decoder_delete.3 b/converter/other/fiasco/doc/fiasco_decoder_delete.3 new file mode 100644 index 00000000..33c0d21b --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_decoder_delete.3 @@ -0,0 +1 @@ +.so man3/fiasco_decoder_new.3 diff --git a/converter/other/fiasco/doc/fiasco_decoder_get_comment.3 b/converter/other/fiasco/doc/fiasco_decoder_get_comment.3 new file mode 100644 index 00000000..33c0d21b --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_decoder_get_comment.3 @@ -0,0 +1 @@ +.so man3/fiasco_decoder_new.3 diff --git a/converter/other/fiasco/doc/fiasco_decoder_get_frame.3 b/converter/other/fiasco/doc/fiasco_decoder_get_frame.3 new file mode 100644 index 00000000..33c0d21b --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_decoder_get_frame.3 @@ -0,0 +1 @@ +.so man3/fiasco_decoder_new.3 diff --git a/converter/other/fiasco/doc/fiasco_decoder_get_framerate.3 b/converter/other/fiasco/doc/fiasco_decoder_get_framerate.3 new file mode 100644 index 00000000..33c0d21b --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_decoder_get_framerate.3 @@ -0,0 +1 @@ +.so man3/fiasco_decoder_new.3 diff --git a/converter/other/fiasco/doc/fiasco_decoder_get_height.3 b/converter/other/fiasco/doc/fiasco_decoder_get_height.3 new file mode 100644 index 00000000..33c0d21b --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_decoder_get_height.3 @@ -0,0 +1 @@ +.so man3/fiasco_decoder_new.3 diff --git a/converter/other/fiasco/doc/fiasco_decoder_get_length.3 b/converter/other/fiasco/doc/fiasco_decoder_get_length.3 new file mode 100644 index 00000000..33c0d21b --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_decoder_get_length.3 @@ -0,0 +1 @@ +.so man3/fiasco_decoder_new.3 diff --git a/converter/other/fiasco/doc/fiasco_decoder_get_title.3 b/converter/other/fiasco/doc/fiasco_decoder_get_title.3 new file mode 100644 index 00000000..33c0d21b --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_decoder_get_title.3 @@ -0,0 +1 @@ +.so man3/fiasco_decoder_new.3 diff --git a/converter/other/fiasco/doc/fiasco_decoder_get_width.3 b/converter/other/fiasco/doc/fiasco_decoder_get_width.3 new file mode 100644 index 00000000..33c0d21b --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_decoder_get_width.3 @@ -0,0 +1 @@ +.so man3/fiasco_decoder_new.3 diff --git a/converter/other/fiasco/doc/fiasco_decoder_is_color.3 b/converter/other/fiasco/doc/fiasco_decoder_is_color.3 new file mode 100644 index 00000000..33c0d21b --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_decoder_is_color.3 @@ -0,0 +1 @@ +.so man3/fiasco_decoder_new.3 diff --git a/converter/other/fiasco/doc/fiasco_decoder_new.3 b/converter/other/fiasco/doc/fiasco_decoder_new.3 new file mode 100644 index 00000000..05e981a9 --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_decoder_new.3 @@ -0,0 +1,194 @@ +.\" $Id: fiasco_decoder_new.3,v 1.5 2000/10/28 17:39:32 hafner Exp $ +.TH fiasco 3 "April, 2000" "FIASCO" "Fractal Image And Sequence COdec" + +.SH NAME +.B fiasco_decoder_new, fiasco_decoder_delete, +.B fiasco_decoder_write_frame, fiasco_decoder_get_frame, +.B fiasco_decoder_get_length, fiasco_decoder_get_rate, +.B fiasco_decoder_get_width, fiasco_decoder_get_height +.B fiasco_decoder_get_title, fiasco_decoder_get_comment +.B fiasco_decoder_is_color +\- decompress a FIASCO file + +.SH SYNOPSIS +.B #include <fiasco.h> +.sp +.BI "fiasco_decoder_t *" +.fi +.BI "fiasco_decoder_new (const char * "fiasco_name , +.fi +.BI " const fiasco_d_options_t * "options ); +.sp +.BI "void" +.fi +.BI "fiasco_decoder_delete (fiasco_decoder_t * "decoder ); +.sp +.BI "int" +.fi +.BI "fiasco_decoder_write_frame (fiasco_decoder_t * "decoder , +.fi +.BI " const char * "image_name ); +.sp +.BI "fiasco_image_t *" +.fi +.BI "fiasco_decoder_get_frame (fiasco_decoder_t * "decoder ); +.sp +.BI "unsigned" +.fi +.BI "fiasco_decoder_get_length (fiasco_decoder_t * "decoder ); +.sp +.BI "unsigned" +.fi +.BI "fiasco_decoder_get_rate (fiasco_decoder_t * "decoder ); +.sp +.BI "unsigned" +.fi +.BI "fiasco_decoder_get_width (fiasco_decoder_t * "decoder ); +.sp +.BI "unsigned" +.fi +.BI "fiasco_decoder_get_height (fiasco_decoder_t * "decoder ); +.sp +.BI "const char *" +.fi +.BI "fiasco_decoder_get_title (fiasco_decoder_t * "decoder ); +.sp +.BI "const char *" +.fi +.BI "fiasco_decoder_get_comment (fiasco_decoder_t * "decoder ); +.sp +.BI "int" +.fi +.BI "fiasco_decoder_is_color (fiasco_decoder_t * "decoder ); +.fi + +.SH DESCRIPTION +The \fBfiasco_decoder_new()\fP function initializes the decompression +of FIASCO file \fIfiasco_name\fP. Several decompression parameters +can be adjusted by the class \fIoptions\fP (see +fiasco_d_options_new(3)). + +The individual frames of a FIASCO video can be decompressed by calling +successively either function \fBfiasco_decoder_write_frame()\fP or +\fBfiasco_decoder_get_frame()\fP. + +The function \fBfiasco_decoder_write_frame()\fP decompresses the +current frame and writes it in raw pgm(5) or ppm(5) format to the file +\fIimage_name\fP. If \fIimage_name\fP=- or a NULL pointer then the +image file is produced on the standard output. If \fIimage_name\fP is a +relative path and the environment variable \fBFIASCO_IMAGES\fP is a +(colon-separated) list of directories, then the output file is +written to the first (writable) directory of this list. Otherwise, the +current directory is used to store the file. + +The function \fBfiasco_decoder_get_frame()\fP decompresses the +current frame and returns the computed image object. Use the function +fiasco_renderer_new(3) to create a renderer object that converts the +FIASCO image to the desired format. + +After all frames have been decompressed, the function +\fBfiasco_decoder_delete()\fP should be called to close the input file +and to free temporarily allocated memory. + +Number of available frames, frame rate and frames geometry, type of the +FIASCO file are accessible through member functions +\fBfiasco_decoder_get_length()\fP, +\fBfiasco_decoder_get_rate()\fP, +\fBfiasco_decoder_get_width()\fP, +\fBfiasco_decoder_get_height()\fP, +and \fBfiasco_decoder_is_color()\fP. Use \fBfiasco_decoder_get_title()\fP, +\fBfiasco_decoder_get_comment()\fP to read title and comment strings of the +FIASCO file. + +.SH ARGUMENTS + +.TP +fiasco_name +Filename of the FIASCO input file. If \fIfiasco_name\fP is a NULL pointer +or "-" then the decoder reads from standard input. If the file is not +found in the current directory and the environment variable +\fBFIASCO_DATA\fP is a (colon-separated) list of directories, then the +input file is searched for in these directories, too. + +.TP +options +This "class" encapsulates the various coding and decoding +parameters. Use the functions fiasco_d_options_new(3) and +fiasco_d_options_delete(3) to create and delete an object of this +class. Several member functions (see fiasco_d_options(3)) are +available to change the default values. + +.TP +decoder +The decoder "class" encapsulates the FIASCO decoder. It is used to +store the internal state of the decoder. + +.SH RETURN VALUES +The function \fBfiasco_decoder_new()\fP returns a pointer to the newly +allocated decoder object. If an error has been catched, a NULL pointer +is returned. + +The function \fBfiasco_decoder_write_frame()\fP returns 1 if the file +has been successfully written. Otherwise, the function returns 0. + +The function \fBfiasco_decoder_get_frame()\fP returns a pointer to the +newly allocated FIASCO image object. If an error has been catched, a NULL +pointer is returned. + +The function \fBfiasco_decoder_get_length()\fP returns the number of +frames of the FIASCO file. If an error has been catched, 0 is +returned. + +The function \fBfiasco_decoder_get_rate()\fP returns the +framerate (number of frames per second) of the FIASCO file. If an +error has been catched, 0 is returned. + +The function \fBfiasco_decoder_get_width()\fP returns the width of the +decoded frames of the FIASCO file. If an error has been catched, 0 is +returned. + +The function \fBfiasco_decoder_get_height()\fP returns the height of the +decoded frames of the FIASCO file. If an error has been catched, 0 is +returned. + +The function \fBfiasco_decoder_get_title()\fP returns an optional +title of the FIASCO file. If an error has been catched, 0 is returned. + +The function \fBfiasco_decoder_get_comment()\fP returns an optional +comment of the FIASCO file. If an error has been catched, 0 is returned. + +The function \fBfiasco_decoder_is_color()\fP returns 0 if the decoded +frames are grayscale images, otherwise a non-zero value is +returned. + +In case of an error in one of the above functions, use the function +fiasco_get_error_message(3) to get a string describing the last error +message of FIASCO. + +.SH ENVIRONMENT +.PD 0 +.TP +.B FIASCO_IMAGES +Search path for image files. Default is "./". +.TP +.B FIASCO_DATA +Search and save path for FIASCO files. Default is "./". +.PD + +.SH "SEE ALSO" +.br +.BR fiasco_d_options_new "(3), " fiasco_d_options_delete (3), +.br +.BR fiasco_d_options "(3), " fiasco_get_error_message (3) +.br + +Ullrich Hafner, Juergen Albert, Stefan Frank, and Michael Unger. +\fBWeighted Finite Automata for Video Compression\fP, IEEE Journal on +Selected Areas In Communications, January 1998 +.br +Ullrich Hafner. \fBLow Bit-Rate Image and Video Coding with Weighted +Finite Automata\fP, Ph.D. thesis, Mensch & Buch Verlag, ISBN +3-89820-002-7, October 1999. + +.SH AUTHOR +Ullrich Hafner <hafner@bigfoot.de> diff --git a/converter/other/fiasco/doc/fiasco_decoder_write_frame.3 b/converter/other/fiasco/doc/fiasco_decoder_write_frame.3 new file mode 100644 index 00000000..33c0d21b --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_decoder_write_frame.3 @@ -0,0 +1 @@ +.so man3/fiasco_decoder_new.3 diff --git a/converter/other/fiasco/doc/fiasco_get_error_message.3 b/converter/other/fiasco/doc/fiasco_get_error_message.3 new file mode 100644 index 00000000..09d593fb --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_get_error_message.3 @@ -0,0 +1,41 @@ +.\" $Id: fiasco_get_error_message.3,v 1.1 2000/06/14 19:07:02 hafner Exp $ +.TH fiasco 3 "April, 2000" "FIASCO" "Fractal Image And Sequence COdec" + +.SH NAME +.B fiasco_get_error_message +\- return string describing last error catched in FIASCO library + +.SH SYNOPSIS +.B #include <fiasco.h> +.sp +.BI "const char * " +.fi +.BI "fiasco_get_error_message (void);" +.fi + +.SH DESCRIPTION +The \fBfiasco_get_error_message()\fP function returns a string +describing the last error that has been catched in the FIASCO library. + +.SH RETURN VALUE +The function \fBfiasco_get_error_message()\fP returns the appropriate +description string, or an empty string if no error has been catched so +far. + +.SH "SEE ALSO" +.br +.BR fiasco_options "(3), " fiasco_coder (3), +.br +.BR fiasco_decoder "(3), " fiasco_renderer (3) +.br + +Ullrich Hafner, Juergen Albert, Stefan Frank, and Michael Unger. +\fBWeighted Finite Automata for Video Compression\fP, IEEE Journal on +Selected Areas In Communications, January 1998 +.br +Ullrich Hafner. \fBLow Bit-Rate Image and Video Coding with Weighted +Finite Automata\fP, Ph.D. thesis, Mensch & Buch Verlag, ISBN +3-89820-002-7, October 1999. + +.SH AUTHOR +Ullrich Hafner <hafner@bigfoot.de> diff --git a/converter/other/fiasco/doc/fiasco_get_verbosity.3 b/converter/other/fiasco/doc/fiasco_get_verbosity.3 new file mode 100644 index 00000000..884cd19e --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_get_verbosity.3 @@ -0,0 +1 @@ +.so man3/fiasco_set_verbosity.3 diff --git a/converter/other/fiasco/doc/fiasco_image.3 b/converter/other/fiasco/doc/fiasco_image.3 new file mode 100644 index 00000000..f8df38d5 --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_image.3 @@ -0,0 +1 @@ +.so man3/fiasco_image_new.3 diff --git a/converter/other/fiasco/doc/fiasco_image_delete.3 b/converter/other/fiasco/doc/fiasco_image_delete.3 new file mode 100644 index 00000000..f8df38d5 --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_image_delete.3 @@ -0,0 +1 @@ +.so man3/fiasco_image_new.3 diff --git a/converter/other/fiasco/doc/fiasco_image_get_height.3 b/converter/other/fiasco/doc/fiasco_image_get_height.3 new file mode 100644 index 00000000..f8df38d5 --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_image_get_height.3 @@ -0,0 +1 @@ +.so man3/fiasco_image_new.3 diff --git a/converter/other/fiasco/doc/fiasco_image_get_width.3 b/converter/other/fiasco/doc/fiasco_image_get_width.3 new file mode 100644 index 00000000..f8df38d5 --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_image_get_width.3 @@ -0,0 +1 @@ +.so man3/fiasco_image_new.3 diff --git a/converter/other/fiasco/doc/fiasco_image_is_color.3 b/converter/other/fiasco/doc/fiasco_image_is_color.3 new file mode 100644 index 00000000..f8df38d5 --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_image_is_color.3 @@ -0,0 +1 @@ +.so man3/fiasco_image_new.3 diff --git a/converter/other/fiasco/doc/fiasco_image_new.3 b/converter/other/fiasco/doc/fiasco_image_new.3 new file mode 100644 index 00000000..10625b63 --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_image_new.3 @@ -0,0 +1,95 @@ +.\" $Id: fiasco_image_new.3,v 1.2 2000/06/14 19:26:06 hafner Exp $ +.TH fiasco 3 "April, 2000" "FIASCO" "Fractal Image And Sequence COdec" + +.SH NAME +.B fiasco_image_new, fiasco_image_delete, fiasco_image_get_width, +.B fiasco_image_get_height, fiasco_image_is_color +\- handle FIASCO image objects + +.SH SYNOPSIS +.B #include <fiasco.h> +.sp +.BI "fiasco_image_t *" +.fi +.BI "fiasco_image_new (const char * "filename ); +.sp +.BI "void" +.fi +.BI "fiasco_image_delete (fiasco_image_t * "image ); +.sp +.BI "unsigned" +.fi +.BI "fiasco_image_get_width (const fiasco_image_t * "image ); +.sp +.BI "unsigned" +.fi +.BI "fiasco_image_get_height (const fiasco_image_t * "image ); +.sp +.BI "int" +.fi +.BI "fiasco_image_is_color (const fiasco_image_t * "image ); +.fi + +.SH DESCRIPTION +The \fBfiasco_image_new()\fP function reads the given image file and +allocates and initializes a FIASCO image object. Use the function +fiasco_renderer_new(3) to create a renderer object that converts the +FIASCO image to the desired image format. + +The function \fBfiasco_image_delete()\fP deletes the image object and +frees the image buffer. + +Image geometry and type are accessible through member functions +\fBfiasco_image_get_width()\fP, +\fBfiasco_image_get_height()\fP, +and \fBfiasco_image_is_color()\fP. + +.SH ARGUMENTS + +.TP +image +The image "class" encapsulates the FIASCO image object. It is used to +store the pixel values of the decoded or read image. + +.TP +filename +Image filename to process. If \fIfilename\fP is "-" or a NULL pointer +then the image is read from standard input. If a filename is a +relative path then the images are searched for in the current +directory and in the (colon-separated) list of directories given by +the environment variable \fBFIASCO_IMAGES\fP. + +.SH RETURN VALUE +The function \fBfiasco_image_new()\fP returns a pointer to the newly +allocated image object. If an error has been catched, a NULL pointer +is returned. + +The function \fBfiasco_image_get_width()\fP returns the width of the +image. If an error has been catched, 0 is returned. + +The function \fBfiasco_image_get_height()\fP returns the height of the +image. If an error has been catched, 0 is returned. + +The function \fBfiasco_image_is_color()\fP returns 0 if the image +object is a grayscale image, otherwise a non-zero value is returned. + +In case of an error in one of the above functions, use the function +fiasco_get_error_message(3) to get a string with the last error +message of FIASCO. + +.SH "SEE ALSO" +.br +.BR fiasco_decoder_get_frame "(3), " fiasco_get_error_message (3) +.BR fiasco_renderer_new (3) +.br + +Ullrich Hafner, Juergen Albert, Stefan Frank, and Michael Unger. +\fBWeighted Finite Automata for Video Compression\fP, IEEE Journal on +Selected Areas In Communications, January 1998 +.br +Ullrich Hafner. \fBLow Bit-Rate Image and Video Coding with Weighted +Finite Automata\fP, Ph.D. thesis, Mensch & Buch Verlag, ISBN +3-89820-002-7, October 1999. + +.SH AUTHOR +Ullrich Hafner <hafner@bigfoot.de> diff --git a/converter/other/fiasco/doc/fiasco_options.3 b/converter/other/fiasco/doc/fiasco_options.3 new file mode 100644 index 00000000..493fcce9 --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_options.3 @@ -0,0 +1 @@ +.so man3/fiasco_options_new.3 diff --git a/converter/other/fiasco/doc/fiasco_options_delete.3 b/converter/other/fiasco/doc/fiasco_options_delete.3 new file mode 100644 index 00000000..493fcce9 --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_options_delete.3 @@ -0,0 +1 @@ +.so man3/fiasco_options_new.3 diff --git a/converter/other/fiasco/doc/fiasco_options_new.3 b/converter/other/fiasco/doc/fiasco_options_new.3 new file mode 100644 index 00000000..26e070ca --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_options_new.3 @@ -0,0 +1,441 @@ +.\" $Id: fiasco_options_new.3,v 1.2 2000/06/25 16:38:06 hafner Exp $ +.TH fiasco 3 "April, 2000" "FIASCO" "Fractal Image And Sequence COdec" + +.SH NAME +.B fiasco_options_new, fiasco_options_set_magnification, +.B fiasco_options_delete, fiasco_options_set_progress_meter, +.B fiasco_options_set_smoothing, fiasco_options_set_tiling, +.B fiasco_options_set_4_2_0_format, fiasco_options_set_basisfile, +.B fiasco_options_set_chroma_quality, fiasco_options_set_optimizations, +.B fiasco_options_set_prediction, fiasco_options_set_video_param, +.B fiasco_options_set_quantization, fiasco_options_set_frame_pattern +\- define additional options of FIASCO coder and decoder + +.SH SYNOPSIS +.B #include <fiasco.h> +.sp +.BI "fiasco_options_t *" +.fi +.BI "fiasco_options_new" +.fi +.BI " (void);" +.sp +.BI "void" +.fi +.BI "fiasco_options_delete" +.fi +.BI " (fiasco_options_t * "options ); +.sp +.BI "int" +.fi +.BI "fiasco_options_set_4_2_0_format" +.fi +.BI " (fiasco_options_t * "options , +.fi +.BI " int "format ); +.sp +.BI "int" +.fi +.BI "fiasco_options_set_basisfile" +.fi +.BI " (fiasco_options_t * "options , +.fi +.BI " const char * "filename ); +.sp +.BI "int" +.fi +.BI "fiasco_options_set_chroma_quality" +.fi +.BI " (fiasco_options_t * "options , +.fi +.BI " float "quality_factor , +.fi +.BI " unsigned "dictionary_size ); +.sp +.BI "int" +.fi +.BI "fiasco_options_set_frame_pattern" +.fi +.BI " (fiasco_options_t * "options , +.fi +.BI " const char * "pattern ); +.sp +.BI "int" +.fi +.BI "fiasco_options_set_magnification" +.fi +.BI " (fiasco_options_t * "options , +.fi +.BI " int "level ); +.sp +.BI "int" +.fi +.BI "fiasco_options_set_optimizations" +.fi +.BI " (fiasco_options_t * "options , +.fi +.BI " unsigned "min_block_level , +.fi +.BI " unsigned "max_block_level , +.fi +.BI " unsigned "max_elements , +.fi +.BI " unsigned "dictionary_size , +.fi +.BI " unsigned "optimization_level ); +.sp +.BI "int" +.fi +.BI "fiasco_options_set_quantization" +.fi +.BI " (fiasco_options_t * "options , +.fi +.BI " unsigned "mantissa , +.fi +.BI " fiasco_rpf_range_e "range , +.fi +.BI " unsigned "dc_mantissa , +.fi +.BI " fiasco_rpf_range_e "dc_range ); +.sp +.BI "int" +.fi +.BI "fiasco_options_set_prediction" +.fi +.BI " (fiasco_options_t * "options , +.fi +.BI " int "intra_prediction , +.fi +.BI " unsigned "min_block_level , +.fi +.BI " unsigned "max_block_level ); +.sp +.BI "int" +.fi +.BI "fiasco_options_set_progress_meter" +.fi +.BI " (fiasco_options_t * "options , +.fi +.BI " fiasco_progress_e "type ); +.sp +.BI "int" +.fi +.BI "fiasco_options_set_smoothing" +.fi +.BI " (fiasco_options_t * "options , +.fi +.BI " unsigned "smoothing ); +.sp +.BI "int" +.fi +.BI "fiasco_options_set_tiling" +.fi +.BI " (fiasco_options_t * "options , +.fi +.BI " fiasco_tiling_e "method , +.fi +.BI " unsigned "exponent ); +.sp +.BI "int" +.fi +.BI "fiasco_options_set_video_param" +.fi +.BI " (fiasco_options_t * "options , +.fi +.BI " unsigned "frames_per_second , +.fi +.BI " int "half_pixel_prediction , +.fi +.BI " int "cross_B_search , +.fi +.BI " int "B_as_past_ref ); +.fi + +.SH DESCRIPTION +The \fBfiasco_options_new()\fP function allocates and initializes a +FIASCO options object which is used to control additional compression and +decompression parameters. + +Conversely, the function \fBfiasco_options_delete()\fP discards the +given FIASCO options object. + +Several member functions are available to modify the default behavior +of the FIASCO coder and decoder. + +\fBfiasco_options_set_smoothing()\fP sets the +\fIsmoothing\fP-percentage along partitioning borders when the image +is regenerated; default is 70. This option is used both by the decoder +and encoder. You should use the \fIsmoothing\fP value specified in the +FIASCO file when you are decoding video frames. + +\fBfiasco_options_set_magnification()\fP sets the \fImagnification\fP +of the regenerated image; default is 0, i.e., the image geometry is +not changed. This option is used by the decoder only. + +\fBfiasco_options_set_4_2_0_format()\fP defines whether the decoder +should use the default 4:4:4 format or the 4:2:0 format. The latter +one significantly reduces the decoding time at the cost of some +additional blocking artefacts. This option is used by the decoder only. + +\fBfiasco_options_set_frame_pattern()\fP sets the type of inter frame +compression which should be applied to individual frames of a video +stream; default is "IPPPPPPPPP". + +\fBfiasco_options_set_tiling()\fP sets \fImethod\fP and \fIexponent\fP +of the image tiling algorithm which runs as initial step of the +encoder; by default the image is subdivided into 16 tiles which +are sorted by decreasing variance. + +\fBfiasco_options_set_basisfile()\fP sets the \fIfilename\fP of +the FIASCO initial basis (codebook of dictionary vectors); default is +"small.fco". + +\fBfiasco_options_set_chroma_quality()\fP sets the quality used when +coding the chroma channels of a color image to the term "\fIquality\fP +of luminance / \fIquality_factor\fP"; default is 2. Moreover, the size +of the codebook is limited by \fIdictionary_size\fP; default is 40 +elements. + +\fBfiasco_options_set_optimizations()\fP toggles various coding +optimizations. E.g., the size of the dictionary (default is 10000), +the subset of dictionary elements to use for an individual +approximation (default is 5), the size of the image blocks to consider +(4x4, ..., 64x64), and some additional low level +optimizations (default level is 1). + +\fBfiasco_options_set_prediction()\fP enables an additional intra +block prediction by using a DC component approximation. By giving +levels \fImin_block_level\fP and \fImax_block_level\fP the prediction +can be limited to a small range of blocks only. By default, this +method is disabled. + +\fBfiasco_options_set_video_param()\fP defines the framerate (default +is 25) and toggles whether to use half pixel precise motion +compensated prediction (disabled by default), whether to determine +motion vectors of interpolated prediction with the Cross-B-Search +algorithm (disabled by default), and whether to allow B frames to be +used for B frame predicion (disabled by default). + +\fBfiasco_options_set_quantization()\fP defines the quantization +parameters of the approximation coefficients. By default the range of +DC coefficients is [-1,+1] using a mantissa of 5 bits (and one sign +bit). By default, all other coefficients are quantized with 3 mantissa +bits in the interval [-1.5,+1.5]. + +\fBfiasco_options_set_progress_meter()\fP sets the type of progress +meter to be used during coding. By default, an RPM style progress bar +using 50 hash marks (####) is used. + +.SH ARGUMENTS +.TP +options +This object encapsulates the various coding and decoding parameters. + +.TP +smoothing +This percentage (range is 0 - i.e., no smoothing - to 100) defines how +much the regenerated image is smoothed along the partitioning borders. + +.TP +level +This value gives the magnification of the decoded image with respect +to the original size. Positive values increase and negative values +decrease the width and height of the image by a factor of +2^abs(\fIlevel\fP). + +.TP +format +If \fIformat\fP is 0 then the 4:4:4 color image format is used, i.e., +the chroma channel are of the same size as the luminance. Otherwise, +the 4:2:0 format is used. Then, width and height of each chroma +channel is only one half of the width and height of the luminance. + +.TP +method +Defines the algorithm which should be used to sort the image tiles +which are generated in the initial coding step. If \fImethod\fP is +\fBFIASCO_VARIANCE_ASC\fP then the tiles are sorted by variance - the +first tile has the lowest variance. Conversely, when using +\fBFIASCO_VARIANCE_DSC\fP the first tile has the largest variance. If +\fImethod\fP is \fBFIASCO_SPIRAL_ASC\fP then the tiles are sorted like +a spiral starting in the middle of the image. Conversely, when using +\fBFIASCO_SPIRAL_DSC\fP the tiles are sorted like a spiral starting in +the upper left corner. + +.TP +exponent +This value sets the number of image tiles - which are generated in the +initial step of the encoder - to 2^\fIexponent\fP. + +.TP +pattern +This string defines the sequence of frame types. Character \fIn\fP of +the string defines the type of frame \fIn\fP (\fIpattern\fP is +periodically extended). Three different frame types are available +(case insensitive): choose 'i' for intra-frames (no inter frame +prediction is used), 'p' for predicted frames (a frame of the +past is used for prediction), or 'b' for bi-directional predicted +frames (both a frame of the past and the future is used for +prediction). + +.TP +filename +The initial basis (codebook) of the coder is loaded from this +(ASCII) file. Files that already come with FIASCO are "small.fco" (3 elements), +"medium.fco" (132 elements), and "large.fco" (219 elements). + +.TP +quality_factor +When coding chroma channels (Cb and Cr band) the approximation quality +is determined by the term `quality of Y component' / \fIquality_factor\fP. + +.TP +dictionary_size +FIASCO uses a dictionary (codebook) of variable size to approximate +individual image blocks. The size of the codebook can be limited by +\fIdictionary_size\fP to reduce the coding time, however, at the cost +of decreasing quality. + +.TP +min_block_level +During coding only those image blocks are considered for approximation +(or prediction) which binary tree level is larger than +\fImin_block_level\fP (minimum value is 3). (Since FIASCO internally +works with binary trees, the size of an image block is determined by +the \fIlevel\fP of the corresponding binary tree). Refer to following +table to convert these values: + +.ce +level | width | height +.fi +------+-------+-------- +.fi + 0 | 1 | 1 +.fi + 1 | 1 | 2 +.fi + 2 | 2 | 2 +.fi + 3 | 2 | 4 +.fi + 4 | 4 | 4 +.fi + 5 | 4 | 8 +.fi + 6 | 8 | 8 +.fi + 7 | 8 | 16 +.fi +------+-------+-------- +.fi +The larger this value is the faster the coder runs but the worse the +image quality will be. + +.TP +max_block_level +During coding only those image blocks are considered for approximation +(or prediction) which binary tree level is smaller than +\fImax_block_level\fP. The smaller this value is the faster the coder +runs but the worse the image quality will be. + +.TP +max_elements +This value defines how many dictionary elements can be +used to approximate an individual image block. The smaller this positive +value (range is 1 to 5) is the faster the coder runs but the worse the +image quality will be. + +.TP +optimization_level +Additional low level optimizations are available by setting +\fIoptimization_level\fP to one of the following values: +.fi +0 standard approximation method +.fi +1 slightly increases the approximation quality, running time is +twice as high as with the standard method +.fi +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) +.fi + +.TP +intra_prediction +If \fIintra_prediction\fP is set to a non-zero value then an +additional block prediction of intra-frames is enabled. For some +images, the image quality is slightly improved, however, at the cost of +a significantly increased running time of the coder. + +.TP +frames_per_second +This value defines the frame rate, i.e., how many frames per second +should be displayed. This value has no effect during coding, it is just +passed to the FIASCO output file where it is read and used by the +decoder. + +.TP +half_pixel_prediction +A non-zero value enables half pixel precise motion compensated +prediction. + +.TP +cross_B_search +A non-zero value enables the fast Cross-B-Search algorithm to determine +the motion vectors of an interpolated prediction. Otherwise, +exhaustive search (in the given search range) is used. + +.TP +B_as_past_ref +A non-zero value allows not only I- and P-frames but also B-frames to be +used for a forward or bi-directional predicion. + +.TP +mantissa, range +Approximation coefficients are quantized to a small number of +values (in fixed point format) in the interval [-\fIrange\fP, ++\fIrange\fP]. The number of \fImantissa\fP bits defines the accuracy of +quantization. + +.TP +dc_mantissa, dc_range +Approximation coefficients of the DC component are quantized in a +different way: the number of mantissa bits is given by +\fIdc_mantissa\fP whereas the quantization interval is given by +[-\fIdc_range\fP, +\fBdc_range\fP]. + +.TP +type +This value sets the \fItype\fP of progress meter which should be used +during coding. The following types are available: +.fi +\fBFIASCO_PROGRESS_NONE\fP: no output at all +.fi +\fBFIASCO_PROGRESS_BAR\fP: print hash marks (###) +\fBFIASCO_PROGRESS_PERCENT\fP: percentage meter (50%) + +.SH RETURN VALUES +The function \fBfiasco_decoder_new()\fP returns a pointer to the newly +allocated option object. If an error has been catched, a NULL pointer +is returned. + +All set functions return 1 on success and 0 if an error has been +catched. + +In case of an error, use the function fiasco_get_error_message(3) to +get a string with the last error message of FIASCO. + +.SH "SEE ALSO" +.br +.BR fiasco_decoder "(3), " fiasco_coder (3) + +Ullrich Hafner, Juergen Albert, Stefan Frank, and Michael Unger. +\fBWeighted Finite Automata for Video Compression\fP, IEEE Journal on +Selected Areas In Communications, January 1998 +.br +Ullrich Hafner. \fBLow Bit-Rate Image and Video Coding with Weighted +Finite Automata\fP, Ph.D. thesis, Mensch & Buch Verlag, ISBN +3-89820-002-7, October 1999. + +.SH AUTHOR +Ullrich Hafner <hafner@bigfoot.de> diff --git a/converter/other/fiasco/doc/fiasco_options_set_4_2_0_format.3 b/converter/other/fiasco/doc/fiasco_options_set_4_2_0_format.3 new file mode 100644 index 00000000..493fcce9 --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_options_set_4_2_0_format.3 @@ -0,0 +1 @@ +.so man3/fiasco_options_new.3 diff --git a/converter/other/fiasco/doc/fiasco_options_set_basisfile.3 b/converter/other/fiasco/doc/fiasco_options_set_basisfile.3 new file mode 100644 index 00000000..493fcce9 --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_options_set_basisfile.3 @@ -0,0 +1 @@ +.so man3/fiasco_options_new.3 diff --git a/converter/other/fiasco/doc/fiasco_options_set_chroma_quality.3 b/converter/other/fiasco/doc/fiasco_options_set_chroma_quality.3 new file mode 100644 index 00000000..493fcce9 --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_options_set_chroma_quality.3 @@ -0,0 +1 @@ +.so man3/fiasco_options_new.3 diff --git a/converter/other/fiasco/doc/fiasco_options_set_frame_pattern.3 b/converter/other/fiasco/doc/fiasco_options_set_frame_pattern.3 new file mode 100644 index 00000000..493fcce9 --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_options_set_frame_pattern.3 @@ -0,0 +1 @@ +.so man3/fiasco_options_new.3 diff --git a/converter/other/fiasco/doc/fiasco_options_set_magnification.3 b/converter/other/fiasco/doc/fiasco_options_set_magnification.3 new file mode 100644 index 00000000..493fcce9 --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_options_set_magnification.3 @@ -0,0 +1 @@ +.so man3/fiasco_options_new.3 diff --git a/converter/other/fiasco/doc/fiasco_options_set_optimizations.3 b/converter/other/fiasco/doc/fiasco_options_set_optimizations.3 new file mode 100644 index 00000000..493fcce9 --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_options_set_optimizations.3 @@ -0,0 +1 @@ +.so man3/fiasco_options_new.3 diff --git a/converter/other/fiasco/doc/fiasco_options_set_prediction.3 b/converter/other/fiasco/doc/fiasco_options_set_prediction.3 new file mode 100644 index 00000000..493fcce9 --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_options_set_prediction.3 @@ -0,0 +1 @@ +.so man3/fiasco_options_new.3 diff --git a/converter/other/fiasco/doc/fiasco_options_set_progress_meter.3 b/converter/other/fiasco/doc/fiasco_options_set_progress_meter.3 new file mode 100644 index 00000000..493fcce9 --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_options_set_progress_meter.3 @@ -0,0 +1 @@ +.so man3/fiasco_options_new.3 diff --git a/converter/other/fiasco/doc/fiasco_options_set_quantization.3 b/converter/other/fiasco/doc/fiasco_options_set_quantization.3 new file mode 100644 index 00000000..493fcce9 --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_options_set_quantization.3 @@ -0,0 +1 @@ +.so man3/fiasco_options_new.3 diff --git a/converter/other/fiasco/doc/fiasco_options_set_smoothing.3 b/converter/other/fiasco/doc/fiasco_options_set_smoothing.3 new file mode 100644 index 00000000..493fcce9 --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_options_set_smoothing.3 @@ -0,0 +1 @@ +.so man3/fiasco_options_new.3 diff --git a/converter/other/fiasco/doc/fiasco_options_set_tiling.3 b/converter/other/fiasco/doc/fiasco_options_set_tiling.3 new file mode 100644 index 00000000..493fcce9 --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_options_set_tiling.3 @@ -0,0 +1 @@ +.so man3/fiasco_options_new.3 diff --git a/converter/other/fiasco/doc/fiasco_options_set_video_param.3 b/converter/other/fiasco/doc/fiasco_options_set_video_param.3 new file mode 100644 index 00000000..493fcce9 --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_options_set_video_param.3 @@ -0,0 +1 @@ +.so man3/fiasco_options_new.3 diff --git a/converter/other/fiasco/doc/fiasco_renderer.3 b/converter/other/fiasco/doc/fiasco_renderer.3 new file mode 100644 index 00000000..0aec996e --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_renderer.3 @@ -0,0 +1 @@ +.so man3/fiasco_renderer_new.3 diff --git a/converter/other/fiasco/doc/fiasco_renderer_delete.3 b/converter/other/fiasco/doc/fiasco_renderer_delete.3 new file mode 100644 index 00000000..0aec996e --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_renderer_delete.3 @@ -0,0 +1 @@ +.so man3/fiasco_renderer_new.3 diff --git a/converter/other/fiasco/doc/fiasco_renderer_new.3 b/converter/other/fiasco/doc/fiasco_renderer_new.3 new file mode 100644 index 00000000..b24d8462 --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_renderer_new.3 @@ -0,0 +1,125 @@ +.\" $Id: fiasco_renderer_new.3,v 1.2 2000/06/14 18:58:35 hafner Exp $ +.TH fiasco 3 "April, 2000" "FIASCO" "Fractal Image And Sequence COdec" + +.SH NAME +.B fiasco_renderer_new, fiasco_renderer_delete +\- convert a FIASCO image object to an X11 XImage + +.SH SYNOPSIS +.B #include <fiasco.h> +.sp +.BI "fiasco_renderer_t *" +.fi +.BI "fiasco_renderer_new (unsigned long "red_mask , +.fi +.BI " unsigned long "green_mask , +.fi +.BI " unsigned long "blue_mask , +.fi +.BI " unsigned "bpp , +.fi +.BI " int "double_resolution ); +.sp +.BI "void" +.fi +.BI "fiasco_renderer_delete (fiasco_renderer_t * "renderer ); +.sp +.BI "int" +.fi +.BI "fiasco_renderer_render (const fiasco_renderer_t * "renderer , +.fi +.BI " unsigned char * "data ); +.fi +.BI " const fiasco_image_t * "fiasco_image ); +.fi + +.SH DESCRIPTION +The \fBfiasco_renderer_new()\fP function allocates and initializes a +renderer object which has to be used to convert an internal FIASCO +image object to one of the supported X11 formats. Currently, the FIASCO +image can be rendered to an X11 XImage of either 16, 24, or 32 bits +per pixel. Additional formats will be supported upon request. + +Function \fBfiasco_renderer_render()\fP is used to convert the given +FIASCO image object to the specified format. + +After all frames are rendered, the function +\fBfiasco_renderer_delete()\fP should be called to free temporarily +allocated memory and to discard the renderer object. + +Note that the FIASCO renderer class is not restricted to X11 images: a +FIASCO image object can be converted to an image data array of the +form RGBRGB... by setting \fIred_mask\fP=0xff0000, +\fIgreen_mask\fP=0xff00, \fIblue_mask\fP=0xff, and \fIbpp\fP=24. + +.SH ARGUMENTS + +.TP +bpp +Determines the number of bits of a single pixel of the X11 XImage +structure (see XCreateImage(3)). If the XImage is already allocated +then the value XImage->bits_per_pixel should be used. Currently, 16, +24, and 32 bits per pixel are supported. + +.TP +red_mask +Determines which bits of a pixel should be used for the red +component. If the XImage is already allocated then the value +XImage->red_mask should be used. E.g., if \fIbpp=16\fP and +\fIred_mask=0xf800\fP then each pixel is stored with two bytes. The +red component uses bits 11-15, the remaining green and blue components +use bits 0-10. + +.TP +green_mask +Determines which bits of a pixel should be used for the green +component. If the XImage is already allocated then the value +XImage->green_mask should be used. + +.TP +blue_mask +Determines which bits of a pixel should be used for the blue +component. If the XImage is already allocated then the value +XImage->blue_mask should be used. + +.TP +data +A pointer to the image data. If the XImage is already allocated then +the value XImage->data should be used. This array has to be large +enough to hold the decoded image at the given size (geometry and bits +per pixel). + +.TP +fiasco_image +This object represents the decoded image which has been +created by the FIASCO functions fiasco_decoder_get_frame(3) or +fiasco_image_new(3). + +.SH RETURN VALUE +The function \fBfiasco_renderer_new()\fP returns a pointer to the newly +allocated renderer object. If an error has been catched, a NULL pointer +is returned. + +The function \fBfiasco_renderer_render()\fP returns 1 if the image +has been successfully converted. Otherwise, the function returns 0. + +In case of an error in one of the above functions, use the function +fiasco_get_error_message(3) to get a string with the last error +message of FIASCO. + +.SH "SEE ALSO" +.br +.BR fiasco_decoder_get_frame "(3), " fiasco_get_error_message (3) +.BR fiasco_image_new (3) +.br + +Ullrich Hafner, Juergen Albert, Stefan Frank, and Michael Unger. +\fBWeighted Finite Automata for Video Compression\fP, IEEE Journal on +Selected Areas In Communications, January 1998 +.br +Ullrich Hafner. \fBLow Bit-Rate Image and Video Coding with Weighted +Finite Automata\fP, Ph.D. thesis, Mensch & Buch Verlag, ISBN +3-89820-002-7, October 1999. + +.SH AUTHOR +Ullrich Hafner <hafner@bigfoot.de> diff --git a/converter/other/fiasco/doc/fiasco_renderer_render.3 b/converter/other/fiasco/doc/fiasco_renderer_render.3 new file mode 100644 index 00000000..0aec996e --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_renderer_render.3 @@ -0,0 +1 @@ +.so man3/fiasco_renderer_new.3 diff --git a/converter/other/fiasco/doc/fiasco_set_verbosity.3 b/converter/other/fiasco/doc/fiasco_set_verbosity.3 new file mode 100644 index 00000000..746854b1 --- /dev/null +++ b/converter/other/fiasco/doc/fiasco_set_verbosity.3 @@ -0,0 +1,46 @@ +.\" $Id: fiasco_set_verbosity.3,v 1.1 2000/06/06 20:55:05 hafner Exp $ +.TH fiasco 3 "April, 2000" "FIASCO" "Fractal Image And Sequence COdec" + +.SH NAME +.B fiasco_get_verbosity, fiasco_set_verbosity +\- get or set verbosity of FIASCO library + +.SH SYNOPSIS +.B #include <fiasco.h> +.sp +.BI "fiasco_verbosity_e" +.fi +.BI "fiasco_get_verbosity (void);" +.sp +.BI "void" +.fi +.BI "fiasco_set_verbosity (fiasco_verbosity_e "level ); +.fi + +.SH DESCRIPTION +The \fBfiasco_get_verbosity()\fP function returns the current +verbosity level of the FIASCO library. Conversely, the function +\fBfiasco_set_verbosity()\fP sets the verbosity of the FIASCO library +to the given \fIlevel\fP. + +.SH RETURN VALUE +The function \fBfiasco_get_verbosity()\fP returns the current +verbosity level. Level either is \fBFIASCO_NO_VERBOSITY\fP (no output at +all), \fBFIASCO_SOME_VERBOSITY\fP (show progress meter) or +\fBFIASCO_ULTIMATE_VERBOSITY\fP (show debugging output). + +.SH "SEE ALSO" +.br +.BR fiasco_coder (3), fiasco_decoder (3) +.br + +Ullrich Hafner, Juergen Albert, Stefan Frank, and Michael Unger. +\fBWeighted Finite Automata for Video Compression\fP, IEEE Journal on +Selected Areas In Communications, January 1998 +.br +Ullrich Hafner. \fBLow Bit-Rate Image and Video Coding with Weighted +Finite Automata\fP, Ph.D. thesis, Mensch & Buch Verlag, ISBN +3-89820-002-7, October 1999. + +.SH AUTHOR +Ullrich Hafner <hafner@bigfoot.de> diff --git a/converter/other/fiasco/fiasco.h b/converter/other/fiasco/fiasco.h new file mode 100644 index 00000000..235b1279 --- /dev/null +++ b/converter/other/fiasco/fiasco.h @@ -0,0 +1,425 @@ +/* + * fiasco.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> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + */ + +/* + * $Date: 2000/10/28 17:39:28 $ + * $Author: hafner $ + * $Revision: 5.6 $ + * $State: Exp $ + */ + +#undef __BEGIN_DECLS +#undef __END_DECLS +#ifdef __cplusplus +# define __BEGIN_DECLS extern "C" { +# define __END_DECLS } +#else +# define __BEGIN_DECLS /* empty */ +# define __END_DECLS /* empty */ +#endif + +#ifndef _FIASCO_H +#define _FIASCO_H 1 + +__BEGIN_DECLS + +/**************************************************************************** + FIASCO data types +****************************************************************************/ + +/* + * Verbosity level: + * FIASCO_NO_VERBOSITY: No output at all. + * FIASCO_SOME_VERBOSITY: Show progress meter during coding + * FIASCO_ULTIMATE_VERBOSITY: Show debugging output + */ +typedef enum {FIASCO_NO_VERBOSITY, + FIASCO_SOME_VERBOSITY, + FIASCO_ULTIMATE_VERBOSITY} fiasco_verbosity_e; + +/* + * Image tiling methods: + * 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. + */ +typedef enum {FIASCO_TILING_SPIRAL_ASC, + FIASCO_TILING_SPIRAL_DSC, + FIASCO_TILING_VARIANCE_ASC, + FIASCO_TILING_VARIANCE_DSC} fiasco_tiling_e; + +/* + * Range of reduced precision format: + * FIASCO_RPF_RANGE_0_75: use interval [-0.75,0.75] + * FIASCO_RPF_RANGE_1_00: use interval [-1.00,1.00] + * FIASCO_RPF_RANGE_1_50: use interval [-1.50,0.75] + * FIASCO_RPF_RANGE_2_00: use interval [-2.00,2.00] + */ +typedef enum {FIASCO_RPF_RANGE_0_75, + FIASCO_RPF_RANGE_1_00, + FIASCO_RPF_RANGE_1_50, + FIASCO_RPF_RANGE_2_00} fiasco_rpf_range_e; + +/* + * Type of progress meter to be used during coding + * FIASCO_PROGRESS_NONE: no output at all + * FIASCO_PROGRESS_BAR: RPM style progress bar using 50 hash marks ###### + * FIASCO_PROGRESS_PERCENT: percentage meter 50% + */ +typedef enum {FIASCO_PROGRESS_NONE, + FIASCO_PROGRESS_BAR, + FIASCO_PROGRESS_PERCENT} fiasco_progress_e; + +/* + * Class to encapsulate FIASCO images. + */ +typedef struct fiasco_image +{ + void (*delete) (struct fiasco_image *image); + unsigned (*get_width) (struct fiasco_image *image); + unsigned (*get_height) (struct fiasco_image *image); + int (*is_color) (struct fiasco_image *image); + void *private; +} fiasco_image_t; + +/* + * Class to store internal state of decoder. + */ +typedef struct fiasco_decoder +{ + int (*delete) (struct fiasco_decoder *decoder); + int (*write_frame) (struct fiasco_decoder *decoder, + const char *filename); + fiasco_image_t * (*get_frame) (struct fiasco_decoder *decoder); + unsigned (*get_length) (struct fiasco_decoder *decoder); + unsigned (*get_rate) (struct fiasco_decoder *decoder); + unsigned (*get_width) (struct fiasco_decoder *decoder); + unsigned (*get_height) (struct fiasco_decoder *decoder); + const char * (*get_title) (struct fiasco_decoder *decoder); + const char * (*get_comment) (struct fiasco_decoder *decoder); + int (*is_color) (struct fiasco_decoder *decoder); + void *private; +} fiasco_decoder_t; + +/* + * Class to encapsulate advanced coder options. + */ +typedef struct fiasco_c_options +{ + void (*delete) (struct fiasco_c_options *options); + int (*set_tiling) (struct fiasco_c_options *options, + fiasco_tiling_e method, + unsigned exponent); + int (*set_frame_pattern) (struct fiasco_c_options *options, + const char *pattern); + int (*set_basisfile) (struct fiasco_c_options *options, + const char *filename); + int (*set_chroma_quality) (struct fiasco_c_options *options, + float quality_factor, + unsigned dictionary_size); + int (*set_optimizations) (struct fiasco_c_options *options, + unsigned min_block_level, + unsigned max_block_level, + unsigned max_elements, + unsigned dictionary_size, + unsigned optimization_level); + int (*set_prediction) (struct fiasco_c_options *options, + int intra_prediction, + unsigned min_block_level, + unsigned max_block_level); + int (*set_video_param) (struct fiasco_c_options *options, + unsigned frames_per_second, + int half_pixel_prediction, + int cross_B_search, + int B_as_past_ref); + int (*set_quantization) (struct fiasco_c_options *options, + unsigned mantissa, + fiasco_rpf_range_e range, + unsigned dc_mantissa, + fiasco_rpf_range_e dc_range); + int (*set_progress_meter) (struct fiasco_c_options *options, + fiasco_progress_e type); + int (*set_smoothing) (struct fiasco_c_options *options, + int smoothing); + int (*set_comment) (struct fiasco_c_options *options, + const char *comment); + int (*set_title) (struct fiasco_c_options *options, + const char *title); + void *private; +} fiasco_c_options_t; + +/* + * Class to encapsulate advanced decoder options. + */ +typedef struct fiasco_d_options +{ + void (*delete) (struct fiasco_d_options *options); + int (*set_smoothing) (struct fiasco_d_options *options, + int smoothing); + int (*set_magnification) (struct fiasco_d_options *options, + int level); + int (*set_4_2_0_format) (struct fiasco_d_options *options, + int format); + void *private; +} fiasco_d_options_t; + +/* + * Class to convert internal FIASCO image structure to a XImage structure. + * Method `renderer()' is used to convert internal image to XImage. + * Method `delete()' is used to delete and free internal image. + */ +typedef struct fiasco_renderer +{ + int (*render) (const struct fiasco_renderer *this, + unsigned char *data, + const fiasco_image_t *fiasco_image); + void (*delete) (struct fiasco_renderer *this); + void *private; +} fiasco_renderer_t; + +/**************************************************************************** + miscellaneous functions +****************************************************************************/ + +/* Get last error message of FIASCO library */ +const char *fiasco_get_error_message (void); + +/* Set verbosity of FIASCO library */ +void fiasco_set_verbosity (fiasco_verbosity_e level); + +/* Get verbosity of FIASCO library */ +fiasco_verbosity_e fiasco_get_verbosity (void); + +/**************************************************************************** + decoder functions +****************************************************************************/ + +/* Decode FIASCO image or sequence */ +fiasco_decoder_t *fiasco_decoder_new (const char *filename, + const fiasco_d_options_t *options); + +/* Flush and discard FIASCO decoder */ +int fiasco_decoder_delete (fiasco_decoder_t *decoder); + +/* Decode next FIASCO frame and write to PNM image 'filename' */ +int fiasco_decoder_write_frame (fiasco_decoder_t *decoder, + const char *filename); + +/* Decode next FIASCO frame to FIASCO image structure */ +fiasco_image_t *fiasco_decoder_get_frame (fiasco_decoder_t *decoder); + +/* Get width of FIASCO image or sequence */ +unsigned fiasco_decoder_get_width (fiasco_decoder_t *decoder); + +/* Get height of FIASCO image or sequence */ +unsigned fiasco_decoder_get_height (fiasco_decoder_t *decoder); + +/* Get width of FIASCO image or sequence */ +int fiasco_decoder_is_color (fiasco_decoder_t *decoder); + +/* Get frame rate of FIASCO sequence */ +unsigned fiasco_decoder_get_rate (fiasco_decoder_t *decoder); + +/* Get number of frames of FIASCO file */ +unsigned fiasco_decoder_get_length (fiasco_decoder_t *decoder); + +/* Get title of FIASCO file */ +const char * +fiasco_decoder_get_title (fiasco_decoder_t *decoder); + +/* Get comment of FIASCO file */ +const char * +fiasco_decoder_get_comment (fiasco_decoder_t *decoder); + +/**************************************************************************** + image functions +****************************************************************************/ + +/* Read FIASCO image (raw ppm or pgm format) */ +fiasco_image_t * fiasco_image_new (const char *filename); + +/* Discard FIASCO image */ +void fiasco_image_delete (fiasco_image_t *image); + +/* Get width of FIASCO image or sequence */ +unsigned fiasco_image_get_width (fiasco_image_t *image); + +/* Get height of FIASCO image or sequence */ +unsigned fiasco_image_get_height (fiasco_image_t *image); + +/* Get width of FIASCO image or sequence */ +int fiasco_image_is_color (fiasco_image_t *image); + +/**************************************************************************** + renderer functions +****************************************************************************/ + +/* Constructor of FIASCO image structure to a XImage renderer */ +fiasco_renderer_t * +fiasco_renderer_new (unsigned long red_mask, unsigned long green_mask, + unsigned long blue_mask, unsigned bpp, + int double_resolution); + +/* Destructor of FIASCO image structure to a XImage renderer */ +void +fiasco_renderer_delete (fiasco_renderer_t *renderer); + +/* FIASCO image structure to a XImage renderer */ +int +fiasco_renderer_render (const fiasco_renderer_t *renderer, + unsigned char *ximage, + const fiasco_image_t *fiasco_image); + +/**************************************************************************** + coder functions +****************************************************************************/ + +/* Encode image or sequence by FIASCO */ +int fiasco_coder (char const * const *inputname, + const char *outputname, + float quality, + const fiasco_c_options_t *options); + +/**************************************************************************** + coder options functions +****************************************************************************/ + +/* FIASCO additional options constructor */ +fiasco_c_options_t *fiasco_c_options_new (void); + +/* FIASCO additional options destructor */ +void fiasco_c_options_delete (fiasco_c_options_t *options); + +/* Define `smoothing'-percentage along partitioning borders.*/ +int fiasco_c_options_set_smoothing (fiasco_c_options_t *options, + int smoothing); + +/* Set type of frame prediction for sequence of frames */ +int fiasco_c_options_set_frame_pattern (fiasco_c_options_t *options, + const char *pattern); + +/* Set method and number of tiles for image tiling */ +int fiasco_c_options_set_tiling (fiasco_c_options_t *options, + fiasco_tiling_e method, + unsigned exponent); + +/* Set FIASCO initial basis file */ +int fiasco_c_options_set_basisfile (fiasco_c_options_t *options, + const char *filename); + +/* Set quality and dictionary size of chroma compression */ +int fiasco_c_options_set_chroma_quality (fiasco_c_options_t *options, + float quality_factor, + unsigned dictionary_size); + +/* + * Since FIASCO internally works with binary trees, all functions + * (which are handling image geometry) rather expect the `level' of + * the corresponding binary tree than the traditional `width' and + * `height' arguments. Refer to following table to convert these + * values: + * + * level | width | height + * ------+-------+-------- + * 0 | 1 | 1 + * 1 | 1 | 2 + * 2 | 2 | 2 + * 3 | 2 | 4 + * 4 | 4 | 4 + * 5 | 4 | 8 + * 6 | 8 | 8 + * 7 | 8 | 16 + * + */ + +/* Set various optimization parameters. */ +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 minimum and maximum size of image block prediction */ +int fiasco_c_options_set_prediction (fiasco_c_options_t *options, + int intra_prediction, + unsigned min_block_level, + unsigned max_block_level); + +/* Set various parameters used for video compensation */ +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 accuracy of coefficients quantization */ +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 type of progress meter */ +int fiasco_c_options_set_progress_meter (fiasco_c_options_t *options, + fiasco_progress_e type); + +/* Set comment of FIASCO stream */ +int fiasco_c_options_set_comment (fiasco_c_options_t *options, + const char *comment); + +/* Set title of FIASCO stream */ +int fiasco_c_options_set_title (fiasco_c_options_t *options, + const char *title); + +/**************************************************************************** + decoder options functions +****************************************************************************/ + +/* FIASCO additional options constructor */ +fiasco_d_options_t *fiasco_d_options_new (void); + +/* FIASCO additional options destructor */ +void fiasco_d_options_delete (fiasco_d_options_t *options); + + +/* Define `smoothing'-percentage along partitioning borders.*/ +int fiasco_d_options_set_smoothing (fiasco_d_options_t *options, + int smoothing); + +/* Set magnification-'level' of decoded image */ +int fiasco_d_options_set_magnification (fiasco_d_options_t *options, + int level); + +/* Set image format to 4:2:0 or 4:4:4 */ +int fiasco_d_options_set_4_2_0_format (fiasco_d_options_t *options, + int format); + +__END_DECLS + +#endif /* not _FIASCO_H */ diff --git a/converter/other/fiasco/fiascotopnm.c b/converter/other/fiasco/fiascotopnm.c new file mode 100644 index 00000000..6d8b6f7f --- /dev/null +++ b/converter/other/fiasco/fiascotopnm.c @@ -0,0 +1,477 @@ +/* + * dwfa.c: Decoding of WFA-files + * + * 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/28 17:39:29 $ + * $Author: hafner $ + * $Revision: 5.7 $ + * $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 <stdlib.h> +#include <string.h> +#include <math.h> + +#include "types.h" +#include "macros.h" + +#include <getopt.h> + +#include "binerror.h" +#include "misc.h" +#include "params.h" +#include "fiasco.h" + +#ifndef X_DISPLAY_MISSING + +# include "display.h" +# include "buttons.h" + +static x11_info_t *xinfo = NULL; + +#endif /* not X_DISPLAY_MISSING */ + +/***************************************************************************** + + prototypes + +*****************************************************************************/ + +static int +checkargs (int argc, char **argv, bool_t *double_resolution, bool_t *panel, + int *fps, char **image_name, fiasco_d_options_t **options); +static void +video_decoder (const char *wfa_name, const char *image_name, bool_t panel, + bool_t double_resolution, int fps, fiasco_d_options_t *options); +static void +get_output_template (const char *image_name, const char *wfa_name, + bool_t color, char **basename, char **suffix); + +#ifndef X_DISPLAY_MISSING + +static void +show_stored_frames (unsigned char * const *frame_buffer, int last_frame, + x11_info_t *xinfo, binfo_t *binfo, size_t size, + unsigned frame_time); + +#endif /* not X_DISPLAY_MISSING */ + +/***************************************************************************** + + public code + +*****************************************************************************/ + +int +main (int argc, char **argv) +{ + char *image_name = NULL; /* output filename */ + bool_t double_resolution = NO; /* double resolution of image */ + bool_t panel = NO; /* control panel */ + int fps = -1; /* frame display rate */ + fiasco_d_options_t *options = NULL; /* additional coder options */ + int last_arg; /* last processed cmdline parameter */ + + init_error_handling (argv[0]); + + last_arg = checkargs (argc, argv, &double_resolution, &panel, &fps, + &image_name, &options); + + if (last_arg >= argc) + video_decoder ("-", image_name, panel, double_resolution, fps, options); + else + while (last_arg++ < argc) + video_decoder (argv [last_arg - 1], image_name, panel, + double_resolution, fps, options); + + return 0; +} + +/***************************************************************************** + + private code + +*****************************************************************************/ + +static param_t params [] = +{ +#ifdef X_DISPLAY_MISSING + {"output", "FILE", 'o', PSTR, {0}, "-", + "Write raw PNM frame(s) to `%s'."}, +#else /* not X_DISPLAY_MISSING */ + {"output", "FILE", 'o', POSTR, {0}, NULL, + "Write raw PNM frame(s) to INPUT.ppm/pgm [or `%s']."}, +#endif /* not X_DISPLAY_MISSING */ + {"double", NULL, 'd', PFLAG, {0}, "FALSE", + "Interpolate images to double size before display."}, + {"fast", NULL, 'r', PFLAG, {0}, "FALSE", + "Use 4:2:0 format for fast, low quality output."}, + {"panel", NULL, 'p', PFLAG, {0}, "FALSE", + "Display control panel."}, + {"magnify", "NUM", 'm', PINT, {0}, "0", + "Magnify/reduce image size by a factor of 4^`%s'."}, + {"framerate", "NUM", 'F', PINT, {0}, "-1", + "Set display rate to `%s' frames per second."}, + {"smoothing", "NUM", 's', PINT, {0}, "-1", + "Smooth image(s) by factor `%s' (0-100)"}, + {NULL, NULL, 0, 0, {0}, NULL, NULL } +}; + +static int +checkargs (int argc, char **argv, bool_t *double_resolution, bool_t *panel, + int *fps, char **image_name, fiasco_d_options_t **options) +/* + * Check validness of command line parameters and of the parameter files. + * + * Return value. + * index in argv of the first argv-element that is not an option. + * + * Side effects: + * 'double_resolution', 'panel', 'fps', 'image_name' and 'options' + * are modified. + */ +{ + int optind; /* last processed commandline param */ + + optind = parseargs (params, argc, argv, +#ifdef X_DISPLAY_MISSING + "Decode FIASCO-FILEs and write frame(s) to disk.", +#else /* not X_DISPLAY_MISSING */ + "Decode and display FIASCO-FILEs using X11.", +#endif /* not X_DISPLAY_MISSING */ + "With no FIASCO-FILE, or if FIASCO-FILE is -, " + "read standard input.\n" +#ifndef X_DISPLAY_MISSING + "With --output=[FILE] specified, " + "write frames without displaying them.\n\n" +#endif /* not X_DISPLAY_MISSING */ + "Environment:\n" + "FIASCO_DATA Search path for automata files. " + "Default: ./\n" + "FIASCO_IMAGES Save path for image files. " + "Default: ./", " [FIASCO-FILE]...", + FIASCO_SHARE, "system.fiascorc", ".fiascorc"); + + *image_name = (char *) parameter_value (params, "output"); + *double_resolution = *((bool_t *) parameter_value (params, "double")); + *panel = *((bool_t *) parameter_value (params, "panel")); + *fps = *((int *) parameter_value (params, "framerate")); + + /* + * Additional options ... (have to be set with the fiasco_set_... methods) + */ + *options = fiasco_d_options_new (); + + { + int n = *((int *) parameter_value (params, "smoothing")); + + if (!fiasco_d_options_set_smoothing (*options, max (-1, n))) + error (fiasco_get_error_message ()); + } + + { + int n = *((int *) parameter_value (params, "magnify")); + + if (!fiasco_d_options_set_magnification (*options, n)) + error (fiasco_get_error_message ()); + } + + { + bool_t n = *((bool_t *) parameter_value (params, "fast")); + + if (!fiasco_d_options_set_4_2_0_format (*options, n > 0 ? YES : NO)) + error (fiasco_get_error_message ()); + } + + return optind; +} + +static void +video_decoder (const char *wfa_name, const char *image_name, bool_t panel, + bool_t double_resolution, int fps, fiasco_d_options_t *options) +{ +#ifndef X_DISPLAY_MISSING + fiasco_renderer_t *renderer = NULL; + unsigned char **frame_buffer = NULL; + binfo_t *binfo = NULL; /* buttons info */ +#endif /* not X_DISPLAY_MISSING */ + + do + { + unsigned width, height, frames, n; + fiasco_decoder_t *decoder_state; + char *filename; + char *basename; /* basename of decoded frame */ + char *suffix; /* suffix of decoded frame */ + unsigned frame_time; + + if (!(decoder_state = fiasco_decoder_new (wfa_name, options))) + error (fiasco_get_error_message ()); + + if (fps <= 0) /* then use value of FIASCO file */ + fps = fiasco_decoder_get_rate (decoder_state); + frame_time = fps ? (1000 / fps) : (1000 / 25); + + if (!(width = fiasco_decoder_get_width (decoder_state))) + error (fiasco_get_error_message ()); + + if (!(height = fiasco_decoder_get_height (decoder_state))) + error (fiasco_get_error_message ()); + + if (!(frames = fiasco_decoder_get_length (decoder_state))) + error (fiasco_get_error_message ()); + + get_output_template (image_name, wfa_name, + fiasco_decoder_is_color (decoder_state), + &basename, &suffix); + + filename = calloc (strlen (basename) + strlen (suffix) + 2 + + 10 + (int) (log10 (frames) + 1), sizeof (char)); + if (!filename) + error ("Out of memory."); + + for (n = 0; n < frames; n++) + { + clock_t fps_timer; /* frames per second timer struct */ + + prg_timer (&fps_timer, START); + + if (image_name) /* just write frame to disk */ + { + if (frames == 1) /* just one image */ + { + if (streq (image_name, "-")) + strcpy (filename, "-"); + else + sprintf (filename, "%s.%s", basename, suffix); + } + else + { + fprintf (stderr, "Decoding frame %d to file `%s.%0*d.%s\n", + n, basename, (int) (log10 (frames - 1) + 1), + n, suffix); + sprintf (filename, "%s.%0*d.%s", basename, + (int) (log10 (frames - 1) + 1), n, suffix); + } + + if (!fiasco_decoder_write_frame (decoder_state, filename)) + error (fiasco_get_error_message ()); + } +#ifndef X_DISPLAY_MISSING + else + { + fiasco_image_t *frame; + + if (!(frame = fiasco_decoder_get_frame (decoder_state))) + error (fiasco_get_error_message ()); + + if (frames == 1) + panel = NO; + + if (xinfo == NULL) /* initialize X11 window */ + { + const char * const title = + fiasco_decoder_get_title (decoder_state); + char titlename [MAXSTRLEN]; + + + sprintf (titlename, "dfiasco " VERSION ": %s", + strlen (title) > 0 ? title : wfa_name); + xinfo = + open_window (titlename, "dfiasco", + (width << (double_resolution ? 1 : 0)), + (height << (double_resolution ? 1 : 0)) + + (panel ? 30 : 0)); + alloc_ximage (xinfo, width << (double_resolution ? 1 : 0), + height << (double_resolution ? 1 : 0)); + if (panel) /* initialize button panel */ + binfo = init_buttons (xinfo, n, frames, 30, 10); + renderer = + fiasco_renderer_new (xinfo->ximage->red_mask, + xinfo->ximage->green_mask, + xinfo->ximage->blue_mask, + xinfo->ximage->bits_per_pixel, + double_resolution); + if (!renderer) + error (fiasco_get_error_message ()); + } + renderer->render (renderer, xinfo->pixels, frame); + frame->delete (frame); + + if (frame_buffer != NULL) /* store next frame */ + { + size_t size = (width << (double_resolution ? 1 : 0)) + * (height << (double_resolution ? 1 : 0)) + * (xinfo->ximage->depth <= 8 + ? sizeof (byte_t) + : (xinfo->ximage->depth <= 16 + ? sizeof (u_word_t) + : sizeof (unsigned int))); + + frame_buffer [n] = malloc (size); + if (!frame_buffer [n]) + error ("Out of memory."); + memcpy (frame_buffer [n], xinfo->pixels, size); + + if (n == frames - 1) + { + show_stored_frames (frame_buffer, frames - 1, + xinfo, binfo, size, frame_time); + break; + } + } + + display_image (0, 0, xinfo); + if (frames == 1) + wait_for_input (xinfo); + else if (panel) + { + check_events (xinfo, binfo, n, frames); + if (binfo->pressed [QUIT_BUTTON]) + /* start from beginning */ + break; + if (binfo->pressed [STOP_BUTTON]) + /* start from beginning */ + n = frames; + + if (binfo->pressed [RECORD_BUTTON] && frame_buffer == NULL) + { + n = frames; + frame_buffer = + calloc (frames, sizeof (unsigned char *)); + if (!frame_buffer) + error ("Out of memory."); + } + } + while (prg_timer (&fps_timer, STOP) < frame_time) /* wait */ + ; + } +#endif /* not X_DISPLAY_MISSING */ + } + free (filename); + + fiasco_decoder_delete (decoder_state); + } while (panel + +#ifndef X_DISPLAY_MISSING + && !binfo->pressed [QUIT_BUTTON] +#endif /* not X_DISPLAY_MISSING */ + + ); + +#ifndef X_DISPLAY_MISSING + if (renderer) + renderer->delete (renderer); + + if (!image_name) + { + close_window (xinfo); + free (xinfo); + xinfo = NULL; + if (binfo) + free (binfo); + } +#endif /* not X_DISPLAY_MISSING */ +} + +static void +get_output_template (const char *image_name, const char *wfa_name, + bool_t color, char **basename, char **suffix) +/* + * Generate image filename template for output of image sequences. + * 'wfa_name' is the filename of the WFA stream. + * Images are either saved with filename 'basename'.'suffix' (still images) + * or 'basename'.%03d.'suffix' (videos). + * + * No return value. + * + * Side effects: + * '*basename' and '*suffix' is set. + */ +{ + if (!wfa_name || streq (wfa_name, "-")) + wfa_name = "stdin"; + /* + * Generate filename template + */ + if (!image_name || streq (image_name, "") || streq (image_name, "-")) + { + *basename = strdup (wfa_name); + *suffix = NULL; + } + else + { + *basename = strdup (image_name); + *suffix = strrchr (*basename, '.'); + } + + if (*suffix) /* found name 'basename.suffix' */ + { + **suffix = 0; /* remove dot */ + (*suffix)++; + if (**suffix == 0) + *suffix = strdup (color ? "ppm" : "pgm"); + } + else /* no suffix found, generate one */ + *suffix = strdup (color ? "ppm" : "pgm"); +} + +#ifndef X_DISPLAY_MISSING + +static void +show_stored_frames (unsigned char * const *frame_buffer, int last_frame, + x11_info_t *xinfo, binfo_t *binfo, size_t size, + unsigned frame_time) +/* + * After a WFA video stream has been saved, all frames have been + * decoded and stored in memory. These frames are then displayed + * in an endless loop. + * + * This function never returns, the program is terminated if the + * STOP button is pressed. + */ +{ + int n = last_frame; /* frame number */ + + while (1) + { + clock_t fps_timer; /* frames per second timer struct */ + + prg_timer (&fps_timer, START); + + display_image (0, 0, xinfo); + check_events (xinfo, binfo, n, last_frame + 1); + + if (binfo->pressed [STOP_BUTTON]) + n = 0; + else if (binfo->pressed [QUIT_BUTTON]) + break; + else if (binfo->pressed [PLAY_BUTTON]) + n++; + else if (binfo->pressed [RECORD_BUTTON]) /* REWIND is mapped RECORD */ + n--; + if (n < 0) + n = last_frame; + if (n > last_frame) + n = 0; + + memcpy (xinfo->pixels, frame_buffer [n], size); + while (prg_timer (&fps_timer, STOP) < frame_time) /* wait */ + ; + }; +} + +#endif /* not X_DISPLAY_MISSING */ diff --git a/converter/other/fiasco/getopt.c b/converter/other/fiasco/getopt.c new file mode 100644 index 00000000..0b2d1b75 --- /dev/null +++ b/converter/other/fiasco/getopt.c @@ -0,0 +1,1002 @@ +/* Getopt for GNU. + NOTE: getopt is now part of the C library, so if you don't know what + "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu + before changing it! + + Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97 + Free Software Foundation, Inc. + + This file is part of the GNU C Library. Its master source is NOT part of + the C library, however. The master source lives in /gd/gnu/lib. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>. + Ditto for AIX 3.2 and <stdlib.h>. */ +#ifndef _NO_PROTO +#define _NO_PROTO +#endif + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#if !defined (__STDC__) || !__STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +#ifndef const +#define const +#endif +#endif + +#include <string.h> +#include <stdio.h> + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#define GETOPT_INTERFACE_VERSION 2 +#if !defined (_LIBC) && defined (__GLIBC__) && __GLIBC__ >= 2 +#include <gnu-versions.h> +#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION +#define ELIDE_CODE +#endif +#endif + +#ifndef ELIDE_CODE + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +/* Don't include stdlib.h for non-GNU C libraries because some of them + contain conflicting prototypes for getopt. */ +#include <stdlib.h> +#include <unistd.h> +#endif /* GNU C library. */ + +#ifdef VMS +#include <unixlib.h> +#if HAVE_STRING_H - 0 +#include <string.h> +#endif +#endif + +#if defined (WIN32) && !defined (__CYGWIN32__) +/* It's not Unix, really. See? Capital letters. */ +#include <windows.h> +#define getpid() GetCurrentProcessId() +#endif + +#ifndef _ +/* This is for other GNU distributions with internationalized messages. + When compiling libc, the _ macro is predefined. */ +#ifdef HAVE_LIBINTL_H +# include <libintl.h> +# define _(msgid) gettext (msgid) +#else +# define _(msgid) (msgid) +#endif +#endif + +/* This version of `getopt' appears to the caller like standard Unix `getopt' + but it behaves differently for the user, since it allows the user + to intersperse the options with the other arguments. + + As `getopt' works, it permutes the elements of ARGV so that, + when it is done, all the options precede everything else. Thus + all application programs are extended to handle flexible argument order. + + Setting the environment variable POSIXLY_CORRECT disables permutation. + Then the behavior is completely standard. + + GNU application programs can use a third alternative mode in which + they can distinguish the relative order of options and other arguments. */ + +#include "getopt.h" + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +char *optarg = NULL; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +/* 1003.2 says this must be 1 before any call. */ +int optind = 1; + +/* Formerly, initialization of getopt depended on optind==0, which + causes problems with re-calling getopt as programs generally don't + know that. */ + +int __getopt_initialized = 0; + +/* The next char to be scanned in the option-element + in which the last option character we returned was found. + This allows us to pick up the scan where we left off. + + If this is zero, or a null string, it means resume the scan + by advancing to the next ARGV-element. */ + +static char *nextchar; + +/* Callers store zero here to inhibit the error message + for unrecognized options. */ + +int opterr = 1; + +/* Set to an option character which was unrecognized. + This must be initialized on some systems to avoid linking in the + system's own getopt implementation. */ + +int optopt = '?'; + +/* Describe how to deal with options that follow non-option ARGV-elements. + + If the caller did not specify anything, + the default is REQUIRE_ORDER if the environment variable + POSIXLY_CORRECT is defined, PERMUTE otherwise. + + REQUIRE_ORDER means don't recognize them as options; + stop option processing when the first non-option is seen. + This is what Unix does. + This mode of operation is selected by either setting the environment + variable POSIXLY_CORRECT, or using `+' as the first character + of the list of option characters. + + PERMUTE is the default. We permute the contents of ARGV as we scan, + so that eventually all the non-options are at the end. This allows options + to be given in any order, even with programs that were not written to + expect this. + + RETURN_IN_ORDER is an option available to programs that were written + to expect options and other ARGV-elements in any order and that care about + the ordering of the two. We describe each non-option ARGV-element + as if it were the argument of an option with character code 1. + Using `-' as the first character of the list of option characters + selects this mode of operation. + + The special argument `--' forces an end of option-scanning regardless + of the value of `ordering'. In the case of RETURN_IN_ORDER, only + `--' can cause `getopt' to return -1 with `optind' != ARGC. */ + +static enum +{ + REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER +} ordering; + +/* Value of POSIXLY_CORRECT environment variable. */ +static char *posixly_correct; + +#ifdef __GNU_LIBRARY__ +/* We want to avoid inclusion of string.h with non-GNU libraries + because there are many ways it can cause trouble. + On some systems, it contains special magic macros that don't work + in GCC. */ +#include <string.h> +#define my_index strchr +#else + +/* Avoid depending on library functions or files + whose names are inconsistent. */ + +char *getenv (); + +static char * +my_index (str, chr) + const char *str; + int chr; +{ + while (*str) + { + if (*str == chr) + return (char *) str; + str++; + } + return 0; +} + +/* If using GCC, we can safely declare strlen this way. + If not using GCC, it is ok not to declare it. */ +#ifdef __GNUC__ +/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. + That was relevant to code that was here before. */ +#if !defined (__STDC__) || !__STDC__ +/* gcc with -traditional declares the built-in strlen to return int, + and has done so at least since version 2.4.5. -- rms. */ +extern int strlen (const char *); +#endif /* not __STDC__ */ +#endif /* __GNUC__ */ + +#endif /* not __GNU_LIBRARY__ */ + +/* Handle permutation of arguments. */ + +/* Describe the part of ARGV that contains non-options that have + been skipped. `first_nonopt' is the index in ARGV of the first of them; + `last_nonopt' is the index after the last of them. */ + +static int first_nonopt; +static int last_nonopt; + +#ifdef _LIBC +/* Bash 2.0 gives us an environment variable containing flags + indicating ARGV elements that should not be considered arguments. */ + +static const char *nonoption_flags; +static int nonoption_flags_len; + +static int original_argc; +static char *const *original_argv; + +/* Make sure the environment variable bash 2.0 puts in the environment + is valid for the getopt call we must make sure that the ARGV passed + to getopt is that one passed to the process. */ +static void store_args (int argc, char *const *argv) __attribute__ ((unused)); +static void +store_args (int argc, char *const *argv) +{ + /* XXX This is no good solution. We should rather copy the args so + that we can compare them later. But we must not use malloc(3). */ + original_argc = argc; + original_argv = argv; +} +text_set_element (__libc_subinit, store_args); +#endif + +/* Exchange two adjacent subsequences of ARGV. + One subsequence is elements [first_nonopt,last_nonopt) + which contains all the non-options that have been skipped so far. + The other is elements [last_nonopt,optind), which contains all + the options processed since those non-options were skipped. + + `first_nonopt' and `last_nonopt' are relocated so that they describe + the new indices of the non-options in ARGV after they are moved. */ + +#if defined (__STDC__) && __STDC__ +static void exchange (char **); +#endif + +static void +exchange (argv) + char **argv; +{ + int bottom = first_nonopt; + int middle = last_nonopt; + int top = optind; + char *tem; + + /* Exchange the shorter segment with the far end of the longer segment. + That puts the shorter segment into the right place. + It leaves the longer segment in the right place overall, + but it consists of two parts that need to be swapped next. */ + + while (top > middle && middle > bottom) + { + if (top - middle > middle - bottom) + { + /* Bottom segment is the short one. */ + int len = middle - bottom; + register int i; + + /* Swap it with the top part of the top segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[top - (middle - bottom) + i]; + argv[top - (middle - bottom) + i] = tem; + } + /* Exclude the moved bottom segment from further swapping. */ + top -= len; + } + else + { + /* Top segment is the short one. */ + int len = top - middle; + register int i; + + /* Swap it with the bottom part of the bottom segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[middle + i]; + argv[middle + i] = tem; + } + /* Exclude the moved top segment from further swapping. */ + bottom += len; + } + } + + /* Update records for the slots the non-options now occupy. */ + + first_nonopt += (optind - last_nonopt); + last_nonopt = optind; +} + +/* Initialize the internal data when the first call is made. */ + +#if defined (__STDC__) && __STDC__ +static const char *_getopt_initialize (int, char *const *, const char *); +#endif +static const char * +_getopt_initialize (argc, argv, optstring) + int argc; + char *const *argv; + const char *optstring; +{ + /* Start processing options with ARGV-element 1 (since ARGV-element 0 + is the program name); the sequence of previously skipped + non-option ARGV-elements is empty. */ + + first_nonopt = last_nonopt = optind = 1; + + nextchar = NULL; + + posixly_correct = getenv ("POSIXLY_CORRECT"); + + /* Determine how to handle the ordering of options and nonoptions. */ + + if (optstring[0] == '-') + { + ordering = RETURN_IN_ORDER; + ++optstring; + } + else if (optstring[0] == '+') + { + ordering = REQUIRE_ORDER; + ++optstring; + } + else if (posixly_correct != NULL) + ordering = REQUIRE_ORDER; + else + ordering = PERMUTE; + +#ifdef _LIBC + if (posixly_correct == NULL + && argc == original_argc && argv == original_argv) + { + /* Bash 2.0 puts a special variable in the environment for each + command it runs, specifying which ARGV elements are the results of + file name wildcard expansion and therefore should not be + considered as options. */ + char var[100]; + sprintf (var, "_%d_GNU_nonoption_argv_flags_", getpid ()); + nonoption_flags = getenv (var); + if (nonoption_flags == NULL) + nonoption_flags_len = 0; + else + nonoption_flags_len = strlen (nonoption_flags); + } + else + nonoption_flags_len = 0; +#endif + + return optstring; +} + +/* Scan elements of ARGV (whose length is ARGC) for option characters + given in OPTSTRING. + + If an element of ARGV starts with '-', and is not exactly "-" or "--", + then it is an option element. The characters of this element + (aside from the initial '-') are option characters. If `getopt' + is called repeatedly, it returns successively each of the option characters + from each of the option elements. + + If `getopt' finds another option character, it returns that character, + updating `optind' and `nextchar' so that the next call to `getopt' can + resume the scan with the following option character or ARGV-element. + + If there are no more option characters, `getopt' returns -1. + Then `optind' is the index in ARGV of the first ARGV-element + that is not an option. (The ARGV-elements have been permuted + so that those that are not options now come last.) + + OPTSTRING is a string containing the legitimate option characters. + If an option character is seen that is not listed in OPTSTRING, + return '?' after printing an error message. If you set `opterr' to + zero, the error message is suppressed but we still return '?'. + + If a char in OPTSTRING is followed by a colon, that means it wants an arg, + so the following text in the same ARGV-element, or the text of the following + ARGV-element, is returned in `optarg'. Two colons mean an option that + wants an optional arg; if there is text in the current ARGV-element, + it is returned in `optarg', otherwise `optarg' is set to zero. + + If OPTSTRING starts with `-' or `+', it requests different methods of + handling the non-option ARGV-elements. + See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. + + Long-named options begin with `--' instead of `-'. + Their names may be abbreviated as long as the abbreviation is unique + or is an exact match for some defined option. If they have an + argument, it follows the option name in the same ARGV-element, separated + from the option name by a `=', or else the in next ARGV-element. + When `getopt' finds a long-named option, it returns 0 if that option's + `flag' field is nonzero, the value of the option's `val' field + if the `flag' field is zero. + + The elements of ARGV aren't really const, because we permute them. + But we pretend they're const in the prototype to be compatible + with other systems. + + LONGOPTS is a vector of `struct option' terminated by an + element containing a name which is zero. + + LONGIND returns the index in LONGOPT of the long-named option found. + It is only valid when a long-named option has been found by the most + recent call. + + If LONG_ONLY is nonzero, '-' as well as '--' can introduce + long-named options. */ + +int +_getopt_internal (argc, argv, optstring, longopts, longind, long_only) + int argc; + char *const *argv; + const char *optstring; + const struct option *longopts; + int *longind; + int long_only; +{ + optarg = NULL; + + if (!__getopt_initialized || optind == 0) + { + optstring = _getopt_initialize (argc, argv, optstring); + optind = 1; /* Don't scan ARGV[0], the program name. */ + __getopt_initialized = 1; + } + + /* Test whether ARGV[optind] points to a non-option argument. + Either it does not have option syntax, or there is an environment flag + from the shell indicating it is not an option. The later information + is only used when the used in the GNU libc. */ +#ifdef _LIBC +#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ + || (optind < nonoption_flags_len \ + && nonoption_flags[optind] == '1')) +#else +#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') +#endif + + if (nextchar == NULL || *nextchar == '\0') + { + /* Advance to the next ARGV-element. */ + + /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been + moved back by the user (who may also have changed the arguments). */ + if (last_nonopt > optind) + last_nonopt = optind; + if (first_nonopt > optind) + first_nonopt = optind; + + if (ordering == PERMUTE) + { + /* If we have just processed some options following some non-options, + exchange them so that the options come first. */ + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (last_nonopt != optind) + first_nonopt = optind; + + /* Skip any additional non-options + and extend the range of non-options previously skipped. */ + + while (optind < argc && NONOPTION_P) + optind++; + last_nonopt = optind; + } + + /* The special ARGV-element `--' means premature end of options. + Skip it like a null option, + then exchange with previous non-options as if it were an option, + then skip everything else like a non-option. */ + + if (optind != argc && !strcmp (argv[optind], "--")) + { + optind++; + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (first_nonopt == last_nonopt) + first_nonopt = optind; + last_nonopt = argc; + + optind = argc; + } + + /* If we have done all the ARGV-elements, stop the scan + and back over any non-options that we skipped and permuted. */ + + if (optind == argc) + { + /* Set the next-arg-index to point at the non-options + that we previously skipped, so the caller will digest them. */ + if (first_nonopt != last_nonopt) + optind = first_nonopt; + return -1; + } + + /* If we have come to a non-option and did not permute it, + either stop the scan or describe it to the caller and pass it by. */ + + if (NONOPTION_P) + { + if (ordering == REQUIRE_ORDER) + return -1; + optarg = argv[optind++]; + return 1; + } + + /* We have found another option-ARGV-element. + Skip the initial punctuation. */ + + nextchar = (argv[optind] + 1 + + (longopts != NULL && argv[optind][1] == '-')); + } + + /* Decode the current option-ARGV-element. */ + + /* Check whether the ARGV-element is a long option. + + If long_only and the ARGV-element has the form "-f", where f is + a valid short option, don't consider it an abbreviated form of + a long option that starts with f. Otherwise there would be no + way to give the -f short option. + + On the other hand, if there's a long option "fubar" and + the ARGV-element is "-fu", do consider that an abbreviation of + the long option, just like "--fu", and not "-f" with arg "u". + + This distinction seems to be the most useful approach. */ + + if (longopts != NULL + && (argv[optind][1] == '-' + || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = -1; + int option_index; + + for (nameend = nextchar; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, nextchar, nameend - nextchar)) + { + if ((unsigned int) (nameend - nextchar) + == (unsigned int) strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + + if (ambig && !exact) + { + if (opterr) + fprintf (stderr, _("%s: option `%s' is ambiguous\n"), + argv[0], argv[optind]); + nextchar += strlen (nextchar); + optind++; + optopt = 0; + return '?'; + } + + if (pfound != NULL) + { + option_index = indfound; + optind++; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else + { + if (opterr) { + if (argv[optind - 1][1] == '-') + /* --option */ + fprintf (stderr, + _("%s: option `--%s' doesn't allow an argument\n"), + argv[0], pfound->name); + else + /* +option or -option */ + fprintf (stderr, + _("%s: option `%c%s' doesn't allow an argument\n"), + argv[0], argv[optind - 1][0], pfound->name); + } + + nextchar += strlen (nextchar); + + optopt = pfound->val; + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (opterr) + fprintf (stderr, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[optind - 1]); + nextchar += strlen (nextchar); + optopt = pfound->val; + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + + /* Can't find it as a long option. If this is not getopt_long_only, + or the option starts with '--' or is not a valid short + option, then it's an error. + Otherwise interpret it as a short option. */ + if (!long_only || argv[optind][1] == '-' + || my_index (optstring, *nextchar) == NULL) + { + if (opterr) + { + if (argv[optind][1] == '-') + /* --option */ + fprintf (stderr, _("%s: unrecognized option `--%s'\n"), + argv[0], nextchar); + else + /* +option or -option */ + fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), + argv[0], argv[optind][0], nextchar); + } + nextchar = (char *) ""; + optind++; + optopt = 0; + return '?'; + } + } + + /* Look at and handle the next short option-character. */ + + { + char c = *nextchar++; + char *temp = my_index (optstring, c); + + /* Increment `optind' when we start to process its last character. */ + if (*nextchar == '\0') + ++optind; + + if (temp == NULL || c == ':') + { + if (opterr) + { + if (posixly_correct) + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, _("%s: illegal option -- %c\n"), + argv[0], c); + else + fprintf (stderr, _("%s: invalid option -- %c\n"), + argv[0], c); + } + optopt = c; + return '?'; + } + /* Convenience. Treat POSIX -W foo same as long option --foo */ + if (temp[0] == 'W' && temp[1] == ';') + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = 0; + int option_index; + + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (opterr) + { + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, _("%s: option requires an argument -- %c\n"), + argv[0], c); + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + return c; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + + /* optarg is now the argument, see if it's in the + table of longopts. */ + + for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, nextchar, nameend - nextchar)) + { + if ((unsigned int) (nameend - nextchar) == strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + if (ambig && !exact) + { + if (opterr) + fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"), + argv[0], argv[optind]); + nextchar += strlen (nextchar); + optind++; + return '?'; + } + if (pfound != NULL) + { + option_index = indfound; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else + { + if (opterr) + fprintf (stderr, _("\ +%s: option `-W %s' doesn't allow an argument\n"), + argv[0], pfound->name); + + nextchar += strlen (nextchar); + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (opterr) + fprintf (stderr, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[optind - 1]); + nextchar += strlen (nextchar); + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + nextchar = NULL; + return 'W'; /* Let the application handle it. */ + } + if (temp[1] == ':') + { + if (temp[2] == ':') + { + /* This is an option that accepts an argument optionally. */ + if (*nextchar != '\0') + { + optarg = nextchar; + optind++; + } + else + optarg = NULL; + nextchar = NULL; + } + else + { + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (opterr) + { + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, + _("%s: option requires an argument -- %c\n"), + argv[0], c); + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + nextchar = NULL; + } + } + return c; + } +} + +int +getopt (argc, argv, optstring) + int argc; + char *const *argv; + const char *optstring; +{ + return _getopt_internal (argc, argv, optstring, + (const struct option *) 0, + (int *) 0, + 0); +} + +#endif /* Not ELIDE_CODE. */ + +#ifdef TEST + +/* Compile with -DTEST to make an executable for use in testing + the above definition of `getopt'. */ + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + + c = getopt (argc, argv, "abc:d:0123456789"); + if (c == -1) + break; + + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/converter/other/fiasco/getopt.h b/converter/other/fiasco/getopt.h new file mode 100644 index 00000000..9acca708 --- /dev/null +++ b/converter/other/fiasco/getopt.h @@ -0,0 +1,129 @@ +/* Declarations for getopt. + Copyright (C) 1989,90,91,92,93,94,96,97 Free Software Foundation, Inc. + + This file is part of the GNU C Library. Its master source is NOT part of + the C library, however. The master source lives in /gd/gnu/lib. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef _GETOPT_H +#define _GETOPT_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +extern char *optarg; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +extern int optind; + +/* Callers store zero here to inhibit the error message `getopt' prints + for unrecognized options. */ + +extern int opterr; + +/* Set to an option character which was unrecognized. */ + +extern int optopt; + +/* Describe the long-named options requested by the application. + The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector + of `struct option' terminated by an element containing a name which is + zero. + + The field `has_arg' is: + no_argument (or 0) if the option does not take an argument, + required_argument (or 1) if the option requires an argument, + optional_argument (or 2) if the option takes an optional argument. + + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. + + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ + +struct option +{ + const char *name; + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; +}; + +/* Names for the values of the `has_arg' field of `struct option'. */ + +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 + +#if defined (__STDC__) && __STDC__ +#ifdef __GNU_LIBRARY__ +/* Many other libraries have conflicting prototypes for getopt, with + differences in the consts, in stdlib.h. To avoid compilation + errors, only prototype getopt for the GNU C library. */ +extern int getopt (int argc, char *const *argv, const char *shortopts); +#else /* not __GNU_LIBRARY__ */ +extern int getopt (); +#endif /* __GNU_LIBRARY__ */ +extern int getopt_long (int argc, char *const *argv, const char *shortopts, + const struct option *longopts, int *longind); +extern int getopt_long_only (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind); + +/* Internal only. Users should not call this directly. */ +extern int _getopt_internal (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind, + int long_only); +#else /* not __STDC__ */ +extern int getopt (); +extern int getopt_long (); +extern int getopt_long_only (); + +extern int _getopt_internal (); +#endif /* __STDC__ */ + +#ifdef __cplusplus +} +#endif + +#endif /* _GETOPT_H */ diff --git a/converter/other/fiasco/getopt1.c b/converter/other/fiasco/getopt1.c new file mode 100644 index 00000000..8347bb13 --- /dev/null +++ b/converter/other/fiasco/getopt1.c @@ -0,0 +1,189 @@ +/* getopt_long and getopt_long_only entry points for GNU getopt. + Copyright (C) 1987,88,89,90,91,92,93,94,96,97 Free Software Foundation, Inc. + + This file is part of the GNU C Library. Its master source is NOT part of + the C library, however. The master source lives in /gd/gnu/lib. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "getopt.h" + +#if !defined (__STDC__) || !__STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +#ifndef const +#define const +#endif +#endif + +#include <stdio.h> + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#define GETOPT_INTERFACE_VERSION 2 +#if !defined (_LIBC) && defined (__GLIBC__) && __GLIBC__ >= 2 +#include <gnu-versions.h> +#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION +#define ELIDE_CODE +#endif +#endif + +#ifndef ELIDE_CODE + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +#include <stdlib.h> +#endif + +#ifndef NULL +#define NULL 0 +#endif + +int +getopt_long (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 0); +} + +/* Like getopt_long, but '-' as well as '--' can indicate a long option. + If an option that starts with '-' (not '--') doesn't match a long option, + but does match a short option, it is parsed as a short option + instead. */ + +int +getopt_long_only (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 1); +} + + +#endif /* Not ELIDE_CODE. */ + +#ifdef TEST + +#include <stdio.h> + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + int option_index = 0; + static struct option long_options[] = + { + {"add", 1, 0, 0}, + {"append", 0, 0, 0}, + {"delete", 1, 0, 0}, + {"verbose", 0, 0, 0}, + {"create", 0, 0, 0}, + {"file", 1, 0, 0}, + {0, 0, 0, 0} + }; + + c = getopt_long (argc, argv, "abc:d:0123456789", + long_options, &option_index); + if (c == -1) + break; + + switch (c) + { + case 0: + printf ("option %s", long_options[option_index].name); + if (optarg) + printf (" with arg %s", optarg); + printf ("\n"); + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case 'd': + printf ("option d with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/converter/other/fiasco/input/Makefile b/converter/other/fiasco/input/Makefile new file mode 100644 index 00000000..c01af772 --- /dev/null +++ b/converter/other/fiasco/input/Makefile @@ -0,0 +1,26 @@ +ifeq ($(SRCDIR)x,x) + SRCDIR = $(CURDIR)/../../../.. + BUILDDIR = $(SRCDIR) +endif +FIASCOSUBDIR = converter/other/fiasco +SUBDIR = $(FIASCOSUBDIR)/input +BUILDDIR = ../../../.. +VPATH=.:$(SRCDIR)/$(SUBDIR) + +include $(BUILDDIR)/Makefile.config + +OBJECTS = basis.o matrices.o mc.o nd.o read.o tree.o weights.o + +MERGE_OBJECTS = $(OBJECTS) + +INCLUDES = -I$(SRCDIR)/$(FIASCOSUBDIR) -I$(SRCDIR)/$(FIASCOSUBDIR)/lib \ + -I$(SRCDIR)/$(FIASCOSUBDIR)/codec + +all: libfiasco_input.a + +include $(SRCDIR)/Makefile.common + +libfiasco_input.a: $(OBJECTS) + $(AR) -rc $@ $(OBJECTS) + $(RANLIB) $@ + diff --git a/converter/other/fiasco/input/basis.c b/converter/other/fiasco/input/basis.c new file mode 100644 index 00000000..cef075e6 --- /dev/null +++ b/converter/other/fiasco/input/basis.c @@ -0,0 +1,141 @@ +/* + * basis.c: WFA initial basis files + * + * 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/25 16:38:06 $ + * $Author: hafner $ + * $Revision: 5.3 $ + * $State: Exp $ + */ + +#include "config.h" + +#include "types.h" +#include "macros.h" +#include "error.h" + +#include "wfa.h" +#include "wfalib.h" + +#include "basis.h" + +typedef struct basis_values +{ + unsigned states; + real_t *final; + bool_t *use_domain; + real_t (*transitions)[4]; +} basis_values_t; + +typedef struct +{ + const char *filename; + void (*function)(basis_values_t *bv); +} basis_file_t; + +/***************************************************************************** + + prototypes + +*****************************************************************************/ + +static void +small_init (basis_values_t *bv); + +static basis_file_t const basis_files[] = { + {"small.fco", small_init}, + {"small.wfa", small_init}, + {NULL, NULL} +}; + +/***************************************************************************** + + public code + +*****************************************************************************/ + +bool_t +get_linked_basis (const char *basis_name, wfa_t *wfa) +/* + * Check wether given WFA initial basis 'basis_name' is already linked + * with the excecutable. If the basis is available then fill the 'wfa' struct + * according to the stored data, otherwise print a warning message. + * + * Return value: + * true on success, false if basis is not available yet. + * + * Side effects: + * 'wfa' struct is filled on success. + */ +{ + bool_t success = NO; /* indicates if basis is found */ + unsigned n; /* counter */ + basis_values_t bv; /* basis values */ + + for (n = 0; basis_files [n].filename != NULL; n++) + if (streq (basis_files [n].filename, basis_name)) /* basis is stored */ + { + unsigned state, edge; + + (*basis_files [n].function) (&bv); /* initialize local variables */ + /* + * Generate WFA + */ + wfa->basis_states = wfa->states = bv.states + 1; + wfa->domain_type[0] = USE_DOMAIN_MASK; + wfa->final_distribution[0] = 128; + append_edge (0, 0, 1.0, 0, wfa); + append_edge (0, 0, 1.0, 1, wfa); + for (state = 1; state < wfa->basis_states; state++) + { + wfa->final_distribution [state] = bv.final [state - 1]; + wfa->domain_type [state] = bv.use_domain [state - 1] + ? USE_DOMAIN_MASK + : AUXILIARY_MASK; + } + for (edge = 0; isedge (bv.transitions [edge][0]); edge++) + append_edge (bv.transitions [edge][0], bv.transitions [edge][1], + bv.transitions [edge][2], bv.transitions [edge][3], + wfa); + + success = YES; + break; + } + + if (!success) + warning ("WFA initial basis '%s' isn't linked with the excecutable yet." + "\nLoading basis from disk instead.", basis_name); + + return success; +} + +/***************************************************************************** + + private code + +*****************************************************************************/ + +/***************************************************************************** + basis "small.wfa" +*****************************************************************************/ + +static unsigned states_small = 2; +static bool_t use_domain_small[] = {YES, YES}; +static real_t final_small[] = {64, 64}; +static real_t transitions_small[][4] = {{1, 2, 0.5, 0}, {1, 2, 0.5, 1}, + {1, 0, 0.5, 1}, {2, 1, 1.0, 0}, + {2, 1, 1.0, 1}, {-1, 0, 0, 0}}; +static void +small_init (basis_values_t *bv) +{ + bv->states = states_small; + bv->final = final_small; + bv->use_domain = use_domain_small; + bv->transitions = transitions_small; +} diff --git a/converter/other/fiasco/input/basis.h b/converter/other/fiasco/input/basis.h new file mode 100644 index 00000000..fa26bca2 --- /dev/null +++ b/converter/other/fiasco/input/basis.h @@ -0,0 +1,26 @@ +/* + * basis.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:13 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#ifndef _BASIS_H +#define _BASIS_H + +#include "wfa.h" + +bool_t +get_linked_basis (const char *basis_name, wfa_t *wfa); + +#endif /* not _BASIS_H */ + diff --git a/converter/other/fiasco/input/matrices.c b/converter/other/fiasco/input/matrices.c new file mode 100644 index 00000000..47cde1aa --- /dev/null +++ b/converter/other/fiasco/input/matrices.c @@ -0,0 +1,644 @@ +/* + * matrices.c: Input of transition matrices + * + * 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:13 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#include "config.h" + +#include "types.h" +#include "macros.h" +#include "error.h" + +#include "bit-io.h" +#include "arith.h" +#include "misc.h" +#include "wfalib.h" + +#include "matrices.h" + +#if STDC_HEADERS +# include <stdlib.h> +#endif /* not STDC_HEADERS */ + +/***************************************************************************** + + prototypes + +*****************************************************************************/ + +static unsigned +delta_decoding (wfa_t *wfa, unsigned last_domain, bitfile_t *input); +static unsigned +column_0_decoding (wfa_t *wfa, unsigned last_row, bitfile_t *input); +static unsigned +chroma_decoding (wfa_t *wfa, bitfile_t *input); +static void +compute_y_state (int state, int y_state, wfa_t *wfa); + +/***************************************************************************** + + public code + +*****************************************************************************/ + +unsigned +read_matrices (wfa_t *wfa, bitfile_t *input) +/* + * Read transitions of WFA given from the stream 'input'. + * + * Return value: + * number of edges + * + * Side effects: + * 'wfa->into' is filled with decoded values + */ +{ + unsigned total; /* total number of edges in the WFA */ + unsigned root_state = wfa->wfainfo->color + ? wfa->tree [wfa->tree [wfa->root_state][0]][0] + : wfa->root_state; + + total = column_0_decoding (wfa, root_state, input); + total += delta_decoding (wfa, root_state, input); + if (wfa->wfainfo->color) + total += chroma_decoding (wfa, input); + + return total; +} + +/***************************************************************************** + + private code + +*****************************************************************************/ + +static unsigned +delta_decoding (wfa_t *wfa, unsigned last_domain, bitfile_t *input) +/* + * Read transition matrices which are encoded with delta coding + * from stream 'input'. + * 'last_domain' is the maximum state number used as domain image. + * + * Return value: + * number of non-zero matrix elements (WFA edges) + * + * Side effects: + * 'wfa->into' is filled with decoded values + */ +{ + range_sort_t rs; /* ranges are sorted as in the coder */ + unsigned max_domain; /* dummy used for recursion */ + unsigned range; + unsigned count [MAXEDGES + 1]; + unsigned state, label; + unsigned *n_edges; /* number of elements per row */ + unsigned total = 0; /* total number of decoded edges */ + + /* + * Generate a list of range blocks. + * The order is the same as in the coder. + */ + rs.range_state = Calloc ((last_domain + 1) * MAXLABELS, + sizeof (u_word_t)); + rs.range_label = Calloc ((last_domain + 1) * MAXLABELS, + sizeof (byte_t)); + rs.range_max_domain = Calloc ((last_domain + 1) * MAXLABELS, + sizeof (u_word_t)); + rs.range_subdivided = Calloc ((last_domain + 1) * MAXLABELS, + sizeof (bool_t)); + rs.range_no = 0; + max_domain = wfa->basis_states - 1; + sort_ranges (last_domain, &max_domain, &rs, wfa); + + /* + * Get row statistics + */ + { + arith_t *decoder; + model_t *elements; + unsigned max_edges = read_rice_code (3, input); + + /* + * Get the probability array of the number of edges distribution + * and allocate the corresponding model. + */ + { + unsigned edge; + + for (edge = 0; edge <= max_edges; edge++) + count [edge] = read_rice_code ((int) log2 (last_domain) - 2, + input); + elements = alloc_model (max_edges + 1, 0, 0, count); + } + + /* + * Get number of elements per matrix row + */ + { + unsigned row; + + n_edges = Calloc (wfa->states, sizeof (unsigned)); + decoder = alloc_decoder (input); + for (row = range = 0; range < rs.range_no; range++) + if (!rs.range_subdivided [range]) + { + state = rs.range_state [range]; + label = rs.range_label [range]; + + n_edges [row++] + = decode_symbol (decoder, elements) + - (isedge (wfa->into [state][label][0]) ? 1 : 0); + } + + free_decoder (decoder); + free_model (elements); + } + } + + /* + * Get matrix elements + */ + { + unsigned row; + u_word_t *mapping1 = Calloc (wfa->states, sizeof (word_t)); + u_word_t *mapping_coder1 = Calloc (wfa->states, sizeof (word_t)); + u_word_t *mapping2 = Calloc (wfa->states, sizeof (word_t)); + u_word_t *mapping_coder2 = Calloc (wfa->states, sizeof (word_t)); + bool_t use_normal_domains = get_bit (input); + bool_t use_delta_domains = get_bit (input); + + /* + * Generate array of states which are admitted domains. + * When coding intra frames 'mapping1' == 'mapping2' otherwise + * 'mapping1' is a list of 'normal' domains which are admitted for + * coding intra blocks + * 'mapping2' is a list of 'delta' domains which are admitted for + * coding the motion compensated prediction error + */ + { + unsigned n1, n2, state; + + for (n1 = n2 = state = 0; state < wfa->states; state++) + { + mapping1 [n1] = state; + mapping_coder1 [state] = n1; + if (usedomain (state, wfa) + && (state < wfa->basis_states + || use_delta_domains || !wfa->delta_state [state])) + n1++; + + mapping2 [n2] = state; + mapping_coder2 [state] = n2; + if (usedomain (state, wfa) + && (state < wfa->basis_states || use_normal_domains + || wfa->delta_state [state])) + n2++; + } + } + + for (row = 0, range = 0; range < rs.range_no; range++) + if (!rs.range_subdivided [range]) + { + u_word_t *mapping; + u_word_t *mapping_coder; + unsigned max_value; + unsigned edge; + unsigned state = rs.range_state [range]; + unsigned label = rs.range_label [range]; + unsigned last = 1; + + if (wfa->delta_state [state] || + wfa->mv_tree [state][label].type != NONE) + { + mapping = mapping2; + mapping_coder = mapping_coder2; + } + else + { + mapping = mapping1; + mapping_coder = mapping_coder1; + } + max_value = mapping_coder [rs.range_max_domain [range]]; + for (edge = n_edges [row]; edge; edge--) + { + unsigned domain; + + if (max_value - last) + domain = read_bin_code (max_value - last, input) + last; + else + domain = max_value; + append_edge (state, mapping [domain], -1, label, wfa); + last = domain + 1; + total++; + } + row++; + } + Free (mapping1); + Free (mapping_coder1); + Free (mapping2); + Free (mapping_coder2); + } + + Free (n_edges); + Free (rs.range_state); + Free (rs.range_label); + Free (rs.range_max_domain); + Free (rs.range_subdivided); + + return total; +} + +static unsigned +column_0_decoding (wfa_t *wfa, unsigned last_row, bitfile_t *input) +/* + * Read column 0 of the transition matrices of the 'wfa' which are coded + * with quasi arithmetic coding from stream 'input'. + * All rows from 'wfa->basis_states' up to 'last_row' are decoded. + * + * Return value: + * number of non-zero matrix elements (WFA edges) + * + * Side effects: + * 'wfa->into' is filled with decoded values + */ +{ + unsigned row; /* current matrix row */ + unsigned total = 0; /* total number of edges in col 0 */ + unsigned *prob_ptr; /* pointer to current probability */ + unsigned *last; /* pointer to minimum probability */ + unsigned *first; /* pointer to maximum probability */ + unsigned *new_prob_ptr; /* ptr to probability of last domain */ + unsigned *prob; /* probability array */ + u_word_t high; /* Start of the current code range */ + u_word_t low; /* End of the current code range */ + u_word_t code; /* The present input code value */ + word_t *is_leaf; /* pointer to the tree structure */ + + /* + * Compute the asymmetric probability array + * prob[] = { 1/2, 1/2, 1/4, 1/4, 1/4, 1/4, + * 1/8, ... , 1/16, ..., 1/(MAXPROB+1)} + */ + { + unsigned n; + unsigned index; /* probability index */ + unsigned exp; /* current exponent */ + + prob = Calloc (1 << (MAX_PROB + 1), sizeof (unsigned)); + + for (index = 0, n = MIN_PROB; n <= MAX_PROB; n++) + for (exp = 0; exp < 1U << n; exp++, index++) + prob [index] = n; + } + + first = prob_ptr = new_prob_ptr = prob; + last = first + 1020; + + is_leaf = wfa->tree [wfa->basis_states]; /* use pointer arithmetics ... */ + + high = HIGH; /* 1.0 */ + low = LOW; /* 0.0 */ + code = get_bits (input, 16); + + /* + * Decode column 0 with a quasi arithmetic coder (QAC). + * Advantage of this QAC with respect to a binary AC: + * Instead of using time consuming multiplications and divisions + * to compute the probability of the most probable symbol (MPS) and + * the range of the interval, a table look up procedure linked + * with a shift operation is used for both computations. + * + * Loops and array accesses have been removed + * to make real time decoding possible. + */ + for (row = wfa->basis_states; row <= last_row; row++) + { + unsigned count; /* value in the current interval */ + + /* + * Read label 0 element + */ + if (isrange (*is_leaf++)) /* valid matrix index */ + { + count = high - ((high - low) >> *prob_ptr); + if (code < count) + { + if (prob_ptr < last) /* model update */ + prob_ptr++; + /* + * Decode the MPS '0' + */ + high = count - 1; + + RESCALE_INPUT_INTERVAL; + } + else + { + prob_ptr = ((prob_ptr - first) >> 1) + first; /* model update */ + /* + * Decode the LPS '1' + */ + low = count; + + RESCALE_INPUT_INTERVAL; + /* + * Restore the transition (weight = -1) + */ + append_edge (row, 0, -1, 0, wfa); + total++; + } + } + /* + * Read label 1 element + */ + if (isrange (*is_leaf++)) /* valid matrix index */ + { + count = high - ((high - low) >> *prob_ptr); + if (code < count) + { + if (prob_ptr < last) + prob_ptr++; /* model update */ + /* + * Decode the MPS '0' + */ + high = count - 1; + + RESCALE_INPUT_INTERVAL; + } + else + { + prob_ptr = ((prob_ptr - first) >> 1) + first; /* model update */ + /* + * Decode the LPS '1' + */ + low = count; + + RESCALE_INPUT_INTERVAL; + /* + * Restore the transition (weight = -1) + */ + append_edge (row, 0, -1, 1, wfa); + total++; + } + } + } + + INPUT_BYTE_ALIGN (input); + + Free (prob); + + return total; +} + +static unsigned +chroma_decoding (wfa_t *wfa, bitfile_t *input) +/* + * Read transition matrices of 'wfa' states which are part of the + * chroma channels Cb and Cr from stream 'input'. + * + * Return value: + * number of non-zero matrix elements (WFA edges) + * + * Side effects: + * 'wfa->into' is filled with decoded values + */ +{ + unsigned domain; /* current domain, counter */ + unsigned total = 0; /* total number of chroma edges */ + unsigned *prob_ptr; /* pointer to current probability */ + unsigned *last; /* pointer to minimum probability */ + unsigned *first; /* pointer to maximum probability */ + unsigned *new_prob_ptr; /* ptr to probability of last domain */ + unsigned *prob; /* probability array */ + u_word_t high; /* Start of the current code range */ + u_word_t low; /* End of the current code range */ + u_word_t code; /* The present input code value */ + word_t *y_domains; /* domain images corresponding to Y */ + int save_index; /* YES: store current probabilty */ + + /* + * Compute the asymmetric probability array + * prob[] = { 1/2, 1/2, 1/4, 1/4, 1/4, 1/4, + * 1/8, ... , 1/16, ..., 1/(MAXPROB+1)} + */ + { + unsigned n; + unsigned index; /* probability index */ + unsigned exp; /* current exponent */ + + prob = Calloc (1 << (MAX_PROB + 1), sizeof (unsigned)); + + for (index = 0, n = MIN_PROB; n <= MAX_PROB; n++) + for (exp = 0; exp < 1U << n; exp++, index++) + prob [index] = n; + } + + high = HIGH; /* 1.0 */ + low = LOW; /* 0.0 */ + code = get_bits (input, 16); + + /* + * Compute list of admitted domains + */ + y_domains = compute_hits (wfa->basis_states, + wfa->tree [wfa->tree [wfa->root_state][0]][0], + wfa->wfainfo->chroma_max_states, wfa); + + first = prob_ptr = new_prob_ptr = prob; + last = first + 1020; + + /* + * First of all, read all matrix columns given in the list 'y_domains' + * which note all admitted domains. + * These matrix elements are stored with QAC (see column_0_decoding ()). + */ + for (domain = 0; y_domains [domain] != -1; domain++) + { + unsigned row = wfa->tree [wfa->tree [wfa->root_state][0]][0] + 1; + word_t *is_leaf = wfa->tree [row]; + + prob_ptr = new_prob_ptr; + save_index = YES; + + for (; row < wfa->states; row++) + { + unsigned count; /* value in the current interval */ + /* + * Read label 0 element + */ + if (isrange (*is_leaf++)) /* valid matrix index */ + { + count = high - ((high - low) >> *prob_ptr); + if (code < count) + { + if (prob_ptr < last) + prob_ptr++; + /* + * Decode the MPS '0' + */ + high = count - 1; + + RESCALE_INPUT_INTERVAL; + } + else + { + prob_ptr = ((prob_ptr - first) >> 1) + first; + /* + * Decode the LPS '1' + */ + low = count; + + RESCALE_INPUT_INTERVAL; + /* + * Restore the transition (weight = -1) + */ + append_edge (row, y_domains [domain], -1, 0, wfa); + total++; + } + } + /* + * Read label 1 element + */ + if (isrange (*is_leaf++)) /* valid matrix index */ + { + count = high - ((high - low) >> *prob_ptr); + if (code < count) + { + if (prob_ptr < last) + prob_ptr++; + /* + * Decode the MPS '0' + */ + high = count - 1; + + RESCALE_INPUT_INTERVAL; + } + else + { + prob_ptr = ((prob_ptr - first) >> 1) + first; + /* + * Decode the LPS '1' + */ + low = count; + + RESCALE_INPUT_INTERVAL; + /* + * Restore the transition (weight = -1) + */ + append_edge (row, y_domains [domain], -1, 1, wfa); + total++; + } + } + if (save_index) + { + save_index = NO; + new_prob_ptr = prob_ptr; + } + } + } + + Free (y_domains); + + compute_y_state (wfa->tree [wfa->tree [wfa->root_state][0]][1], + wfa->tree [wfa->tree [wfa->root_state][0]][0], wfa); + compute_y_state (wfa->tree [wfa->tree [wfa->root_state][1]][0], + wfa->tree [wfa->tree [wfa->root_state][0]][0], wfa); + + first = prob_ptr = new_prob_ptr = prob; + + /* + * Decode the additional column which indicates whether there + * are transitions to a state with same spatial coordinates + * in the Y component. + * + * Again, quasi arithmetic decoding is used for this task. + */ + { + unsigned row; + + for (row = wfa->tree [wfa->tree [wfa->root_state][0]][0] + 1; + row < wfa->states; row++) + { + int label; /* current label */ + + for (label = 0; label < MAXLABELS; label++) + { + u_word_t count = high - ((high - low) >> *prob_ptr); + + if (code < count) + { + if (prob_ptr < last) + prob_ptr++; + /* + * Decode the MPS '0' + */ + high = count - 1; + + RESCALE_INPUT_INTERVAL; + } + else + { + prob_ptr = ((prob_ptr - first) >> 1) + first; + /* + * Decode the LPS '1' + */ + low = count; + + RESCALE_INPUT_INTERVAL; + /* + * Restore the transition (weight = -1) + */ + append_edge (row, wfa->y_state [row][label], -1, label, wfa); + total++; + } + } + } + } + + INPUT_BYTE_ALIGN (input); + + Free (prob); + + return total; +} + +static void +compute_y_state (int state, int y_state, wfa_t *wfa) +/* + * Compute the 'wfa->y_state' array which denotes those states of + * the Y band that have the same spatial coordinates as the corresponding + * states of the Cb and Cr bands. + * The current root of the Y tree is given by 'y_state'. + * The current root of the tree of the chroma channel is given by 'state'. + * + * No return value. + * + * Side effects: + * 'wfa->y_state' is filled with the generated tree structure. + */ +{ + unsigned label; + + for (label = 0; label < MAXLABELS; label++) + if (isrange (y_state)) + wfa->y_state [state][label] = RANGE; + else + { + wfa->y_state [state][label] = wfa->tree [y_state][label]; + if (!isrange (wfa->tree [state][label])) + compute_y_state (wfa->tree [state][label], + wfa->y_state [state][label], wfa); + } + +} diff --git a/converter/other/fiasco/input/matrices.h b/converter/other/fiasco/input/matrices.h new file mode 100644 index 00000000..ba8fd9bf --- /dev/null +++ b/converter/other/fiasco/input/matrices.h @@ -0,0 +1,27 @@ +/* + * matrices.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:13 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#ifndef _MATRICES_H +#define _MATRICES_H + +#include "wfa.h" +#include "bit-io.h" + +unsigned +read_matrices (wfa_t *wfa, bitfile_t *input); + +#endif /* not _MATRICES_H */ + diff --git a/converter/other/fiasco/input/mc.c b/converter/other/fiasco/input/mc.c new file mode 100644 index 00000000..070d839e --- /dev/null +++ b/converter/other/fiasco/input/mc.c @@ -0,0 +1,334 @@ +/* + * mc.c: Input of motion compensation + * + * 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:13 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#include <stdlib.h> +#include "config.h" + +#include "types.h" +#include "macros.h" +#include "error.h" + +#include "wfa.h" +#include "bit-io.h" +#include "misc.h" +#include "mvcode.h" + +#include "mc.h" + +/***************************************************************************** + + local variables + +*****************************************************************************/ + +typedef struct huff_node +{ + int code_index; /* leaf if index >= 0 */ + struct huff_node *left; /* follow if '0' bit read */ + struct huff_node *right; /* follow if '1' bit read */ + int index_set [34]; +} huff_node_t; + +/***************************************************************************** + + prototypes + +*****************************************************************************/ + +static void +decode_mc_tree (frame_type_e frame_type, unsigned max_state, + wfa_t *wfa, bitfile_t *input); +static void +decode_mc_coords (unsigned max_state, wfa_t *wfa, bitfile_t *input); +static int +get_mv (int f_code, huff_node_t *hn, bitfile_t *input); +static huff_node_t * +create_huff_tree (void); +static void +create_huff_node (huff_node_t *hn, int bits_processed); + +/***************************************************************************** + + public code + +*****************************************************************************/ + +void +read_mc (frame_type_e frame_type, wfa_t *wfa, bitfile_t *input) +/* + * Read motion compensation information of the 'input' stream. + * Depending on 'frame_type' different decoding methods are used. + * + * No return value. + * + * Side effects: + * 'wfa->mv_tree' is filled with the decoded values. + */ +{ + unsigned max_state = wfa->wfainfo->color + ? wfa->tree [wfa->tree [wfa->root_state][0]][0] + : wfa->states; + + decode_mc_tree (frame_type, max_state, wfa, input); + decode_mc_coords (max_state, wfa, input); +} + +/***************************************************************************** + + private code + +*****************************************************************************/ + +static void +decode_mc_tree (frame_type_e frame_type, unsigned max_state, + wfa_t *wfa, bitfile_t *input) +/* + * Read tree of motion compensation decisions of the 'input' stream. + * Depending on 'frame_type' different decoding methods are used. + * 'max_state' is the last state with motion compensation infos. + * + * No return value. + * + * Side effects: + * 'wfa->mv_tree' is filled with decoded values. + */ +{ + unsigned state; /* current state */ + unsigned *queue; /* states in breadth first order */ + unsigned last; /* last node + (update for each new node) */ + + /* + * Traverse tree in breadth first order (starting at level + * 'wfa->wfainfo->p_max_level'). Use a queue to store the childs + * of each node ('last' is the next free queue element). + */ + queue = Calloc (MAXSTATES, sizeof (unsigned)); + for (last = 0, state = wfa->basis_states; state < max_state; state++) + if (wfa->level_of_state [state] - 1 == (int) wfa->wfainfo->p_max_level) + queue [last++] = state; /* init level 'p_max_level' */ + + if (frame_type == P_FRAME) + { + unsigned label; /* current label */ + unsigned current; /* current node to process */ + + for (current = 0; current < last; current++) + for (label = 0; label < MAXLABELS; label++) + { + state = queue[current]; + if (wfa->x [state][label] /* process visible states only */ + + width_of_level (wfa->level_of_state [state] - 1) + <= wfa->wfainfo->width + && + wfa->y [state][label] + + height_of_level (wfa->level_of_state [state] - 1) + <= wfa->wfainfo->height) + { + wfa->mv_tree [state][label].type + = get_bit (input) ? NONE : FORWARD; + } + else + wfa->mv_tree [state][label].type = NONE; + if (wfa->mv_tree [state][label].type == NONE && + !isrange (wfa->tree [state][label]) && + wfa->level_of_state [state] - 1 >= + (int) wfa->wfainfo->p_min_level) + queue [last++] = wfa->tree [state][label]; /* append child */ + } + } + else + { + unsigned label; /* current label */ + unsigned current; /* current node to process */ + + for (current = 0; current < last; current++) + for (label = 0; label < MAXLABELS; label++) + { + state = queue[current]; + if (wfa->x [state][label] /* process visible states only */ + + width_of_level (wfa->level_of_state [state] - 1) + > wfa->wfainfo->width + || + wfa->y [state][label] + + height_of_level (wfa->level_of_state [state] - 1) + > wfa->wfainfo->height) + wfa->mv_tree[state][label].type = NONE; + else if (get_bit (input)) /* 1 */ + wfa->mv_tree[state][label].type = NONE; + else if (get_bit (input)) /* 01 */ + wfa->mv_tree[state][label].type = INTERPOLATED; + else if (get_bit (input)) /* 001 */ + wfa->mv_tree[state][label].type = BACKWARD; + else /* 000 */ + wfa->mv_tree[state][label].type = FORWARD; + if (wfa->mv_tree[state][label].type == NONE && + !isrange (wfa->tree[state][label]) && + wfa->level_of_state[state] - 1 + >= (int) wfa->wfainfo->p_min_level) + queue[last++] = wfa->tree[state][label]; /* append child */ + } + } + + INPUT_BYTE_ALIGN (input); + Free (queue); +} + +static void +decode_mc_coords (unsigned max_state, wfa_t *wfa, bitfile_t *input) +/* + * Read motion vector coordinates of the 'input' stream. They are stored + * with the static Huffman code of the MPEG and H.263 standards. + * 'max_state' is the last state with motion compensation infos. + * + * No return value. + * + * Side effects: + * 'wfa->mv_tree' is filled with decoded values. + */ +{ + unsigned label; /* current label */ + unsigned state; /* current state */ + mv_t *mv; /* current motion vector */ + static huff_node_t *huff_mv_root = NULL; /* root of huffman tree */ + + if (huff_mv_root == NULL) + huff_mv_root = create_huff_tree (); + + for (state = wfa->basis_states; state < max_state; state++) + for (label = 0; label < MAXLABELS; label++) + { + mv = &wfa->mv_tree[state][label]; + switch (mv->type) + { + case NONE: + break; + case FORWARD: + mv->fx = get_mv (1, huff_mv_root, input); + mv->fy = get_mv (1, huff_mv_root, input); + break; + case BACKWARD: + mv->bx = get_mv (1, huff_mv_root, input); + mv->by = get_mv (1, huff_mv_root, input); + break; + case INTERPOLATED: + mv->fx = get_mv (1, huff_mv_root, input); + mv->fy = get_mv (1, huff_mv_root, input); + mv->bx = get_mv (1, huff_mv_root, input); + mv->by = get_mv (1, huff_mv_root, input); + break; + } + } + + INPUT_BYTE_ALIGN (input); +} + +static int +get_mv (int f_code, huff_node_t *hn, bitfile_t *input) +/* + * Decode next motion vector component in bitstream + * by traversing the huffman tree. + */ +{ + int vlc_code, vlc_code_magnitude, residual, diffvec; + + while (hn->code_index < 0) + { + if (hn->code_index == -2) + error ("wrong huffman code !"); + if (get_bit (input)) + hn = hn->right; + else + hn = hn->left; + } + vlc_code = hn->code_index - 16; + if (vlc_code == 0 || f_code == 1) + return vlc_code; + + vlc_code_magnitude = abs (vlc_code) - 1; + if (f_code <= 1) + residual = 0; + else + residual = get_bits (input, f_code - 1); + diffvec = (vlc_code_magnitude << (f_code - 1)) + residual + 1; + + return vlc_code > 0 ? diffvec : - diffvec; +} + +static huff_node_t * +create_huff_tree (void) +/* + * Construct huffman tree from code table + */ +{ + unsigned i; + huff_node_t *huff_root = Calloc (1, sizeof (huff_node_t)); + + /* + * The nodes' index set contains indices of all codewords that are + * still decodable by traversing further down from the node. + * (The root node has the full index set.) + */ + + for (i = 0; i < 33; i++) + huff_root->index_set [i] = i; + huff_root->index_set [i] = -1; /* end marker */ + + create_huff_node (huff_root, 0); + + return huff_root; +} + +static void +create_huff_node (huff_node_t *hn, int bits_processed) +/* + * Create one node in the huffman tree + */ +{ + int lind = 0; /* next index of left huff_node */ + int rind = 0; /* next index of right huff_node */ + int code_len, i, ind; + + hn->code_index = -1; + if (hn->index_set [0] < 0) /* empty index set ? */ + { + hn->code_index = -2; /* error */ + return; + } + hn->left = Calloc (1, sizeof (huff_node_t)); + hn->right = Calloc (1, sizeof (huff_node_t)); + + for (i = 0; (ind = hn->index_set[i]) >= 0; i++) + { + code_len = mv_code_table[ind][1]; + if (code_len == bits_processed) /* generate leaf */ + { + hn->code_index = ind; + Free (hn->left); + Free (hn->right); + return; + } + if (mv_code_table[ind][0] & (1 << (code_len - 1 - bits_processed))) + hn->right->index_set[rind++] = ind; + else + hn->left->index_set[lind++] = ind; + } + hn->right->index_set[rind] = -1; /* set end markers */ + hn->left->index_set[lind] = -1; + create_huff_node (hn->left, bits_processed + 1); + create_huff_node (hn->right, bits_processed + 1); +} diff --git a/converter/other/fiasco/input/mc.h b/converter/other/fiasco/input/mc.h new file mode 100644 index 00000000..1e14d287 --- /dev/null +++ b/converter/other/fiasco/input/mc.h @@ -0,0 +1,28 @@ +/* + * mc.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:13 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#ifndef _MC_H +#define _MC_H + +#include "wfa.h" +#include "bit-io.h" + +void +read_mc (frame_type_e frame_type, wfa_t *wfa, bitfile_t *input); + +#endif /* not _MC_H */ + diff --git a/converter/other/fiasco/input/nd.c b/converter/other/fiasco/input/nd.c new file mode 100644 index 00000000..1a68bfbf --- /dev/null +++ b/converter/other/fiasco/input/nd.c @@ -0,0 +1,237 @@ +/* + * nd.c: Input of prediction 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:13 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#include "config.h" + +#include "types.h" +#include "macros.h" +#include "error.h" + +#include "bit-io.h" +#include "arith.h" +#include "misc.h" +#include "list.h" +#include "wfalib.h" + +#include "nd.h" + +/***************************************************************************** + + prototypes + +*****************************************************************************/ + +static void +decode_nd_coefficients (unsigned total, wfa_t *wfa, bitfile_t *input); +static unsigned +decode_nd_tree (wfa_t *wfa, bitfile_t *input); + +/***************************************************************************** + + public code + +*****************************************************************************/ + +void +read_nd (wfa_t *wfa, bitfile_t *input) +/* + * Read transitions of the nondetermistic 'wfa' part from 'input' stream. + * ND is used only at levels {'wfa->p_min_level', ... , 'wfa->p_max_level'}. + * + * Side effects: + * 'wfa->into' and 'wfa->weights' are filled with the decoded values + */ +{ + unsigned total = decode_nd_tree (wfa, input); + + if (total > 0) + decode_nd_coefficients (total, wfa, input); +} + +/***************************************************************************** + + private code + +*****************************************************************************/ + +static unsigned +decode_nd_tree (wfa_t *wfa, bitfile_t *input) +/* + * Read 'wfa' prediction tree of given 'input' stream. + * + * No return value. + * + * Side effects: + * 'wfa->into' is filled with the decoded values + */ +{ + lqueue_t *queue; /* queue of states */ + int next, state; /* state and its current child */ + unsigned total = 0; /* total number of predicted states */ + u_word_t sum0, sum1; /* Probability model */ + u_word_t code; /* The present input code value */ + u_word_t low; /* Start of the current code range */ + u_word_t high; /* End of the current code range */ + + /* + * Initialize arithmetic decoder + */ + code = get_bits (input, 16); + low = 0; + high = 0xffff; + sum0 = 1; + sum1 = 11; + + queue = alloc_queue (sizeof (int)); + state = wfa->root_state; + queue_append (queue, &state); + + /* + * Traverse the WFA tree in breadth first order (using a queue). + */ + while (queue_remove (queue, &next)) + { + unsigned label; + + if (wfa->level_of_state [next] > wfa->wfainfo->p_max_level + 1) + { + /* + * Nondetermismn is not allowed at levels larger than + * 'wfa->wfainfo->p_max_level'. + */ + for (label = 0; label < MAXLABELS; label++) + if (ischild (state = wfa->tree [next][label])) + queue_append (queue, &state); /* continue with childs */ + } + else if (wfa->level_of_state [next] > wfa->wfainfo->p_min_level) + { + for (label = 0; label < MAXLABELS; label++) + if (ischild (state = wfa->tree [next][label])) + { + unsigned count; /* Current interval count */ + unsigned range; /* Current interval range */ + + count = (((code - low) + 1) * sum1 - 1) / ((high - low) + 1); + if (count < sum0) + { + /* + * Decode a '0' symbol + * First, the range is expanded to account for the + * symbol removal. + */ + range = (high - low) + 1; + high = low + (u_word_t) ((range * sum0) / sum1 - 1 ); + RESCALE_INPUT_INTERVAL; + /* + * Update the frequency counts + */ + sum0++; + sum1++; + if (sum1 > 50) /* scale the symbol frequencies */ + { + sum0 >>= 1; + sum1 >>= 1; + if (!sum0) + sum0 = 1; + if (sum0 >= sum1) + sum1 = sum0 + 1; + } + if (wfa->level_of_state [state] > wfa->wfainfo->p_min_level) + queue_append (queue, &state); + } + else + { + /* + * Decode a '1' symbol + * First, the range is expanded to account for the + * symbol removal. + */ + range = (high - low) + 1; + high = low + (u_word_t) ((range * sum1) / sum1 - 1); + low = low + (u_word_t) ((range * sum0) / sum1); + RESCALE_INPUT_INTERVAL; + /* + * Update the frequency counts + */ + sum1++; + if (sum1 > 50) /* scale the symbol frequencies */ + { + sum0 >>= 1; + sum1 >>= 1; + if (!sum0) + sum0 = 1; + if (sum0 >= sum1) + sum1 = sum0 + 1; + } + append_edge (next, 0, -1, label, wfa); + total++; + } + } + } + } + free_queue (queue); + + INPUT_BYTE_ALIGN (input); + + return total; +} + +static void +decode_nd_coefficients (unsigned total, wfa_t *wfa, bitfile_t *input) +/* + * Read #'total' weights of nondeterministic part of 'wfa' + * of given 'input' stream. + * 'frame' gives the current frame number. + * + * No return value. + * + * Side effects: + * 'wfa->weights' is filled with the decoded values. + */ +{ + unsigned *coefficients; /* array of factors to encode */ + unsigned *ptr; /* pointer to current factor */ + + /* + * Decode array of coefficients stored with arithmetic coding + */ + { + const int scaling = 50; /* scaling factor of prob. model */ + unsigned c_symbols = 1 << (wfa->wfainfo->dc_rpf->mantissa_bits + 1); + + ptr = coefficients = decode_array (input, NULL, &c_symbols, 1, + total, scaling); + } + + /* + * Fill 'wfa->weights' with decoded coefficients + */ + { + unsigned state, label; + + for (state = wfa->basis_states; state < wfa->states; state++) + for (label = 0; label < MAXLABELS; label++) + if (ischild (wfa->tree [state][label]) + && isedge (wfa->into [state][label][0])) + { + wfa->weight [state][label][0] = btor (*ptr++, + wfa->wfainfo->dc_rpf); + wfa->int_weight [state][label][0] + = wfa->weight [state][label][0] * 512 + 0.5; + } + } + Free (coefficients); +} diff --git a/converter/other/fiasco/input/nd.h b/converter/other/fiasco/input/nd.h new file mode 100644 index 00000000..2c2fff4b --- /dev/null +++ b/converter/other/fiasco/input/nd.h @@ -0,0 +1,28 @@ +/* + * nd.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:13 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#ifndef _ND_H +#define _ND_H + +#include "wfa.h" +#include "rpf.h" +#include "bit-io.h" + +void +read_nd (wfa_t *wfa, bitfile_t *input); + +#endif /* not _ND_H */ + diff --git a/converter/other/fiasco/input/read.c b/converter/other/fiasco/input/read.c new file mode 100644 index 00000000..26bae7e4 --- /dev/null +++ b/converter/other/fiasco/input/read.c @@ -0,0 +1,499 @@ +/* + * read.c: Input of WFA files + * + * 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:58 $ + * $Author: hafner $ + * $Revision: 5.4 $ + * $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 <stdio.h> + +#include <string.h> + +#include "types.h" +#include "macros.h" +#include "error.h" + +#include "wfa.h" +#include "misc.h" +#include "rpf.h" +#include "bit-io.h" +#include "wfalib.h" + +#include "tree.h" +#include "matrices.h" +#include "weights.h" +#include "nd.h" +#include "mc.h" +#include "basis.h" +#include "read.h" + +/***************************************************************************** + + prototypes + +*****************************************************************************/ + +static void +read_tiling (tiling_t *tiling, unsigned image_width, unsigned image_height, + unsigned image_level, bitfile_t *input); + +/***************************************************************************** + + public code + +*****************************************************************************/ + +bitfile_t * +open_wfa (const char *filename, wfa_info_t *wi) +/* + * Open WFA file 'filename' and read header information. + * + * Return value: + * Pointer to input stream (fileposition: first WFA frame) + * + * Side effects: + * The values of the header of 'filename' are copied to 'wfainfo'. + * + */ +{ + bitfile_t *input; /* pointer to WFA bitfile */ + + assert (filename && wi); + + wi->wfa_name = strdup (filename); + + /* + * Check whether 'filename' is a regular WFA file + */ + { + unsigned n; + const char *str; + + if (!(input = open_bitfile (filename, "FIASCO_DATA", READ_ACCESS))) + file_error (filename); + + for (str = FIASCO_MAGIC, n = strlen (FIASCO_MAGIC); n; n--) + if (get_bits (input, 8) != (unsigned) *str++) + error ("Input file %s is not a valid FIASCO file!", filename); + get_bits (input, 8); /* fetch newline */ + } + + /* + * Read WFA header information + */ + { + char basis_name [MAXSTRLEN]; /* temp. buffer */ + const unsigned rice_k = 8; /* parameter of Rice Code */ + char *str = basis_name; + + while ((*str++ = get_bits (input, 8)) != 0 + && str < basis_name + MAXSTRLEN) + ; + if (str == basis_name + MAXSTRLEN) + error ("Input file %s is not a valid FIASCO file!", filename); + + { + wi->release = read_rice_code (rice_k, input); + + if (wi->release > FIASCO_BINFILE_RELEASE) + error ("Can't decode FIASCO files of file format release `%d'." + "\nCurrent file format release is `%d'.", wi->release, + FIASCO_BINFILE_RELEASE); + } + + if (wi->release > 1) + { + header_type_e type; + + while ((type = read_rice_code (rice_k, input)) != HEADER_END) + { + char buffer [MAXSTRLEN]; + unsigned n = 0; + + switch (type) + { + case HEADER_TITLE: + while ((buffer [n++] = get_bits (input, 8))) + ; + wi->title = strdup (buffer); + break; + case HEADER_COMMENT: + while ((buffer [n++] = get_bits (input, 8))) + ; + wi->comment = strdup (buffer); + break; + default: /* should not happen */ + break; + } + } + } + + wi->basis_name = strdup (basis_name); + wi->max_states = read_rice_code (rice_k, input); + wi->color = get_bit (input) ? YES : NO; + wi->width = read_rice_code (rice_k, input); + wi->height = read_rice_code (rice_k, input); + + /* + * Compute bintree level + */ + { + unsigned lx = log2 (wi->width - 1) + 1; + unsigned ly = log2 (wi->height - 1) + 1; + + wi->level = max (lx, ly) * 2 - ((ly == lx + 1) ? 1 : 0); + } + wi->chroma_max_states = wi->color ? read_rice_code (rice_k, input) : -1; + wi->p_min_level = read_rice_code (rice_k, input); + wi->p_max_level = read_rice_code (rice_k, input); + wi->frames = read_rice_code (rice_k, input); + wi->smoothing = read_rice_code (rice_k, input); + + /* + * Read RPF models from disk + */ + { + unsigned mantissa; + fiasco_rpf_range_e range; + + mantissa = get_bits (input, 3) + 2; + range = get_bits (input, 2); + wi->rpf = alloc_rpf (mantissa, range); + + if (get_bit (input)) /* different DC model */ + { + mantissa = get_bits (input, 3) + 2; + range = get_bits (input, 2); + wi->dc_rpf = alloc_rpf (mantissa, range); + } + else /* use same model for DC coefficents */ + wi->dc_rpf = alloc_rpf (wi->rpf->mantissa_bits, + wi->rpf->range_e); + + if (get_bit (input)) /* different delta model */ + { + mantissa = get_bits (input, 3) + 2; + range = get_bits (input, 2); + wi->d_rpf = alloc_rpf (mantissa, range); + } + else + wi->d_rpf = alloc_rpf (wi->rpf->mantissa_bits, + wi->rpf->range_e); + + if (get_bit (input)) /* different DC delta model */ + { + mantissa = get_bits (input, 3) + 2; + range = get_bits (input, 2); + wi->d_dc_rpf = alloc_rpf (mantissa, range); + } + else + wi->d_dc_rpf = alloc_rpf (wi->dc_rpf->mantissa_bits, + wi->dc_rpf->range_e); + } + + if (wi->frames > 1) /* motion compensation stuff */ + { + wi->fps = read_rice_code (rice_k, input); + wi->search_range = read_rice_code (rice_k, input); + wi->half_pixel = get_bit (input) ? YES : NO; + wi->B_as_past_ref = get_bit (input) ? YES : NO; + } + } + + INPUT_BYTE_ALIGN (input); + + return input; +} + +void +read_basis (const char *filename, wfa_t *wfa) +/* + * Read WFA initial basis 'filename' and fill 'wfa' struct. + * + * No return value. + * + * Side effects: + * wfa->into, wfa->weights, wfa->final_distribution, wfa->basis_states + * wfa->domain_type wfa->wfainfo->basis_name, are filled with the + * values of the WFA basis. + */ +{ + FILE *input; /* ASCII WFA initial basis file */ + + assert (filename && wfa); + + if (!wfa->wfainfo->basis_name || + !streq (wfa->wfainfo->basis_name, filename)) + { + if (wfa->wfainfo->basis_name) + Free (wfa->wfainfo->basis_name); + wfa->wfainfo->basis_name = strdup (filename); + } + + if (get_linked_basis (filename, wfa)) + return; /* basis is linked with excecutable */ + + /* + * Check whether 'wfa_name' is a regular ASCII WFA initial basis file + */ + { + char magic [MAXSTRLEN]; /* WFA magic number */ + + if (!(input = open_file (filename, "FIASCO_DATA", READ_ACCESS))) + file_error(filename); + + if (fscanf (input, MAXSTRLEN_SCANF, magic) != 1) + error ("Format error: ASCII FIASCO initial basis file %s", filename); + else if (strneq (FIASCO_BASIS_MAGIC, magic)) + error ("Input file %s is not an ASCII FIASCO initial basis!", + filename); + } + + /* + * WFA ASCII format: + * + * Note: State 0 is assumed to be the constant function f(x, y) = 128. + * Don't define any transitions of state 0 in an initial basis. + * + * Header: + * type |description + * ----------------+----------- + * string |MAGIC Number "Wfa" + * int |Number of basis states 'N' + * bool_t-array[N] |use vector in linear combinations, + * |0: don't use vector (auxilliary state) + * |1: use vector in linear combinations + * float-array[N] |final distribution of every state + * + * Transitions: + * + * <state 1> current state + * <label> <into> <weight> transition 1 of current state + * <label> <into> <weight> transition 2 of current state + * ... + * <-1> last transition marker + * <state 2> + * ... + * <-1> last transition marker + * <state N> + * ... + * + * <-1> last transition marker + * <-1> last state marker + */ + { + unsigned state; + + if (fscanf (input ,"%u", &wfa->basis_states) != 1) + error ("Format error: ASCII FIASCO initial basis file %s", filename); + + /* + * State 0 is assumed to be the constant function f(x, y) = 128. + */ + wfa->domain_type [0] = USE_DOMAIN_MASK; + wfa->final_distribution [0] = 128; + wfa->states = wfa->basis_states; + wfa->basis_states++; + + append_edge (0, 0, 1.0, 0, wfa); + append_edge (0, 0, 1.0, 1, wfa); + + for (state = 1; state < wfa->basis_states; state++) + wfa->domain_type [state] + = read_int (input) ? USE_DOMAIN_MASK : AUXILIARY_MASK; + + for (state = 1; state < wfa->basis_states; state++) + wfa->final_distribution[state] = read_real (input); + + /* + * Read transitions + */ + for (state = 1; state < wfa->basis_states; state++) + { + unsigned domain; + int label; + real_t weight; + + if (read_int (input) != (int) state) + error ("Format error: ASCII FIASCO initial basis file %s", + filename); + + while((label = read_int (input)) != -1) + { + domain = read_int (input); + weight = read_real (input); + append_edge (state, domain, weight, label, wfa); + } + } + } + + fclose (input); +} + +unsigned +read_next_wfa (wfa_t *wfa, bitfile_t *input) +/* + * Read next WFA frame of the WFA stream 'input'. + * WFA header information has to be already present in the 'wfainfo' struct. + * (i.e. open_wfa must be called first!) + * + * No return value. + * + * Side effects: + * wfa->into, wfa->weights, wfa->final_distribution, wfa->states + * wfa->x, wfa->y, wfa->level_of_state, wfa->domain_type + * mt->type, mt->number are filled with the values of the WFA file. + */ +{ + tiling_t tiling; /* tiling information */ + unsigned frame_number; /* current frame number */ + + assert (wfa && input); + + /* + * Frame header information + */ + { + const unsigned rice_k = 8; /* parameter of Rice Code */ + + wfa->states = read_rice_code (rice_k, input); + wfa->frame_type = read_rice_code (rice_k, input); + frame_number = read_rice_code (rice_k, input); + } + + if (wfa->wfainfo->release > 1) /* no alignment in version 1 */ + { + INPUT_BYTE_ALIGN (input); + } + + /* + * Read image tiling info + */ + if (get_bit (input)) /* tiling performed ? */ + read_tiling (&tiling, wfa->wfainfo->width, wfa->wfainfo->height, + wfa->wfainfo->level, input); + else + tiling.exponent = 0; + + INPUT_BYTE_ALIGN (input); + + read_tree (wfa, &tiling, input); + + /* + * Compute domain pool. + * Large images have not been used due to image tiling. + */ + { + unsigned state; + + for (state = wfa->basis_states; state < wfa->states; state++) + if ((!wfa->wfainfo->color + || (int) state <= wfa->tree [wfa->tree [wfa->root_state][0]][0]) + && + (!tiling.exponent || + wfa->level_of_state [state] <= (wfa->wfainfo->level + - tiling.exponent)) + && ((wfa->x [state][0] + + width_of_level (wfa->level_of_state [state])) + <= wfa->wfainfo->width) + && ((wfa->y [state][0] + + height_of_level (wfa->level_of_state [state])) + <= wfa->wfainfo->height)) + wfa->domain_type [state] = USE_DOMAIN_MASK; + else + wfa->domain_type [state] = 0; + } + + if (tiling.exponent) + Free (tiling.vorder); + + if (get_bit (input)) /* nondeterministic prediction used */ + read_nd (wfa, input); + + if (wfa->frame_type != I_FRAME) /* motion compensation used */ + read_mc (wfa->frame_type, wfa, input); + + locate_delta_images (wfa); + + /* + * Read linear combinations (coefficients and indices) + */ + { + unsigned edges = read_matrices (wfa, input); + + if (edges) + read_weights (edges, wfa, input); + } + + /* + * Compute final distribution of all states + */ + { + unsigned state; + + for (state = wfa->basis_states; state <= wfa->states; state++) + wfa->final_distribution[state] + = compute_final_distribution (state, wfa); + } + + return frame_number; +} + +/***************************************************************************** + + private code + +*****************************************************************************/ + +static void +read_tiling (tiling_t *tiling, unsigned image_width, unsigned image_height, + unsigned image_level, bitfile_t *input) +/* + * Read image tiling information from the given file 'input' + * and store parameters in struct 'tiling'. + * + * No return value. + */ +{ + const unsigned rice_k = 8; /* parameter of Rice Code */ + + tiling->exponent = read_rice_code (rice_k, input); + + if (get_bit (input)) /* variance order */ + { + unsigned tile; /* current image tile */ + unsigned x0, y0; /* NW corner of image tile */ + unsigned width, height; /* size of image tile */ + + tiling->vorder = Calloc (1 << tiling->exponent, sizeof (int)); + for (tile = 0; tile < 1U << tiling->exponent; tile++) + { + locate_subimage (image_level, image_level - tiling->exponent, tile, + &x0, &y0, &width, &height); + if (x0 < image_width && y0 < image_height) + tiling->vorder [tile] = get_bits (input, tiling->exponent); + else + tiling->vorder [tile] = -1; + } + } + else /* spiral order */ + { + tiling->vorder = Calloc (1 << tiling->exponent, sizeof (int)); + compute_spiral (tiling->vorder, image_width, image_height, + tiling->exponent, get_bit (input) ? YES : NO); + } +} diff --git a/converter/other/fiasco/input/read.h b/converter/other/fiasco/input/read.h new file mode 100644 index 00000000..d0d0ee13 --- /dev/null +++ b/converter/other/fiasco/input/read.h @@ -0,0 +1,31 @@ +/* + * read.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:13 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#ifndef _READ_H +#define _READ_H + +#include "wfa.h" +#include "bit-io.h" + +bitfile_t * +open_wfa (const char *filename, wfa_info_t *wfainfo); +void +read_basis (const char *filename, wfa_t *wfa); +unsigned +read_next_wfa (wfa_t *wfa, bitfile_t *input); + +#endif /* not _READ_H */ + diff --git a/converter/other/fiasco/input/tree.c b/converter/other/fiasco/input/tree.c new file mode 100644 index 00000000..e3e7117e --- /dev/null +++ b/converter/other/fiasco/input/tree.c @@ -0,0 +1,303 @@ +/* + * tree.c: Input of bintree partitioning + * + * 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:13 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#include "config.h" + +#include "types.h" +#include "macros.h" +#include "error.h" + +#include "bit-io.h" +#include "arith.h" +#include "misc.h" +#include "wfalib.h" +#include "tiling.h" + +#include "tree.h" + +/***************************************************************************** + + prototypes + +*****************************************************************************/ + +static unsigned +restore_depth_first_order (unsigned src_state, unsigned level, unsigned x, + unsigned y, unsigned *dst_state, + word_t (*bfo_tree)[MAXLABELS], + wfa_t *wfa, tiling_t *tiling); +static void +decode_tree (bitfile_t *input, byte_t *data, unsigned n_data, unsigned scaling, + u_word_t sum0, u_word_t sum1); + +/***************************************************************************** + + public code + +*****************************************************************************/ + +void +read_tree (wfa_t *wfa, tiling_t *tiling, bitfile_t *input) +/* + * Read bintree partitioning of WFA from the 'input' stream. + * 'tiling' provides the information about image tiling, if applied. + * + * No return value. + * + * Side effects: + * 'wfa->tree', 'wfa->x', 'wfa->y', 'wfa->level_of_state' + * are filled with decoded values. + */ +{ + byte_t *bitstring; /* the encoded data */ + word_t (*bfo_tree)[MAXLABELS]; /* node numbers in BFO */ + + /* + * Read WFA tree stored in breadth first order + */ + { + unsigned total = (wfa->states - wfa->basis_states) * MAXLABELS; + unsigned scale = total / 20; + + bitstring = Calloc (total, sizeof (byte_t)); + decode_tree (input, bitstring, total, scale, 1, 11); + } + + /* + * Generate tree using a breadth first traversal + */ + { + unsigned next; /* next free node number of the tree */ + unsigned state; + unsigned label; + byte_t *buffer = bitstring; /* pointer to decoded data */ + + bfo_tree = Calloc (wfa->states * MAXLABELS, sizeof (word_t)); + for (state = 0, next = 1; state < next; state++) + for (label = 0; label < MAXLABELS; label++) + bfo_tree [state][label] = *buffer++ ? next++ : RANGE; + } + + /* + * Traverse tree and restore depth first order + */ + { + unsigned dst_state = wfa->basis_states; + + wfa->root_state + = restore_depth_first_order (0, (wfa->wfainfo->level + + (wfa->wfainfo->color ? 2 : 0)), + 0, 0, &dst_state, bfo_tree, wfa, tiling); + } + + Free (bitstring); + Free (bfo_tree); +} + +/***************************************************************************** + + private code + +*****************************************************************************/ + +static unsigned +restore_depth_first_order (unsigned src_state, unsigned level, unsigned x, + unsigned y, unsigned *dst_state, + word_t (*bfo_tree)[MAXLABELS], + wfa_t *wfa, tiling_t *tiling) +/* + * Map state 'src_state' (breadth first order) + * to state '*dst_state' (depth first order) + * Add a tree edge 'state' --> 'child' with label and weight 1.0 + * if required. + * 'x', 'y' give the coordinates of the current state in the 'color' image + * of size 'image_level'. 'tiling' defines the image partitioning. + * + * Return value: + * new node number in depth first order + * + * Side effects: + * 'wfa->tree', 'wfa->x', 'wfa->y', 'wfa->level_of_state' + * are filled with decoded values. + */ +{ + unsigned newx [MAXLABELS]; /* x coordinate of childs */ + unsigned newy [MAXLABELS]; /* y coordinate of childs */ + unsigned x0, y0; /* NW corner of image tile */ + unsigned width, height; /* size of image tile */ + + /* + * If tiling is performed then replace current coordinates + */ + if (tiling->exponent && level == wfa->wfainfo->level - tiling->exponent) + { + unsigned tile; + + for (tile = 0; tile < 1U << tiling->exponent; tile++) + { + locate_subimage (wfa->wfainfo->level, level, tile, + &x0, &y0, &width, &height); + if (x0 == x && y0 == y) /* matched ! */ + { + locate_subimage (wfa->wfainfo->level, level, tiling->vorder[tile], + &x, &y, &width, &height); + break; + } + } + } + /* + * Coordinates of childs 0 and 1 + */ + if (wfa->wfainfo->color && level == wfa->wfainfo->level + 1) + newx[0] = newy[0] = newx[1] = newy[1] = 0; + else + { + newx[0] = x; + newy[0] = y; + newx[1] = level & 1 ? x : x + width_of_level (level - 1); + newy[1] = level & 1 ? y + height_of_level (level - 1) : y; + } + + /* + * Remap node numbers + */ + { + int child [MAXLABELS]; /* childs of current node (state) */ + int domain; /* current domain */ + unsigned label; + + for (label = 0; label < MAXLABELS; label++) + if (!isrange (domain = bfo_tree [src_state][label])) + child [label] = restore_depth_first_order (domain, level - 1, + newx [label], + newy [label], dst_state, + bfo_tree, wfa, tiling); + else + child [label] = RANGE; + + for (label = 0; label < MAXLABELS; label++) + { + wfa->tree [*dst_state][label] = child [label]; + wfa->x [*dst_state][label] = newx [label]; + wfa->y [*dst_state][label] = newy [label]; + } + wfa->level_of_state [*dst_state] = level; + } + + return (*dst_state)++; +} + +/**************************************************************************** + + Binary adaptive arithmetic compression + +****************************************************************************/ + +static void +decode_tree (bitfile_t *input, byte_t *data, unsigned n_data, unsigned scaling, + u_word_t sum0, u_word_t sum1) +/* + * Decode bintree partitioning using adaptive binary arithmetic decoding. + * 'input' input stream, + * 'data' buffer for decoded szmbols, + * 'n_data' number of symbols to decode, + * 'scaling' rescale probability models if range > 'scaling' + * 'sum0' initial totals of symbol '0' + * 'sum1' initial totals of symbol '1' + * + * No return value. + * + * Side effects: + * 'data []' is filled with the decoded bitstring + */ +{ + u_word_t code; /* The present input code value */ + u_word_t low; /* Start of the current code range */ + u_word_t high; /* End of the current code range */ + unsigned n; /* Data counter */ + + assert (data); + + code = get_bits (input, 16); + low = 0; + high = 0xffff; + + for (n = n_data; n; n--) + { + unsigned count; /* Current interval count */ + unsigned range; /* Current interval range */ + + count = (((code - low) + 1) * sum1 - 1) / ((high - low) + 1); + if (count < sum0) + { + /* + * Decode a '0' symbol + * First, the range is expanded to account for the symbol removal. + */ + range = (high - low) + 1; + high = low + (u_word_t) ((range * sum0) / sum1 - 1 ); + + RESCALE_INPUT_INTERVAL; + + *data++ = 0; + /* + * Update the frequency counts + */ + sum0++; + sum1++; + if (sum1 > scaling) /* scale the symbol frequencies */ + { + sum0 >>= 1; + sum1 >>= 1; + if (!sum0) + sum0 = 1; + if (sum0 >= sum1) + sum1 = sum0 + 1; + } + + } + else + { + /* + * Decode a '1' symbol + * First, the range is expanded to account for the symbol removal. + */ + range = (high - low) + 1; + high = low + (u_word_t) ((range * sum1) / sum1 - 1); + low = low + (u_word_t) ((range * sum0) / sum1); + + RESCALE_INPUT_INTERVAL; + + *data++ = 1; + /* + * Update the frequency counts + */ + sum1++; + if (sum1 > scaling) /* scale the symbol frequencies */ + { + sum0 >>= 1; + sum1 >>= 1; + if (!sum0) + sum0 = 1; + if (sum0 >= sum1) + sum1 = sum0 + 1; + } + } + } + INPUT_BYTE_ALIGN (input); +} + + diff --git a/converter/other/fiasco/input/tree.h b/converter/other/fiasco/input/tree.h new file mode 100644 index 00000000..e4b5f2d8 --- /dev/null +++ b/converter/other/fiasco/input/tree.h @@ -0,0 +1,28 @@ +/* + * tree.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:13 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#ifndef _TREE_H +#define _TREE_H + +#include "wfa.h" +#include "bit-io.h" +#include "tiling.h" + +void +read_tree (wfa_t *wfa, tiling_t *tiling, bitfile_t *input); + +#endif /* not _TREE_H */ + diff --git a/converter/other/fiasco/input/weights.c b/converter/other/fiasco/input/weights.c new file mode 100644 index 00000000..55339980 --- /dev/null +++ b/converter/other/fiasco/input/weights.c @@ -0,0 +1,200 @@ +/* + * weights.c: Input of weights + * + * 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:13 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#include "config.h" + +#include "types.h" +#include "macros.h" +#include "error.h" + +#include "bit-io.h" +#include "arith.h" +#include "rpf.h" +#include "misc.h" + +#include "weights.h" + +/***************************************************************************** + + public code + +*****************************************************************************/ + +void +read_weights (unsigned total, wfa_t *wfa, bitfile_t *input) +/* + * Read #'total' weights from input stream 'input' and + * update transitions of the WFA states with corresponding weights. + * + * No return value. + * + * Side effects: + * 'wfa->weights' are filled with the decoded values + */ +{ + unsigned state; + unsigned label; + unsigned edge; /* current edge */ + unsigned *weights_array; /* array of weights to encode */ + unsigned *level_array; /* array of corresponding levels */ + unsigned offset1, offset2; /* prob. model offsets. */ + unsigned offset3, offset4; /* prob. model offsets. */ + bool_t delta_approx = NO; /* true if delta has been used */ + + /* + * Check whether delta approximation has been used + */ + for (state = wfa->basis_states; state < wfa->states; state++) + if (wfa->delta_state [state]) + { + delta_approx = YES; + break; + } + + /* + * Generate array of corresponding levels (context of probability model) + */ + { + int min_level, max_level; /* min and max range level */ + int d_min_level, d_max_level; /* min and max range level (delta) */ + unsigned *lptr; /* pointer to current corresp. level */ + int domain; /* current domain */ + bool_t dc, d_dc; /* indicates whether DC is used */ + + /* + * Compute minimum and maximum level of delta and normal approximations + */ + min_level = d_min_level = MAXLEVEL; + max_level = d_max_level = 0; + dc = d_dc = NO; + + for (state = wfa->basis_states; state < wfa->states; state++) + for (label = 0; label < MAXLABELS; label++) + if (isrange (wfa->tree [state][label])) + { + if (delta_approx && wfa->delta_state [state]) + { + d_min_level = min (d_min_level, + wfa->level_of_state [state] - 1); + d_max_level = max (d_max_level, + wfa->level_of_state [state] - 1); + if (wfa->into [state][label][0] == 0) + d_dc = YES; + } + else + { + min_level = min (min_level, wfa->level_of_state [state] - 1); + max_level = max (max_level, wfa->level_of_state [state] - 1); + if (wfa->into [state][label][0] == 0) + dc = YES; + } + } + if (min_level > max_level) /* no lc found */ + max_level = min_level - 1; + if (d_min_level > d_max_level) + d_max_level = d_min_level - 1; + + offset1 = dc ? 1 : 0; + offset2 = offset1 + (d_dc ? 1 : 0); + offset3 = offset2 + (max_level - min_level + 1); + offset4 = offset3 + (d_max_level - d_min_level + 1); + + lptr = level_array = Calloc (total, sizeof (int)); + for (state = wfa->basis_states; state < wfa->states; state++) + for (label = 0; label < MAXLABELS; label++) + if (isrange (wfa->tree[state][label])) + for (edge = 0; isedge (domain = wfa->into[state][label][edge]); + edge++) + { + if ((unsigned) (lptr - level_array) >= total) + error ("Can't read more than %d weights.", total); + if (domain) + { + if (delta_approx && wfa->delta_state [state]) + *lptr++ = offset3 + wfa->level_of_state [state] + - 1 - d_min_level; + else + *lptr++ = offset2 + wfa->level_of_state [state] + - 1 - min_level; + } + else + *lptr++ = delta_approx && wfa->delta_state [state] + ? offset1 : 0; + } + } + + /* + * Decode the list of weights with an arithmetic decoder + */ + { + unsigned i; + unsigned *c_symbols = Calloc (offset4, sizeof (unsigned)); + const unsigned scale = 500; /* scaling of probability model */ + + c_symbols [0] = 1 << (wfa->wfainfo->dc_rpf->mantissa_bits + 1); + if (offset1 != offset2) + c_symbols [offset1] = 1 << (wfa->wfainfo->d_dc_rpf->mantissa_bits + + 1); + for (i = offset2; i < offset3; i++) + c_symbols [i] = 1 << (wfa->wfainfo->rpf->mantissa_bits + 1); + for (; i < offset4; i++) + c_symbols [i] = 1 << (wfa->wfainfo->d_rpf->mantissa_bits + 1); + + weights_array = decode_array (input, level_array, c_symbols, + offset4, total, scale); + Free (c_symbols); + } + Free (level_array); + + /* + * Update transitions with decoded weights + */ + { + unsigned *wptr = weights_array; /* pointer to current weight */ + int domain; /* current domain */ + + for (state = wfa->basis_states; state < wfa->states; state++) + for (label = 0; label < MAXLABELS; label++) + if (isrange (wfa->tree[state][label])) + for (edge = 0; isedge (domain = wfa->into[state][label][edge]); + edge++) + { + if (domain) /* not DC component */ + { + if (delta_approx && wfa->delta_state [state]) + wfa->weight [state][label][edge] + = btor (*wptr++, wfa->wfainfo->d_rpf); + else + wfa->weight [state][label][edge] + = btor (*wptr++, wfa->wfainfo->rpf); + } + else + { + if (delta_approx && wfa->delta_state [state]) + wfa->weight [state][label][edge] + = btor (*wptr++, wfa->wfainfo->d_dc_rpf); + else + wfa->weight [state][label][edge] + = btor (*wptr++, wfa->wfainfo->dc_rpf); + } + wfa->int_weight [state][label][edge] + = wfa->weight [state][label][edge] * 512 + 0.5; + } + } + + Free (weights_array); +} + diff --git a/converter/other/fiasco/input/weights.h b/converter/other/fiasco/input/weights.h new file mode 100644 index 00000000..1e2285a9 --- /dev/null +++ b/converter/other/fiasco/input/weights.h @@ -0,0 +1,27 @@ +/* + * weights.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:13 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#ifndef _WEIGHTS_H +#define _WEIGHTS_H + +#include "wfa.h" +#include "bit-io.h" + +void +read_weights (unsigned total, wfa_t *wfa, bitfile_t *input); + +#endif /* not _WEIGHTS_H */ + diff --git a/converter/other/fiasco/lib/Makefile b/converter/other/fiasco/lib/Makefile new file mode 100644 index 00000000..99d7c1d7 --- /dev/null +++ b/converter/other/fiasco/lib/Makefile @@ -0,0 +1,33 @@ +ifeq ($(SRCDIR)x,x) + SRCDIR = $(CURDIR)/../../../.. + BUILDDIR = $(SRCDIR) +endif +FIASCOSUBDIR = converter/other/fiasco +SUBDIR = $(FIASCOSUBDIR)/lib +VPATH=.:$(SRCDIR)/$(SUBDIR) + +include $(BUILDDIR)/Makefile.config + +OBJECTS = \ + arith.o \ + bit-io.o \ + dither.o \ + error.o \ + image.o \ + list.o \ + misc.o \ + rpf.o \ + mvcode.o \ + +MERGE_OBJECTS = $(OBJECTS) + +INCLUDES = -I$(SRCDIR)/$(FIASCOSUBDIR) + +all: libfiasco_lib.a + +include $(SRCDIR)/Makefile.common + +libfiasco_lib.a: $(OBJECTS) + $(AR) -rc $@ $(OBJECTS) + $(RANLIB) $@ + diff --git a/converter/other/fiasco/lib/arith.c b/converter/other/fiasco/lib/arith.c new file mode 100644 index 00000000..e3745bf7 --- /dev/null +++ b/converter/other/fiasco/lib/arith.c @@ -0,0 +1,708 @@ +/* + * arith.c: Adaptive arithmetic coding 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/06/14 20:49:37 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#include "config.h" + +#include "types.h" +#include "macros.h" +#include "error.h" + +#include "bit-io.h" +#include "misc.h" +#include "arith.h" + +/****************************************************************************** + + public code + +******************************************************************************/ + +arith_t * +alloc_encoder (bitfile_t *output) +/* + * Arithmetic coder constructor: + * Initialize the arithmetic coder. + * + * Return value: + * A pointer to the new coder structure + */ +{ + arith_t *arith = Calloc (1, sizeof (arith_t)); + + assert (output); + + arith->low = LOW; + arith->high = HIGH; + arith->underflow = 0; + arith->file = output; + + return arith; +} + +void +free_encoder (arith_t *arith) +/* + * Arithmetic encoder destructor. + * Flush the arithmetic coder. Append all remaining bits to the + * output stream. Append zero bits to get the output file byte aligned. + * + * No return value. + */ +{ + u_word_t low; /* start of the current code range */ + u_word_t high; /* end of the current code range */ + u_word_t underflow; /* number of underflow bits pending */ + bitfile_t *output; + + assert (arith); + + low = arith->low; + high = arith->high; + underflow = arith->underflow; + output = arith->file; + + low = high; + + RESCALE_OUTPUT_INTERVAL; + + OUTPUT_BYTE_ALIGN (output); + + Free (arith); +} + +real_t +encode_symbol (unsigned symbol, arith_t *arith, model_t *model) +/* + * Encode the given 'symbol' using the given probability 'model'. + * The current state of the arithmetic coder is given by 'arith'. + * Output bits are appended to the stream 'output'. + * + * The model is updated after encoding the symbol (if neccessary the + * symbol counts are rescaled). + * + * Return value: + * information content of the encoded symbol. + * + * Side effects: + * 'model' is updated (probability distribution) + * 'arith' is updated (coder state) + */ +{ + u_word_t low_count; /* lower bound of 'symbol' interval */ + u_word_t high_count; /* upper bound of 'symbol' interval */ + u_word_t scale; /* range of all 'm' symbol intervals */ + unsigned range; /* range of current interval */ + unsigned index; /* index of probability model */ + u_word_t low; /* start of the current code range */ + u_word_t high; /* end of the current code range */ + u_word_t underflow; /* number of underflow bits pending */ + bitfile_t *output; /* output file */ + + assert (model && arith); + + /* + * Get interval values + */ + low = arith->low; + high = arith->high; + underflow = arith->underflow; + output = arith->file; + + assert (high > low); + + if (model->order > 0) /* order-'n' model*/ + { + unsigned power; /* multiplicator */ + unsigned i; + + /* + * Compute index of the probability model to use. + * See init_model() for more details. + */ + power = 1; /* multiplicator */ + index = 0; /* address of prob. model */ + + for (i = 0; i < model->order; i++) /* genarate a M-nary number */ + { + index += model->context [i] * power; + power *= model->symbols; + } + + index *= model->symbols + 1; /* we need space for M + 1 elements */ + + for (i = 0; i < model->order - 1; i++) + model->context [i] = model->context [i + 1]; + model->context [i] = symbol; + } + else + index = 0; + + scale = model->totals [index + model->symbols]; + low_count = model->totals [index + symbol]; + high_count = model->totals [index + symbol + 1]; + + /* + * Compute the new interval depending on the input 'symbol'. + */ + range = (high - low) + 1; + high = low + (u_word_t) ((range * high_count) / scale - 1); + low = low + (u_word_t) ((range * low_count) / scale); + + RESCALE_OUTPUT_INTERVAL; + + if (model->scale > 0) /* adaptive model */ + { + unsigned i; + + /* + * Update probability model + */ + for (i = symbol + 1; i <= model->symbols; i++) + model->totals [index + i]++; + if (model->totals [index + model->symbols] > model->scale) /* scaling */ + { + for (i = 1; i <= model->symbols; i++) + { + model->totals [index + i] >>= 1; + if (model->totals [index + i] <= model->totals [index + i - 1]) + model->totals [index + i] = model->totals [index + i - 1] + 1; + } + } + } + + /* + * Store interval values + */ + arith->low = low; + arith->high = high; + arith->underflow = underflow; + + return - log2 ((high_count - low_count) / (real_t) scale); +} + +void +encode_array (bitfile_t *output, const unsigned *data, const unsigned *context, + const unsigned *c_symbols, unsigned n_context, unsigned n_data, + unsigned scaling) +/* + * Arithmetic coding of #'n_data' symbols given in the array 'data'. + * If 'n_context' > 1 then a number (context [n]) is assigned to every + * data element n, specifying which context (i.e. number of symbols given by + * c_symbols [context [n]] and adaptive probability model) must be used. + * Rescale probability models if range > 'scaling'. + * + * No return value. + */ +{ + u_word_t **totals; /* probability model */ + + if (!n_context) + n_context = 1; /* always use one context */ + + assert (output && c_symbols && data); + assert (n_context == 1 || context); + + /* + * Allocate probability models, start with uniform distribution + */ + totals = Calloc (n_context, sizeof (u_word_t *)); + { + unsigned c; + + for (c = 0; c < n_context; c++) + { + unsigned i; + + totals [c] = Calloc (c_symbols [c] + 1, sizeof (u_word_t)); + totals [c][0] = 0; + + for (i = 0; i < c_symbols [c]; i++) + totals [c][i + 1] = totals [c][i] + 1; + } + } + + /* + * Encode array elements + */ + { + u_word_t low = 0; /* Start of the current code range */ + u_word_t high = 0xffff; /* End of the current code range */ + u_word_t underflow = 0; /* Number of underflow bits pending */ + unsigned n; + + for (n = 0; n < n_data; n++) + { + u_word_t low_count; /* lower bound of 'symbol' interval */ + u_word_t high_count; /* upper bound of 'symbol' interval */ + u_word_t scale; /* range of all 'm' symbol intervals */ + unsigned range; /* current range */ + int d; /* current data symbol */ + int c; /* context of current data symbol */ + + d = data [n]; + c = n_context > 1 ? context [n] : 0; + + scale = totals [c][c_symbols [c]]; + low_count = totals [c][d]; + high_count = totals [c][d + 1]; + + /* + * Rescale high and low for the new symbol. + */ + range = (high - low) + 1; + high = low + (u_word_t) ((range * high_count) / scale - 1); + low = low + (u_word_t) ((range * low_count) / scale); + RESCALE_OUTPUT_INTERVAL; + + /* + * Update probability models + */ + { + unsigned i; + + for (i = d + 1; i < c_symbols [c] + 1; i++) + totals [c][i]++; + + if (totals [c][c_symbols [c]] > scaling) /* scaling */ + for (i = 1; i < c_symbols [c] + 1; i++) + { + totals [c][i] >>= 1; + if (totals [c][i] <= totals [c][i - 1]) + totals [c][i] = totals [c][i - 1] + 1; + } + } + } + /* + * Flush arithmetic encoder + */ + low = high; + RESCALE_OUTPUT_INTERVAL; + OUTPUT_BYTE_ALIGN (output); + } + + /* + * Cleanup ... + */ + { + unsigned c; + for (c = 0; c < n_context; c++) + Free (totals [c]); + Free (totals); + } +} + +arith_t * +alloc_decoder (bitfile_t *input) +/* + * Arithmetic decoder constructor: + * Initialize the arithmetic decoder with the first + * 16 input bits from the stream 'input'. + * + * Return value: + * A pointer to the new decoder structure + */ + +{ + arith_t *arith = Calloc (1, sizeof (arith_t)); + + assert (input); + + arith->low = LOW; + arith->high = HIGH; + arith->code = get_bits (input, 16); + arith->file = input; + + return arith; +} + +void +free_decoder (arith_t *arith) +/* + * Arithmetic decoder destructor: + * Flush the arithmetic decoder, i.e., read bits to get the input + * file byte aligned. + * + * No return value. + * + * Side effects: + * structure 'arith' is discarded. + */ +{ + assert (arith); + + INPUT_BYTE_ALIGN (arith->file); + + Free (arith); +} + +unsigned +decode_symbol (arith_t *arith, model_t *model) +/* + * Decode the next symbol - the state of the arithmetic decoder + * is given in 'arith'. Read refinement bits from the stream 'input' + * and use the given probability 'model'. Update the probability model after + * deconding the symbol (if neccessary also rescale the symbol counts). + * + * Return value: + * decoded symbol + * + * Side effects: + * 'model' is updated (probability distribution) + * 'arith' is updated (decoder state) + */ +{ + unsigned range; /* range of current interval */ + unsigned count; /* value in the current interval */ + unsigned index; /* index of probability model */ + unsigned symbol; /* decoded symbol */ + u_word_t scale; /* range of all 'm' symbol intervals */ + u_word_t low; /* start of the current code range */ + u_word_t high; /* end of the current code range */ + u_word_t code; /* the present input code value */ + bitfile_t *input; /* input file */ + + assert (arith && model); + + /* + * Get interval values + */ + low = arith->low; + high = arith->high; + code = arith->code; + input = arith->file; + + assert (high > low); + + if (model->order > 0) /* order-'n' model */ + { + unsigned power; /* multiplicator */ + unsigned i; + + /* + * Compute index of the probability model to use. + * See init_model() for more details. + */ + power = 1; /* multiplicator */ + index = 0; /* address of prob. model */ + + for (i = 0; i < model->order; i++) /* genarate a m-nary number */ + { + index += model->context[i] * power; + power *= model->symbols; + } + + index *= model->symbols + 1; /* we need space for m + 1 elements */ + } + else + index = 0; + + scale = model->totals [index + model->symbols]; + range = (high - low) + 1; + count = ((code - low + 1) * scale - 1) / range; + + for (symbol = model->symbols; count < model->totals [index + symbol]; + symbol--) + ; + + if (model->order > 0) /* order-'n' model */ + { + unsigned i; + + for (i = 0; i < model->order - 1; i++) + model->context [i] = model->context [i + 1]; + model->context [i] = symbol; + } + + /* + * Compute interval boundaries + */ + { + u_word_t low_count; /* lower bound of 'symbol' interval */ + u_word_t high_count; /* upper bound of 'symbol' interval */ + + low_count = model->totals [index + symbol]; + high_count = model->totals [index + symbol + 1]; + high = low + (u_word_t) ((range * high_count) / scale - 1 ); + low = low + (u_word_t) ((range * low_count) / scale ); + } + + RESCALE_INPUT_INTERVAL; + + if (model->scale > 0) /* adaptive model */ + { + unsigned i; + + /* + * Update probability model + */ + for (i = symbol + 1; i <= model->symbols; i++) + model->totals [index + i]++; + if (model->totals [index + model->symbols] > model->scale) /* scaling */ + { + for (i = 1; i <= model->symbols; i++) + { + model->totals [index + i] >>= 1; + if (model->totals [index + i] <= model->totals [index + i - 1]) + model->totals [index + i] = model->totals [index + i - 1] + 1; + } + } + } + + /* + * Store interval values + */ + arith->low = low; + arith->high = high; + arith->code = code; + + return symbol; +} + +unsigned * +decode_array (bitfile_t *input, const unsigned *context, + const unsigned *c_symbols, unsigned n_context, + unsigned n_data, unsigned scaling) +/* + * Arithmetic decoding of #'n_data' symbols. + * If 'n_context' > 1 then a number (context [n]) is assigned to every + * data element n, specifying which context (i.e. number of symbols given by + * c_symbols [context [n]] and adaptive probability model) must be used. + * Rescale probability models if range > 'scaling'. + * + * Return value: + * pointer to array containing the decoded symbols + */ +{ + unsigned *data; /* array to store decoded symbols */ + u_word_t **totals; /* probability model */ + + if (n_context < 1) + n_context = 1; /* always use one context */ + assert (input && c_symbols); + assert (n_context == 1 || context); + + data = Calloc (n_data, sizeof (unsigned)); + + /* + * Allocate probability models, start with uniform distribution + */ + totals = Calloc (n_context, sizeof (u_word_t *)); + { + unsigned c; + + for (c = 0; c < n_context; c++) + { + unsigned i; + + totals [c] = Calloc (c_symbols [c] + 1, sizeof (u_word_t)); + totals [c][0] = 0; + + for (i = 0; i < c_symbols [c]; i++) + totals [c][i + 1] = totals [c][i] + 1; + } + } + + /* + * Fill array 'data' with decoded values + */ + { + u_word_t code = get_bits (input, 16); /* The present input code value */ + u_word_t low = 0; /* Start of the current code range */ + u_word_t high = 0xffff; /* End of the current code range */ + unsigned n; + + for (n = 0; n < n_data; n++) + { + u_word_t scale; /* range of all 'm' symbol intervals */ + u_word_t low_count; /* lower bound of 'symbol' interval */ + u_word_t high_count; /* upper bound of 'symbol' interval */ + unsigned count; /* value in the current interval */ + unsigned range; /* current interval range */ + unsigned d; /* current data symbol */ + unsigned c; /* context of current data symbol */ + + c = n_context > 1 ? context [n] : 0; + + assert (high > low); + scale = totals [c][c_symbols [c]]; + range = (high - low) + 1; + count = (((code - low) + 1 ) * scale - 1) / range; + + for (d = c_symbols [c]; count < totals [c][d]; d--) /* next symbol */ + ; + low_count = totals [c][d]; + high_count = totals [c][d + 1]; + + high = low + (u_word_t) ((range * high_count) / scale - 1 ); + low = low + (u_word_t) ((range * low_count) / scale ); + RESCALE_INPUT_INTERVAL; + + /* + * Updata probability models + */ + { + unsigned i; + + for (i = d + 1; i < c_symbols [c] + 1; i++) + totals [c][i]++; + + if (totals [c][c_symbols [c]] > scaling) /* scaling */ + for (i = 1; i < c_symbols [c] + 1; i++) + { + totals [c][i] >>= 1; + if (totals [c][i] <= totals [c][i - 1]) + totals [c][i] = totals [c][i - 1] + 1; + } + } + data [n] = d; + } + INPUT_BYTE_ALIGN (input); + } + + /* + * Cleanup ... + */ + { + unsigned c; + + for (c = 0; c < n_context; c++) + Free (totals [c]); + Free (totals); + } + + return data; +} + +model_t * +alloc_model (unsigned m, unsigned scale, unsigned n, unsigned *totals) +/* + * Model constructor: + * allocate and initialize an order-'n' probability model. + * The size of the source alphabet is 'm'. Rescale the symbol counts after + * 'scale' symbols are encoded/decoded. The initial probability of every + * symbol is 1/m. + * If 'scale' = 0 then use static modeling (p = 1/n). + * If 'totals' is not NULL then use this array of 'm' values to set + * the initial counts. + * + * Return value: + * a pointer to the new probability model structure. + * + * Note: We recommend a small size of the alphabet because no escape codes + * are used to encode/decode previously unseen symbols. + * + */ +{ + model_t *model; /* new probability model */ + unsigned num; /* number of contexts to allocate */ + bool_t cont; /* continue flag */ + bool_t dec; /* next order flag */ + unsigned i; + + /* + * Allocate memory for the structure + */ + model = Calloc (1, sizeof (model_t)); + model->symbols = m; + model->scale = scale; + model->order = n; + model->context = n > 0 ? Calloc (n, sizeof (unsigned)) : NULL; + /* + * Allocate memory for the probabilty model. + * Each of the m^n different contexts requires its own probability model. + */ + for (num = 1, i = 0; i < model->order; i++) + num *= model->symbols; + + model->totals = Calloc (num * (model->symbols + 1), sizeof (unsigned)); + + for (i = 0; i < model->order; i++) + model->context[i] = 0; /* start with context 0,0, .. ,0 */ + cont = YES; + while (cont) /* repeat while context != M ... M */ + { + int power; /* multiplicator */ + int index; /* index of probability model */ + /* + * There are m^n different contexts: + * Let "context_1 context_2 ... context_n symbol" be the current input + * stream then the index of the probability model is given by: + * index = context_1 * M^0 + context_2 * M^1 + ... + context_n * M^(n-1) + */ + power = 1; /* multiplicator */ + index = 0; /* address of prob. model */ + + for (i = 0; i < model->order; i++) /* genarate a m-nary number */ + { + index += model->context[i] * power; + power *= model->symbols; + } + + index *= model->symbols + 1; /* size of each model is m + 1 */ + + model->totals [index + 0] = 0; /* always zero */ + + for (i = 1; i <= model->symbols; i++) /* prob of each symbol is 1/m or + as given in totals */ + model->totals[index + i] = model->totals [index + i - 1] + + (totals ? totals [i - 1] : 1); + + if (model->order == 0) /* order-0 model */ + cont = NO; + else /* try next context */ + for (i = model->order - 1, dec = YES; dec; i--) + { + dec = NO; + model->context[i]++; + if (model->context[i] >= model->symbols) + { + /* change previous context */ + model->context[i] = 0; + if (i > 0) /* there's still a context remaining */ + dec = YES; + else + cont = NO; /* all context models initilized */ + } + } + } + for (i = 0; i < model->order; i++) + model->context[i] = 0; /* start with context 0,0, .. ,0 */ + + return model; +} + +void +free_model (model_t *model) +/* + * Model destructor: + * Free memory allocated by the arithmetic 'model'. + * + * No return value. + * + * Side effects: + * struct 'model' is discarded + */ +{ + if (model != NULL) + { + if (model->context != NULL) + Free (model->context); + Free (model->totals); + Free (model); + } + else + warning ("Can't free model <NULL>."); +} diff --git a/converter/other/fiasco/lib/arith.h b/converter/other/fiasco/lib/arith.h new file mode 100644 index 00000000..744eb9d7 --- /dev/null +++ b/converter/other/fiasco/lib/arith.h @@ -0,0 +1,122 @@ +/* + * arith.h + * + * 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:49:37 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#ifndef _ARITH_H +#define _ARITH_H + +#include "types.h" +#include "bit-io.h" + +typedef struct model +{ + unsigned symbols; /* number of symbols in the alphabet */ + unsigned scale; /* if totals > scale rescale totals */ + unsigned order; /* order of the probability model */ + unsigned *context; /* context of the model */ + unsigned *totals; /* the totals */ +} model_t; + +typedef struct arith +{ + u_word_t low; /* start of the current code range */ + u_word_t high; /* end of the current code range */ + u_word_t underflow; /* number of underflow bits pending */ + u_word_t code; /* the present input code value */ + bitfile_t *file; /* I/O stream */ +} arith_t; + +enum interval {LOW = 0x0000, FIRST_QUARTER = 0x4000, HALF = 0x8000, + THIRD_QUARTER = 0xc000, HIGH = 0xffff}; + +arith_t * +alloc_encoder (bitfile_t *file); +void +free_encoder (arith_t *arith); +real_t +encode_symbol (unsigned symbol, arith_t *arith, model_t *model); +void +encode_array (bitfile_t *output, const unsigned *data, const unsigned *context, + const unsigned *c_symbols, unsigned n_context, unsigned n_data, + unsigned scaling); +arith_t * +alloc_decoder (bitfile_t *input); +void +free_decoder (arith_t *arith); +unsigned +decode_symbol (arith_t *arith, model_t *model); +unsigned * +decode_array (bitfile_t *input, const unsigned *context, + const unsigned *c_symbols, unsigned n_context, + unsigned n_data, unsigned scaling); +model_t * +alloc_model (unsigned m, unsigned scale, unsigned n, unsigned *totals); +void +free_model (model_t *model); + +#define RESCALE_INPUT_INTERVAL for (;;) \ + if ((high >= HALF) && (low < HALF) && \ + ((low & FIRST_QUARTER) != FIRST_QUARTER \ + || (high & FIRST_QUARTER) != 0)) \ + { \ + break; \ + } \ + else if ((high < HALF) || (low >= HALF)) \ + { \ + low <<= 1; \ + high <<= 1; \ + high |= 1; \ + code <<= 1; \ + code += get_bit (input); \ + } \ + else \ + { \ + code ^= FIRST_QUARTER; \ + low &= FIRST_QUARTER - 1; \ + low <<= 1; \ + high <<= 1; \ + high |= HALF + 1; \ + code <<= 1; \ + code += get_bit (input); \ + } + +#define RESCALE_OUTPUT_INTERVAL for (;;) \ + { \ + if (high < HALF) \ + { \ + put_bit (output, 0); \ + for (; underflow; underflow--) \ + put_bit (output, 1); \ + } \ + else if (low >= HALF) \ + { \ + put_bit (output, 1); \ + for (; underflow; underflow--) \ + put_bit (output, 0); \ + } \ + else if (high < THIRD_QUARTER && \ + low >= FIRST_QUARTER) \ + { \ + underflow++; \ + high |= FIRST_QUARTER; \ + low &= FIRST_QUARTER - 1; \ + } \ + else \ + break; \ + high <<= 1; \ + high |= 1; \ + low <<= 1; \ + } + +#endif /* not _ARITH_H */ + diff --git a/converter/other/fiasco/lib/bit-io.c b/converter/other/fiasco/lib/bit-io.c new file mode 100644 index 00000000..364a1c05 --- /dev/null +++ b/converter/other/fiasco/lib/bit-io.c @@ -0,0 +1,327 @@ +/* + * bit-io.c: Buffered and bit oriented file I/O + * + * 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:49:37 $ + * $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 <string.h> +#if STDC_HEADERS +# include <stdlib.h> +#endif /* not STDC_HEADERS */ + +#include "macros.h" +#include "types.h" +#include "error.h" + +#include "misc.h" +#include "bit-io.h" + +/***************************************************************************** + + local constants + +*****************************************************************************/ + +static const unsigned BUFFER_SIZE = 16350; + +static const unsigned mask[] = {0x0001, 0x0002, 0x0004, 0x0008, + 0x0010, 0x0020, 0x0040, 0x0080, + 0x0100, 0x0200, 0x0400, 0x0800, + 0x1000, 0x2000, 0x4000, 0x8000}; + +/***************************************************************************** + + public code + +*****************************************************************************/ + +FILE * +open_file (const char *filename, const char *env_var, openmode_e mode) +/* + * Try to open file 'filename' with mode 'mode' (READ_ACCESS, WRITE_ACCESS). + * Scan the current directory first and then cycle through the + * path given in the environment variable 'env_var', if set. + * + * Return value: + * Pointer to open file on success, else NULL. + */ +{ + char *path; /* current path */ + FILE *fp; /* file pointer of I/O stream */ + char *ext_filename = NULL; /* full path of file */ + char *env_path = NULL; /* path given by 'env_var' */ + char const * const PATH_SEP = " ;:,"; /* path separation characters */ + char const * const DEFAULT_PATH = "."; /* default for output files */ + const char * const read_mode = "rb"; + const char * const write_mode = "wb"; + + + assert (mode == READ_ACCESS || mode == WRITE_ACCESS); + + /* + * First check for stdin or stdout + */ + if (filename == NULL || streq (filename, "-")) + { + if (mode == READ_ACCESS) + return stdin; + else + return stdout; + } + + /* + * Try to open 'readonly' file in the current directory + */ + if (mode == READ_ACCESS && (fp = fopen (filename, read_mode))) + return fp; + + if (mode == WRITE_ACCESS && strchr (filename, '/')) /* contains path */ + return fopen (filename, write_mode); + + /* + * Get value of environment variable 'env_var', if set + * else use DEFAULT_PATH ("./") + */ + if (env_var != NULL) + env_path = getenv (env_var); + if (env_path == NULL) + env_path = strdup (DEFAULT_PATH); + else + env_path = strdup (env_path); + + /* + * Try to open file in the directory given by the environment + * variable env_var - individual path components are separated by PATH_SEP + */ + path = strtok (env_path, PATH_SEP); + do + { + if (ext_filename) + Free (ext_filename); + ext_filename = Calloc (strlen (path) + strlen (filename) + 2, + sizeof (char)); + strcpy (ext_filename, path); + if (*(ext_filename + strlen (ext_filename) - 1) != '/') + strcat (ext_filename, "/"); + strcat (ext_filename, filename); + fp = fopen (ext_filename, mode == READ_ACCESS ? read_mode : write_mode); + } + while (fp == NULL && (path = strtok (NULL, PATH_SEP)) != NULL); + + Free (env_path); + + return fp; +} + +bitfile_t * +open_bitfile (const char *filename, const char *env_var, openmode_e mode) +/* + * Bitfile constructor: + * Try to open file 'filename' for buffered bit oriented access with mode + * 'mode'. Scan the current directory first and then cycle through the path + * given in the environment variable 'env_var', if set. + * + * Return value: + * Pointer to open bitfile on success, + * otherwise the program is terminated. + */ +{ + bitfile_t *bitfile = Calloc (1, sizeof (bitfile_t)); + + bitfile->file = open_file (filename, env_var, mode); + + if (bitfile->file == NULL) + file_error (filename); + + if (mode == READ_ACCESS) + { + bitfile->bytepos = 0; + bitfile->bitpos = 0; + bitfile->mode = mode; + bitfile->filename = filename ? strdup (filename) : strdup ("(stdin)"); + } + else if (mode == WRITE_ACCESS) + { + bitfile->bytepos = BUFFER_SIZE - 1; + bitfile->bitpos = 8; + bitfile->mode = mode; + bitfile->filename = filename ? strdup (filename) : strdup ("(stdout)"); + } + else + error ("Unknow file access mode '%d'.", mode); + + bitfile->bits_processed = 0; + bitfile->buffer = Calloc (BUFFER_SIZE, sizeof (byte_t)); + bitfile->ptr = bitfile->buffer; + + return bitfile; +} + +bool_t +get_bit (bitfile_t *bitfile) +/* + * Get one bit from the given stream 'bitfile'. + * + * Return value: + * 1 H bit + * 0 L bit + * + * Side effects: + * Buffer of 'bitfile' is modified accordingly. + */ +{ + assert (bitfile); + + if (!bitfile->bitpos--) /* use next byte ? */ + { + bitfile->ptr++; + if (!bitfile->bytepos--) /* no more bytes left in the buffer? */ + { + /* + * Fill buffer with new data + */ + int bytes = fread (bitfile->buffer, sizeof (byte_t), + BUFFER_SIZE, bitfile->file) - 1; + if (bytes < 0) /* Error or EOF */ + error ("Can't read next bit from bitfile %s.", bitfile->filename); + else + bitfile->bytepos = bytes; + + bitfile->ptr = bitfile->buffer; + } + bitfile->bitpos = 7; + } + + bitfile->bits_processed++; + + return *bitfile->ptr & mask [bitfile->bitpos] ? 1 : 0; +} + +unsigned int +get_bits (bitfile_t *bitfile, unsigned bits) +/* + * Get #'bits' bits from the given stream 'bitfile'. + * + * Return value: + * composed integer value + * + * Side effects: + * Buffer of 'bitfile' is modified. + */ +{ + unsigned value = 0; /* input value */ + + while (bits--) + value = (unsigned) (value << 1) | get_bit (bitfile); + + return value; +} + +void +put_bit (bitfile_t *bitfile, unsigned value) +/* + * Put the bit 'value' to the bitfile buffer. + * The buffer is written to the file 'bitfile->file' if the number of + * buffer bytes exceeds 'BUFFER_SIZE'. + * + * No return value. + * + * Side effects: + * Buffer of 'bitfile' is modified. + */ +{ + assert (bitfile); + + if (!bitfile->bitpos--) /* use next byte ? */ + { + bitfile->ptr++; + if (!bitfile->bytepos--) /* no more bytes left ? */ + { + /* + * Write buffer to disk and fill buffer with zeros + */ + if (fwrite (bitfile->buffer, sizeof (byte_t), + BUFFER_SIZE, bitfile->file) != BUFFER_SIZE) + error ("Can't write next bit of bitfile %s!", bitfile->filename); + memset (bitfile->buffer, 0, BUFFER_SIZE); + bitfile->bytepos = BUFFER_SIZE - 1; + bitfile->ptr = bitfile->buffer; + } + bitfile->bitpos = 7; + } + + if (value) + *bitfile->ptr |= mask [bitfile->bitpos]; + + bitfile->bits_processed++; +} + +void +put_bits (bitfile_t *bitfile, unsigned value, unsigned bits) +/* + * Put #'bits' bits of integer 'value' to the bitfile buffer 'bitfile'. + * + * No return value. + * + * Side effects: + * Buffer of 'bitfile' is modified. + */ +{ + while (bits--) + put_bit (bitfile, value & mask [bits]); +} + +void +close_bitfile (bitfile_t *bitfile) +/* + * Bitfile destructor: + * Close 'bitfile', if 'bitfile->mode' == WRITE_ACCESS write bit buffer + * to disk. + * + * No return value. + * + * Side effects: + * Structure 'bitfile' is discarded. + */ +{ + assert (bitfile); + + if (bitfile->mode == WRITE_ACCESS) + { + unsigned bytes = fwrite (bitfile->buffer, sizeof (byte_t), + BUFFER_SIZE - bitfile->bytepos, bitfile->file); + if (bytes != BUFFER_SIZE - bitfile->bytepos) + error ("Can't write remaining %d bytes of bitfile " + "(only %d bytes written)!", + BUFFER_SIZE - bitfile->bytepos, bytes); + } + fclose (bitfile->file); + Free (bitfile->buffer); + Free (bitfile->filename); + Free (bitfile); +} + +unsigned +bits_processed (const bitfile_t *bitfile) +/* + * Return value: + * Number of bits processed up to now + */ +{ + return bitfile->bits_processed; +} diff --git a/converter/other/fiasco/lib/bit-io.h b/converter/other/fiasco/lib/bit-io.h new file mode 100644 index 00000000..d37cc47c --- /dev/null +++ b/converter/other/fiasco/lib/bit-io.h @@ -0,0 +1,58 @@ +/* + * bit-io.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:49:37 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#ifndef _BIT_IO_H +#define _BIT_IO_H + +#include <stdio.h> +#include "types.h" + +#define OUTPUT_BYTE_ALIGN(bfile) while ((bfile)->bitpos) put_bit (bfile, 0); +#define INPUT_BYTE_ALIGN(bfile) while ((bfile)->bitpos) get_bit (bfile); + +typedef enum {READ_ACCESS, WRITE_ACCESS} openmode_e; + +typedef struct bitfile +{ + FILE *file; /* associated filepointer */ + char *filename; /* corresponding filename */ + byte_t *buffer; /* stream buffer */ + byte_t *ptr; /* pointer to current buffer pos */ + unsigned bytepos; /* current I/O byte */ + unsigned bitpos; /* current I/O bit */ + unsigned bits_processed; /* number of bits already processed */ + openmode_e mode; /* access mode */ +} bitfile_t; + +FILE * +open_file (const char *filename, const char *env_var, openmode_e mode); +bitfile_t * +open_bitfile (const char *filename, const char *env_var, openmode_e mode); +void +put_bit (bitfile_t *bitfile, unsigned value); +void +put_bits (bitfile_t *bitfile, unsigned value, unsigned bits); +bool_t +get_bit (bitfile_t *bitfile); +unsigned +get_bits (bitfile_t *bitfile, unsigned bits); +void +close_bitfile (bitfile_t *bitfile); +unsigned +bits_processed (const bitfile_t *bitfile); + +#endif /* not _BIT_IO_H */ + diff --git a/converter/other/fiasco/lib/dither.c b/converter/other/fiasco/lib/dither.c new file mode 100644 index 00000000..c7f9ebab --- /dev/null +++ b/converter/other/fiasco/lib/dither.c @@ -0,0 +1,1892 @@ +/* + * dither.c: Various dithering routines + * + * Adapted 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> + */ + +/* + * Copyright (c) 1995 Erik Corry + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose, without fee, and without written agreement is + * hereby granted, provided that the above copyright notice and the following + * two paragraphs appear in all copies of this software. + * + * IN NO EVENT SHALL ERIK CORRY BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, + * SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF + * THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF ERIK CORRY HAS BEEN ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ERIK CORRY SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" + * BASIS, AND ERIK CORRY HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +/* + * $Date: 2000/11/27 20:22:51 $ + * $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 */ +#if STDC_HEADERS +# include <stdlib.h> +#endif /* not STDC_HEADERS */ + +#include "types.h" +#include "macros.h" +#include "error.h" + +#include "fiasco.h" +#include "image.h" +#include "misc.h" +#include "dither.h" + +/***************************************************************************** + + prototypes + +*****************************************************************************/ + +static int +display_16_bit (const struct fiasco_renderer *this, unsigned char *ximage, + const fiasco_image_t *fiasco_image); +static int +display_24_bit_bgr (const struct fiasco_renderer *this, unsigned char *ximage, + const fiasco_image_t *fiasco_image); +static int +display_24_bit_rgb (const struct fiasco_renderer *this, unsigned char *ximage, + const fiasco_image_t *fiasco_image); +static int +display_32_bit (const struct fiasco_renderer *this, unsigned char *ximage, + const fiasco_image_t *fiasco_image); +static int +free_bits_at_bottom (unsigned long a); +static int +free_bits_at_top (unsigned long a); +static int +number_of_bits_set (unsigned long a); + +/***************************************************************************** + + public code + +*****************************************************************************/ + +fiasco_renderer_t * +fiasco_renderer_new (unsigned long red_mask, unsigned long green_mask, + unsigned long blue_mask, unsigned bpp, + int double_resolution) +/* + * FIASCO renderer constructor. + * Allocate memory for the FIASCO renderer structure and + * initialize values. + * `red_mask', `green_mask', and `blue_mask' are the corresponding masks + * of the X11R6 XImage structure. + * `bpp' gives the depth of the image in bits per pixel (16, 24, or 32). + * If `double_resolution' is not 0 the the image width and height is doubled. + * (fast pixel doubling, no interpolation!) + * + * Return value: + * pointer to the new structure or NULL on error + */ +{ + if (bpp != 16 && bpp != 24 && bpp !=32) + { + set_error (_("Rendering depth of XImage must be 16, 24, or 32 bpp.")); + return NULL; + } + else + { + fiasco_renderer_t *render = calloc (1, sizeof (fiasco_renderer_t)); + renderer_private_t *private = calloc (1, sizeof (renderer_private_t)); + bool_t twopixels = (bpp == 16 && double_resolution); + int crval, cbval, i; /* counter */ + + if (!render || !private) + { + set_error (_("Out of memory.")); + return NULL; + } + switch (bpp) + { + case 16: + render->render = display_16_bit; + break; + case 24: + if (red_mask > green_mask) + render->render = display_24_bit_rgb; + else + render->render = display_24_bit_bgr; + break; + case 32: + render->render = display_32_bit; + break; + default: + break; /* does not happen */ + } + render->private = private; + render->delete = fiasco_renderer_delete; + + private->double_resolution = double_resolution; + private->Cr_r_tab = calloc (256 + 2 * 1024, sizeof (int)); + private->Cr_g_tab = calloc (256 + 2 * 1024, sizeof (int)); + private->Cb_g_tab = calloc (256 + 2 * 1024, sizeof (int)); + private->Cb_b_tab = calloc (256 + 2 * 1024, sizeof (int)); + + if (!private->Cr_r_tab || !private->Cr_g_tab + || !private->Cb_b_tab || !private->Cb_g_tab) + { + set_error (_("Out of memory.")); + return NULL; + } + + for (i = 1024; i < 1024 + 256; i++) + { + cbval = crval = i - 128 - 1024; + + private->Cr_r_tab [i] = 1.4022 * crval + 0.5; + private->Cr_g_tab [i] = -0.7145 * crval + 0.5; + private->Cb_g_tab [i] = -0.3456 * cbval + 0.5; + private->Cb_b_tab [i] = 1.7710 * cbval + 0.5; + } + for (i = 0; i < 1024; i++) + { + private->Cr_r_tab [i] = private->Cr_r_tab [1024]; + private->Cr_g_tab [i] = private->Cr_g_tab [1024]; + private->Cb_g_tab [i] = private->Cb_g_tab [1024]; + private->Cb_b_tab [i] = private->Cb_b_tab [1024]; + } + for (i = 1024 + 256; i < 2048 + 256; i++) + { + private->Cr_r_tab [i] = private->Cr_r_tab [1024 + 255]; + private->Cr_g_tab [i] = private->Cr_g_tab [1024 + 255]; + private->Cb_g_tab [i] = private->Cb_g_tab [1024 + 255]; + private->Cb_b_tab [i] = private->Cb_b_tab [1024 + 255]; + } + + private->Cr_r_tab += 1024 + 128; + private->Cr_g_tab += 1024 + 128; + private->Cb_g_tab += 1024 + 128; + private->Cb_b_tab += 1024 + 128; + + /* + * Set up entries 0-255 in rgb-to-pixel value tables. + */ + private->r_table = calloc (256 + 2 * 1024, sizeof (unsigned int)); + private->g_table = calloc (256 + 2 * 1024, sizeof (unsigned int)); + private->b_table = calloc (256 + 2 * 1024, sizeof (unsigned int)); + private->y_table = calloc (256 + 2 * 1024, sizeof (unsigned int)); + + if (!private->r_table || !private->g_table + || !private->b_table || !private->y_table) + { + set_error (_("Out of memory.")); + return NULL; + } + + for (i = 0; i < 256; i++) + { + private->r_table [i + 1024] + = i >> (8 - number_of_bits_set(red_mask)); + private->r_table [i + 1024] + <<= free_bits_at_bottom (red_mask); + private->g_table [i + 1024] + = i >> (8 - number_of_bits_set (green_mask)); + private->g_table [i + 1024] + <<= free_bits_at_bottom (green_mask); + private->b_table [i + 1024] + <<= free_bits_at_bottom (blue_mask); + private->b_table [i + 1024] + = i >> (8 - number_of_bits_set (blue_mask)); + if (twopixels) + { + private->r_table [i + 1024] = ((private->r_table [i + 1024] << 16) + | private->r_table [i + 1024]); + private->g_table [i + 1024] = ((private->g_table [i + 1024] << 16) + | private->g_table [i + 1024]); + private->b_table [i + 1024] = ((private->b_table [i + 1024] << 16) + | private->b_table [i + 1024]); + } + private->y_table [i + 1024] = (private->r_table [i + 1024] + | private->g_table [i + 1024] + | private->b_table [i + 1024]); + } + + /* + * Spread out the values we have to the rest of the array so that + * we do not need to check for overflow. + */ + for (i = 0; i < 1024; i++) + { + private->r_table [i] = private->r_table [1024]; + private->r_table [i + 1024 + 256] = private->r_table [1024 + 255]; + private->g_table [i] = private->g_table [1024]; + private->g_table [i + 1024 + 256] = private->g_table [1024 + 255]; + private->b_table [i] = private->b_table [1024]; + private->b_table [i + 1024 + 256] = private->b_table [1024 + 255]; + private->y_table [i] = private->y_table [1024]; + private->y_table [i + 1024 + 256] = private->y_table [1024 + 255]; + } + + private->r_table += 1024; + private->g_table += 1024; + private->b_table += 1024; + private->y_table += 1024 + 128; + + return render; + } + +} + +void +fiasco_renderer_delete (fiasco_renderer_t *renderer) +/* + * FIASCO renderer destructor: + * Free memory of 'renderer' structure. + * + * No return value. + * + * Side effects: + * structure 'renderer' is discarded. + */ +{ + if (!renderer) + return; + else + { + renderer_private_t *private = (renderer_private_t *) renderer->private; + + Free (private->Cr_g_tab - (1024 + 128)); + Free (private->Cr_r_tab - (1024 + 128)); + Free (private->Cb_g_tab - (1024 + 128)); + Free (private->Cb_b_tab - (1024 + 128)); + Free (private->r_table - 1024); + Free (private->g_table - 1024); + Free (private->b_table - 1024); + Free (private->y_table - (1024 + 128)); + + Free (private); + Free (renderer); + } +} + +int +fiasco_renderer_render (const fiasco_renderer_t *renderer, + unsigned char *ximage, + const fiasco_image_t *fiasco_image) +{ + if (!renderer) + { + set_error (_("Parameter `%s' not defined (NULL)."), "renderer"); + return 0; + } + else + return renderer->render (renderer, ximage, fiasco_image); +} + +/***************************************************************************** + + private code + +*****************************************************************************/ + +/* + * Erik Corry's multi-byte dither routines. + * + * The basic idea is that the Init generates all the necessary + * tables. The tables incorporate the information about the layout + * of pixels in the XImage, so that it should be able to cope with + * 16-bit 24-bit (non-packed) and 32-bit (10-11 bits per + * color!) screens. At present it cannot cope with 24-bit packed + * mode, since this involves getting down to byte level again. It is + * assumed that the bits for each color are contiguous in the + * longword. + * + * Writing to memory is done in shorts or ints. (Unfortunately, short + * is not very fast on Alpha, so there is room for improvement + * here). There is no dither time check for overflow - instead the + * tables have slack at each end. This is likely to be faster than an + * 'if' test as many modern architectures are really bad at + * ifs. Potentially, each '&&' causes a pipeline flush! + * + * There is no shifting and fixed point arithmetic, as I really doubt + * you can see the difference, and it costs. This may be just my + * bias, since I heard that Intel is really bad at shifting. + */ + +static int +number_of_bits_set (unsigned long a) +/* + * How many 1 bits are there in the longword. + * Low performance, do not call often. + */ +{ + if (!a) + return 0; + if (a & 1) + return 1 + number_of_bits_set (a >> 1); + else + return (number_of_bits_set (a >> 1)); +} + +static int +free_bits_at_top (unsigned long a) +/* + * How many 0 bits are there at most significant end of longword. + * Low performance, do not call often. + */ +{ + if(!a) /* assume char is 8 bits */ + return sizeof (unsigned long) * 8; + else if (((long) a) < 0l) /* assume twos complement */ + return 0; + else + return 1 + free_bits_at_top ( a << 1); +} + +static int +free_bits_at_bottom (unsigned long a) +/* + * How many 0 bits are there at least significant end of longword. + * Low performance, do not call often. + */ +{ + /* assume char is 8 bits */ + if (!a) + return sizeof (unsigned long) * 8; + else if(((long) a) & 1l) + return 0; + else + return 1 + free_bits_at_bottom ( a >> 1); +} + +static int +display_16_bit (const struct fiasco_renderer *this, unsigned char *ximage, + const fiasco_image_t *fiasco_image) +/* + * Convert 'image' to 16 bit color bitmap. + * If 'double_resolution' is true then double image size in both directions. + * + * No return value. + * + * Side effects: + * 'out[]' is filled with dithered image + */ +{ + const image_t *image; + renderer_private_t *private; + byte_t *out; + + if (!this) + { + set_error (_("Parameter `%s' not defined (NULL)."), "this"); + return 0; + } + if (!ximage) + { + set_error (_("Parameter `%s' not defined (NULL)."), "ximage"); + return 0; + } + if (!fiasco_image) + { + set_error (_("Parameter `%s' not defined (NULL)."), "fiasco_image"); + return 0; + } + + out = (byte_t *) ximage; + image = cast_image ((fiasco_image_t *) fiasco_image); + if (!image) + return 0; + private = (renderer_private_t *) this->private; + + if (image->color) + { + word_t *cbptr, *crptr; /* pointer to chroma bands */ + word_t *yptr; /* pointers to lumincance band */ + int yval, crval, cbval; /* pixel value in YCbCr color space */ + int R, G, B; /* pixel value in RGB color space */ + int n; /* pixel counter */ + int x, y; /* pixel coordinates */ + int *Cr_r_tab, *Cr_g_tab, *Cb_g_tab, *Cb_b_tab; + unsigned int *r_table, *g_table, *b_table; + + Cr_g_tab = private->Cr_g_tab; + Cr_r_tab = private->Cr_r_tab; + Cb_b_tab = private->Cb_b_tab; + Cb_g_tab = private->Cb_g_tab; + r_table = private->r_table; + g_table = private->g_table; + b_table = private->b_table; + yptr = image->pixels [Y]; + cbptr = image->pixels [Cb]; + crptr = image->pixels [Cr]; + + if (image->format == FORMAT_4_2_0) + { + u_word_t *dst, *dst2; /* pointers to dithered pixels */ + word_t *yptr2; /* pointers to lumincance band */ + + if (private->double_resolution) + { + yptr2 = yptr + image->width; + dst = (u_word_t *) out; + dst2 = dst + 4 * image->width; + for (y = image->height / 2; y; y--) + { + for (x = image->width / 2; x; x--) + { +#ifdef HAVE_SIGNED_SHIFT + crval = *crptr++ >> 4; + cbval = *cbptr++ >> 4; + yval = (*yptr++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + crval = *crptr++ / 16; + cbval = *cbptr++ / 16; + yval = *yptr++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + R = yval + Cr_r_tab [crval]; + G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval]; + B = yval + Cb_b_tab [cbval]; + *dst++ = r_table [R] | g_table [G] | b_table [B]; + *dst++ = r_table [R] | g_table [G] | b_table [B]; + +#ifdef HAVE_SIGNED_SHIFT + yval = (*yptr++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + yval = *yptr++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + R = yval + Cr_r_tab [crval]; + G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval]; + B = yval + Cb_b_tab [cbval]; + *dst++ = r_table [R] | g_table [G] | b_table [B]; + *dst++ = r_table [R] | g_table [G] | b_table [B]; + +#ifdef HAVE_SIGNED_SHIFT + yval = (*yptr2++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + yval = *yptr2++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + R = yval + Cr_r_tab [crval]; + G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval]; + B = yval + Cb_b_tab [cbval]; + *dst2++ = r_table [R] | g_table [G] | b_table [B]; + *dst2++ = r_table [R] | g_table [G] | b_table [B]; + +#ifdef HAVE_SIGNED_SHIFT + yval = (*yptr2++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + yval = *yptr2++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + R = yval + Cr_r_tab [crval]; + G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval]; + B = yval + Cb_b_tab [cbval]; + *dst2++ = r_table [R] | g_table [G] | b_table [B]; + *dst2++ = r_table [R] | g_table [G] | b_table [B]; + } + memcpy (dst, dst - 2 * image->width, + 2 * image->width * sizeof (u_word_t)); + memcpy (dst2, dst2 - 2 * image->width, + 2 * image->width * sizeof (u_word_t)); + yptr += image->width; + yptr2 += image->width; + dst += 3 * image->width * 2; + dst2 += 3 * image->width * 2; + } + } + else + { + yptr2 = yptr + image->width; + dst = (u_word_t *) out; + dst2 = dst + image->width; + + for (y = image->height / 2; y; y--) + { + for (x = image->width / 2; x; x--) + { +#ifdef HAVE_SIGNED_SHIFT + crval = *crptr++ >> 4; + cbval = *cbptr++ >> 4; + yval = (*yptr++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + crval = *crptr++ / 16; + cbval = *cbptr++ / 16; + yval = *yptr++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + R = yval + Cr_r_tab [crval]; + G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval]; + B = yval + Cb_b_tab [cbval]; + *dst++ = r_table [R] | g_table [G] | b_table [B]; + +#ifdef HAVE_SIGNED_SHIFT + yval = (*yptr++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + yval = *yptr++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + R = yval + Cr_r_tab [crval]; + G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval]; + B = yval + Cb_b_tab [cbval]; + *dst++ = r_table [R] | g_table [G] | b_table [B]; + +#ifdef HAVE_SIGNED_SHIFT + yval = (*yptr2++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + yval = *yptr2++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + R = yval + Cr_r_tab [crval]; + G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval]; + B = yval + Cb_b_tab [cbval]; + *dst2++ = r_table [R] | g_table [G] | b_table [B]; + +#ifdef HAVE_SIGNED_SHIFT + yval = (*yptr2++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + yval = *yptr2++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + R = yval + Cr_r_tab [crval]; + G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval]; + B = yval + Cb_b_tab [cbval]; + *dst2++ = r_table [R] | g_table [G] | b_table [B]; + } + yptr += image->width; + yptr2 += image->width; + dst += image->width; + dst2 += image->width; + } + } + } + else /* 4:4:4 format */ + { + if (private->double_resolution) + { + unsigned int *dst; /* pointer to dithered pixels */ + + dst = (unsigned int *) out; + + for (y = image->height; y; y--) + { + for (x = image->width; x; x--) + { +#ifdef HAVE_SIGNED_SHIFT + crval = *crptr++ >> 4; + cbval = *cbptr++ >> 4; + yval = (*yptr++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + crval = *crptr++ / 16; + cbval = *cbptr++ / 16; + yval = *yptr++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + R = yval + Cr_r_tab [crval]; + G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval]; + B = yval + Cb_b_tab [cbval]; + + *dst++ = r_table [R] | g_table [G] | b_table [B]; + } + memcpy (dst, dst - image->width, + image->width * sizeof (unsigned int)); + dst += image->width; + } + } + else + { + u_word_t *dst; /* pointer to dithered pixels */ + + dst = (u_word_t *) out; + + for (n = image->width * image->height; n; n--) + { +#ifdef HAVE_SIGNED_SHIFT + crval = *crptr++ >> 4; + cbval = *cbptr++ >> 4; + yval = (*yptr++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + crval = *crptr++ / 16; + cbval = *cbptr++ / 16; + yval = *yptr++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + R = yval + Cr_r_tab [crval]; + G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval]; + B = yval + Cb_b_tab [cbval]; + + *dst++ = r_table [R] | g_table [G] | b_table [B]; + } + } + } + } + else + { + unsigned int *dst; /* pointer to dithered pixels */ + word_t *src; /* current pixel of frame */ + unsigned int *y_table; + + y_table = private->y_table; + dst = (unsigned int *) out; + src = image->pixels [GRAY]; + + if (private->double_resolution) + { + int x, y; /* pixel coordinates */ + + for (y = image->height; y; y--) + { + for (x = image->width; x; x--) + { + int value; + +#ifdef HAVE_SIGNED_SHIFT + value = y_table [*src++ >> 4]; +#else /* not HAVE_SIGNED_SHIFT */ + value = y_table [*src++ / 16]; +#endif /* not HAVE_SIGNED_SHIFT */ + *dst++ = (value << 16) | value; + } + + memcpy (dst, dst - image->width, + image->width * sizeof (unsigned int)); + dst += image->width; + } + } + else + { + int n; /* pixel counter */ + + for (n = image->width * image->height / 2; n; n--, src += 2) +#ifdef HAVE_SIGNED_SHIFT +# ifndef WORDS_BIGENDIAN + *dst++ = (y_table [src [1] >> 4] << 16) | y_table [src [0] >> 4]; +# else /* not WORDS_BIGENDIAN */ + *dst++ = (y_table [src [0] >> 4] << 16) | y_table [src [1] >> 4]; +# endif +#else /* not HAVE_SIGNED_SHIFT */ +# ifndef WORDS_BIGENDIAN + *dst++ = (y_table [src [1] / 16] << 16) | y_table [src [0] / 16]; +# else /* not WORDS_BIGENDIAN */ + *dst++ = (y_table [src [0] / 16] << 16) | y_table [src [1] / 16]; +# endif +#endif /* not HAVE_SIGNED_SHIFT */ + } + } + + return 1; +} + +static int +display_24_bit_bgr (const struct fiasco_renderer *this, unsigned char *ximage, + const fiasco_image_t *fiasco_image) +/* + * Convert 'image' to 16 bit color bitmap. + * If 'double_resolution' is true then double image size in both directions. + * + * No return value. + * + * Side effects: + * 'out[]' is filled with dithered image + */ +{ + unsigned *gray_clip = init_clipping (); + const image_t *image; + renderer_private_t *private; + byte_t *out; + + if (!gray_clip) + return 0; + if (!this) + { + set_error (_("Parameter `%s' not defined (NULL)."), "this"); + return 0; + } + if (!ximage) + { + set_error (_("Parameter `%s' not defined (NULL)."), "ximage"); + return 0; + } + if (!fiasco_image) + { + set_error (_("Parameter `%s' not defined (NULL)."), "fiasco_image"); + return 0; + } + + out = (byte_t *) ximage; + image = cast_image ((fiasco_image_t *) fiasco_image); + if (!image) + return 0; + private = (renderer_private_t *) this->private; + + if (image->color) + { + word_t *cbptr, *crptr; /* pointer to chroma bands */ + word_t *yptr; /* pointers to lumincance band */ + int *Cr_r_tab, *Cr_g_tab, *Cb_g_tab, *Cb_b_tab; + unsigned int *r_table, *g_table, *b_table; + + Cr_g_tab = private->Cr_g_tab; + Cr_r_tab = private->Cr_r_tab; + Cb_b_tab = private->Cb_b_tab; + Cb_g_tab = private->Cb_g_tab; + r_table = private->r_table; + g_table = private->g_table; + b_table = private->b_table; + yptr = image->pixels [Y]; + cbptr = image->pixels [Cb]; + crptr = image->pixels [Cr]; + + if (image->format == FORMAT_4_2_0) + { + if (private->double_resolution) + { + int yval1; /* lumincance pixel */ + int crval1, cbval1; /* chroma pixels */ + int yval2; /* pixel in YCbCr color space */ + unsigned int R1, G1, B1; /* pixel in RGB color space */ + unsigned int R2, G2, B2; /* pixel in RGB color space */ + int x, y; /* pixel counter */ + unsigned int *dst; /* pointer to dithered pixels */ + unsigned int *dst2; /* pointers to dithered pixels */ + word_t *yptr2; /* pointers to lumincance band */ + + dst = (unsigned int *) out; + dst2 = dst + (image->width >> 1) * 3 * 2; + yptr2 = yptr + image->width; + + for (y = image->height >> 1; y; y--) + { + for (x = image->width >> 1; x; x--) + { +#ifdef HAVE_SIGNED_SHIFT + yval1 = (*yptr++ >> 4) + 128; + yval2 = (*yptr++ >> 4) + 128; + crval1 = *crptr++ >> 4; + cbval1 = *cbptr++ >> 4; +#else /* not HAVE_SIGNED_SHIFT */ + yval1 = *yptr++ / 16 + 128; + yval2 = *yptr++ / 16 + 128; + crval1 = *crptr++ / 16; + cbval1 = *cbptr++ / 16; +#endif /* not HAVE_SIGNED_SHIFT */ + + R1 = gray_clip [yval1 + Cr_r_tab [crval1]]; + G1 = gray_clip [yval1 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B1 = gray_clip [yval1 + Cb_b_tab [cbval1]]; + R2 = gray_clip [yval2 + Cr_r_tab [crval1]]; + G2 = gray_clip [yval2 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B2 = gray_clip [yval2 + Cb_b_tab [cbval1]]; + + *dst++ = B1 | (G1 << 8) | (R1 << 16) | (B1 << 24); + *dst++ = G1 | (R1 << 8) | (B2 << 16) | (G2 << 24); + *dst++ = R2 | (B2 << 8) | (G2 << 16) | (R2 << 24); + +#ifdef HAVE_SIGNED_SHIFT + yval1 = (*yptr2++ >> 4) + 128; + yval2 = (*yptr2++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + yval1 = *yptr2++ / 16 + 128; + yval2 = *yptr2++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + + R1 = gray_clip [yval1 + Cr_r_tab [crval1]]; + G1 = gray_clip [yval1 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B1 = gray_clip [yval1 + Cb_b_tab [cbval1]]; + R2 = gray_clip [yval2 + Cr_r_tab [crval1]]; + G2 = gray_clip [yval2 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B2 = gray_clip [yval2 + Cb_b_tab [cbval1]]; + + *dst2++ = B1 | (G1 << 8) | (R1 << 16) | (B1 << 24); + *dst2++ = G1 | (R1 << 8) | (B2 << 16) | (G2 << 24); + *dst2++ = R2 | (B2 << 8) | (G2 << 16) | (R2 << 24); + } + memcpy (dst, dst - (image->width >> 1) * 3, + (image->width >> 1) * 3 * sizeof (unsigned int)); + memcpy (dst2, dst2 - (image->width >> 1) * 3, + (image->width >> 1) * 3 * sizeof (unsigned int)); + dst += (image->width >> 1) * 3 * 3; + dst2 += (image->width >> 1) * 3 * 3; + yptr += image->width; + yptr2 += image->width; + } + } + else + { + int yval1; /* lumincance pixel */ + int crval1, cbval1; /* chroma pixels */ + int yval2; /* pixel in YCbCr color space */ + unsigned int R1, G1, B1; /* pixel in RGB color space */ + unsigned int R2, G2, B2; /* pixel in RGB color space */ + int x, y; /* pixel counter */ + unsigned int *dst; /* pointer to dithered pixels */ + unsigned int *dst2; /* pointers to dithered pixels */ + word_t *yptr2; /* pointers to lumincance band */ + + dst = (unsigned int *) out; + dst2 = dst + (image->width >> 2) * 3; + yptr2 = yptr + image->width; + + for (y = image->height >> 1; y; y--) + { + for (x = image->width >> 2; x; x--) + { +#ifdef HAVE_SIGNED_SHIFT + yval1 = (*yptr++ >> 4) + 128; + yval2 = (*yptr++ >> 4) + 128; + crval1 = *crptr++ >> 4; + cbval1 = *cbptr++ >> 4; +#else /* not HAVE_SIGNED_SHIFT */ + yval1 = *yptr++ / 16 + 128; + yval2 = *yptr++ / 16 + 128; + crval1 = *crptr++ / 16; + cbval1 = *cbptr++ / 16; +#endif /* not HAVE_SIGNED_SHIFT */ + + R1 = gray_clip [yval1 + Cr_r_tab [crval1]]; + G1 = gray_clip [yval1 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B1 = gray_clip [yval1 + Cb_b_tab [cbval1]]; + R2 = gray_clip [yval2 + Cr_r_tab [crval1]]; + G2 = gray_clip [yval2 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B2 = gray_clip [yval2 + Cb_b_tab [cbval1]]; + + *dst++ = B1 | (G1 << 8) | (R1 << 16) | (B2 << 24); + *dst = G2 | (R2 << 8); + +#ifdef HAVE_SIGNED_SHIFT + yval1 = (*yptr2++ >> 4) + 128; + yval2 = (*yptr2++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + yval1 = *yptr2++ / 16 + 128; + yval2 = *yptr2++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + + R1 = gray_clip [yval1 + Cr_r_tab [crval1]]; + G1 = gray_clip [yval1 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B1 = gray_clip [yval1 + Cb_b_tab [cbval1]]; + R2 = gray_clip [yval2 + Cr_r_tab [crval1]]; + G2 = gray_clip [yval2 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B2 = gray_clip [yval2 + Cb_b_tab [cbval1]]; + + *dst2++ = B1 | (G1 << 8) | (R1 << 16) | (B2 << 24); + *dst2 = G2 | (R2 << 8); + +#ifdef HAVE_SIGNED_SHIFT + yval1 = (*yptr++ >> 4) + 128; + yval2 = (*yptr++ >> 4) + 128; + crval1 = *crptr++ >> 4; + cbval1 = *cbptr++ >> 4; +#else /* not HAVE_SIGNED_SHIFT */ + yval1 = *yptr++ / 16 + 128; + yval2 = *yptr++ / 16 + 128; + crval1 = *crptr++ / 16; + crval2 = *crptr++ / 16; + cbval1 = *cbptr++ / 16; + cbval2 = *cbptr++ / 16; +#endif /* not HAVE_SIGNED_SHIFT */ + + R1 = gray_clip [yval1 + Cr_r_tab [crval1]]; + G1 = gray_clip [yval1 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B1 = gray_clip [yval1 + Cb_b_tab [cbval1]]; + R2 = gray_clip [yval2 + Cr_r_tab [crval1]]; + G2 = gray_clip [yval2 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B2 = gray_clip [yval2 + Cb_b_tab [cbval1]]; + + *dst++ |= (B1 << 16) | (G1 << 24); + *dst++ = R1 | (B2 << 8) | (G2 << 16) | (R2 << 24); + +#ifdef HAVE_SIGNED_SHIFT + yval1 = (*yptr2++ >> 4) + 128; + yval2 = (*yptr2++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + yval1 = *yptr2++ / 16 + 128; + yval2 = *yptr2++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + + R1 = gray_clip [yval1 + Cr_r_tab [crval1]]; + G1 = gray_clip [yval1 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B1 = gray_clip [yval1 + Cb_b_tab [cbval1]]; + R2 = gray_clip [yval2 + Cr_r_tab [crval1]]; + G2 = gray_clip [yval2 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B2 = gray_clip [yval2 + Cb_b_tab [cbval1]]; + + *dst2++ |= (B1 << 16) | (G1 << 24); + *dst2++ = R1 | (B2 << 8) | (G2 << 16) | (R2 << 24); + } + dst += (image->width >> 2) * 3; + dst2 += (image->width >> 2) * 3; + yptr += image->width; + yptr2 += image->width; + } + } + } + else /* 4:4:4 format */ + { + if (private->double_resolution) + { + unsigned int R1, G1, B1; /* pixel1 in RGB color space */ + unsigned int R2, G2, B2; /* pixel2 in RGB color space */ + int yval1, crval1, cbval1; /* pixel1 in YCbCr space */ + int yval2, crval2, cbval2; /* pixel2 in YCbCr space */ + int x, y; /* pixel counter */ + unsigned int *dst; /* dithered pixel pointer */ + + dst = (unsigned int *) out; + + for (y = image->height; y; y--) + { + for (x = image->width >> 1; x; x--) + { +#ifdef HAVE_SIGNED_SHIFT + yval1 = (*yptr++ >> 4) + 128; + yval2 = (*yptr++ >> 4) + 128; + crval1 = *crptr++ >> 4; + crval2 = *crptr++ >> 4; + cbval1 = *cbptr++ >> 4; + cbval2 = *cbptr++ >> 4; +#else /* not HAVE_SIGNED_SHIFT */ + yval1 = *yptr++ / 16 + 128; + yval2 = *yptr++ / 16 + 128; + crval1 = *crptr++ / 16; + crval2 = *crptr++ / 16; + cbval1 = *cbptr++ / 16; + cbval2 = *cbptr++ / 16; +#endif /* not HAVE_SIGNED_SHIFT */ + + R1 = gray_clip [yval1 + Cr_r_tab [crval1]]; + G1 = gray_clip [yval1 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B1 = gray_clip [yval1 + Cb_b_tab [cbval1]]; + R2 = gray_clip [yval2 + Cr_r_tab [crval2]]; + G2 = gray_clip [yval2 + Cr_g_tab [crval2] + + Cb_g_tab [cbval2]]; + B2 = gray_clip [yval2 + Cb_b_tab [cbval2]]; + + *dst++ = B1 | (G1 << 8) | (R1 << 16) | (B1 << 24); + *dst++ = G1 | (R1 << 8) | (B2 << 16) | (G2 << 24); + *dst++ = R2 | (B2 << 8) | (G2 << 16) | (R2 << 24); + } + memcpy (dst, dst - 3 * (image->width >> 1), + 3 * (image->width >> 1) * sizeof (unsigned int)); + dst += 3 * (image->width >> 1); + } + } + else + { + unsigned int R1, G1, B1; /* pixel in RGB color space */ + unsigned int R2, G2, B2; /* pixel in RGB color space */ + int yval1, crval1, cbval1; /* pixel1 in YCbCr space */ + int yval2, crval2, cbval2; /* pixel2 in YCbCr space */ + int n; /* pixel counter */ + unsigned int *dst; /* dithered pixel pointer */ + + dst = (unsigned int *) out; + + for (n = (image->width * image->height) >> 2; n; n--) + { +#ifdef HAVE_SIGNED_SHIFT + yval1 = (*yptr++ >> 4) + 128; + yval2 = (*yptr++ >> 4) + 128; + crval1 = *crptr++ >> 4; + crval2 = *crptr++ >> 4; + cbval1 = *cbptr++ >> 4; + cbval2 = *cbptr++ >> 4; +#else /* not HAVE_SIGNED_SHIFT */ + yval1 = *yptr++ / 16 + 128; + yval2 = *yptr++ / 16 + 128; + crval1 = *crptr++ / 16; + crval2 = *crptr++ / 16; + cbval1 = *cbptr++ / 16; + cbval2 = *cbptr++ / 16; +#endif /* not HAVE_SIGNED_SHIFT */ + + R1 = gray_clip [yval1 + Cr_r_tab [crval1]]; + G1 = gray_clip [yval1 + Cr_g_tab [crval1] + Cb_g_tab [cbval1]]; + B1 = gray_clip [yval1 + Cb_b_tab [cbval1]]; + R2 = gray_clip [yval2 + Cr_r_tab [crval2]]; + G2 = gray_clip [yval2 + Cr_g_tab [crval2] + Cb_g_tab [cbval2]]; + B2 = gray_clip [yval2 + Cb_b_tab [cbval2]]; + + *dst++ = B1 | (G1 << 8) | (R1 << 16) | (B2 << 24); + *dst = G2 | (R2 << 8); + +#ifdef HAVE_SIGNED_SHIFT + yval1 = (*yptr++ >> 4) + 128; + yval2 = (*yptr++ >> 4) + 128; + crval1 = *crptr++ >> 4; + crval2 = *crptr++ >> 4; + cbval1 = *cbptr++ >> 4; + cbval2 = *cbptr++ >> 4; +#else /* not HAVE_SIGNED_SHIFT */ + yval1 = *yptr++ / 16 + 128; + yval2 = *yptr++ / 16 + 128; + crval1 = *crptr++ / 16; + crval2 = *crptr++ / 16; + cbval1 = *cbptr++ / 16; + cbval2 = *cbptr++ / 16; +#endif /* not HAVE_SIGNED_SHIFT */ + + R1 = gray_clip [yval1 + Cr_r_tab [crval1]]; + G1 = gray_clip [yval1 + Cr_g_tab [crval1] + Cb_g_tab [cbval1]]; + B1 = gray_clip [yval1 + Cb_b_tab [cbval1]]; + R2 = gray_clip [yval2 + Cr_r_tab [crval2]]; + G2 = gray_clip [yval2 + Cr_g_tab [crval2] + Cb_g_tab [cbval2]]; + B2 = gray_clip [yval2 + Cb_b_tab [cbval2]]; + + *dst++ |= (B1 << 16) | (G1 << 24); + *dst++ = R1 | (B2 << 8) | (G2 << 16) | (R2 << 24); + } + } + } + } + else + { + unsigned int *dst; /* pointer to dithered pixels */ + word_t *src; /* current pixel of frame */ + unsigned int *y_table; + + y_table = private->y_table; + dst = (unsigned int *) out; + src = image->pixels [GRAY]; + + if (private->double_resolution) + { + int x, y; /* pixel counter */ + unsigned *shift_clipping = gray_clip + 128; + + for (y = image->height; y; y--) + { + for (x = image->width >> 1; x; x--) + { + unsigned int val1, val2; +#ifdef HAVE_SIGNED_SHIFT + val1 = shift_clipping [*src++ >> 4]; + val2 = shift_clipping [*src++ >> 4]; +#else /* not HAVE_SIGNED_SHIFT */ + val1 = shift_clipping [*src++ / 16]; + val2 = shift_clipping [*src++ / 16]; +#endif /* not HAVE_SIGNED_SHIFT */ + + *dst++ = val1 | (val1 << 8) | (val1 << 16) | (val1 << 24); + *dst++ = val1 | (val1 << 8) | (val2 << 16) | (val2 << 24); + *dst++ = val2 | (val2 << 8) | (val2 << 16) | (val2 << 24); + } + + memcpy (dst, dst - 3 * (image->width >> 1), + 3 * (image->width >> 1) * sizeof (unsigned int)); + dst += 3 * (image->width >> 1); + } + } + else + { + int n; /* pixel counter */ + unsigned *shift_clipping = gray_clip + 128; + + for (n = (image->width * image->height) >> 2; n; n--) + { + unsigned int val1, val2; + +#ifdef HAVE_SIGNED_SHIFT + val1 = shift_clipping [*src++ >> 4]; + val2 = shift_clipping [*src++ >> 4]; +#else /* not HAVE_SIGNED_SHIFT */ + val1 = shift_clipping [*src++ / 16]; + val2 = shift_clipping [*src++ / 16]; +#endif /* not HAVE_SIGNED_SHIFT */ + + *dst++ = val1 | (val1 << 8) + | (val1 << 16) | (val2 << 24); /* RGBR */ + *dst = val2 | (val2 << 8); /* GB-- */ + +#ifdef HAVE_SIGNED_SHIFT + val1 = shift_clipping [*src++ >> 4]; + val2 = shift_clipping [*src++ >> 4]; +#else /* not HAVE_SIGNED_SHIFT */ + val1 = shift_clipping [*src++ / 16]; + val2 = shift_clipping [*src++ / 16]; +#endif /* not HAVE_SIGNED_SHIFT */ + + *dst++ |= (val1 << 16) | (val1 << 24); /* --RG */ + *dst++ = val1 | (val2 << 8) + | (val2 << 16) | (val2 << 24); /* BRGB */ + } + } + } + + return 1; +} + +static int +display_24_bit_rgb (const struct fiasco_renderer *this, unsigned char *ximage, + const fiasco_image_t *fiasco_image) +/* + * Convert 'image' to 16 bit color bitmap. + * If 'double_resolution' is true then double image size in both directions. + * + * No return value. + * + * Side effects: + * 'out[]' is filled with dithered image + */ +{ + unsigned *gray_clip = init_clipping (); + const image_t *image; + renderer_private_t *private; + byte_t *out; + + if (!gray_clip) + return 0; + if (!this) + { + set_error (_("Parameter `%s' not defined (NULL)."), "this"); + return 0; + } + if (!ximage) + { + set_error (_("Parameter `%s' not defined (NULL)."), "ximage"); + return 0; + } + if (!fiasco_image) + { + set_error (_("Parameter `%s' not defined (NULL)."), "fiasco_image"); + return 0; + } + + out = (byte_t *) ximage; + image = cast_image ((fiasco_image_t *) fiasco_image); + if (!image) + return 0; + private = (renderer_private_t *) this->private; + + if (image->color) + { + word_t *cbptr, *crptr; /* pointer to chroma bands */ + word_t *yptr; /* pointers to lumincance band */ + int *Cr_r_tab, *Cr_g_tab, *Cb_g_tab, *Cb_b_tab; + unsigned int *r_table, *g_table, *b_table; + + Cr_g_tab = private->Cr_g_tab; + Cr_r_tab = private->Cr_r_tab; + Cb_b_tab = private->Cb_b_tab; + Cb_g_tab = private->Cb_g_tab; + r_table = private->r_table; + g_table = private->g_table; + b_table = private->b_table; + yptr = image->pixels [Y]; + cbptr = image->pixels [Cb]; + crptr = image->pixels [Cr]; + + if (image->format == FORMAT_4_2_0) + { + if (private->double_resolution) + { + int yval1; /* lumincance pixel */ + int crval1, cbval1; /* chroma pixels */ + int yval2; /* pixel in YCbCr color space */ + unsigned int R1, G1, B1; /* pixel in RGB color space */ + unsigned int R2, G2, B2; /* pixel in RGB color space */ + int x, y; /* pixel counter */ + unsigned int *dst; /* pointer to dithered pixels */ + unsigned int *dst2; /* pointers to dithered pixels */ + word_t *yptr2; /* pointers to lumincance band */ + + dst = (unsigned int *) out; + dst2 = dst + (image->width >> 1) * 3 * 2; + yptr2 = yptr + image->width; + + for (y = image->height >> 1; y; y--) + { + for (x = image->width >> 1; x; x--) + { +#ifdef HAVE_SIGNED_SHIFT + yval1 = (*yptr++ >> 4) + 128; + yval2 = (*yptr++ >> 4) + 128; + crval1 = *crptr++ >> 4; + cbval1 = *cbptr++ >> 4; +#else /* not HAVE_SIGNED_SHIFT */ + yval1 = *yptr++ / 16 + 128; + yval2 = *yptr++ / 16 + 128; + crval1 = *crptr++ / 16; + cbval1 = *cbptr++ / 16; +#endif /* not HAVE_SIGNED_SHIFT */ + + R1 = gray_clip [yval1 + Cr_r_tab [crval1]]; + G1 = gray_clip [yval1 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B1 = gray_clip [yval1 + Cb_b_tab [cbval1]]; + R2 = gray_clip [yval2 + Cr_r_tab [crval1]]; + G2 = gray_clip [yval2 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B2 = gray_clip [yval2 + Cb_b_tab [cbval1]]; + + *dst++ = R1 | (G1 << 8) | (B1 << 16) | (R1 << 24); + *dst++ = G1 | (B1 << 8) | (R2 << 16) | (G2 << 24); + *dst++ = B2 | (R2 << 8) | (G2 << 16) | (B2 << 24); + +#ifdef HAVE_SIGNED_SHIFT + yval1 = (*yptr2++ >> 4) + 128; + yval2 = (*yptr2++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + yval1 = *yptr2++ / 16 + 128; + yval2 = *yptr2++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + + R1 = gray_clip [yval1 + Cr_r_tab [crval1]]; + G1 = gray_clip [yval1 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B1 = gray_clip [yval1 + Cb_b_tab [cbval1]]; + R2 = gray_clip [yval2 + Cr_r_tab [crval1]]; + G2 = gray_clip [yval2 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B2 = gray_clip [yval2 + Cb_b_tab [cbval1]]; + + *dst2++ = R1 | (G1 << 8) | (B1 << 16) | (R1 << 24); + *dst2++ = G1 | (B1 << 8) | (R2 << 16) | (G2 << 24); + *dst2++ = B2 | (R2 << 8) | (G2 << 16) | (B2 << 24); + } + memcpy (dst, dst - (image->width >> 1) * 3, + (image->width >> 1) * 3 * sizeof (unsigned int)); + memcpy (dst2, dst2 - (image->width >> 1) * 3, + (image->width >> 1) * 3 * sizeof (unsigned int)); + dst += (image->width >> 1) * 3 * 3; + dst2 += (image->width >> 1) * 3 * 3; + yptr += image->width; + yptr2 += image->width; + } + } + else + { + int yval1; /* lumincance pixel */ + int crval1, cbval1; /* chroma pixels */ + int yval2; /* pixel in YCbCr color space */ + unsigned int R1, G1, B1; /* pixel in RGB color space */ + unsigned int R2, G2, B2; /* pixel in RGB color space */ + int x, y; /* pixel counter */ + unsigned int *dst; /* pointer to dithered pixels */ + unsigned int *dst2; /* pointers to dithered pixels */ + word_t *yptr2; /* pointers to lumincance band */ + + dst = (unsigned int *) out; + dst2 = dst + (image->width >> 2) * 3; + yptr2 = yptr + image->width; + + for (y = image->height >> 1; y; y--) + { + for (x = image->width >> 2; x; x--) + { +#ifdef HAVE_SIGNED_SHIFT + yval1 = (*yptr++ >> 4) + 128; + yval2 = (*yptr++ >> 4) + 128; + crval1 = *crptr++ >> 4; + cbval1 = *cbptr++ >> 4; +#else /* not HAVE_SIGNED_SHIFT */ + yval1 = *yptr++ / 16 + 128; + yval2 = *yptr++ / 16 + 128; + crval1 = *crptr++ / 16; + cbval1 = *cbptr++ / 16; +#endif /* not HAVE_SIGNED_SHIFT */ + + R1 = gray_clip [yval1 + Cr_r_tab [crval1]]; + G1 = gray_clip [yval1 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B1 = gray_clip [yval1 + Cb_b_tab [cbval1]]; + R2 = gray_clip [yval2 + Cr_r_tab [crval1]]; + G2 = gray_clip [yval2 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B2 = gray_clip [yval2 + Cb_b_tab [cbval1]]; + + *dst++ = R1 | (G1 << 8) | (B1 << 16) | (R2 << 24); + *dst = G2 | (B2 << 8); + +#ifdef HAVE_SIGNED_SHIFT + yval1 = (*yptr2++ >> 4) + 128; + yval2 = (*yptr2++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + yval1 = *yptr2++ / 16 + 128; + yval2 = *yptr2++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + + R1 = gray_clip [yval1 + Cr_r_tab [crval1]]; + G1 = gray_clip [yval1 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B1 = gray_clip [yval1 + Cb_b_tab [cbval1]]; + R2 = gray_clip [yval2 + Cr_r_tab [crval1]]; + G2 = gray_clip [yval2 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B2 = gray_clip [yval2 + Cb_b_tab [cbval1]]; + + *dst2++ = R1 | (G1 << 8) | (B1 << 16) | (R2 << 24); + *dst2 = G2 | (B2 << 8); + +#ifdef HAVE_SIGNED_SHIFT + yval1 = (*yptr++ >> 4) + 128; + yval2 = (*yptr++ >> 4) + 128; + crval1 = *crptr++ >> 4; + cbval1 = *cbptr++ >> 4; +#else /* not HAVE_SIGNED_SHIFT */ + yval1 = *yptr++ / 16 + 128; + yval2 = *yptr++ / 16 + 128; + crval1 = *crptr++ / 16; + crval2 = *crptr++ / 16; + cbval1 = *cbptr++ / 16; + cbval2 = *cbptr++ / 16; +#endif /* not HAVE_SIGNED_SHIFT */ + + R1 = gray_clip [yval1 + Cr_r_tab [crval1]]; + G1 = gray_clip [yval1 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B1 = gray_clip [yval1 + Cb_b_tab [cbval1]]; + R2 = gray_clip [yval2 + Cr_r_tab [crval1]]; + G2 = gray_clip [yval2 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B2 = gray_clip [yval2 + Cb_b_tab [cbval1]]; + + *dst++ |= (R1 << 16) | (G1 << 24); + *dst++ = B1 | (R2 << 8) | (G2 << 16) | (B2 << 24); + +#ifdef HAVE_SIGNED_SHIFT + yval1 = (*yptr2++ >> 4) + 128; + yval2 = (*yptr2++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + yval1 = *yptr2++ / 16 + 128; + yval2 = *yptr2++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + + R1 = gray_clip [yval1 + Cr_r_tab [crval1]]; + G1 = gray_clip [yval1 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B1 = gray_clip [yval1 + Cb_b_tab [cbval1]]; + R2 = gray_clip [yval2 + Cr_r_tab [crval1]]; + G2 = gray_clip [yval2 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B2 = gray_clip [yval2 + Cb_b_tab [cbval1]]; + + *dst2++ |= (R1 << 16) | (G1 << 24); + *dst2++ = B1 | (R2 << 8) | (G2 << 16) | (B2 << 24); + } + dst += (image->width >> 2) * 3; + dst2 += (image->width >> 2) * 3; + yptr += image->width; + yptr2 += image->width; + } + } + } + else /* 4:4:4 format */ + { + if (private->double_resolution) + { + unsigned int R1, G1, B1; /* pixel1 in RGB color space */ + unsigned int R2, G2, B2; /* pixel2 in RGB color space */ + int yval1, crval1, cbval1; /* pixel1 in YCbCr space */ + int yval2, crval2, cbval2; /* pixel2 in YCbCr space */ + int x, y; /* pixel counter */ + unsigned int *dst; /* dithered pixel pointer */ + + dst = (unsigned int *) out; + + for (y = image->height; y; y--) + { + for (x = image->width >> 1; x; x--) + { +#ifdef HAVE_SIGNED_SHIFT + yval1 = (*yptr++ >> 4) + 128; + yval2 = (*yptr++ >> 4) + 128; + crval1 = *crptr++ >> 4; + crval2 = *crptr++ >> 4; + cbval1 = *cbptr++ >> 4; + cbval2 = *cbptr++ >> 4; +#else /* not HAVE_SIGNED_SHIFT */ + yval1 = *yptr++ / 16 + 128; + yval2 = *yptr++ / 16 + 128; + crval1 = *crptr++ / 16; + crval2 = *crptr++ / 16; + cbval1 = *cbptr++ / 16; + cbval2 = *cbptr++ / 16; +#endif /* not HAVE_SIGNED_SHIFT */ + + R1 = gray_clip [yval1 + Cr_r_tab [crval1]]; + G1 = gray_clip [yval1 + Cr_g_tab [crval1] + + Cb_g_tab [cbval1]]; + B1 = gray_clip [yval1 + Cb_b_tab [cbval1]]; + R2 = gray_clip [yval2 + Cr_r_tab [crval2]]; + G2 = gray_clip [yval2 + Cr_g_tab [crval2] + + Cb_g_tab [cbval2]]; + B2 = gray_clip [yval2 + Cb_b_tab [cbval2]]; + + *dst++ = R1 | (G1 << 8) | (B1 << 16) | (R1 << 24); + *dst++ = G1 | (B1 << 8) | (R2 << 16) | (G2 << 24); + *dst++ = B2 | (R2 << 8) | (G2 << 16) | (B2 << 24); + } + memcpy (dst, dst - 3 * (image->width >> 1), + 3 * (image->width >> 1) * sizeof (unsigned int)); + dst += 3 * (image->width >> 1); + } + } + else + { + unsigned int R1, G1, B1; /* pixel in RGB color space */ + unsigned int R2, G2, B2; /* pixel in RGB color space */ + int yval1, crval1, cbval1; /* pixel1 in YCbCr space */ + int yval2, crval2, cbval2; /* pixel2 in YCbCr space */ + int n; /* pixel counter */ + unsigned int *dst; /* dithered pixel pointer */ + + dst = (unsigned int *) out; + + for (n = (image->width * image->height) >> 2; n; n--) + { +#ifdef HAVE_SIGNED_SHIFT + yval1 = (*yptr++ >> 4) + 128; + yval2 = (*yptr++ >> 4) + 128; + crval1 = *crptr++ >> 4; + crval2 = *crptr++ >> 4; + cbval1 = *cbptr++ >> 4; + cbval2 = *cbptr++ >> 4; +#else /* not HAVE_SIGNED_SHIFT */ + yval1 = *yptr++ / 16 + 128; + yval2 = *yptr++ / 16 + 128; + crval1 = *crptr++ / 16; + crval2 = *crptr++ / 16; + cbval1 = *cbptr++ / 16; + cbval2 = *cbptr++ / 16; +#endif /* not HAVE_SIGNED_SHIFT */ + + R1 = gray_clip [yval1 + Cr_r_tab [crval1]]; + G1 = gray_clip [yval1 + Cr_g_tab [crval1] + Cb_g_tab [cbval1]]; + B1 = gray_clip [yval1 + Cb_b_tab [cbval1]]; + R2 = gray_clip [yval2 + Cr_r_tab [crval2]]; + G2 = gray_clip [yval2 + Cr_g_tab [crval2] + Cb_g_tab [cbval2]]; + B2 = gray_clip [yval2 + Cb_b_tab [cbval2]]; + + *dst++ = R1 | (G1 << 8) | (B1 << 16) | (R2 << 24); + *dst = G2 | (B2 << 8); + +#ifdef HAVE_SIGNED_SHIFT + yval1 = (*yptr++ >> 4) + 128; + yval2 = (*yptr++ >> 4) + 128; + crval1 = *crptr++ >> 4; + crval2 = *crptr++ >> 4; + cbval1 = *cbptr++ >> 4; + cbval2 = *cbptr++ >> 4; +#else /* not HAVE_SIGNED_SHIFT */ + yval1 = *yptr++ / 16 + 128; + yval2 = *yptr++ / 16 + 128; + crval1 = *crptr++ / 16; + crval2 = *crptr++ / 16; + cbval1 = *cbptr++ / 16; + cbval2 = *cbptr++ / 16; +#endif /* not HAVE_SIGNED_SHIFT */ + + R1 = gray_clip [yval1 + Cr_r_tab [crval1]]; + G1 = gray_clip [yval1 + Cr_g_tab [crval1] + Cb_g_tab [cbval1]]; + B1 = gray_clip [yval1 + Cb_b_tab [cbval1]]; + R2 = gray_clip [yval2 + Cr_r_tab [crval2]]; + G2 = gray_clip [yval2 + Cr_g_tab [crval2] + Cb_g_tab [cbval2]]; + B2 = gray_clip [yval2 + Cb_b_tab [cbval2]]; + + *dst++ |= (R1 << 16) | (G1 << 24); + *dst++ = B1 | (R2 << 8) | (G2 << 16) | (B2 << 24); + } + } + } + } + else + { + unsigned int *dst; /* pointer to dithered pixels */ + word_t *src; /* current pixel of frame */ + unsigned int *y_table; + + y_table = private->y_table; + dst = (unsigned int *) out; + src = image->pixels [GRAY]; + + if (private->double_resolution) + { + int x, y; /* pixel counter */ + unsigned *shift_clipping = gray_clip + 128; + + for (y = image->height; y; y--) + { + for (x = image->width >> 1; x; x--) + { + unsigned int val1, val2; +#ifdef HAVE_SIGNED_SHIFT + val1 = shift_clipping [*src++ >> 4]; + val2 = shift_clipping [*src++ >> 4]; +#else /* not HAVE_SIGNED_SHIFT */ + val1 = shift_clipping [*src++ / 16]; + val2 = shift_clipping [*src++ / 16]; +#endif /* not HAVE_SIGNED_SHIFT */ + + *dst++ = val1 | (val1 << 8) | (val1 << 16) | (val1 << 24); + *dst++ = val1 | (val1 << 8) | (val2 << 16) | (val2 << 24); + *dst++ = val2 | (val2 << 8) | (val2 << 16) | (val2 << 24); + } + + memcpy (dst, dst - 3 * (image->width >> 1), + 3 * (image->width >> 1) * sizeof (unsigned int)); + dst += 3 * (image->width >> 1); + } + } + else + { + int n; /* pixel counter */ + unsigned *shift_clipping = gray_clip + 128; + + for (n = (image->width * image->height) >> 2; n; n--) + { + unsigned int val1, val2; + +#ifdef HAVE_SIGNED_SHIFT + val1 = shift_clipping [*src++ >> 4]; + val2 = shift_clipping [*src++ >> 4]; +#else /* not HAVE_SIGNED_SHIFT */ + val1 = shift_clipping [*src++ / 16]; + val2 = shift_clipping [*src++ / 16]; +#endif /* not HAVE_SIGNED_SHIFT */ + + *dst++ = val1 | (val1 << 8) + | (val1 << 16) | (val2 << 24); /* RGBR */ + *dst = val2 | (val2 << 8); /* GB-- */ + +#ifdef HAVE_SIGNED_SHIFT + val1 = shift_clipping [*src++ >> 4]; + val2 = shift_clipping [*src++ >> 4]; +#else /* not HAVE_SIGNED_SHIFT */ + val1 = shift_clipping [*src++ / 16]; + val2 = shift_clipping [*src++ / 16]; +#endif /* not HAVE_SIGNED_SHIFT */ + + *dst++ |= (val1 << 16) | (val1 << 24); /* --RG */ + *dst++ = val1 | (val2 << 8) + | (val2 << 16) | (val2 << 24); /* BRGB */ + } + } + } + + return 1; +} + +static int +display_32_bit (const struct fiasco_renderer *this, unsigned char *ximage, + const fiasco_image_t *fiasco_image) +/* + * Convert 'image' to 16 bit color bitmap. + * If 'double_resolution' is true then double image size in both directions. + * + * No return value. + * + * Side effects: + * 'out[]' is filled with dithered image + */ +{ + const image_t *image; + renderer_private_t *private; + byte_t *out; + + if (!this) + { + set_error (_("Parameter `%s' not defined (NULL)."), "this"); + return 0; + } + if (!ximage) + { + set_error (_("Parameter `%s' not defined (NULL)."), "ximage"); + return 0; + } + if (!fiasco_image) + { + set_error (_("Parameter `%s' not defined (NULL)."), "fiasco_image"); + return 0; + } + + out = (byte_t *) ximage; + private = (renderer_private_t *) this->private; + image = cast_image ((fiasco_image_t *) fiasco_image); + if (!image) + return 0; + + if (image->color) + { + word_t *cbptr, *crptr; /* pointer to chroma bands */ + word_t *yptr; /* pointers to lumincance band */ + int yval, crval, cbval; /* pixel value in YCbCr color space */ + int R, G, B; /* pixel value in RGB color space */ + int n; /* pixel counter */ + int x, y; /* pixel coordinates */ + int *Cr_r_tab, *Cr_g_tab, *Cb_g_tab, *Cb_b_tab; + unsigned int *r_table, *g_table, *b_table; + + Cr_g_tab = private->Cr_g_tab; + Cr_r_tab = private->Cr_r_tab; + Cb_b_tab = private->Cb_b_tab; + Cb_g_tab = private->Cb_g_tab; + r_table = private->r_table; + g_table = private->g_table; + b_table = private->b_table; + yptr = image->pixels [Y]; + cbptr = image->pixels [Cb]; + crptr = image->pixels [Cr]; + + if (image->format == FORMAT_4_2_0) + { + unsigned int *dst, *dst2; /* pointers to dithered pixels */ + word_t *yptr2; /* pointers to lumincance band */ + + if (private->double_resolution) + { + yptr2 = yptr + image->width; + dst = (unsigned int *) out; + dst2 = dst + 4 * image->width; + for (y = image->height / 2; y; y--) + { + for (x = image->width / 2; x; x--) + { +#ifdef HAVE_SIGNED_SHIFT + crval = *crptr++ >> 4; + cbval = *cbptr++ >> 4; + yval = (*yptr++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + crval = *crptr++ / 16; + cbval = *cbptr++ / 16; + yval = *yptr++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + R = yval + Cr_r_tab [crval]; + G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval]; + B = yval + Cb_b_tab [cbval]; + *dst++ = r_table [R] | g_table [G] | b_table [B]; + *dst++ = r_table [R] | g_table [G] | b_table [B]; + +#ifdef HAVE_SIGNED_SHIFT + yval = (*yptr++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + yval = *yptr++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + R = yval + Cr_r_tab [crval]; + G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval]; + B = yval + Cb_b_tab [cbval]; + *dst++ = r_table [R] | g_table [G] | b_table [B]; + *dst++ = r_table [R] | g_table [G] | b_table [B]; + +#ifdef HAVE_SIGNED_SHIFT + yval = (*yptr2++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + yval = *yptr2++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + R = yval + Cr_r_tab [crval]; + G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval]; + B = yval + Cb_b_tab [cbval]; + *dst2++ = r_table [R] | g_table [G] | b_table [B]; + *dst2++ = r_table [R] | g_table [G] | b_table [B]; + +#ifdef HAVE_SIGNED_SHIFT + yval = (*yptr2++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + yval = *yptr2++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + R = yval + Cr_r_tab [crval]; + G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval]; + B = yval + Cb_b_tab [cbval]; + *dst2++ = r_table [R] | g_table [G] | b_table [B]; + *dst2++ = r_table [R] | g_table [G] | b_table [B]; + } + memcpy (dst, dst - 2 * image->width, + 2 * image->width * sizeof (unsigned int)); + memcpy (dst2, dst2 - 2 * image->width, + 2 * image->width * sizeof (unsigned int)); + yptr += image->width; + yptr2 += image->width; + dst += 3 * image->width * 2; + dst2 += 3 * image->width * 2; + } + } + else + { + yptr2 = yptr + image->width; + dst = (unsigned int *) out; + dst2 = dst + image->width; + + for (y = image->height / 2; y; y--) + { + for (x = image->width / 2; x; x--) + { +#ifdef HAVE_SIGNED_SHIFT + crval = *crptr++ >> 4; + cbval = *cbptr++ >> 4; + yval = (*yptr++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + crval = *crptr++ / 16; + cbval = *cbptr++ / 16; + yval = *yptr++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + R = yval + Cr_r_tab [crval]; + G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval]; + B = yval + Cb_b_tab [cbval]; + *dst++ = r_table [R] | g_table [G] | b_table [B]; + +#ifdef HAVE_SIGNED_SHIFT + yval = (*yptr++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + yval = *yptr++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + R = yval + Cr_r_tab [crval]; + G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval]; + B = yval + Cb_b_tab [cbval]; + *dst++ = r_table [R] | g_table [G] | b_table [B]; + +#ifdef HAVE_SIGNED_SHIFT + yval = (*yptr2++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + yval = *yptr2++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + R = yval + Cr_r_tab [crval]; + G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval]; + B = yval + Cb_b_tab [cbval]; + *dst2++ = r_table [R] | g_table [G] | b_table [B]; + +#ifdef HAVE_SIGNED_SHIFT + yval = (*yptr2++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + yval = *yptr2++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + R = yval + Cr_r_tab [crval]; + G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval]; + B = yval + Cb_b_tab [cbval]; + *dst2++ = r_table [R] | g_table [G] | b_table [B]; + } + yptr += image->width; + yptr2 += image->width; + dst += image->width; + dst2 += image->width; + } + } + } + else /* 4:4:4 format */ + { + if (private->double_resolution) + { + unsigned int *dst; /* pointer to dithered pixels */ + + dst = (unsigned int *) out; + + for (y = image->height; y; y--) + { + for (x = image->width; x; x--) + { +#ifdef HAVE_SIGNED_SHIFT + crval = *crptr++ >> 4; + cbval = *cbptr++ >> 4; + yval = (*yptr++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + crval = *crptr++ / 16; + cbval = *cbptr++ / 16; + yval = *yptr++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + R = yval + Cr_r_tab [crval]; + G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval]; + B = yval + Cb_b_tab [cbval]; + + *dst++ = r_table [R] | g_table [G] | b_table [B]; + *dst++ = r_table [R] | g_table [G] | b_table [B]; + } + memcpy (dst, dst - 2 * image->width, + 2 * image->width * sizeof (unsigned int)); + dst += image->width * 2; + } + } + else + { + unsigned int *dst; /* pointer to dithered pixels */ + + dst = (unsigned int *) out; + + for (n = image->width * image->height; n; n--) + { +#ifdef HAVE_SIGNED_SHIFT + crval = *crptr++ >> 4; + cbval = *cbptr++ >> 4; + yval = (*yptr++ >> 4) + 128; +#else /* not HAVE_SIGNED_SHIFT */ + crval = *crptr++ / 16; + cbval = *cbptr++ / 16; + yval = *yptr++ / 16 + 128; +#endif /* not HAVE_SIGNED_SHIFT */ + R = yval + Cr_r_tab [crval]; + G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval]; + B = yval + Cb_b_tab [cbval]; + + *dst++ = r_table [R] | g_table [G] | b_table [B]; + } + } + } + } + else + { + unsigned int *dst; /* pointer to dithered pixels */ + word_t *src; /* current pixel of frame */ + unsigned int *y_table; + + y_table = private->y_table; + dst = (unsigned int *) out; + src = image->pixels [GRAY]; + + if (private->double_resolution) + { + int x, y; /* pixel coordinates */ + + for (y = image->height; y; y--) + { + for (x = image->width; x; x--) + { + int value; + +#ifdef HAVE_SIGNED_SHIFT + value = y_table [*src++ >> 4]; +#else /* not HAVE_SIGNED_SHIFT */ + value = y_table [*src++ / 16]; +#endif /* not HAVE_SIGNED_SHIFT */ + *dst++ = value; + *dst++ = value; + } + + memcpy (dst, dst - 2 * image->width, + 2 * image->width * sizeof (unsigned int)); + dst += 2 * image->width; + } + } + else + { + int n; /* pixel counter */ + + for (n = image->width * image->height; n; n--) +#ifdef HAVE_SIGNED_SHIFT + *dst++ = y_table [*src++ >> 4]; +#else /* not HAVE_SIGNED_SHIFT */ + *dst++ = y_table [*src++ / 16]; +#endif /* not HAVE_SIGNED_SHIFT */ + } + } + + return 1; +} + + + diff --git a/converter/other/fiasco/lib/dither.h b/converter/other/fiasco/lib/dither.h new file mode 100644 index 00000000..71f9d3c3 --- /dev/null +++ b/converter/other/fiasco/lib/dither.h @@ -0,0 +1,27 @@ +/* + * dither.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:49:37 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#ifndef _DITHER_H +#define _DITHER_H + +typedef struct renderer_private +{ + int *Cr_r_tab, *Cr_g_tab, *Cb_g_tab, *Cb_b_tab; + unsigned int *r_table, *g_table, *b_table, *y_table; + bool_t double_resolution; +} renderer_private_t; + +#endif /* _DITHER_H */ diff --git a/converter/other/fiasco/lib/error.c b/converter/other/fiasco/lib/error.c new file mode 100644 index 00000000..b858badf --- /dev/null +++ b/converter/other/fiasco/lib/error.c @@ -0,0 +1,326 @@ +/* + * error.c: Error handling + * + * Written by: Stefan Frank + * Ullrich Hafner + * + * Credits: Modelled after variable argument routines from Jef + * Poskanzer's pbmplus package. + * + * 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> + + "int dummy = " change to int dummy; dummy =" for Netpbm to avoid + unused variable warning. + + */ + +/* + * $Date: 2000/06/14 20:49:37 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#define _ERROR_C + +#include "config.h" + +#include <stdio.h> +#include <errno.h> + +#if STDC_HEADERS +# include <stdarg.h> +# define VA_START(args, lastarg) va_start(args, lastarg) +#else /* not STDC_HEADERS */ +# include <varargs.h> +# define VA_START(args, lastarg) va_start(args) +#endif /* not STDC_HEADERS */ +#if HAVE_STRING_H +# include <string.h> +#else /* not HAVE_STRING_H */ +# include <strings.h> +#endif /* not HAVE_STRING_H */ + +#if HAVE_SETJMP_H +# include <setjmp.h> +#endif /* HAVE_SETJMP_H */ + +#include "types.h" +#include "macros.h" +#include "error.h" + +#include "misc.h" +#include "fiasco.h" + +/***************************************************************************** + + local variables + +*****************************************************************************/ + +static fiasco_verbosity_e verboselevel = FIASCO_SOME_VERBOSITY; +static char *error_message = NULL; + +#if HAVE_SETJMP_H +jmp_buf env; +#endif /* HAVE_SETJMP_H */ + +/***************************************************************************** + + public code + +*****************************************************************************/ + +void +set_error (const char *format, ...) +/* + * Set error text to given string. + */ +{ + va_list args; + unsigned len = 0; + const char *str = format; + + VA_START (args, format); + + len = strlen (format); + while ((str = strchr (str, '%'))) + { + str++; + if (*str == 's') + { + char *vstring = va_arg (args, char *); + len += strlen (vstring); + } + else if (*str == 'd') + { + int dummy; + dummy = va_arg (args, int); + len += 10; + } + else if (*str == 'c') + { + int dummy; + dummy = va_arg (args, int); + len += 1; + } + else + return; + str++; + } + va_end(args); + + VA_START (args, format); + + if (error_message) + Free (error_message); + error_message = Calloc (len, sizeof (char)); + +#if HAVE_VPRINTF + vsprintf (error_message, format, args); +#elif HAVE_DOPRNT + _doprnt (format, args, stderr); +#endif /* HAVE_DOPRNT */ + + va_end (args); +} + +void +error (const char *format, ...) +/* + * Set error text to given string. + */ +{ + va_list args; + unsigned len = 0; + const char *str = format; + + VA_START (args, format); + + len = strlen (format); + while ((str = strchr (str, '%'))) + { + str++; + if (*str == 's') + { + char *vstring = va_arg (args, char *); + len += strlen (vstring); + } + else if (*str == 'd') + { + int dummy; + dummy = va_arg (args, int); + len += 10; + } + else if (*str == 'c') + { + int dummy; + dummy = va_arg (args, int); + len += 1; + } + else + { +#if HAVE_SETJMP_H + longjmp (env, 1); +#else /* not HAVE_SETJMP_H */ + exit (1); +#endif /* HAVE_SETJMP_H */ + }; + + str++; + } + va_end(args); + + VA_START (args, format); + + if (error_message) + Free (error_message); + error_message = Calloc (len, sizeof (char)); + +#if HAVE_VPRINTF + vsprintf (error_message, format, args); +#elif HAVE_DOPRNT + _doprnt (format, args, stderr); +#endif /* HAVE_DOPRNT */ + + va_end (args); + +#if HAVE_SETJMP_H + longjmp (env, 1); +#else /* not HAVE_SETJMP_H */ + exit (1); +#endif /* HAVE_SETJMP_H */ +} + +const char * +fiasco_get_error_message (void) +/* + * Return value: + * Last error message of FIASCO library. + */ +{ + return error_message ? error_message : ""; +} + +const char * +get_system_error (void) +{ + return strerror (errno); +} + +void +file_error (const char *filename) +/* + * Print file error message and exit. + * + * No return value. + */ +{ + error ("File `%s': I/O Error - %s.", filename, get_system_error ()); +} + +void +warning (const char *format, ...) +/* + * Issue a warning and continue execution. + * + * No return value. + */ +{ + va_list args; + + VA_START (args, format); + + if (verboselevel == FIASCO_NO_VERBOSITY) + return; + + fprintf (stderr, "Warning: "); +#if HAVE_VPRINTF + vfprintf (stderr, format, args); +#elif HAVE_DOPRNT + _doprnt (format, args, stderr); +#endif /* HAVE_DOPRNT */ + fputc ('\n', stderr); + + va_end (args); +} + +void +message (const char *format, ...) +/* + * Print a message to stderr. + */ +{ + va_list args; + + VA_START (args, format); + + if (verboselevel == FIASCO_NO_VERBOSITY) + return; + +#if HAVE_VPRINTF + vfprintf (stderr, format, args); +#elif HAVE_DOPRNT + _doprnt (format, args, stderr); +#endif /* HAVE_DOPRNT */ + fputc ('\n', stderr); + va_end (args); +} + +void +debug_message (const char *format, ...) +/* + * Print a message to stderr. + */ +{ + va_list args; + + VA_START (args, format); + + if (verboselevel < FIASCO_ULTIMATE_VERBOSITY) + return; + + fprintf (stderr, "*** "); +#if HAVE_VPRINTF + vfprintf (stderr, format, args); +#elif HAVE_DOPRNT + _doprnt (format, args, stderr); +#endif /* HAVE_DOPRNT */ + fputc ('\n', stderr); + va_end (args); +} + +void +info (const char *format, ...) +/* + * Print a message to stderr. Do not append a newline. + */ +{ + va_list args; + + VA_START (args, format); + + if (verboselevel == FIASCO_NO_VERBOSITY) + return; + +#if HAVE_VPRINTF + vfprintf (stderr, format, args); +#elif HAVE_DOPRNT + _doprnt (format, args, stderr); +#endif /* HAVE_DOPRNT */ + fflush (stderr); + va_end (args); +} + +void +fiasco_set_verbosity (fiasco_verbosity_e level) +{ + verboselevel = level; +} + +fiasco_verbosity_e +fiasco_get_verbosity (void) +{ + return verboselevel; +} diff --git a/converter/other/fiasco/lib/error.h b/converter/other/fiasco/lib/error.h new file mode 100644 index 00000000..288b25f4 --- /dev/null +++ b/converter/other/fiasco/lib/error.h @@ -0,0 +1,39 @@ +/* + * error.h + * + * Written by: Stefan Frank + * 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> + */ + +#ifndef ERROR_H_INCLUDED +#define ERROR_H_INCLUDED + +void +set_error (const char *format, ...); +void +error (const char *format, ...); +void +file_error (const char *filename); +void +message (const char *format, ...); +void +debug_message (const char *format, ...); +void +warning (const char *format, ...); +void +info (const char *format, ...); +const char * +get_system_error (void); + +#include <setjmp.h> +extern jmp_buf env; + +#define try if (setjmp (env) == 0) +#define catch else + +#include <assert.h> + +#endif diff --git a/converter/other/fiasco/lib/image.c b/converter/other/fiasco/lib/image.c new file mode 100644 index 00000000..019ba03c --- /dev/null +++ b/converter/other/fiasco/lib/image.c @@ -0,0 +1,512 @@ +/* + * image.c: Input and output of PNM 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/06/15 17:21:30 $ + * $Author: hafner $ + * $Revision: 5.2 $ + * $State: Exp $ + */ + +#include "pnm.h" + +#include <string.h> + +#include "types.h" +#include "macros.h" +#include "error.h" + +#include "fiasco.h" +#include "misc.h" +#include "image.h" + +/***************************************************************************** + + prototypes + +*****************************************************************************/ + +static void +init_chroma_tables (void); + +/***************************************************************************** + + local variables + +*****************************************************************************/ +static int *Cr_r_tab = NULL; +static int *Cr_g_tab = NULL; +static int *Cb_g_tab = NULL; +static int *Cb_b_tab = NULL; + +/***************************************************************************** + + public code + +*****************************************************************************/ + +fiasco_image_t * +fiasco_image_new (const char *filename) +/* + * FIASCO image constructor. + * Allocate memory for the FIASCO image structure and + * load the specified image `filename'. The image has to be in + * raw pgm or ppm format. + * + * Return value: + * pointer to the new image structure + * or NULL in case of an error + */ +{ + try + { + fiasco_image_t *image = Calloc (1, sizeof (fiasco_image_t)); + + image->private = read_image (filename); + 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; + } +} + +void +fiasco_image_delete (fiasco_image_t *image) +/* + * FIASCO image destructor. + * Free memory of FIASCO image struct. + * + * No return value. + * + * Side effects: + * structure 'image' is discarded. + */ +{ + image_t *this = cast_image (image); + + if (!this) + return; + + try + { + free_image (this); + } + catch + { + return; + } +} + +unsigned +fiasco_image_get_width (fiasco_image_t *image) +{ + image_t *this = cast_image (image); + + if (!this) + return 0; + else + return this->width; +} + +unsigned +fiasco_image_get_height (fiasco_image_t *image) +{ + image_t *this = cast_image (image); + + if (!this) + return 0; + else + return this->width; +} + +int +fiasco_image_is_color (fiasco_image_t *image) +{ + image_t *this = cast_image (image); + + if (!this) + return 0; + else + return this->color; +} + +image_t * +cast_image (fiasco_image_t *image) +/* + * Cast pointer `image' to type image_t. + * Check whether `image' is a valid object of type image_t. + * + * Return value: + * pointer to dfiasco_t struct on success + * NULL otherwise + */ +{ + image_t *this = (image_t *) image->private; + if (this) + { + if (!streq (this->id, "IFIASCO")) + { + set_error (_("Parameter `image' doesn't match required type.")); + return NULL; + } + } + else + { + set_error (_("Parameter `%s' not defined (NULL)."), "image"); + } + + return this; +} + +image_t * +alloc_image (unsigned width, unsigned height, bool_t color, format_e format) +/* + * Image constructor: + * Allocate memory for the image_t structure. + * Image size is given by 'width' and 'height'. + * If 'color' == YES then allocate memory for three color bands (Y, Cb, Cr). + * otherwise just allocate memory for a grayscale image. + * 'format' specifies whether image pixels of color images + * are stored in 4:4:4 or 4:2:0 format. + * + * Return value: + * pointer to the new image structure. + */ +{ + image_t *image; + color_e band; + + if ((width & 1) || (height & 1)) + error ("Width and height of images must be even numbers."); + if (!color) + format = FORMAT_4_4_4; + + image = Calloc (1, sizeof (image_t)); + image->width = width; + image->height = height; + image->color = color; + image->format = format; + image->reference_count = 1; + + strcpy (image->id, "IFIASCO"); + + for (band = first_band (color); band <= last_band (color); band++) + if (format == FORMAT_4_2_0 && band != Y) + image->pixels [band] = Calloc ((width * height) >> 2, + sizeof (word_t)); + else + image->pixels [band] = Calloc (width * height, sizeof (word_t)); + + return image; +} + +image_t * +clone_image (image_t *image) +/* + * Copy constructor: + * Construct new image by copying the given `image'. + * + * Return value: + * pointer to the new image structure. + */ +{ + image_t *new = alloc_image (image->width, image->height, image->color, + image->format); + color_e band; + + for (band = first_band (new->color); band <= last_band (new->color); band++) + if (new->format == FORMAT_4_2_0 && band != Y) + { + memcpy (new->pixels [band], image->pixels [band], + ((new->width * new->height) >> 2) * sizeof (word_t)); + } + else + { + memcpy (new->pixels [band], image->pixels [band], + new->width * new->height * sizeof (word_t)); + } + + return new; +} + +void +free_image (image_t *image) +/* + * Image destructor: + * Free memory of 'image' struct and pixel data. + * + * No return value. + * + * Side effects: + * structure 'image' is discarded. + */ +{ + if (image != NULL) + { + if (--image->reference_count) + return; /* image is still referenced */ + else + { + color_e band; + + for (band = first_band (image->color); + band <= last_band (image->color); band++) + if (image->pixels [band]) + Free (image->pixels [band]); + Free (image); + } + } + else + warning ("Can't free image <NULL>."); +} + + +static void +read_image_data(image_t * const image, FILE *input, const bool_t color, + const int width, const int height, const xelval maxval, + const int format) { + int row; + int i; /* Cursor into image->pixels arrays */ + xel * xelrow; + /* The following are just the normal rgb -> YCbCr conversion matrix, + except normalization to maxval 4095 (12 bit color) is built in + */ + const double coeff_lu_r = +0.2989 / maxval * 4095; + const double coeff_lu_g = +0.5866 / maxval * 4095; + const double coeff_lu_b = +0.1145 / maxval * 4095; + const double coeff_cb_r = -0.1687 / maxval * 4095; + const double coeff_cb_g = -0.3312 / maxval * 4095; + const double coeff_cb_b = +0.5000 / maxval * 4095; + const double coeff_cr_r = +0.5000 / maxval * 4095; + const double coeff_cr_g = -0.4183 / maxval * 4095; + const double coeff_cr_b = -0.0816 / maxval * 4095; + + xelrow = pnm_allocrow(width); + + i = 0; + for (row = 0; row < height; row++) { + int col; + pnm_readpnmrow(input, xelrow, width, maxval, format); + for (col = 0; col < width; col++) { + if (color) { + image->pixels[Y][i] = + coeff_lu_r * PPM_GETR(xelrow[col]) + + coeff_lu_g * PPM_GETG(xelrow[col]) + + coeff_lu_b * PPM_GETB(xelrow[col]) - 2048; + image->pixels[Cb][i] = + coeff_cb_r * PPM_GETR(xelrow[col]) + + coeff_cb_g * PPM_GETG(xelrow[col]) + + coeff_cb_b * PPM_GETB(xelrow[col]); + image->pixels[Cr][i] = + coeff_cr_r * PPM_GETR(xelrow[col]) + + coeff_cr_g * PPM_GETG(xelrow[col]) + + coeff_cr_b * PPM_GETB(xelrow[col]); + + i++; + } else + image->pixels[GRAY][i++] = + PNM_GET1(xelrow[col]) * 4095 / maxval - 2048; + } + } + + free(xelrow); +} + + + +image_t * +read_image (const char *image_name) +/* + * Read image 'image_name'. + * + * Return value: + * pointer to the image structure. + */ +{ + FILE *input; /* input stream */ + image_t *image; /* pointer to new image structure */ + int width, height; /* image size */ + xelval maxval; /* Maxval of image */ + int format; /* Image's format code */ + bool_t color; /* color image ? (YES/NO) */ + + if (image_name == NULL) + input = stdin; + else + input = pm_openr((char*)image_name); + + pnm_readpnminit(input, &width, &height, &maxval, &format); + + if (PNM_FORMAT_TYPE(format) == PPM_FORMAT) + color = YES; + else + color = NO; + + if (width < 32) + pm_error("Image must have a width of at least 32 pixels."); + + if (height < 32) + pm_error("Image must have a height of at least 32 pixels."); + + image = alloc_image (width, height, color, FORMAT_4_4_4); + + read_image_data(image, input, color, width, height, maxval, format); + + pm_close(input); + + return image; +} + +void +write_image (const char *image_name, const image_t *image) +/* + * Write given 'image' data to the file 'image_name'. + * + * No return value. + */ +{ + FILE *output; /* output stream */ + int format; + int row; + int i; /* Cursor into image->pixel arrays */ + xel * xelrow; + unsigned *gray_clip; /* clipping table */ + + assert (image && image_name); + + if (image->format == FORMAT_4_2_0) + { + warning ("Writing of images in 4:2:0 format not supported."); + return; + } + + if (image_name == NULL) + output = stdout; + else if (strcmp(image_name, "-") == 0) + output = stdout; + else + output = pm_openw((char*)image_name); + + gray_clip = init_clipping (); /* mapping of int -> unsigned */ + if (!gray_clip) + error (fiasco_get_error_message ()); + init_chroma_tables (); + + format = image->color ? PPM_TYPE : PGM_TYPE; + + pnm_writepnminit(output, image->width, image->height, 255, format, 0); + + xelrow = pnm_allocrow(image->width); + i = 0; + for (row = 0; row < image->height; row++) { + int col; + for (col = 0; col < image->width; col++) { + if (image->color) { + word_t yval, cbval, crval; + + yval = image->pixels[Y][i] / 16 + 128; + cbval = image->pixels[Cb][i] / 16; + crval = image->pixels[Cr][i] / 16; + + PPM_ASSIGN(xelrow[col], + gray_clip[yval + Cr_r_tab[crval]], + gray_clip[yval + Cr_g_tab[crval] + Cb_g_tab [cbval]], + gray_clip[yval + Cb_b_tab[cbval]]); + + } else + /* The 16 below should be 4095/255 = 16.0588 */ + PNM_ASSIGN1(xelrow[col], + gray_clip[image->pixels[GRAY][i]/16+128]); + i++; + } + pnm_writepnmrow(output, xelrow, + image->width, 255, format, 0); + } + pnm_freerow(xelrow); + + pm_close(output); +} + +bool_t +same_image_type (const image_t *img1, const image_t *img2) +/* + * Check whether the given images 'img1' and `img2' are of the same type. + * + * Return value: + * YES if images 'img1' and `img2' are of the same type + * NO otherwise. + */ +{ + assert (img1 && img2); + + return ((img1->width == img2->width) + && (img1->height == img2->height) + && (img1->color == img2->color) + && (img1->format == img2->format)); +} + +/***************************************************************************** + + private code + +*****************************************************************************/ + +static void +init_chroma_tables (void) +/* + * Chroma tables are used to perform fast YCbCr->RGB color space conversion. + */ +{ + int crval, cbval, i; + + if (Cr_r_tab != NULL || Cr_g_tab != NULL || + Cb_g_tab != NULL || Cb_b_tab != NULL) + return; + + Cr_r_tab = Calloc (768, sizeof (int)); + Cr_g_tab = Calloc (768, sizeof (int)); + Cb_g_tab = Calloc (768, sizeof (int)); + Cb_b_tab = Calloc (768, sizeof (int)); + + for (i = 256; i < 512; i++) + { + cbval = crval = i - 128 - 256; + + Cr_r_tab[i] = 1.4022 * crval + 0.5; + Cr_g_tab[i] = -0.7145 * crval + 0.5; + Cb_g_tab[i] = -0.3456 * cbval + 0.5; + Cb_b_tab[i] = 1.7710 * cbval + 0.5; + } + for (i = 0; i < 256; i++) + { + Cr_r_tab[i] = Cr_r_tab[256]; + Cr_g_tab[i] = Cr_g_tab[256]; + Cb_g_tab[i] = Cb_g_tab[256]; + Cb_b_tab[i] = Cb_b_tab[256]; + } + for (i = 512; i < 768; i++) + { + Cr_r_tab[i] = Cr_r_tab[511]; + Cr_g_tab[i] = Cr_g_tab[511]; + Cb_g_tab[i] = Cb_g_tab[511]; + Cb_b_tab[i] = Cb_b_tab[511]; + } + + Cr_r_tab += 256 + 128; + Cr_g_tab += 256 + 128; + Cb_g_tab += 256 + 128; + Cb_b_tab += 256 + 128; +} + diff --git a/converter/other/fiasco/lib/image.h b/converter/other/fiasco/lib/image.h new file mode 100644 index 00000000..958049f6 --- /dev/null +++ b/converter/other/fiasco/lib/image.h @@ -0,0 +1,59 @@ +/* + * image.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:43:56 $ + * $Author: hafner $ + * $Revision: 5.3 $ + * $State: Exp $ + */ + +#ifndef _IMAGE_H +#define _IMAGE_H + +#include <stdio.h> +#include "types.h" +#include "fiasco.h" + +typedef enum {FORMAT_4_4_4, FORMAT_4_2_0} format_e; + +typedef struct image +/* + * Image data + */ +{ + char id [7]; + unsigned reference_count; + unsigned width; /* Width of the image */ + unsigned height; /* Height of the image */ + bool_t color; /* Color or grayscale image */ + format_e format; /* Pixel format 4:4:4 or 4:2:0 */ + word_t *pixels [3]; /* Pixels in short format */ +} image_t; + +image_t * +cast_image (fiasco_image_t *image); +image_t * +alloc_image (unsigned width, unsigned height, bool_t color, format_e format); +image_t * +clone_image (image_t *image); +void +free_image (image_t *image); +FILE * +read_pnmheader (const char *image_name, unsigned *width, unsigned *height, + bool_t *color); +image_t * +read_image (const char *image_name); +void +write_image (const char *image_name, const image_t *image); +bool_t +same_image_type (const image_t *img1, const image_t *img2); + +#endif /* not _IMAGE_H */ + diff --git a/converter/other/fiasco/lib/list.c b/converter/other/fiasco/lib/list.c new file mode 100644 index 00000000..9f516c2e --- /dev/null +++ b/converter/other/fiasco/lib/list.c @@ -0,0 +1,258 @@ +/* + * list.c: List operations + * + * 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:49:37 $ + * $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 "misc.h" +#include "list.h" + +/***************************************************************************** + + public code + +*****************************************************************************/ + +list_t * +alloc_list (size_t size_of_element) +/* + * List constructor: + * Allocate a new list. + * Size of list element values is given by 'size_of_element'. + * + * Return value: + * pointer to an empty list + */ +{ + list_t *new_list = Calloc (1, sizeof (list_t)); + + assert (size_of_element > 0); + + new_list->head = NULL; + new_list->tail = NULL; + new_list->size_of_element = size_of_element; + + return new_list; +} + +void +free_list (list_t *list) +/* + * List destructor: + * Discard list and its elements. + * + * No return value. + * + * Side effects: + * struct 'list' is discarded + */ +{ + assert (list); + + while (list_remove (list, HEAD, NULL)) + ; + Free (list); +} + +void +list_insert (list_t *list, pos_e pos, const void *data) +/* + * Insert a new 'list' element at head ('pos' = HEAD) or + * tail ('pos' = TAIL) of 'list'. + * 'data' is a pointer to a memory segment of size + * 'list'->size_of_element containing the value to store. + * The value is directly copied - no references are stored. + * + * No return value. + * + * Side effects: + * lists current tail or head is replaced by the new element + */ +{ + node_t *element; + + assert (list && data); + + element = Calloc (1, sizeof (node_t)); + element->value = Calloc (1, list->size_of_element); + memcpy (element->value, data, list->size_of_element); + + if (pos == TAIL) + { + element->next = NULL; + element->prev = list->tail; + if (list->tail) + list->tail->next = element; + list->tail = element; + if (!list->head) + list->head = element; + } + else /* pos == HEAD */ + { + element->prev = NULL; + element->next = list->head; + if (list->head) + list->head->prev = element; + list->head = element; + if (!list->tail) + list->tail = element; + } +} + +bool_t +list_remove (list_t *list, pos_e pos, void *data) +/* + * Remove 'list' element from head or tail of 'list'. + * + * Return value: + * TRUE on success, + * FALSE if list is empty or + * if list value data is NULL + * + * Side effects: + * lists current head or tail is removed + * value of the removed list element (if not NULL) is copied to + * 'data' (if 'data' is not NULL) + */ +{ + node_t *element; + void *valueptr; + + assert (list); + + if (pos == TAIL) + { + element = list->tail; + if (element) + { + list->tail = element->prev; + valueptr = element->value; + Free (element); + } + else + valueptr = NULL; + if (!list->tail) /* 'element' was last node */ + list->head = NULL; + } + else /* pos == HEAD */ + { + element = list->head; + if (element) + { + list->head = element->next; + valueptr = element->value; + Free (element); + } + else + valueptr = NULL; + if (!list->head) /* 'element' was last node */ + list->tail = NULL; + } + + if (valueptr) /* copy value of node */ + { + if (data) + memcpy (data, valueptr, list->size_of_element); + Free (valueptr); + } + + return valueptr ? TRUE : FALSE; +} + +bool_t +list_element_n (const list_t *list, pos_e pos, unsigned n, void *data) +/* + * Get value of 'list' element number 'n'. + * (First element is list head if 'pos' == HEAD + * or list tail if 'pos' == TAIL. + * Accordingly, traverse the list in ascending or descending order). + * + * Return value: + * TRUE on success, FALSE if there is no element 'n' + * + * Side effects: + * value of list element 'n' is copied to 'data' + */ +{ + node_t *element; + + assert (list && data); + + if (pos == HEAD) + for (element = list->head; element != NULL && n; + element = element->next, n--) + ; + else + for (element = list->tail; element != NULL && n; + element = element->prev, n--) + ; + + if (element) + { + memcpy (data, element->value, list->size_of_element); + return TRUE; + } + else + return FALSE; +} + +unsigned +list_sizeof (const list_t *list) +/* + * Count number of 'list' elements. + * + * Return value: + * number of 'list' elements. + */ +{ + node_t *element; + unsigned n = 0; + + assert (list); + + for (element = list->head; element != NULL; element = element->next) + n++; + + return n; +} + +void +list_foreach (const list_t *list, void (*function)(void *, void *), void *data) +/* + * Call 'function' for each element of the 'list'. + * Parameters given to 'function' are a pointer to the value of the + * current 'list' element and the user pointer 'data'. + * + * No return value. + */ +{ + node_t *element; + + assert (list && function && data); + + for (element = list->head; element; element = element->next) + function (element->value, data); +} + diff --git a/converter/other/fiasco/lib/list.h b/converter/other/fiasco/lib/list.h new file mode 100644 index 00000000..db7c08b2 --- /dev/null +++ b/converter/other/fiasco/lib/list.h @@ -0,0 +1,72 @@ +/* + * list.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:49:37 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#ifndef _LIST_H +#define _LIST_H + +#include <stdio.h> +#include <stddef.h> + +typedef struct node +{ + struct node *prev; /* pointer to prev list element */ + struct node *next; /* pointer to next list element */ + void *value; /* pointer to value of node */ +} node_t; + +typedef struct list +{ + node_t *head; + node_t *tail; + size_t size_of_element; /* number of bytes to store value */ +} list_t; + +typedef enum {TAIL, HEAD} pos_e; + +/* + * Alias definitions for queue and stack + */ + +typedef list_t lqueue_t ; +#define alloc_queue alloc_list +#define free_queue free_list +#define queue_append(q, d) (list_insert ((q), TAIL, (d))) +#define queue_remove(q, d) (list_remove ((q), HEAD, (d))) + +typedef list_t lstack_t ; +#define alloc_stack alloc_list +#define free_stack free_list +#define stack_push(q, d) (list_insert ((q), TAIL, (d))) +#define stack_pop(q, d) (list_remove ((q), TAIL, (d))) + +list_t * +alloc_list (size_t size_of_element); +void +free_list (list_t *list); +bool_t +list_element_n (const list_t *list, pos_e pos, unsigned n, void *data); +void +list_foreach (const list_t *list, void (*function)(void *, void *), + void *data); +void +list_insert (list_t *list, pos_e pos, const void *data); +bool_t +list_remove (list_t *list, pos_e pos, void *data); +unsigned +list_sizeof (const list_t *list); + +#endif /* not _LIST_H */ + diff --git a/converter/other/fiasco/lib/macros.h b/converter/other/fiasco/lib/macros.h new file mode 100644 index 00000000..877abeea --- /dev/null +++ b/converter/other/fiasco/lib/macros.h @@ -0,0 +1,70 @@ +/* + * macros.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:49:37 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#ifndef _MACROS_H +#define _MACROS_H + +#include <string.h> +/******************************************************************************* + + System configuration section + +*******************************************************************************/ + +#ifndef SEEK_CUR +# define SEEK_CUR 1 +#endif /* not SEEK_CUR */ + +#ifdef WIN32 +#undef max +#undef min +#endif /* not WIN32 */ + +/***************************************************************************** + + Various macros + +*****************************************************************************/ + +#define streq(str1, str2) (strcmp ((str1), (str2)) == 0) +#define strneq(str1, str2) (strcmp ((str1), (str2)) != 0) +#define square(x) ((x) * (x)) +#define first_band(color) ((unsigned) ((color) ? Y : GRAY)) +#define last_band(color) ((unsigned) ((color) ? Cr : GRAY)) +#define width_of_level(l) ((unsigned) (1 << ((l) >> 1))) +#define height_of_level(l) ((unsigned) (1 << (((l) + 1) >> 1))) +#define size_of_level(l) ((unsigned) (1 << (l))) +#define address_of_level(l) ((unsigned) (size_of_level (l) - 1)) +#define size_of_tree(l) ((unsigned) (address_of_level ((l) + 1))) +#define is_odd(n) (abs (n) % 2) +#ifndef max +#define max(a,b) ((a) < (b) ? (b) : (a)) +#endif +#ifndef min +#define min(a,b) ((a) > (b) ? (b) : (a)) +#endif +#define _(x) (x) + + +#define MAXSTRLEN 1024 +#define MAXSTRLEN_SCANF "%1024s" + +typedef enum color {GRAY = 0, Y = 0, Cb = 1, Cr = 2} color_e; + +#endif /* _MACROS_H */ + + + diff --git a/converter/other/fiasco/lib/misc.c b/converter/other/fiasco/lib/misc.c new file mode 100644 index 00000000..02a1314f --- /dev/null +++ b/converter/other/fiasco/lib/misc.c @@ -0,0 +1,563 @@ +/* + * misc.c: Some usefull functions, that don't fit in one of + * the other files and that are needed by at least + * two modules. + * + * Written by: Stefan Frank + * 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:49:37 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#include "config.h" + +#include <math.h> +#include <ctype.h> + +#ifdef TIME_WITH_SYS_TIME +# include <sys/time.h> +# include <time.h> +#else /* not TIME_WITH_SYS_TIME */ +# if HAVE_SYS_TIME_H +# include <sys/time.h> +# else /* not HAVE_SYS_TIME_H */ +# include <time.h> +# endif /* not HAVE_SYS_TIME_H */ +#endif /* not TIME_WITH_SYS_TIME */ + +#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 "bit-io.h" +#include "misc.h" + +/***************************************************************************** + + prototypes + +*****************************************************************************/ + +static void +remove_comments (FILE *file); + +/***************************************************************************** + + public code + +*****************************************************************************/ + +void * +Calloc (size_t n, size_t size) +/* + * Allocate memory like calloc (). + * + * Return value: Pointer to the new block of memory on success, + * otherwise the program is terminated. + */ +{ + void *ptr; /* pointer to the new memory block */ + + if (n <= 0 || size <= 0) + error ("Can't allocate memory for %d items of size %d", + (int) n, (int) size); + + ptr = calloc (n, size); + if (!ptr) + error ("Out of memory!"); + + return ptr; +} + +void +Free (void *memory) +/* + * Free memory given by the pointer 'memory' + * + * No return value. + */ +{ + if (memory != NULL) + free (memory); + else + warning ("Can't free memory block <NULL>."); +} + +unsigned +prg_timer (clock_t *last_timer, enum action_e action) +/* + * If 'action' == START then store current value of system timer. + * If 'action' == STOP then compute number of elapsed micro seconds since + * the last time 'prg_timer' was called + * with 'action' == START. + * + * Return value: + * Number of elapsed micro seconds if 'action' == STOP + * 0 if 'action' == START + * + * Side effects: + * last_timer is set to current timer if action == START + */ +{ + assert (last_timer); + + if (action == START) + { + *last_timer = clock (); + return 0; + } + else + return (clock () - *last_timer) / (CLOCKS_PER_SEC / 1000.0); +} + +real_t +read_real (FILE *infile) +/* + * Read one real value from the given input stream 'infile'. + * + * Return value: + * real value on success + */ +{ + float input; + + assert (infile); + + remove_comments (infile); + if (fscanf(infile, "%f", &input) != 1) + error("Can't read float value!"); + + return (real_t) input; +} + +int +read_int (FILE *infile) +/* + * Read one integer value from the given input stream 'infile'. + * + * Return value: + * integer value on success + */ +{ + int input; /* integer */ + + assert (infile); + + remove_comments (infile); + if (fscanf(infile, "%d", &input) != 1) + error("Can't read integer value!"); + + return input; +} + +static void +remove_comments (FILE *file) +/* + * Remove shell/pgm style comments (#) from the input 'file' + * + * No return value. + */ +{ + int c; /* current character */ + + assert (file); + + do + { + while (isspace(c = getc (file))) + ; + if (c == EOF) + error ("EOF reached, input seems to be truncated!"); + if (c == '#') + { + int dummy; + + while (((dummy = getc (file)) != '\n') && dummy != EOF) + ; + if (dummy == EOF) + error ("EOF reached, input seems to be truncated!"); + } + else + ungetc (c, file); + } while (c == '#'); +} + +void +write_rice_code (unsigned value, unsigned rice_k, bitfile_t *output) +/* + * Write 'value' to the stream 'output' using Rice coding with base 'rice_k'. + * + * No return value. + */ +{ + unsigned unary; /* unary part of Rice Code */ + + assert (output); + + for (unary = value >> rice_k; unary; unary--) + put_bit (output, 1); + put_bit (output, 0); + put_bits (output, value & ((1 << rice_k) - 1), rice_k); +} + +unsigned +read_rice_code (unsigned rice_k, bitfile_t *input) +/* + * Read a Rice encoded integer (base 'rice_k') from the stream 'input'. + * + * Return value: + * decoded integer + */ +{ + unsigned unary; /* unary part of Rice code */ + + assert (input); + + for (unary = 0; get_bit (input); unary++) /* unary part */ + ; + + return (unary << rice_k) | get_bits (input, rice_k); +} + +void +write_bin_code (unsigned value, unsigned maxval, bitfile_t *output) +/* + * Write 'value' to the stream 'output' using an adjusted binary code + * based on given 'maxval'. + * + * No return value. + */ +{ + unsigned k; + unsigned r; + + assert (output && maxval && value <= maxval); + + k = log2 (maxval + 1); + r = (maxval + 1) % (1 << k); + + if (value < maxval + 1 - 2 * r) /* 0, ... , maxval - 2r */ + put_bits (output, value, k); + else /* maxval - 2r + 1, ..., maxval */ + put_bits (output, value + maxval + 1 - 2 * r, k + 1); +} + +unsigned +read_bin_code (unsigned maxval, bitfile_t *input) +/* + * Read a bincode encoded integer from the stream 'input'. + * + * Return value: + * decoded integer + */ +{ + unsigned k; + unsigned r; + unsigned value; + + assert (input); + + k = log2 (maxval + 1); + r = (maxval + 1) % (1 << k); + + value = get_bits (input, k); + if (value < maxval + 1 - 2 * r) + return value; + else + { + value <<= 1; + if (get_bit (input)) + value++; + return value - maxval - 1 + 2 * r; + } +} + +unsigned +bits_rice_code (unsigned value, unsigned rice_k) +/* + * Compute number of bits needed for coding integer 'value' + * with given Rice code 'rice_k'. + * + * Return value: + * number of bits + */ +{ + unsigned unary; + unsigned bits = 0; + + for (unary = value >> rice_k; unary; unary--) + bits++; + bits += rice_k + 1; + + return bits; +} + +unsigned +bits_bin_code (unsigned value, unsigned maxval) +/* + * Compute number of bits needed for coding integer 'value' + * with adjusted binary code of given maximum value 'maxval'. + * + * Return value: + * number of bits + */ +{ + unsigned k; + unsigned r; + + assert (maxval && value <= maxval); + + k = log2 (maxval + 1); + r = (maxval + 1) % (1 << k); + + return value < maxval + 1 - 2 * r ? k : k + 1; +} + +unsigned * +init_clipping (void) +/* + * Initialize the clipping tables + * + * Return value: + * pointer to clipping table + */ +{ + static unsigned *gray_clip = NULL; /* clipping array */ + + if (gray_clip == NULL) /* initialize clipping table */ + { + int i; /* counter */ + + gray_clip = calloc (256 * 3, sizeof (unsigned)); + if (!gray_clip) + { + set_error (_("Out of memory.")); + return NULL; + } + gray_clip += 256; + + for (i = -256; i < 512; i++) + if (i < 0) + gray_clip [i] = 0; + else if (i > 255) + gray_clip [i] = 255; + else + gray_clip [i] = i; + } + + return gray_clip; +} + +#ifndef HAVE_MEMMOVE +void * +memmove (void *v_dst, const void *v_src, size_t n) +/* + * Copy 'n' bytes from memory area 'src' to memory area 'dest'. + * The memory areas may overlap. + * + * Return value: + * pointer 'dest' + */ +{ + byte_t *to, *dst = (byte_t *) v_dst; + const byte_t *from, *src = (byte_t *) v_src; + + assert (v_dst && v_src); + + if (dst <= src) + { + from = src; + to = dst; + for (; n; n--) + *to++ = *from++; + } + else + { + from = src + (n - 1); + to = dst + (n - 1); + for (; n; n--) + *to-- = *from--; + } + + return v_dst; +} +#endif /* not HAVE_MEMMOVE */ + +#ifndef HAVE_STRDUP +char * +strdup (const char *s) +/* + * Duplicate given string 's'. + * + * Return value: + * pointer to new string value + */ +{ + assert (s); + + return strcpy (Calloc (strlen (s) + 1, sizeof (char)), s); +} +#endif /* not HAVE_STRDUP */ + +/* Note that some systems have a "log2()" in the math library and some + have a "log2" macro. So we name ours Log2. But to avoid lots of + differences from the original fiasco source code, we define a + macro log2 in config.h to expand to Log2. + */ +double +Log2 (double x) +/* + * Return value: + * base-2 logarithm of 'x' + */ +{ + return log (x) / 0.69314718; +} + +#ifndef HAVE_STRCASECMP +bool_t +strcaseeq (const char *s1, const char *s2) +/* + * Compare strings 's1' and 's2', ignoring the case of the characters. + * + * Return value: + * TRUE if strings match, else FALSE + */ +{ + bool_t matched; + char *ls1, *ls2, *ptr; + + assert (s1 && s2); + + ls1 = strdup (s1); + ls2 = strdup (s2); + + for (ptr = ls1; *ptr; ptr++) + *ptr = tolower (*ptr); + for (ptr = ls2; *ptr; ptr++) + *ptr = tolower (*ptr); + + matched = streq (ls1, ls2) ? YES : NO; + + Free (ls1); + Free (ls2); + + return matched; +} +#endif /* not HAVE_STRCASECMP */ + +real_t +variance (const word_t *pixels, unsigned x0, unsigned y0, + unsigned width, unsigned height, unsigned cols) +/* + * Compute variance of subimage ('x0', y0', 'width', 'height') of + * the image data given by 'pixels' ('cols' is the number of pixels + * in one row of the image). + * + * Return value: + * variance + */ +{ + real_t average; /* average of pixel values */ + real_t variance; /* variance of pixel values */ + unsigned x, y; /* pixel counter */ + unsigned n; /* number of pixels */ + + assert (pixels); + + for (average = 0, n = 0, y = y0; y < y0 + height; y++) + for (x = x0; x < min (x0 + width, cols); x++, n++) + average += pixels [y * cols + x] / 16; + + average /= n; + + for (variance = 0, y = y0; y < y0 + height; y++) + for (x = x0; x < min (x0 + width, cols); x++) + variance += square ((pixels [y * cols + x] / 16) - average); + + return variance; +} + +int +sort_asc_word (const void *value1, const void *value2) +/* + * Sorting function for quicksort. + * Smallest values come first. + */ +{ + if (* (word_t *) value1 < * (word_t *) value2) + return -1; + else if (* (word_t *) value1 > * (word_t *) value2) + return +1; + else + return 0; +} + +int +sort_desc_word (const void *value1, const void *value2) +/* + * Sorting function for quicksort. + * Largest values come first. + */ +{ + if (* (word_t *) value1 > * (word_t *) value2) + return -1; + else if (* (word_t *) value1 < * (word_t *) value2) + return +1; + else + return 0; +} + +int +sort_asc_pair (const void *value1, const void *value2) +/* + * Sorting function for quicksort. + * Smallest values come first. + */ +{ + word_t v1 = ((pair_t *) value1)->key; + word_t v2 = ((pair_t *) value2)->key; + + if (v1 < v2) + return -1; + else if (v1 > v2) + return +1; + else + return 0; +} + +int +sort_desc_pair (const void *value1, const void *value2) +/* + * Sorting function for quicksort. + * Largest values come first. + */ +{ + word_t v1 = ((pair_t *) value1)->key; + word_t v2 = ((pair_t *) value2)->key; + + if (v1 > v2) + return -1; + else if (v1 < v2) + return +1; + else + return 0; +} diff --git a/converter/other/fiasco/lib/misc.h b/converter/other/fiasco/lib/misc.h new file mode 100644 index 00000000..29456590 --- /dev/null +++ b/converter/other/fiasco/lib/misc.h @@ -0,0 +1,98 @@ +/* + * misc.h + * + * Written by: Stefan Frank + * 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:49:37 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#ifndef _MISC_H +#define _MISC_H + +#include "config.h" + +#if TIME_WITH_SYS_TIME +# include <sys/time.h> +# include <time.h> +#else /* not TIME_WITH_SYS_TIME */ +# if HAVE_SYS_TIME_H +# include <sys/time.h> +# else /* not HAVE_SYS_TIME_H */ +# include <time.h> +# endif /* not HAVE_SYS_TIME_H */ +#endif /* not TIME_WITH_SYS_TIME */ + +#include <stdio.h> +#include "types.h" +#include "bit-io.h" + +enum action_e {START, STOP}; + +void * +Calloc (size_t n, size_t size); +void +Free (void *memory); +unsigned +prg_timer (clock_t *ptimer, enum action_e action); +int +read_int(FILE *infile); +real_t +read_real(FILE *infile); +unsigned +read_rice_code (unsigned rice_k, bitfile_t *input); +void +write_rice_code (unsigned value, unsigned rice_k, bitfile_t *output); +void +write_bin_code (unsigned value, unsigned maxval, bitfile_t *output); +unsigned +bits_bin_code (unsigned value, unsigned maxval); +unsigned +bits_rice_code (unsigned value, unsigned rice_k); +unsigned +read_bin_code (unsigned maxval, bitfile_t *input); +unsigned * +init_clipping (void); +real_t +variance (const word_t *pixels, unsigned x0, unsigned y0, + unsigned width, unsigned height, unsigned cols); + +#ifndef HAVE_MEMMOVE +void * +memmove(void *dest, const void *src, size_t n); +#endif /* not HAVE_MEMMOVE */ + +double +Log2 (double x); +#ifndef HAVE_STRDUP +char * +strdup (const char *s); +#endif +#ifndef HAVE_STRCASECMP +bool_t +strcaseeq (const char *s1, const char *s2); +#else /* HAVE_STRCASECMP */ +int +strcasecmp (const char *s1, const char *s2); +#define strcaseeq(s1, s2) (strcasecmp ((s1), (s2)) == 0) +#endif /* HAVE_STRCASECMP */ + +int +sort_asc_word (const void *value1, const void *value2); +int +sort_desc_word (const void *value1, const void *value2); +int +sort_asc_pair (const void *value1, const void *value2); +int +sort_desc_pair (const void *value1, const void *value2); + +#endif /* not _MISC_H */ + diff --git a/converter/other/fiasco/lib/mvcode.c b/converter/other/fiasco/lib/mvcode.c new file mode 100644 index 00000000..d9ce91e2 --- /dev/null +++ b/converter/other/fiasco/lib/mvcode.c @@ -0,0 +1,14 @@ +#include "mvcode.h" + +unsigned mv_code_table [33][2] = +/* + * MPEG's huffman code for vector components. Format: code_value, length + */ +{ + {0x19, 11}, {0x1b, 11}, {0x1d, 11}, {0x1f, 11}, {0x21, 11}, {0x23, 11}, + {0x13, 10}, {0x15, 10}, {0x17, 10}, {0x7, 8}, {0x9, 8}, {0xb, 8}, {0x7, 7}, + {0x3, 5}, {0x3, 4}, {0x3, 3}, {0x1, 1}, {0x2, 3}, {0x2, 4}, {0x2, 5}, + {0x6, 7}, {0xa, 8}, {0x8, 8}, {0x6, 8}, {0x16, 10}, {0x14, 10}, {0x12, 10}, + {0x22, 11}, {0x20, 11}, {0x1e, 11}, {0x1c, 11}, {0x1a, 11}, {0x18, 11} +}; + diff --git a/converter/other/fiasco/lib/mvcode.h b/converter/other/fiasco/lib/mvcode.h new file mode 100644 index 00000000..f43f2081 --- /dev/null +++ b/converter/other/fiasco/lib/mvcode.h @@ -0,0 +1,6 @@ +#ifndef MVCODE_H_INCLUDED +#define MVCODE_H_INCLUDED + +extern unsigned mv_code_table [33][2]; + +#endif diff --git a/converter/other/fiasco/lib/rpf.c b/converter/other/fiasco/lib/rpf.c new file mode 100644 index 00000000..ac7d48ca --- /dev/null +++ b/converter/other/fiasco/lib/rpf.c @@ -0,0 +1,223 @@ +/* + * rpf.c: Conversion of float to reduced precision format values + * + * Written by: Stefan Frank + * Richard Krampfl + * 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:49:37 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#include "config.h" + +#include "types.h" +#include "macros.h" +#include "error.h" + +#include "misc.h" +#include "rpf.h" + +/* + * CAUTION: The IEEE float format must be used by your compiler, + * or all following code is void! + */ + +#ifdef WORDS_BIGENDIAN +/* + * Big-Endian Architecture (e.g. SUN, Motorola) + * Memory representation of integer 0x00112233 is 00,11,22,33 + */ + +enum real_bytes {BYTE_0, BYTE_1, BYTE_2, BYTE_3}; + +#else /* not WORDS_BIGENDIAN */ +/* + * Little-Endian Architecture (e.g. Intel, VAX, Alpha) + * Memory representation of integer 0x00112233 is 33,22,11,00 + */ + +enum real_bytes {BYTE_3, BYTE_2, BYTE_1, BYTE_0}; + +#endif /* not WORDS_BIGENDIAN */ + +const int RPF_ZERO = -1; + +/***************************************************************************** + + private code + +*****************************************************************************/ + +int +rtob (real_t f, const rpf_t *rpf) +/* + * Convert real number 'f' into fixed point format. + * The real number in [-'range'; +'range'] is scaled to [-1 ; +1]. + * Sign and the first 'precision' - 1 bits of the mantissa are + * packed into one integer. + * + * Return value: + * real value in reduced precision format + */ +{ + unsigned int mantissa; + int exponent, sign; + union + { + float f; + unsigned char c[4]; + } v; /* conversion dummy */ + + f /= rpf->range; /* scale f to [-1,+1] */ + v.f = f; + + /* + * Extract mantissa (23 Bits), exponent (8 Bits) and sign (1 Bit) + */ + + mantissa = ((((v.c[BYTE_1] & 127) << 8 ) | v.c[BYTE_2]) << 8) | v.c[BYTE_3]; + exponent = (((v.c[BYTE_0] & 127) << 1) | (v.c[BYTE_1] & 128 ? 1 : 0)) - 126; + sign = v.c[BYTE_0] & 128 ? 1 : 0; + + /* + * Generate reduced precision mantissa. + */ + mantissa >>= 1; /* shift 1 into from left */ + mantissa |= (1 << 22); + if (exponent > 0) + mantissa <<= exponent; + else + mantissa >>= -exponent; + + mantissa >>= (23 - rpf->mantissa_bits - 1); + + mantissa += 1; /* Round last bit. */ + mantissa >>= 1; + + if (mantissa == 0) /* close to zero */ + return RPF_ZERO; + else if (mantissa >= (1U << rpf->mantissa_bits)) /* overflow */ + return sign; + else + return ((mantissa & ((1U << rpf->mantissa_bits) - 1)) << 1) | sign; +} + +float +btor (int binary, const rpf_t *rpf) +/* + * Convert value 'binary' in reduced precision format to a real value. + * For more information refer to function lin_rtob() above. + * + * Return value: + * converted value + */ +{ + unsigned int mantissa; + int sign, exponent; + union + { + float f; + unsigned char c[4]; + } value; + + if (binary == RPF_ZERO) + return 0; + + if (binary < 0 || binary >= 1 << (rpf->mantissa_bits + 1)) + error ("Reduced precision format: value %d out of range.", binary); + + /* + * Restore IEEE float format: + * mantissa (23 Bits), exponent (8 Bits) and sign (1 Bit) + */ + + sign = binary & 1; + mantissa = (binary & ((1 << (rpf->mantissa_bits + 1)) - 1)) >> 1; + mantissa <<= (23 - rpf->mantissa_bits); + exponent = 0; + + if (mantissa == 0) + { + value.f = (sign ? -1.0 : 1.0); + } + else + { + while (!(mantissa & (1 << 22))) /* normalize mantissa */ + { + exponent--; + mantissa <<= 1; + } + mantissa <<= 1; + + value.c[BYTE_0] = (sign << 7) | ((exponent + 126) >> 1); + value.c[BYTE_1] = (((exponent + 126) & 1) << 7) + | ((mantissa >> 16) & 127); + value.c[BYTE_2] = (mantissa >> 8) & 255; + value.c[BYTE_3] = mantissa & 255; + } + + return value.f * rpf->range; /* expand [ -1 ; +1 ] to + [ -range ; +range ] */ +} + +rpf_t * +alloc_rpf (unsigned mantissa, fiasco_rpf_range_e range) +/* + * Reduced precision format constructor. + * Allocate memory for the rpf_t structure. + * Number of mantissa bits is given by `mantissa'. + * The range of the real values is in the interval [-`range', +`range']. + * In case of invalid parameters, a structure with default values is + * returned. + * + * Return value + * pointer to the new rpf structure + */ +{ + rpf_t *rpf = Calloc (1, sizeof (rpf_t)); + + if (mantissa < 2) + { + warning (_("Size of RPF mantissa has to be in the interval [2,8]. " + "Using minimum value 2.\n")); + mantissa = 2; + } + else if (mantissa > 8) + { + warning (_("Size of RPF mantissa has to be in the interval [2,8]. " + "Using maximum value 8.\n")); + mantissa = 2; + } + + rpf->mantissa_bits = mantissa; + rpf->range_e = range; + switch (range) + { + case FIASCO_RPF_RANGE_0_75: + rpf->range = 0.75; + break; + case FIASCO_RPF_RANGE_1_50: + rpf->range = 1.50; + break; + case FIASCO_RPF_RANGE_2_00: + rpf->range = 2.00; + break; + case FIASCO_RPF_RANGE_1_00: + rpf->range = 1.00; + break; + default: + warning (_("Invalid RPF range specified. Using default value 1.0.")); + rpf->range = 1.00; + rpf->range_e = FIASCO_RPF_RANGE_1_00; + break; + } + return rpf; +} diff --git a/converter/other/fiasco/lib/rpf.h b/converter/other/fiasco/lib/rpf.h new file mode 100644 index 00000000..ba3ff6be --- /dev/null +++ b/converter/other/fiasco/lib/rpf.h @@ -0,0 +1,47 @@ +/* + * rpf.h + * + * Written by: Stefan Frank + * Richard Krampfl + * 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:49:37 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#ifndef _RPF_H +#define _RPF_H + +#include "types.h" +#include "fiasco.h" + +typedef struct rpf +{ + unsigned mantissa_bits; /* number of bits used for mantissa */ + real_t range; /* scale value to [-range, +range] */ + fiasco_rpf_range_e range_e; +} rpf_t; + +int +rtob (real_t real, const rpf_t *rpf); +real_t +btor (int b, const rpf_t *rpf); +rpf_t * +alloc_rpf (unsigned mantissa, fiasco_rpf_range_e range); + +extern const int RPF_ZERO; + +#endif /* not _RPF_H */ + + + + + + diff --git a/converter/other/fiasco/lib/types.h b/converter/other/fiasco/lib/types.h new file mode 100644 index 00000000..16d8028c --- /dev/null +++ b/converter/other/fiasco/lib/types.h @@ -0,0 +1,38 @@ +/* + * types.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:49:37 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#ifndef _FIASCO_TYPES_H +#define _FIASCO_TYPES_H + +#undef FALSE +#undef NO +#undef TRUE +#undef YES + +enum fiasco_boolean { NO = 0, FALSE = 0, YES = 1, TRUE = 1}; + +typedef float real_t; +typedef enum fiasco_boolean bool_t; +typedef unsigned char byte_t; +typedef short word_t; +typedef unsigned short u_word_t; +typedef struct pair +{ + word_t key; + word_t value; +} pair_t; + +#endif diff --git a/converter/other/fiasco/output/Makefile b/converter/other/fiasco/output/Makefile new file mode 100644 index 00000000..3bdc4635 --- /dev/null +++ b/converter/other/fiasco/output/Makefile @@ -0,0 +1,26 @@ +ifeq ($(SRCDIR)x,x) + SRCDIR = $(CURDIR)/../../../.. + BUILDDIR = $(SRCDIR) +endif +FIASCOSUBDIR = converter/other/fiasco +SUBDIR = $(FIASCOSUBDIR)/output +VPATH=.:$(SRCDIR)/$(SUBDIR) + +include $(BUILDDIR)/Makefile.config + +OBJECTS = matrices.o mc.o nd.o tree.o weights.o write.o + +MERGE_OBJECTS = $(OBJECTS) + +INCLUDES = -I$(SRCDIR)/$(FIASCOSUBDIR) \ + -I$(SRCDIR)/$(FIASCOSUBDIR)/lib \ + -I$(SRCDIR)/$(FIASCOSUBDIR)/codec + +all: libfiasco_output.a + +include $(SRCDIR)/Makefile.common + +libfiasco_output.a: $(OBJECTS) + $(AR) -rc $@ $(OBJECTS) + $(RANLIB) $@ + diff --git a/converter/other/fiasco/output/matrices.c b/converter/other/fiasco/output/matrices.c new file mode 100644 index 00000000..fd8d31e2 --- /dev/null +++ b/converter/other/fiasco/output/matrices.c @@ -0,0 +1,547 @@ +/* + * matrices.c: Output of transitions matrices + * + * 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> + */ + +/* NETPBM: When you call delta_encoding() with last_domain < 4, it + crashes. And we have seen it happen. +*/ + +/* + * $Date: 2000/06/14 20:50:31 $ + * $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 "wfa.h" +#include "bit-io.h" +#include "arith.h" +#include "misc.h" +#include "wfalib.h" + +#include "matrices.h" + +/***************************************************************************** + + prototypes + +*****************************************************************************/ + +static unsigned +delta_encoding (bool_t use_normal_domains, bool_t use_delta_domains, + const wfa_t *wfa, unsigned last_domain, bitfile_t *output); +static unsigned +column_0_encoding (const wfa_t *wfa, unsigned last_row, bitfile_t *output); +static unsigned +chroma_encoding (const wfa_t *wfa, bitfile_t *output); + +/***************************************************************************** + + public code + +*****************************************************************************/ + +unsigned +write_matrices (bool_t use_normal_domains, bool_t use_delta_domains, + const wfa_t *wfa, bitfile_t *output) +/* + * Write transition matrices of 'wfa' to stream 'output'. + * + * Return value: + * number of transitions encoded + */ +{ + unsigned root_state; /* root of luminance */ + unsigned total = 0; /* number of transitions */ + + root_state = wfa->wfainfo->color + ? wfa->tree [wfa->tree [wfa->root_state][0]][0] + : wfa->root_state; + + total = column_0_encoding (wfa, root_state, output); + + total += delta_encoding (use_normal_domains, use_delta_domains, + wfa, root_state, output); + + if (wfa->wfainfo->color) + total += chroma_encoding (wfa, output); + + return total; +} + +/***************************************************************************** + + private code + +*****************************************************************************/ + +static unsigned +delta_encoding (bool_t use_normal_domains, bool_t use_delta_domains, + const wfa_t *wfa, unsigned last_domain, bitfile_t *output) +/* + * Write transition matrices with delta coding to stream 'input'. + * 'last_domain' is the maximum state number used as domain image. + * + * Return value: + * number of non-zero matrix elements (WFA edges) + */ +{ + range_sort_t rs; /* ranges are sorted as in the coder */ + unsigned max_domain; /* dummy used for recursion */ + unsigned total = 0; + + /* + * Generate a list of range blocks. + * The order is the same as in the coder. + */ + rs.range_state = Calloc ((last_domain + 1) * MAXLABELS, + sizeof (u_word_t)); + rs.range_label = Calloc ((last_domain + 1) * MAXLABELS, + sizeof (byte_t)); + rs.range_max_domain = Calloc ((last_domain + 1) * MAXLABELS, + sizeof (u_word_t)); + rs.range_subdivided = Calloc ((last_domain + 1) * MAXLABELS, + sizeof (bool_t)); + rs.range_no = 0; + max_domain = wfa->basis_states - 1; + sort_ranges (last_domain, &max_domain, &rs, wfa); + + /* + * Compute and write distribution of #edges + */ + { + unsigned state, label; + unsigned edge; + unsigned count [MAXEDGES + 1]; + unsigned n; + unsigned edges = 0; + unsigned M = 0; + unsigned bits = bits_processed (output); + + for (n = 0; n < MAXEDGES + 1; n++) + count [n] = 0; + + for (state = wfa->basis_states; state <= last_domain; state++) + for (label = 0; label < MAXLABELS; label++) + if (isrange (wfa->tree [state][label])) + { + for (edge = 0; isedge (wfa->into [state][label][edge]); edge++) + ; + count [edge]++; + edges++; + M = max (edge, M); + } + write_rice_code (M, 3, output); + for (n = 0; n <= M; n++) +/* NETPBM: The following causes a crash when last_domain < 4, because + it requests writing of a negative number of bits. And we have seen + last_domain = 3. But we have no clue what last_domain means, or + even what a rice code is, so we don't know where the error lies. + -Bryan 2001.02.09 +*/ + write_rice_code (count [n], (int) log2 (last_domain) - 2, output); + + /* + * Arithmetic coding of values */ + { + unsigned range; + model_t *elements = alloc_model (M + 1, 0, 0, count); + arith_t *encoder = alloc_encoder (output); + + for (range = 0; range < rs.range_no; range++) + if (!rs.range_subdivided [range]) + { + state = rs.range_state [range]; + label = rs.range_label [range]; + for (edge = 0; isedge (wfa->into [state][label][edge]); edge++) + ; + + encode_symbol (edge, encoder, elements); + } + free_encoder (encoder); + free_model (elements); + } + debug_message ("delta-#edges: %5d bits. (%5d symbols => %5.2f bps)", + bits_processed (output) - bits, edges, + edges > 0 ? ((bits_processed (output) - bits) / + (double) edges) : 0); + } + + /* + * Write matrix elements + */ + { + unsigned bits = bits_processed (output); + u_word_t *mapping1 = Calloc (wfa->states, sizeof (u_word_t)); + u_word_t *mapping2 = Calloc (wfa->states, sizeof (u_word_t)); + unsigned range; + + put_bit (output, use_normal_domains); + put_bit (output, use_delta_domains); + + /* + * Generate array of states which are admitted domains. + * When coding intra frames 'mapping1' == 'mapping2' otherwise + * 'mapping1' is a list of 'normal' domains which are admitted for + * coding intra blocks + * 'mapping2' is a list of 'delta' domains which are admitted for + * coding the motion compensated prediction error + */ + { + unsigned n1, n2, state; + + for (n1 = n2 = state = 0; state < wfa->states; state++) + { + mapping1 [state] = n1; + if (usedomain (state, wfa) + && (state < wfa->basis_states || use_delta_domains + || !wfa->delta_state [state])) + n1++; + + mapping2 [state] = n2; + if (usedomain (state, wfa) + && (state < wfa->basis_states || use_normal_domains + || wfa->delta_state [state])) + n2++; + } + debug_message ("# normal states = %d, # delta states = %d," + " # WFA states = %d", n1, n2, wfa->states); + } + + for (range = 0; range < rs.range_no; range++) + if (!rs.range_subdivided [range]) + { + unsigned state = rs.range_state [range]; + unsigned label = rs.range_label [range]; + unsigned last = 1; + u_word_t *mapping; + unsigned max_value; + unsigned edge; + word_t domain; + + if (wfa->delta_state [state] || + wfa->mv_tree [state][label].type != NONE) + mapping = mapping2; + else + mapping = mapping1; + + max_value = mapping [rs.range_max_domain [range]]; + + for (edge = 0; isedge (domain = wfa->into [state][label][edge]); + edge++) + if (domain > 0) + { + total++; + if (max_value - last) + { + write_bin_code (mapping [domain] - last, + max_value - last, output); + last = mapping [domain] + 1; + } + } + } + + debug_message ("delta-index: %5d bits. (%5d symbols => %5.2f bps)", + bits_processed (output) - bits, total, + total > 0 ? ((bits_processed (output) - bits) / + (double) total) : 0); + Free (mapping1); + Free (mapping2); + } + + Free (rs.range_state); + Free (rs.range_label); + Free (rs.range_max_domain); + Free (rs.range_subdivided); + + return total; +} + +static unsigned +column_0_encoding (const wfa_t *wfa, unsigned last_row, bitfile_t *output) +/* + * Write column 0 of the transition matrices of the 'wfa' to stream 'output' + * with quasi arithmetic coding. + * All rows from 'wfa->basis_states' up to 'last_row' are decoded. + * + * Return value: + * number of non-zero matrix elements (WFA edges) + */ +{ + u_word_t high; /* Start of the current code range */ + u_word_t low; /* End of the current code range */ + unsigned *prob; /* probability array */ + unsigned row; /* current matrix row */ + unsigned label; /* current matrix label */ + unsigned underflow; /* Underflow bits */ + unsigned index; /* probability index */ + unsigned total = 0; /* Number of '1' elements */ + unsigned bits = bits_processed (output); + + /* + * Compute the probability array: + * prob[] = { 1/2, 1/2, 1/4, 1/4, 1/4, 1/4, + * 1/8, ... , 1/16, ..., 1/(MAXPROB+1)} + */ + { + unsigned n; + unsigned exp; /* current exponent */ + + prob = Calloc (1 << (MAX_PROB + 1), sizeof (unsigned)); + + for (index = 0, n = MIN_PROB; n <= MAX_PROB; n++) + for (exp = 0; exp < 1U << n; exp++, index++) + prob [index] = n; + } + + high = HIGH; /* 1.0 */ + low = LOW; /* 0.0 */ + underflow = 0; /* no underflow bits */ + + index = 0; + + /* + * Encode column 0 with a quasi arithmetic coder (QAC). + * Advantage of this QAC with respect to a binary AC: + * Instead of using time consuming multiplications and divisions + * to compute the probability of the most probable symbol (MPS) and + * the range of the interval, a table look up procedure linked + * with a shift operation is used for both computations. + */ + for (row = wfa->basis_states; row <= last_row; row++) + for (label = 0; label < MAXLABELS; label++) + if (isrange (wfa->tree [row][label])) + { + if (wfa->into [row][label][0] != 0) + { + /* + * encode the MPS '0' + */ + high = high - ((high - low) >> prob [index]) - 1; + RESCALE_OUTPUT_INTERVAL; + + if (index < 1020) + index++; + } + else + { + /* + * encode the LPS '1' + */ + low = high - ((high - low) >> prob [index]); + + RESCALE_OUTPUT_INTERVAL; + + total++; + index >>= 1; + } + } + /* + * Flush the quasi-arithmetic encoder + */ + low = high; + + RESCALE_OUTPUT_INTERVAL; + + OUTPUT_BYTE_ALIGN (output); + + Free (prob); + + debug_message ("delta-state0: %5d bits. (%5d symbols => %5.2f bps)", + bits_processed (output) - bits, total, + total > 0 ? ((bits_processed (output) - bits) / + (double) total) : 0); + + return total; +} + +static unsigned +chroma_encoding (const wfa_t *wfa, bitfile_t *output) +/* + * Write transition matrices of 'wfa' states which are part of the + * chroma channels Cb and Cr to stream 'output'. + * + * Return value: + * number of non-zero matrix elements (WFA edges) + */ +{ + + unsigned domain; /* current domain, counter */ + unsigned label; /* current label */ + unsigned total = 0; /* number of '1' elements */ + u_word_t high; /* Start of the current code range */ + u_word_t low; /* End of the current code range */ + unsigned underflow; /* underflow bits */ + unsigned *prob; /* probability array */ + unsigned index; /* probability index, counter */ + unsigned next_index; /* probability of last domain */ + unsigned row; /* current matrix row */ + word_t *y_domains; + unsigned count = 0; /* number of transitions for part 1 */ + unsigned bits = bits_processed (output); + + /* + * Compute the asymmetric probability array + * prob[] = { 1/2, 1/2, 1/4, 1/4, 1/4, 1/4, + * 1/8, ... , 1/16, ..., 1/(MAXPROB+1)} + */ + { + unsigned n; + unsigned exp; /* current exponent */ + + prob = Calloc (1 << (MAX_PROB + 1), sizeof (unsigned)); + + for (index = 0, n = MIN_PROB; n <= MAX_PROB; n++) + for (exp = 0; exp < 1U << n; exp++, index++) + prob [index] = n; + } + + high = HIGH; /* 1.0 */ + low = LOW; /* 0.0 */ + underflow = 0; /* no underflow bits */ + + next_index = index = 0; + + y_domains = compute_hits (wfa->basis_states, + wfa->tree [wfa->tree [wfa->root_state][0]][0], + wfa->wfainfo->chroma_max_states, wfa); + + /* + * First of all, read all matrix columns given in the list 'y_domains' + * which note all admitted domains. + * These matrix elements are stored with QAC (see column_0_encoding ()). + */ + for (domain = 0; y_domains [domain] != -1; domain++) + { + bool_t save_index = YES; /* YES: store current prob. index */ + + row = wfa->tree [wfa->tree [wfa->root_state][0]][0] + 1; + index = next_index; + + for (; row < wfa->states; row++) + { + for (label = 0; label < MAXLABELS; label++) + if (isrange (wfa->tree [row][label])) + { + unsigned edge; + int into; + bool_t match; /* approx with current domain found */ + + for (match = NO, edge = 0; + isedge (into = wfa->into [row][label][edge]) + && (unsigned) into < row; + edge++) + if (into == y_domains [domain] + && into != wfa->y_state [row][label]) + match = YES; + if (!match) + { + /* + * encode the MPS '0' + */ + high = high - ((high - low) >> prob [index]) - 1; + + RESCALE_OUTPUT_INTERVAL; + + if (index < 1020) + index++; + } + else + { + /* + * encode the LPS '1' + */ + low = high - ((high - low) >> prob [index]); + + RESCALE_OUTPUT_INTERVAL; + + total++; + index >>= 1; + } + } + if (save_index) + { + next_index = index; + save_index = NO; + } + } + } + + debug_message ("CbCr_matrix: %5d bits. (%5d symbols => %5.2f bps)", + bits_processed (output) - bits, total, + total > 0 ? ((bits_processed (output) - bits) / + (double) total) : 0); + count = total; + bits = bits_processed (output); + + /* + * Encode the additional column which indicates whether there + * are transitions to a state with same spatial coordinates + * in the Y component. + * + * Again, quasi arithmetic coding is used for this task. + */ + + next_index = index = 0; + + for (row = wfa->tree [wfa->tree [wfa->root_state][0]][0] + 1; + row < wfa->states; row++) + for (label = 0; label < MAXLABELS; label++) + if (!wfa->y_column [row][label]) + { + /* + * encode the MPS '0' + */ + high = high - ((high - low) >> prob [index]) - 1; + + RESCALE_OUTPUT_INTERVAL; + + if (index < 1020) + index++; + } + else + { + /* + * encode the LPS '1' + */ + low = high - ((high - low) >> prob [index]); + + RESCALE_OUTPUT_INTERVAL; + + index >>= 1; + total++; + } + + /* + * Flush the quasi-arithmetic encoder + */ + low = high; + + RESCALE_OUTPUT_INTERVAL; + OUTPUT_BYTE_ALIGN (output); + + debug_message ("Yreferences: %5d bits. (%5d symbols => %5.2f bps)", + bits_processed (output) - bits, total - count, + total - count > 0 ? ((bits_processed (output) - bits) / + (double) (total - count)) : 0); + + Free (prob); + Free (y_domains); + + return total; +} diff --git a/converter/other/fiasco/output/matrices.h b/converter/other/fiasco/output/matrices.h new file mode 100644 index 00000000..f880fef8 --- /dev/null +++ b/converter/other/fiasco/output/matrices.h @@ -0,0 +1,28 @@ +/* + * matrices.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:31 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#ifndef _MATRICES_H +#define _MATRICES_H + +#include "wfa.h" +#include "bit-io.h" + +unsigned +write_matrices (bool_t use_normal_domains, bool_t use_delta_domains, + const wfa_t *wfa, bitfile_t *output); + +#endif /* _MATRICES_H */ + diff --git a/converter/other/fiasco/output/mc.c b/converter/other/fiasco/output/mc.c new file mode 100644 index 00000000..afff586b --- /dev/null +++ b/converter/other/fiasco/output/mc.c @@ -0,0 +1,250 @@ +/* + * mc.c: Output of motion compensation + * + * 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:31 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#include "config.h" + +#include "types.h" +#include "macros.h" +#include "error.h" + +#include "wfa.h" +#include "bit-io.h" +#include "mvcode.h" + +#include "mc.h" + +/***************************************************************************** + + local variables + +*****************************************************************************/ + +static unsigned p_frame_codes [4][2] = +/* + * Code values and bits for P-frame prediction + * NONE, FORWARD + */ +{ + {1, 1}, {0, 1}, {0, 0}, {0, 0} +}; + +static unsigned b_frame_codes [4][2] = +/* + * Code values and bits for B-frame prediction + * NONE, FORWARD, BACKWARD, INTERPOLATED + */ +{ + {1, 1}, {000, 3}, {001, 3}, {01, 2} +}; + +enum vlc_e {CODE = 0, BITS = 1}; + +/***************************************************************************** + + prototypes + +*****************************************************************************/ + +static void +encode_mc_tree (unsigned max_state, frame_type_e frame_type, const wfa_t *wfa, + bitfile_t *output); +static void +encode_mc_coords (unsigned max_state, const wfa_t *wfa, bitfile_t *output); + +/***************************************************************************** + + public code + +*****************************************************************************/ + +void +write_mc (frame_type_e frame_type, const wfa_t *wfa, bitfile_t *output) +{ + unsigned max_state = wfa->wfainfo->color + ? wfa->tree[wfa->tree[wfa->root_state][0]][0] + : wfa->states; + + encode_mc_tree (max_state, frame_type, wfa, output); + encode_mc_coords (max_state, wfa, output); +} + +/***************************************************************************** + + private code + +*****************************************************************************/ + +static void +encode_mc_tree (unsigned max_state, frame_type_e frame_type, const wfa_t *wfa, + bitfile_t *output) +/* + * Write tree of motion compensation decisions to the 'output' stream. + * Depending on 'frame_type' different decoding methods are used. + * 'max_state' is the last state with motion compensation infos. + * + * No return value. + */ +{ + unsigned label; /* current label */ + unsigned state; /* current state */ + unsigned total = 0; /* number of motion tree decisions */ + unsigned queue [MAXSTATES]; /* state numbers in BFO */ + unsigned current; /* current node to process */ + unsigned last; /* last node (update every new node) */ + mc_type_e type; /* type of motion compensation */ + unsigned (*mc_tree_codes)[2]; /* pointer to VLC table */ + unsigned bits = bits_processed (output); /* number of bits used */ + + if (frame_type == P_FRAME) + mc_tree_codes = p_frame_codes; /* binary code */ + else + mc_tree_codes = b_frame_codes; /* variable length code */ + + /* + * Traverse tree in breadth first order (starting at + * level 'wfa->p_max_level'). Use a queue to store the childs + * of each node ('last' is the next free queue element). + */ + + for (last = 0, state = wfa->basis_states; state < max_state; state++) + if (wfa->level_of_state [state] - 1 == (int) wfa->wfainfo->p_max_level) + queue [last++] = state; /* init level = 'mc_max_level' */ + + for (current = 0; current < last; current++) + for (label = 0; label < MAXLABELS; label++) + { + state = queue [current]; + type = wfa->mv_tree [state][label].type; + if (wfa->x [state][label] + + width_of_level (wfa->level_of_state [state] - 1) + <= wfa->wfainfo->width + && + wfa->y [state][label] + + height_of_level (wfa->level_of_state [state] - 1) + <= wfa->wfainfo->height) + { + put_bits (output, mc_tree_codes [type][CODE], + mc_tree_codes [type][BITS]); + total++; + } + if (type == NONE && !isrange (wfa->tree [state][label]) && + wfa->level_of_state [state] - 1 >= + (int) wfa->wfainfo->p_min_level) + queue [last++] = wfa->tree [state][label]; /* append child */ + + } + + OUTPUT_BYTE_ALIGN (output); + debug_message ("mc-tree: %5d bits. (%5d symbols => %5.2f bps)", + bits_processed (output) - bits, total, + total > 0 ? ((bits_processed (output) - bits) / + (double) total) : 0); +} + +static void +encode_mc_coords (unsigned max_state, const wfa_t *wfa, bitfile_t *output) +/* + * Write motion vector coordinates to the 'output' stream. They are stored + * with the static Huffman code of the MPEG and H.263 standards. + * 'max_state' is the last state with motion compensation infos. + * + * No return value. + */ +{ + unsigned state; /* current state */ + unsigned label; /* current label */ + unsigned level_count [MAXLEVEL]; /* number of mv per level */ + unsigned level; /* counter */ + unsigned ftotal = 0; /* #forward motion tree decisions */ + unsigned btotal = 0; /* #backward decisions */ + unsigned itotal = 0; /* #interpolated decisions */ + unsigned bits = bits_processed (output); /* number of bits used */ + unsigned sr = wfa->wfainfo->search_range; /* search range */ + + for (level = wfa->wfainfo->p_max_level; + level >= wfa->wfainfo->p_min_level; level--) + level_count [level] = 0; + + for (state = wfa->basis_states; state < max_state; state++) + for (label = 0; label < MAXLABELS; label++) + { + mv_t *mv = &wfa->mv_tree[state][label]; /* motion vector info */ + + if (mv->type != NONE) + { + level_count [wfa->level_of_state [state] - 1]++; + switch (mv->type) + { + case FORWARD: + put_bits (output, + mv_code_table[(mv->fx + sr)][CODE], + mv_code_table[(mv->fx + sr)][BITS]); + put_bits (output, + mv_code_table[(mv->fy + sr)][CODE], + mv_code_table[(mv->fy + sr)][BITS]); + ftotal++; + break; + case BACKWARD: + put_bits (output, + mv_code_table[(mv->bx + sr)][CODE], + mv_code_table[(mv->bx + sr)][BITS]); + put_bits (output, + mv_code_table[(mv->by + sr)][CODE], + mv_code_table[(mv->by + sr)][BITS]); + btotal++; + break; + case INTERPOLATED: + put_bits (output, + mv_code_table[(mv->fx + sr)][CODE], + mv_code_table[(mv->fx + sr)][BITS]); + put_bits (output, + mv_code_table[(mv->fy + sr)][CODE], + mv_code_table[(mv->fy + sr)][BITS]); + put_bits (output, + mv_code_table[(mv->bx + sr)][CODE], + mv_code_table[(mv->bx + sr)][BITS]); + put_bits (output, + mv_code_table[(mv->by + sr)][CODE], + mv_code_table[(mv->by + sr)][BITS]); + itotal++; + break; + default: + break; + } + } + } + + OUTPUT_BYTE_ALIGN (output); + + debug_message ("Motion compensation: %d forward, %d backward, " + "%d interpolated", ftotal, btotal, itotal); + + for (level = wfa->wfainfo->p_max_level; + level >= wfa->wfainfo->p_min_level; level--) + debug_message ("Level %d: %d motion vectors", level, level_count[level]); + + { + unsigned total = ftotal * 2 + btotal * 2 + itotal * 4; + + debug_message ("mv-coord: %5d bits. (%5d symbols => %5.2f bps)", + bits_processed (output) - bits, total, + total > 0 ? ((bits_processed (output) - bits) / + (double) total) : 0); + } + + return; +} diff --git a/converter/other/fiasco/output/mc.h b/converter/other/fiasco/output/mc.h new file mode 100644 index 00000000..b7843fd8 --- /dev/null +++ b/converter/other/fiasco/output/mc.h @@ -0,0 +1,28 @@ +/* + * mc.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:31 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#ifndef _MC_H +#define _MC_H + +#include "wfa.h" +#include "bit-io.h" + +void +write_mc (frame_type_e frame_type, const wfa_t *wfa, bitfile_t *output); + +#endif /* not _MC_H */ + diff --git a/converter/other/fiasco/output/nd.c b/converter/other/fiasco/output/nd.c new file mode 100644 index 00000000..a09ff762 --- /dev/null +++ b/converter/other/fiasco/output/nd.c @@ -0,0 +1,244 @@ +/* + * nd.c: Output of prediction 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:31 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#include "config.h" + +#include "types.h" +#include "macros.h" +#include "error.h" + +#include "wfa.h" +#include "arith.h" +#include "misc.h" +#include "bit-io.h" +#include "rpf.h" +#include "list.h" + +#include "nd.h" + +/***************************************************************************** + + prototypes + +*****************************************************************************/ + +static unsigned +encode_nd_tree (const wfa_t *wfa, bitfile_t *output); +static void +encode_nd_coefficients (unsigned total, const wfa_t *wfa, bitfile_t *output); + +/***************************************************************************** + + public code + +*****************************************************************************/ + +void +write_nd (const wfa_t *wfa, bitfile_t *output) +/* + * Write prediction information of 'wfa' to given stream 'output'. + * Coefficients are quantized with model 'p_rpf'. + * + * No return value. + */ +{ + unsigned total = encode_nd_tree (wfa, output); + + if (total > 0) + encode_nd_coefficients (total, wfa, output); +} + +/***************************************************************************** + + private code + +*****************************************************************************/ + +static unsigned +encode_nd_tree (const wfa_t *wfa, bitfile_t *output) +/* + * Write prediction tree of 'wfa' to given stream 'output'. + * + * No return value. + */ +{ + lqueue_t *queue; /* queue of states */ + int state, next; /* state and its current child */ + unsigned used, not_used; /* counter ND used/not used */ + u_word_t low; /* Start of the current code range */ + u_word_t high; /* End of the current code range */ + u_word_t underflow; /* Number of underflow bits pending */ + u_word_t sum0, sum1; /* Probability model */ + unsigned bits = bits_processed (output); + + used = not_used = 0; + + /* + * Initialize arithmetic coder + */ + low = 0; + high = 0xffff; + underflow = 0; + sum0 = 1; + sum1 = 11; + + queue = alloc_queue (sizeof (int)); + state = wfa->root_state; + queue_append (queue, &state); + + /* + * Traverse the WFA tree in breadth first order (using a queue). + */ + while (queue_remove (queue, &next)) + { + unsigned label; + + if (wfa->level_of_state [next] > wfa->wfainfo->p_max_level + 1) + { + /* + * Nondetermismn is not allowed at levels larger than + * 'wfa->wfainfo->p_max_level'. + */ + for (label = 0; label < MAXLABELS; label++) + if (ischild (state = wfa->tree [next][label])) + queue_append (queue, &state); /* continue with childs */ + } + else if (wfa->level_of_state [next] > wfa->wfainfo->p_min_level) + { + for (label = 0; label < MAXLABELS; label++) + if (ischild (state = wfa->tree [next][label])) + { + unsigned range; /* Current interval range */ + + if (isedge (wfa->into [next][label][0])) /* prediction used */ + { + used++; + + /* + * Encode a '1' symbol + */ + range = (high - low) + 1; + low = low + (u_word_t) ((range * sum0) / sum1); + RESCALE_OUTPUT_INTERVAL; + } + else /* no predict., continue with childs */ + { + not_used++; + if (wfa->level_of_state [state] > wfa->wfainfo->p_min_level) + queue_append (queue, &state); + + /* + * Encode a '0' symbol + */ + range = (high - low) + 1; + high = low + (u_word_t) ((range * sum0) / sum1 - 1); + RESCALE_OUTPUT_INTERVAL; + sum0++; + } + /* + * Update the frequency counts + */ + sum1++; + if (sum1 > 50) /* Scale the symbol frequencies */ + { + sum0 >>= 1; + sum1 >>= 1; + if (!sum0) + sum0 = 1; + if (sum0 >= sum1) + sum1 = sum0 + 1; + } + } + + } + } + free_queue (queue); + + /* + * Flush the quasi-arithmetic encoder + */ + low = high; + RESCALE_OUTPUT_INTERVAL; + OUTPUT_BYTE_ALIGN (output); + + debug_message ("%d nd fields: %d used nd, %d used not nd", used + not_used, + used, not_used); + { + unsigned total = used + not_used; + + debug_message ("nd-tree: %5d bits. (%5d symbols => %5.2f bps)", + bits_processed (output) - bits, total, + total > 0 ? ((bits_processed (output) - bits) / + (double) total) : 0); + } + + return used; +} + +static void +encode_nd_coefficients (unsigned total, const wfa_t *wfa, bitfile_t *output) +/* + * Write #'total' weights of nondeterministic part of 'wfa' to given 'output' + * stream. Coefficients are stored with arithmetic coding (the model is + * given by 'p_rpf'). + * + * No return value. + */ +{ + unsigned bits = bits_processed (output); + + { + unsigned *coefficients; /* array of factors to encode */ + unsigned *ptr; /* pointer to current factor */ + unsigned state, label, edge; + word_t domain; + + ptr = coefficients = Calloc (total, sizeof (unsigned)); + + for (state = wfa->basis_states; state < wfa->states; state++) + for (label = 0; label < MAXLABELS; label++) + if (ischild (wfa->tree [state][label]) + && isedge (wfa->into [state][label][0])) + for (edge = 0; isedge (domain = wfa->into [state][label][edge]); + edge++) + { + if (ptr - coefficients >= (int) total) + error ("Can't write more than %d coefficients.", total); + + *ptr++ = rtob (wfa->weight [state][label][edge], + wfa->wfainfo->dc_rpf); + } + + /* + * Encode array of coefficients with arithmetic coding + */ + { + const int scaling = 50; /* scaling factor of prob. model */ + unsigned c_symbols = 1 << (wfa->wfainfo->dc_rpf->mantissa_bits + 1); + + encode_array (output, coefficients, NULL, &c_symbols, 1, + total, scaling); + } + + debug_message ("nd-factors: %5d bits. (%5d symbols => %5.2f bps)", + bits_processed (output) - bits, total, + total ? ((bits_processed (output) - bits) + / (double) total) : 0); + Free (coefficients); + } +} + + diff --git a/converter/other/fiasco/output/nd.h b/converter/other/fiasco/output/nd.h new file mode 100644 index 00000000..600b3d73 --- /dev/null +++ b/converter/other/fiasco/output/nd.h @@ -0,0 +1,27 @@ +/* + * nd.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:31 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#ifndef _ND_H +#define _ND_H + +#include "wfa.h" +#include "bit-io.h" + +void +write_nd (const wfa_t *wfa, bitfile_t *output); + +#endif /* not _ND_H */ + diff --git a/converter/other/fiasco/output/tree.c b/converter/other/fiasco/output/tree.c new file mode 100644 index 00000000..0056d7dd --- /dev/null +++ b/converter/other/fiasco/output/tree.c @@ -0,0 +1,176 @@ +/* + * tree.c: Output of bintree partitioning + * + * 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:31 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#include "config.h" + +#include "types.h" +#include "macros.h" +#include "error.h" + +#include "wfa.h" +#include "bit-io.h" +#include "arith.h" +#include "misc.h" + +#include "tree.h" + +/***************************************************************************** + + prototypes + +*****************************************************************************/ + +static void +encode_tree (bitfile_t *output, const byte_t *data, unsigned n_data, + unsigned scaling, u_word_t sum0, u_word_t sum1); + +/***************************************************************************** + + public code + +*****************************************************************************/ + +void +write_tree (const wfa_t *wfa, bitfile_t *output) +/* + * Write bintree to stream 'output'. + * Traverse tree in breadth first order and save a '1' for each child + * and a '0' for each range image. + * + * No return value. + */ +{ + unsigned queue [MAXSTATES]; /* state numbers in BFO */ + unsigned current; /* current node to process */ + unsigned last; /* last node (update every new node) */ + unsigned label; /* current label */ + int into; /* next child */ + byte_t *tree_string; /* bitstring to encode */ + unsigned total = 0; /* number of ranges */ + unsigned bits = bits_processed (output); /* number of bits */ + + /* + * Traverse tree in breadth first order. Use a queue to store + * the childs of each node ('last' is the next free queue element). + * The first element ('current') of this queue will get the new parent + * node. + */ + tree_string = Calloc (MAXSTATES * MAXLABELS, sizeof (byte_t)); + queue [0] = wfa->root_state; + for (last = 1, current = 0; current < last; current++) + for (label = 0; label < MAXLABELS; label++) + if (!isrange (into = wfa->tree [queue[current]][label])) /* child ? */ + { + queue [last++] = into; + tree_string [total++] = 1; + } + else /* or range ? */ + tree_string [total++] = 0; + + if (total != (wfa->states - wfa->basis_states) * MAXLABELS) + error ("total [%d] != (states - basis_states) * 2 [%d]", total, + (wfa->states - wfa->basis_states) * MAXLABELS); + + { + unsigned scale = total / 20 ; + + encode_tree (output, tree_string, total, scale, 1, 11); + } + + Free (tree_string); + + debug_message ("tree: %5d bits. (%5d symbols => %5.2f bps)", + bits_processed (output) - bits, total, + total > 0 ? ((bits_processed (output) - bits) + / (double) total) : 0); +} + +/***************************************************************************** + + private code + +*****************************************************************************/ + +static void +encode_tree (bitfile_t *output, const byte_t *data, unsigned n_data, + unsigned scaling, u_word_t sum0, u_word_t sum1) +/* + * Encode bintree data with adaptive binary arithmetic coding. + * Write 'n_data' output symbols stored in 'data' to stream 'output'. + * Rescale probability model after every 'scaling' symbols. + * Initial counts are given by 'sum0' and 'sum1'. + * + * No return value. + */ +{ + u_word_t low; /* Start of the current code range */ + u_word_t high; /* End of the current code range */ + u_word_t underflow; /* Number of underflow bits pending */ + unsigned n; /* Data counter */ + + low = 0; + high = 0xffff; + underflow = 0; + + for (n = n_data; n; n--) + { + unsigned range; /* Current interval range */ + + if (!*data++) + { + /* + * encode a '0' + */ + range = (high - low) + 1; + high = low + (u_word_t) ((range * sum0) / sum1 - 1); + + RESCALE_OUTPUT_INTERVAL; + + sum0++; + } + else + { + /* + * encode a '1' + */ + range = (high - low) + 1; + low = low + (u_word_t) ((range * sum0) / sum1); + + RESCALE_OUTPUT_INTERVAL; + } + /* + * Update the frequency counts + */ + sum1++; + if (sum1 > scaling) /* Scale the symbol frequencies */ + { + sum0 >>= 1; + sum1 >>= 1; + if (!sum0) + sum0 = 1; + if (sum0 >= sum1) + sum1 = sum0 + 1; + } + } + /* + * Flush the quasi-arithmetic encoder + */ + low = high; + + RESCALE_OUTPUT_INTERVAL; + + OUTPUT_BYTE_ALIGN (output); +} diff --git a/converter/other/fiasco/output/tree.h b/converter/other/fiasco/output/tree.h new file mode 100644 index 00000000..6f8a3800 --- /dev/null +++ b/converter/other/fiasco/output/tree.h @@ -0,0 +1,27 @@ +/* + * tree.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:31 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#ifndef _TREE_H +#define _TREE_H + +#include "wfa.h" +#include "bit-io.h" + +void +write_tree (const wfa_t *wfa, bitfile_t *output); + +#endif /* not _TREE_H */ + diff --git a/converter/other/fiasco/output/weights.c b/converter/other/fiasco/output/weights.c new file mode 100644 index 00000000..085a1f00 --- /dev/null +++ b/converter/other/fiasco/output/weights.c @@ -0,0 +1,200 @@ +/* + * weights.c: Output of weights + * + * 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:31 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#include "config.h" + +#include "types.h" +#include "macros.h" +#include "error.h" + +#include "wfa.h" +#include "misc.h" +#include "bit-io.h" +#include "arith.h" +#include "wfalib.h" + +#include "weights.h" + +/***************************************************************************** + + public code + +*****************************************************************************/ + +void +write_weights (unsigned total, const wfa_t *wfa, bitfile_t *output) +/* + * Traverse the transition matrices of the 'wfa' and write #'total' + * weights != 0 to stream 'output'. + * + * No return value. + */ +{ + unsigned state, label; /* current label */ + unsigned offset1, offset2; /* model offsets. */ + unsigned offset3, offset4; /* model offsets. */ + unsigned *weights_array; /* array of weights to encode */ + unsigned *wptr; /* pointer to current weight */ + unsigned *level_array; /* array of corresponding levels */ + unsigned *lptr; /* pointer to current corr. level */ + int min_level, max_level; /* min and max range level */ + int d_min_level, d_max_level; /* min and max delta range level */ + bool_t dc, d_dc; /* true if dc or delta dc are used */ + bool_t delta_approx = NO; /* true if delta has been used */ + unsigned delta_count = 0; /* number of delta ranges */ + unsigned bits = bits_processed (output); + + /* + * Check whether delta approximation has been used + */ + for (state = wfa->basis_states; state < wfa->states; state++) + if (wfa->delta_state [state]) + { + delta_approx = YES; + break; + } + + /* + * Generate array of corresponding levels (context of probability model) + */ + min_level = d_min_level = MAXLEVEL; + max_level = d_max_level = 0; + dc = d_dc = NO; + + for (state = wfa->basis_states; state < wfa->states; state++) + for (label = 0; label < MAXLABELS; label++) + if (isrange (wfa->tree [state][label])) + { + if (delta_approx && wfa->delta_state [state]) /* delta approx. */ + { + d_min_level = min (d_min_level, + wfa->level_of_state [state] - 1); + d_max_level = max (d_max_level, + wfa->level_of_state [state] - 1); + if (wfa->into [state][label][0] == 0) + d_dc = YES; + } + else + { + min_level = min (min_level, wfa->level_of_state [state] - 1); + max_level = max (max_level, wfa->level_of_state [state] - 1); + if (wfa->into [state][label][0] == 0) + dc = YES; + } + } + if (min_level > max_level) /* no lc found */ + max_level = min_level - 1; + if (d_min_level > d_max_level) + d_max_level = d_min_level - 1; + + /* + * Context model: + * 0 DC weight + * 1 Delta DC weight + * 2-k normal weights per level + * k+1 - m Delta weights per level + */ + + offset1 = dc ? 1 : 0; + offset2 = offset1 + (d_dc ? 1 : 0); + offset3 = offset2 + (max_level - min_level + 1); + offset4 = offset3 + (d_max_level - d_min_level + 1); + + /* + * Weights are encoded as follows: + * all weights of state n + * sorted by label + * sorted by domain number + */ + + wptr = weights_array = Calloc (total, sizeof (unsigned)); + lptr = level_array = Calloc (total, sizeof (unsigned)); + + for (state = wfa->basis_states; state < wfa->states; state++) + for (label = 0; label < MAXLABELS; label++) + if (isrange (wfa->tree [state][label])) + { + int edge; /* current edge */ + int domain; /* current domain (context of model) */ + + for (edge = 0; isedge (domain = wfa->into [state][label][edge]); + edge++) + { + if (wptr - weights_array >= (int) total) + error ("Can't write more than %d weights.", total); + if (domain) /* not DC component */ + { + if (delta_approx && wfa->delta_state [state]) /* delta */ + { + *wptr++ = rtob (wfa->weight [state][label][edge], + wfa->wfainfo->d_rpf); + *lptr++ = offset3 + + wfa->level_of_state [state] - 1 - d_min_level; + delta_count++; + } + else + { + *wptr++ = rtob (wfa->weight [state][label][edge], + wfa->wfainfo->rpf); + *lptr++ = offset2 + + wfa->level_of_state [state] - 1 - min_level; + } + } + else /* DC component */ + { + if (delta_approx && wfa->delta_state [state]) /* delta */ + { + *wptr++ = rtob (wfa->weight [state][label][edge], + wfa->wfainfo->d_dc_rpf); + *lptr++ = offset1; + } + else + { + *wptr++ = rtob (wfa->weight [state][label][edge], + wfa->wfainfo->dc_rpf); + *lptr++ = 0; + } + } + } + } + + { + unsigned i; + unsigned *c_symbols = Calloc (offset4, sizeof (int)); + const int scale = 500; /* scaling of probability model */ + + c_symbols [0] = 1 << (wfa->wfainfo->dc_rpf->mantissa_bits + 1); + if (offset1 != offset2) + c_symbols [offset1] = 1 << (wfa->wfainfo->d_dc_rpf->mantissa_bits + + 1); + for (i = offset2; i < offset3; i++) + c_symbols [i] = 1 << (wfa->wfainfo->rpf->mantissa_bits + 1); + for (; i < offset4; i++) + c_symbols [i] = 1 << (wfa->wfainfo->d_rpf->mantissa_bits + 1); + + encode_array (output, weights_array, level_array, c_symbols, offset4, + total, scale); + Free (c_symbols); + } + + debug_message ("%d delta weights out of %d.", delta_count, total); + debug_message ("weights: %5d bits. (%5d symbols => %5.2f bps)", + bits_processed (output) - bits, total, + (bits_processed (output) - bits) / (double) total); + + Free (weights_array); + Free (level_array); +} diff --git a/converter/other/fiasco/output/weights.h b/converter/other/fiasco/output/weights.h new file mode 100644 index 00000000..271203ad --- /dev/null +++ b/converter/other/fiasco/output/weights.h @@ -0,0 +1,27 @@ +/* + * weights.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:31 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#ifndef _WEIGHTS_H +#define _WEIGHTS_H + +#include "wfa.h" +#include "bit-io.h" + +void +write_weights (unsigned total, const wfa_t *wfa, bitfile_t *output); + +#endif /* not _WEIGHTS_H */ + diff --git a/converter/other/fiasco/output/write.c b/converter/other/fiasco/output/write.c new file mode 100644 index 00000000..e6185ad3 --- /dev/null +++ b/converter/other/fiasco/output/write.c @@ -0,0 +1,250 @@ +/* + * write.c: Output of WFA files + * + * 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:59 $ + * $Author: hafner $ + * $Revision: 5.3 $ + * $State: Exp $ + */ + +#include "config.h" + +#include "types.h" +#include "macros.h" +#include "error.h" + +#include "cwfa.h" +#include "image.h" +#include "misc.h" +#include "bit-io.h" +#include "rpf.h" + +#include "tree.h" +#include "matrices.h" +#include "weights.h" +#include "mc.h" +#include "nd.h" +#include "write.h" + +/***************************************************************************** + + prototypes + +*****************************************************************************/ + +static void +write_tiling (const tiling_t *tiling, bitfile_t *output); + +/***************************************************************************** + + public code + + +*****************************************************************************/ + + +void +write_next_wfa (const wfa_t *wfa, const coding_t *c, bitfile_t *output) +/* + * Write 'wfa' to stream 'output'. If the first frame should be written + * then also store the header information of the coding struct 'c'. + * + * No return value. + */ +{ + unsigned edges = 0; /* number of transitions */ + unsigned bits; + + debug_message ("--------------------------------------" + "--------------------------------------"); + + if (c->mt->number == 0) /* first WFA */ + write_header (wfa->wfainfo, output); + + bits = bits_processed (output); + + /* + * Frame header information + */ + { + const int rice_k = 8; /* parameter of Rice Code */ + + write_rice_code (wfa->states, rice_k, output); + write_rice_code (c->mt->frame_type, rice_k, output); + write_rice_code (c->mt->number, rice_k, output); + } + + OUTPUT_BYTE_ALIGN (output); + + debug_message ("frame-header: %5d bits.", bits_processed (output) - bits); + + if (c->tiling->exponent) /* write tiling permutation */ + { + put_bit (output, 1); + write_tiling (c->tiling, output); + } + else + put_bit (output, 0); + + OUTPUT_BYTE_ALIGN (output); + + write_tree (wfa, output); + + if (c->options.prediction) /* write nondeterministic approx. */ + { + put_bit (output, 1); + write_nd (wfa, output); + } + else + put_bit (output, 0); + + if (c->mt->frame_type != I_FRAME) /* write motion compensation info */ + write_mc (c->mt->frame_type, wfa, output); + + edges = write_matrices (c->options.normal_domains, + c->options.delta_domains, wfa, output); + + if (edges) /* found at least one approximation */ + write_weights (edges, wfa, output); + + debug_message ("--------------------------------------" + "--------------------------------------"); +} + +void +write_header (const wfa_info_t *wi, bitfile_t *output) +/* + * Write the header information describing the type of 'wfa' + * to stream 'output'. + * + * No return value. + */ +{ + const unsigned rice_k = 8; /* parameter of Rice Code */ + unsigned bits = bits_processed (output); + const char *text; /* next character to write */ + + /* + * Write magic number and name of initial basis + */ + for (text = FIASCO_MAGIC; *text; text++) + put_bits (output, *text, 8); + put_bits (output, '\n', 8); + for (text = wi->basis_name; *text; text++) + put_bits (output, *text, 8); + put_bits (output, *text, 8); + + write_rice_code (FIASCO_BINFILE_RELEASE, rice_k, output); + + write_rice_code (HEADER_TITLE, rice_k, output); + for (text = wi->title; + text && *text && text - wi->title < MAXSTRLEN - 2; + text++) + put_bits (output, *text, 8); + put_bits (output, 0, 8); + + write_rice_code (HEADER_COMMENT, rice_k, output); + for (text = wi->comment; + text && *text && text - wi->comment < MAXSTRLEN - 2; + text++) + put_bits (output, *text, 8); + put_bits (output, 0, 8); + + write_rice_code (HEADER_END, rice_k, output); + + write_rice_code (wi->max_states, rice_k, output); + put_bit (output, wi->color ? 1 : 0); + write_rice_code (wi->width, rice_k, output); + write_rice_code (wi->height, rice_k, output); + if (wi->color) + write_rice_code (wi->chroma_max_states, rice_k, output); + write_rice_code (wi->p_min_level, rice_k, output); + write_rice_code (wi->p_max_level, rice_k, output); + write_rice_code (wi->frames, rice_k, output); + write_rice_code (wi->smoothing, rice_k, output); + + put_bits (output, wi->rpf->mantissa_bits - 2, 3); + put_bits (output, wi->rpf->range_e, 2); + if (wi->rpf->mantissa_bits != wi->dc_rpf->mantissa_bits || + wi->rpf->range != wi->dc_rpf->range) + { + put_bit (output, YES); + put_bits (output, wi->dc_rpf->mantissa_bits - 2, 3); + put_bits (output, wi->dc_rpf->range_e, 2); + } + else + put_bit (output, NO); + if (wi->rpf->mantissa_bits != wi->d_rpf->mantissa_bits || + wi->rpf->range != wi->d_rpf->range) + { + put_bit (output, YES); + put_bits (output, wi->d_rpf->mantissa_bits - 2, 3); + put_bits (output, wi->d_rpf->range_e, 2); + } + else + put_bit (output, NO); + if (wi->dc_rpf->mantissa_bits != wi->d_dc_rpf->mantissa_bits || + wi->dc_rpf->range != wi->d_dc_rpf->range) + { + put_bit (output, YES); + put_bits (output, wi->d_dc_rpf->mantissa_bits - 2, 3); + put_bits (output, wi->d_dc_rpf->range_e, 2); + } + else + put_bit (output, NO); + + if (wi->frames > 1) /* motion compensation stuff */ + { + write_rice_code (wi->fps, rice_k, output); + write_rice_code (wi->search_range, rice_k, output); + put_bit (output, wi->half_pixel ? 1 : 0); + put_bit (output, wi->B_as_past_ref ? 1 : 0); + } + + OUTPUT_BYTE_ALIGN (output); + debug_message ("header: %d bits.", bits_processed (output) - bits); +} + +/***************************************************************************** + + private code + +*****************************************************************************/ + +static void +write_tiling (const tiling_t *tiling, bitfile_t *output) +/* + * Write image tiling information given by 'tiling' to stream 'output'. + * + * No return value. + */ +{ + const unsigned rice_k = 8; /* parameter of Rice Code */ + unsigned bits = bits_processed (output); + + write_rice_code (tiling->exponent, rice_k, output); + if (tiling->method == FIASCO_TILING_VARIANCE_ASC + || tiling->method == FIASCO_TILING_VARIANCE_DSC) + { + unsigned tile; /* current image tile */ + + put_bit (output, 1); + for (tile = 0; tile < 1U << tiling->exponent; tile++) + if (tiling->vorder [tile] != -1) /* image tile is visible */ + put_bits (output, tiling->vorder [tile], tiling->exponent); + } + else + { + put_bit (output, 0); + put_bit (output, tiling->method == FIASCO_TILING_SPIRAL_ASC); + } + + debug_message ("tiling: %4d bits.", bits_processed (output) - bits); +} diff --git a/converter/other/fiasco/output/write.h b/converter/other/fiasco/output/write.h new file mode 100644 index 00000000..a3ede1f4 --- /dev/null +++ b/converter/other/fiasco/output/write.h @@ -0,0 +1,28 @@ +/* + * write.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 17:27:30 $ + * $Author: hafner $ + * $Revision: 5.2 $ + * $State: Exp $ + */ + +#ifndef _WRITE_H +#define _WRITE_H + +#include "cwfa.h" +#include "bit-io.h" + +void +write_next_wfa (const wfa_t *wfa, const coding_t *c, bitfile_t *output); +void +write_header (const wfa_info_t *wi, bitfile_t *output); + +#endif /* not _WRITE_H */ diff --git a/converter/other/fiasco/params.c b/converter/other/fiasco/params.c new file mode 100644 index 00000000..3d0a0252 --- /dev/null +++ b/converter/other/fiasco/params.c @@ -0,0 +1,727 @@ +/* + * params.c: Parameter file and command line parsing + * + * Written by: Stefan Frank + * 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:24:21 $ + * $Author: hafner $ + * $Revision: 5.2 $ + * $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 <stdio.h> +#include <ctype.h> +#include <math.h> /* strtod() on SUN sparc */ + +#include <stdlib.h> +#include <string.h> + +#include <getopt.h> /* system or ../lib */ + +#include "nstring.h" + +#include "types.h" +#include "macros.h" +#include "bit-io.h" +#include "misc.h" +#include "fiasco.h" + +#include "binerror.h" + +#include "params.h" + +/***************************************************************************** + + prototypes + +*****************************************************************************/ + +static void +read_parameter_file (param_t *params, FILE *file); +static int +get_parameter_index (const param_t *params, const char *search_string); +static void +set_parameter (param_t *parameter, const char *value); +static void +usage (const param_t *params, const char *progname, const char *synopsis, + const char *comment, const char *non_opt_string, + bool_t show_all_options, const char *sys_file_name, + const char *usr_file_name); + +/***************************************************************************** + + public code + +*****************************************************************************/ + +int +parseargs (param_t *usr_params, + int argc, char **argv, + const char *synopsis, + const char *comment, + const char *non_opt_string, + const char *path, + const char *sys_file_name, + const char *usr_file_name) +/* + * Perform the command line parsing. + * List of allowed parameters is given by 'usr_params'. + * Command line and number of parameters are given by 'argv' and 'argc'. + * 'synopsis' contains a brief description of the program and + * 'comment' may contain some additional advice. + * Initialization order of parameters: + * 1.) Default values given by the param_t struct + * 2.) System parameter-file ('path'/'sys_file_name') + * 3.) User parameter-file ($HOME/'usr_file_name') + * 4.) Command line parameters + * 5.) Parameter-file forced by option -f (--config-file) + * + * Return value: + * index in ARGV of the first ARGV-element that is not an option. + * + * Side effects: + * the elements of ARGV are permuted + * usr_params [].value is modified + */ +{ + extern int optind; /* index in ARGV of the 1st element + that is not an option */ + bool_t detailed_help = NO; /* NO if all parameters can be modified + with short options too */ + unsigned n1; /* number of user parameters */ + unsigned n2; /* number of system parameters */ + bool_t read_config_file = NO; /* will override command line */ + param_t *params; /* array of user and system params */ + param_t *sys_params; /* array of system parameters */ + param_t detailed_sys_params [] = /* detailed system parameters */ + { + {"version", NULL, 'v', PFLAG, {0}, NULL, + "Print program version number, then exit."}, + {"verbose", "NUM", 'V', PINT, {0}, "1", + "Set level of verbosity to `%s'."}, + {"config", "FILE", 'f', PSTR, {0}, NULL, + "Load `%s' to initialize parameters."}, + {"info", NULL, 'h', PFLAG, {0}, NULL, + "Print brief help, then exit."}, + {"help", NULL, 'H', PFLAG, {0}, NULL, + "Print detailed help, then exit."}, + {NULL, NULL, 0, PSTR, {0}, NULL, NULL } + }; + param_t short_sys_params [] = /* short system parameters */ + { + {"version", NULL, 'v', PFLAG, {0}, NULL, + "Print program version number, then exit."}, + {"verbose", "NUM", 'V', PINT, {0}, "1", + "Set level of verbosity to `%s'."}, + {"config", "FILE", 'f', PSTR, {0}, NULL, + "Load `%s' to initialize parameters."}, + {"help", NULL, 'h', PFLAG, {0}, NULL, + "Print this help, then exit."}, + {NULL, NULL, 0, PSTR, {0}, NULL, NULL } + }; + char *sys_path; /* path to system config file */ + + sys_path = calloc (strlen (path) + strlen (sys_file_name) + 2, + sizeof (char)); + if (!sys_path) + error ("Out of memory."); + sprintf (sys_path, "%s/%s", path, sys_file_name); + + /* + * Set parameters defaults + */ + { + param_t *p; + + for (p = usr_params; p->name != NULL; p++) + { + set_parameter (p, p->default_value); + if (p->optchar == '\0') + detailed_help = YES; + } + + sys_params = detailed_help ? detailed_sys_params : short_sys_params; + + for (p = sys_params; p->name != NULL; p++) + set_parameter (p, p->default_value); + } + /* + * Append system command line option to user parameters + */ + for (n1 = 0; usr_params [n1].name != NULL; n1++) + ; + for (n2 = 0; sys_params [n2].name != NULL; n2++) + ; + params = calloc (n1 + n2 + 1, sizeof (param_t)); + if (!params) + error ("Out of memory."); + + memcpy (params, usr_params, n1 * sizeof (param_t)); + memcpy (params + n1, sys_params, (n2 + 1) * sizeof (param_t)); + /* + * Try to open the system resource file 'path'/'sys_file_name' + */ + { + FILE *parameter_file = open_file (sys_path, NULL, READ_ACCESS); + if (parameter_file == NULL) +/* + warning ("No system resource file found."); +*/ {} + else + { + read_parameter_file (params, parameter_file); + fclose (parameter_file); + } + } + /* + * Try to read user resource file $HOME/'usr_file_name' + */ + { + FILE *parameter_file = open_file (usr_file_name, "HOME", READ_ACCESS); + if (parameter_file != NULL) + { + read_parameter_file (params, parameter_file); + fclose (parameter_file); + } + } + /* + * Parse command line options + */ + { + extern char *optarg; /* argument of current option */ + struct option *long_options; /* array of long options */ + int option_index = 0; + char optstr [MAXSTRLEN]; /* string containing the legitimate + option characters */ + int optchar; /* found option character */ + + /* + * Build short option string for getopt_long (). + */ + { + param_t *p; /* counter */ + char *ptr_optstr; /* pointer to position in string */ + + ptr_optstr = optstr; + for (p = params; p->name != NULL; p++) + if (p->optchar != '\0') + { + *ptr_optstr++ = p->optchar; + if (p->type == POSTR) + { + *ptr_optstr++ = ':'; + *ptr_optstr++ = ':'; + } + else if (p->type != PFLAG) + *ptr_optstr++ = ':'; + } + *ptr_optstr = '\0'; + } + + /* + * Build long option string for getopt_long (). + */ + { + int i; + + long_options = calloc (n1 + n2 + 1, sizeof (struct option)); + if (!long_options) + error ("Out of memory."); + for (i = 0; params [i].name != NULL; i++) + { + long_options [i].name = params [i].name; + switch (params [i].type) + { + case PFLAG: + long_options [i].has_arg = 0; + break; + case POSTR: + long_options [i].has_arg = 2; + break; + case PINT: + case PSTR: + case PFLOAT: + default: + long_options [i].has_arg = 1; + break; + } + long_options [i].has_arg = params [i].type != PFLAG; + long_options [i].flag = NULL; + long_options [i].val = 0; + } + } + + /* + * Parse comand line + */ + while ((optchar = getopt_long (argc, argv, optstr, long_options, + &option_index)) != EOF) + { + int param_index = -1; + + switch (optchar) + { + case 0: + param_index = option_index; + break; + case ':': + if (detailed_help) + fprintf (stderr, + "Try `%s -h' or `%s --help' for " + "more information.\n", + argv [0], argv [0]); + else + fprintf (stderr, "Try `%s --help' for more information.\n", + argv [0]); + exit (2); + break; + case '?': + if (detailed_help) + fprintf (stderr, + "Try `%s -h' or `%s --help' " + "for more information.\n", + argv [0], argv [0]); + else + fprintf (stderr, "Try `%s --help' for more information.\n", + argv [0]); + exit (2); + break; + default: + { + int i; + + for (i = 0; params [i].name != NULL; i++) + if (params [i].optchar == optchar) + { + param_index = i; + break; + } + } + } + /* + * Check for system options + */ + if (param_index >= 0) + { + set_parameter (params + param_index, optarg ? optarg : ""); + if (streq (params [param_index].name, "help")) + usage (params, argv [0], synopsis, comment, non_opt_string, + YES, sys_path, usr_file_name); + else if (streq (params [param_index].name, "info")) + usage (params, argv [0], synopsis, comment, non_opt_string, + NO, sys_path, usr_file_name); + else if (streq (params [param_index].name, "version")) + { + fprintf (stderr, "%s " VERSION "\n", argv [0]); + exit (2); + } + else if (streq (params [param_index].name, "verbose")) + fiasco_set_verbosity ( + * (fiasco_verbosity_e *) parameter_value (params, + "verbose")); + else if (streq (params [param_index].name, "config")) + read_config_file = YES; + param_index = -1; /* clear index flag */ + } + } + + free (long_options); + } + + /* + * Read config-file if specified by option -f + */ + if (read_config_file) + { + char *filename; + + if ((filename = (char *) parameter_value (params, "config")) != NULL) + { + FILE *parameter_file; /* input file */ + + warning ("Options set in file `%s' will override" + " command line options.", filename); + parameter_file = open_file (filename, NULL, READ_ACCESS); + if (parameter_file != NULL) + { + read_parameter_file (params, parameter_file); + fclose (parameter_file); + } + else + file_error (filename); + } + else + error ("Invalid config filename."); + } + + memcpy (usr_params, params, n1 * sizeof (param_t)); /* fill user struct */ + free (sys_path); + + return optind; +} + +void * +parameter_value (const param_t *params, const char *name) +/* + * Extract value of parameter 'name.' of the given parameters 'params'. + * + * Return value: + * value of given parameter + */ +{ + int pind = get_parameter_index (params, name); + + if (pind < 0) + error ("Invalid parameter `%s'.", name); + + if (params [pind].type == PSTR || params [pind].type == POSTR) + return (void *) params [pind].value.s; + + return (void *) &(params [pind].value); +} + +void +ask_and_set (param_t *params, const char *name, const char *msg) +/* + * Ask user (print given message 'msg') for missing mandatory + * parameter 'name' of the given parameters 'params'. + * + * No return value. + * + * Side effects: + * 'params ['name'].value' is changed + */ +{ + char answer [MAXSTRLEN]; + int index = get_parameter_index (params, name); + + if (index < 0) + error ("Invalid parameter %s.", name); + + if (msg) + fprintf (stderr, "%s\n", msg); + + switch (params [index].type) + { + case PFLAG: /* Unusual, at least. */ + warning ("Flags should be initialized and set on demand, " + "not request"); + case PINT: + case PSTR: + case POSTR: + case PFLOAT: + scanf (MAXSTRLEN_SCANF, answer); + set_parameter (¶ms [index], answer); + break; + default: + error ("Invalid parameter type for %s", name); + } +} + +void +write_parameters (const param_t *params, FILE *output) +/* + * Write all parameter settings to 'output'. + * + * No return value. + */ +{ + int pind; + + if (!params || !output) + error ("Parameters must be not NULL."); + + for (pind = 0; params [pind].name != NULL; pind++) + { + fprintf (output, "# %s = ", params [pind].name); + switch (params [pind].type) + { + case PFLAG: + fprintf (output, "%s\n", params [pind].value.b ? "TRUE" : "FALSE"); + break; + case PINT: + fprintf (output, "%d\n", params [pind].value.i); + break; + case PFLOAT: + fprintf (output, "%.4f\n", (double) params [pind].value.f); + break; + case PSTR: + case POSTR: + fprintf (output, "%s\n", params [pind].value.s); + break; + default: + error ("Invalid type %d for parameter %s", + params [pind].type, params [pind].name); + } + } + fputc ('\n', output); +} + +/***************************************************************************** + + private code + +*****************************************************************************/ + +static void +set_parameter (param_t *parameter, const char *value) +/* + * Set value of 'parameter' to 'value'. + * + * No return value. + * + * Side effects: + * 'parameter.value' is changed accordingly + */ +{ + assert (parameter); + + switch (parameter->type) + { + case PFLAG: + if (value != NULL && *value != '\0') + { + if (strcaseeq (value, "TRUE")) + parameter->value.b = YES; + else if (strcaseeq (value, "FALSE")) + parameter->value.b = NO; + else if (strcaseeq (value, "YES")) + parameter->value.b = YES; + else if (strcaseeq (value, "NO")) + parameter->value.b = NO; + else + { + long int data; + char *endptr; + + data = strtol (value, &endptr, 0); + if (*endptr != '\0' || endptr == value) + warning ("Invalid value `%s' converted to %d", + value, (int) data); + parameter->value.b = data ? YES : NO; + } + } + else + parameter->value.b = !parameter->value.b; + break; + case PINT: + { + long int data; + char *endptr; + + data = strtol (value, &endptr, 0); + if (*endptr != '\0' || endptr == value) + warning ("Invalid value `%s' converted to %d", + value, (int) data); + parameter->value.i = data; + } + break; + case PFLOAT: + { + double data; + char *endptr; + + data = strtod (value, &endptr); + if (*endptr != '\0' || endptr == value) + warning ("Invalid value `%s' converted to %f", + value, (double) data); + parameter->value.f = data; + } + break; + case PSTR: + case POSTR: + parameter->value.s = value ? strdup (value) : NULL; + break; + default: + error ("Invalid parameter type for %s", parameter->name); + } +} + +static int +get_parameter_index (const param_t *params, const char *search_string) +/* + * Search for parameter with name 'search_string' in parameter struct. + * + * Return value: + * index of parameter or -1 if no matching parameter has been found + */ +{ + int n; + int index = -1; + + assert (params && search_string); + + for (n = 0; params [n].name != NULL; n++) + if (strcaseeq (params [n].name, search_string)) + { + index = n; + break; + } + + return index; +} + +static void +read_parameter_file (param_t *params, FILE *file) +/* + * Read parameter settings from 'file'. + * + * No return value. + * + * Side effects: + * 'params [].value' are changed if specified in 'file' + */ +{ + char buffer [MAXSTRLEN]; + int n = 0; + + assert (params && file); + + while (fgets (buffer, MAXSTRLEN, file) != NULL) + { + char *b; /* temporary variable */ + char *name; /* parameter name */ + char *value; /* parameter value */ + int pind; /* current argument number */ + + b = strchr (buffer, '#'); + if (b != NULL) /* Strip comments. */ + *b = '\0'; + + b = strchr (buffer, '='); + if (b == NULL) /* Strip lines that contain no '=' */ + continue; + *b = '\0'; /* Replace '=' by string terminator */ + + /* + * Extract value of parameter + */ + for (value = b + 1; ISSPACE (*value); value++) + ; /* Delete leading spaces */ + + for (b = value + strlen (value) - 1; b >= value && ISSPACE (*b); b--) + *b = '\0'; /* Delete trailing spaces. */ + + /* + * Extract parameter name + */ + for (name = buffer; ISSPACE (*name); name++) + ; /* Delete leading spaces */ + + for (b = name + strlen (name) - 1; b >= name && ISSPACE (*b); b--) + *b = '\0'; /* Delete trailing spaces. */ + + pind = get_parameter_index (params, name); + if (pind >= 0) + set_parameter (¶ms [pind], value); + + n++; + } +} + +static void +usage (const param_t *params, const char *progname, const char *synopsis, + const char *comment, const char *non_opt_string, + bool_t show_all_options, const char *sys_file_name, + const char *usr_file_name) +/* + * Generates and prints command line description from param_t struct 'params'. + * 'progname' is the name of the excecutable, 'synopsis' a short program + * description, and 'comment' some more advice. + * If flag 'show_all_options' is set then print also options that are not + * associated with a short option character. + * 'sys_file_name' and 'usr_file_name' are filenames to parameter files. + * + * No return value. + */ +{ + int i; + size_t width = 0; + + fprintf (stderr, "Usage: %s [OPTION]...%s\n", progname, + non_opt_string ? non_opt_string : " "); + if (synopsis != NULL) + fprintf (stderr, synopsis); + fprintf (stderr, "\n\n"); + fprintf (stderr, "Mandatory or optional arguments to long options " + "are mandatory or optional\nfor short options too. " + "Default values are surrounded by {}.\n"); + for (i = 0; params [i].name != NULL; i++) + if (params [i].optchar != '\0' || show_all_options) + { + if (params [i].type == POSTR) + width = max (width, (strlen (params [i].name) + + strlen (params [i].argument_name) + 2)); + else if (params [i].type != PFLAG) + width = max (width, (strlen (params [i].name) + + strlen (params [i].argument_name))); + else + width = max (width, (strlen (params [i].name)) - 1); + } + + for (i = 0; params [i].name != NULL; i++) + if (params [i].optchar != '\0' || show_all_options) + { + if (params [i].optchar != '\0') + fprintf (stderr, " -%c, --", params [i].optchar); + else + fprintf (stderr, " --"); + + if (params [i].type == POSTR) + fprintf (stderr, "%s=[%s]%-*s ", params [i].name, + params [i].argument_name, + max (0, (width - 2 - strlen (params [i].name) + - strlen (params [i].argument_name))), ""); + else if (params [i].type != PFLAG) + fprintf (stderr, "%s=%-*s ", params [i].name, + width - strlen (params [i].name), + params [i].argument_name); + else + fprintf (stderr, "%-*s ", width + 1, params [i].name); + + fprintf (stderr, params [i].use, params [i].argument_name); + + switch (params [i].type) + { + case PFLAG: + break; + case PINT: + fprintf (stderr, "{%d}", params [i].value.i); + break; + case PFLOAT: + fprintf (stderr, "{%.2f}", (double) params [i].value.f); + break; + case PSTR: + case POSTR: + if (params [i].value.s) + fprintf (stderr, "{%s}", params [i].value.s); + break; + default: + error ("type %d for %s invalid", + params [i].type, params [i].name); + } + fprintf (stderr, "\n"); + } + fprintf (stderr, "\n"); + fprintf (stderr, "Parameter initialization order:\n"); + fprintf (stderr, + "1.) %s\n2.) $HOME/%s\t 3.) command line\t 4.) --config=file", + sys_file_name, usr_file_name); + fprintf (stderr, "\n\n"); + if (comment != NULL) + fprintf (stderr, "%s\n", comment); + + exit (1); +} + diff --git a/converter/other/fiasco/params.h b/converter/other/fiasco/params.h new file mode 100644 index 00000000..810a9ff0 --- /dev/null +++ b/converter/other/fiasco/params.h @@ -0,0 +1,61 @@ +/* + * params.h + * + * Written by: Stefan Frank + * 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:51:17 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#ifndef PARAMS_H +#define PARAMS_H + +#include <stdio.h> + +typedef union pdata_t /* Allow for different */ +{ /* parameter types. */ + int b; + int i; + float f; + char *s; +} pdata_t; + +typedef enum {PFLAG = 1, PINT, PFLOAT, PSTR, POSTR} param_e; + +typedef struct param_t +{ + const char *name; /* Parameter name */ + const char *argument_name; /* Argument name */ + char optchar; /* Corresponding command line switch */ + param_e type; /* Parameter type */ + pdata_t value; /* Parameter value */ + const char *default_value; /* Parameters default value */ + const char *use; /* One line usage. Must contain %s, + which will be replaced by 'name'. */ +} param_t; + +int +parseargs (param_t *usr_params, + int argc, char **argv, + const char *synopsis, + const char *comment, + const char *non_opt_string, + const char *path, + const char *sys_file_name, + const char *usr_file_name); +void +write_parameters (const param_t *params, FILE *output); +void +ask_and_set (param_t *params, const char *name, const char *msg); +void * +parameter_value (const param_t *params, const char *name); + +#endif /* not PARAMS_H */ diff --git a/converter/other/fiasco/pnmtofiasco.c b/converter/other/fiasco/pnmtofiasco.c new file mode 100644 index 00000000..2218256d --- /dev/null +++ b/converter/other/fiasco/pnmtofiasco.c @@ -0,0 +1,411 @@ +/* + * cwfa.c: FIASCO coder + * + * 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:29 $ + * $Author: hafner $ + * $Revision: 5.4 $ + * $State: Exp $ + */ + +#include "config.h" +#include "pnm.h" + +#if STDC_HEADERS +# include <stdlib.h> +# include <string.h> +#else /* not STDC_HEADERS */ +# if HAVE_STRING_H +# include <string.h> +# else /* not HAVE_STRING_H */ +# include <strings.h> +# endif /* not HAVE_STRING_H */ +#endif /* not STDC_HEADERS */ + +#include "types.h" +#include "macros.h" + +#include "binerror.h" +#include "misc.h" +#include "params.h" +#include "fiasco.h" + +/***************************************************************************** + + local variables + +*****************************************************************************/ + +static param_t params [] = +{ + /* + * Options for standard user + */ + {"image-name", "FILE", 'i', PSTR, {0}, NULL, + "Compress raw PPM/PGM image(s) `%s'."}, + {"output-name", "FILE", 'o', PSTR, {0}, "-", + "Write automaton to `%s' (`-' means stdout)."}, + {"quality", "REAL", 'q', PFLOAT, {0}, "20.0", + "Set quality of compression to `%s'."}, + {"title", "NAME", 't', PSTR, {0}, "", + "Set title of FIASCO stream to `%s'."}, + {"comment", "NAME", 'c', PSTR, {0}, "", + "Set comment of FIASCO stream to `%s'."}, + {"chroma-qfactor", "REAL", '\0', PFLOAT, {0}, "2", + "Decrease chroma band quality `%s' times."}, + {"basis-name", "FILE", '\0', PSTR, {0}, "small.fco", + "Preload basis `%s' into FIASCO."}, + {"optimize", "NUM", 'z', PINT, {0}, "0", + "Set optimization level to `%s'."}, + {"dictionary-size", "NUM", '\0', PINT, {0}, "10000", + "Set max# size of dictionary to `%s'."}, + {"chroma-dictionary", "NUM", '\0', PINT, {0}, "40", + "Set max# size of chroma dictionary to `%s'.."}, + {"min-level", "NUM", '\0', PINT, {0}, "6", + "Start prediction on block level `%s'."}, + {"max-level", "NUM", '\0', PINT, {0}, "10", + "Stop prediction on block level `%s'."}, + {"tiling-exponent", "NUM", '\0', PINT, {0}, "4", + "Set exponent of image permutation to `%s'."}, + {"tiling-method", "NAME", '\0', PSTR, {0}, "desc-variance", + "Set type of permutation to `%s'."}, + {"rpf-range", "REAL", '\0', PFLOAT, {0}, "1.5", + "Set quantization range to `%s'."}, + {"rpf-mantissa", "NUM", '\0', PINT, {0}, "3", + "Set quantization mantissa to `%s' bits."}, + {"dc-rpf-range", "REAL", '\0', PFLOAT, {0}, "1", + "Set quant. range (DC part) to `%s'."}, + {"dc-rpf-mantissa", "NUM", '\0', PINT, {0}, "5", + "Set quant. mantissa (DC part) to `%s' bits."}, + {"pattern", "NAME", '\0', PSTR, {0}, "ippppppppp", + "Set frame type sequence to `%s'."}, + {"fps", "NUM", '\0', PINT, {0}, "25", + "Set display rate to `%s' frames per second."}, + {"half-pixel", NULL, '\0', PFLAG, {0}, "FALSE", + "Use half-pixel precision for mc."}, + {"cross-B-search", NULL, '\0', PFLAG, {0}, "FALSE", + "Use cross-B-search for interpolated mc."}, + {"B-as-past-ref", NULL, '\0', PFLAG, {0}, "FALSE", + "Use B-frames as reference images." }, + {"prediction", NULL, '\0', PFLAG, {0}, "FALSE", + "Use additional predictive coding."}, + {"progress-meter", "NUM", '\0', PINT, {0}, "2", + "Set type of progress meter to `%s'."}, + {"smooth", "NUM", '\0', PINT, {0}, "70", + "Smooth image(s) by factor `%s' (0-100)"}, +#if 0 + /* + * Options currently not activated (maybe in future versions of FIASCO) + */ + {"min-level", "NUM", 'm', PINT, {0}, "4", + "Start compression on block level `%s'."}, + {"max-level", "NUM", 'M', PINT, {0}, "12", + "Stop compression on block level `%s'."}, + {"max-elements", "NUM", 'N', PINT, {0}, "8", + "Set max# of elements in an approx. to `%s'." }, + {"domain-pool", "NAME", '\0', PSTR, {0}, "rle", + "Set domain pool of r-lc to `%s'."}, + {"coeff", "NAME", '\0', PSTR, {0}, "adaptive", + "Set coefficients model to `%s'."}, + /* DELTA APPROXIATION */ + {"d-domain-pool", "NAME", '\0', PSTR, {0}, "rle", + "Set domain pool of d-lc to `%s'."}, + {"d-coeff", "NAME", '\0', PSTR, {0}, "adaptive", + "Set d coefficients model to `%s'."}, + {"d-range", "REAL", '\0', PFLOAT, {0}, "1.5", + "Set range of RPF for delta lc to `%s'."}, + {"d-mantissa", "NUM", '\0', PINT, {0}, "3", + "Set #m-bits of RPF for delta lc to `%s'."}, + {"d-dc-range", "REAL", '\0', PFLOAT, {0}, "1", + "Set DC range of RPF of delta lc to `%s'."}, + {"d-dc-mantissa", "NUM", '\0', PINT, {0}, "5", + "Set #m-bits of delta RPF for DC domain to `%s'."}, + /* ADVANCED */ + {"images-level", "NUM", '\0', PINT, {0}, "5", + "Compute state images up to level `%s'."}, + {"delta-domains", NULL, '\0', PFLAG, {0}, "FALSE", + "Use delta domains every time."}, + {"normal-domains", NULL, '\0', PFLAG, {0}, "FALSE", + "Use normal domains every time."}, + /* VIDEO COMPRESSION */ + {"smooth", "REAL", 's', PFLOAT, {0}, "1.0", + "Smooth frames by factor `%s' (0.5 - 1.0)"}, + {"reference-frame", "FILE", '\0', PSTR, {0}, NULL, + "Use PPM/PGM image `%s' as reference frame."}, +#endif + {NULL, NULL, 0, PSTR, {0}, NULL, NULL } +}; + +/***************************************************************************** + + prototypes + +*****************************************************************************/ + +static void +checkargs (int argc, char **argv, char const ***image_template, + char **wfa_name, float *quality, fiasco_c_options_t **options); + +/***************************************************************************** + + public code + +*****************************************************************************/ + +int +main (int argc, char **argv) +{ + char const **image_template; /* template for input image files */ + char *wfa_name; /* filename of output WFA */ + float quality; /* approximation quality */ + fiasco_c_options_t *options; /* additional coder options */ + + pnm_init(&argc, argv); + + init_error_handling (argv [0]); + + checkargs (argc, argv, &image_template, &wfa_name, &quality, &options); + + if (fiasco_coder (image_template, wfa_name, quality, options)) + return 0; + else + { + fprintf (stderr, fiasco_get_error_message ()); + fprintf (stderr, "\n"); + return 1; + } +} + +/***************************************************************************** + + private code + +*****************************************************************************/ + +static void +checkargs (int argc, char **argv, char const ***image_template, + char **wfa_name, float *quality, fiasco_c_options_t **options) +/* + * Check validness of command line parameters and of the parameter files. + * + * Return value: + * 1 on success + * 0 otherwise + * + * + * Side effects: + * 'image_template', 'wfa_name', 'quality' and 'options' are set. + */ +{ + int optind; /* last processed commandline param */ + char *image_name; /* filename given by option '-i' */ + int i; /* counter */ + + optind = parseargs (params, argc, argv, + "Compress raw PPM/PGM image FILEs to a FIASCO file.", + "With no image FILE, or if FILE is -, " + "read standard input.\n" + "FILE must be either a filename" + " or an image template of the form:\n" + "`prefix[start-end{+,-}step]suffix'\n" + "e.g., img0[12-01-1].pgm is substituted by" + " img012.pgm ... img001.pgm\n\n" + "Environment:\n" + "FIASCO_DATA Search and save path for FIASCO files. " + "Default: ./\n" + "FIASCO_IMAGES Search path for image files. " + "Default: ./", " [FILE]...", + FIASCO_SHARE, "system.fiascorc", ".fiascorc"); + + /* + * Default options ... + */ + image_name = (char *) parameter_value (params, "image-name"); + *wfa_name = (char *) parameter_value (params, "output-name"); + for (;;) + { + *quality = * (float *) parameter_value (params, "quality"); + if (*quality > 100) + fprintf (stderr, "Typical range of quality: (0,100].\n" + "Expect some trouble on slow machines.\n"); + if (*quality > 0) + break; + ask_and_set (params, "quality", + "Please enter coding quality 'q' ('q' > 0): "); + } + + if (optind < argc) /* Additional command line param */ + { + if (image_name) + error ("Multiple image_template arguments." + "\nOption -i %s already specified!", image_name); + + *image_template = calloc (argc - optind + 1, sizeof (char *)); + if (!*image_template) + error ("Out of memory."); + for (i = 0; optind < argc; i++, optind++) + (*image_template) [i] = argv [optind]; + (*image_template) [i] = NULL; + } + else /* option -i image_name */ + { + *image_template = calloc (2, sizeof (char *)); + if (!*image_template) + error ("Out of memory."); + (*image_template) [0] = image_name; + (*image_template) [1] = NULL; + } + /* + * Additional options ... (have to be set with the fiasco_set_... methods) + */ + { + *options = fiasco_c_options_new (); + + { + char *pattern = (char *) parameter_value (params, "pattern"); + + if (!fiasco_c_options_set_frame_pattern (*options, pattern)) + error (fiasco_get_error_message ()); + } + + { + char *basis = (char *) parameter_value (params, "basis-name"); + + if (!fiasco_c_options_set_basisfile (*options, basis)) + error (fiasco_get_error_message ()); + } + + { + int n = * (int *) parameter_value (params, "chroma-dictionary"); + float q = * (float *) parameter_value (params, "chroma-qfactor"); + + if (!fiasco_c_options_set_chroma_quality (*options, q, max (0, n))) + error (fiasco_get_error_message ()); + } + + { + int n = *((int *) parameter_value (params, "smooth")); + + if (!fiasco_c_options_set_smoothing (*options, max (0, n))) + error (fiasco_get_error_message ()); + } + + { + int n = * (int *) parameter_value (params, "progress-meter"); + fiasco_progress_e type = (n < 0) ? + FIASCO_PROGRESS_NONE : (fiasco_progress_e) n; + + if (!fiasco_c_options_set_progress_meter (*options, type)) + error (fiasco_get_error_message ()); + } + + { + char *t = (char *) parameter_value (params, "title"); + + if (strlen (t) > 0 && !fiasco_c_options_set_title (*options, t)) + error (fiasco_get_error_message ()); + } + + { + char *c = (char *) parameter_value (params, "comment"); + + if (strlen (c) > 0 && !fiasco_c_options_set_comment (*options, c)) + error (fiasco_get_error_message ()); + } + + { + fiasco_tiling_e method = FIASCO_TILING_VARIANCE_DSC; + int e = * (int *) parameter_value (params, "tiling-exponent"); + char *m = (char *) parameter_value (params, "tiling-method"); + + if (strcaseeq (m, "desc-variance")) + method = FIASCO_TILING_VARIANCE_DSC; + else if (strcaseeq (m, "asc-variance")) + method = FIASCO_TILING_VARIANCE_ASC; + else if (strcaseeq (m, "asc-spiral")) + method = FIASCO_TILING_SPIRAL_ASC; + else if (strcaseeq (m, "dsc-spiral")) + method = FIASCO_TILING_SPIRAL_DSC; + else + error (_("Invalid tiling method `%s' specified."), m); + + if (!fiasco_c_options_set_tiling (*options, method, max (0, e))) + error (fiasco_get_error_message ()); + } + + { + int M/* = * (int *) parameter_value (params, "max-level") */; + int m/* = * (int *) parameter_value (params, "min-level") */; + int N/* = * (int *) parameter_value (params, "max-elements") */; + int D = * (int *) parameter_value (params, "dictionary-size"); + int o = * (int *) parameter_value (params, "optimize"); + + if (o <= 0) + { + o = 0; + M = 10; + m = 6; + N = 3; + } + else + { + o -= 1; + M = 12; + m = 4; + N = 5; + } + + if (!fiasco_c_options_set_optimizations (*options, m, M, N, + max (0, D), o)) + error (fiasco_get_error_message ()); + } + { + int M = * (int *) parameter_value (params, "max-level"); + int m = * (int *) parameter_value (params, "min-level"); + int p = * (int *) parameter_value (params, "prediction"); + + if (!fiasco_c_options_set_prediction (*options, + p, max (0, m), max (0, M))) + error (fiasco_get_error_message ()); + } + { + float r = * (float *) parameter_value (params, "rpf-range"); + float dc_r = * (float *) parameter_value (params, "dc-rpf-range"); + int m = * (int *) parameter_value (params, "rpf-mantissa"); + int dc_m = * (int *) parameter_value (params, "dc-rpf-mantissa"); + fiasco_rpf_range_e range, dc_range; + + if (r < 1) + range = FIASCO_RPF_RANGE_0_75; + else if (r < 1.5) + range = FIASCO_RPF_RANGE_1_00; + else if (r < 2.0) + range = FIASCO_RPF_RANGE_1_50; + else + range = FIASCO_RPF_RANGE_2_00; + + if (dc_r < 1) + dc_range = FIASCO_RPF_RANGE_0_75; + else if (dc_r < 1.5) + dc_range = FIASCO_RPF_RANGE_1_00; + else if (dc_r < 2.0) + dc_range = FIASCO_RPF_RANGE_1_50; + else + dc_range = FIASCO_RPF_RANGE_2_00; + + if (!fiasco_c_options_set_quantization (*options, + max (0, m), range, + max (0, dc_m), dc_range)) + error (fiasco_get_error_message ()); + } + + if (fiasco_get_verbosity () == FIASCO_ULTIMATE_VERBOSITY) + write_parameters (params, stderr); + } +} diff --git a/converter/other/fiasco/system.fiascorc b/converter/other/fiasco/system.fiascorc new file mode 100644 index 00000000..86ff2da2 --- /dev/null +++ b/converter/other/fiasco/system.fiascorc @@ -0,0 +1,120 @@ +# +# system.wfarc: Resource file WFA coder +# +# 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/25 16:38:01 $ +# $Author: hafner $ +# $Revision: 5.2 $ +# $State: Exp $ + +# +# Options for FIASCO coder `cfiasco': +# + +# Initial basis to start with +# small.fco: domains 1, x, y +# medium.fco: domains 1, x, y and 129 additional images +# large.fco: domains 1, x, y and 226 additional images +basis-name = small.fco + +# Limit the number of elements in the dictionary by `dictionary-size' +# The smaller the value is the faster the coder runs and the worse +# the image quality will be. +dictionary-size = 10000 + +# Optimization level +# 0: standard approximation method, process blocks of level [6, 10], +# use up to 3 dictionary vectors +# 1: standard approximation method, process blocks of level [4, 12], +# use up to 5 dictionary vectors +# 2: significantly increases the approximation quality, +# running time is twice as high as with the standard method +# 3: hardly increases the approximation quality of method 2, +# running time is twice as high as with method 21 +# (this method just remains for completeness) +optimize = 0 + +# Approximation quality (typical range = [1-100]) +quality = 20.0 + +# For compression of chroma bands the dictionary can be reduced to +# the best #`chroma-dictionary' elements. +# Furthermore, the quality of the approximation is decreased +# 'chroma-qfactor' times. +chroma-dictionary = 40 +chroma-qfactor = 2 + +# Verbosity level +# 0 no debug output +# 1 some verbosity and statistics of the output size +# 2 lots of debug information and log-files are written +verbose = 1 + +# Set exponent and method of image tiling +# 0 image is processed in normal bintree order +# >0 image is subdivided into 2^`tiling-exponent' tiles. +# Set type of image tiling +# asc-variance Tiles with large variances are processed first +# desc-variance Tiles with small variances are processed first +# asc-spiral Tiles are process in spiral order starting in the middle +# desc-spiral Tiles are process in spiral order starting at the border +tiling-exponent = 4 +tiling-method = desc-variance + +# Quantization parameters define the accuracy of coefficients quantization. +# DC coefficients (of the constant dictionary vector f(x,y) = 1) are quantized +# to values of the interval [-`dc-rpf-range', `dc-rpf-range'] using +# #`dc-rpf-mantissa' bits. All other quantized coefficients are quantized in +# an analogous way using the parameters `rpf-range' and `rpf-mantissa'. +rpf-mantissa = 3 +rpf-range = 1.5 +dc-rpf-mantissa = 5 +dc-rpf-range = 1 + +# Search for prediction (coarse approximation or motion compensation) +# on all levels between minlevel and maxlevel +min-level = 6 +max-level = 10 + +# Set various parameters used for video compensation. +# 'fps' 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' is set then half pixel precise +# motion compensated prediction is used. +# If 'cross-B-search' is set 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 set then B frames are allowed to be used +# for B frame predicion. +fps = 25 +half-pixel = NO +cross-B-search = NO +B-as-past-ref = NO + +# 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). + +pattern = ippppppppp + +# +# Options for FIASCO decoder `dfiasco': +# + +double = NO +reduced = NO +panel = NO +enlarge = 0 |