我正在致力于将捕获库从 DirectShow 转换为 MediaFoundation。捕获库似乎工作得很好,但我在运行 Windows 8 32 位的平板电脑上遇到集成网络摄像头的问题。
枚举捕获格式时(如中所述媒体基金会文档 http://msdn.microsoft.com/en-us/library/windows/desktop/ff485858%28v=vs.85%29.aspx),我得到了相机支持的以下格式:
- 0:MFVideoFormat_NV12,分辨率:448x252,帧率:30000x1001
- 1:MFVideoFormat_YUY2,分辨率:448x252,帧率:30000x1001
- 2:MFVideoFormat_NV12,分辨率:640x360,帧率:30000x1001
- 3:MFVideoFormat_YUY2,分辨率:640x360,帧率:30000x1001
- 4:MFVideoFormat_NV12,分辨率:640x480,帧率:30000x1001
- 5:MFVideoFormat_YUY2,分辨率:640x480,帧率:30000x1001
然后,我使用以下函数设置捕获格式,在本例中为索引 5 处的格式,如示例中所述:
hr = pHandler->SetCurrentMediaType(pType);
该函数执行没有错误。因此,相机应配置为以 YUY2 格式拍摄,分辨率为 640*480。
In the onReadSample 回调 http://msdn.microsoft.com/en-us/library/windows/desktop/dd374658%28v=vs.85%29.aspx,我应该收到一个缓冲区大小为 的样本:
640 * 480 * sizeof(unsigned char) * 2 = 614400 //YUY2 is encoded on 2 bytes
但是,我得到了一个缓冲区大小为 169344 的样本。下面是回调函数的一部分。
HRESULT SourceReader::OnReadSample(
HRESULT hrStatus,
DWORD dwStreamIndex,
DWORD dwStreamFlags,
LONGLONG llTimeStamp,
IMFSample *pSample // Can be NULL
)
{
EnterCriticalSection(&m_critsec);
if (pSample)
{
DWORD expectedBufferSize = 640*480*1*2; // = 614400 (hard code for the example)
IMFMediaBuffer* buffer = NULL;
hr = pSample->ConvertToContiguousBuffer(&buffer);
if (FAILED(hr))
{
//...
goto done;
}
DWORD byteLength = 0;
BYTE* pixels = NULL;
hr = buffer->Lock(&pixels, NULL, &byteLength);
//byteLength is 169344 instead of 614400
if (byteLength > 0 && byteLength == expectedBufferSize)
{
//do someting with the image, but never comes here because byteLength is wrong
}
//...
为什么我会得到尺寸为 169344 的样本,有什么建议吗?
提前致谢
感谢 Mgetz 的回答。
我检查了媒体类型的 MF_MT_INTERLACE_MODE 的值,发现视频流包含逐行帧。 MF_MT_INTERLACE_MODE 的值返回 MFVideoInterlace_Progressive。
hr = pHandler->SetCurrentMediaType(m_pType);
if(FAILED(hr)){
//
}
else
{
//get info about interlacing
UINT32 interlaceFormat = MFVideoInterlace_Unknown;
m_pType->GetUINT32(MF_MT_INTERLACE_MODE, &interlaceFormat);
//...
所以视频流不是隔行扫描的。我在 onReadSample 中再次检查 MFSampleExtension_Interlaced 的值,以查看样本是否隔行扫描,并且看起来样本是隔行扫描的。
if (pSample && m_bCapture)
{
//check if interlaced
UINT32 isSampleInterlaced = 0;
pSample->GetUINT32(MFSampleExtension_Interlaced, &isSampleInterlaced);
if(isSampleInterlaced)
{
//enters here
}
流怎么可能是逐行的而样本是隔行的?我还在 onReadSample 回调中仔细检查了 MF_MT_INTERLACE_MODE 的值,它仍然给我值 MFT_INPUT_STREAM_WHOLE_SAMPLES。
关于您的第一个建议,我无法在输入流上强制使用标志 MFT_INPUT_STREAM_WHOLE_SAMPLES 。
提前致谢
我仍然面临这个问题,我现在正在调查可用的不同流。
根据文档,每个媒体源都提供一个表示描述符,我们可以从中获取可用的流。要获取表示描述符,我们必须调用:
HRESULT hr = pSource->CreatePresentationDescriptor(&pPD);
然后,我使用 IMFPresentationDescriptor::GetStreamDescriptorCount 函数请求可用的流:
DWORD nbrStream;
pPD->GetStreamDescriptorCount(&nbrStream);
当在运行 Windows 8 的 ACER 平板电脑上的前置网络摄像头上请求此信息时,我得到了三个可用的流。我循环访问这些流,请求它们的 MediaTypeHandler 并检查 MajorType。这三个流的主要类型为:MFMediaType_Video,因此所有流都是视频流。当列出不同流上可用的媒体类型时,我发现所有流都支持以 640x480 捕获。 (某些流具有更多可用的媒体类型)。
我测试选择每个不同的流和适当的格式类型(框架没有返回任何错误),但我仍然没有在回调函数中收到正确的样本...
对于解决这个问题有什么建议吗?
终于找到了问题:我必须使用 SourceReader->SetCurrentMediaType(..) 直接在源阅读器上设置媒体类型。这就成功了!
感谢您的帮助!