From 79067778a7de220b4fe60264f05b81f657a6d402 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 22 Jan 2017 14:02:11 +0100 Subject: [PATCH] unsafe version of EnsureNBits --- .../Components/Decoder/Bits.cs | 20 +++++++-- .../Components/Decoder/EOFException.cs | 3 ++ .../JpegScanDecoder.ComputationData.cs | 6 +-- .../Components/Decoder/JpegScanDecoder.cs | 44 ++++++++----------- .../Components/Decoder/JpegScanDecoder.md | 4 +- .../JpegDecoderCore.cs | 11 ++--- 6 files changed, 48 insertions(+), 40 deletions(-) diff --git a/src/ImageSharp.Formats.Jpeg/Components/Decoder/Bits.cs b/src/ImageSharp.Formats.Jpeg/Components/Decoder/Bits.cs index 8e46e18066..f80e75b990 100644 --- a/src/ImageSharp.Formats.Jpeg/Components/Decoder/Bits.cs +++ b/src/ImageSharp.Formats.Jpeg/Components/Decoder/Bits.cs @@ -37,9 +37,24 @@ namespace ImageSharp.Formats.Jpg /// /// The number of bits to ensure. /// Jpeg decoder + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void EnsureNBits(int n, JpegDecoderCore decoder) + { + DecoderErrorCode errorCode = this.EnsureNBitsUnsafe(n, decoder); + errorCode.EnsureNoError(); + } + + /// + /// Reads bytes from the byte buffer to ensure that bits.UnreadBits is at + /// least n. For best performance (avoiding function calls inside hot loops), + /// the caller is the one responsible for first checking that bits.UnreadBits < n. + /// This method does not throw. Returns instead. + /// + /// The number of bits to ensure. + /// Jpeg decoder /// Error code [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal DecoderErrorCode EnsureNBits(int n, JpegDecoderCore decoder) + public DecoderErrorCode EnsureNBitsUnsafe(int n, JpegDecoderCore decoder) { while (true) { @@ -84,8 +99,7 @@ namespace ImageSharp.Formats.Jpg { if (this.UnreadBits < t) { - DecoderErrorCode errorCode = this.EnsureNBits(t, decoder); - errorCode.EnsureNoError(); + this.EnsureNBits(t, decoder); } this.UnreadBits -= t; diff --git a/src/ImageSharp.Formats.Jpeg/Components/Decoder/EOFException.cs b/src/ImageSharp.Formats.Jpeg/Components/Decoder/EOFException.cs index 81857b456c..b695e68123 100644 --- a/src/ImageSharp.Formats.Jpeg/Components/Decoder/EOFException.cs +++ b/src/ImageSharp.Formats.Jpeg/Components/Decoder/EOFException.cs @@ -13,6 +13,9 @@ namespace ImageSharp.Formats.Jpg /// internal class EOFException : Exception { + /// + /// Initializes a new instance of the class. + /// public EOFException() : base("Reached end of stream before proceeding EOI marker!") { diff --git a/src/ImageSharp.Formats.Jpeg/Components/Decoder/JpegScanDecoder.ComputationData.cs b/src/ImageSharp.Formats.Jpeg/Components/Decoder/JpegScanDecoder.ComputationData.cs index ef04bf4188..06f170be5a 100644 --- a/src/ImageSharp.Formats.Jpeg/Components/Decoder/JpegScanDecoder.ComputationData.cs +++ b/src/ImageSharp.Formats.Jpeg/Components/Decoder/JpegScanDecoder.ComputationData.cs @@ -13,7 +13,7 @@ namespace ImageSharp.Formats.Jpg internal unsafe partial struct JpegScanDecoder { /// - /// Holds the "large" data blocks needed for computations + /// Holds the "large" data blocks needed for computations. /// [StructLayout(LayoutKind.Sequential)] public struct ComputationData @@ -44,12 +44,12 @@ namespace ImageSharp.Formats.Jpg public UnzigData Unzig; /// - /// The no-idea-what's this data + /// The buffer storing the -s for each component /// public fixed byte ScanData[3 * JpegDecoderCore.MaxComponents]; /// - /// The DC component values + /// The DC values for each component /// public fixed int Dc[JpegDecoderCore.MaxComponents]; diff --git a/src/ImageSharp.Formats.Jpeg/Components/Decoder/JpegScanDecoder.cs b/src/ImageSharp.Formats.Jpeg/Components/Decoder/JpegScanDecoder.cs index 8c2f079707..ef2ce18883 100644 --- a/src/ImageSharp.Formats.Jpeg/Components/Decoder/JpegScanDecoder.cs +++ b/src/ImageSharp.Formats.Jpeg/Components/Decoder/JpegScanDecoder.cs @@ -2,7 +2,6 @@ // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // - // ReSharper disable InconsistentNaming namespace ImageSharp.Formats.Jpg { @@ -10,8 +9,21 @@ namespace ImageSharp.Formats.Jpg using System.Runtime.CompilerServices; /// - /// Encapsulates the impementation of Jpeg SOS decoder. - /// See JpegScanDecoder.md! + /// Encapsulates the impementation of Jpeg SOS decoder. See JpegScanDecoder.md! + /// and are the spectral selection bounds. + /// and are the successive approximation high and low values. + /// The spec calls these values Ss, Se, Ah and Al. + /// For progressive JPEGs, these are the two more-or-less independent + /// aspects of progression. Spectral selection progression is when not + /// all of a block's 64 DCT coefficients are transmitted in one pass. + /// For example, three passes could transmit coefficient 0 (the DC + /// component), coefficients 1-5, and coefficients 6-63, in zig-zag + /// order. Successive approximation is when not all of the bits of a + /// band of coefficients are transmitted in one pass. For example, + /// three passes could transmit the 6 most significant bits, followed + /// by the second-least significant bit, followed by the least + /// significant bit. + /// For baseline JPEGs, these parameters are hard-coded to 0/63/0/0. /// internal unsafe partial struct JpegScanDecoder { @@ -35,21 +47,6 @@ namespace ImageSharp.Formats.Jpg /// private int by; - // zigStart and zigEnd are the spectral selection bounds. - // ah and al are the successive approximation high and low values. - // The spec calls these values Ss, Se, Ah and Al. - // For progressive JPEGs, these are the two more-or-less independent - // aspects of progression. Spectral selection progression is when not - // all of a block's 64 DCT coefficients are transmitted in one pass. - // For example, three passes could transmit coefficient 0 (the DC - // component), coefficients 1-5, and coefficients 6-63, in zig-zag - // order. Successive approximation is when not all of the bits of a - // band of coefficients are transmitted in one pass. For example, - // three passes could transmit the 6 most significant bits, followed - // by the second-least significant bit, followed by the least - // significant bit. - // For baseline JPEGs, these parameters are hard-coded to 0/63/0/0. - /// /// Start index of the zig-zag selection bound /// @@ -91,14 +88,14 @@ namespace ImageSharp.Formats.Jpg private ushort eobRun; /// - /// The buffer + /// Pointers to elements of /// - private ComputationData data; + private DataPointers pointers; /// - /// Pointers to elements of + /// The buffer /// - private DataPointers pointers; + private ComputationData data; /// /// Initializes the default instance after creation. @@ -320,7 +317,6 @@ namespace ImageSharp.Formats.Jpg else { int zig = this.zigStart; - DecoderErrorCode errorCode; if (zig == 0) { zig++; @@ -335,7 +331,6 @@ namespace ImageSharp.Formats.Jpg } int deltaDC = decoder.Bits.ReceiveExtend(value, decoder); - // errorCode.EnsureNoError(); this.pointers.Dc[this.componentIndex] += deltaDC; @@ -364,7 +359,6 @@ namespace ImageSharp.Formats.Jpg } int ac = decoder.Bits.ReceiveExtend(val1, decoder); - // errorCode.EnsureNoError(); // b[Unzig[zig]] = ac << al; Block8x8F.SetScalarAt(b, this.pointers.Unzig[zig], ac << this.al); diff --git a/src/ImageSharp.Formats.Jpeg/Components/Decoder/JpegScanDecoder.md b/src/ImageSharp.Formats.Jpeg/Components/Decoder/JpegScanDecoder.md index 215f21807b..4ca4d1f642 100644 --- a/src/ImageSharp.Formats.Jpeg/Components/Decoder/JpegScanDecoder.md +++ b/src/ImageSharp.Formats.Jpeg/Components/Decoder/JpegScanDecoder.md @@ -4,7 +4,7 @@ The implementation is optimized to hold most of the necessary data in a single v #### Benefits: - Maximized locality of reference by keeping most of the operation data on the stack -- Reaching this without long parameter lists, most of the values describing the state of the decoder algorithm +- Achieving this without long parameter lists, most of the values describing the state of the decoder algorithm are members of the `JpegScanDecoder` struct - Most of the logic related to Scan decoding is refactored & simplified now to live in the methods of `JpegScanDecoder` - The first step is done towards separating the stream reading from block processing. They can be refactored later to be executed in two disctinct loops. @@ -16,8 +16,8 @@ are members of the `JpegScanDecoder` struct |JpegScanDecoder | |-------------------| |Variables | -|ComputationData | |DataPointers | +|ComputationData | - **ComputationData** holds the "large" data blocks needed for computations (Mostly `Block8x8F`-s) - **DataPointers** contains pointers to the memory regions of `ComponentData` so they can be easily passed around to pointer based utility methods of `Block8x8F` diff --git a/src/ImageSharp.Formats.Jpeg/JpegDecoderCore.cs b/src/ImageSharp.Formats.Jpeg/JpegDecoderCore.cs index 3bb774b69e..aa5158395c 100644 --- a/src/ImageSharp.Formats.Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp.Formats.Jpeg/JpegDecoderCore.cs @@ -431,8 +431,7 @@ namespace ImageSharp.Formats { if (this.Bits.UnreadBits == 0) { - DecoderErrorCode errorCode = this.Bits.EnsureNBits(1, this); - errorCode.EnsureNoError(); + this.Bits.EnsureNBits(1, this); } bool ret = (this.Bits.Accumulator & this.Bits.Mask) != 0; @@ -506,8 +505,7 @@ namespace ImageSharp.Formats { if (this.Bits.UnreadBits < count) { - DecoderErrorCode errorCode = this.Bits.EnsureNBits(count, this); - errorCode.EnsureNoError(); + this.Bits.EnsureNBits(count, this); } uint ret = this.Bits.Accumulator >> (this.Bits.UnreadBits - count); @@ -532,7 +530,7 @@ namespace ImageSharp.Formats if (this.Bits.UnreadBits < 8) { - DecoderErrorCode errorCode = this.Bits.EnsureNBits(8, this); + DecoderErrorCode errorCode = this.Bits.EnsureNBitsUnsafe(8, this); if (errorCode == DecoderErrorCode.NoError) { @@ -561,8 +559,7 @@ namespace ImageSharp.Formats { if (this.Bits.UnreadBits == 0) { - DecoderErrorCode errorCode = this.Bits.EnsureNBits(1, this); - errorCode.EnsureNoError(); + this.Bits.EnsureNBits(1, this); } if ((this.Bits.Accumulator & this.Bits.Mask) != 0)