|
|
|
@ -1047,24 +1047,31 @@ bool CvCapture_MSMF::open(const cv::String& _filename) |
|
|
|
|
|
|
|
|
|
bool CvCapture_MSMF::grabFrame() |
|
|
|
|
{ |
|
|
|
|
CV_TRACE_FUNCTION(); |
|
|
|
|
if (isOpen) |
|
|
|
|
{ |
|
|
|
|
DWORD streamIndex, flags; |
|
|
|
|
if (videoSample) |
|
|
|
|
videoSample.Reset(); |
|
|
|
|
HRESULT hr; |
|
|
|
|
while(SUCCEEDED(hr = videoFileSource->ReadSample( |
|
|
|
|
for(;;) |
|
|
|
|
{ |
|
|
|
|
CV_TRACE_REGION("ReadSample"); |
|
|
|
|
if (!SUCCEEDED(hr = videoFileSource->ReadSample( |
|
|
|
|
dwStreamIndex, // Stream index.
|
|
|
|
|
0, // Flags.
|
|
|
|
|
&streamIndex, // Receives the actual stream index.
|
|
|
|
|
&flags, // Receives status flags.
|
|
|
|
|
&sampleTime, // Receives the time stamp.
|
|
|
|
|
&videoSample // Receives the sample or NULL.
|
|
|
|
|
)) && |
|
|
|
|
streamIndex == dwStreamIndex && !(flags & (MF_SOURCE_READERF_ERROR|MF_SOURCE_READERF_ALLEFFECTSREMOVED|MF_SOURCE_READERF_ENDOFSTREAM)) && |
|
|
|
|
!videoSample |
|
|
|
|
) |
|
|
|
|
{ |
|
|
|
|
))) |
|
|
|
|
break; |
|
|
|
|
if (streamIndex != dwStreamIndex) |
|
|
|
|
break; |
|
|
|
|
if (flags & (MF_SOURCE_READERF_ERROR | MF_SOURCE_READERF_ALLEFFECTSREMOVED | MF_SOURCE_READERF_ENDOFSTREAM)) |
|
|
|
|
break; |
|
|
|
|
if (videoSample) |
|
|
|
|
break; |
|
|
|
|
if (flags & MF_SOURCE_READERF_STREAMTICK) |
|
|
|
|
{ |
|
|
|
|
DebugPrintOut(L"\tStream tick detected. Retrying to grab the frame\n"); |
|
|
|
@ -1117,39 +1124,80 @@ bool CvCapture_MSMF::grabFrame() |
|
|
|
|
|
|
|
|
|
bool CvCapture_MSMF::retrieveFrame(int, cv::OutputArray frame) |
|
|
|
|
{ |
|
|
|
|
DWORD bcnt; |
|
|
|
|
if (videoSample && SUCCEEDED(videoSample->GetBufferCount(&bcnt)) && bcnt > 0) |
|
|
|
|
CV_TRACE_FUNCTION(); |
|
|
|
|
do |
|
|
|
|
{ |
|
|
|
|
if (!videoSample) |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
_ComPtr<IMFMediaBuffer> buf = NULL; |
|
|
|
|
if (SUCCEEDED(videoSample->GetBufferByIndex(0, &buf))) |
|
|
|
|
|
|
|
|
|
CV_TRACE_REGION("get_contiguous_buffer"); |
|
|
|
|
if (!SUCCEEDED(videoSample->ConvertToContiguousBuffer(&buf))) |
|
|
|
|
{ |
|
|
|
|
DWORD maxsize, cursize; |
|
|
|
|
CV_TRACE_REGION("get_buffer"); |
|
|
|
|
DWORD bcnt = 0; |
|
|
|
|
if (!SUCCEEDED(videoSample->GetBufferCount(&bcnt))) |
|
|
|
|
break; |
|
|
|
|
if (bcnt == 0) |
|
|
|
|
break; |
|
|
|
|
if (!SUCCEEDED(videoSample->GetBufferByIndex(0, &buf))) |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool lock2d = false; |
|
|
|
|
BYTE* ptr = NULL; |
|
|
|
|
if (SUCCEEDED(buf->Lock(&ptr, &maxsize, &cursize))) |
|
|
|
|
LONG pitch = 0; |
|
|
|
|
DWORD maxsize = 0, cursize = 0; |
|
|
|
|
|
|
|
|
|
// "For 2-D buffers, the Lock2D method is more efficient than the Lock method"
|
|
|
|
|
// see IMFMediaBuffer::Lock method documentation: https://msdn.microsoft.com/en-us/library/windows/desktop/bb970366(v=vs.85).aspx
|
|
|
|
|
_ComPtr<IMF2DBuffer> buffer2d; |
|
|
|
|
if (convertFormat) |
|
|
|
|
{ |
|
|
|
|
if (SUCCEEDED(buf.As<IMF2DBuffer>(&buffer2d))) |
|
|
|
|
{ |
|
|
|
|
CV_TRACE_REGION_NEXT("lock2d"); |
|
|
|
|
if (SUCCEEDED(buffer2d->Lock2D(&ptr, &pitch))) |
|
|
|
|
{ |
|
|
|
|
lock2d = true; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (ptr == NULL) |
|
|
|
|
{ |
|
|
|
|
CV_Assert(lock2d == false); |
|
|
|
|
CV_TRACE_REGION_NEXT("lock"); |
|
|
|
|
if (!SUCCEEDED(buf->Lock(&ptr, &maxsize, &cursize))) |
|
|
|
|
{ |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (!ptr) |
|
|
|
|
break; |
|
|
|
|
if (convertFormat) |
|
|
|
|
{ |
|
|
|
|
if ((unsigned int)cursize == captureFormat.MF_MT_SAMPLE_SIZE) |
|
|
|
|
if (lock2d || (unsigned int)cursize == captureFormat.MF_MT_SAMPLE_SIZE) |
|
|
|
|
{ |
|
|
|
|
switch (outputFormat) |
|
|
|
|
{ |
|
|
|
|
case CV_CAP_MODE_YUYV: |
|
|
|
|
cv::Mat(captureFormat.height, captureFormat.width, CV_8UC2, ptr).copyTo(frame); |
|
|
|
|
cv::Mat(captureFormat.height, captureFormat.width, CV_8UC2, ptr, pitch).copyTo(frame); |
|
|
|
|
break; |
|
|
|
|
case CV_CAP_MODE_BGR: |
|
|
|
|
if (captureMode == MODE_HW) |
|
|
|
|
cv::cvtColor(cv::Mat(captureFormat.height, captureFormat.width, CV_8UC4, ptr), frame, cv::COLOR_BGRA2BGR); |
|
|
|
|
cv::cvtColor(cv::Mat(captureFormat.height, captureFormat.width, CV_8UC4, ptr, pitch), frame, cv::COLOR_BGRA2BGR); |
|
|
|
|
else |
|
|
|
|
cv::Mat(captureFormat.height, captureFormat.width, CV_8UC3, ptr).copyTo(frame); |
|
|
|
|
cv::Mat(captureFormat.height, captureFormat.width, CV_8UC3, ptr, pitch).copyTo(frame); |
|
|
|
|
break; |
|
|
|
|
case CV_CAP_MODE_RGB: |
|
|
|
|
if (captureMode == MODE_HW) |
|
|
|
|
cv::cvtColor(cv::Mat(captureFormat.height, captureFormat.width, CV_8UC4, ptr), frame, cv::COLOR_BGRA2BGR); |
|
|
|
|
cv::cvtColor(cv::Mat(captureFormat.height, captureFormat.width, CV_8UC4, ptr, pitch), frame, cv::COLOR_BGRA2BGR); |
|
|
|
|
else |
|
|
|
|
cv::cvtColor(cv::Mat(captureFormat.height, captureFormat.width, CV_8UC3, ptr), frame, cv::COLOR_BGR2RGB); |
|
|
|
|
cv::cvtColor(cv::Mat(captureFormat.height, captureFormat.width, CV_8UC3, ptr, pitch), frame, cv::COLOR_BGR2RGB); |
|
|
|
|
break; |
|
|
|
|
case CV_CAP_MODE_GRAY: |
|
|
|
|
cv::Mat(captureFormat.height, captureFormat.width, CV_8UC1, ptr).copyTo(frame); |
|
|
|
|
cv::Mat(captureFormat.height, captureFormat.width, CV_8UC1, ptr, pitch).copyTo(frame); |
|
|
|
|
break; |
|
|
|
|
default: |
|
|
|
|
frame.release(); |
|
|
|
@ -1161,13 +1209,15 @@ bool CvCapture_MSMF::retrieveFrame(int, cv::OutputArray frame) |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
cv::Mat(1, cursize, CV_8UC1, ptr).copyTo(frame); |
|
|
|
|
cv::Mat(1, cursize, CV_8UC1, ptr, pitch).copyTo(frame); |
|
|
|
|
} |
|
|
|
|
CV_TRACE_REGION_NEXT("unlock"); |
|
|
|
|
if (lock2d) |
|
|
|
|
buffer2d->Unlock2D(); |
|
|
|
|
else |
|
|
|
|
buf->Unlock(); |
|
|
|
|
return !frame.empty(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} while (0); |
|
|
|
|
|
|
|
|
|
frame.release(); |
|
|
|
|
return false; |
|
|
|
|