Example #1
0
 /// <summary>
 /// Writes data to "Define Quantization Tables" block for QuantIndex
 /// </summary>
 /// <param name="dqt">The "Define Quantization Tables" block</param>
 /// <param name="offset">Offset in "Define Quantization Tables" block</param>
 /// <param name="i">The quantization index</param>
 /// <param name="quant">The quantization table to copy data from</param>
 private static void WriteDataToDqt(byte[] dqt, ref int offset, QuantIndex i, ref Block8x8F quant)
 {
     dqt[offset++] = (byte)i;
     for (int j = 0; j < Block8x8F.Size; j++)
     {
         dqt[offset++] = (byte)quant[j];
     }
 }
Example #2
0
        public static void IDCT8x4_LeftPart(ref Block8x8F s, ref Block8x8F d)
        {
            Vector4 my1 = s.V1L;
            Vector4 my7 = s.V7L;
            Vector4 mz0 = my1 + my7;

            Vector4 my3 = s.V3L;
            Vector4 mz2 = my3 + my7;
            Vector4 my5 = s.V5L;
            Vector4 mz1 = my3 + my5;
            Vector4 mz3 = my1 + my5;

            Vector4 mz4 = (mz0 + mz1) * C_1_175876;

            mz2 = (mz2 * C_1_961571) + mz4;
            mz3 = (mz3 * C_0_390181) + mz4;
            mz0 = mz0 * C_0_899976;
            mz1 = mz1 * C_2_562915;

            Vector4 mb3 = (my7 * C_0_298631) + mz0 + mz2;
            Vector4 mb2 = (my5 * C_2_053120) + mz1 + mz3;
            Vector4 mb1 = (my3 * C_3_072711) + mz1 + mz2;
            Vector4 mb0 = (my1 * C_1_501321) + mz0 + mz3;

            Vector4 my2 = s.V2L;
            Vector4 my6 = s.V6L;

            mz4 = (my2 + my6) * C_0_541196;
            Vector4 my0 = s.V0L;
            Vector4 my4 = s.V4L;

            mz0 = my0 + my4;
            mz1 = my0 - my4;

            mz2 = mz4 + (my6 * C_1_847759);
            mz3 = mz4 + (my2 * C_0_765367);

            my0 = mz0 + mz3;
            my3 = mz0 - mz3;
            my1 = mz1 + mz2;
            my2 = mz1 - mz2;

            d.V0L = my0 + mb0;
            d.V7L = my0 - mb0;
            d.V1L = my1 + mb1;
            d.V6L = my1 - mb1;
            d.V2L = my2 + mb2;
            d.V5L = my2 - mb2;
            d.V3L = my3 + mb3;
            d.V4L = my3 - mb3;
        }
Example #3
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.
            HuffIndex 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);
        }
Example #4
0
        /// <summary>
        /// Encodes the image with no subsampling.
        /// </summary>
        /// <typeparam name="TPixel">The pixel format.</typeparam>
        /// <param name="pixels">The pixel accessor providing access to the image pixels.</param>
        private void Encode444 <TPixel>(Image <TPixel> pixels)
            where TPixel : struct, IPixel <TPixel>
        {
            // TODO: Need a JpegScanEncoder<TPixel> class or struct that encapsulates the scan-encoding implementation. (Similar to JpegScanDecoder.)
            // (Partially done with YCbCrForwardConverter<TPixel>)
            Block8x8F temp1 = default(Block8x8F);
            Block8x8F temp2 = default(Block8x8F);

            Block8x8F onStackLuminanceQuantTable   = this.luminanceQuantTable;
            Block8x8F onStackChrominanceQuantTable = this.chrominanceQuantTable;

            ZigZag unzig = ZigZag.CreateUnzigTable();

            // ReSharper disable once InconsistentNaming
            int prevDCY = 0, prevDCCb = 0, prevDCCr = 0;

            YCbCrForwardConverter <TPixel> pixelConverter = YCbCrForwardConverter <TPixel> .Create();

            for (int y = 0; y < pixels.Height; y += 8)
            {
                for (int x = 0; x < pixels.Width; x += 8)
                {
                    pixelConverter.Convert(pixels.Frames.RootFrame, x, y);

                    prevDCY = this.WriteBlock(
                        QuantIndex.Luminance,
                        prevDCY,
                        &pixelConverter.Y,
                        &temp1,
                        &temp2,
                        &onStackLuminanceQuantTable,
                        unzig.Data);
                    prevDCCb = this.WriteBlock(
                        QuantIndex.Chrominance,
                        prevDCCb,
                        &pixelConverter.Cb,
                        &temp1,
                        &temp2,
                        &onStackChrominanceQuantTable,
                        unzig.Data);
                    prevDCCr = this.WriteBlock(
                        QuantIndex.Chrominance,
                        prevDCCr,
                        &pixelConverter.Cr,
                        &temp1,
                        &temp2,
                        &onStackChrominanceQuantTable,
                        unzig.Data);
                }
            }
        }
Example #5
0
        /// <summary>
        /// Apply floating point IDCT transformation into dest, using a temporary block 'temp' provided by the caller (optimization).
        /// Ported from https://github.com/norishigefukushima/dct_simd/blob/master/dct/dct8x8_simd.cpp#L239
        /// </summary>
        /// <param name="src">Source</param>
        /// <param name="dest">Destination</param>
        /// <param name="temp">Temporary block provided by the caller</param>
        public static void TransformIDCT(ref Block8x8F src, ref Block8x8F dest, ref Block8x8F temp)
        {
            // TODO: Transpose is a bottleneck now. We need full AVX support to optimize it:
            // https://github.com/dotnet/corefx/issues/22940
            src.TransposeInto(ref temp);

            IDCT8x4_LeftPart(ref temp, ref dest);
            IDCT8x4_RightPart(ref temp, ref dest);

            dest.TransposeInto(ref temp);

            IDCT8x4_LeftPart(ref temp, ref dest);
            IDCT8x4_RightPart(ref temp, ref dest);

            // TODO: What if we leave the blocks in a scaled-by-x8 state until final color packing?
            dest.MultiplyInplace(C_0_125);
        }
Example #6
0
        /// <summary>
        /// Initializes quantization table.
        /// </summary>
        /// <param name="i">The quantization index.</param>
        /// <param name="scale">The scaling factor.</param>
        /// <param name="quant">The quantization table.</param>
        private static void InitQuantizationTable(int i, int scale, ref Block8x8F quant)
        {
            for (int j = 0; j < Block8x8F.Size; j++)
            {
                int x = UnscaledQuant[i, j];
                x = ((x * scale) + 50) / 100;
                if (x < 1)
                {
                    x = 1;
                }

                if (x > 255)
                {
                    x = 255;
                }

                quant[j] = x;
            }
        }
Example #7
0
        /// <summary>
        /// Apply floating point IDCT transformation into dest, using a temporary block 'temp' provided by the caller (optimization)
        /// </summary>
        /// <param name="src">Source</param>
        /// <param name="dest">Destination</param>
        /// <param name="temp">Temporary block provided by the caller</param>
        /// <param name="offsetSourceByNeg128">If true, a constant -128.0 offset is applied for all values before FDCT </param>
        public static void TransformFDCT(
            ref Block8x8F src,
            ref Block8x8F dest,
            ref Block8x8F temp,
            bool offsetSourceByNeg128 = true)
        {
            src.TransposeInto(ref temp);
            if (offsetSourceByNeg128)
            {
                temp.AddToAllInplace(new Vector4(-128));
            }

            FDCT8x4_LeftPart(ref temp, ref dest);
            FDCT8x4_RightPart(ref temp, ref dest);

            dest.TransposeInto(ref temp);

            FDCT8x4_LeftPart(ref temp, ref dest);
            FDCT8x4_RightPart(ref temp, ref dest);

            dest.MultiplyInplace(C_0_125);
        }
Example #8
0
        public void TransposeInto(ref Block8x8F d)
        {
            d.V0L.X = V0L.X;
            d.V1L.X = V0L.Y;
            d.V2L.X = V0L.Z;
            d.V3L.X = V0L.W;
            d.V4L.X = V0R.X;
            d.V5L.X = V0R.Y;
            d.V6L.X = V0R.Z;
            d.V7L.X = V0R.W;

            d.V0L.Y = V1L.X;
            d.V1L.Y = V1L.Y;
            d.V2L.Y = V1L.Z;
            d.V3L.Y = V1L.W;
            d.V4L.Y = V1R.X;
            d.V5L.Y = V1R.Y;
            d.V6L.Y = V1R.Z;
            d.V7L.Y = V1R.W;

            d.V0L.Z = V2L.X;
            d.V1L.Z = V2L.Y;
            d.V2L.Z = V2L.Z;
            d.V3L.Z = V2L.W;
            d.V4L.Z = V2R.X;
            d.V5L.Z = V2R.Y;
            d.V6L.Z = V2R.Z;
            d.V7L.Z = V2R.W;

            d.V0L.W = V3L.X;
            d.V1L.W = V3L.Y;
            d.V2L.W = V3L.Z;
            d.V3L.W = V3L.W;
            d.V4L.W = V3R.X;
            d.V5L.W = V3R.Y;
            d.V6L.W = V3R.Z;
            d.V7L.W = V3R.W;

            d.V0R.X = V4L.X;
            d.V1R.X = V4L.Y;
            d.V2R.X = V4L.Z;
            d.V3R.X = V4L.W;
            d.V4R.X = V4R.X;
            d.V5R.X = V4R.Y;
            d.V6R.X = V4R.Z;
            d.V7R.X = V4R.W;

            d.V0R.Y = V5L.X;
            d.V1R.Y = V5L.Y;
            d.V2R.Y = V5L.Z;
            d.V3R.Y = V5L.W;
            d.V4R.Y = V5R.X;
            d.V5R.Y = V5R.Y;
            d.V6R.Y = V5R.Z;
            d.V7R.Y = V5R.W;

            d.V0R.Z = V6L.X;
            d.V1R.Z = V6L.Y;
            d.V2R.Z = V6L.Z;
            d.V3R.Z = V6L.W;
            d.V4R.Z = V6R.X;
            d.V5R.Z = V6R.Y;
            d.V6R.Z = V6R.Z;
            d.V7R.Z = V6R.W;

            d.V0R.W = V7L.X;
            d.V1R.W = V7L.Y;
            d.V2R.W = V7L.Z;
            d.V3R.W = V7L.W;
            d.V4R.W = V7R.X;
            d.V5R.W = V7R.Y;
            d.V6R.W = V7R.Z;
            d.V7R.W = V7R.W;
        }
Example #9
0
        /// <summary>
        /// Encodes the image with subsampling. The Cb and Cr components are each subsampled
        /// at a factor of 2 both horizontally and vertically.
        /// </summary>
        /// <typeparam name="TPixel">The pixel format.</typeparam>
        /// <param name="pixels">The pixel accessor providing access to the image pixels.</param>
        private void Encode420 <TPixel>(Image <TPixel> pixels)
            where TPixel : struct, IPixel <TPixel>
        {
            // TODO: Need a JpegScanEncoder<TPixel> class or struct that encapsulates the scan-encoding implementation. (Similar to JpegScanDecoder.)
            Block8x8F b = default(Block8x8F);

            BlockQuad  cb    = default(BlockQuad);
            BlockQuad  cr    = default(BlockQuad);
            Block8x8F *cbPtr = (Block8x8F *)cb.Data;
            Block8x8F *crPtr = (Block8x8F *)cr.Data;

            Block8x8F temp1 = default(Block8x8F);
            Block8x8F temp2 = default(Block8x8F);

            Block8x8F onStackLuminanceQuantTable   = this.luminanceQuantTable;
            Block8x8F onStackChrominanceQuantTable = this.chrominanceQuantTable;

            ZigZag unzig = ZigZag.CreateUnzigTable();

            var pixelConverter = YCbCrForwardConverter <TPixel> .Create();

            // ReSharper disable once InconsistentNaming
            int prevDCY = 0, prevDCCb = 0, prevDCCr = 0;

            for (int y = 0; y < pixels.Height; y += 16)
            {
                for (int x = 0; x < pixels.Width; x += 16)
                {
                    for (int i = 0; i < 4; i++)
                    {
                        int xOff = (i & 1) * 8;
                        int yOff = (i & 2) * 4;

                        pixelConverter.Convert(pixels.Frames.RootFrame, x + xOff, y + yOff);

                        cbPtr[i] = pixelConverter.Cb;
                        crPtr[i] = pixelConverter.Cr;

                        prevDCY = this.WriteBlock(
                            QuantIndex.Luminance,
                            prevDCY,
                            &pixelConverter.Y,
                            &temp1,
                            &temp2,
                            &onStackLuminanceQuantTable,
                            unzig.Data);
                    }

                    Block8x8F.Scale16X16To8X8(&b, cbPtr);
                    prevDCCb = this.WriteBlock(
                        QuantIndex.Chrominance,
                        prevDCCb,
                        &b,
                        &temp1,
                        &temp2,
                        &onStackChrominanceQuantTable,
                        unzig.Data);

                    Block8x8F.Scale16X16To8X8(&b, crPtr);
                    prevDCCr = this.WriteBlock(
                        QuantIndex.Chrominance,
                        prevDCCr,
                        &b,
                        &temp1,
                        &temp2,
                        &onStackChrominanceQuantTable,
                        unzig.Data);
                }
            }
        }