Skip to content

Commit ca434e6

Browse files
committed
Huffman and OpenMP
+ Completed Huffman integration + Added Bitstream realloc + Added progress bar when handling Blocks + Added Block parallelisation witrh OpenMP + Added class diagram
1 parent a6b3359 commit ca434e6

29 files changed

+911
-15787
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,5 @@
3535
/bin/*.png
3636
/bin/ex*.txt
3737
/bin/*.enc
38+
/bin/*_dec.raw
3839
*.qbs.user*

BitStream.cpp

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,23 @@ namespace util {
88
BitStreamReader::~BitStreamReader() {}
99

1010
void BitStreamReader::flush() {
11-
if (this->position % 8 != 0) {
12-
this->position += 8 - (this->position % 8);
13-
}
11+
this->position = this->get_last_byte_position();
1412
}
1513

1614
uint8_t BitStreamReader::get_bit() {
17-
const size_t bits_taken = this->position % 8;
18-
uint8_t value = this->buffer[this->position / 8];
19-
value &= (1 << (7 - bits_taken));
15+
const size_t current_start_byte = this->position / 8u;
16+
17+
if (current_start_byte >= this->get_size()) {
18+
// Prevent reading byte outside of array (-> Valgrind flagged)
19+
return 0u;
20+
}
21+
22+
const size_t bits_taken = this->position % 8;
23+
const uint8_t value = this->buffer[current_start_byte];
24+
2025
this->position++;
21-
return value != 0;
26+
27+
return (value & (1 << (7 - bits_taken))) != 0;
2228
}
2329

2430
uint32_t BitStreamReader::get(size_t l) {

BitStream.hpp

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ namespace util {
2222

2323
~BitStream(void) {
2424
if (this->managed) {
25-
this->clear();
25+
util::deallocArray(this->buffer);
2626
}
2727
}
2828

@@ -38,6 +38,10 @@ namespace util {
3838
return this->size;
3939
}
4040

41+
inline size_t get_size_bits(void) const {
42+
return this->size * 8u;
43+
}
44+
4145
inline void set_managed(bool m) {
4246
this->managed = m;
4347
}
@@ -50,20 +54,34 @@ namespace util {
5054
return this->position;
5155
}
5256

57+
inline size_t get_last_byte_position(void) const {
58+
return util::round_to_byte(this->position);
59+
}
60+
5361
inline void reset(void) {
5462
this->set_position(0);
5563
}
5664

5765
/**
58-
* Deallocate the buffer and reset all fields
66+
* @brief Resize the internal buffer if needed.
67+
* Default resize is by 50% increase.
68+
* @param new_size
69+
* The new size for the buffer.
70+
* @return Returns the size after resizing.
5971
*/
60-
void clear(void) {
61-
if (this->buffer != nullptr) {
62-
util::deallocArray(this->buffer);
72+
size_t resize(size_t new_size=0u) {
73+
if (this->managed /*&& this->malloc*/) {
74+
if (new_size == 0) {
75+
// Resize by 50%
76+
new_size = this->size + this->size / 2u;
77+
} else if (new_size <= this->get_size()) {
78+
return this->get_size();
79+
}
80+
81+
util::reallocArray(this->buffer, this->size, new_size);
6382
}
6483

65-
this->position = 0;
66-
this->size = 0;
84+
return this->get_size();
6785
}
6886
};
6987

@@ -150,15 +168,13 @@ namespace util {
150168
* Byte-align: Move the bitwise position pointer to the next byte boundary
151169
*/
152170
void flush();
153-
154171
};
155172

156173
/**
157174
* Write the contents of the bitstream to the specified file
158175
*/
159176
void write(FILE *f, const BitStreamWriter &b);
160177
void write(std::ofstream &fs, const BitStreamWriter &b);
161-
162178
}
163179
#endif /* UTIL_BITSTREAM_H */
164180

Debug/Debug.bg

-237 KB
Binary file not shown.

Decoder.cpp

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ dc::Decoder::Decoder(const std::string &source_file, const std::string &dest_fil
1616
: ImageProcessor(source_file, dest_file)
1717
{
1818
// Decoding info like (this->quant_m, this->use_rle, width, height)
19-
// is gathered in the ImageProcessor ctor.
19+
// is gathered in the ImageProcessor ctor after Huffman decompress.
2020

2121
// Verify settings
2222
assert(this->width % dc::BlockSize == 0);
@@ -26,9 +26,9 @@ dc::Decoder::Decoder(const std::string &source_file, const std::string &dest_fil
2626
const float hdrlen = float(this->reader->get_position()) / 8.0f;
2727
const float datlen = float(this->reader->get_size()) - hdrlen;
2828

29-
util::Logger::WriteLn(std::string_format("[Decoder] Loaded image with "
29+
util::Logger::WriteLn(std::string_format("[Decoder] Loaded %dx%d image with "
3030
"%.1f bytes header and %.1f bytes data.",
31-
hdrlen, datlen));
31+
this->width, this->height, hdrlen, datlen));
3232

3333
// Create the output buffer
3434
this->writer = util::allocVar<util::BitStreamWriter>(this->width * this->height);
@@ -59,7 +59,11 @@ bool dc::Decoder::process(void) {
5959

6060
success = ImageProcessor::process(this->writer->get_buffer());
6161

62+
const size_t block_count = this->blocks->size();
63+
size_t blockid = 0u;
64+
6265
util::Logger::WriteLn("[Decoder] Processing Blocks...");
66+
util::Logger::WriteProgress(0, block_count);
6367

6468
#ifdef LOG_LOCAL
6569
size_t blockid = 0u;
@@ -83,15 +87,38 @@ bool dc::Decoder::process(void) {
8387
util::Logger::WriteLn("", false);
8488
}
8589
#else
86-
for (Block<>* b : *this->blocks) {
87-
b->loadFromStream(*this->reader, this->use_rle);
88-
b->processIDCTMulQ(this->quant_m.getData());
89-
b->expand();
90-
}
90+
#ifdef ENABLE_OPENMP
91+
// Reading raw must happen in sequence
92+
for (Block<>* b : *this->blocks) {
93+
b->loadFromStream(*this->reader, this->use_rle);
94+
}
95+
96+
#pragma omp parallel for shared(blockid) schedule(dynamic)
97+
for (auto it = this->blocks->begin(); it < this->blocks->end(); it++) {
98+
Block<> *b = *it;
99+
b->processIDCTMulQ(this->quant_m.getData());
100+
b->expand();
101+
102+
#pragma omp atomic
103+
++blockid;
104+
105+
#pragma omp critical
106+
util::Logger::WriteProgress(blockid, block_count);
107+
}
108+
#else
109+
for (Block<>* b : *this->blocks) {
110+
b->loadFromStream(*this->reader, this->use_rle);
111+
b->processIDCTMulQ(this->quant_m.getData());
112+
b->expand();
113+
util::Logger::WriteProgress(++blockid, block_count);
114+
}
115+
#endif
91116
#endif
92117

118+
util::Logger::WriteLn("", false);
119+
93120
// Buffer is written implicitly
94-
this->writer->set_position(this->writer->get_size() * 8u);
121+
this->writer->set_position(this->writer->get_size_bits());
95122

96123
return success;
97124
}

Encoder.cpp

Lines changed: 62 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,19 @@ bool dc::Encoder::process(void) {
7272
float(output_length) / 8.f));
7373

7474
output_length += this->blocks->size() * this->blocks->front()->streamSize();
75-
output_length += (8 - (output_length % 8u)) % 8u; // Padding to next whole byte
76-
output_length /= 8u;
75+
#ifndef ENABLE_HUFFMAN
76+
output_length++; // Add one bit to signal Huffman is not enabled.
77+
#endif
78+
79+
output_length = util::round_to_byte(output_length); // Padding to next whole byte
80+
7781

7882
this->writer = util::allocVar<util::BitStreamWriter>(output_length);
7983

84+
#ifndef ENABLE_HUFFMAN
85+
this->writer->put_bit(0); // '0': No Huffman sequence present.
86+
#endif
87+
8088
// Write matrix data first
8189
this->quant_m.write(*this->writer);
8290

@@ -85,11 +93,13 @@ bool dc::Encoder::process(void) {
8593
this->writer->put(dc::ImageProcessor::DIM_BITS, this->width);
8694
this->writer->put(dc::ImageProcessor::DIM_BITS, this->height);
8795

96+
const size_t block_count = this->blocks->size();
97+
size_t blockid = 0u;
98+
8899
util::Logger::WriteLn("[Encoder] Processing Blocks...");
100+
util::Logger::WriteProgress(0, block_count);
89101

90102
#ifdef LOG_LOCAL
91-
size_t blockid = 0u;
92-
93103
for (Block<>* b : *this->blocks) {
94104
util::Logger::WriteLn(std::string_format("Block % 3d:", blockid++));
95105
b->printExpanded();
@@ -108,38 +118,63 @@ bool dc::Encoder::process(void) {
108118
util::Logger::WriteLn("", false);
109119
}
110120
#else
111-
for (Block<>* b : *this->blocks) {
112-
b->processDCTDivQ(this->quant_m.getData());
113-
b->createRLESequence();
114-
b->streamEncoded(*this->writer, this->use_rle);
115-
}
121+
#ifdef ENABLE_OPENMP
122+
#pragma omp parallel for shared(blockid) schedule(dynamic)
123+
for (auto it = this->blocks->begin(); it < this->blocks->end(); it++) {
124+
Block<> *b = *it;
125+
b->processDCTDivQ(this->quant_m.getData());
126+
b->createRLESequence();
127+
128+
#pragma omp atomic
129+
++blockid;
130+
131+
#pragma omp critical
132+
util::Logger::WriteProgress(blockid, block_count);
133+
}
134+
135+
// Writing results must happen in sequence
136+
for (Block<>* b : *this->blocks) {
137+
b->streamEncoded(*this->writer, this->use_rle);
138+
}
139+
#else
140+
for (Block<>* b : *this->blocks) {
141+
b->processDCTDivQ(this->quant_m.getData());
142+
b->createRLESequence();
143+
b->streamEncoded(*this->writer, this->use_rle);
144+
util::Logger::WriteProgress(++blockid, block_count);
145+
}
146+
#endif
116147
#endif
117148

118-
return success;
119-
}
120-
121-
/**
122-
* @brief Save the resulting stream to the destination.
123-
*/
124-
void dc::Encoder::saveResult(void) const {
149+
util::Logger::WriteLn("", false);
125150

126-
util::Logger::WriteLn("\n", false);
151+
#ifdef ENABLE_HUFFMAN
152+
util::BitStreamReader hm_input(this->writer->get_buffer(),
153+
this->writer->get_last_byte_position());
127154

128-
util::Logger::WriteLn("[Encoder] Huffman:");
129-
algo::Huffman<> h;
155+
algo::Huffman<> hm;
156+
util::BitStreamWriter *hm_output = hm.encode(hm_input);
130157

131-
this->writer->flush();
132-
util::BitStreamReader h_input(this->writer->get_buffer(), this->writer->get_position() / 8u);
158+
#ifdef LOG_LOCAL
159+
util::Logger::WriteLn("\n", false);
160+
hm.printDict();
161+
util::Logger::WriteLn("\n", false);
162+
#endif
133163

134-
util::BitStreamWriter* h_stream = h.encode(h_input);
164+
if (hm_output != nullptr) {
165+
util::deallocVar(this->writer);
166+
this->writer = hm_output;
167+
}
135168

136-
#ifdef LOG_LOCAL
137-
h.printDict();
169+
util::Logger::WriteLn("", false);
138170
#endif
139171

140-
delete h_stream;
141-
142-
util::Logger::WriteLn("\n", false);
172+
return success;
173+
}
143174

175+
/**
176+
* @brief Save the resulting stream to the destination.
177+
*/
178+
void dc::Encoder::saveResult(void) const {
144179
ImageProcessor::saveResult(true);
145180
}

0 commit comments

Comments
 (0)