-
Notifications
You must be signed in to change notification settings - Fork 10
/
ArithEncoder.cpp
100 lines (89 loc) · 2.06 KB
/
ArithEncoder.cpp
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
/* Copyright (C) Teemu Suutari */
#include <vector>
#include "onekpaq_common.h"
#include "ArithEncoder.hpp"
ArithEncoder::ArithEncoder(EncoderType type) :
_type(type)
{
ASSERT(_type<=EncoderType::TypeLast,"Unknown encoder type");
}
void ArithEncoder::Normalize()
{
auto encodeBit=[&](bool bit) {
_dest.resize((_destPos>>3)+1);
if (bit) _dest[_destPos>>3]|=0x80U>>(_destPos&7);
_destPos++;
};
while (_range<0x4000'0000U) {
if (_bitCount) _bitCount--;
else {
if (_type!=EncoderType::Standard) {
if (!_destPos) encodeBit(false); // start bit
if (_destPos==6) encodeBit(true); // anchor bit
if (_destPos==7) encodeBit(false); // filler bit
}
ASSERT(!(_value&0x8000'0000'0000'0000ULL),"Overflow");
encodeBit(_value&0x4000'0000'0000'0000ULL);
_value&=~0x4000'0000'0000'0000ULL;
}
_value<<=1;
_range<<=1;
}
}
void ArithEncoder::PreEncode(u32 subRange)
{
if (_type!=EncoderType::Standard&&!_hasPreBit) {
Encode(false,subRange);
_hasPreBit=true;
}
}
void ArithEncoder::Encode(bool bit,u32 subRange)
{
DEBUG("bit %u, range %x, subrange %x, value %llx",bit,_range,subRange,_value);
ASSERT(subRange&&subRange<_range-1,"probability error");
if (_type==EncoderType::SingleAsm) {
if (bit) _range-=subRange;
else {
_value+=_range-subRange+1;
// _range=subRange-1 would be correct here.
_range=subRange;
}
} else {
if (bit) _range-=subRange;
else {
_value+=_range-subRange;
_range=subRange;
}
}
Normalize();
}
void ArithEncoder::EndSection(u32 subRange)
{
DEBUG("range %x, subrange %x, value %llx",_range,subRange,_value);
ASSERT(subRange&&subRange<_range-1,"probability error at the end");
if (_type==EncoderType::SingleAsm) {
_value+=_range-subRange;
_range=1;
Normalize();
}
}
void ArithEncoder::Finalize()
{
#if 1
for (uint i=0;i<63;i++) {
_range>>=1;
Normalize();
}
#else
u64 valueX=_value+_range^_value;
while (!(valueX&0x4000'0000'0000'0000ULL)) {
_range>>=1;
Normalize();
valueX<<=1;
}
_value|=0x4000'0000'0000'0000ULL;
_range>>=1;
Normalize();
#endif
DEBUG("%u bits encoded",_destPos);
}