我首先要说这个问题与另一个问题非常相似- 我希望主要区别在于,我将提供足够的上下文来解决这个问题:)
我正在为专有的 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)以供参考。非常感谢任何和所有帮助。谢谢!