【发布时间】:2015-12-22 17:33:42
【问题描述】:
最近我一直在开发一个简单的屏幕共享程序。
实际上,该程序在 TCP protocol 上运行,并使用 Desktop duplication API - 一项很酷的服务,支持非常快速的屏幕捕获并提供有关 MovedRegions 的信息(仅更改其位置的区域在屏幕上但仍然存在)和UpdatedRegions(更改区域)。
桌面复制有 2 个重要的属性 - 2 字节数组 一个数组用于 previouspixels 和一个 NewPixels 数组。每 4 个字节代表 RGBA 形式的一个像素,例如,如果我的屏幕为 1920 x 1080,则缓冲区大小为 1920 x 1080 * 4。
以下是我的策略的重要亮点
- 在初始状态(第一次)我发送整个像素缓冲区(在我的情况下它是 1920 x 1080 * 3)- alpha 分量在屏幕上始终为 255 :)
-
从现在开始,我遍历 UpdatedRegions(它是一个矩形数组)并发送区域边界和 Xo'r 像素,如下所示:
writer.Position = 0; var n = frame._newPixels; var w = 1920 * 4; //frame boundaries. var p = frame._previousPixels; foreach (var region in frame.UpdatedRegions) { writer.WriteInt(region.Top); writer.WriteInt(region.Height); writer.WriteInt(region.Left); writer.WriteInt(region.Width); for (int y = region.Top, yOffset = y * w; y < region.Bottom; y++, yOffset += w) { for (int x = region.Left, xOffset = x * 4, i = yOffset + xOffset; x < region.Right; x++, i += 4) { writer.WriteByte(n[i] ^ p[i]); //'n' is the newpixels buffer and 'p' is the previous.xoring for differences. writer.WriteByte(n[i+1] ^ p[i+1]); writer.WriteByte(n[i + 2] ^ p[i + 2]); } } } - 我使用用 c# 编写的 lz4 包装器压缩缓冲区(请参阅lz4.NET@github)。然后,我将数据写入 NetworkStream。
- 我合并接收端的区域以获得更新的图像 - 这不是我们今天的问题 :)
'writer' 是我编写的'QuickBinaryWriter' 类的一个实例(只是为了再次重用相同的缓冲区)。
public class QuickBinaryWriter
{
private readonly byte[] _buffer;
private int _position;
public QuickBinaryWriter(byte[] buffer)
{
_buffer = buffer;
}
public int Position
{
get { return _position; }
set { _position = value; }
}
public void WriteByte(byte value)
{
_buffer[_position++] = value;
}
public void WriteInt(int value)
{
byte[] arr = BitConverter.GetBytes(value);
for (int i = 0; i < arr.Length; i++)
WriteByte(arr[i]);
}
}
从许多措施来看,我发现发送的数据非常庞大,有时单帧更新数据可能高达 200kb(压缩后!)。 老实说,200kb 真的不算什么,但如果我想流畅地流式传输屏幕并能够以高 Fps 速率观看,我将不得不在这方面做一点工作 - 尽量减少网络流量和带宽使用。
我正在寻找提高程序效率的建议和创意 - 主要是在网络部分发送的数据(通过以其他方式或任何其他想法打包)我将不胜感激任何帮助和想法。谢谢.
【问题讨论】:
-
你的问题有点含糊。您应该指定要优化的部分。目前,这个问题有太多潜在的答案,这可能会导致投反对票,并且由于过于广泛而被搁置。我将举一个例子来说明它的广泛性。您想优化代码、发送数据的方式、压缩方式还是更新屏幕的方式?
-
@dakre18 感谢您的关注,我主要寻找数据压缩 - 我需要专注于最小化网络流量 - 也许以其他方式打包图形数据......我不知道那是我写的问题:)
-
你以前问过这个问题。
-
@harold 我问过类似的问题-您可能会注意到这里的数据组织方法发生了变化。
-
它是通用的脚轮,还是用于流式传输的特定类型的应用程序/桌面?例如。当您知道会有很多相同颜色的补丁时,简单压缩可能是一种快速且良好的压缩选项。如果是 3D 游戏,其中所有像素都可能发生变化并且几乎没有任何相同颜色的补丁存在,那么 jpg 或 H.264 编码可能会更好。
标签: c# performance sockets