private static int GetLevel(IVncServerSession vncServerSession, VncEncoding lower, VncEncoding upper, int defaultValue) { if (vncServerSession?.ClientEncodings == null) { return(defaultValue); } foreach (var encoding in vncServerSession.ClientEncodings) { if (encoding >= lower && encoding <= upper) { return(encoding - lower); } } return(defaultValue); }
/// <summary> /// Initializes a new instance of the <see cref="TightEncoder"/> class. /// </summary> /// <param name="vncServerSession"> /// The parent session to which this <see cref="TightEncoder"/> is linked. /// </param> public TightEncoder(IVncServerSession vncServerSession) { this.VncServerSession = vncServerSession ?? throw new ArgumentNullException(nameof(vncServerSession)); }
/// <summary> /// Gets the zlib compression level to use. /// </summary> /// <param name="vncServerSession"> /// The current VNC server session. /// </param> /// <returns> /// The <see cref="CompressionLevel"/> to use for zlib streams for this session. /// </returns> public static CompressionLevel GetCompressionLevel(IVncServerSession vncServerSession) { return((CompressionLevel)GetLevel(vncServerSession, VncEncoding.TightCompressionLevel0, VncEncoding.TightCompressionLevel9, (int)CompressionLevel.Default)); }
/// <summary> /// Gets the JPEG quality level to use. /// </summary> /// <param name="vncServerSession"> /// The current VNC server session. /// </param> /// <returns> /// The JPEG quality level to use, or 0 when JPEG compression should be disabled. /// </returns> public static int GetQualityLevel(IVncServerSession vncServerSession) { return(QualityLevels[GetLevel(vncServerSession, VncEncoding.TightQualityLevel0, VncEncoding.TightQualityLevel9, 10)]); }
/// <summary> /// Responds to a <see cref="VncServerSession"/> update request. /// </summary> /// <param name="session"> /// The session on which the update request was received. /// </param> /// <returns> /// <see langword="true"/> if the operation completed successfully; otherwise, /// <see langword="false"/>. /// </returns> public unsafe bool RespondToUpdateRequest(IVncServerSession session) { VncRectangle subregion = default(VncRectangle); var fb = this.Framebuffer; var fbr = session.FramebufferUpdateRequest; if (fb == null || fbr == null) { return(false); } var incremental = fbr.Incremental; var region = fbr.Region; int bpp = fb.PixelFormat.BytesPerPixel; this.logger?.Log(LogLevel.Debug, () => $"Responding to an update request for region {region}."); session.FramebufferManualBeginUpdate(); // Take a lock here, as we will modify // both buffers heavily in the next block. lock (fb.SyncRoot) { lock (this.cachedFramebuffer.SyncRoot) { var actualBuffer = this.Framebuffer.GetBuffer(); var bufferedBuffer = this.cachedFramebuffer.GetBuffer(); // In this block, we will determine which rectangles need updating. Right now, we consider // each line at once. It's not a very efficient algorithm, but it works. // We're going to start at the upper-left position of the region, and then we will work our way down, // on a line by line basis, to determine if each line is still valid. // isLineInvalid will indicate, on a line-by-line basis, whether a line is still valid or not. for (int y = region.Y; y < region.Y + region.Height; y++) { subregion.X = region.X; subregion.Y = y; subregion.Width = region.Width; subregion.Height = 1; // For a given y, the x pixels are stored sequentially in the array // starting at y * stride (number of bytes per row); for each x // value there are bpp bytes of data (4 for a 32-bit integer); we are looking // for pixels between x and x + w so this translates to // y * stride + bpp * x and y * stride + bpp * (x + w) int srcOffset = (y * this.Framebuffer.Stride) + (bpp * region.X); int length = bpp * region.Width; var isValid = actualBuffer.AsSpan().Slice(srcOffset, length) .SequenceCompareTo(bufferedBuffer.AsSpan().Slice(srcOffset, length)) == 0; if (!isValid) { try { Buffer.BlockCopy(actualBuffer, srcOffset, bufferedBuffer, srcOffset, length); } catch { throw; } } this.isLineInvalid[y - region.Y] = !isValid; } } // lock } // lock if (incremental) { // Determine logical group of lines which are invalid. We find the first line which is invalid, // create a new region which contains the all invalid lines which immediately follow the current line. // If we find a valid line, we'll create a new region. int?y = null; for (int line = 0; line < region.Height; line++) { if (y == null && this.isLineInvalid[line]) { y = region.Y + line; } if (y != null && (!this.isLineInvalid[line] || line == region.Height - 1)) { // Flush subregion.X = region.X; subregion.Y = region.Y + y.Value; subregion.Width = region.Width; subregion.Height = line - y.Value + 1; session.FramebufferManualInvalidate(subregion); y = null; } } } else { session.FramebufferManualInvalidate(region); } return(session.FramebufferManualEndUpdate()); }