Browse Source

unsafe version of EnsureNBits

af/merge-core
Anton Firszov 9 years ago
parent
commit
79067778a7
  1. 20
      src/ImageSharp.Formats.Jpeg/Components/Decoder/Bits.cs
  2. 3
      src/ImageSharp.Formats.Jpeg/Components/Decoder/EOFException.cs
  3. 6
      src/ImageSharp.Formats.Jpeg/Components/Decoder/JpegScanDecoder.ComputationData.cs
  4. 44
      src/ImageSharp.Formats.Jpeg/Components/Decoder/JpegScanDecoder.cs
  5. 4
      src/ImageSharp.Formats.Jpeg/Components/Decoder/JpegScanDecoder.md
  6. 11
      src/ImageSharp.Formats.Jpeg/JpegDecoderCore.cs

20
src/ImageSharp.Formats.Jpeg/Components/Decoder/Bits.cs

@ -37,9 +37,24 @@ namespace ImageSharp.Formats.Jpg
/// </summary>
/// <param name="n">The number of bits to ensure.</param>
/// <param name="decoder">Jpeg decoder</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void EnsureNBits(int n, JpegDecoderCore decoder)
{
DecoderErrorCode errorCode = this.EnsureNBitsUnsafe(n, decoder);
errorCode.EnsureNoError();
}
/// <summary>
/// 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 &lt; n.
/// This method does not throw. Returns <see cref="DecoderErrorCode"/> instead.
/// </summary>
/// <param name="n">The number of bits to ensure.</param>
/// <param name="decoder">Jpeg decoder</param>
/// <returns>Error code</returns>
[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;

3
src/ImageSharp.Formats.Jpeg/Components/Decoder/EOFException.cs

@ -13,6 +13,9 @@ namespace ImageSharp.Formats.Jpg
/// </summary>
internal class EOFException : Exception
{
/// <summary>
/// Initializes a new instance of the <see cref="EOFException"/> class.
/// </summary>
public EOFException()
: base("Reached end of stream before proceeding EOI marker!")
{

6
src/ImageSharp.Formats.Jpeg/Components/Decoder/JpegScanDecoder.ComputationData.cs

@ -13,7 +13,7 @@ namespace ImageSharp.Formats.Jpg
internal unsafe partial struct JpegScanDecoder
{
/// <summary>
/// Holds the "large" data blocks needed for computations
/// Holds the "large" data blocks needed for computations.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct ComputationData
@ -44,12 +44,12 @@ namespace ImageSharp.Formats.Jpg
public UnzigData Unzig;
/// <summary>
/// The no-idea-what's this data
/// The buffer storing the <see cref="ComponentScan"/>-s for each component
/// </summary>
public fixed byte ScanData[3 * JpegDecoderCore.MaxComponents];
/// <summary>
/// The DC component values
/// The DC values for each component
/// </summary>
public fixed int Dc[JpegDecoderCore.MaxComponents];

44
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.
// </copyright>
// ReSharper disable InconsistentNaming
namespace ImageSharp.Formats.Jpg
{
@ -10,8 +9,21 @@ namespace ImageSharp.Formats.Jpg
using System.Runtime.CompilerServices;
/// <summary>
/// Encapsulates the impementation of Jpeg SOS decoder.
/// See JpegScanDecoder.md!
/// Encapsulates the impementation of Jpeg SOS decoder. See JpegScanDecoder.md!
/// <see cref="zigStart"/> and <see cref="zigEnd"/> are the spectral selection bounds.
/// <see cref="ah"/> and <see cref="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.
/// </summary>
internal unsafe partial struct JpegScanDecoder
{
@ -35,21 +47,6 @@ namespace ImageSharp.Formats.Jpg
/// </summary>
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.
/// <summary>
/// Start index of the zig-zag selection bound
/// </summary>
@ -91,14 +88,14 @@ namespace ImageSharp.Formats.Jpg
private ushort eobRun;
/// <summary>
/// The <see cref="ComputationData"/> buffer
/// Pointers to elements of <see cref="data"/>
/// </summary>
private ComputationData data;
private DataPointers pointers;
/// <summary>
/// Pointers to elements of <see cref="data"/>
/// The <see cref="ComputationData"/> buffer
/// </summary>
private DataPointers pointers;
private ComputationData data;
/// <summary>
/// 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);

4
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`

11
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)

Loading…
Cancel
Save