【问题标题】:Using Media Foundation to encode Direct X surfaces使用 Media Foundation 对 Direct X 表面进行编码
【发布时间】:2016-11-29 07:03:12
【问题描述】:

我正在尝试使用 MediaFoundation API 对视频进行编码,但在将样本推送到 SinkWriter 时遇到问题。

我正在通过桌面复制 API 获取要编码的帧。我最终得到的是一个 ID3D11Texture2D,其中包含桌面图像。

我正在尝试创建一个包含此表面的 IMFVideoSample,然后将该视频样本推送到 SinkWriter。

我尝试过以不同的方式解决这个问题:

  • 我调用了MFCreateVideoSampleFromSurface(texture, &pSample),其中纹理是 ID3D11Texture2D,填充了 SampleTime 和 SampleDuration,然后将创建的样本传递给 SinkWriter。
    SinkWriter 返回 E_INVALIDARG。

  • 我尝试通过将 nullptr 作为第一个参数传递并自己使用 MFCreateDXGISurfaceBuffer 创建缓冲区来创建示例,然后将生成的缓冲区传递给示例。
    那也没用。

  • 我通读了 MediaFoundation 文档,但找不到有关如何使用 DirectX 纹理创建示例的详细信息。

我没有东西可以尝试了。
有没有人以前使用过这个 API 并且可以想到我应该检查的东西,或者我可以如何去调试它?

【问题讨论】:

  • 我认为您在使用MFCreateVideoSampleFromSurfaceMFCreateDXGISurfaceBuffer 时犯了一个错误。这些函数创建用于写入 DirectX 表面和可视化的缓冲区,它们创建具有接口IMF2DBuffer 的对象,但编码器和编写器需要具有IMFMediaBuffer 的对象。他们无法理解IMF2DBuffer。尝试使用函数 'MFCreateSampleCopierMFT' - 它创建了 MFT 对象,用于在 MSDN 上从 IMFMediaBuffer 复制到 IMF2DBuffer。也许它可以做反向工作!?!
  • 你确定吗?查看MFCreateDXGISurfaceBuffer 的文档,它声明它返回一个指向 IMFMediaBuffer 的指针。
  • 从 DXGI 表面支持的样本/缓冲区中获取数据的最佳方法似乎是 MFGetService。另一个线程表明这两个 API 应该能够处理这个任务:stackoverflow.com/questions/14527718/…。我无法在任何地方找到任何体面的例子来充分利用这两种方法。我们将尝试朝着另一个方向前进,这是一种耻辱,因为 DesktopDuplication + MediaFoundation 似乎是解决我们问题的最佳解决方案。
  • 您使用 DesktopDuplication + MediaFoundation 的想法很有趣。在“CaptureProject”站点上的项目 CaptureManager SDK 中,我使用 DirectX9 + MediaFoundation 来捕获实时屏幕视频,但它从桌面管理器复制图像(在任务管理器程序和桌面管理器中,彼此占 15%)。我认为使用 DesktopDuplication 会更有效率。
  • @Tiago Magalhães 你找到解决问题的方法了吗?我也被它困住了,因为我找不到相关的资源。

标签: c++ directx-11 ms-media-foundation dxgi


【解决方案1】:

首先你应该学会使用mftrace tool。 很可能,它会立即告诉您问题所在。

但我的猜测是,可能会出现以下问题。

  1. 可能除了 SampleTime / SampleDuration 之外,还需要一些其他属性。

  2. 可能 SinkWriter 需要它可以在 CPU 上读取的纹理。为了解决这个问题,当一个框架可用时,创建一个相同格式 + 大小的暂存纹理,调用 CopyResource 将桌面复制到暂存纹理,然后将该暂存纹理传递给 MF。

  3. 即使您使用硬件编码器使 CPU 从不尝试读取纹理数据,我认为直接将桌面纹理传递给 MF 也不是一个好主意。

当您为样本设置 D3D 纹理时,不会在任何地方复制任何数据,样本仅保留纹理。

MF 异步工作,如果需要,它可以在其拓扑节点中缓冲多个样本。

DD 同步为您提供数据,您只能在 AcquireNextFrame 和 ReleaseFrame 调用之间访问纹理。

【讨论】:

  • 我尽量不要因为太多细节而陷入困境,但我在将桌面纹理传递给 MF 之前复制了桌面纹理,方法是获取桌面纹理描述符并在使用 CopyResource 之前使用该描述符创建一个新纹理。但是感谢 lor 提供的 mftrace 指针,我会看看。
  • 我使用 mfctrace 并发现发送到接收器的样本被报告为 0B 大小,因此它们的创建出现问题。
  • @Soonts,我什至尝试过创建暂存纹理并确实调用了 CopyResource,但对输出没有影响。获得简单的绿屏。 stackoverflow.com/questions/58503662/…
猜你喜欢
  • 1970-01-01
  • 2019-10-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-30
相关资源
最近更新 更多