如何在Media Foundation(Windows 10)中使用硬件(nvenc)编码

时间:2016-11-28 21:04:14

标签: c# video h.264 ms-media-foundation nvenc

抱歉我的英文。 我对Windows 10中的MF硬件编码有疑问。我有Nvidia gtx 650(带nvenc)。 我开发了用于将实时帧流编码为c#。

中的h264文件的应用程序

我使用此代码(https://codereview.stackexchange.com/questions/136144/h-264-image-encoding-using-media-foundation-net)作为示例。 我创建了IMFSinkWriter对象(sinkWriter),例如,MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS = true

private int InitializeSinkWriter(String outputFile, int videoWidth, int videoHeight)
{            
    IMFMediaType mediaTypeIn = null;
    IMFMediaType mediaTypeOut = null;
    IMFAttributes attributes = null;

    int hr = 0;

    if (Succeeded(hr)) hr = MFExtern.MFCreateAttributes(out attributes, 1);
    if (Succeeded(hr)) hr = attributes.SetUINT32(MFAttributesClsid.MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, 1);
    if (Succeeded(hr)) hr = attributes.SetUINT32(MFAttributesClsid.MF_LOW_LATENCY, 1);

    // Create the sink writer 
    if (Succeeded(hr)) hr = MFExtern.MFCreateSinkWriterFromURL(outputFile, null, attributes, out sinkWriter);

    // Create the output type
    if (Succeeded(hr)) hr = MFExtern.MFCreateMediaType(out mediaTypeOut);
    if (Succeeded(hr)) hr = mediaTypeOut.SetGUID(MFAttributesClsid.MF_MT_MAJOR_TYPE, MFMediaType.Video);
    if (Succeeded(hr)) hr = mediaTypeOut.SetGUID(MFAttributesClsid.MF_MT_SUBTYPE, MFMediaType.H264);
    if (Succeeded(hr)) hr = mediaTypeOut.SetUINT32(MFAttributesClsid.MF_MT_AVG_BITRATE, videoBitRate);
    if (Succeeded(hr)) hr = mediaTypeOut.SetUINT32(MFAttributesClsid.MF_MT_INTERLACE_MODE, (int) MFVideoInterlaceMode.Progressive);
    if (Succeeded(hr)) hr = MFExtern.MFSetAttributeSize(mediaTypeOut, MFAttributesClsid.MF_MT_FRAME_SIZE, videoWidth, videoHeight);
    if (Succeeded(hr)) hr = MFExtern.MFSetAttributeRatio(mediaTypeOut, MFAttributesClsid.MF_MT_FRAME_RATE, VIDEO_FPS, 1);
    if (Succeeded(hr)) hr = MFExtern.MFSetAttributeRatio(mediaTypeOut, MFAttributesClsid.MF_MT_PIXEL_ASPECT_RATIO, 1, 1);
    if (Succeeded(hr)) hr = sinkWriter.AddStream(mediaTypeOut, out streamIndex);

    // Create the input type 
    if (Succeeded(hr))  hr = MFExtern.MFCreateMediaType(out mediaTypeIn);
    if (Succeeded(hr)) hr = mediaTypeIn.SetGUID(MFAttributesClsid.MF_MT_MAJOR_TYPE, MFMediaType.Video);
    if (Succeeded(hr)) hr = mediaTypeIn.SetGUID(MFAttributesClsid.MF_MT_SUBTYPE, MFMediaType.RGB24);
    if (Succeeded(hr)) hr = mediaTypeIn.SetUINT32(MFAttributesClsid.MF_MT_INTERLACE_MODE, (int)MFVideoInterlaceMode.Progressive);
    if (Succeeded(hr)) hr = MFExtern.MFSetAttributeSize(mediaTypeIn, MFAttributesClsid.MF_MT_FRAME_SIZE, videoWidth, videoHeight);
    if (Succeeded(hr)) hr = MFExtern.MFSetAttributeRatio(mediaTypeIn, MFAttributesClsid.MF_MT_FRAME_RATE, VIDEO_FPS, 1);
    if (Succeeded(hr)) hr = MFExtern.MFSetAttributeRatio(mediaTypeIn, MFAttributesClsid.MF_MT_PIXEL_ASPECT_RATIO, 1, 1);
    if (Succeeded(hr)) hr = sinkWriter.SetInputMediaType(streamIndex, mediaTypeIn, null);

    // Start accepting data
    if (Succeeded(hr))  hr = sinkWriter.BeginWriting();

    COMBase.SafeRelease(mediaTypeIn);
    COMBase.SafeRelease(mediaTypeOut);

    return hr;            
}

我做了,例如,每个帧编码的以下步骤: 1.创建IMFMediaBuffer对象(缓冲区)并在那里复制帧 2.创建IMFSample对象(示例)和sample.AddBuffer(缓冲区) 3.将样本写入IMFSinkWriter对象(sinkWriter)

结果我100%加载CPU(这不是硬件编码!!!)。我如何使用相同的代码进行硬件编码?

1 个答案:

答案 0 :(得分:2)

Sink Writer API为您提供数据的自动转换(尤其是编码),当您请求时,它会依次包含H.264编码。您确实通过AddStream MFMediaType.H264跟随SetInputMediaTypeMFMediaType.RGB24进行请求。

然而,您没有编码器选择的细粒度灵活性。 API为您选择“最佳”编码器是设计行为。您申请MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS意味着您可以使用硬件MFT,但这并不意味着您强制使用该选项。您甚至不知道硬件MFT是否可用于首选,是吗?同样,设计的行为是API通过保留选择最佳适用编码器本身的权利来避免被称为“编解码器地狱”的歧义。文档以这种方式解释:If a certified hardware encoder is present, it will generally be used instead of the inbox system encoder for Media Foundation related scenarios.

最大CPU负载是一种提示,压缩可能是软件,但它也可能是由其他原因引起的。在您的情况下,您需要查看可用的H​​.264编码器,调试和跟踪您的应用程序。当API没有自动选择编码器时强制使用Media Foundation进行硬件H.264编码,除了自己将视频压缩到H.264之外别无选择(使用MFT,这对应于编码器作为MFT而不是API存在的不太可能的情况)没有提取,或者使用特定于供应商的SDK进行编码,然后将压缩数据提供给Sink Writer API以生成格式良好的MP4文件,可能混合了音频。

另见:

  

您可以使用MediaFoundationVideoEncoderTransforms tool检查硬件编码器的可用性。