240 lines
6.6 KiB
C++
240 lines
6.6 KiB
C++
// Copyright (C) 2003 Davis E. King (davis@dlib.net)
|
|
// License: Boost Software License See LICENSE.txt for the full license.
|
|
#ifndef DLIB_ENTROPY_ENCODER_KERNEL_1_CPp_
|
|
#define DLIB_ENTROPY_ENCODER_KERNEL_1_CPp_
|
|
#include "entropy_encoder_kernel_1.h"
|
|
#include <iostream>
|
|
#include <streambuf>
|
|
|
|
namespace dlib
|
|
{
|
|
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
entropy_encoder_kernel_1::
|
|
entropy_encoder_kernel_1(
|
|
) :
|
|
initial_low(0x00000001),
|
|
initial_high(0xffffffff),
|
|
out(0),
|
|
low(initial_low),
|
|
high(initial_high),
|
|
buf(0),
|
|
buf_used(0)
|
|
{
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
entropy_encoder_kernel_1::
|
|
~entropy_encoder_kernel_1 (
|
|
)
|
|
{
|
|
try {
|
|
if (out != 0)
|
|
{
|
|
flush();
|
|
}
|
|
} catch (...) {}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
void entropy_encoder_kernel_1::
|
|
clear(
|
|
)
|
|
{
|
|
if (out != 0)
|
|
{
|
|
flush();
|
|
}
|
|
out = 0;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
void entropy_encoder_kernel_1::
|
|
set_stream (
|
|
std::ostream& out_
|
|
)
|
|
{
|
|
if (out != 0)
|
|
{
|
|
// if a stream is currently set then flush the buffers to it before
|
|
// we switch to the new stream
|
|
flush();
|
|
}
|
|
|
|
out = &out_;
|
|
streambuf = out_.rdbuf();
|
|
|
|
// reset the encoder state
|
|
buf_used = 0;
|
|
buf = 0;
|
|
low = initial_low;
|
|
high = initial_high;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
bool entropy_encoder_kernel_1::
|
|
stream_is_set (
|
|
) const
|
|
{
|
|
if (out != 0)
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
std::ostream& entropy_encoder_kernel_1::
|
|
get_stream (
|
|
) const
|
|
{
|
|
return *out;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
void entropy_encoder_kernel_1::
|
|
encode (
|
|
uint32 low_count,
|
|
uint32 high_count,
|
|
uint32 total
|
|
)
|
|
{
|
|
// note that we must add one because of the convention that
|
|
// high == the real upper range minus 1
|
|
uint32 r = (high-low+1)/total;
|
|
|
|
// note that we must subtract 1 to preserve the convention that
|
|
// high == the real upper range - 1
|
|
high = low + r*high_count-1;
|
|
low = low + r*low_count;
|
|
|
|
|
|
while (true)
|
|
{
|
|
|
|
// if the highest order bit in high and low is the same
|
|
if ( low >= 0x80000000 || high < 0x80000000)
|
|
{
|
|
// if buf is full then write it out
|
|
if (buf_used == 8)
|
|
{
|
|
if (streambuf->sputn(reinterpret_cast<char*>(&buf),1)==0)
|
|
{
|
|
throw std::ios_base::failure("error occurred in the entropy_encoder object");
|
|
}
|
|
buf = 0;
|
|
buf_used = 0;
|
|
}
|
|
|
|
|
|
// write the high order bit from low into buf
|
|
buf <<= 1;
|
|
++buf_used;
|
|
if (low&0x80000000)
|
|
buf |= 0x1;
|
|
|
|
// roll off the bit we just wrote to buf
|
|
low <<= 1;
|
|
high <<= 1;
|
|
high |= 1; // note that it is ok to add one to high here because
|
|
// of the convention that high == real upper range - 1.
|
|
// so that means that if we want to shift the upper range
|
|
// left by one then we must shift a one into high also
|
|
// since real upper range == high + 0.999999999...
|
|
|
|
// make sure low is never zero
|
|
if (low == 0)
|
|
low = 1;
|
|
}
|
|
// if the distance between high and low is small and there aren't
|
|
// any bits we can roll off then round low up or high down.
|
|
else if (high-low < 0x10000)
|
|
{
|
|
if (high == 0x80000000)
|
|
high = 0x7fffffff;
|
|
else
|
|
low = 0x80000000;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
} // while (true)
|
|
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
void entropy_encoder_kernel_1::
|
|
flush (
|
|
)
|
|
{
|
|
// flush the next 4 or 5 bytes that are buffered
|
|
// thats whatever is contained in buf and then all of low plus any extra
|
|
// bits needed to pad that to be an even 4 or 5 bytes
|
|
|
|
|
|
if (buf_used != 8)
|
|
{
|
|
buf <<= (8-buf_used);
|
|
buf |= static_cast<unsigned char>(low>>(24+buf_used));
|
|
low <<= (8-buf_used);
|
|
}
|
|
|
|
if (streambuf->sputn(reinterpret_cast<char*>(&buf),1) == 0)
|
|
throw std::ios_base::failure("error occurred in the entropy_encoder object");
|
|
|
|
|
|
|
|
buf = static_cast<unsigned char>((low >> 24)&0xFF);
|
|
if (streambuf->sputn(reinterpret_cast<char*>(&buf),1) == 0)
|
|
throw std::ios_base::failure("error occurred in the entropy_encoder object");
|
|
|
|
|
|
|
|
|
|
buf = static_cast<unsigned char>((low >> 16)&0xFF);
|
|
if (streambuf->sputn(reinterpret_cast<char*>(&buf),1)==0)
|
|
throw std::ios_base::failure("error occurred in the entropy_encoder object");
|
|
|
|
|
|
|
|
buf = static_cast<unsigned char>((low >> 8)&0xFF);
|
|
if (streambuf->sputn(reinterpret_cast<char*>(&buf),1)==0)
|
|
throw std::ios_base::failure("error occurred in the entropy_encoder object");
|
|
|
|
|
|
|
|
if (buf_used != 0)
|
|
{
|
|
buf = static_cast<unsigned char>((low)&0xFF);
|
|
if (streambuf->sputn(reinterpret_cast<char*>(&buf),1)==0)
|
|
throw std::ios_base::failure("error occurred in the entropy_encoder object");
|
|
}
|
|
|
|
|
|
|
|
// make sure the stream buffer flushes to its I/O channel
|
|
streambuf->pubsync();
|
|
|
|
|
|
// reset the encoder state
|
|
buf_used = 0;
|
|
buf = 0;
|
|
low = initial_low;
|
|
high = initial_high;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
}
|
|
#endif // DLIB_ENTROPY_ENCODER_KERNEL_1_CPp_
|
|
|