@@ -18,11 +18,24 @@ internal class HuffmanScanDecoder
18
18
{
19
19
private readonly BufferedReadStream stream ;
20
20
21
- // Frame related
21
+ /// <summary>
22
+ /// <see cref="JpegFrame"/> instance containing decoding-related information.
23
+ /// </summary>
22
24
private JpegFrame frame ;
25
+
26
+ /// <summary>
27
+ /// Shortcut for <see cref="frame"/>.Components.
28
+ /// </summary>
23
29
private JpegComponent [ ] components ;
24
30
25
- // The restart interval.
31
+ /// <summary>
32
+ /// Number of component in the current scan.
33
+ /// </summary>
34
+ private int componentsCount ;
35
+
36
+ /// <summary>
37
+ /// The reset interval determined by RST markers.
38
+ /// </summary>
26
39
private int restartInterval ;
27
40
28
41
// How many mcu's are left to do.
@@ -31,6 +44,16 @@ internal class HuffmanScanDecoder
31
44
// The End-Of-Block countdown for ending the sequence prematurely when the remaining coefficients are zero.
32
45
private int eobrun ;
33
46
47
+ /// <summary>
48
+ /// The DC Huffman tables.
49
+ /// </summary>
50
+ private readonly HuffmanTable [ ] dcHuffmanTables ;
51
+
52
+ /// <summary>
53
+ /// The AC Huffman tables
54
+ /// </summary>
55
+ private readonly HuffmanTable [ ] acHuffmanTables ;
56
+
34
57
// The unzig data.
35
58
private ZigZag dctZigZag ;
36
59
@@ -55,14 +78,16 @@ public HuffmanScanDecoder(
55
78
this . stream = stream ;
56
79
this . spectralConverter = converter ;
57
80
this . cancellationToken = cancellationToken ;
58
- }
59
81
60
- // huffman tables
61
- public HuffmanTable [ ] DcHuffmanTables { get ; set ; }
62
-
63
- public HuffmanTable [ ] AcHuffmanTables { get ; set ; }
82
+ // TODO: this is actually a variable value depending on component count
83
+ const int maxTables = 4 ;
84
+ this . dcHuffmanTables = new HuffmanTable [ maxTables ] ;
85
+ this . acHuffmanTables = new HuffmanTable [ maxTables ] ;
86
+ }
64
87
65
- // Reset interval
88
+ /// <summary>
89
+ /// Sets reset interval determined by RST markers.
90
+ /// </summary>
66
91
public int ResetInterval
67
92
{
68
93
set
@@ -72,9 +97,6 @@ public int ResetInterval
72
97
}
73
98
}
74
99
75
- // The number of interleaved components.
76
- public int ComponentsLength { get ; set ; }
77
-
78
100
// The spectral selection start.
79
101
public int SpectralStart { get ; set ; }
80
102
@@ -90,10 +112,12 @@ public int ResetInterval
90
112
/// <summary>
91
113
/// Decodes the entropy coded data.
92
114
/// </summary>
93
- public void ParseEntropyCodedData ( )
115
+ public void ParseEntropyCodedData ( int componentCount )
94
116
{
95
117
this . cancellationToken . ThrowIfCancellationRequested ( ) ;
96
118
119
+ this . componentsCount = componentCount ;
120
+
97
121
this . scanBuffer = new HuffmanScanBuffer ( this . stream ) ;
98
122
99
123
bool fullScan = this . frame . Progressive || this . frame . MultiScan ;
@@ -124,7 +148,7 @@ public void InjectFrameData(JpegFrame frame, IRawJpegData jpegData)
124
148
125
149
private void ParseBaselineData ( )
126
150
{
127
- if ( this . ComponentsLength == this . frame . ComponentCount )
151
+ if ( this . componentsCount == this . frame . ComponentCount )
128
152
{
129
153
this . ParseBaselineDataInterleaved ( ) ;
130
154
}
@@ -143,13 +167,13 @@ private void ParseBaselineDataInterleaved()
143
167
ref HuffmanScanBuffer buffer = ref this . scanBuffer ;
144
168
145
169
// Pre-derive the huffman table to avoid in-loop checks.
146
- for ( int i = 0 ; i < this . ComponentsLength ; i ++ )
170
+ for ( int i = 0 ; i < this . componentsCount ; i ++ )
147
171
{
148
172
int order = this . frame . ComponentOrder [ i ] ;
149
173
JpegComponent component = this . components [ order ] ;
150
174
151
- ref HuffmanTable dcHuffmanTable = ref this . DcHuffmanTables [ component . DCHuffmanTableId ] ;
152
- ref HuffmanTable acHuffmanTable = ref this . AcHuffmanTables [ component . ACHuffmanTableId ] ;
175
+ ref HuffmanTable dcHuffmanTable = ref this . dcHuffmanTables [ component . DCHuffmanTableId ] ;
176
+ ref HuffmanTable acHuffmanTable = ref this . acHuffmanTables [ component . ACHuffmanTableId ] ;
153
177
dcHuffmanTable . Configure ( ) ;
154
178
acHuffmanTable . Configure ( ) ;
155
179
}
@@ -163,13 +187,13 @@ private void ParseBaselineDataInterleaved()
163
187
{
164
188
// Scan an interleaved mcu... process components in order
165
189
int mcuCol = mcu % mcusPerLine ;
166
- for ( int k = 0 ; k < this . ComponentsLength ; k ++ )
190
+ for ( int k = 0 ; k < this . componentsCount ; k ++ )
167
191
{
168
192
int order = this . frame . ComponentOrder [ k ] ;
169
193
JpegComponent component = this . components [ order ] ;
170
194
171
- ref HuffmanTable dcHuffmanTable = ref this . DcHuffmanTables [ component . DCHuffmanTableId ] ;
172
- ref HuffmanTable acHuffmanTable = ref this . AcHuffmanTables [ component . ACHuffmanTableId ] ;
195
+ ref HuffmanTable dcHuffmanTable = ref this . dcHuffmanTables [ component . DCHuffmanTableId ] ;
196
+ ref HuffmanTable acHuffmanTable = ref this . acHuffmanTables [ component . ACHuffmanTableId ] ;
173
197
174
198
int h = component . HorizontalSamplingFactor ;
175
199
int v = component . VerticalSamplingFactor ;
@@ -221,8 +245,8 @@ private void ParseBaselineDataNonInterleaved()
221
245
int w = component . WidthInBlocks ;
222
246
int h = component . HeightInBlocks ;
223
247
224
- ref HuffmanTable dcHuffmanTable = ref this . DcHuffmanTables [ component . DCHuffmanTableId ] ;
225
- ref HuffmanTable acHuffmanTable = ref this . AcHuffmanTables [ component . ACHuffmanTableId ] ;
248
+ ref HuffmanTable dcHuffmanTable = ref this . dcHuffmanTables [ component . DCHuffmanTableId ] ;
249
+ ref HuffmanTable acHuffmanTable = ref this . acHuffmanTables [ component . ACHuffmanTableId ] ;
226
250
dcHuffmanTable . Configure ( ) ;
227
251
acHuffmanTable . Configure ( ) ;
228
252
@@ -272,7 +296,7 @@ private void CheckProgressiveData()
272
296
}
273
297
274
298
// AC scans may have only one component.
275
- if ( this . ComponentsLength != 1 )
299
+ if ( this . componentsCount != 1 )
276
300
{
277
301
invalid = true ;
278
302
}
@@ -304,7 +328,7 @@ private void ParseProgressiveData()
304
328
{
305
329
this . CheckProgressiveData ( ) ;
306
330
307
- if ( this . ComponentsLength == 1 )
331
+ if ( this . componentsCount == 1 )
308
332
{
309
333
this . ParseProgressiveDataNonInterleaved ( ) ;
310
334
}
@@ -323,11 +347,11 @@ private void ParseProgressiveDataInterleaved()
323
347
ref HuffmanScanBuffer buffer = ref this . scanBuffer ;
324
348
325
349
// Pre-derive the huffman table to avoid in-loop checks.
326
- for ( int k = 0 ; k < this . ComponentsLength ; k ++ )
350
+ for ( int k = 0 ; k < this . componentsCount ; k ++ )
327
351
{
328
352
int order = this . frame . ComponentOrder [ k ] ;
329
353
JpegComponent component = this . components [ order ] ;
330
- ref HuffmanTable dcHuffmanTable = ref this . DcHuffmanTables [ component . DCHuffmanTableId ] ;
354
+ ref HuffmanTable dcHuffmanTable = ref this . dcHuffmanTables [ component . DCHuffmanTableId ] ;
331
355
dcHuffmanTable . Configure ( ) ;
332
356
}
333
357
@@ -338,11 +362,11 @@ private void ParseProgressiveDataInterleaved()
338
362
// Scan an interleaved mcu... process components in order
339
363
int mcuRow = mcu / mcusPerLine ;
340
364
int mcuCol = mcu % mcusPerLine ;
341
- for ( int k = 0 ; k < this . ComponentsLength ; k ++ )
365
+ for ( int k = 0 ; k < this . componentsCount ; k ++ )
342
366
{
343
367
int order = this . frame . ComponentOrder [ k ] ;
344
368
JpegComponent component = this . components [ order ] ;
345
- ref HuffmanTable dcHuffmanTable = ref this . DcHuffmanTables [ component . DCHuffmanTableId ] ;
369
+ ref HuffmanTable dcHuffmanTable = ref this . dcHuffmanTables [ component . DCHuffmanTableId ] ;
346
370
347
371
int h = component . HorizontalSamplingFactor ;
348
372
int v = component . VerticalSamplingFactor ;
@@ -390,7 +414,7 @@ private void ParseProgressiveDataNonInterleaved()
390
414
391
415
if ( this . SpectralStart == 0 )
392
416
{
393
- ref HuffmanTable dcHuffmanTable = ref this . DcHuffmanTables [ component . DCHuffmanTableId ] ;
417
+ ref HuffmanTable dcHuffmanTable = ref this . dcHuffmanTables [ component . DCHuffmanTableId ] ;
394
418
dcHuffmanTable . Configure ( ) ;
395
419
396
420
for ( int j = 0 ; j < h ; j ++ )
@@ -418,7 +442,7 @@ ref Unsafe.Add(ref blockRef, i),
418
442
}
419
443
else
420
444
{
421
- ref HuffmanTable acHuffmanTable = ref this . AcHuffmanTables [ component . ACHuffmanTableId ] ;
445
+ ref HuffmanTable acHuffmanTable = ref this . acHuffmanTables [ component . ACHuffmanTableId ] ;
422
446
acHuffmanTable . Configure ( ) ;
423
447
424
448
for ( int j = 0 ; j < h ; j ++ )
@@ -722,5 +746,19 @@ private bool HandleRestart()
722
746
723
747
return false ;
724
748
}
749
+
750
+ /// <summary>
751
+ /// Build the huffman table using code lengths and code values.
752
+ /// </summary>
753
+ /// <param name="type">Table type.</param>
754
+ /// <param name="index">Table index.</param>
755
+ /// <param name="codeLengths">Code lengths.</param>
756
+ /// <param name="values">Code values.</param>
757
+ [ MethodImpl ( InliningOptions . ShortMethod ) ]
758
+ public void BuildHuffmanTable ( int type , int index , ReadOnlySpan < byte > codeLengths , ReadOnlySpan < byte > values )
759
+ {
760
+ HuffmanTable [ ] tables = type == 0 ? this . dcHuffmanTables : this . acHuffmanTables ;
761
+ tables [ index ] = new HuffmanTable ( codeLengths , values ) ;
762
+ }
725
763
}
726
764
}
0 commit comments