内容简介:代码日志版权声明:翻译自:http://stackoverflow.com/questions/34421447/c-sharp-screen-streaming-program
最近我一直在做一个简单的屏幕共享程序.
实际上该程序的工作原理是一个TCP协议,并使用桌面复制API – 一个很酷的服务,支持非常快速的屏幕捕获,并且还提供有关MovedRegions的信息(只改变了他们在屏幕上的位置但仍然存在的区域)和更新区域(更改的区域) .
桌面复制有2个改进的属性 – 2个字节的数组,用于先前的像素和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速率观看,我将不得不在这一点上工作 – 以最大限度地减少网络流量和带宽使用.
我正在寻找建议和创意,以提高程序的效率 – 主要是网络部分发送的数据(通过其他方式打包或其他任何想法),我会感谢任何帮助和想法.
对于1920×1080的屏幕,具有4字节的颜色,您正在看每帧大约8 MB.有20 FPS,你有160 MB / s.所以从8 MB到200 KB(4 MB / s @ 20 FPS)是一个很大的进步.
我想提请您注意某些方面,我不确定你是专注于哪些,希望它有帮助.
压缩屏幕图像越多,可能需要的处理越多
>您实际上需要专注于为连续不断变化的图像设计的压缩机制,类似于视频编解码器(无音频).例如:H.264
>记住,您需要使用某种实时协议来传输数据.这样的想法是,如果你的一个框架让它到达目的地机器有一个滞后,你可以放下下几帧来追赶.否则你会处于一个长期的滞后状态,我怀疑用户将会喜欢.
>您可以随时牺牲品质的表现.您在类似技术(如MS远程桌面,VNC等)中看到的最简单的这种机制是发送8位颜色(ARGB每2位),而不是您使用的3字节颜色.
>另一种改善情况的方法是将焦点放在要流式传输的屏幕上的特定矩形上,而不是将整个桌面流式传输.这将减少框架本身的尺寸.
>另一种方法是在传输之前将屏幕图像缩放到较小的图像,然后在显示之前将其缩放至正常.
>发送初始屏幕后,您可以始终在新像素和先前像素之间发送差异.不用说原始屏幕和差分屏幕都将被LZ4压缩/解压缩.如果您使用一些有损耗的算法来压缩差异,那么您应该常常发送完整的数组而不是diff.
>更新区域有重叠区域吗?可以优化为不发送重复的像素信息吗?
上面的想法可以应用于另一个,以获得更好的用户体验.最终,这取决于您的应用程序和最终用户的具体情况.
编辑:
> Color Quantization 可用于减少用于颜色的位数.以下是颜色量化的具体实现的一些链接
> Optimizing Color Quantization for Images
>通常将量化的颜色存储在 Color Palette and only the index into this palette 中给予解码逻辑
代码日志版权声明:
翻译自:http://stackoverflow.com/questions/34421447/c-sharp-screen-streaming-program
以上所述就是小编给大家介绍的《C#屏幕流媒体节目》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- Go语言实战流媒体视频网站
- SRS流媒体服务器源码分析(一)
- 为什么流媒体直播的延迟很高
- 谁能接力 Flash video 流媒体传输
- PearPlayer 2.2.1 发布,流媒体播放器
- PearPlayer 2.2.2 发布,流媒体播放器
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。