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).
FilterBankStream
FilterBankStream
isFilterBankStream
is a StreamDescr
especially suited for
the case of coefficients obtained by means of an oversampled filter
bank.
FilterBankStream
The 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
bool
s, known
, such that known[n]
is
true
if and only if the n
-th coefficient arrived.
double
s, 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) const
proc_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 orderx(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)