我正在尝试优化屏幕共享应用程序。我已经使用了几种方法来使其更快和更稳定,例如仅在两个帧之间发送增量,并使用Gzip压缩数据。

这是我的客户代码:

    private void Form1_Load(object sender, EventArgs e)
    {

        Thread th = new Thread(startSend);
        th.Start();
       }


    private void startSend()
    {
        Bitmap curr;
        Bitmap diff;
        encoderParams.Param[0] = qualityParam;

       Bitmap pre = screenshot();

        bmpBytes = imageToByteArray(pre);

        SendVarData(handler, bmpBytes);

        while (true)
        {


            curr= screenshot();

        diff= Difference(pre, curr);


            bmpBytes = imageToByteArray(diff);


            SendVarData(handler, bmpBytes);

            pre = curr;

        }
    }

截屏:
public Bitmap screenshot()
    {

        Bitmap screenshot = new Bitmap(SystemInformation.VirtualScreen.Width,
                              SystemInformation.VirtualScreen.Height,
                              PixelFormat.Format24bppRgb);
        Graphics screenGraph = Graphics.FromImage(screenshot);
        screenGraph.CopyFromScreen(0,
                                   0,
                                   0,
                                   0,
                                   SystemInformation.VirtualScreen.Size,
                                   CopyPixelOperation.SourceCopy);

        return screenshot;

    }
Difference方法:
 public  Bitmap Difference(Bitmap bmp0, Bitmap bmp1)
    {
        Bitmap bmp2;

        int Bpp = 3;

       bmp2 = new Bitmap(bmp0.Width, bmp0.Height, bmp0.PixelFormat);

        var bmpData0 = bmp0.LockBits(
                        new Rectangle(0, 0, bmp0.Width, bmp0.Height),
                        ImageLockMode.ReadOnly, bmp0.PixelFormat);
        var bmpData1 = bmp1.LockBits(
                        new Rectangle(0, 0, bmp1.Width, bmp1.Height),
                        ImageLockMode.ReadOnly, bmp1.PixelFormat);
        var bmpData2 = bmp2.LockBits(
                        new Rectangle(0, 0, bmp2.Width, bmp2.Height),
                        ImageLockMode.ReadWrite, bmp2.PixelFormat);

        bmp0.UnlockBits(bmpData0);
        bmp1.UnlockBits(bmpData1);
        bmp2.UnlockBits(bmpData2);
        int len = bmpData0.Height * bmpData0.Stride;

     //   MessageBox.Show(bmpData0.Stride.ToString());
        bool changed=false;

        byte[] data0 = new byte[len];
        byte[] data1 = new byte[len];
        byte[] data2 = new byte[len];
        Marshal.Copy(bmpData0.Scan0, data0, 0, len);
        Marshal.Copy(bmpData1.Scan0, data1, 0, len);
        Marshal.Copy(bmpData2.Scan0, data2, 0, len);

        for (int i = 0; i < len; i += Bpp)
        {


               changed = ((data0[i] != data1[i])
                             || (data0[i + 1] != data1[i + 1])
                             || (data0[i + 2] != data1[i + 2]));



                // this.Invoke(new Action(() => this.Text = changed.ToString()));

                data2[i] = changed ? data1[i] : (byte)2;   // special markers
                data2[i + 1] = changed ? data1[i + 1] : (byte)3;   // special markers
                data2[i + 2] = changed ? data1[i + 2] : (byte)7;   // special markers
                if (Bpp == 4) data2[i + 3] =
                                 changed ? (byte)255 : (byte)42;  // special markers



        }


     //  this.Invoke(new Action(() => this.Text = changed.ToString()));
        Marshal.Copy(data2, 0, bmpData2.Scan0, len);


        return bmp2;
    }

SendVarData函数:
int total = 0;
    byte[] datasize;
    private  int SendVarData(Socket s, byte[] data)
    {
       total = 0;
        int size = data.Length;
        int dataleft = size;
        int sent;


        datasize = BitConverter.GetBytes(size);
        sent = s.Send(datasize);


            sent = s.Send(data, total, dataleft, SocketFlags.None);
            total += sent;
            dataleft -= sent;
          //  MessageBox.Show("D");

        return total;
    }

这是服务器-一开始我只是收到完整的图片,然后才收到增量:
    public void startListening()
    {

        prev =  byteArrayToImage(ReceiveVarData(client.Client));

        theImage.Image = prev;
        while (true)
        {

            data = ReceiveVarData(client.Client);

            curr = byteArrayToImage(data) ;

            merge = Merge(prev, curr);

            theImage.Image = merge;

            count++;

            prev = merge;
        }

    }

   public static Bitmap Merge(Bitmap bmp0, Bitmap bmp1)
 {

int Bpp = 3;

Bitmap bmp2 = new Bitmap(bmp0.Width, bmp0.Height, bmp0.PixelFormat);

var bmpData0 = bmp0.LockBits(
                new System.Drawing.Rectangle(0, 0, bmp0.Width, bmp0.Height),
                ImageLockMode.ReadOnly, bmp0.PixelFormat);
var bmpData1 = bmp1.LockBits(
                new System.Drawing.Rectangle(0, 0, bmp1.Width, bmp1.Height),
                ImageLockMode.ReadOnly, bmp1.PixelFormat);
var bmpData2 = bmp2.LockBits(
                new System.Drawing.Rectangle(0, 0, bmp2.Width, bmp2.Height),
                ImageLockMode.ReadWrite, bmp2.PixelFormat);
bmp0.UnlockBits(bmpData0);
bmp1.UnlockBits(bmpData1);
bmp2.UnlockBits(bmpData2);

int len = bmpData0.Height * bmpData0.Stride;
byte[] data0 = new byte[len];
byte[] data1 = new byte[len];
byte[] data2 = new byte[len];
Marshal.Copy(bmpData0.Scan0, data0, 0, len);
Marshal.Copy(bmpData1.Scan0, data1, 0, len);
Marshal.Copy(bmpData2.Scan0, data2, 0, len);

for (int i = 0; i < len; i += Bpp)
{

        bool toberestored = (data1[i] != 2 && data1[i + 1] != 3 &&
                                data1[i + 2] != 7 && data1[i + 2] != 42);
        if (toberestored)
        {
            data2[i] = data1[i];
            data2[i + 1] = data1[i + 1];
            data2[i + 2] = data1[i + 2];
            if (Bpp == 4) data2[i + 3] = data1[i + 3];
        }
        else
        {
            data2[i] = data0[i];
            data2[i + 1] = data0[i + 1];
            data2[i + 2] = data0[i + 2];
            if (Bpp == 4) data2[i + 3] = data0[i + 3];
        }


}

Marshal.Copy(data2, 0, bmpData2.Scan0, len);

return bmp2;

}

我认为它的编码很好,但是在两台具有快速且稳定的互联网连接的计算机上运行时,我仍然无法获得超过6〜7fps(8kb-100kb)的视频,而在同时运行客户端和服务器时,则无法获得最高11fps的视频在同一台计算机上。我认为这是因为增量和合并算法的复杂性,但我不知道。

如果有人可以建议如何进一步优化,我将不胜感激。

最佳答案

编写差异的代码如下所示。
我让您构建处理相反 Action 的代码,即读取差异以更新前一个图像。

    Data2Index     = 0 ; // next index for additions in data2 ;
    int idcount   = 0 ;
    int diffstart = -1 ;
    int diffstart = -1 ;
    for (int i = 0; i < len; i += Bpp)
    {
       changed = ((data0[i] != data1[i])
               || (data0[i + 1] != data1[i + 1])
               || (data0[i + 2] != data1[i + 2]));
       if (!changed)
   {
     if (idcount==ushort.MaxValue)
     { // still identical, but there is a limitation on count
           // write to data2 the identical count + differencecount equals to 0
           AddIdCountDiffCountAndDifferences(idcount,0,0) ;
           idcount = 0 ;
         }
         if (diffstart>0)
         { // after 0 or more identical values, a change was found
           // write to data2 the identical count + difference count + different pixels
           AddIdCountDiffCountAndDifferences(idcount,diffcount,diffstart) ;
       idcount = 0  ;
           diffcount= 0 ;
           diffstart=-1 ;
     }
         else identicalcount++ ; // still identical, continue until difference found
       }
       else if (diffstart<0)
       { // a difference is found after a sequence of identical pixels, store the index of first difference
         diffstart=i ; diffcount=1 ;
       }
       else
       { // different pixel follows another difference (and limitation not reached)
         if (diffcount<ushort.MaxVakue) diffcount++ ;
       }
       else
       { // limitation reached, i.e. diffcount equals 65535
         AddIdCountDiffCountAndDifferences(0,diffcount,diffstart) ;
         diffstart+=diffcount ;
         diffcount=0 ;
       }

此处用于填充data2的过程:
   private int Data2Index = 0 ; // to be reset before

   private void AddIdCountDiffCountAndDifferences(int idcount,int diffcount,int diffstart)
   {
     data2[Data2Index++]=(byte)(idcount        && 0xFF) ; // low byte of the int
     data2[Data2Index++]=(byte)(idcount   >> 8 && 0xFF) ; // second byte of the int
     data2[Data2Index++]=(byte)(diffcount      && 0xFF) ; // low byte of the int
     data2[Data2Index++]=(byte)(diffcount >> 8 && 0xFF) ; // second byte of the int
     for (int i=0;i<diffcount;i++)
     {
        data2[Data2Index++]=data1[diffstart+Bpp*i  ] ;
        data2[Data2Index++]=data1[diffstart+Bpp*i+1] ;
        data2[Data2Index++]=data1[diffstart+Bpp*i+2] ;
      }
    }

09-10 04:45