Начну с того, что этот вопрос очень похож на этот другой - основное отличие будет, я надеюсь, я предоставлю достаточно контекста, чтобы иметь возможность решить проблему :)
Я пишу библиотеку C ++ для проприетарного устройства камеры UV C, которое использует MS Media Foundation для захвата кадров для обработки и отображения с помощью специального приложения 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 - выполняется в al oop, который выполняется постоянно
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;
}
Я в тупике и довольно долгое время был в тупике. Я бы предположил, что если бы была какая-то проблема на стороне UV C, то первый вызов ReadSample указывал бы на это, и я мог бы просто диагностировать эту проблему. Первоначально у меня была синхронная реализация ReadSample, которая столкнулась с проблемой, представленной таким же образом (первый вызов дал MF_SOURCE_READERF_STREAMTICK, следующий никогда не вернулся). Мне остается только гадать, есть ли какой-нибудь другой способ проверки состояния медиаисточника, чтобы я мог отладить его дальше?
Что вы думаете? Я использую Windows 10 Pro 64-Bit (10.0, сборка 18363) для справки. Любая помощь очень ценится. Спасибо!