首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用IMFTransform将mp4电影帧解码为二维纹理的Windows基金会

使用IMFTransform将mp4电影帧解码为二维纹理的Windows基金会
EN

Stack Overflow用户
提问于 2016-05-26 12:51:41
回答 3查看 2.1K关注 0票数 4

我试图解码一个mp4视频使用类和转换帧到2D纹理,可以使用DirectX着色器进行渲染。我已经能够使用MFCreateSourceReaderfromURL读取源流,并能够读取流的媒体类型,该流的主要类型是MFMEdiaType_Video,次要类型与预期的MFVideoFormat_H264相同。

我现在需要将这种格式转换成RGB格式,该格式可以用于初始化D3D11_TEXTURE2D资源和资源视图,然后可以传递给HLSL像素着色器进行采样。我已经厌倦了使用IMFTransform类来为我进行转换,但是当我试图在转换中设置输出类型到任何MFVideoFormat_RGB变量时,我会得到一个错误。我还尝试在源读取器上设置一个新的输出类型,只对希望得到正确格式的示例进行采样,但我还是没有运气。

所以我的问题是:

  • 这种转换是可能的吗?
  • 这可以通过IMFTransform/SourceReader类来完成吗?就像我已经厌倦了上面那样,我是否只需要调整代码,还是需要手动进行这种类型的转换?
  • 这是将视频纹理数据输入着色器进行采样的最佳方法,还是有一种更简单的选择,我还没有想过。

所使用的操作系统是Windows 7,所以我不能使用SourceReaderEx或ID3D11VideoDevice接口,因为据我所知,这些解决方案似乎只能在Windows 8上使用。

任何正确方向的帮助/指针都将不胜感激,如果有必要,我也可以提供一些源代码。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 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中这样做:

代码语言:javascript
复制
                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视频文件源上替换网络凸轮源,您将得到接近您需要的解决方案。

问候

票数 2
EN

Stack Overflow用户

发布于 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相比,在功能集上也可能受到限制)。

票数 4
EN

Stack Overflow用户

发布于 2016-05-31 23:41:28

下一段代码可以执行解码:

代码语言:javascript
复制
                    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分配所需的内存。在此介绍了该职能的实例:

代码语言:javascript
复制
            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分钟。我不知道您需要解码哪个项目的视频,但您应该有严肃的理由使用代码直接调用媒体基金会的功能和接口。

致以问候。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37461426

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档