Esempio n. 1
0
        /// <summary>
        /// Writes the DirtyImageFragment to the data stream in compressed format.
        /// </summary>
        /// <param name="s">The stream to write the frame to.</param>
        /// <param name="compressor">A TJCompressor instance that is preconfigured with quality and subsampling options.  Can be null if the image is already compressed.</param>
        /// <param name="compressToBuffer">The buffer to compress to, not used if the image is already compressed.</param>
        public void WriteToDataStream(IDataStream s, TJCompressor compressor, ref byte[] compressToBuffer)
        {
            s.WriteInt16((short)bounds.X);
            s.WriteInt16((short)bounds.Y);
            s.WriteUInt16((ushort)bounds.Width);
            s.WriteUInt16((ushort)bounds.Height);

            if (screenshot.BufferIsCompressed)
            {
                s.WriteInt32(screenshot.Buffer.Length);                  // Write length of image
                s.Write(screenshot.Buffer, 0, screenshot.Buffer.Length); // Write image
            }
            else
            {
                turbojpegCLI.PixelFormat pixelFormat = screenshot.BitsPerPixel == 24 ? turbojpegCLI.PixelFormat.BGR : turbojpegCLI.PixelFormat.BGRX;
                compressor.setSourceImage(screenshot.Buffer, 0, 0, screenshot.Width, screenshot.Stride, screenshot.Height, pixelFormat);
                compressor.compress(ref compressToBuffer, turbojpegCLI.Flag.NONE);
                int compressedSize = compressor.getCompressedSize();
                s.WriteInt32(compressedSize);                 // Write length of image
                s.Write(compressToBuffer, 0, compressedSize); // Write image
            }
        }
Esempio n. 2
0
 private static void benchTJSimpleAPI()
 {
     byte[] data                     = File.ReadAllBytes(inputFilePath);
     byte[] rawImg                   = null;
     byte[] recompressed             = null;
     System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
     sw.Start();
     using (TJDecompressor decomp = new TJDecompressor(data))
     {
         using (TJCompressor comp = new TJCompressor())
         {
             comp.setJPEGQuality(jpegQuality);
             for (int i = 0; i < numIterations; i++)
             {
                 rawImg = decomp.decompress();
                 comp.setSourceImage(rawImg, decomp.getWidth(), decomp.getHeight());
                 recompressed = comp.compressToExactSize();
             }
         }
     }
     sw.Stop();
     PrintBenchmarkResult("turbojpegCLI simple API", sw.ElapsedMilliseconds);
     File.WriteAllBytes("out-libjpeg-turbo.jpg", recompressed);
 }
Esempio n. 3
0
        /// <summary>
        /// Accepts a jpeg frame and encodes the corresponding JpegDiff video frame.  This instance reserves ownership of the returned byte array, and may return the same byte array again later after changing its content.  You can use the byte array for any purpose until the next call to EncodeFrame on this instance.
        /// </summary>
        /// <param name="jpegData">A byte array containing a jpeg image.</param>
        /// <param name="inputSizeBytes">The length of the input data (probably jpegData.Length).</param>
        /// <param name="outputSizeBytes">This variable will be set to the length of the jpeg data in the returned array. Assume the returned array is actually longer than this value.</param>
        /// <returns></returns>
        public byte[] EncodeFrame(byte[] jpegData, int inputSizeBytes, out int outputSizeBytes, int version)
        {
            if (!Versions.Contains(version))
            {
                outputSizeBytes = 0;
                return(new byte[0]);
            }
            lock (this)
            {
                if (isDisposed)
                {
                    outputSizeBytes = 0;
                    return(new byte[0]);
                }
                if (clientVisibleFrame == null)
                {
                    // Special case: First frame of video.
                    clientVisibleFrame = decoder.DecodeFrame(jpegData, inputSizeBytes, version);
                    outputSizeBytes    = jpegData.Length;
                    return(jpegData);
                }
                decomp.setSourceImage(jpegData, inputSizeBytes);
                if (decoder.Width != decomp.getWidth() || decoder.Height != decomp.getHeight())
                {
                    throw new JpegDiffVideoException("New frame dimensions (" + decomp.getWidth() + "x" + decomp.getHeight() + ") do not match the first frame (" + decoder.Width + "x" + decoder.Height + ")");
                }

                if (diffFrame == null)
                {
                    diffFrame = new byte[clientVisibleFrame.Length];
                }

                decomp.decompress(diffFrame);

                try
                {
                    waitBeforeStartingEncode.WaitOne();
                    // We will now iterate through the pixels, one color channel at a time (each byte is one color channel for one pixel)
                    // When we are done iterating, the [bitmap] object will contain an image representing the difference between the
                    // live (previous) frame and the upcoming (new) frame.
                    //
                    // We are shooting for a low contrast image here, as this will compress the best.
                    byte[] encoderArray;
                    if (version == 1)
                    {
                        encoderArray = encoderArrayV1;                         // V1 clamps extreme values to -128 or 128.  Color quality is maintained, but sharp color transitions suffer.
                    }
                    else if (version == 2)
                    {
                        encoderArray = encoderArrayV2;                         // V2 simply cuts color depth in half.
                    }
                    else if (version == 3)
                    {
                        encoderArray = encoderArrayV3;                         // V3 compresses the full color range into half the space, giving priority to small changes.
                    }
                    else if (version == 4)
                    {
                        encoderArray = encoderArrayV4;                         // V4 compresses the full color range into the full space, giving priority to small changes.
                    }
                    else
                    {
                        throw new Exception("Invalid version number specified");
                    }

                    for (int i = 0; i < diffFrame.Length; i++)
                    {
                        diffFrame[i] = encoderArray[255 + ((int)diffFrame[i] - (int)clientVisibleFrame[i])];
                    }

                    lastArguedVersion = version;

                    // The diff frame has been calculated.  Now compress it.
                    comp.setSourceImage(diffFrame, decoder.Width, decoder.Height);
                    comp.setJPEGQuality(compressionQuality);
                    if (returnDataBuffer == null)
                    {
                        returnDataBuffer = comp.compress();
                    }
                    else
                    {
                        comp.compress(ref returnDataBuffer, Flag.NONE);
                    }
                    outputSizeBytes = comp.getCompressedSize();

                    //comp.setSourceImage(previousFrameData, decoder.Width, decoder.Height);
                    //returnDataBuffer = comp.compress();
                    //outputSizeBytes = comp.getCompressedSize();
                    return(returnDataBuffer);
                }
                finally
                {
                    waitBeforeStartingEncode.Reset();
                    waitBeforeStartingDecode.Set();
                }
            }
        }