【问题标题】:Windows media foundation decoding audio streamsWindows 媒体基础解码音频流
【发布时间】:2020-02-27 18:29:04
【问题描述】:

我是 Windows Media Foundation 的新手,我目前正在学习一些关于入门和解码音频的基础教程。但是,我遇到了一些问题。使用:Windows 10 64bit (1809),并且正在使用 Python(ctypes 和 COM 的接口)。

1) IMFSourceReader 不允许我选择或取消选择任何输出流。我尝试过 wav 和 mp3 格式(以及多个不同的文件),但它们都出错了。根据文档,为了提高性能,您需要取消选择其他流并选择所需的流,在本例中为音频。

但是: source_reader.SetStreamSelection(MF_SOURCE_READER_ANY_STREAM, False)

产生错误: OSError: [WinError -1072875853] The stream number provided was invalid.

哪个应该是正确的,因为MF_SOURCE_READER_ANY_STREAM 值(4294967294 的 DWORD)应该是通用的?还是我说的不对?

我试过看看是否可以只选择音频流: source_reader.SetStreamSelection(MF_SOURCE_READER_FIRST_AUDIO_STREAM, True)

这会产生不同的错误: OSError: exception: access violation reading 0x0000000000000001

到目前为止我的当前代码:

MFStartup(MF_VERSION)  # initialize

source_reader = IMFSourceReader() 

filename = "C:\\test.mp3"

MFCreateSourceReaderFromURL(filename, None, ctypes.byref(source_reader))  # out: source reader.

if source_reader:  # Not null
    source_reader.SetStreamSelection(MF_SOURCE_READER_ANY_STREAM, False)  # invalid stream #?

    source_reader.SetStreamSelection(MF_SOURCE_READER_FIRST_AUDIO_STREAM, True)  # access violation??

IMFSourceReader 似乎在其他功能上运行良好,例如GetCurrentMediaTypeSetCurrentMediaType 等。如果有任何问题,它还能返回IMFSourceReader吗?

2) 我不确定无法选择流是否会导致进一步的问题(我怀疑是这样)。如果我只是跳过选择或取消选择流,那么一切都会正常运行,直到尝试使用ConvertToContiguousBuffer 将样本转换为单个缓冲区,根据文档,该缓冲区输出到IMFMediaBuffer。问题是,在运行之后,它确实返回为S_OK,但缓冲区是null。我使用GetBufferCount 来确保样本中至少有一些缓冲区,并且根据使用的文件,它总是返回 1-3,所以它不应该为空。

以下是相关代码:

while True:
    flags = DWORD()
    sample = IMFSample()

    source_reader.ReadSample(streamIndex, 0, None, ctypes.byref(flags), None, ctypes.byref(sample))  # flags, sample [out]

    if flags.value & MF_SOURCE_READERF_ENDOFSTREAM:
        print("READ ALL OF STREAM")
        break

    if sample:
        buffer_count = DWORD()
        sample.GetBufferCount(ctypes.byref(buffer_count))
        print("BUFFER COUNT IN SAMPLE", buffer_count.value)
    else:
        print("NO SAMPLE")
        continue

    buffer = IMFMediaBuffer()
    hr = sample.ConvertToContiguousBuffer(ctypes.byref(buffer))

    print("Conversion succeeded", hr == 0)  # true

    if buffer:
        print("CREATED BUFFER")
    else:
        print("BUFFER IS NULL")
        break

我不确定从这里去哪里,我在互联网上找不到关于这些具体问题的太多解释。 WMF 仍然是 Windows 10 的首选吗?我应该使用别的东西吗?我真的很难过,非常感谢任何帮助。

【问题讨论】:

  • 我觉得SetStreamSelection 没问题,可能这个方法的 Python 绑定坏了。
  • 这是正确的,在 Python com 中,您必须具有头文件中列出的方法的确切顺序,否则它将不起作用。它们没有正确排列,并且根据版本删除/添加了一些方法。一旦我解决了这个问题,它就开始工作了。谢谢。

标签: python windows audio decode ms-media-foundation


【解决方案1】:

尝试使用MF_SOURCE_READER_ALL_STREAMS 而不是MF_SOURCE_READER_ANY_STREAM

source_reader.SetStreamSelection(MF_SOURCE_READER_ALL_STREAMS, False) 

在阅读示例时,您还需要指定一个有效的流索引,在您的情况下,我怀疑 0 不是。试试:

source_reader.ReadSample((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, None, ctypes.byref(flags), None, ctypes.byref(sample))

当您调用 Media Foundation 时,您的 Python 包装器是否也会返回结果?几乎所有 Media Foundation 方法都返回一个HRESULT,重要的是在继续之前检查它是否等于S_OK。如果不这样做,就很难找出错误呼叫发生的位置。

WMF 仍然是 Windows 10 的首选吗?

很多人问过that question。答案取决于您需要做什么(在您的情况下,音频编解码器支持非常有限,因此它可能不是最佳选择)。但是对于渲染音频/视频、读取/写入媒体文件、音频/视频设备捕获等,Media Foundation 仍然是 Microsoft 支持的最新选项。

【讨论】:

  • 感谢您的回复,MF_SOURCE_READER_ALL_STREAMS 都试过了,但没有任何变化。我正在查看头文件,它们似乎是相同的值,或者我拥有的头文件可能已过时? (0xfffffffe)。我忘了把streamIndexMF_SOURCE_READER_FIRST_AUDIO_STREAM,但是如果我直接输入它没有变化。包装器确实返回HRESULTReadSample 确实返回 S_OK。考虑到我只能加载的当前音频是 wav 文件,有限的支持对 WMF 来说不是太大的问题。不确定它是否被取代,但这有帮助。
  • 我不知道它是否会有所帮助,因为它没有使用您的 Python 包装器,但这是一个读取 mp4 文件的 C++ 示例github.com/sipsorcery/mediafoundationsamples/blob/master/…
【解决方案2】:

通常,使用 MediaFoundation,您需要在 MFStartup 之前调用 CoInitializeEx:

Media Foundation and COM

应用程序的最佳实践

在 Media Foundation 中,异步处理和回调由工作队列处理。工作队列始终具有多线程单元 (MTA) 线程,因此如果应用程序也运行在 MTA 线程上,它的实现将更简单。 因此,建议使用 COINIT_MULTITHREADED 标志调用 CoInitializeEx。

MFCreateSourceReaderFromURL function

备注

在调用此函数之前调用 CoInitialize(Ex) 和 MFStartup。

在您的代码中,我没有看到对 CoInitializeEx 的调用。

编辑

因为你使用的是音频文件,通常你应该只有一个音频流,索引应该是0。 试试看:

source_reader.SetStreamSelection(0, True)

并告诉我们结果。

【讨论】:

  • 我很抱歉,我也应该将它添加到我的源代码中。我曾经尝试过:CoInitializeEx(None, COINIT_MULTITHREADED),但没有任何区别。
猜你喜欢
  • 2015-05-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-16
  • 2012-11-09
  • 1970-01-01
  • 2012-08-11
  • 2010-10-01
相关资源
最近更新 更多