当前位置:  开发笔记 > 编程语言 > 正文

C#屏幕流媒体节目

如何解决《C#屏幕流媒体节目》经验,为你挑选了1个好方法。

最近我一直在做一个简单的屏幕共享程序.

实际上,该程序可以TCP protocol使用桌面复制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速率观看,我将不得不对此进行一些工作 - 以最小化网络流量和带宽使用.

我正在寻找建议和创意,以提高计划的效率 - 主要是在网络部分发送的数据(通过以其他方式或任何其他方式包装)我会感激任何帮助和想法.谢谢.



1> Vikhram..:

对于屏幕为1920 x 1080,具有4字节颜色,​​您每帧大约需要8 MB.使用20 FPS,您可以达到160 MB/s.因此从8 MB到200 KB(4 MB/s @ 20 FPS)是一个很大的改进.

我想提醒你注意我不确定你关注的某些方面,希望它有所帮助.

    压缩屏幕图像越多,它可能需要的处理就越多

    实际上,您需要专注于为一系列连续变化的图像设计的压缩机制,类似于视频编解码器(尽管没有音频).例如:H.264

    请记住,您需要使用某种实时协议来传输数据.这背后的想法是,如果你的一个框架使其延迟到目的地机器,你可以放下接下来的几帧来追赶.否则你将陷入常年滞后的境地,我怀疑用户会喜欢.

    你总是可以牺牲质量来提高性能.您在类似技术(如MS远程桌面,VNC等)中看到的最简单的此类机制是发送8位颜色(每个2位的ARGB)而不是您正在使用的3字节颜色.

    改善您的情况的另一种方法是关注屏幕上您要流式传输的特定矩形,而不是流式传输整个桌面.这将减小框架本身的尺寸.

    另一种方法是在传输之前将屏幕图像缩放为较小的图像,然后在显示之前将其缩放回正常状态.

    发送初始屏幕后,您始终可以在newpixels和之间发送差异previouspixels.不用说原始屏幕和差异屏幕都将被LZ4压缩/解压缩.如果你使用一些有损算法来压缩差异,你应该经常发送完整的数组而不是diff.

    UpdatedRegions是否有重叠区域?可以优化以不发送重复的像素信息吗?

上述想法可以一个接一个地应用,以获得更好的用户体验.最终,它取决于您的应用程序和最终用户的具体情况.

编辑:

颜色量化可用于减少用于颜色的位数.以下是颜色量化的具体实现的一些链接

优化图像颜色量化

nQuant图书馆

通常,量化的颜色存储在调色板中,并且只有该调色板的索引被提供给解码逻辑

推荐阅读
ar_wen2402851455
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有