示例#1
0
            public void IDCT2D8x4_RightPart()
            {
                float[] sourceArray       = Create8x8FloatData();
                var     expectedDestArray = new float[64];

                ReferenceImplementations.LLM_FloatingPoint_DCT.IDCT2D8x4_32f(sourceArray.AsSpan(4), expectedDestArray.AsSpan(4));

                var source = default(Block8x8F);

                source.LoadFrom(sourceArray);

                var dest = default(Block8x8F);

                FastFloatingPointDCT.IDCT8x4_RightPart(ref source, ref dest);

                var actualDestArray = new float[64];

                dest.CopyTo(actualDestArray);

                this.Print8x8Data(expectedDestArray);
                this.Output.WriteLine("**************");
                this.Print8x8Data(actualDestArray);

                Assert.Equal(expectedDestArray, actualDestArray);
            }
示例#2
0
            public void LLM_TransformIDCT_CompareToAccurate(int seed)
            {
                float[] sourceArray = Create8x8RoundedRandomFloatData(MinAllowedValue, MaxAllowedValue, seed);

                var srcBlock = Block8x8F.Load(sourceArray);

                // reference
                Block8x8F expected = ReferenceImplementations.AccurateDCT.TransformIDCT(ref srcBlock);

                // testee
                // Part of the IDCT calculations is fused into the quantization step
                // We must multiply input block with adjusted no-quantization matrix
                // before applying IDCT
                // Dequantization using unit matrix - no values are upscaled
                Block8x8F dequantMatrix = CreateBlockFromScalar(1);

                // This step is needed to apply adjusting multipliers to the input block
                FastFloatingPointDCT.AdjustToIDCT(ref dequantMatrix);

                // IDCT implementation tranforms blocks after transposition
                srcBlock.TransposeInplace();
                srcBlock.MultiplyInPlace(ref dequantMatrix);

                // IDCT calculation
                FastFloatingPointDCT.TransformIDCT(ref srcBlock);

                this.CompareBlocks(expected, srcBlock, 1f);
            }
示例#3
0
                static void RunTest(string serialized)
                {
                    int seed = FeatureTestRunner.Deserialize <int>(serialized);

                    Span <float> src      = Create8x8RoundedRandomFloatData(-200, 200, seed);
                    var          srcBlock = default(Block8x8F);

                    srcBlock.LoadFrom(src);

                    var expectedDest = new float[64];
                    var temp1        = new float[64];
                    var temp2        = default(Block8x8F);

                    // reference
                    ReferenceImplementations.LLM_FloatingPoint_DCT.IDCT2D_llm(src, expectedDest, temp1);

                    // testee
                    FastFloatingPointDCT.TransformIDCT(ref srcBlock, ref temp2);

                    var actualDest = new float[64];

                    srcBlock.ScaledCopyTo(actualDest);

                    Assert.Equal(actualDest, expectedDest, new ApproximateFloatComparer(1f));
                }
示例#4
0
                static void RunTest(string serialized)
                {
                    int seed = FeatureTestRunner.Deserialize <int>(serialized);

                    Span <float> src   = Create8x8RoundedRandomFloatData(-200, 200, seed);
                    var          block = default(Block8x8F);

                    block.LoadFrom(src);

                    float[] expectedDest = new float[64];
                    float[] temp1        = new float[64];

                    // reference
                    ReferenceImplementations.LLM_FloatingPoint_DCT.FDCT2D_llm(src, expectedDest, temp1, downscaleBy8: true);

                    // testee
                    // Part of the FDCT calculations is fused into the quantization step
                    // We must multiply transformed block with reciprocal values from FastFloatingPointDCT.ANN_DCT_reciprocalAdjustmen
                    FastFloatingPointDCT.TransformFDCT(ref block);
                    for (int i = 0; i < 64; i++)
                    {
                        block[i] = block[i] * FastFloatingPointDCT.DctReciprocalAdjustmentCoefficients[i];
                    }

                    float[] actualDest = block.ToArray();

                    Assert.Equal(expectedDest, actualDest, new ApproximateFloatComparer(1f));
                }
示例#5
0
                static void RunTest(string serialized)
                {
                    int seed = FeatureTestRunner.Deserialize <int>(serialized);

                    Span <float> src   = Create8x8RoundedRandomFloatData(MinAllowedValue, MaxAllowedValue, seed);
                    var          block = default(Block8x8F);

                    block.LoadFrom(src);

                    float[] expectedDest = new float[64];
                    float[] temp1        = new float[64];

                    // reference
                    ReferenceImplementations.LLM_FloatingPoint_DCT.FDCT2D_llm(src, expectedDest, temp1, downscaleBy8: true);

                    // testee
                    // Second transpose call is done by Quantize step
                    // Do this manually here just to be complient to the reference implementation
                    FastFloatingPointDCT.TransformFDCT(ref block);
                    block.TransposeInplace();

                    // Part of the IDCT calculations is fused into the quantization step
                    // We must multiply input block with adjusted no-quantization matrix
                    // after applying FDCT
                    Block8x8F quantMatrix = CreateBlockFromScalar(1);

                    FastFloatingPointDCT.AdjustToFDCT(ref quantMatrix);
                    block.MultiplyInPlace(ref quantMatrix);

                    float[] actualDest = block.ToArray();

                    Assert.Equal(expectedDest, actualDest, new ApproximateFloatComparer(1f));
                }
示例#6
0
            public void IDCT8x8_Avx(int seed)
            {
#if SUPPORTS_RUNTIME_INTRINSICS
                if (!Avx.IsSupported)
                {
                    this.Output.WriteLine("No AVX present, skipping test!");
                }

                Span <float> src      = Create8x8RoundedRandomFloatData(-200, 200, seed);
                Block8x8F    srcBlock = default;
                srcBlock.LoadFrom(src);

                Block8x8F destBlock = default;

                float[] expectedDest = new float[64];

                // reference, left part
                ReferenceImplementations.LLM_FloatingPoint_DCT.IDCT2D8x4_32f(src, expectedDest);

                // reference, right part
                ReferenceImplementations.LLM_FloatingPoint_DCT.IDCT2D8x4_32f(src.Slice(4), expectedDest.AsSpan(4));

                // testee, whole 8x8
                FastFloatingPointDCT.IDCT8x8_Avx(ref srcBlock, ref destBlock);

                float[] actualDest = new float[64];
                destBlock.ScaledCopyTo(actualDest);

                Assert.Equal(actualDest, expectedDest, new ApproximateFloatComparer(1f));
#endif
            }
示例#7
0
        /// <summary>
        /// Writes a block of pixel data using the given quantization table,
        /// returning the post-quantized DC value of the DCT-transformed block.
        /// The block is in natural (not zig-zag) order.
        /// </summary>
        /// <param name="index">The quantization table index.</param>
        /// <param name="prevDC">The previous DC value.</param>
        /// <param name="src">Source block</param>
        /// <param name="tempDest1">Temporal block to be used as FDCT Destination</param>
        /// <param name="tempDest2">Temporal block 2</param>
        /// <param name="quant">Quantization table</param>
        /// <param name="unzigPtr">The 8x8 Unzig block pointer</param>
        /// <returns>
        /// The <see cref="int"/>
        /// </returns>
        private int WriteBlock(
            QuantIndex index,
            int prevDC,
            Block8x8F *src,
            Block8x8F *tempDest1,
            Block8x8F *tempDest2,
            Block8x8F *quant,
            byte *unzigPtr)
        {
            FastFloatingPointDCT.TransformFDCT(ref *src, ref *tempDest1, ref *tempDest2);

            Block8x8F.Quantize(tempDest1, tempDest2, quant, unzigPtr);
            float *unziggedDestPtr = (float *)tempDest2;

            int dc = (int)unziggedDestPtr[0];

            // Emit the DC delta.
            this.EmitHuffRLE((HuffIndex)((2 * (int)index) + 0), 0, dc - prevDC);

            // Emit the AC components.
            var h         = (HuffIndex)((2 * (int)index) + 1);
            int runLength = 0;

            for (int zig = 1; zig < Block8x8F.Size; zig++)
            {
                int ac = (int)unziggedDestPtr[zig];

                if (ac == 0)
                {
                    runLength++;
                }
                else
                {
                    while (runLength > 15)
                    {
                        this.EmitHuff(h, 0xf0);
                        runLength -= 16;
                    }

                    this.EmitHuffRLE(h, runLength, ac);
                    runLength = 0;
                }
            }

            if (runLength > 0)
            {
                this.EmitHuff(h, 0x00);
            }

            return(dc);
        }
示例#8
0
        /// <summary>
        /// Writes a block of pixel data using the given quantization table,
        /// returning the post-quantized DC value of the DCT-transformed block.
        /// The block is in natural (not zig-zag) order.
        /// </summary>
        /// <param name="index">The quantization table index.</param>
        /// <param name="prevDC">The previous DC value.</param>
        /// <param name="src">Source block</param>
        /// <param name="tempDest1">Temporal block to be used as FDCT Destination</param>
        /// <param name="tempDest2">Temporal block 2</param>
        /// <param name="quant">Quantization table</param>
        /// <param name="unZig">The 8x8 Unzig block.</param>
        /// <param name="emitBufferBase">The reference to the emit buffer.</param>
        /// <returns>The <see cref="int"/>.</returns>
        private int WriteBlock(
            QuantIndex index,
            int prevDC,
            ref Block8x8F src,
            ref Block8x8F tempDest1,
            ref Block8x8F tempDest2,
            ref Block8x8F quant,
            ref ZigZag unZig,
            ref byte emitBufferBase)
        {
            FastFloatingPointDCT.TransformFDCT(ref src, ref tempDest1, ref tempDest2);

            Block8x8F.Quantize(ref tempDest1, ref tempDest2, ref quant, ref unZig);

            int dc = (int)tempDest2[0];

            // Emit the DC delta.
            this.EmitHuffRLE((HuffIndex)((2 * (int)index) + 0), 0, dc - prevDC, ref emitBufferBase);

            // Emit the AC components.
            var h         = (HuffIndex)((2 * (int)index) + 1);
            int runLength = 0;

            for (int zig = 1; zig < Block8x8F.Size; zig++)
            {
                int ac = (int)tempDest2[zig];

                if (ac == 0)
                {
                    runLength++;
                }
                else
                {
                    while (runLength > 15)
                    {
                        this.EmitHuff(h, 0xf0, ref emitBufferBase);
                        runLength -= 16;
                    }

                    this.EmitHuffRLE(h, runLength, ac, ref emitBufferBase);
                    runLength = 0;
                }
            }

            if (runLength > 0)
            {
                this.EmitHuff(h, 0x00, ref emitBufferBase);
            }

            return(dc);
        }
示例#9
0
            public void LLM_TransformIDCT_CompareToAccurate(int seed)
            {
                float[] sourceArray = Create8x8RoundedRandomFloatData(-1000, 1000, seed);

                var srcBlock = Block8x8F.Load(sourceArray);

                Block8x8F expected = ReferenceImplementations.AccurateDCT.TransformIDCT(ref srcBlock);

                var temp = default(Block8x8F);

                FastFloatingPointDCT.TransformIDCT(ref srcBlock, ref temp);

                this.CompareBlocks(expected, srcBlock, 1f);
            }
示例#10
0
            public void LLM_TransformIDCT_CompareToNonOptimized(int seed)
            {
                float[] sourceArray = Create8x8RoundedRandomFloatData(-1000, 1000, seed);

                var source = Block8x8F.Load(sourceArray);

                Block8x8F expected = ReferenceImplementations.LLM_FloatingPoint_DCT.TransformIDCT(ref source);

                var temp   = default(Block8x8F);
                var actual = default(Block8x8F);

                FastFloatingPointDCT.TransformIDCT(ref source, ref actual, ref temp);

                this.CompareBlocks(expected, actual, 1f);
            }
示例#11
0
        /// <summary>
        /// Convert raw spectral DCT data to color data and copy it to the color buffer <see cref="ColorBuffer"/>.
        /// </summary>
        public void CopyBlocksToColorBuffer(int spectralStep)
        {
            Buffer2D <Block8x8> spectralBuffer = this.component.SpectralBlocks;

            float maximumValue = this.frame.MaxColorChannelValue;

            int destAreaStride = this.ColorBuffer.Width;

            int yBlockStart = spectralStep * this.blockRowsPerStep;

            Size subSamplingDivisors = this.component.SubSamplingDivisors;

            Block8x8F dequantTable   = this.rawJpeg.QuantizationTables[this.component.QuantizationTableIndex];
            Block8x8F workspaceBlock = default;

            for (int y = 0; y < this.blockRowsPerStep; y++)
            {
                int yBuffer = y * this.blockAreaSize.Height;

                Span <float>    colorBufferRow = this.ColorBuffer.DangerousGetRowSpan(yBuffer);
                Span <Block8x8> blockRow       = spectralBuffer.DangerousGetRowSpan(yBlockStart + y);

                for (int xBlock = 0; xBlock < spectralBuffer.Width; xBlock++)
                {
                    // Integer to float
                    workspaceBlock.LoadFrom(ref blockRow[xBlock]);

                    // Dequantize
                    workspaceBlock.MultiplyInPlace(ref dequantTable);

                    // Convert from spectral to color
                    FastFloatingPointDCT.TransformIDCT(ref workspaceBlock);

                    // To conform better to libjpeg we actually NEED TO loose precision here.
                    // This is because they store blocks as Int16 between all the operations.
                    // To be "more accurate", we need to emulate this by rounding!
                    workspaceBlock.NormalizeColorsAndRoundInPlace(maximumValue);

                    // Write to color buffer acording to sampling factors
                    int xColorBufferStart = xBlock * this.blockAreaSize.Width;
                    workspaceBlock.ScaledCopyTo(
                        ref colorBufferRow[xColorBufferStart],
                        destAreaStride,
                        subSamplingDivisors.Width,
                        subSamplingDivisors.Height);
                }
            }
        }
示例#12
0
            public void FDCT8x4_RightPart(int seed)
            {
                Span <float> src      = Create8x8RoundedRandomFloatData(-200, 200, seed);
                var          srcBlock = new Block8x8F();

                srcBlock.LoadFrom(src);

                var destBlock = new Block8x8F();

                float[] expectedDest = new float[64];

                ReferenceImplementations.LLM_FloatingPoint_DCT.fDCT2D8x4_32f(src.Slice(4), expectedDest.AsSpan(4));
                FastFloatingPointDCT.FDCT8x4_RightPart(ref srcBlock, ref destBlock);

                float[] actualDest = new float[64];
                destBlock.CopyTo(actualDest);

                Assert.Equal(actualDest, expectedDest, new ApproximateFloatComparer(1f));
            }
示例#13
0
            public void FDCT8x4_LeftPart(int seed)
            {
                Span <float> src      = Create8x8RoundedRandomFloatData(-200, 200, seed);
                var          srcBlock = default(Block8x8F);

                srcBlock.LoadFrom(src);

                var destBlock = default(Block8x8F);

                var expectedDest = new float[64];

                ReferenceImplementations.LLM_FloatingPoint_DCT.FDCT2D8x4_32f(src, expectedDest);
                FastFloatingPointDCT.FDCT8x4_LeftPart(ref srcBlock, ref destBlock);

                var actualDest = new float[64];

                destBlock.ScaledCopyTo(actualDest);

                Assert.Equal(actualDest, expectedDest, new ApproximateFloatComparer(1f));
            }
示例#14
0
            public void TransformFDCT(int seed)
            {
                Span <float> src      = Create8x8RoundedRandomFloatData(-200, 200, seed);
                var          srcBlock = new Block8x8F();

                srcBlock.LoadFrom(src);

                var destBlock = new Block8x8F();

                float[] expectedDest = new float[64];
                float[] temp1        = new float[64];
                var     temp2        = new Block8x8F();

                ReferenceImplementations.LLM_FloatingPoint_DCT.fDCT2D_llm(src, expectedDest, temp1, downscaleBy8: true);
                FastFloatingPointDCT.TransformFDCT(ref srcBlock, ref destBlock, ref temp2, false);

                float[] actualDest = new float[64];
                destBlock.CopyTo(actualDest);

                Assert.Equal(actualDest, expectedDest, new ApproximateFloatComparer(1f));
            }
示例#15
0
                static void RunTest(string serialized)
                {
                    int seed = FeatureTestRunner.Deserialize <int>(serialized);

                    Span <float> src      = Create8x8RoundedRandomFloatData(MinAllowedValue, MaxAllowedValue, seed);
                    var          srcBlock = default(Block8x8F);

                    srcBlock.LoadFrom(src);

                    float[] expectedDest = new float[64];
                    float[] temp         = new float[64];

                    // reference
                    ReferenceImplementations.LLM_FloatingPoint_DCT.IDCT2D_llm(src, expectedDest, temp);

                    // testee
                    // Part of the IDCT calculations is fused into the quantization step
                    // We must multiply input block with adjusted no-quantization matrix
                    // before applying IDCT
                    Block8x8F dequantMatrix = CreateBlockFromScalar(1);

                    // Dequantization using unit matrix - no values are upscaled
                    // as quant matrix is all 1's
                    // This step is needed to apply adjusting multipliers to the input block
                    FastFloatingPointDCT.AdjustToIDCT(ref dequantMatrix);
                    srcBlock.MultiplyInPlace(ref dequantMatrix);

                    // IDCT implementation tranforms blocks after transposition
                    srcBlock.TransposeInplace();

                    // IDCT calculation
                    FastFloatingPointDCT.TransformIDCT(ref srcBlock);

                    float[] actualDest = srcBlock.ToArray();

                    Assert.Equal(actualDest, expectedDest, new ApproximateFloatComparer(1f));
                }
示例#16
0
            public void iDCT2D8x4_LeftPart()
            {
                float[] sourceArray       = JpegFixture.Create8x8FloatData();
                float[] expectedDestArray = new float[64];

                ReferenceImplementations.LLM_FloatingPoint_DCT.iDCT2D8x4_32f(sourceArray, expectedDestArray);

                var source = new Block8x8F();

                source.LoadFrom(sourceArray);

                var dest = new Block8x8F();

                FastFloatingPointDCT.IDCT8x4_LeftPart(ref source, ref dest);

                float[] actualDestArray = new float[64];
                dest.CopyTo(actualDestArray);

                this.Print8x8Data(expectedDestArray);
                this.Output.WriteLine("**************");
                this.Print8x8Data(actualDestArray);

                Assert.Equal(expectedDestArray, actualDestArray);
            }
示例#17
0
        public override void ProcessScan(ref JpegReader reader, JpegScanHeader scanHeader)
        {
            JpegFrameHeader       frameHeader  = _frameHeader;
            JpegBlockOutputWriter?outputWriter = Decoder.GetOutputWriter();

            if (frameHeader.Components is null)
            {
                ThrowInvalidDataException();
            }
            if (scanHeader.Components is null)
            {
                ThrowInvalidDataException();
            }
            if (outputWriter is null)
            {
                ThrowInvalidDataException();
            }

            // Resolve each component
            Span <JpegArithmeticDecodingComponent> components = _components.AsSpan(0, InitDecodeComponents(frameHeader, scanHeader, _components));

            foreach (JpegArithmeticDecodingComponent component in _components)
            {
                component.DcPredictor = 0;
                component.DcContext   = 0;
                component.DcStatistics?.Reset();
                component.AcStatistics?.Reset();
            }

            Reset();

            // Prepare
            int           maxHorizontalSampling = _maxHorizontalSampling;
            int           maxVerticalSampling   = _maxVerticalSampling;
            int           mcusBeforeRestart     = _restartInterval;
            int           mcusPerLine           = _mcusPerLine;
            int           mcusPerColumn         = _mcusPerColumn;
            int           levelShift            = _levelShift;
            JpegBitReader bitReader             = new JpegBitReader(reader.RemainingBytes);

            // DCT Block
            JpegBlock8x8F blockFBuffer  = default;
            JpegBlock8x8F outputFBuffer = default;
            JpegBlock8x8F tempFBuffer   = default;

            JpegBlock8x8 outputBuffer;

            for (int rowMcu = 0; rowMcu < mcusPerColumn; rowMcu++)
            {
                int offsetY = rowMcu * maxVerticalSampling;
                for (int colMcu = 0; colMcu < mcusPerLine; colMcu++)
                {
                    int offsetX = colMcu * maxHorizontalSampling;

                    // Scan an interleaved mcu... process components in order
                    foreach (JpegArithmeticDecodingComponent component in components)
                    {
                        int index = component.ComponentIndex;
                        int h     = component.HorizontalSamplingFactor;
                        int v     = component.VerticalSamplingFactor;
                        int hs    = component.HorizontalSubsamplingFactor;
                        int vs    = component.VerticalSubsamplingFactor;

                        for (int y = 0; y < v; y++)
                        {
                            int blockOffsetY = (offsetY + y) * 8;
                            for (int x = 0; x < h; x++)
                            {
                                // Read MCU
                                outputBuffer = default;
                                ReadBlock(ref bitReader, component, ref outputBuffer);

                                // Dequantization
                                DequantizeBlockAndUnZigZag(component.QuantizationTable, ref outputBuffer, ref blockFBuffer);

                                // IDCT
                                FastFloatingPointDCT.TransformIDCT(ref blockFBuffer, ref outputFBuffer, ref tempFBuffer);

                                // Level shift
                                ShiftDataLevel(ref outputFBuffer, ref outputBuffer, levelShift);

                                // CopyToOutput
                                WriteBlock(outputWriter, ref Unsafe.As <JpegBlock8x8, short>(ref outputBuffer), index, (offsetX + x) * 8, blockOffsetY, hs, vs);
                            }
                        }
                    }

                    // Handle restart
                    if (_restartInterval > 0 && (--mcusBeforeRestart) == 0)
                    {
                        bitReader.AdvanceAlignByte();

                        JpegMarker marker = bitReader.TryReadMarker();
                        if (marker == JpegMarker.EndOfImage)
                        {
                            int bytesConsumedEoi = reader.RemainingByteCount - bitReader.RemainingBits / 8;
                            reader.TryAdvance(bytesConsumedEoi - 2);
                            return;
                        }
                        if (!marker.IsRestartMarker())
                        {
                            throw new InvalidOperationException("Expect restart marker.");
                        }

                        mcusBeforeRestart = _restartInterval;

                        foreach (JpegArithmeticDecodingComponent component in components)
                        {
                            component.DcPredictor = 0;
                            component.DcContext   = 0;
                            component.DcStatistics?.Reset();
                            component.AcStatistics?.Reset();
                        }

                        Reset();
                    }
                }
            }

            bitReader.AdvanceAlignByte();
            int bytesConsumed = reader.RemainingByteCount - bitReader.RemainingBits / 8;

            if (bitReader.TryPeekMarker() != 0)
            {
                if (!bitReader.TryPeekMarker().IsRestartMarker())
                {
                    bytesConsumed -= 2;
                }
            }
            reader.TryAdvance(bytesConsumed);
        }