-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathRangeCoderDecoder.pm
executable file
·110 lines (94 loc) · 3.55 KB
/
RangeCoderDecoder.pm
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
#!/usr/bin/perl
##########################################################################
# Range Coder / Decoder
# Copyright (C) 2012 Tomonobu Saito All Rights Reserverd.
package RangeCoderDecoder;
use warnings;
use strict;
use Carp qw(croak);
use constant kTopMask => ~((1 << 24) - 1);
use constant kNumBitModelTotalBits => 11;
use constant kBitModelTotal => 1 << kNumBitModelTotalBits;
use constant kNumMoveBits => 5;
sub new {
my $pkg = shift;
bless {
range => undef,
code => undef,
ref_buffer => undef,
}, $pkg;
}
sub SetStream {
my $self = shift;
my $rbuf = shift;
$self->{ ref_buffer } = $rbuf; # reference to array
}
sub ReleaseStream {
my $self = shift;
$self->{ ref_buffer } = undef;
}
sub Init {
my $self = shift;
$self->{ code } = 0;
$self->{ range } = -1;
for (my $i = 0; $i < 5; ++$i) {
$self->{ code } = ($self->{ code } << 8) | shift(@{$self->{ ref_buffer }});
}
}
sub DecodeDirectBits {
my $self = shift;
my $numTotalBits = shift;
my $result = 0;
for (my $i = $numTotalBits; 0 != $i; --$i) {
$self->{ range } = $self->{ range } >> 1;
my $t = (($self->{ code } - $self->{ range }) >> 31);
$self->{ code } -= $self->{ range } & ($t - 1);
$result = ($result << 1) | (1 - $t);
if (0 == ($self->{ range } & kTopMask)) {
$self->{ code } = ($self->{ code } << 8) | shift(@{$self->{ ref_buffer }});
$self->{ range } = $self->{ range } << 8;
}
}
return $result;
}
sub DecodeBit {
my $self = shift;
my $ref_probs = shift; # reference to array (of short)
my $index = shift;
my $prob = $$ref_probs[$index] & 0xFFFF; # short
my $newBound = ($self->{ range } >> kNumBitModelTotalBits) * $prob;
#printf "code 0x%x(0x%x) nb 0x%x(0x%x)\n",
# $self->{ code }, ($self->{ code } ^ 0x80000000), $newBound, ($newBound ^ 0x80000000);
my $signed_cd = unpack("i", pack("I", ($self->{ code } ^ 0x80000000)));
my $signed_nb = unpack("i", pack("I", ($newBound ^ 0x80000000)));
if ($signed_cd < $signed_nb) {
$self->{ range } = $newBound;
$$ref_probs[$index] = ($prob + ((kBitModelTotal - $prob) >> kNumMoveBits)) & 0xFFFF; # short
if (0 == ($self->{ range } & kTopMask)) {
$self->{ code } = ($self->{ code } << 8) | shift(@{$self->{ ref_buffer }});
$self->{ range } <<= 8;
}
#printf "DecodeBit --> 0 (code 0x%x range 0x%x nb 0x%x prob 0x%x probs 0x%x index %d)\n", $self->{ code }, $self->{ range }, $newBound, $prob, $$ref_probs[$index], $index;
return 0;
}
else {
$self->{ range } -= $newBound;
$self->{ code } -= $newBound;
$$ref_probs[$index] = ($prob - (($prob) >> kNumMoveBits)) & 0xFFFF; # short
if (0 == ($self->{ range } & kTopMask)) {
$self->{ code } = ($self->{ code } << 8) | shift(@{$self->{ ref_buffer }});
$self->{ range } <<= 8;
}
#printf "DecodeBit --> 1 (code 0x%x range 0x%x nb 0x%x prob 0x%x probs 0x%x index %d)\n", $self->{ code }, $self->{ range }, $newBound, $prob, $$ref_probs[$index], $index;
return 1;
}
}
# static
sub InitBitModels {
my $ref_probs = shift; # reference to array
for (my $i = 0; $i < @$ref_probs; ++$i) {
$$ref_probs[$i] = (kBitModelTotal >> 1);
}
}
1;