Warning: This is an old version. The latest stable version is Version 10.0.0.
In this example shows how to use the API of otacast
to implement save and
restore of a decoder. This allows the decoder to be shutdown and then later
continue from where ever it left off.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 | #include <algorithm>
#include <cstdint>
#include <cstdlib>
#include <ctime>
#include <fstream>
#include <iostream>
#include <random>
#include <vector>
#include <otacast/decoder.hpp>
#include <otacast/encoder.hpp>
#include <otacast/to_string.hpp>
#include <otacast/version.hpp>
bool file_exists(const std::string filename)
{
return std::ifstream(filename).good();
}
std::vector<uint8_t> read(const std::string filename)
{
std::vector<uint8_t> buffer;
std::ifstream in(
filename, std::ifstream::ate | std::ios::out | std::ios::binary);
buffer.resize(in.tellg());
in.seekg(0);
in.read((char*)buffer.data(), buffer.size());
return buffer;
}
void write(const std::string filename, const uint8_t* data, std::size_t size)
{
std::ofstream(filename, std::ios::out | std::ios::binary)
.write((char*)data, size);
}
std::string decoder_state_filename(uint64_t files)
{
return "decoder.state." + std::to_string(files);
}
uint64_t decoder_state_files()
{
uint64_t files = 0;
while (file_exists(decoder_state_filename(files + 1)))
{
files++;
}
return files;
}
int main()
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
/* using nano-seconds instead of seconds */
srand((time_t)ts.tv_nsec);
// Create an encoder and decoder
otacast::encoder encoder;
otacast::decoder decoder;
// Pick the number of bytes to encode/decode
auto block_bytes = 100000;
// Pick the size of each symbol in bytes
auto symbol_bytes = 1400;
// Pick the encoding width. The higher the width, the higher the chance that
// an encoded packet is useful, but also increase the complexity of both the
// encoding and the decoding
auto width = 20;
// Pick the finite field to use for the encoding and decoding
auto field = otacast::finite_field::binary8;
// Configure the encoder
encoder.configure(field, block_bytes, symbol_bytes, width);
// Allocate some storage for a symbol
std::vector<uint8_t> symbol(encoder.symbol_bytes());
// Allocate some data to encode. In this case we make a buffer with the same
// size as the encoder's blocksize (the max. amount a single encoder can
// encode)
std::vector<uint8_t> data_in;
if (file_exists("data.in"))
{
data_in = read("data.in");
}
else
{
data_in.resize(encoder.block_bytes());
// Just for fun - fill data_in with random data
std::generate(data_in.begin(), data_in.end(), rand);
write("data.in", data_in.data(), data_in.size());
}
// Assign the data buffer to the encoder so that we may start to produce
// encoded symbols from it
encoder.set_symbols_storage(data_in.data());
// Configure the decoder to some previous configurations or define it like
// the current encoder
auto state_files = decoder_state_files();
if (state_files != 0)
{
std::vector<uint8_t> state = read(decoder_state_filename(state_files));
auto result = decoder.restore_state(state.data(), state.size());
if (!result)
{
std::cout << "decoder state corrupted, "
<< "please delete decoder.state" << std::endl;
return 1;
}
}
else
{
decoder.configure(field, block_bytes, symbol_bytes, width);
}
// Define a data buffer for the decoder
std::vector<uint8_t> data_out;
if (file_exists("data.out"))
{
data_out = read("data.out");
}
else
{
data_out.resize(decoder.block_bytes());
}
decoder.set_symbols_storage(data_out.data());
auto old_progress = decoder.progress();
auto seed = rand();
auto offset = encoder.encode(symbol.data(), seed);
std::cout << "offset: " << offset << " seed: " << seed << std::endl;
decoder.decode(symbol.data(), seed, offset);
if (decoder.can_complete_decoding())
decoder.complete_decoding();
if (decoder.is_complete())
{
if (data_out == data_in)
{
std::cout << "Data decoded correctly" << std::endl;
}
else
{
std::cout << "Unexpected failure to decode, "
<< "please file a bug report :)" << std::endl;
return 1;
}
}
else
{
std::cout << "Progress: " << decoder.progress() << "%.";
if (decoder.progress() == old_progress)
{
std::cout << " packet linearly dependent!" << std::endl;
return 0;
}
std::cout << std::endl;
std::vector<uint8_t> state(decoder.state_bytes());
decoder.save_state(state.data());
write(
decoder_state_filename(state_files + 1), state.data(),
state.size());
write("data.out", data_out.data(), data_out.size());
}
return 0;
}
|