C#螢幕流媒體節目
最近我一直在做一個簡單的螢幕共享程式.
實際上該程式的工作原理是一個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包裝器壓縮緩衝區(參見ofollow,noindex" target="_blank">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