Browse Source

JpegScanDecoder: ReadBlock() <--> ProcessBlock() split

af/merge-core
Anton Firszov 9 years ago
parent
commit
496914cdea
  1. 104
      src/ImageSharp.Formats.Jpeg/Components/Decoder/JpegScanDecoder.cs

104
src/ImageSharp.Formats.Jpeg/Components/Decoder/JpegScanDecoder.cs

@ -112,6 +112,28 @@ namespace ImageSharp.Formats.Jpg
/// <summary>
/// Reads the blocks from the <see cref="JpegDecoderCore"/>-s stream, and processes them into the corresponding <see cref="JpegPixelArea"/> instances.
/// The blocks are traversed one MCU at a time. For 4:2:0 chroma
/// subsampling, there are four Y 8x8 blocks in every 16x16 MCU.
/// For a baseline 32x16 pixel image, the Y blocks visiting order is:
/// 0 1 4 5
/// 2 3 6 7
/// For progressive images, the interleaved scans (those with component count &gt; 1)
/// are traversed as above, but non-interleaved scans are traversed left
/// to right, top to bottom:
/// 0 1 2 3
/// 4 5 6 7
/// Only DC scans (zigStart == 0) can be interleave AC scans must have
/// only one component.
/// To further complicate matters, for non-interleaved scans, there is no
/// data for any blocks that are inside the image at the MCU level but
/// outside the image at the pixel level. For example, a 24x16 pixel 4:2:0
/// progressive image consists of two 16x16 MCUs. The interleaved scans
/// will process 8 Y blocks:
/// 0 1 4 5
/// 2 3 6 7
/// The non-interleaved scans will process only 6 Y blocks:
/// 0 1 2
/// 3 4 5
/// </summary>
/// <param name="decoder">The <see cref="JpegDecoderCore"/> instance</param>
public void ProcessBlocks(JpegDecoderCore decoder)
@ -132,28 +154,6 @@ namespace ImageSharp.Formats.Jpg
for (int j = 0; j < this.hi * vi; j++)
{
// The blocks are traversed one MCU at a time. For 4:2:0 chroma
// subsampling, there are four Y 8x8 blocks in every 16x16 MCU.
// For a baseline 32x16 pixel image, the Y blocks visiting order is:
// 0 1 4 5
// 2 3 6 7
// For progressive images, the interleaved scans (those with component count > 1)
// are traversed as above, but non-interleaved scans are traversed left
// to right, top to bottom:
// 0 1 2 3
// 4 5 6 7
// Only DC scans (zigStart == 0) can be interleave AC scans must have
// only one component.
// To further complicate matters, for non-interleaved scans, there is no
// data for any blocks that are inside the image at the MCU level but
// outside the image at the pixel level. For example, a 24x16 pixel 4:2:0
// progressive image consists of two 16x16 MCUs. The interleaved scans
// will process 8 Y blocks:
// 0 1 4 5
// 2 3 6 7
// The non-interleaved scans will process only 6 Y blocks:
// 0 1 2
// 3 4 5
if (this.componentScanCount != 1)
{
this.bx = (this.hi * mx) + (j % this.hi);
@ -171,23 +171,8 @@ namespace ImageSharp.Formats.Jpg
}
}
int qtIndex = decoder.ComponentArray[this.componentIndex].Selector;
// TODO: Reading & processing blocks should be done in 2 separate loops. The second one could be parallelized. The first one could be async.
this.data.QuantiazationTable = decoder.QuantizationTables[qtIndex];
// Load the previous partially decoded coefficients, if applicable.
if (decoder.IsProgressive)
{
int blockIndex = this.GetBlockIndex(decoder);
this.data.Block = decoder.DecodedBlocks[this.componentIndex][blockIndex];
}
else
{
this.data.Block.Clear();
}
this.ProcessBlockImpl(decoder, scanIndex);
this.ReadBlock(decoder, scanIndex);
this.ProcessBlock(decoder);
}
// for j
@ -301,12 +286,15 @@ namespace ImageSharp.Formats.Jpg
}
/// <summary>
/// Process the current block at (<see cref="bx"/>, <see cref="by"/>)
/// Read the current the current block at (<see cref="bx"/>, <see cref="by"/>) from the decoders stream
/// </summary>
/// <param name="decoder">The decoder</param>
/// <param name="scanIndex">The index of the scan</param>
private void ProcessBlockImpl(JpegDecoderCore decoder, int scanIndex)
private void ReadBlock(JpegDecoderCore decoder, int scanIndex)
{
int blockIndex = this.GetBlockIndex(decoder);
this.data.Block = decoder.DecodedBlocks[this.componentIndex][blockIndex];
var b = this.pointers.Block;
DecoderErrorCode errorCode;
int huffmannIdx = (AcTableIndex * HuffmanTree.ThRowSize) + this.pointers.ComponentScan[scanIndex].AcTableSelector;
@ -391,23 +379,23 @@ namespace ImageSharp.Formats.Jpg
}
}
if (decoder.IsProgressive)
{
if (this.zigEnd != Block8x8F.ScalarCount - 1 || this.al != 0)
{
// We haven't completely decoded this 8x8 block. Save the coefficients.
decoder.DecodedBlocks[this.componentIndex][this.GetBlockIndex(decoder)] = *b;
// At this point, we could execute the rest of the loop body to dequantize and
// perform the inverse DCT, to save early stages of a progressive image to the
// *image.YCbCr buffers (the whole point of progressive encoding), but in Go,
// the jpeg.Decode function does not return until the entire image is decoded,
// so we "continue" here to avoid wasted computation.
return;
}
}
decoder.DecodedBlocks[this.componentIndex][blockIndex] = this.data.Block;
}
private bool IsProgressiveBlockFinished(JpegDecoderCore decoder)
=> decoder.IsProgressive && (this.zigEnd != Block8x8F.ScalarCount - 1 || this.al != 0);
/// <summary>
/// Dequantize, perform the inverse DCT and store the block to the into the corresponding <see cref="JpegPixelArea"/> instances.
/// </summary>
/// <param name="decoder">The <see cref="JpegDecoderCore"/> instance</param>
private void ProcessBlock(JpegDecoderCore decoder)
{
int qtIndex = decoder.ComponentArray[this.componentIndex].Selector;
this.data.QuantiazationTable = decoder.QuantizationTables[qtIndex];
Block8x8F* b = this.pointers.Block;
// Dequantize, perform the inverse DCT and store the block to the image.
Block8x8F.UnZig(b, this.pointers.QuantiazationTable, this.pointers.Unzig);
DCT.TransformIDCT(ref *b, ref *this.pointers.Temp1, ref *this.pointers.Temp2);
@ -437,7 +425,7 @@ namespace ImageSharp.Formats.Jpg
/// <returns>The index</returns>
private int GetBlockIndex(JpegDecoderCore decoder)
{
return ((this.@by * decoder.MCUCountX) * this.hi) + this.bx;
return ((this.by * decoder.MCUCountX) * this.hi) + this.bx;
}
private void ProcessScanImpl(JpegDecoderCore decoder, int i, ref ComponentScan currentComponentScan, ref int totalHv)

Loading…
Cancel
Save