1

我首先要说这个问题与另一个问题非常相似- 我希望主要区别在于,我将提供足够的上下文来解决这个问题:)

我正在为专有的 UVC 相机设备编写 C++ 库,该设备利用 ms 媒体基础来抓取帧以通过自定义 C++/CUDA/C# 应用程序进行处理和显示。相机在正常使用过程中偶尔会与设备连接和分离,大约 15% 的时间会发生这种情况:

成功创建 IMFSourceReader 对象后,将对 ReadSample 进行后续异步调用。回调函数首先被调用,“hrStatus”设置为 S_OK,dwStreamFlags 设置为指示的 MF_SOURCE_READERF_STREAMTICK。在此之后,对 ReadSample 函数的任何后续调用都不会引发对已注册 OnReadSample 回调的调用。

下面包括 SourceReader 初始化代码、对 ReadSample 的调用和 OnReadSample 实现的片段。

Source Reader 对象的初始化代码

      // Create the media source
      res = SUCCEEDED(CreateVideoDeviceSource(&cap_mediasrc_des));
      if (!res)
      {
         std::cout << "Failed to create video device source" << std::endl;
      }

      // Get the stream and presentation descriptors to set data type
      .
      . excluded this code for brevity
      .

      // Create source reader object and get handle to it
      if (res)
      {
         // Create attributes store for the source reader
         // to indicate that it should be used asynchronously
         HRESULT hr = S_OK;
         IMFAttributes *src_rdr_attr = NULL;

         res = SUCCEEDED(hr = MFCreateAttributes(&src_rdr_attr, 1));

         if (res)
         {
            res = SUCCEEDED(hr = src_rdr_attr->SetUnknown(MF_SOURCE_READER_ASYNC_CALLBACK, &frame_src_reader_cb));
         }

         if (res)
         {
            res = SUCCEEDED(MFCreateSourceReaderFromMediaSource(cap_mediasrc_des, src_rdr_attr, &cap_src_rdr_h));
            if (!res)
            {
               std::cout << "Failed to create source reader from media source" << std::endl;
            }
         }
      }

对 ReadSample 的调用 - 在连续运行的循环中进行

      res = SUCCEEDED(capture_result = cap_src_rdr_h->ReadSample(
         MF_SOURCE_READER_FIRST_VIDEO_STREAM,
         0,
         NULL,
         NULL,
         NULL,
         NULL
      ));

      if (res)
      {
         // wait for async call to finish or to timeout, whichever comes first
         std::uint32_t timeout_cnt = 0U;
         while (!read_sample_available && (timeout_cnt < 100U)) 
         {
            Sleep(1);
            timeout_cnt++;
         }

         if (timeout_cnt >= 100U)
         {
            read_time_expired = true;
         }
      } 

最后是 OnReadSample 的实现(为简洁起见,排除了一些图像处理代码)

   HRESULT FrameSource::FrameSourceReaderCallback::OnReadSample(
      HRESULT   hrStatus,
      DWORD     dwStreamIndex,
      DWORD     dwStreamFlags,
      LONGLONG  llTimestamp,
      IMFSample *pSample
   )
   {
      HRESULT res = hrStatus;

      // Check the flags
      if (((dwStreamFlags & MF_SOURCE_READERF_STREAMTICK) != MF_SOURCE_READERF_STREAMTICK) && (dwStreamFlags > 0))
      {
         // If the flags indicate something other than just MF_SOURCE_READERF_STREAMTICK, we've run into a problem
         // Retain hrStatus if possible
         res = SUCCEEDED(hrStatus) ? S_FALSE : hrStatus; 

         FrameSource::GetInstance().read_sample_available = false;
      }
      else if ((dwStreamFlags & MF_SOURCE_READERF_STREAMTICK) == MF_SOURCE_READERF_STREAMTICK)
      {
         // There isn't a new frame to grab
         FrameSource::GetInstance().read_sample_available = false;
         }
      }
      else if (SUCCEEDED(res))
      {
         // Good frame available
         IMFMediaBuffer* in_buff_h = nullptr;
         IMF2DBuffer2* in_buff2d_h = nullptr;
         IMFMediaBuffer* out_buff_h = nullptr;
         IMF2DBuffer2* out_buff2d_h = nullptr;

         ... here we convert the sample to a contiguous buffer, read some data out of it,
         ... run it through a color conversion MFT, and copy it into a CUDA GPU resident buffer
         ... excluded for brevity

         if (SUCCEEDED(res))
         {
            frm_src_ref.read_sample_available = true;
         }

         // Make sure to release everything that we allocated
         if (in_buff_h != nullptr)
         {
            in_buff_h->Release();
         }

         if (in_buff2d_h != nullptr)
         {
            in_buff2d_h->Release();
         }

         if (out_buff_h != nullptr)
         {
            out_buff_h->Release();
         }

         if (out_buff2d_h != nullptr)
         {
            out_buff2d_h->Release();
         }
      }
      else
      {
         // res failed, but no flags?
         std::cout << "OnReadSample failed, but there are no error flags" << std::endl;
      }
      return res;
   }

我被难住了,并且已经被难住了一段时间。我会假设如果在第一个 ReadSample 调用的 UVC 方面存在一些问题,那么我将能够简单地诊断出这个问题。最初,我有一个 ReadSample 的同步实现,它会遇到以相同方式呈现的问题(第一次调用给了 MF_SOURCE_READERF_STREAMTICK,下一个从未返回)。我想知道是否有其他媒体基础方法来检查媒体源的状态,以便我可以进一步调试?

你们怎么想?我正在运行 Windows 10 Pro 64 位(10.0,内部版本 18363)以供参考。非常感谢任何和所有帮助。谢谢!

4

0 回答 0