mirror of
https://github.com/immense/Remotely.git
synced 2025-10-26 11:27:15 +00:00
Implement SkiaSharp. Remove manual quality controls.
This commit is contained in:
parent
c00e01436b
commit
0d98fcd278
@ -47,6 +47,8 @@
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.EventLog" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.MixedReality.WebRTC" Version="2.0.2" />
|
||||
<PackageReference Include="SkiaSharp" Version="2.80.2" />
|
||||
<PackageReference Include="SkiaSharp.Views.Desktop.Common" Version="2.80.2" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="5.0.2" />
|
||||
<PackageReference Include="System.IO.FileSystem.AccessControl" Version="5.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
@ -90,9 +90,6 @@ namespace Remotely.Desktop.Core.Services
|
||||
case BaseDtoType.CtrlAltDel:
|
||||
await viewer.SendCtrlAltDel();
|
||||
break;
|
||||
case BaseDtoType.AutoQualityAdjust:
|
||||
SetAutoQualityAdjust(message, viewer);
|
||||
break;
|
||||
case BaseDtoType.ToggleAudio:
|
||||
ToggleAudio(message);
|
||||
break;
|
||||
@ -108,9 +105,6 @@ namespace Remotely.Desktop.Core.Services
|
||||
case BaseDtoType.KeyPress:
|
||||
await KeyPress(message);
|
||||
break;
|
||||
case BaseDtoType.QualityChange:
|
||||
QualityChange(message, viewer);
|
||||
break;
|
||||
case BaseDtoType.File:
|
||||
await DownloadFile(message);
|
||||
break;
|
||||
@ -223,11 +217,6 @@ namespace Remotely.Desktop.Core.Services
|
||||
{
|
||||
FileTransferService.OpenFileTransferWindow(viewer);
|
||||
}
|
||||
private void QualityChange(byte[] message, Services.Viewer viewer)
|
||||
{
|
||||
var dto = MessagePackSerializer.Deserialize<QualityChangeDto>(message);
|
||||
viewer.ImageQuality = dto.QualityLevel;
|
||||
}
|
||||
|
||||
private void SelectScreen(byte[] message, Services.Viewer viewer)
|
||||
{
|
||||
@ -235,12 +224,6 @@ namespace Remotely.Desktop.Core.Services
|
||||
viewer.Capturer.SetSelectedScreen(dto.DisplayName);
|
||||
}
|
||||
|
||||
private void SetAutoQualityAdjust(byte[] message, Services.Viewer viewer)
|
||||
{
|
||||
var dto = MessagePackSerializer.Deserialize<AutoQualityAdjustDto>(message);
|
||||
viewer.AutoAdjustQuality = dto.IsOn;
|
||||
}
|
||||
|
||||
private void SetKeyStatesUp()
|
||||
{
|
||||
KeyboardMouseInput.SetKeyStatesUp();
|
||||
|
||||
@ -21,6 +21,8 @@ namespace Remotely.Desktop.Core.Services
|
||||
{
|
||||
private readonly Conductor _conductor;
|
||||
private readonly ICursorIconWatcher _cursorIconWatcher;
|
||||
private readonly int _maxQuality = 75;
|
||||
private readonly int _minQuality = 10;
|
||||
private readonly ISessionIndicator _sessionIndicator;
|
||||
private readonly IShutdownService _shutdownService;
|
||||
|
||||
@ -42,6 +44,8 @@ namespace Remotely.Desktop.Core.Services
|
||||
try
|
||||
{
|
||||
var sendFramesLock = new SemaphoreSlim(1, 1);
|
||||
var lastFullscreen = DateTimeOffset.Now;
|
||||
var currentQuality = _maxQuality;
|
||||
Bitmap currentFrame = null;
|
||||
Bitmap previousFrame = null;
|
||||
|
||||
@ -90,7 +94,7 @@ namespace Remotely.Desktop.Core.Services
|
||||
{
|
||||
await viewer.SendScreenCapture(new CaptureFrame()
|
||||
{
|
||||
EncodedImageBytes = ImageUtils.EncodeJpg(initialFrame, viewer.EncoderParams),
|
||||
EncodedImageBytes = ImageUtils.EncodeJpg(initialFrame, _maxQuality),
|
||||
Left = viewer.Capturer.CurrentScreenBounds.Left,
|
||||
Top = viewer.Capturer.CurrentScreenBounds.Top,
|
||||
Width = viewer.Capturer.CurrentScreenBounds.Width,
|
||||
@ -134,18 +138,56 @@ namespace Remotely.Desktop.Core.Services
|
||||
currentFrame?.Dispose();
|
||||
currentFrame = viewer.Capturer.GetNextFrame();
|
||||
|
||||
var diffArea = ImageUtils.GetDiffArea(currentFrame, previousFrame, viewer.Capturer.CaptureFullscreen);
|
||||
|
||||
if (diffArea.IsEmpty)
|
||||
if (currentFrame is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (DateTimeOffset.Now - lastFullscreen > TimeSpan.FromSeconds(5))
|
||||
{
|
||||
viewer.Capturer.CaptureFullscreen = true;
|
||||
}
|
||||
|
||||
|
||||
var diffArea = ImageUtils.GetDiffArea(currentFrame, previousFrame, viewer.Capturer.CaptureFullscreen);
|
||||
|
||||
if (diffArea.IsEmpty)
|
||||
{
|
||||
if (currentQuality < _maxQuality)
|
||||
{
|
||||
currentQuality++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (viewer.Capturer.CaptureFullscreen)
|
||||
{
|
||||
currentQuality = _maxQuality;
|
||||
lastFullscreen = DateTimeOffset.Now;
|
||||
}
|
||||
|
||||
if (viewer.PendingSentFrames.Any())
|
||||
{
|
||||
currentQuality = Math.Min(_minQuality, currentQuality - viewer.PendingSentFrames.Count);
|
||||
}
|
||||
|
||||
if (viewer.PendingSentFrames.TryPeek(out var oldestFrame) &&
|
||||
DateTimeOffset.Now - oldestFrame > TimeSpan.FromMilliseconds(100))
|
||||
{
|
||||
currentQuality = Math.Max(_minQuality, currentQuality - 10);
|
||||
}
|
||||
else
|
||||
{
|
||||
currentQuality = Math.Min(_maxQuality, currentQuality + 5);
|
||||
}
|
||||
|
||||
viewer.Capturer.CaptureFullscreen = false;
|
||||
|
||||
var clone = currentFrame.Clone(diffArea, currentFrame.PixelFormat);
|
||||
using var clone = currentFrame.Clone(diffArea, currentFrame.PixelFormat);
|
||||
var encodedImageBytes = ImageUtils.EncodeJpg(clone, currentQuality);
|
||||
await sendFramesLock.WaitAsync();
|
||||
SendFrame(clone, diffArea, viewer, sendFramesLock);
|
||||
SendFrame(encodedImageBytes, diffArea, viewer, sendFramesLock);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -172,14 +214,13 @@ namespace Remotely.Desktop.Core.Services
|
||||
}
|
||||
}
|
||||
|
||||
private static void SendFrame(Bitmap clone, Rectangle diffArea, Viewer viewer, SemaphoreSlim sendFramesLock)
|
||||
private static void SendFrame(byte[] encodedImageBytes, Rectangle diffArea, Viewer viewer, SemaphoreSlim sendFramesLock)
|
||||
{
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var encodedImageBytes = ImageUtils.EncodeJpg(clone, viewer.EncoderParams);
|
||||
|
||||
|
||||
if (encodedImageBytes.Length == 0)
|
||||
{
|
||||
return;
|
||||
@ -198,7 +239,6 @@ namespace Remotely.Desktop.Core.Services
|
||||
finally
|
||||
{
|
||||
sendFramesLock.Release();
|
||||
clone.Dispose();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -16,9 +16,6 @@ namespace Remotely.Desktop.Core.Services
|
||||
{
|
||||
public class Viewer : IDisposable
|
||||
{
|
||||
private readonly int _defaultImageQuality = 60;
|
||||
private long _imageQuality;
|
||||
private DateTimeOffset _lastQualityAdjustment;
|
||||
public Viewer(ICasterSocket casterSocket,
|
||||
IScreenCapturer screenCapturer,
|
||||
IClipboardService clipboardService,
|
||||
@ -28,45 +25,17 @@ namespace Remotely.Desktop.Core.Services
|
||||
Capturer = screenCapturer;
|
||||
CasterSocket = casterSocket;
|
||||
WebRtcSessionFactory = webRtcSessionFactory;
|
||||
EncoderParams = new EncoderParameters();
|
||||
ImageQuality = _defaultImageQuality;
|
||||
ClipboardService = clipboardService;
|
||||
ClipboardService.ClipboardTextChanged += ClipboardService_ClipboardTextChanged;
|
||||
AudioCapturer = audioCapturer;
|
||||
AudioCapturer.AudioSampleReady += AudioCapturer_AudioSampleReady;
|
||||
}
|
||||
|
||||
public bool AutoAdjustQuality { get; set; } = true;
|
||||
|
||||
public IScreenCapturer Capturer { get; }
|
||||
|
||||
public bool DisconnectRequested { get; set; }
|
||||
public EncoderParameters EncoderParams { get; private set; }
|
||||
public bool HasControl { get; set; } = true;
|
||||
public long ImageQuality
|
||||
{
|
||||
get
|
||||
{
|
||||
return _imageQuality;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_imageQuality == value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_imageQuality > 100 || _imageQuality < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_imageQuality = value;
|
||||
|
||||
EncoderParams.Param[0] = new EncoderParameter(Encoder.Quality, value);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsConnected => CasterSocket.IsConnected;
|
||||
|
||||
public bool IsStalled
|
||||
@ -259,8 +228,7 @@ namespace Remotely.Desktop.Core.Services
|
||||
Width = width,
|
||||
Height = height,
|
||||
EndOfFrame = false,
|
||||
ImageBytes = screenFrame.EncodedImageBytes.Skip(i).Take(50_000).ToArray(),
|
||||
ImageQuality = _imageQuality
|
||||
ImageBytes = screenFrame.EncodedImageBytes.Skip(i).Take(50_000).ToArray()
|
||||
};
|
||||
|
||||
await SendToViewer(() => RtcSession.SendDto(dto),
|
||||
@ -273,8 +241,7 @@ namespace Remotely.Desktop.Core.Services
|
||||
Top = top,
|
||||
Width = width,
|
||||
Height = height,
|
||||
EndOfFrame = true,
|
||||
ImageQuality = _imageQuality
|
||||
EndOfFrame = true
|
||||
};
|
||||
|
||||
await SendToViewer(() => RtcSession.SendDto(endOfFrameDto),
|
||||
@ -312,14 +279,7 @@ namespace Remotely.Desktop.Core.Services
|
||||
public void ThrottleIfNeeded()
|
||||
{
|
||||
TaskHelper.DelayUntil(() =>
|
||||
{
|
||||
UpdateImageQuality();
|
||||
|
||||
return PendingSentFrames.Count < 7 &&
|
||||
(
|
||||
!PendingSentFrames.TryPeek(out var result) || DateTimeOffset.Now - result < TimeSpan.FromSeconds(1)
|
||||
);
|
||||
},
|
||||
!PendingSentFrames.TryPeek(out var result) || DateTimeOffset.Now - result < TimeSpan.FromSeconds(1),
|
||||
TimeSpan.MaxValue);
|
||||
}
|
||||
|
||||
@ -357,23 +317,5 @@ namespace Remotely.Desktop.Core.Services
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateImageQuality()
|
||||
{
|
||||
if (AutoAdjustQuality && DateTimeOffset.Now - _lastQualityAdjustment > TimeSpan.FromSeconds(2))
|
||||
{
|
||||
_lastQualityAdjustment = DateTimeOffset.Now;
|
||||
|
||||
if (PendingSentFrames.TryPeek(out var result) && DateTimeOffset.Now - result > TimeSpan.FromMilliseconds(200))
|
||||
{
|
||||
var latency = (DateTimeOffset.Now - result).TotalMilliseconds;
|
||||
ImageQuality = Math.Max(20, (int)(200 / latency * _defaultImageQuality));
|
||||
}
|
||||
else if (ImageQuality != _defaultImageQuality)
|
||||
{
|
||||
ImageQuality = Math.Min(_defaultImageQuality, ImageQuality + 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
using System;
|
||||
using SkiaSharp;
|
||||
using SkiaSharp.Views.Desktop;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
@ -12,29 +14,18 @@ namespace Remotely.Desktop.Core.Utilities
|
||||
{
|
||||
public class ImageUtils
|
||||
{
|
||||
public static ImageCodecInfo GifEncoder { get; } = ImageCodecInfo.GetImageEncoders().FirstOrDefault(x => x.FormatID == ImageFormat.Gif.Guid);
|
||||
public static ImageCodecInfo JpegEncoder { get; } = ImageCodecInfo.GetImageEncoders().FirstOrDefault(x => x.FormatID == ImageFormat.Jpeg.Guid);
|
||||
|
||||
public static byte[] EncodeJpg(Bitmap bitmap, EncoderParameters encoderParams)
|
||||
{
|
||||
|
||||
using var ms = new MemoryStream();
|
||||
bitmap.Save(ms, JpegEncoder, encoderParams);
|
||||
return ms.ToArray();
|
||||
}
|
||||
|
||||
public static byte[] EncodePng(Bitmap bitmap)
|
||||
public static byte[] EncodeJpg(Bitmap bitmap, int quality)
|
||||
{
|
||||
using var ms = new MemoryStream();
|
||||
bitmap.Save(ms, ImageFormat.Png);
|
||||
return ms.ToArray();
|
||||
}
|
||||
var info = new SKImageInfo(bitmap.Width, bitmap.Height);
|
||||
var skBitmap = new SKBitmap(info);
|
||||
using (var pixmap = skBitmap.PeekPixels())
|
||||
{
|
||||
bitmap.ToSKPixmap(pixmap);
|
||||
}
|
||||
|
||||
skBitmap.Encode(ms, SKEncodedImageFormat.Jpeg, quality);
|
||||
|
||||
public static byte[] EncodeGif(Bitmap diffImage)
|
||||
{
|
||||
diffImage.MakeTransparent(Color.FromArgb(0, 0, 0, 0));
|
||||
using var ms = new MemoryStream();
|
||||
diffImage.Save(ms, ImageFormat.Gif);
|
||||
return ms.ToArray();
|
||||
}
|
||||
|
||||
|
||||
@ -55,6 +55,8 @@
|
||||
<PackageReference Include="Avalonia" Version="0.10.0" />
|
||||
<PackageReference Include="Avalonia.Desktop" Version="0.10.0" />
|
||||
<PackageReference Include="Avalonia.ReactiveUI" Version="0.10.0" />
|
||||
<PackageReference Include="SkiaSharp" Version="2.80.2" />
|
||||
<PackageReference Include="SkiaSharp.Views.Desktop.Common" Version="2.80.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Desktop.Core\Desktop.Core.csproj" />
|
||||
|
||||
@ -39,6 +39,8 @@
|
||||
<PackageReference Include="SharpDX" Version="4.2.0" />
|
||||
<PackageReference Include="SharpDX.Direct3D11" Version="4.2.0" />
|
||||
<PackageReference Include="SharpDX.DXGI" Version="4.2.0" />
|
||||
<PackageReference Include="SkiaSharp" Version="2.80.2" />
|
||||
<PackageReference Include="SkiaSharp.Views.Desktop.Common" Version="2.80.2" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="5.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@ -154,10 +154,6 @@
|
||||
<button id="fitToScreenButton" class="toggled option-button" title="If toggled, will resize image to fit in the window.">
|
||||
Fit <i class="fas fa-expand"></i>
|
||||
</button>
|
||||
|
||||
<button id="qualityButton" class="option-button" title="Adjust the image quality when not in Stream Mode.">
|
||||
Quality <i class="far fa-image"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
||||
@ -197,19 +193,6 @@
|
||||
|
||||
</div>
|
||||
|
||||
<div id="qualityBar" class="horizontal-button-bar">
|
||||
<div style="color:white; font-size:12px">
|
||||
Image Quality
|
||||
</div>
|
||||
<div>
|
||||
<input id="qualityRangeInput" value="60" max="100" class="form-control-range" type="range" />
|
||||
<div style="color:white; font-size:12px; text-align: left">
|
||||
<input id="autoAdjustQualityCheckBox" type="checkbox" checked />
|
||||
<label for="autoAdjustQualityCheckBox">Auto Adjust</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="clipboardTransferBar" class="horizontal-button-bar">
|
||||
<div style="color:white; font-size:12px">
|
||||
Shared Clipboard
|
||||
|
||||
@ -31,9 +31,6 @@ export const ViewerApp = {
|
||||
Settings: GetSettings(),
|
||||
|
||||
Init: () => {
|
||||
UI.AutoQualityAdjustCheckBox.checked = ViewerApp.Settings.autoQualityEnabled;
|
||||
UI.QualitySlider.value = String(ViewerApp.Settings.qualityLevel);
|
||||
|
||||
if (ViewerApp.ViewOnlyMode) {
|
||||
UI.ViewOnlyButton.classList.add("toggled");
|
||||
}
|
||||
|
||||
@ -60,10 +60,6 @@ export class DtoMessageHandler {
|
||||
}
|
||||
|
||||
HandleCaptureFrame(captureFrame: CaptureFrameDto) {
|
||||
if (UI.AutoQualityAdjustCheckBox.checked &&
|
||||
Number(UI.QualitySlider.value) != captureFrame.ImageQuality) {
|
||||
UI.QualitySlider.value = String(captureFrame.ImageQuality);
|
||||
}
|
||||
|
||||
if (captureFrame.EndOfFrame) {
|
||||
let completedFrame = new Blob(this.ImagePartials, { type: "image/jpeg" });
|
||||
@ -114,8 +110,6 @@ export class DtoMessageHandler {
|
||||
}
|
||||
HandleScreenData(screenDataDto: ScreenDataDto) {
|
||||
UI.UpdateDisplays(screenDataDto.SelectedScreen, screenDataDto.DisplayNames);
|
||||
ViewerApp.MessageSender.SendAutoQualityAdjust(ViewerApp.Settings.autoQualityEnabled);
|
||||
ViewerApp.MessageSender.SendQualityChange(ViewerApp.Settings.qualityLevel);
|
||||
}
|
||||
|
||||
HandleScreenSize(screenSizeDto: ScreenSizeDto) {
|
||||
|
||||
@ -19,10 +19,6 @@
|
||||
TouchKeyboardTextArea,
|
||||
MenuFrame,
|
||||
MenuButton,
|
||||
QualityButton,
|
||||
QualityBar,
|
||||
QualitySlider,
|
||||
AutoQualityAdjustCheckBox,
|
||||
ScreenViewerWrapper,
|
||||
WindowsSessionSelect,
|
||||
RecordSessionButton,
|
||||
@ -219,18 +215,6 @@ export function ApplyInputHandlers() {
|
||||
ev.stopPropagation();
|
||||
MenuButton.style.top = `${ev.touches[0].clientY}px`;
|
||||
});
|
||||
QualityButton.addEventListener("click", (ev) => {
|
||||
closeAllHorizontalBars("qualityBar");
|
||||
QualityBar.classList.toggle("open");
|
||||
})
|
||||
QualitySlider.addEventListener("change", (ev) => {
|
||||
var value = Number(QualitySlider.value);
|
||||
|
||||
ViewerApp.Settings.qualityLevel = value;
|
||||
SetSettings(ViewerApp.Settings);
|
||||
|
||||
ViewerApp.MessageSender.SendQualityChange(value);
|
||||
});
|
||||
StreamVideoButton.addEventListener("click", (ev) => {
|
||||
var toggleOn = !StreamVideoButton.classList.contains("toggled");
|
||||
|
||||
@ -240,14 +224,6 @@ export function ApplyInputHandlers() {
|
||||
UpdateStreamingToggled(toggleOn);
|
||||
ViewerApp.MessageSender.SendToggleWebRtcVideo(toggleOn);
|
||||
});
|
||||
AutoQualityAdjustCheckBox.addEventListener("change", ev => {
|
||||
var checked = AutoQualityAdjustCheckBox.checked;
|
||||
|
||||
ViewerApp.Settings.autoQualityEnabled = checked;
|
||||
SetSettings(ViewerApp.Settings);
|
||||
|
||||
ViewerApp.MessageSender.SendAutoQualityAdjust(checked);
|
||||
});
|
||||
|
||||
[ ScreenViewer, VideoScreenViewer ].forEach(viewer => {
|
||||
viewer.addEventListener("pointermove", function (e: PointerEvent) {
|
||||
|
||||
@ -2,15 +2,6 @@ import { BaseDto } from "./BaseDto.js";
|
||||
import { BaseDtoType } from "../../Shared/Enums/BaseDtoType.js";
|
||||
import { WindowsSession } from "../../Shared/Models/WindowsSession.js";
|
||||
|
||||
export class AutoQualityAdjustDto implements BaseDto {
|
||||
constructor(isOn: boolean) {
|
||||
this.IsOn = isOn;
|
||||
}
|
||||
|
||||
IsOn: boolean;
|
||||
DtoType: BaseDtoType = BaseDtoType.AutoQualityAdjust;
|
||||
}
|
||||
|
||||
|
||||
export interface AudioSampleDto extends BaseDto {
|
||||
Buffer: Uint8Array;
|
||||
@ -23,7 +14,6 @@ export interface CaptureFrameDto extends BaseDto {
|
||||
Width: number;
|
||||
Height: number;
|
||||
ImageBytes: Uint8Array;
|
||||
ImageQuality: number;
|
||||
}
|
||||
|
||||
export interface ClipboardTextDto extends BaseDto {
|
||||
@ -163,15 +153,6 @@ export class MouseWheelDto implements BaseDto {
|
||||
DtoType: BaseDtoType = BaseDtoType.MouseWheel;
|
||||
}
|
||||
|
||||
export class QualityChangeDto implements BaseDto {
|
||||
constructor(qualityLevel: number) {
|
||||
this.QualityLevel = qualityLevel;
|
||||
}
|
||||
|
||||
QualityLevel: number;
|
||||
DtoType: BaseDtoType = BaseDtoType.QualityChange;
|
||||
}
|
||||
|
||||
export interface ScreenDataDto extends BaseDto {
|
||||
DisplayNames: string[];
|
||||
SelectedScreen: string;
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
export interface Settings {
|
||||
autoQualityEnabled: boolean;
|
||||
qualityLevel: number;
|
||||
streamModeEnabled: boolean;
|
||||
}
|
||||
@ -8,10 +8,8 @@ import {
|
||||
MouseMoveDto,
|
||||
MouseUpDto,
|
||||
MouseWheelDto,
|
||||
QualityChangeDto,
|
||||
SelectScreenDto,
|
||||
TapDto,
|
||||
AutoQualityAdjustDto,
|
||||
ToggleAudioDto,
|
||||
ToggleBlockInputDto,
|
||||
ClipboardTransferDto,
|
||||
@ -131,16 +129,6 @@ export class MessageSender {
|
||||
() => ViewerApp.ViewerHubConnection.SendDtoToClient(dto));
|
||||
}
|
||||
|
||||
SendQualityChange(qualityLevel: number) {
|
||||
var dto = new QualityChangeDto(qualityLevel);
|
||||
this.SendToAgent(() => ViewerApp.RtcSession.SendDto(dto),
|
||||
() => ViewerApp.ViewerHubConnection.SendDtoToClient(dto));
|
||||
}
|
||||
SendAutoQualityAdjust(isOn: boolean) {
|
||||
var dto = new AutoQualityAdjustDto(isOn);
|
||||
this.SendToAgent(() => ViewerApp.RtcSession.SendDto(dto),
|
||||
() => ViewerApp.ViewerHubConnection.SendDtoToClient(dto));
|
||||
}
|
||||
SendToggleAudio(toggleOn: boolean) {
|
||||
var dto = new ToggleAudioDto(toggleOn);
|
||||
this.SendToAgent(() => ViewerApp.RtcSession.SendDto(dto),
|
||||
|
||||
@ -31,7 +31,6 @@ export class RtcSession {
|
||||
|
||||
UI.StreamVideoButton.setAttribute("hidden", "hidden");
|
||||
UI.ScreenViewer.removeAttribute("hidden");
|
||||
UI.QualityButton.removeAttribute("hidden");
|
||||
UI.VideoScreenViewer.setAttribute("hidden", "hidden");
|
||||
};
|
||||
this.DataChannel.onerror = (ev) => {
|
||||
@ -41,7 +40,6 @@ export class RtcSession {
|
||||
|
||||
UI.StreamVideoButton.setAttribute("hidden", "hidden");
|
||||
UI.ScreenViewer.removeAttribute("hidden");
|
||||
UI.QualityButton.removeAttribute("hidden");
|
||||
UI.VideoScreenViewer.setAttribute("hidden", "hidden");
|
||||
};
|
||||
this.DataChannel.onmessage = (ev) => {
|
||||
|
||||
@ -1,10 +1,6 @@
|
||||
import { ViewerApp } from "./App.js";
|
||||
import { Settings } from "./Interfaces/Settings.js";
|
||||
import { AutoQualityAdjustCheckBox, QualitySlider, UpdateStreamingToggled } from "./UI.js";
|
||||
import { Settings } from "./Interfaces/Settings.js";
|
||||
|
||||
const defaultSettings = {
|
||||
autoQualityEnabled: true,
|
||||
qualityLevel: 60,
|
||||
streamModeEnabled: false
|
||||
};
|
||||
|
||||
|
||||
@ -17,13 +17,9 @@ export var Screen2DContext = ScreenViewer ? ScreenViewer.getContext("2d") : null
|
||||
export var HorizontalBars = document.querySelectorAll(".horizontal-button-bar");
|
||||
export var ConnectBox = document.getElementById("connectBox") as HTMLDivElement;
|
||||
export var ScreenSelectBar = document.getElementById("screenSelectBar") as HTMLDivElement;
|
||||
export var QualityBar = document.getElementById("qualityBar") as HTMLDivElement;
|
||||
export var QualitySlider = document.getElementById("qualityRangeInput") as HTMLInputElement;
|
||||
export var AutoQualityAdjustCheckBox = document.getElementById("autoAdjustQualityCheckBox") as HTMLInputElement;
|
||||
export var ActionsBar = document.getElementById("actionsBar") as HTMLDivElement;
|
||||
export var ViewBar = document.getElementById("viewBar") as HTMLDivElement;
|
||||
export var ChangeScreenButton = document.getElementById("changeScreenButton") as HTMLButtonElement;
|
||||
export var QualityButton = document.getElementById("qualityButton") as HTMLButtonElement;
|
||||
export var StreamVideoButton = document.getElementById("streamVideoButton") as HTMLButtonElement;
|
||||
export var FitToScreenButton = document.getElementById("fitToScreenButton") as HTMLButtonElement;
|
||||
export var BlockInputButton = document.getElementById("blockInputButton") as HTMLButtonElement;
|
||||
@ -161,12 +157,10 @@ export function UpdateStreamingToggled(toggleOn: boolean) {
|
||||
StreamVideoButton.classList.add("toggled");
|
||||
VideoScreenViewer.removeAttribute("hidden");
|
||||
ScreenViewer.setAttribute("hidden", "hidden");
|
||||
QualityButton.setAttribute("hidden", "hidden");
|
||||
}
|
||||
else {
|
||||
StreamVideoButton.classList.remove("toggled");
|
||||
ScreenViewer.removeAttribute("hidden");
|
||||
QualityButton.removeAttribute("hidden");
|
||||
VideoScreenViewer.setAttribute("hidden", "hidden");
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,12 +15,10 @@
|
||||
KeyDown = 13,
|
||||
KeyUp = 14,
|
||||
CtrlAltDel = 15,
|
||||
AutoQualityAdjust = 16,
|
||||
ToggleAudio = 17,
|
||||
ToggleBlockInput = 18,
|
||||
ClipboardTransfer = 19,
|
||||
KeyPress = 20,
|
||||
QualityChange = 21,
|
||||
File = 22,
|
||||
WindowsSessions = 23,
|
||||
SetKeyStatesUp = 24,
|
||||
|
||||
@ -37,8 +37,6 @@ namespace Remotely.Shared.Enums
|
||||
KeyUp = 14,
|
||||
[EnumMember(Value = "CtrlAltDel")]
|
||||
CtrlAltDel = 15,
|
||||
[EnumMember(Value = "AutoQualityAdjust")]
|
||||
AutoQualityAdjust = 16,
|
||||
[EnumMember(Value = "ToggleAudio")]
|
||||
ToggleAudio = 17,
|
||||
[EnumMember(Value = "ToggleBlockInput")]
|
||||
@ -47,8 +45,6 @@ namespace Remotely.Shared.Enums
|
||||
ClipboardTransfer = 19,
|
||||
[EnumMember(Value = "KeyPress")]
|
||||
KeyPress = 20,
|
||||
[EnumMember(Value = "QualityChange")]
|
||||
QualityChange = 21,
|
||||
[EnumMember(Value = "File")]
|
||||
File = 22,
|
||||
[EnumMember(Value = "WindowsSessions")]
|
||||
|
||||
@ -1,15 +0,0 @@
|
||||
using Remotely.Shared.Enums;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Remotely.Shared.Models.RemoteControlDtos
|
||||
{
|
||||
[DataContract]
|
||||
public class AutoQualityAdjustDto : BaseDto
|
||||
{
|
||||
[DataMember(Name = "IsOn")]
|
||||
public bool IsOn { get; set; }
|
||||
|
||||
[DataMember(Name = "DtoType")]
|
||||
public new BaseDtoType DtoType { get; } = BaseDtoType.AutoQualityAdjust;
|
||||
}
|
||||
}
|
||||
@ -18,9 +18,6 @@ namespace Remotely.Shared.Models.RemoteControlDtos
|
||||
[DataMember(Name = "ImageBytes")]
|
||||
public byte[] ImageBytes { get; set; }
|
||||
|
||||
[DataMember(Name = "ImageQuality")]
|
||||
public long ImageQuality { get; set; }
|
||||
|
||||
[DataMember(Name = "Left")]
|
||||
public int Left { get; set; }
|
||||
[DataMember(Name = "Top")]
|
||||
|
||||
@ -1,15 +0,0 @@
|
||||
using Remotely.Shared.Enums;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Remotely.Shared.Models.RemoteControlDtos
|
||||
{
|
||||
[DataContract]
|
||||
public class QualityChangeDto : BaseDto
|
||||
{
|
||||
[DataMember(Name = "QualityLevel")]
|
||||
public int QualityLevel { get; set; }
|
||||
|
||||
[DataMember(Name = "DtoType")]
|
||||
public new BaseDtoType DtoType { get; } = BaseDtoType.QualityChange;
|
||||
}
|
||||
}
|
||||
@ -100,8 +100,8 @@ namespace Remotely.Tests
|
||||
tempImage.Save(ms, jpegEncoder, encoderParams);
|
||||
diffSize = ms.ToArray().Length;
|
||||
}
|
||||
Debug.WriteLine($"Diff size: {diffSize}");
|
||||
Debug.WriteLine($"Diff time: {sw.Elapsed.TotalMilliseconds}");
|
||||
Debug.WriteLine($"Diff area size: {diffSize}");
|
||||
Debug.WriteLine($"Diff area time: {sw.Elapsed.TotalMilliseconds}");
|
||||
|
||||
|
||||
sw.Restart();
|
||||
@ -116,76 +116,6 @@ namespace Remotely.Tests
|
||||
Debug.WriteLine($"Diff Image time: {sw.Elapsed.TotalMilliseconds}");
|
||||
|
||||
|
||||
|
||||
sw.Restart();
|
||||
var gifImage = (Bitmap)diffImage.Clone();
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
gifImage.MakeTransparent(Color.FromArgb(0, 0, 0, 0));
|
||||
gifImage.Save(ms, ImageFormat.Gif);
|
||||
Debug.WriteLine($"GIF image size: {ms.ToArray().Length}");
|
||||
}
|
||||
Debug.WriteLine($"GIF Image time: {sw.Elapsed.TotalMilliseconds}");
|
||||
|
||||
//sw.Restart();
|
||||
//using (var ms = new MemoryStream())
|
||||
//{
|
||||
// diffImage.Save(ms, ImageFormat.Jpeg);
|
||||
// ms.Seek(0, SeekOrigin.Begin);
|
||||
// var pngEncoder = new PngEncoder() { CompressionLevel = PngCompressionLevel.BestSpeed };
|
||||
// using (var ms2 = new MemoryStream())
|
||||
// {
|
||||
// SixLabors.ImageSharp.Image.Load(ms).Save(ms2, pngEncoder);
|
||||
// Debug.WriteLine($"ImageSharp size: {ms2.ToArray().Length}");
|
||||
// }
|
||||
//}
|
||||
//Debug.WriteLine($"ImageSharp encode time: {sw.Elapsed.TotalMilliseconds}");
|
||||
|
||||
|
||||
//sw.Restart();
|
||||
//using (var ms = new MemoryStream())
|
||||
//{
|
||||
// diffImage.Save(ms, ImageFormat.Jpeg);
|
||||
// ms.Seek(0, SeekOrigin.Begin);
|
||||
// using (var ms2 = new MemoryStream())
|
||||
// {
|
||||
// Aspose.Imaging.Image.Load(ms).Save(ms2, new PngOptions() { CompressionLevel = 5 });
|
||||
// Debug.WriteLine($"Aspose size: {ms2.ToArray().Length}");
|
||||
// }
|
||||
//}
|
||||
//Debug.WriteLine($"Aspose encode time: {sw.Elapsed.TotalMilliseconds}");
|
||||
|
||||
|
||||
|
||||
|
||||
//sw.Restart();
|
||||
//var drawingBytes = ImageUtils.EncodeBitmap(frame1, null);
|
||||
//Debug.WriteLine($"Drawing Encoder time: {sw.Elapsed.TotalMilliseconds}");
|
||||
//Debug.WriteLine($"Drawing encoder size: {drawingBytes.Length}");
|
||||
|
||||
//sw.Restart();
|
||||
//using (var ms = new MemoryStream())
|
||||
//{
|
||||
// frame1.Clone(new Rectangle(0, 0, 500, 500), PixelFormat.Format32bppArgb)
|
||||
// .Save(ms, GetEncoder(ImageFormat.Jpeg), encoderParams);
|
||||
// Debug.WriteLine($"Jpeg encode time: {sw.Elapsed.TotalMilliseconds}");
|
||||
// Debug.WriteLine($"Jpeg encode size: {ms.ToArray().Length}");
|
||||
//}
|
||||
|
||||
//var factory = new ImageProcessor.ImageFactory();
|
||||
//sw.Restart();
|
||||
//using (var ms = new MemoryStream())
|
||||
//{
|
||||
// var webPFormat = new ImageProcessor.Plugins.WebP.Imaging.Formats.WebPFormat();
|
||||
// factory.Load(diffImage)
|
||||
// .Format(webPFormat)
|
||||
// .Quality(60)
|
||||
// .Save(ms);
|
||||
|
||||
// Debug.WriteLine($"Webp encode time: {sw.Elapsed.TotalMilliseconds}");
|
||||
// Debug.WriteLine($"Webp encode size: {ms.ToArray().Length}");
|
||||
//}
|
||||
|
||||
Debug.WriteLine($"\n");
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user