簡體   English   中英

在 C# 中的線程中接收幀的最佳方式

[英]Best way of receiving frames in a thread in C#

我在從 HoloLens 接收幀時遇到問題。 基本上我正在捕獲幀並使用一個套接字連接將其發送到服務器。 當 HoloLens 使用Task.Run(#send to server call)獲取幀時,我曾經將幀發送到服務器,但問題是它在開始時工作正常,但隨后每秒幀數 (FPS) 下降到零並且問題我發現它基本上制造了太多線程並且產生了瓶頸(這就是我想出來的)所以現在我所做的是而不是使用Task.Run(#send to server call)我使用Parallel.Invoke(#send to server call) ,但它給出了低 FPS,我發現它的原因是,當它在這個調用調用上工作時,有一些幀到達,導致低 FPS。 我也嘗試了 async/await 方法,但仍然發生了同樣的瓶頸,並且 FPS 降低到零。 我也嘗試使用取消令牌,但也沒有用。 這是 function ,它在幀到達 HoloLens 時調用。

    private void ColorFrameReader_FrameArrivedAsync(MediaFrameReader sender, MediaFrameArrivedEventArgs args)
    {
        var frame = sender.TryAcquireLatestFrame();
        if (frame != null)
        {
            SoftwareBitmap originalBitmap = null;
            var inputBitmap = frame.VideoMediaFrame?.SoftwareBitmap;
            if (inputBitmap != null)
            {
                // The XAML Image control can only display images in BRGA8 format with premultiplied or no alpha
                // The frame reader as configured in this sample gives BGRA8 with straight alpha, so need to convert it
                originalBitmap = SoftwareBitmap.Convert(inputBitmap, BitmapPixelFormat.Bgra8, BitmapAlphaMode.Premultiplied);                 
                SoftwareBitmap outputBitmap = new SoftwareBitmap(BitmapPixelFormat.Bgra8, originalBitmap.PixelWidth, originalBitmap.PixelHeight, BitmapAlphaMode.Premultiplied);

                //this thread goes to the c++ code and start the TCP communication                
                //var task = Task.Factory.StartNew(() => { ct.ThrowIfCancellationRequested(); _helper.Connect(originalBitmap); }, cts.Token);
                
                ab_func(originalBitmap);
                                                                            
               //System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(_helper.Connect(originalBitmap)));
                //Windows.System.Threading.ThreadPool.RunAsync                    
                //Parallel.Invoke(() => _helper.Connect(originalBitmap));
                //task.Start();
            }

            Interlocked.Increment(ref _frameCount);
        }
    }

    async void ab_func(SoftwareBitmap fr)
    {
       await Task.Run(() => { _helper.Connect(fr); });
    }

以下是有關 C++ 文件的連接方法的更多信息。 _helper基本上是 C++ class 的 object。

void OpenCVHelper::Connect(SoftwareBitmap^ input)
{
  Mat inputMat, outputMat;
  if (!(TryConvert(input)))
  {
      return;
  }
int imgSize = GlobalMat.total() * GlobalMat.elemSize();
//m_OutStream << "GlobalMat.total()  " << GlobalMat.total();
//m_OutStream << "GlobalMat.total()  " << GlobalMat.elemSize();
int i = 1;
//m_OutStream << "i value is  \n"<<i;
auto t0 = std::chrono::system_clock::now();
auto nanosec = t0.time_since_epoch();


if (ConnectSocket == INVALID_SOCKET) {
    //printf("Unable to connect to server!\n");
    //m_OutStream << "Unable to connect to server! 2\n" << WSAGetLastError();
    WSACleanup();
    return;
}
uchar* iptr = GlobalMat.data;
t0 = std::chrono::system_clock::now();
nanosec = t0.time_since_epoch();
m_OutStream << "timestamp before sending of frame " << i++ << " = " << std::chrono::duration_cast<std::chrono::milliseconds>(nanosec).count() << std::endl;


//send the frame to the server
if ((bytes = send(ConnectSocket, (char*)iptr, imgSize, 0)) < 0) {
    //m_OutStream << "bytes = " << bytes << std::endl;
    m_OutStream << "problem 2 ! \n";
    //break;
}

return;
}

這是調試屏幕截圖,我說它制造了太多線程並造成瓶頸。 調試截圖

顯然,瓶頸是通過網絡發送幀。 任務、 System.Threading.ThreadPool.QueueUserWorkItemParallel.Invoke都使用線程池。 通過 TCP 發送幀顯然很慢,並且新任務在線程池中排隊的速度比線程再次空閑的速度要快,並且您很快就會耗盡線程池。

更好的方法是將所有幀排隊到本地隊列ConcurrentQueue<t>中,並讓一些線程消耗隊列並將幀發送到服務器。 通過這種方式,您將能夠更快地從設備讀取幀(更高的 FPS)。 缺點是停止接收幀后,您仍然需要等待所有幀都發送到服務器。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM