2017-04-19 80 views
1

我有一个MOV文件,我想解码它,并将所有帧作为单独的图像。媒体基金会设置视频隔行扫描和解码

所以我尝试按以下方式配置未压缩的媒体类型:

// configure the source reader 
IMFSourceReader* m_pReader; 
MFCreateSourceReaderFromURL(filePath, NULL, &m_pReader); 

// get the compressed media type 
IMFMediaType* pFileVideoMediaType; 
m_pReader->GetCurrentMediaType(MF_SOURCE_READER_FIRST_VIDEO_STREAM, &pFileVideoMediaType); 

// create new media type for uncompressed type 
IMFMediaType* pTypeUncomp; 
MFCreateMediaType(&pTypeUncomp); 

// copy all settings from compressed to uncompressed type 
pFileVideoMediaType->CopyAllItems(pTypeUncomp); 

// set the uncompressed video attributes 
pTypeUncomp->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_RGB8); 
pTypeUncomp->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE); 
pTypeUncomp->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive); 

// set the new uncompressed type to source reader 
m_pReader->SetCurrentMediaType(MF_SOURCE_READER_FIRST_VIDEO_STREAM, 0, pTypeUncomp); 

// get the full uncompressed media type 
m_pReader->GetCurrentMediaType(MF_SOURCE_READER_FIRST_VIDEO_STREAM, &pTypeUncomp); 

我注意到,即使我明确设置MF_MT_INTERLACE_MODEMFVideoInterlace_Progressive最终配置仍与旧模式MFVideoInterlace_MixedInterlaceOrProgressive配置。

之后,我遍历所有的样本,看看它们的大小:

IMFSample* videoSample = nullptr; 
IMFMediaBuffer* mbuffer = nullptr; 
LONGLONG llTimeStamp; 
DWORD streamIndex, flags; 

m_pReader->ReadSample(
      MF_SOURCE_READER_FIRST_VIDEO_STREAM, 
      0,        // Flags. 
      &streamIndex,     // Receives the actual stream index. 
      &flags,       // Receives status flags. 
      &llTimeStamp,     // Receives the time stamp. 
      &videoSample)     // Receives the sample or NULL. 

videoSample->ConvertToContiguousBuffer(&mbuffer); 

BYTE* videoData = nullptr; 
DWORD sampleBufferLength = 0; 

mbuffer->Lock(&videoData, nullptr, &sampleBufferLength); 
cout << sampleBufferLength << endl; 

我也得到了相当的样本大小不同:从31bytes到18000bytes。 即使将格式更改为MFVideoFormat_RGB32也不会影响样本大小。

This问题似乎有同样的问题,但解决方案没有解决它。

为什么我不能改变隔行扫描以及如何正确解码视频帧并从样本中获取图像数据?

非常感谢提前。

+1

也许你应该尝试先调用GetNativeMediaType而不是m_pReader-> GetCurrentMediaType(MF_SOURCE_READER_FIRST_VIDEO_STREAM,&pFileVideoMediaType);.你还检查每个样本是否交错:pSample-> GetUINT32(MFSampleExtension_Interlaced,&isSampleInterlaced); – VuVirt

+1

您可以在此检查ConfigureDecoder函数:https://msdn.microsoft.com/en-us/library/windows/desktop/dd389281(v=vs.85).aspx#setting_output_formats。调用ReadSample时,您还可以在收到状态标志中检查MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED,以查看类型是否已更改。 – VuVirt

+0

@VuVirt,感谢您的评论。获取本地媒体类型不会改变任何内容。检查隔行扫描样本最终出现错误。并没有媒体类型的变化。你脑子里还有别的东西吗?如果你能找到几分钟看我的代码:https://github.com/mbaros100/Media-Foundation-video-decoder。非常感谢您的帮助。 – mbaros

回答

1

为了使SourceReader转换样本为RGB,你需要这样的创建:

IMFAttributes* pAttr = NULL; 
MFCreateAttributes(&pAttr, 1); 
pAttr->SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, TRUE); 
pAttr->SetUINT32(MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING, TRUE); 

IMFSourceReader* m_pReader; 
throwIfFailed(MFCreateSourceReaderFromURL(filePath, pAttr, &m_pReader), Can't create source reader from url"); 
pAttr->Release(); 

后来,你不应该从循环时MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED发生断裂。现在您将拥有相同尺寸的所有样本。 否则,您可以使用MFVideoFormat_NV12子类型,然后在创建阅读器时不需要指定MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING属性。 注意:MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING仅在Windows 8和更高版本上受支持。

+0

为我工作。非常感谢你。 – mbaros

+0

让我再问你一个问题。对于某些文件,我得到的缓冲区大小完全匹配图像高度*宽度* 4,数据是正确的。对于其他一些文件,我得到的缓冲区大小比高*宽* 4大。你知道这些额外的数据代表什么吗? – mbaros

+0

VuVirt,我看到你的答案http://stackoverflow.com/questions/43014780/extarct-rgb32-byte-data-from-imfsample/43027190#43027190,这是非常好的。正如你所说的,我试图将我的IMFSample锁定为2D数据,但是我最终出现了一个错误。你能否也请分享一段代码,展示如何正确锁定和访问2D样本数据?在此先感谢 – mbaros