Windows Media Foundation解码音频流

问题描述 投票:1回答:2

我是Windows Media Foundation的新手,我目前正在关注一些基础知识的入门和解码音频的教程。但是,我正在处理一些问题。使用:Windows 10 64位(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值(DWORD为4294967294)应该是通用的?还是我不正确?

我尝试查看是否可以选择音频流: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的首选吗?我应该使用其他东西吗?我真的很沮丧,任何帮助都将不胜感激。

python windows audio decode ms-media-foundation
2个回答
0
投票

尝试使用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支持的最新选项。


0
投票

通常,使用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)

并告诉我们结果。

© www.soinside.com 2019 - 2024. All rights reserved.