【问题标题】:How use hardware(nvenc) encoding in Media Foundation (Windows 10)如何在 Media Foundation (Windows 10) 中使用硬件 (nvenc) 编码
【发布时间】:2017-04-12 17:09:42
【问题描述】:

对不起我的英语。 我对在 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) 和 sample.AddBuffer(buffer) 3. 向IMFSinkWriter对象(sinkWriter)写入样本

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

【问题讨论】:

  • 你怎么知道除了 CPU 使用率之外没有使用硬件编码器(这可能是由你的代码的其他部分引起的)?你需要用 mftrace 运行你的程序,看看哪个编码器已经被初始化了。

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


【解决方案1】:

Sink Writer API 为您提供数据的自动转换(尤其是编码),其中包括在您请求时依次进行 H.264 编码。您可以通过 AddStreamMFMediaType.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 检查硬件编码器的可用性。

【讨论】:

  • 非常感谢您的回答!是的,我读到了 MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS。但我等MF会首先选择硬件编码。有没有关于使用 MFT 编码原始帧的好例子?
  • 我将一个关于将原始位图编码到 H.264 的问题链接,但它没有明确的答案或参考。我不知道有什么好的例子,尤其是在 C# 中(因为 API 是本机的,而在 C# 中,您必须使用包装器或其他中间接口层)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多