Skip to content

Commit 0df60d0

Browse files
Now faster and much cleaner.
1 parent e78b4bd commit 0df60d0

File tree

5 files changed

+75
-432
lines changed

5 files changed

+75
-432
lines changed

src/ImageSharp/Formats/Jpeg/Components/Decoder/FastACTable.cs

Lines changed: 0 additions & 61 deletions
This file was deleted.

src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs

Lines changed: 30 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,10 @@ internal class HuffmanScanDecoder
2828
private readonly JpegFrame frame;
2929
private readonly HuffmanTable[] dcHuffmanTables;
3030
private readonly HuffmanTable[] acHuffmanTables;
31-
private readonly FastACTable[] fastACTables;
3231

33-
private readonly JpegStreamReader stream;
32+
private readonly DoubleBufferedStreamReader stream;
3433
private readonly HuffmanScanBuffer scanBuffer;
3534
private readonly JpegComponent[] components;
36-
private readonly ZigZag dctZigZag;
3735

3836
// The restart interval.
3937
private readonly int restartInterval;
@@ -59,26 +57,26 @@ internal class HuffmanScanDecoder
5957
// The End-Of-Block countdown for ending the sequence prematurely when the remaining coefficients are zero.
6058
private int eobrun;
6159

60+
private ZigZag dctZigZag;
61+
6262
/// <summary>
6363
/// Initializes a new instance of the <see cref="HuffmanScanDecoder"/> class.
6464
/// </summary>
6565
/// <param name="stream">The input stream.</param>
6666
/// <param name="frame">The image frame.</param>
6767
/// <param name="dcHuffmanTables">The DC Huffman tables.</param>
6868
/// <param name="acHuffmanTables">The AC Huffman tables.</param>
69-
/// <param name="fastACTables">The fast AC decoding tables.</param>
7069
/// <param name="componentsLength">The length of the components. Different to the array length.</param>
7170
/// <param name="restartInterval">The reset interval.</param>
7271
/// <param name="spectralStart">The spectral selection start.</param>
7372
/// <param name="spectralEnd">The spectral selection end.</param>
7473
/// <param name="successiveHigh">The successive approximation bit high end.</param>
7574
/// <param name="successiveLow">The successive approximation bit low end.</param>
7675
public HuffmanScanDecoder(
77-
JpegStreamReader stream,
76+
DoubleBufferedStreamReader stream,
7877
JpegFrame frame,
7978
HuffmanTable[] dcHuffmanTables,
8079
HuffmanTable[] acHuffmanTables,
81-
FastACTable[] fastACTables,
8280
int componentsLength,
8381
int restartInterval,
8482
int spectralStart,
@@ -92,7 +90,6 @@ public HuffmanScanDecoder(
9290
this.frame = frame;
9391
this.dcHuffmanTables = dcHuffmanTables;
9492
this.acHuffmanTables = acHuffmanTables;
95-
this.fastACTables = fastACTables;
9693
this.components = frame.Components;
9794
this.componentsLength = componentsLength;
9895
this.restartInterval = restartInterval;
@@ -164,9 +161,6 @@ private unsafe void ParseBaselineDataInterleaved()
164161
ref HuffmanTable acHuffmanTable = ref this.acHuffmanTables[component.ACHuffmanTableId];
165162
dcHuffmanTable.Configure();
166163
acHuffmanTable.Configure();
167-
168-
ref FastACTable fastAcTable = ref this.fastACTables[component.ACHuffmanTableId];
169-
fastAcTable.Derive(ref acHuffmanTable);
170164
}
171165

172166
for (int j = 0; j < mcusPerColumn; j++)
@@ -183,8 +177,6 @@ private unsafe void ParseBaselineDataInterleaved()
183177

184178
ref HuffmanTable dcHuffmanTable = ref this.dcHuffmanTables[component.DCHuffmanTableId];
185179
ref HuffmanTable acHuffmanTable = ref this.acHuffmanTables[component.ACHuffmanTableId];
186-
ref FastACTable fastAcTable = ref this.fastACTables[component.ACHuffmanTableId];
187-
ref short fastACRef = ref fastAcTable.Lookahead[0];
188180

189181
int h = component.HorizontalSamplingFactor;
190182
int v = component.VerticalSamplingFactor;
@@ -199,18 +191,13 @@ private unsafe void ParseBaselineDataInterleaved()
199191

200192
for (int x = 0; x < h; x++)
201193
{
202-
// if (this.jpegBuffer.Eof)
203-
// {
204-
// return;
205-
// }
206194
int blockCol = (mcuCol * h) + x;
207195

208196
this.DecodeBlockBaseline(
209197
component,
210198
ref Unsafe.Add(ref blockRef, blockCol),
211199
ref dcHuffmanTable,
212-
ref acHuffmanTable,
213-
ref fastACRef);
200+
ref acHuffmanTable);
214201
}
215202
}
216203
}
@@ -240,10 +227,6 @@ private unsafe void ParseBaselineDataNonInterleaved()
240227
dcHuffmanTable.Configure();
241228
acHuffmanTable.Configure();
242229

243-
ref FastACTable fastAcTable = ref this.fastACTables[component.ACHuffmanTableId];
244-
fastAcTable.Derive(ref acHuffmanTable);
245-
ref short fastACRef = ref fastAcTable.Lookahead[0];
246-
247230
int mcu = 0;
248231
for (int j = 0; j < h; j++)
249232
{
@@ -252,16 +235,11 @@ private unsafe void ParseBaselineDataNonInterleaved()
252235

253236
for (int i = 0; i < w; i++)
254237
{
255-
// if (this.jpegBuffer.Eof)
256-
// {
257-
// return;
258-
// }
259238
this.DecodeBlockBaseline(
260239
component,
261240
ref Unsafe.Add(ref blockRef, i),
262241
ref dcHuffmanTable,
263-
ref acHuffmanTable,
264-
ref fastACRef);
242+
ref acHuffmanTable);
265243

266244
// Every data block is an MCU, so countdown the restart interval
267245
mcu++;
@@ -447,10 +425,6 @@ ref Unsafe.Add(ref blockRef, i),
447425
ref HuffmanTable acHuffmanTable = ref this.acHuffmanTables[component.ACHuffmanTableId];
448426
acHuffmanTable.Configure();
449427

450-
ref FastACTable fastAcTable = ref this.fastACTables[component.ACHuffmanTableId];
451-
fastAcTable.Derive(ref acHuffmanTable);
452-
ref short fastACRef = ref fastAcTable.Lookahead[0];
453-
454428
int mcu = 0;
455429
for (int j = 0; j < h; j++)
456430
{
@@ -466,8 +440,7 @@ ref Unsafe.Add(ref blockRef, i),
466440

467441
this.DecodeBlockProgressiveAC(
468442
ref Unsafe.Add(ref blockRef, i),
469-
ref acHuffmanTable,
470-
ref fastACRef);
443+
ref acHuffmanTable);
471444

472445
// Every data block is an MCU, so countdown the restart interval
473446
mcu++;
@@ -481,11 +454,11 @@ private void DecodeBlockBaseline(
481454
JpegComponent component,
482455
ref Block8x8 block,
483456
ref HuffmanTable dcTable,
484-
ref HuffmanTable acTable,
485-
ref short fastACRef)
457+
ref HuffmanTable acTable)
486458
{
487459
ref short blockDataRef = ref Unsafe.As<Block8x8, short>(ref block);
488460
HuffmanScanBuffer buffer = this.scanBuffer;
461+
ref ZigZag zigzag = ref this.dctZigZag;
489462

490463
// DC
491464
int t = this.DecodeHuffman(buffer, ref dcTable);
@@ -510,7 +483,7 @@ private void DecodeBlockBaseline(
510483
{
511484
i += r;
512485
s = Receive(buffer, s);
513-
Unsafe.Add(ref blockDataRef, this.dctZigZag[i++]) = (short)s;
486+
Unsafe.Add(ref blockDataRef, zigzag[i++]) = (short)s;
514487
}
515488
else
516489
{
@@ -556,10 +529,7 @@ private static int Receive(HuffmanScanBuffer buffer, int nbits)
556529
return Extend(GetBits(buffer, nbits), nbits);
557530
}
558531

559-
private void DecodeBlockProgressiveDC(
560-
JpegComponent component,
561-
ref Block8x8 block,
562-
ref HuffmanTable dcTable)
532+
private void DecodeBlockProgressiveDC(JpegComponent component, ref Block8x8 block, ref HuffmanTable dcTable)
563533
{
564534
ref short blockDataRef = ref Unsafe.As<Block8x8, short>(ref block);
565535
HuffmanScanBuffer buffer = this.scanBuffer;
@@ -585,10 +555,7 @@ private void DecodeBlockProgressiveDC(
585555
}
586556
}
587557

588-
private void DecodeBlockProgressiveAC(
589-
ref Block8x8 block,
590-
ref HuffmanTable acTable,
591-
ref short fastACRef)
558+
private void DecodeBlockProgressiveAC(ref Block8x8 block, ref HuffmanTable acTable)
592559
{
593560
ref short blockDataRef = ref Unsafe.As<Block8x8, short>(ref block);
594561
if (this.successiveHigh == 0)
@@ -602,6 +569,7 @@ private void DecodeBlockProgressiveAC(
602569
}
603570

604571
HuffmanScanBuffer buffer = this.scanBuffer;
572+
ref ZigZag zigzag = ref this.dctZigZag;
605573
int start = this.spectralStart;
606574
int end = this.spectralEnd;
607575
int low = this.successiveLow;
@@ -617,7 +585,7 @@ private void DecodeBlockProgressiveAC(
617585
if (s != 0)
618586
{
619587
s = Receive(buffer, s);
620-
Unsafe.Add(ref blockDataRef, this.dctZigZag[i]) = (short)(s << low);
588+
Unsafe.Add(ref blockDataRef, zigzag[i]) = (short)(s << low);
621589
}
622590
else
623591
{
@@ -647,6 +615,7 @@ private void DecodeBlockProgressiveACRefined(ref short blockDataRef, ref Huffman
647615
{
648616
// Refinement scan for these AC coefficients
649617
HuffmanScanBuffer buffer = this.scanBuffer;
618+
ref ZigZag zigzag = ref this.dctZigZag;
650619
int start = this.spectralStart;
651620
int end = this.spectralEnd;
652621

@@ -693,8 +662,7 @@ private void DecodeBlockProgressiveACRefined(ref short blockDataRef, ref Huffman
693662

694663
do
695664
{
696-
// C++ TO C# CONVERTER TODO TASK: Pointer arithmetic is detected on this variable, so pointers on this variable are left unchanged:
697-
ref short coef = ref Unsafe.Add(ref blockDataRef, this.dctZigZag[k]);
665+
ref short coef = ref Unsafe.Add(ref blockDataRef, zigzag[k]);
698666
if (coef != 0)
699667
{
700668
buffer.CheckBits();
@@ -720,7 +688,7 @@ private void DecodeBlockProgressiveACRefined(ref short blockDataRef, ref Huffman
720688

721689
if ((s != 0) && (k < 64))
722690
{
723-
Unsafe.Add(ref blockDataRef, this.dctZigZag[k]) = (short)s;
691+
Unsafe.Add(ref blockDataRef, zigzag[k]) = (short)s;
724692
}
725693
}
726694
}
@@ -729,7 +697,7 @@ private void DecodeBlockProgressiveACRefined(ref short blockDataRef, ref Huffman
729697
{
730698
for (; k <= end; k++)
731699
{
732-
ref short coef = ref Unsafe.Add(ref blockDataRef, this.dctZigZag[k]);
700+
ref short coef = ref Unsafe.Add(ref blockDataRef, zigzag[k]);
733701

734702
if (coef != 0)
735703
{
@@ -786,9 +754,9 @@ private bool HandleRestart()
786754

787755
internal sealed class HuffmanScanBuffer
788756
{
789-
private readonly JpegStreamReader stream;
757+
private readonly DoubleBufferedStreamReader stream;
790758

791-
public HuffmanScanBuffer(JpegStreamReader stream)
759+
public HuffmanScanBuffer(DoubleBufferedStreamReader stream)
792760
{
793761
this.stream = stream;
794762
this.Reset();
@@ -857,15 +825,19 @@ public bool HasRestart()
857825
return m >= JpegConstants.Markers.RST0 && m <= JpegConstants.Markers.RST7;
858826
}
859827

860-
[MethodImpl(InliningOptions.ColdPath)]
828+
[MethodImpl(InliningOptions.ShortMethod)]
861829
public void FillBuffer()
862830
{
863831
// Attempt to load at least the minimum number of required bits into the buffer.
864832
// We fail to do so only if we hit a marker or reach the end of the input stream.
865-
//
866-
// TODO: JpegStreamReader we could keep track of marker positions within the
867-
// stream and we could use that knowledge to do a fast cast of bytes to a ulong
868-
// avoiding this loop.
833+
// TODO: Investigate whether a faster path can be taken here.
834+
this.Remain += 48;
835+
this.Data = (this.Data << 48) | this.GetBytes();
836+
}
837+
838+
[MethodImpl(InliningOptions.ColdPath)]
839+
private ulong GetBytes()
840+
{
869841
ulong temp = 0;
870842
for (int i = 0; i < 6; i++)
871843
{
@@ -910,8 +882,7 @@ public void FillBuffer()
910882
temp = (temp << 8) | (ulong)(long)b;
911883
}
912884

913-
this.Remain += 48;
914-
this.Data = (this.Data << 48) | temp;
885+
return temp;
915886
}
916887
}
917888
}

0 commit comments

Comments
 (0)