我是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
似乎对其他功能,例如GetCurrentMediaType
,SetCurrentMediaType
等都很好用。如果有任何问题,它是否仍可以返回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的首选吗?我应该使用其他东西吗?我真的很沮丧,任何帮助都将不胜感激。
尝试使用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支持的最新选项。
通常,使用MediaFoundation,您需要在MFStartup之前调用CoInitializeEx:
最佳应用实践
在Media Foundation中,异步处理和回调由工作队列处理。工作队列始终具有多线程单元(MTA)线程,因此,如果应用程序也运行在MTA线程上,则其实现将更为简单。 因此,建议使用COINIT_MULTITHREADED标志调用CoInitializeEx。] >>
MFCreateSourceReaderFromURL function
备注
在调用此函数之前先调用CoInitialize(Ex)和MFStartup。
在您的代码中,我看不到对CoInitializeEx的调用。
编辑
因为您正在使用音频文件,所以通常只应有一个音频流,索引应为0。尝试:
source_reader.SetStreamSelection(0, True)
并告诉我们结果。