C# · 12月 22, 2021

c# – 寻找提高代码速度的信息

我有一些代码可以从720p和24fps的摄像头流式传输视频.我试图在代码中捕获这个流,并最终通过将压缩的jpegs放在mjpeg等中来创建它的视频.我遇到的问题是这个整体代码不够快,无法以每帧24 fps或.04秒的速度创建.

运用

Stopwatch();

我发现循环的内部每个循环需要.000000000022秒.

每个循环完成循环的外部需要.0000077秒.

我发现从开始到图像保存的整个功能每次运行运行.21秒.

从内部循环计算完成图像:

.000000000022 x 640 = .000000001408 seconds.000000001408 x 360 = .00000050688 seconds

从外部循环计算到完成图像:

.0000077 x 360 = .002772 seconds

如果我可以创建一个与我将被设置的时间相关的图像,但运行整个代码的代码需要.21秒来完成所有代码

temp_byte1 = main_byte1;temp_byte2 = main_byte2;timer1.Reset();timer1.Start();Bitmap mybmp = new Bitmap(1280,720);BitmapData BPD = mybmp.LockBits(new Rectangle(0,1280,720),ImageLockMode.writeonly,mybmp.PixelFormat);IntPtr xptr = BPD.Scan0;IntPtr yptr = BPD.Scan0;yptr = new IntPtr( yptr.ToInt64() + (1280 * 720 * 2));int bytes = Math.Abs(BPD.Stride);byte[][] rgb = new byte[720][];int Y1,Y2,Y3,Y4,Y5,Y6,Y7,Y8;int U1,U2,V1,V2,U3,U4,V3,V4;for (int one = 0; one < 360; one++){ timer2.Reset(); timer2.Start(); rgb[one] = new byte[bytes]; rgb[360 + one] = new byte[bytes]; for (int two = 0; two < 640; two++) { timer3.Reset(); timer3.Start(); U1 = temp_byte1[one * 2560 + 4 * two + 0]; Y1 = temp_byte1[one * 2560 + 4 * two + 1]; V1 = temp_byte1[one * 2560 + 4 * two + 2]; Y2 = temp_byte1[one * 2560 + 4 * two + 3]; U2 = temp_byte2[one * 2560 + 4 * two + 0]; Y3 = temp_byte2[one * 2560 + 4 * two + 1]; V2 = temp_byte2[one * 2560 + 4 * two + 2]; Y4 = temp_byte2[one * 2560 + 4 * two + 3]; RGB_Conversion(Y1,U1,two * 8 + 0,rgb[one]); RGB_Conversion(Y2,two * 8 + 4,rgb[one]); RGB_Conversion(Y3,rgb[(360 + one)]); RGB_Conversion(Y4,rgb[(360 + one)]); timer3.Stop(); timer3_[two] = timer3.Elapsed; } Marshal.Copy(rgb[one],xptr,5120); xptr = new IntPtr(xptr.ToInt64() + 5120); Marshal.Copy(rgb[(360 + one)],yptr,5120); yptr = new IntPtr(yptr.ToInt64() + 5120); timer2.Stop(); timer2_[one] = timer2.Elapsed;}mybmp.UnlockBits(BPD);mybmp.Save(GetDateTimeString(“IP Pictures”) + “.jpg”,ImageFormat.Jpeg);

代码工作,它将yuv422传入的字节数组转换为完整大小的jpeg,但无法理解为什么for循环的速度和整个代码之间存在这样的差异

我感动了

byte[][]rgb = new byte[720]; rgb[x] = new byte[bytes];

在程序启动时获取init而不是每个函数调用/运行没有可测量的速度增加的全局.

UPDATE

RGB转换:接收YUV并将其转换为RGB并将其放入保存值的全局数组中

public void RGB_Conversion(int Y,int U,int V,int MULT,byte[] rgb){ int C,D,E; int R,G,B; // create the params for rgb conversion C = Y – 16; D = U – 128; E = V – 128; //R = clamp((298 x C + 409 x E + 128)>>8) //G = clamp((298 x C – 100 x D – 208 x E + 128)>>8) //B = clamp((298 x C + 516 x D + 128)>>8) R = (298 * C + 409 * E + 128)/256; G = (298 * C – 100 * D – 208 * E + 128)/256; B = (298 * C + 516 * D + 128)/256; if (R > 255) R = 255; if (R < 0) R = 0; if (G > 255) G = 255; if (G < 0) G = 0; if (B > 255) B = 255; if (B < 0) B = 0; rgb[MULT + 3] = 255; rgb[MULT + 0] = (byte)B; rgb[MULT + 1] = (byte)G; rgb[MULT + 2] = (byte)R; }解决方法 首先

您需要从循环内部删除开始/停止和秒表业务

在紧密的循环中重置秒表640x会使数字偏斜.更好地使用分析器或测量粗粒度性能.

此外,这些语句的存在可能会阻止编译器优化(循环平铺和循环展开看起来是非常好的候选者,但是JITter可能无法使用它们,因为寄存器被破坏以调用秒表函数…

数据结构:

我觉得你应该能够使用’扁平’数据结构,而不是在那里新建所有锯齿状数组.也就是说,我不知道你正在为它提供什么样的API,而且我没有对它进行过多的考虑.

我确实认为让RGB_Conversion’只是’返回RGB部分而不是让它写入数组可能真的给编译器提供优化的优势.

其他想法:

>查看RGB_Conversion(其中/如何定义?).也许你可以把它拉成内联.
>使用unchecked block来阻止所有数组索引操作检查溢出
>考虑使用/不安全代码(here)以避免边界检查