我试图解码一个mp4视频使用类和转换帧到2D纹理,可以使用DirectX着色器进行渲染。我已经能够使用MFCreateSourceReaderfromURL读取源流,并能够读取流的媒体类型,该流的主要类型是MFMEdiaType_Video,次要类型与预期的MFVideoFormat_H264相同。
我现在需要将这种格式转换成RGB格式,该格式可以用于初始化D3D11_TEXTURE2D资源和资源视图,然后可以传递给HLSL像素着色器进行采样。我已经厌倦了使用IMFTransform类来为我进行转换,但是当我试图在转换中设置输出类型到任何MFVideoFormat_RGB变量时,我会得到一个错误。我还尝试在源读取器上设置一个新的输出类型,只对希望得到正确格式的示例进行采样,但我还是没有运气。
所以我的问题是:
所使用的操作系统是Windows 7,所以我不能使用SourceReaderEx或ID3D11VideoDevice接口,因为据我所知,这些解决方案似乎只能在Windows 8上使用。
任何正确方向的帮助/指针都将不胜感激,如果有必要,我也可以提供一些源代码。
发布于 2016-05-26 22:52:40
我发现你在理解媒体基金会方面有一些错误。您希望从MFVideoFormat_H264获取RGB格式的图像,但不使用解码器H264。你写了“我厌倦了使用IMFTransform类”-- IMFTransform不是类。它是转换COM对象的接口。必须创建COM对象媒体基金会H264解码器。用于微软软件H264解码器的CLSID是CLSID_CMSH264DecoderMFT。但是,从该解码器可以获得下一种格式的输出图像:输出类型。
MFVideoFormat_I420
MFVideoFormat_IYUV
MFVideoFormat_NV12
MFVideoFormat_YUY2
MFVideoFormat_YV12
您可以从其中一个创建D3D11_TEXTURE2D。或者您可以在我的项目CaptureManager SDK中这样做:
CComPtrCustom<IMFTransform> lColorConvert;
if (!Result(lColorConvert.CoCreateInstance(__uuidof(CColorConvertDMO))))
{
lresult = MediaFoundationManager::setInputType(
lColorConvert,
0,
lVideoMediaType,
0);
if (lresult)
{
break;
}
DWORD lTypeIndex = 0;
while (!lresult)
{
CComPtrCustom<IMFMediaType> lOutputType;
lresult = lColorConvert->GetOutputAvailableType(0, lTypeIndex++, &lOutputType);
if (!lresult)
{
lresult = MediaFoundationManager::getGUID(
lOutputType,
MF_MT_SUBTYPE,
lSubType);
if (lresult)
{
break;
}
if (lSubType == MFVideoFormat_RGB32)
{
LONG lstride = 0;
MediaFoundationManager::getStrideForBitmapInfoHeader(
lSubType,
lWidth,
lstride);
if (lstride < 0)
lstride = -lstride;
lBitRate = (lHight * (UINT32)lstride * 8 * lNumerator) / lDenominator;
lresult = MediaFoundationManager::setUINT32(
lOutputType,
MF_MT_AVG_BITRATE,
lBitRate);
if (lresult)
{
break;
}
PROPVARIANT lVarItem;
lresult = MediaFoundationManager::getItem(
*aPtrPtrInputMediaType,
MF_MT_FRAME_RATE,
lVarItem);
if (lresult)
{
break;
}
lresult = MediaFoundationManager::setItem(
lOutputType,
MF_MT_FRAME_RATE,
lVarItem);
if (lresult)
{
break;
}
(*aPtrPtrInputMediaType)->Release();
*aPtrPtrInputMediaType = lOutputType.detach();
break;
}
}
}
}您可以设置ColorConvertDMO,以便将H264解码器的输出格式转换为所需的格式。
此外,您还可以通过链接查看代码:videoInput。此代码从网络摄像机中获取实时视频,并将其解码到RGB中。如果您在mp4视频文件源上替换网络凸轮源,您将得到接近您需要的解决方案。
问候
发布于 2016-05-27 16:08:07
这种转换是可能的吗?
是的是可能的。股票H.264视频解码器 MFT是"Direct3D感知“,这意味着它可以解码视频到Direct3D 9表面/Direct3D 11纹理利用DXVA。或者,如果硬件功能不足,也会出现软件回退模式。出于性能原因,您有兴趣将输出直接交付到纹理中(否则,您将不得不自己加载该数据,并为此花费CPU和视频资源)。
这可以通过IMFTransform/SourceReader类来完成吗?就像我已经厌倦了上面那样,我是否只需要调整代码,还是需要手动进行这种类型的转换?
IMFTransform是抽象的接口。它是由H.264解码器(以及其他MFT )实现的,您可以直接使用它,也可以使用更高级的源代码读取器API来管理它从文件中读取视频和使用该MFT进行解码。
也就是说,MFT和Source实际上不是排他性的替代选项,而是更高、更低级别的API。MFT接口由解码器提供,您负责在解码输出中输入H.264并排出解码输出。源阅读器管理相同的MFT并增加文件读取功能。
源阅读器本身在Windows7中是可用的,BTW (即使是在Vista上,与较新的OSes相比,在功能集上也可能受到限制)。
发布于 2016-05-31 23:41:28
下一段代码可以执行解码:
MFT_OUTPUT_DATA_BUFFER loutputDataBuffer;
initOutputDataBuffer(
lTransform,
loutputDataBuffer);
DWORD lprocessOutputStatus = 0;
lresult = lTransform->ProcessOutput(
0,
1,
&loutputDataBuffer,
&lprocessOutputStatus);
if ((HRESULT)lresult == E_FAIL)
{
break;
}函数initOutputDataBuffer分配所需的内存。在此介绍了该职能的实例:
Result initOutputDataBuffer(IMFTransform* aPtrTransform,
MFT_OUTPUT_DATA_BUFFER& aRefOutputBuffer)
{
Result lresult;
MFT_OUTPUT_STREAM_INFO loutputStreamInfo;
DWORD loutputStreamId = 0;
CComPtrCustom<IMFSample> lOutputSample;
CComPtrCustom<IMFMediaBuffer> lMediaBuffer;
do
{
if (aPtrTransform == nullptr)
{
lresult = E_POINTER;
break;
}
ZeroMemory(&loutputStreamInfo, sizeof(loutputStreamInfo));
ZeroMemory(&aRefOutputBuffer, sizeof(aRefOutputBuffer));
lresult = aPtrTransform->GetOutputStreamInfo(loutputStreamId, &loutputStreamInfo);
if (lresult)
{
break;
}
if ((loutputStreamInfo.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES) == 0 &&
(loutputStreamInfo.dwFlags & MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES) == 0)
{
lresult = MFCreateSample(&lOutputSample);
if (lresult)
{
break;
}
lresult = MFCreateMemoryBuffer(loutputStreamInfo.cbSize, &lMediaBuffer);
if (lresult)
{
break;
}
lresult = lOutputSample->AddBuffer(lMediaBuffer);
if (lresult)
{
break;
}
aRefOutputBuffer.pSample = lOutputSample.Detach();
}
else
{
lresult = S_OK;
}
aRefOutputBuffer.dwStreamID = loutputStreamId;
} while (false);
return lresult;
}它需要通过GetOutputStreamInfo的IMFTransform方法获取输出样本的信息。MFT_OUTPUT_STREAM_INFO包含关于输出媒体示例- cbSize所需内存大小的信息。它需要以这个大小分配内存,将其添加到MediaSample中,并将其附加到th MFT_OUTPUT_DATA_BUFFER。
因此,您可以看到,通过直接调用MediaFoundation函数来编写编码和解码视频的代码是很困难的,并且需要对它有重要的了解。从你的任务描述中,我发现你只需要解码视频并呈现出来。我可以建议您尝试使用Media Foundation会话功能。它是由微软的工程师开发的,已经包括了使用所需的编码器和优化算法。在项目中,使用videoInput媒体基金会会话来寻找适合于网络摄像机的媒体源解码器,并以非压缩格式捕获帧。它已经完成了所需的处理。您只需要替换来自网络摄像机的媒体源,就可以从视频文件中替换媒体源。它可以更容易地编写代码,直接调用IMFTransform进行解码,并允许简化许多问题(例如,稳定帧速率)。如果代码在解码后立即呈现图像,然后解码新帧,那么它可以在几秒钟内渲染1分钟视频剪辑,或者如果视频和其他内容的渲染可以占用多个帧持续时间,则可以以“慢动作”的方式呈现视频,而1分钟视频剪辑的渲染可能需要2、3或5分钟。我不知道您需要解码哪个项目的视频,但您应该有严肃的理由使用代码直接调用媒体基金会的功能和接口。
致以问候。
https://stackoverflow.com/questions/37461426
复制相似问题