Exemplo n.º 1
0
        /// <summary>
        /// Copies a region of the framebuffer into a bitmap.
        /// </summary>
        /// <param name="source">The framebuffer to read.</param>
        /// <param name="sourceRectangle">The framebuffer region to copy.</param>
        /// <param name="target">The bitmap to copy into.</param>
        /// <param name="targetX">The leftmost X coordinate of the bitmap to draw to.</param>
        /// <param name="targetY">The topmost Y coordinate of the bitmap to draw to.</param>
        public unsafe static void CopyFromFramebuffer(VncFramebuffer source, VncRectangle sourceRectangle,
                                                      Bitmap target, int targetX, int targetY)
        {
            Throw.If.Null(source, "source").Null(target, "target");
            if (sourceRectangle.IsEmpty)
            {
                return;
            }

            var winformsRect = new Rectangle(targetX, targetY, sourceRectangle.Width, sourceRectangle.Height);
            var data         = target.LockBits(winformsRect, ImageLockMode.WriteOnly, PixelFormat.Format32bppRgb);

            try
            {
                fixed(byte *framebufferData = source.GetBuffer())
                {
                    VncPixelFormat.Copy((IntPtr)framebufferData, source.Stride, source.PixelFormat, sourceRectangle,
                                        data.Scan0, data.Stride, new VncPixelFormat());
                }
            }
            finally
            {
                target.UnlockBits(data);
            }
        }
Exemplo n.º 2
0
        /// <summary>
        /// 将需要更新位图的区域复制到framebuffer中
        /// </summary>
        /// <param name="source">图片源.</param>
        /// <param name="sourceRectangle">要复制的位图区域.</param>
        /// <param name="target">目标帧缓冲区</param>
        /// <param name="targetX">帧缓冲区的左顶点X坐标</param>
        /// <param name="targetY">帧缓冲区的左顶点Y坐标</param>
        public unsafe static void CopyToFramebuffer(Bitmap source, VncRectangle sourceRectangle,
                                                    VncFramebuffer target, int targetX, int targetY)
        {
            Throw.If.Null(source, "source").Null(target, "target");
            if (sourceRectangle.IsEmpty)
            {
                return;
            }

            var winformsRect = new Rectangle(sourceRectangle.X, sourceRectangle.Y, sourceRectangle.Width, sourceRectangle.Height);
            var data         = source.LockBits(winformsRect, ImageLockMode.ReadOnly, PixelFormat.Format32bppRgb);

            try
            {
                fixed(byte *framebufferData = target.GetBuffer())
                {
                    VncPixelFormat.Copy(data.Scan0, data.Stride, new VncPixelFormat(32, 24, 8, 16, 8, 8, 8, 0), sourceRectangle,
                                        (IntPtr)framebufferData, target.Stride, target.PixelFormat, targetX, targetY);
                }
            }
            finally
            {
                source.UnlockBits(data);
            }
        }
Exemplo n.º 3
0
        /// <summary>
        /// Copies a region of a bitmap into the framebuffer.
        /// </summary>
        /// <param name="source">The bitmap to read.</param>
        /// <param name="sourceRectangle">The bitmap region to copy.</param>
        /// <param name="target">The framebuffer to copy into.</param>
        /// <param name="targetX">The leftmost X coordinate of the framebuffer to draw to.</param>
        /// <param name="targetY">The topmost Y coordinate of the framebuffer to draw to.</param>
        public static unsafe void CopyToFramebuffer(
            Bitmap source,
            VncRectangle sourceRectangle,
            VncFramebuffer target,
            int targetX,
            int targetY)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }

            if (target == null)
            {
                throw new ArgumentNullException(nameof(target));
            }

            if (sourceRectangle.IsEmpty)
            {
                return;
            }

            var winformsRect = new Rectangle(sourceRectangle.X, sourceRectangle.Y, sourceRectangle.Width, sourceRectangle.Height);
            var data         = source.LockBits(winformsRect, ImageLockMode.ReadOnly, PixelFormat.Format32bppRgb);

            try
            {
                fixed(byte *framebufferData = target.GetBuffer())
                {
                    VncPixelFormat.Copy(
                        data.Scan0,
                        data.Stride,
                        new VncPixelFormat(),
                        sourceRectangle,
                        (IntPtr)framebufferData,
                        target.Stride,
                        target.PixelFormat,
                        targetX,
                        targetY);
                }
            }
            finally
            {
                source.UnlockBits(data);
            }
        }
Exemplo n.º 4
0
        public VncFramebuffer Capture()
        {
            lock (_lock)
            {
                using (var bmpRef = Window.GetLastRenderedFrame())
                {
                    if (bmpRef?.Item == null)
                    {
                        return(_framebuffer);
                    }
                    var bmp = bmpRef.Item;
                    if (bmp.PixelSize.Width != _framebuffer.Width || bmp.PixelSize.Height != _framebuffer.Height)
                    {
                        _framebuffer = new VncFramebuffer("Avalonia", bmp.PixelSize.Width, bmp.PixelSize.Height,
                                                          VncPixelFormat.RGB32);
                    }

                    using (var fb = bmp.Lock())
                    {
                        var buf = _framebuffer.GetBuffer();
                        if (_framebuffer.Stride == fb.RowBytes)
                        {
                            Marshal.Copy(fb.Address, buf, 0, buf.Length);
                        }
                        else
                        {
                            for (var y = 0; y < fb.Size.Height; y++)
                            {
                                var sourceStart = fb.RowBytes * y;
                                var dstStart    = _framebuffer.Stride * y;
                                var row         = fb.Size.Width * 4;
                                Marshal.Copy(new IntPtr(sourceStart + fb.Address.ToInt64()), buf, dstStart, row);
                            }
                        }
                    }
                }
            }

            return(_framebuffer);
        }
Exemplo n.º 5
0
        /// <summary>
        /// Asynchronously writes framebuffer packages to a <see cref="Stream"/>.
        /// </summary>
        /// <param name="stream">
        /// The <see cref="Stream"/> to which to write.
        /// </param>
        /// <param name="cancellationToken">
        /// A <see cref="CancellationToken"/> which can be used to cancel the asynchronous operation. This method
        /// will keep recording until cancellation is requested.
        /// </param>
        /// <returns>
        /// A <see cref="Task"/> which represents the asynchronous operation.
        /// </returns>
        public async Task WriteAsync(Stream stream, CancellationToken cancellationToken)
        {
            if (stream == null)
            {
                throw new ArgumentNullException(nameof(stream));
            }

            VncFramebuffer framebuffer = this.framebufferSource.Capture();

            // The RIFF header, wraps the entire file.
            await stream.WriteStructAsync(
                new List()
            {
                ListType = FourCC.Riff,
                FourCC   = FourCC.Avi,
                Size     = this.ExpectedSize,
            },
                cancellationToken).ConfigureAwait(false);

            // HDRL list. Defines the format of the data and is the first required LIST chunk.
            await stream.WriteStructAsync(
                new List()
            {
                ListType = FourCC.List,
                FourCC   = FourCC.Hdrl,
                Size     = 0x449c, // TBC
            },
                cancellationToken).ConfigureAwait(false);

            // AVIH chunk. Contains the main AVI header.
            await stream.WriteStructAsync(
                new Chunk()
            {
                FourCC = FourCC.Avih,
                Size   = Unsafe.SizeOf <AviMainHeader>(),
            },
                cancellationToken).ConfigureAwait(false);

            await stream.WriteStructAsync(
                new AviMainHeader()
            {
                Flags               = MainHeaderFlags.HasIndex,
                Height              = framebuffer.Height,
                Width               = framebuffer.Width,
                MaxBytesPerSec      = 1448660, // TBC
                MicroSecPerFrame    = this.MicrosecondsPerFrame,
                Streams             = 1,
                SuggestedBufferSize = 0x046bc4,     // TBC
                TotalFrames         = this.ExpectedTotalFrames,
            },
                cancellationToken).ConfigureAwait(false);

            // STRL list. Contains informatio about a stream.
            await stream.WriteStructAsync(
                new List()
            {
                ListType = FourCC.List,
                FourCC   = FourCC.Strl,
                Size     = 17220,
            },
                cancellationToken).ConfigureAwait(false);

            // STRH chunk
            await stream.WriteStructAsync(
                new Chunk()
            {
                FourCC = FourCC.Strh,
                Size   = 0x38,
            },
                cancellationToken).ConfigureAwait(false);

            await stream.WriteStructAsync(
                new AviStreamHeader()
            {
                Type                = FourCC.Vids,
                Handler             = FourCC.VMnc,
                Length              = this.ExpectedTotalFrames,
                Quality             = -1,
                Rate                = this.Rate,
                Scale               = this.Scale,
                SuggestedBufferSize = 0x00046bc4,
                Bottom              = (short)framebuffer.Height,
                Right               = (short)framebuffer.Width,
            },
                cancellationToken).ConfigureAwait(false);

            // STRF chunk
            await stream.WriteStructAsync(
                new Chunk()
            {
                FourCC = FourCC.Strf,
                Size   = 0x28,
            },
                cancellationToken).ConfigureAwait(false);

            // BitmapInfoHeader
            await stream.WriteStructAsync(
                new BitmapInfoHeader()
            {
                BitCount    = 0x20,
                Compression = FourCC.VMnc,
                Height      = framebuffer.Height,
                Planes      = 1,
                Size        = 0x28, // TBC
                Width       = framebuffer.Width,
            },
                cancellationToken).ConfigureAwait(false);

            // Index chunk
            var indexSize = 0x000042c8; // TBC
            await stream.WriteStructAsync(
                new AviIndexChunck()
            {
                FourCC        = FourCC.Indx,
                Size          = indexSize,
                EntriesInUse  = 1,
                ChunkId       = FourCC.Dc00,
                LongsPerEntry = 4,
                IndexType     = IndexType.IndexOfIndexes,
                IndexSubType  = IndexSubType.None,
            },
                cancellationToken).ConfigureAwait(false);

            // Super index chunk
            await stream.WriteStructAsync(
                new AviSuperIndexEntry()
            {
                Duration = this.ExpectedTotalFrames,
                Offset   = 0x000000000004196a,
                Size     = 0x4000,
            },
                cancellationToken);

            await stream.GrowAsync(indexSize - Unsafe.SizeOf <AviSuperIndexEntry>() - Unsafe.SizeOf <AviIndexChunck>() + Unsafe.SizeOf <Chunk>(), cancellationToken).ConfigureAwait(false);

            // ODML chunk
            await stream.WriteStructAsync(
                new List()
            {
                ListType = FourCC.List,
                FourCC   = FourCC.Odml,
                Size     = 0x00000104,
            },
                cancellationToken).ConfigureAwait(false);

            // DMLH chunk
            indexSize = 0xf8;
            await stream.WriteStructAsync(
                new AviIndexChunck()
            {
                FourCC        = FourCC.Dmlh,
                Size          = indexSize,
                IndexType     = IndexType.IndexOfIndexes,
                IndexSubType  = IndexSubType.None,
                ChunkId       = (FourCC)BinaryPrimitives.ReverseEndianness((uint)VncEncoding.Raw),
                EntriesInUse  = 0,
                LongsPerEntry = 0x13e,
            },
                cancellationToken);

            await stream.GrowAsync(indexSize - Unsafe.SizeOf <AviIndexChunck>() + Unsafe.SizeOf <Chunk>(), cancellationToken).ConfigureAwait(false);

            var junkSize = 0x00000348;
            await stream.WriteStructAsync(
                new Chunk()
            {
                FourCC = FourCC.Junk,
                Size   = junkSize,   // TBC
            },
                cancellationToken).ConfigureAwait(false);

            var junk = "VMware Workstation";

            byte[] buffer = new byte[128];
            Encoding.ASCII.GetBytes(junk, 0, junk.Length, buffer, 0);
            stream.Write(buffer, 0, junk.Length);

            await stream.GrowAsync(junkSize - junk.Length, cancellationToken).ConfigureAwait(false);

            // The movie list
            await stream.WriteStructAsync(
                new List()
            {
                FourCC   = FourCC.Movi,
                ListType = FourCC.List,
                Size     = this.ExpectedSize - 0x4800,
            },
                cancellationToken);

            FramebufferUpdate framebufferUpdate = new FramebufferUpdate()
            {
                MessageType        = 0,
                NumberOfRectangles = 2,
            };

            FramebufferUpdateRectangle rectangle         = new FramebufferUpdateRectangle();
            DisplayModeChange          displayModeChange = new DisplayModeChange();

            Chunk dcChunk = new Chunk()
            {
                FourCC = FourCC.Dc00,
                Size   =
                    4
                    + (2 * framebufferUpdate.Buffer.Length)
                    + displayModeChange.Buffer.Length
                    + (framebuffer.Stride * framebuffer.Width * framebuffer.PixelFormat.BytesPerPixel),
            };

            Stopwatch timer = new Stopwatch();

            while (!cancellationToken.IsCancellationRequested)
            {
                // Start a timer which will timeout after the timeframe allotted to each frame.
                timer.Restart();
                var interval = Task.Delay(this.MicrosecondsPerFrame / 1000, cancellationToken).ConfigureAwait(false);
                framebuffer = this.framebufferSource.Capture();

                if (framebuffer == null)
                {
                    break;
                }

                rectangle.Width  = (ushort)framebuffer.Width;
                rectangle.Height = (ushort)framebuffer.Height;

                await stream.WriteStructAsync(dcChunk, cancellationToken).ConfigureAwait(false);

                // Framebuffer update message, with 2 rectangles
                await stream.WriteAsync(framebufferUpdate.Buffer, cancellationToken).ConfigureAwait(false);

                // Pseudo-rectangle: display mode change pseudo-encoding
                rectangle.EncodingType = VncEncoding.VMWi;
                await stream.WriteAsync(rectangle.Buffer, cancellationToken).ConfigureAwait(false);

                displayModeChange.BitsPerSample = (byte)framebuffer.PixelFormat.BitsPerPixel;
                displayModeChange.Depth         = (byte)framebuffer.PixelFormat.BitDepth;
                displayModeChange.MaxBlue       = framebuffer.PixelFormat.BlueMax;
                displayModeChange.MaxGreen      = framebuffer.PixelFormat.GreenMax;
                displayModeChange.MaxRed        = framebuffer.PixelFormat.RedMax;
                displayModeChange.BlueShift     = (byte)framebuffer.PixelFormat.BlueShift;
                displayModeChange.GreenShift    = (byte)framebuffer.PixelFormat.GreenShift;
                displayModeChange.RedShift      = (byte)framebuffer.PixelFormat.RedShift;
                displayModeChange.TrueColor     = !framebuffer.PixelFormat.IsPalettized;
                await stream.WriteAsync(displayModeChange.Buffer, cancellationToken).ConfigureAwait(false);

                // Rectangle: framebuffer
                rectangle.EncodingType = VncEncoding.Raw;
                await stream.WriteAsync(rectangle.Buffer, cancellationToken).ConfigureAwait(false);

                var rawFramebuffer = framebuffer.GetBuffer();
                await stream.WriteAsync(rawFramebuffer, 0, rawFramebuffer.Length, cancellationToken).ConfigureAwait(false);

                Debug.WriteLine($"Completed in {timer.ElapsedMilliseconds} ms out of allowed {this.MicrosecondsPerFrame / 1000} ms");

                // Wait for the timer to complete.
                await interval;
            }
        }