Frame recover library is a C++ library for recovering losses in
coefficient streams obtained by means of an oversampled filter bank.
This chapter describes briefly the goals of this library, what it
provides and the application software which comes with it.
This library implements the algorithm of [???] for coefficient recovering for frame-analyzed signals.
Frame analysis (e.g. analysis with a redundant filter bank) is a recently proposed solution to the problem of transmitting in a robust way multimedia signals over unrielable channels. Here and in the following I will suppose that you are confident with the idea of robust transmission and oversampled filter banks. If the first sentence of this paragraph made no sense to you, then almost surely you do not need this library and you can stop reading here.
This library was designed by trying to meet the following apparently incompatible goals
Those goals were met by interfacing the main computational function
(recover_stream) to the “external world” by means of
abstract class StreamDescr whose objects takes care of
coefficient I/O and carry all the informations necessary to
recover_stream. In order to actually use recover_stream
the user should write a derived class of StreamDescr suited to
its own needs. Since the filter bank based case is the most common
case, the library gives a pret-a-porter class
FilterBankStream which allows one to use recover_stream
with almost no work at all. (see Simple Example).
In this section we show some simple examples of usage of
recover_stream together with FilterBankStream. We cover
the four most common cases.
In this example we suppose that the input coefficients are stored on a file according to the format described in Coefficient Format. A brief description of the program follows.
1: #include<iostream>
2: #include"recover.h"
3: #include"filter_bank_stream.h"
4:
5: using namespace std;
6:
7: void die(string msg)
8: { cerr << msg << endl; exit(1); }
9:
10: int main(int argc, char **argv)
11: {
12: //
13: // Command line parameters processing
14: //
15: if (argc < 4)
16: die("Usage: test_recover sp_table coeff_in coeff_out\n");
17:
18: string sp_filename(argv[1]);
19: string in_filename(argv[2]);
20: string out_filename(argv[3]);
21:
22: //
23: // Load the scalar product table
24: //
25: SpTable<double> sp;
26: load_sp_table(sp, sp_filename);
27:
28: //
29: // Create the data descriptor with the two channels and the
30: // scalar product table
31: //
32: FilterBankStream fbstream(in_filename, // Input
33: out_filename, // Output
34: sp); // SP table
35:
36: //
37: // Recover the lost coefficients.
38: //
39: recover_stream(fbstream);
40:
41: exit(0);
42: }
A brief comment about the program is in order. A
FilterBankStream needs to know
When the coefficients are read from a file the first two informations
are read from the file header (see Coefficient Format) and the
third one can be obtained from the table of scalar products. Because
of this, we need to give to the FilterBankStream constructor at
line 32 only the names of the input and output files and the scalar
product table loaded at line 26.
When the FilterBankStream is ready, we can give it to
recover_stream (line 39) and let it do its work.
In this example we suppose that the coefficient are already in memory (for example, they are the result of some other processing) and we want to write the recovered stream to a file.
1: #include<iostream>
2: #include"recover.h"
3: #include"filter_bank_stream.h"
4:
5: using namespace std;
6:
7: void die(string msg)
8: { cerr << msg << endl; exit(1); }
9:
10: int main(int argc, char **argv)
11: {
12: vector<double> val; // Coefficient values
13: vector<bool> known; // known[n]==true iff n-th coefficient arrived
14:
15: vector<unsigned int>signal_size; // Signal dimensions
16: vector<border_type> padding_type; // How the signal was padded
17:
18:
19: //
20: // Command line parameters processing
21: //
22: if (argc < 3)
23: die("Usage: test_recover sp_table coeff_out\n");
24:
25: string sp_filename(argv[1]);
26: string out_filename(argv[2]);
27:
28: //
29: // Load the scalar product table
30: //
31: SpTable<double> sp;
32: load_sp_table(sp, sp_filename);
33:
34: //
35: // Get the coefficient values and the signal size
36: //
37:
38: ...here you should put the code which reads the signal size,...
39: ...how the signal was padded and the coefficient values ...
40
41 //
42: // Create the data descriptor with the two channels and the
43: // scalar product table
44: //
45:
46: FilterBankStream fbstream(val, known, // Input
47: out_filename, // Output
48: sp, // SP table
49: signal_size, // Signal size
50: padding_type); // Signal padding
51:
52: //
53: // Recover the lost coefficients.
54: //
55: recover_stream(fbstream);
56:
57: exit(0);
58: }
This case is sligthly more complex than the example shown in File to File because now the signal dimensions and padding cannot be read
from file, but they must be given explicitely to the
FilterBankStream constructor (lines 46–50) via arrays
signal_size and padding_type.
The input coefficients are given to the FilterBankStream
constructor via two arrays: the first one (val) contains the
coefficient values ordered according to the same order used in the
coefficient file format (see Coefficient Format), while the second
arrays (known) is a vector of bool such that
known[n] is true if and only if the n-th
coefficient arrived. If known[n] is false, val[n]
is not read and it can have any value.
This case is the “dual” of the case considered in Memory to File: the input coefficients are stored in a file (still according to the format described in Coefficient Format) and the recovered stream will be in memory.
1: #include<iostream>
2: #include"recover.h"
3: #include"filter_bank_stream.h"
4:
5: using namespace std;
6:
7: void die(string msg)
8: { cerr << msg << endl; exit(1); }
9:
10: int main(int argc, char **argv)
11: {
12: //
13: // Command line parameters processing
14: //
15: if (argc < 4)
16: die("Usage: test_recover sp_table coeff_in coeff_out\n");
17:
18: string sp_filename(argv[1]);
19: string in_filename(argv[2]);
20: string out_filename(argv[3]);
21:
22: //
23: // Load the scalar product table
24: //
25: SpTable<double> sp;
26: load_sp_table(sp, sp_filename);
27:
28: //
29: // Create the data descriptor with the two channels and the
30: // scalar product table
31: //
32: vector<double> val;
33: vector<bool> known;
34: FilterBankStream fbstream(in_filename, // Input
35: val, known, // Output
37: sp); // SP table
38:
39: //
40: // Recover the lost coefficients.
41: //
42: recover_stream(fbstream);
43:
44: exit(0);
45: }
Since in this case the input coefficients are stored in a file, it is
not necessary to give to the FilterBankStream constructor the
informations about the signal size and the padding type.
The output coefficients will be stored in two arrays (val and
known) according to the same convention used in the “Memory to
File” (see Memory to File) case. Note that even after the call
to recover_stream some element of known can still be
false if recovering was not possible because of excessive losses.
Finally, we consider the “memory to memory” case. The same comments
used for the other cases (File to File, File to Memory,
Memory to File) apply. The only new observation is that this
time the same pair of array (val and known) is used both
for input and for output. If desired, it is also possible to use
different vectors for the original coefficients and for the recovered ones.
1: #include<iostream>
2: #include"recover.h"
3: #include"filter_bank_stream.h"
4:
5: using namespace std;
6:
7: void die(string msg)
8: { cerr << msg << endl; exit(1); }
9:
10: int main(int argc, char **argv)
11: {
12: //
13: // Command line parameters processing
14: //
15: if (argc < 4)
16: die("Usage: test_recover sp_table coeff_in coeff_out\n");
17:
18: string sp_filename(argv[1]);
19: string in_filename(argv[2]);
20: string out_filename(argv[3]);
21:
22: //
23: // Load the scalar product table
24: //
25: SpTable<double> sp;
26: load_sp_table(sp, sp_filename);
27:
28: //
29: // Create the data descriptor with the two channels and the
30: // scalar product table
31: //
32: vector<double> val;
33: vector<bool> known;
34: FilterBankStream fbstream(val, known, // Input and Output
35: sp, // SP table
36: signal_size, ext); // Signal size
38:
39: //
40: // Recover the lost coefficients.
41: //
42: recover_stream(fbstream);
43:
44: exit(0);
45: }
recover_stream()Procedure recover_stream() is the “computational core” of the
library and implements the algorithm of [???] in complete generality.
In order to do its work recover_stream() needs to
All those informations are stored in a stream descriptor passed
as parameter to recover_stream(). In C++ a stream
descriptor is represented by an object of class StreamDescr.
Actually, since the informations above strongly depend on how the
coefficients were generated and how they are stored and/or
transmitted, class StreamDescr is just an abstract class
whose only goal is to describe the interface that a “good”
stream descriptor should implement (see StreamDescr interface for details).
This implies that it is not possible to allocate objects of type
StreamDescr, but the user needs to create a new class, derived
from StreamDescr and suited to its own needs. Note that since
the methods of StreamDescr are declared virtual new
stream descriptors can be used without the need of recompiling the
library.
The use of an object derived from an abstract class as interface
between recover_stream and the “external world” gives great
flexibility to the library, at the expense of requiring the user to
write its own stream descriptor.
Since the most common case is the case of a coefficient stream
stored on disk or in memory and obtained by means of an oversampled
filter bank, the library provides a pret-a-porter stream
descriptor FilterBankStream suited to this case
(see FilterBankStream).
FilterBankStreamFilterBankStream isFilterBankStream is a StreamDescr especially suited for
the case of coefficients obtained by means of an oversampled filter
bank.
FilterBankStreamThe only user methods of FilterBankStream are the constructors
described in the following. FilterBankStream has several
different constructors, one for each possible case of interest. In
order to understand the constructor interface, observe that a
FilterBankStream must know
In general, the first and second informations are given to the
FilterBankStream via two objects of type CoeffSource. A
CoeffSource models a stream of coefficients which can be
sequentially read/write. At each read access the CoeffSource
returns if the next coefficient has been received and its value. A
FilterBankStream supposes that a CoeffSource stores the
coefficients according to the order used in the coefficient files
(see Coefficient Format).
Note the difference between a FilterBankStream and a
CoeffSource: the latter is just a sequence of coefficients with
no knowledge about channels, signal dimensions and so on... Instead a
FilterBankStream organizes the coefficients in
macro-coefficients, handle the signal padding and so on. By making a
parallel with databases, one could say that a CoeffSource
represents the binary file which holds the database (it is just a
sequence of byte), while a FilterBankStream is a higher-level
interface which allows to access the database by records.
In order to have a greater generality, class CoeffSource is an
abstract one which specifies the minimum interface of a source of
coefficients (see CoeffSource interface). To enhance the
usability the library includes two derived classes of
CoeffSource for the two cases of more common interest, i.e,
coefficients stored in memory (class Array_CoeffSource or in a
file (class File_CoeffSource).
In order to make the library usage still easier, class
FilterBankStream has specialized constructors which only
require a filename (if the coefficients are on file) or a pair of
arrays (if the coefficients are in memory).
The third information (the scalar products between frame and dual
functions) is given via an object of class SpTable which is
usually loaded with load_sp_table (see SpTable interface)
as in
SpTable<double> sp; load_sp_table(sp, sp_filename);
The fourth group of informations (signal size, signal extension and so on) can sometimes be read from the input stream (for example, if the input stream is a file, such informations can be read from the file header (see Coefficient Format)). In this case is not necessary to give the informations to the constructor.
FilterBankStream constructorsEvery FilterBankStream constructor follows the same convention
in parameter order
The possible source/destinations are
bools, known, such that known[n] is
true if and only if the n-th coefficient arrived.
doubles, val, such that val[n] is the
value of the n-th coefficient. If known[n] is
false, val[n] is not read and it can have any value
For an example, See Memory to File.
CoeffSource. This allows to use the class
FilterBankStream with other setups (e.g., if the coefficients are
received through a network socket).
FilterBankStream(std::vector<double> &val_src, // Input values std::vector<bool> &rec_src, // Received? std::vector<double> &val_dst, // Output values std::vector<bool> &rec_dst, // Restored? const scal_prod_table &sp, // SP table const std::vector<unsigned int> &sz, // signal size const std::vector<border_type> &extension); // padding
FilterBankStream(std::vector<double> &val_src, // Input values
std::vector<bool> &rec_src, // Received?
std::vector<double> &val_dst, // Output values
std::vector<bool> &rec_dst, // Restored?
const scal_prod_table &sp, // SP table
const std::vector<unsigned int> &sz, // signal size
border_type extension); // same padding along all
// the dimensions
FilterBankStream(std::vector<double> &val_src_dst, // Input and output std::vector<bool> &rec_src_dst, const scal_prod_table &sp, // SP table const std::vector<unsigned int> &sz, // size const std::vector<border_type> &extension);
FilterBankStream(std::vector<double> &val_src_dst, // Input and output
std::vector<bool> &rec_src_dst,
const scal_prod_table &sp, // SP table
const std::vector<unsigned int> &sz,
border_type extension); // same padding along all
// the dimensions
FilterBankStream(const std::string &filein, // Input const std::string &fileout, // Output const scal_prod_table &sp, // SP table const std::vector<unsigned int> &sz, const std::vector<border_type> &extension);
FilterBankStream(const std::string &filein, // Input
const std::string &fileout, // Output
const scal_prod_table &sp, // SP table
const std::vector<unsigned int> &sz,
border_type extension); // same padding along all
// the dimensions
FilterBankStream(const std::string &filein, // Input
const std::string &fileout, // Output
const scal_prod_table &sp); // SP table
// size and padding read from the input file
FilterBankStream(const std::string &filein, // Input std::vector<double> &val_dst, // Output std::vector<bool> &rec_dst, // Recovered? const scal_prod_table &sp, const std::vector<unsigned int> &sz, const std::vector<border_type> &extension);
FilterBankStream(const std::string &filein, // Input
std::vector<double> &val_dst, // Output
std::vector<bool> &rec_dst, // Recovered?
const scal_prod_table &sp,
const std::vector<unsigned int> &sz,
border_type extension); // same padding along all
// the dimensions
FilterBankStream(const std::string &filein, // Input
std::vector<double> &val_dst, // Output
std::vector<bool> &rec_dst, // Recovered?
const scal_prod_table &sp);
// size and padding read from the input file
FilterBankStream(std::vector<double> &val_src, // Input std::vector<bool> &rec_src, // Received? const std::string &fileout, // Output const scal_prod_table &sp, const std::vector<unsigned int> &sz, const std::vector<border_type> &extension);
FilterBankStream(std::vector<double> &val_src, // Input
std::vector<bool> &rec_src, // Received?
const std::string &fileout, // Output
const scal_prod_table &sp,
const std::vector<unsigned int> &sz,
border_type extension); // same padding along all
// the dimensions
FilterBankStream(CoeffSource &src, CoeffSource &dst, const scal_prod_table &sp, const std::vector<unsigned int> &sz, const std::vector<border_type> &ext);
FilterBankStream(CoeffSource &src, CoeffSource &dst, const scal_prod_table &sp, const std::vector<unsigned int> &sz, border_type ext);
FilterBankStream(CoeffSource &src, CoeffSource &dst, const scal_prod_table &sp);
Class StreamDescr is an abstract class which describes
the minimum interface of a stream descriptor. The duty of a
stream descriptor is to give to recover_stream() all the
necessary informations about the coefficient stream and allow for
coefficient I/O.
More in details, the informations which a stream descriptor
must make available to recover_stream() are
A stream descriptor must also accept from
recover_stream()
Here we give a list of methods of class StreamDescr. You will
notice that some methods are pure virtual, while some other are
not. We decided to make a method non pure virtual if it was possible
to code that method by exploiting other methods of StreamDescr.
For example, method receive(const std::set<Coefficient> &),
which is used by recover_stream() in order to output a
macro-coefficient, is not pure virtual since it can be coded by
repeatedly calling receive(const Coefficient &) which outputs a
single coefficient.
This choice allows one to derive a new class from StreamDescr
writing only the minimum amount of code, while leaving the possibility
of rewriting some of the other methods for reasons of efficiency (for
example, depending on the coefficient organization, it could be more
efficient to output a whole macro-coefficient instead of outputting
each single coefficient).
double sp_table(const Coefficient &r, const Coefficient &c) Pure virtual.r and the frame function associated with
c.
unsigned int size() Pure virtualbool again(unsigned int proc_time)proc_time. The default behavior is to check if proc_tim
is less than the value returned by method size(). It can be
rewritten for the sake of efficiency.
std::set<Coefficient> coeffs(unsigned int proc_time) Pure virtual.proc_time
bool is_complete(unsigned int proc_time)proc_time have been received. The default
behavior is to check the known field of all the coefficients
returned by coeffs(proc_time). It can be rewritten for the
sake of efficiency.
std::set<int> neighborhood(unsigned int proc_time) const Pure virtual.proc_time
int waiting_time(unsigned int proc_time) constproc_time. The default behavior is to return the maximum among
the values returned by neighborhood(proc_time). It can be
rewritten for the sake of efficiency.
void receive(const Coefficient &coeff) Pure virtual.coeff
void receive(const std::set<Coefficient> ¯o_coeff)macro_coeff. The default behavior is to
repeatly call receive(const Coefficient &coeff) for every
element in macro_coeff. It can be rewritten for the sake of
efficiency.
void kernel_vec(const std::vector<double> &val, const std::vector<Coefficient> &c)recover_stream()
calls this function in order to comunicate a basis of the kernel. The
recipient stream descriptor can do whatever it likes with
them. The default action is to ignore the kernel vectors.
To be written
To be written
In this section we describe the complementary program given with the library.
In this section we briefly describe the model we choose for the coefficient stream. The assumptions are weak enough to be adapted to any case of practical relevance.
Definitions:
If the frame is obtained by means of oversampled filter banks, c represents the channel number, N is the number of channels and k represent the sampling istant.
Note that this two-values labelling method can be made equivalent to a
one-values one by letting N=1.
The set of macro-coefficients which are close to a
macro-coefficient C will be called the
neighborhood of C.
recover_stream(). If macro-coefficient C is read
at the n-th iteration, we will say that C has
processing time equal to n. recover_stream()
accesses the coefficient stream by asking for the
macro-coefficient with a given processing time.
A coefficient file is composed of two part
The header line begins with the string %FBstream% followed by
the following fields, separated by whitespaces
Any character following the last field is ignored and it can be used to save remarks and other informations (for example, analysis_fb writes at the end of the header the filter bank used to produce the coefficient sequence).
Example
The header%FBstream% 1 1 2 5 32 32 PP ../data/banks/daub4-2d.frameis relative to a file with version 1.1 which contains a set of 32x32 coefficients obtained by applying a 5-channel filter bank (daub4-2d.frame) to a 2-dimensional signal. The signal was extended by periodicity along both dimensions.
Each line after the header line has a two entries: a floating point
number (in any format accepted by C++) and an integer number
that can be only 0 or 1. If the second entry is 1, the coefficient
has been received, if it is 0 the coefficient is lost. In the latter
case the first field is never read and it can contain any value, but
it must be present.
The coefficients are ordered as follows. Each coefficient is uniquely
determined by D+1 values: the D coordinates plus
the number of the channel. If we denote with x(c; n_1, ...,
n_D) the coefficient relative to channel c and
coordinates n_1, ..., n_D, the coefficients
are stored in the file by varying the first index more rapidaly, then
the second and so on, similarly to the way used by
Matlab® to transform a multidimensional
array into a column vector.
Example
In the case of the header above, the coefficients would be stored on
file according to the following order
x(1; 0, 0)
x(2; 0, 0)
x(3; 0, 0)
x(4; 0, 0)
x(5; 0, 0)
x(1; 1, 0)
x(2; 1, 0)
x(3; 1, 0)
x(4; 1, 0)
x(5; 1, 0)
x(1; 2, 0)
x(2; 2, 0)
:
:
x(5; 31, 0)
x(1; 0, 1)
:
:
x(5; 31, 31)