1 // Copyright (C) 2003 Davis E. King (davis@dlib.net) 2 // License: Boost Software License See LICENSE.txt for the full license. 3 #ifndef DLIB_ENTROPY_ENCODER_KERNEL_1_CPp_ 4 #define DLIB_ENTROPY_ENCODER_KERNEL_1_CPp_ 5 #include "entropy_encoder_kernel_1.h" 6 #include <iostream> 7 #include <streambuf> 8 9 namespace dlib 10 { 11 12 13 // ---------------------------------------------------------------------------------------- 14 15 entropy_encoder_kernel_1:: entropy_encoder_kernel_1()16 entropy_encoder_kernel_1( 17 ) : 18 initial_low(0x00000001), 19 initial_high(0xffffffff), 20 out(0), 21 low(initial_low), 22 high(initial_high), 23 buf(0), 24 buf_used(0) 25 { 26 } 27 28 // ---------------------------------------------------------------------------------------- 29 30 entropy_encoder_kernel_1:: ~entropy_encoder_kernel_1()31 ~entropy_encoder_kernel_1 ( 32 ) 33 { 34 try { 35 if (out != 0) 36 { 37 flush(); 38 } 39 } catch (...) {} 40 } 41 42 // ---------------------------------------------------------------------------------------- 43 44 void entropy_encoder_kernel_1:: clear()45 clear( 46 ) 47 { 48 if (out != 0) 49 { 50 flush(); 51 } 52 out = 0; 53 } 54 55 // ---------------------------------------------------------------------------------------- 56 57 void entropy_encoder_kernel_1:: set_stream(std::ostream & out_)58 set_stream ( 59 std::ostream& out_ 60 ) 61 { 62 if (out != 0) 63 { 64 // if a stream is currently set then flush the buffers to it before 65 // we switch to the new stream 66 flush(); 67 } 68 69 out = &out_; 70 streambuf = out_.rdbuf(); 71 72 // reset the encoder state 73 buf_used = 0; 74 buf = 0; 75 low = initial_low; 76 high = initial_high; 77 } 78 79 // ---------------------------------------------------------------------------------------- 80 81 bool entropy_encoder_kernel_1:: stream_is_set() const82 stream_is_set ( 83 ) const 84 { 85 if (out != 0) 86 return true; 87 else 88 return false; 89 } 90 91 // ---------------------------------------------------------------------------------------- 92 93 std::ostream& entropy_encoder_kernel_1:: get_stream() const94 get_stream ( 95 ) const 96 { 97 return *out; 98 } 99 100 // ---------------------------------------------------------------------------------------- 101 102 void entropy_encoder_kernel_1:: encode(uint32 low_count,uint32 high_count,uint32 total)103 encode ( 104 uint32 low_count, 105 uint32 high_count, 106 uint32 total 107 ) 108 { 109 // note that we must add one because of the convention that 110 // high == the real upper range minus 1 111 uint32 r = (high-low+1)/total; 112 113 // note that we must subtract 1 to preserve the convention that 114 // high == the real upper range - 1 115 high = low + r*high_count-1; 116 low = low + r*low_count; 117 118 119 while (true) 120 { 121 122 // if the highest order bit in high and low is the same 123 if ( low >= 0x80000000 || high < 0x80000000) 124 { 125 // if buf is full then write it out 126 if (buf_used == 8) 127 { 128 if (streambuf->sputn(reinterpret_cast<char*>(&buf),1)==0) 129 { 130 throw std::ios_base::failure("error occurred in the entropy_encoder object"); 131 } 132 buf = 0; 133 buf_used = 0; 134 } 135 136 137 // write the high order bit from low into buf 138 buf <<= 1; 139 ++buf_used; 140 if (low&0x80000000) 141 buf |= 0x1; 142 143 // roll off the bit we just wrote to buf 144 low <<= 1; 145 high <<= 1; 146 high |= 1; // note that it is ok to add one to high here because 147 // of the convention that high == real upper range - 1. 148 // so that means that if we want to shift the upper range 149 // left by one then we must shift a one into high also 150 // since real upper range == high + 0.999999999... 151 152 // make sure low is never zero 153 if (low == 0) 154 low = 1; 155 } 156 // if the distance between high and low is small and there aren't 157 // any bits we can roll off then round low up or high down. 158 else if (high-low < 0x10000) 159 { 160 if (high == 0x80000000) 161 high = 0x7fffffff; 162 else 163 low = 0x80000000; 164 } 165 else 166 { 167 break; 168 } 169 } // while (true) 170 171 } 172 173 // ---------------------------------------------------------------------------------------- 174 175 void entropy_encoder_kernel_1:: flush()176 flush ( 177 ) 178 { 179 // flush the next 4 or 5 bytes that are buffered 180 // thats whatever is contained in buf and then all of low plus any extra 181 // bits needed to pad that to be an even 4 or 5 bytes 182 183 184 if (buf_used != 8) 185 { 186 buf <<= (8-buf_used); 187 buf |= static_cast<unsigned char>(low>>(24+buf_used)); 188 low <<= (8-buf_used); 189 } 190 191 if (streambuf->sputn(reinterpret_cast<char*>(&buf),1) == 0) 192 throw std::ios_base::failure("error occurred in the entropy_encoder object"); 193 194 195 196 buf = static_cast<unsigned char>((low >> 24)&0xFF); 197 if (streambuf->sputn(reinterpret_cast<char*>(&buf),1) == 0) 198 throw std::ios_base::failure("error occurred in the entropy_encoder object"); 199 200 201 202 203 buf = static_cast<unsigned char>((low >> 16)&0xFF); 204 if (streambuf->sputn(reinterpret_cast<char*>(&buf),1)==0) 205 throw std::ios_base::failure("error occurred in the entropy_encoder object"); 206 207 208 209 buf = static_cast<unsigned char>((low >> 8)&0xFF); 210 if (streambuf->sputn(reinterpret_cast<char*>(&buf),1)==0) 211 throw std::ios_base::failure("error occurred in the entropy_encoder object"); 212 213 214 215 if (buf_used != 0) 216 { 217 buf = static_cast<unsigned char>((low)&0xFF); 218 if (streambuf->sputn(reinterpret_cast<char*>(&buf),1)==0) 219 throw std::ios_base::failure("error occurred in the entropy_encoder object"); 220 } 221 222 223 224 // make sure the stream buffer flushes to its I/O channel 225 streambuf->pubsync(); 226 227 228 // reset the encoder state 229 buf_used = 0; 230 buf = 0; 231 low = initial_low; 232 high = initial_high; 233 } 234 235 // ---------------------------------------------------------------------------------------- 236 237 } 238 #endif // DLIB_ENTROPY_ENCODER_KERNEL_1_CPp_ 239 240