在 Windows 8 (VB) 中将 MP3/WMA 流式传输或转换为 PCM/WAV 的代码
使用 MediaFoundation 在 Windows 8 中将 MP3 转换为 WAV 的 VB 代码。
介绍
此代码在 Windows 8 上将音频从 MP3 或 WMA 转换为 PCM 或 WAV 格式。它用 VB 编写,但相同的技术适用于 C#。它可以转换存储在硬盘上的 file:///
文件,也适用于来自互联网的 http://
文件,以及 mms://
流。
它使用 Media Foundation Source Reader API。
Windows 带有 MP3 和 WMA 格式的内置解码器。它通过几个 API 公开这些解码器:
- MediaElement - 所有 UI 框架都有一个
MediaElement
控件 - 适用于 Windows 8 的 XAML、WPF、Silverlight、WinForms。它们让您可以播放音频和视频。但它们不提供获取原始音频数据的方法。
- MediaTranscoder - 此 API 在 Windows 8 中引入。它允许您转码音频和视频,例如更改视频分辨率,但其唯一的音频目标格式是 MP3 和 WMA:没有 WAV。有一个 SDK 示例 展示了如何使用它。
- 音频压缩管理器 - 此旧版 C++ API 公开 MP3 文件的解码,但它不允许在 Windows 应用商店应用中使用。
- Windows Media Format SDK - 此 C++/COM API 用于所有与 WMA 相关的事情,但它不允许在 Windows 应用商店应用中使用。
- Media Foundation Source Reader - Media Foundation C++/COM API 于 Vista 中引入,是旧版 DirectShow 的继任者。“Source Reader”是其独立的解码部分。Microsoft 有一个 C++ 示例 展示了如何使用它转换为 WAV;当前这篇文章主要基于该示例。Tamir Khason 写了一篇关于如何从 C# 使用 Media Foundation 部分功能的精彩文章:https://codeproject.org.cn/Articles/239378/Video-encoder-and-metadata-reading-by-using-Window
- XAudio2 - 此 C++/COM API 是旧版 DirectSound 的继任者。它面向游戏开发者。
NAudio。作为 .NET 开发人员,如果您想要音频,您的首选通常应该是 http://naudio.codeplex.com/。NAudio 是一个高质量的库,通过 NuGet 提供,采用 MS-Pl 许可,用于向 VB 和 C# 应用添加音频。
我写这篇文章是因为(截至 2012 年 9 月)NAudio 是基于音频压缩管理器和 Windows Media Format API 构建的,这两个 API 都不允许在 Windows 应用商店应用中使用。我需要找到一个不同的解决方案。
使用代码
COM 互操作和入门
IMFSourceReader
COM 对象是 Media Foundation Source Reader API 的入口点。这些 API 仅由 Microsoft 向 C++/COM 公开。如果您想从 VB 或 C# 使用它们,您需要大量的 COM PInvoke 互操作。
<MTAThread>
Sub Main()
MFStartup(MF_VERSION)
Dim pReader As IMFSourceReader = Nothing
MFCreateSourceReaderFromURL(source, Nothing, pReader)
...
Runtime.InteropServices.Marshal.ReleaseComObject(pReader) : pReader = Nothing
MFShutdown()
End Sub
在音频应用程序中,您处理大量数据,及时释放资源很重要。VB 和 C# 使用 IDispose
机制来处理此问题,并依靠 .NET 垃圾回收来处理所有其他问题。C++/COM 使用 IUnknown.Release
和引用计数。弥合两者之间的差距很困难。有关背景信息,我建议阅读这篇 MSDN 文章“提高互操作性能”以及这篇 C++ 团队博客文章“混合确定性和非确定性清理”以及 Lim Bio Liong 的这篇博客“RCW 内部引用计数”。
我们将关注上述代码中创建的 COM 对象,它维护一个引用计数,以及它的 .NET 运行时可调用包装器 (RCW),它有自己的内部引用计数。RCW 与 COM 对象的 IUnknown
IntPtr
之间存在一对一关系。当 IUnknown IntPtr
第一次进入托管代码(例如通过分配新的 COM 对象或 Marshal.ObjectFromIUnknown
)时,RCW 被创建,其内部引用计数设置为 1,并且它只调用 IUnknown.AddRef
一次。随后,当相同的 IUnknown
IntPtr
进入托管代码时,RCW 的内部引用计数会递增,但它不会调用 IUnknown.AddRef
。RCW 的内部引用计数通过自然垃圾回收递减;您也可以使用 Marshal.ReleaseComObject
手动递减它,或者使用 Marshal.FinalReleaseComObject
强制将其直接设置为 0。当 RCW 的内部引用计数降至 0 时,它只调用 IUnknown.Release 一次。任何对其的后续方法都将失败,并显示消息“COM 对象已与其底层 RCW 分离,无法使用”。
建议实践:创建一个实现 IDisposable
的包装类,该类具有用于 COM 对象(或更准确地说,用于其 RCW)的私有字段。绝不允许您的客户端直接访问 COM 对象。如果需要,包装类中的局部变量引用相同的 RCW 也没有问题。在 IDisposable.Dispose
中,调用 Marshal.ReleaseComObject
,将字段设置为 Nothing,并确保您的包装器不再访问该字段的方法或字段。我没有在当前这篇文章中这样做:我想展示如何使用 Media Foundation API 本身,并将其留给 COM 专家编写一个好的包装器。
Windows 8 上读取本地文件的权限
在桌面应用程序中,上述对 MFCreateSourceReaderFromURL
的调用对于 file:/// URL、http:// 和 mms:// URL 都将正常工作,您也可以传递相对或绝对文件名。
在 Windows 8 应用商店应用程序中,MFCreateSourceReaderFromURL
将适用于互联网 http:// 和 mms:// URL(如果您拥有互联网客户端权限)以及 ms-appx:/// URL。但是,如果您尝试在文件名或 file:/// URL 上使用它,您将收到访问被拒绝错误,即使您拥有访问权限的文件也会如此。对于本地文件,您必须使用 MFCreateMFByteStreamOnStreamEx
:
Dim pReader As IMFSourceReader = Nothing
Dim src_file = Await Windows.Storage.StorageFile.GetFileFromPathAsync(src_uri.LocalPath)
Using src_stream = Await src_file.OpenAsync(Windows.Storage.FileAccessMode.Read)
Dim src_bytestream As IMFByteStream = Nothing
MFCreateMFByteStreamOnStreamEx(src_stream, src_bytestream)
MFCreateSourceReaderFromByteStream(src_bytestream, Nothing, pReader)
Runtime.InteropServices.Marshal.ReleaseComObject(src_bytestream)
End Using
...
Runtime.InteropServices.Marshal.ReleaseComObject(pReader) : pReader = Nothing
选择正确的音频格式
我们向 IMFSourceReader
请求它是否能够以我们想要的格式(PCM 数据,44100Hz,2 通道,每样本 16 位)提供解码音频。然后它会告诉我们它最终为我们选择了哪种媒体格式。
pReader.SetStreamSelection(MF_SOURCE_READER_ALL_STREAMS, False)
pReader.SetStreamSelection(MF_SOURCE_READER_FIRST_AUDIO_STREAM, True)
Dim pRequestedType As IMFMediaType = Nothing : MFCreateMediaType(pRequestedType)
pRequestedType.SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio)
pRequestedType.SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM)
pRequestedType.SetUINT32(MF_MT_AUDIO_NUM_CHANNELS, 2)
pRequestedType.SetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 16)
pRequestedType.SetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100)
pReader.SetCurrentMediaType(MF_SOURCE_READER_FIRST_AUDIO_STREAM, Nothing, pRequestedType)
Runtime.InteropServices.Marshal.ReleaseComObject(pRequestedType) : pRequestedType = Nothing
Dim pAudioType As IMFMediaType = Nothing : pReader.GetCurrentMediaType(MF_SOURCE_READER_FIRST_AUDIO_STREAM, pAudioType)
Dim cbBlockSize = 0 : pAudioType.GetUINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, cbBlockSize)
Dim cbBytesPerSecond = 0 : pAudioType.GetUINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, cbBytesPerSecond)
Dim pWav As IntPtr, cbFormat As Integer : MFCreateWaveFormatExFromMFMediaType(pAudioType, pWav, cbFormat)
Dim wfx = New Byte(cbFormat - 1) {} : Runtime.InteropServices.Marshal.Copy(pWav, wfx, 0, cbFormat)
pReader.SetStreamSelection(MF_SOURCE_READER_FIRST_AUDIO_STREAM, True)
Runtime.InteropServices.Marshal.ReleaseComObject(pAudioType) : pAudioType = Nothing
写入 WAV 文件。WAV 文件格式简单明了:一个简单的文件头,后面跟着原始 PCM 数据。
Dim header As Byte() =
{CByte(AscW("R"c)), CByte(AscW("I"c)), CByte(AscW("F"c)), CByte(AscW("F"c)), 0, 0, 0, 0,
CByte(AscW("W"c)), CByte(AscW("A"c)), CByte(AscW("V"c)), CByte(AscW("E"c)),
CByte(AscW("f"c)), CByte(AscW("m"c)), CByte(AscW("t"c)), CByte(AscW(" "c)),
CByte(cbFormat And 255), CByte((cbFormat >> 8) And 255),
CByte((cbFormat >> 16) And 255), CByte((cbFormat >> 24) And 255)}
Dim dataHeader As Byte() =
{CByte(AscW("d"c)), CByte(AscW("a"c)), _
CByte(AscW("t"c)), CByte(AscW("a"c)), 0, 0, 0, 0}
Await dest.WriteAsync(header, 0, header.Length)
Await dest.WriteAsync(wfx, 0, wfx.Length)
Await dest.WriteAsync(dataHeader, 0, dataHeader.Length)
Runtime.InteropServices.Marshal.FreeCoTaskMem(pWav)
Dim cbHeader = header.Length + cbFormat + dataHeader.Length
Dim cbAudioData = 0
' Now a loop to get buffer after buffer from the MFSourceReader, and write it to disk:
' ...
' Some fields in the WAV file header need to be patched up, now that we know the correct sizes
Dim cbRiffFileSize = cbHeader + cbAudioData - 8
dest.Seek(4, IO.SeekOrigin.Begin) : Await dest.WriteAsync(BitConverter.GetBytes(cbRiffFileSize), 0, 4)
dest.Seek(cbHeader - 4, IO.SeekOrigin.Begin) : Await dest.WriteAsync(BitConverter.GetBytes(cbAudioData), 0, 4)
从 IMFSourceReader 获取 PCM 数据
剩下的就是循环从 IMFSourceReader
获取音频数据:
Do
Dim pSample As IMFSample = Nothing, dwFlags As Integer : _
pReader.ReadSample(MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, 0, dwFlags, 0, pSample)
If dwFlags <> 0 Then pSample = Nothing : Exit Do
Dim pBuffer As IMFMediaBuffer = Nothing : pSample.ConvertToContiguousBuffer(pBuffer)
Dim pAudioData As IntPtr, cbBuffer As Integer : pBuffer.Lock(pAudioData, Nothing, cbBuffer)
Dim buf = New Byte(cbBuffer - 1) {} : Runtime.InteropServices.Marshal.Copy(pAudioData, buf, 0, cbBuffer)
Await dest.WriteAsync(buf, 0, cbBuffer) : cbAudioData += cbBuffer
pBuffer.Unlock()
Runtime.InteropServices.Marshal.ReleaseComObject(pBuffer) : pBuffer = Nothing
Runtime.InteropServices.Marshal.ReleaseComObject(pSample) : pSample = Nothing
Loop
调用 Media Foundation 的互操作库
剩下的是一个巨大的 pinvoke 互操作库。我花了几天时间才把这些整理出来。
我绝不是 pinvoke 专家。我敢打赌这些定义中存在错误,而且我确信它们没有体现最佳实践。
Module Interop
<Runtime.InteropServices.DllImport("mfplat.dll", ExactSpelling:=True, PreserveSig:=False)>
Sub MFStartup(Version As Integer, Optional dwFlags As Integer = 0)
End Sub
<Runtime.InteropServices.DllImport("mfplat.dll", ExactSpelling:=True, PreserveSig:=False)>
Public Sub MFShutdown()
End Sub
<Runtime.InteropServices.DllImport("mfplat.dll", ExactSpelling:=True, PreserveSig:=False)>
Public Sub MFCreateMediaType(ByRef ppMFType As IMFMediaType)
End Sub
<Runtime.InteropServices.DllImport("mfplat.dll", ExactSpelling:=True, PreserveSig:=False)>
Public Sub MFCreateWaveFormatExFromMFMediaType(pMFType As IMFMediaType, _
ByRef ppWF As IntPtr, ByRef pcbSize As Integer, Optional Flags As Integer = 0)
End Sub
<Runtime.InteropServices.DllImport("mfreadwrite.dll", ExactSpelling:=True, PreserveSig:=False)>
Public Sub MFCreateSourceReaderFromURL(<Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPWStr)> pwszURL As String, _
pAttributes As IntPtr, ByRef ppSourceReader As IMFSourceReader)
End Sub
<Runtime.InteropServices.DllImport("mfreadwrite.dll", ExactSpelling:=True, PreserveSig:=False)>
Public Sub MFCreateSourceReaderFromByteStream(pByteStream As IMFByteStream, _
pAttributes As IntPtr, ByRef ppSourceReader As IMFSourceReader)
End Sub
<Runtime.InteropServices.DllImport("mfplat.dll", ExactSpelling:=True, PreserveSig:=False)>
Public Sub MFCreateMFByteStreamOnStreamEx(<Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.IUnknown)> punkStream As Object, _
ByRef ppByteStream As IMFByteStream)
End Sub
Public Const MF_SOURCE_READER_ALL_STREAMS As Integer = &HFFFFFFFE
Public Const MF_SOURCE_READER_FIRST_AUDIO_STREAM As Integer = &HFFFFFFFD
Public Const MF_SDK_VERSION As Integer = &H2
Public Const MF_API_VERSION As Integer = &H70
Public Const MF_VERSION As Integer = (MF_SDK_VERSION << 16) Or MF_API_VERSION
Public ReadOnly MF_MT_MAJOR_TYPE As New Guid("48eba18e-f8c9-4687-bf11-0a74c9f96a8f")
Public ReadOnly MF_MT_SUBTYPE As New Guid("f7e34c9a-42e8-4714-b74b-cb29d72c35e5")
Public ReadOnly MF_MT_AUDIO_BLOCK_ALIGNMENT As New Guid("322de230-9eeb-43bd-ab7a-ff412251541d")
Public ReadOnly MF_MT_AUDIO_AVG_BYTES_PER_SECOND As New Guid("1aab75c8-cfef-451c-ab95-ac034b8e1731")
Public ReadOnly MF_MT_AUDIO_NUM_CHANNELS As New Guid("37e48bf5-645e-4c5b-89de-ada9e29b696a")
Public ReadOnly MF_MT_AUDIO_SAMPLES_PER_SECOND As New Guid("5faeeae7-0290-4c31-9e8a-c534f68d9dba")
Public ReadOnly MF_MT_AUDIO_BITS_PER_SAMPLE As New Guid("f2deb57f-40fa-4764-aa33-ed4f2d1ff669")
Public ReadOnly MFMediaType_Audio As New Guid("73647561-0000-0010-8000-00AA00389B71")
Public ReadOnly MFAudioFormat_PCM As New Guid("00000001-0000-0010-8000-00AA00389B71")
<Runtime.InteropServices.ComImport, Runtime.InteropServices.InterfaceType( _
Runtime.InteropServices.ComInterfaceType.InterfaceIsIUnknown), _
Runtime.InteropServices.Guid("70ae66f2-c809-4e4f-8915-bdcb406b7993")>
Public Interface IMFSourceReader
Sub GetStreamSelection(<Runtime.InteropServices.In> _
dwStreamIndex As Integer, <Runtime.InteropServices.Out> ByRef pSelected As Boolean)
Sub SetStreamSelection(<Runtime.InteropServices.In> _
dwStreamIndex As Integer, <Runtime.InteropServices.In> pSelected As Boolean)
Sub GetNativeMediaType(<Runtime.InteropServices.In> dwStreamIndex As Integer, _
<Runtime.InteropServices.In> dwMediaTypeIndex As Integer, _
<Runtime.InteropServices.Out> ByRef ppMediaType As IntPtr)
Sub GetCurrentMediaType(<Runtime.InteropServices.In> dwStreamIndex As Integer, _
<Runtime.InteropServices.Out> ByRef ppMediaType As IMFMediaType)
Sub SetCurrentMediaType(<Runtime.InteropServices.In> dwStreamIndex _
As Integer, pdwReserved As IntPtr, <Runtime.InteropServices.In> pMediaType As IMFMediaType)
Sub SetCurrentPosition(<Runtime.InteropServices.In, _
Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPStruct)> _
guidTimeFormat As Guid, <Runtime.InteropServices.In> varPosition As Object)
Sub ReadSample(<Runtime.InteropServices.In> dwStreamIndex As Integer, _
<Runtime.InteropServices.In> dwControlFlags As Integer, _
<Runtime.InteropServices.Out> ByRef pdwActualStreamIndex As Integer, _
<Runtime.InteropServices.Out> ByRef pdwStreamFlags As Integer, _
<Runtime.InteropServices.Out> ByRef pllTimestamp As UInt64, _
<Runtime.InteropServices.Out> ByRef ppSample As IMFSample)
Sub Flush(<Runtime.InteropServices.In> dwStreamIndex As Integer)
Sub GetServiceForStream(<Runtime.InteropServices.In> dwStreamIndex As Integer, _
<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> guidService As Guid, _
<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> riid As Guid, _
<Runtime.InteropServices.Out> ByRef ppvObject As IntPtr)
Sub GetPresentationAttribute(<Runtime.InteropServices.In> _
dwStreamIndex As Integer, <Runtime.InteropServices.In, _
Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPStruct)> _
guidAttribute As Guid, <Runtime.InteropServices.Out> pvarAttribute As IntPtr)
End Interface
<Runtime.InteropServices.ComImport, Runtime.InteropServices.InterfaceType( _
Runtime.InteropServices.ComInterfaceType.InterfaceIsIUnknown), _
Runtime.InteropServices.Guid("2CD2D921-C447-44A7-A13C-4ADABFC247E3")>
Public Interface IMFAttributes
Sub GetItem(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, pValue As IntPtr)
Sub GetItemType(<Runtime.InteropServices.In, _
Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPStruct)> _
guidKey As Guid, ByRef pType As Integer)
Sub CompareItem(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, _
Value As IntPtr, <Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.Bool)> ByRef pbResult As Boolean)
Sub Compare(<Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.Interface)> _
pTheirs As IMFAttributes, MatchType As Integer, _
<Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.Bool)> ByRef pbResult As Boolean)
Sub GetUINT32(<Runtime.InteropServices.In, _
Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPStruct)> _
guidKey As Guid, ByRef punValue As Integer)
Sub GetUINT64(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, ByRef punValue As Long)
Sub GetDouble(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, ByRef pfValue As Double)
Sub GetGUID(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, ByRef pguidValue As Guid)
Sub GetStringLength(<Runtime.InteropServices.In, _
Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPStruct)> _
guidKey As Guid, ByRef pcchLength As Integer)
Sub GetString(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, _
<Runtime.InteropServices.Out, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPWStr)> pwszValue As Text.StringBuilder, _
cchBufSize As Integer, ByRef pcchLength As Integer)
Sub GetAllocatedString(<Runtime.InteropServices.In, _
Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPStruct)> _
guidKey As Guid, <Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPWStr)> ByRef ppwszValue As String, ByRef pcchLength As Integer)
Sub GetBlobSize(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, ByRef pcbBlobSize As Integer)
Sub GetBlob(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, _
<Runtime.InteropServices.Out, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPArray)> pBuf As Byte(), _
cbBufSize As Integer, ByRef pcbBlobSize As Integer)
Sub GetAllocatedBlob(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, ByRef ip As IntPtr, ByRef pcbSize As Integer)
Sub GetUnknown(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, _
<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> riid As Guid, _
<Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.IUnknown)> ByRef ppv As Object)
Sub SetItem(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, Value As IntPtr)
Sub DeleteItem(<Runtime.InteropServices.In, _
Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid)
Sub DeleteAllItems()
Sub SetUINT32(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, unValue As Integer)
Sub SetUINT64(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, unValue As Long)
Sub SetDouble(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, fValue As Double)
Sub SetGUID(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, _
<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> guidValue As Guid)
Sub SetString(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, _
<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPWStr)> wszValue As String)
Sub SetBlob(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, _
<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPArray, SizeParamIndex:=2)> pBuf As Byte(), cbBufSize As Integer)
Sub SetUnknown(<Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPStruct)> _
guidKey As Guid, <Runtime.InteropServices.In, _
Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.IUnknown)> pUnknown As Object)
Sub LockStore()
Sub UnlockStore()
Sub GetCount(ByRef pcItems As Integer)
Sub GetItemByIndex(unIndex As Integer, ByRef pguidKey As Guid, pValue As IntPtr)
Sub CopyAllItems(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.Interface)> pDest As IMFAttributes)
End Interface
<Runtime.InteropServices.ComImport, Runtime.InteropServices.InterfaceType( _
Runtime.InteropServices.ComInterfaceType.InterfaceIsIUnknown), _
Runtime.InteropServices.Guid("44AE0FA8-EA31-4109-8D2E-4CAE4997C555")>
Public Interface IMFMediaType
Inherits IMFAttributes
Overloads Sub GetItem(<Runtime.InteropServices.In, _
Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> _
guidKey As Guid, pValue As IntPtr)
Overloads Sub GetItemType(<Runtime.InteropServices.In, _
Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPStruct)> _
guidKey As Guid, ByRef pType As Integer)
Overloads Sub CompareItem(<Runtime.InteropServices.In, _
Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPStruct)> _
guidKey As Guid, Value As IntPtr, <Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.Bool)> ByRef pbResult As Boolean)
Overloads Sub Compare(<Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.Interface)> _
pTheirs As IMFAttributes, MatchType As Integer, _
<Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.Bool)> ByRef pbResult As Boolean)
Overloads Sub GetUINT32(<Runtime.InteropServices.In, _
Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPStruct)> _
guidKey As Guid, ByRef punValue As Integer)
Overloads Sub GetUINT64(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, ByRef punValue As Long)
Overloads Sub GetDouble(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, ByRef pfValue As Double)
Overloads Sub GetGUID(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, ByRef pguidValue As Guid)
Overloads Sub GetStringLength(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, ByRef pcchLength As Integer)
Overloads Sub GetString(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, _
<Runtime.InteropServices.Out, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPWStr)> pwszValue _
As Text.StringBuilder, cchBufSize As Integer, ByRef pcchLength As Integer)
Overloads Sub GetAllocatedString(<Runtime.InteropServices.In, _
Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPStruct)> _
guidKey As Guid, <Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPWStr)> _
ByRef ppwszValue As String, ByRef pcchLength As Integer)
Overloads Sub GetBlobSize(<Runtime.InteropServices.In, _
Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, ByRef pcbBlobSize As Integer)
Overloads Sub GetBlob(<Runtime.InteropServices.In, _
Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPStruct)> _
guidKey As Guid, <Runtime.InteropServices.Out, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPArray)> pBuf As Byte(), _
cbBufSize As Integer, ByRef pcbBlobSize As Integer)
Overloads Sub GetAllocatedBlob(<Runtime.InteropServices.In, _
Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> _
guidKey As Guid, ByRef ip As IntPtr, ByRef pcbSize As Integer)
Overloads Sub GetUnknown(<Runtime.InteropServices.In, _
Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPStruct)> _
guidKey As Guid, <Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> riid As Guid, _
<Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.IUnknown)> ByRef ppv As Object)
Overloads Sub SetItem(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, Value As IntPtr)
Overloads Sub DeleteItem(<Runtime.InteropServices.In, _
Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid)
Overloads Sub DeleteAllItems()
Overloads Sub SetUINT32(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, unValue As Integer)
Overloads Sub SetUINT64(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, unValue As Long)
Overloads Sub SetDouble(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, fValue As Double)
Overloads Sub SetGUID(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, _
<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> guidValue As Guid)
Overloads Sub SetString(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, _
<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPWStr)> wszValue As String)
Overloads Sub SetBlob(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, _
<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPArray, SizeParamIndex:=2)> pBuf As Byte(), cbBufSize As Integer)
Overloads Sub SetUnknown(<Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, _
<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.IUnknown)> pUnknown As Object)
Overloads Sub LockStore()
Overloads Sub UnlockStore()
Overloads Sub GetCount(ByRef pcItems As Integer)
Overloads Sub GetItemByIndex(unIndex As Integer, ByRef pguidKey As Guid, pValue As IntPtr)
Overloads Sub CopyAllItems(<Runtime.InteropServices.In, _
Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.Interface)> pDest As IMFAttributes)
'
Sub GetMajorType(ByRef pguidMajorType As Guid)
Sub IsCompressedFormat(<Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.Bool)> ByRef pfCompressed As Boolean)
<Runtime.InteropServices.PreserveSig> Function IsEqual(<Runtime.InteropServices.In, _
Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.Interface)> _
pIMediaType As IMFMediaType, ByRef pdwFlags As Integer) As Integer
Sub GetRepresentation(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.Struct)> guidRepresentation As Guid, _
ByRef ppvRepresentation As IntPtr)
Sub FreeRepresentation(<Runtime.InteropServices.In, _
Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.Struct)> _
guidRepresentation As Guid, <Runtime.InteropServices.In> pvRepresentation As IntPtr)
End Interface
<Runtime.InteropServices.ComImport, Runtime.InteropServices.InterfaceType( _
Runtime.InteropServices.ComInterfaceType.InterfaceIsIUnknown), _
Runtime.InteropServices.Guid("c40a00f2-b93a-4d80-ae8c-5a1c634f58e4")>
Public Interface IMFSample
Inherits IMFAttributes
Overloads Sub GetItem(<Runtime.InteropServices.In, _
Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, pValue As IntPtr)
Overloads Sub GetItemType(<Runtime.InteropServices.In, _
Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, ByRef pType As Integer)
Overloads Sub CompareItem(<Runtime.InteropServices.In, _
Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, _
Value As IntPtr, <Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.Bool)> ByRef pbResult As Boolean)
Overloads Sub Compare(<Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.Interface)> _
pTheirs As IMFAttributes, MatchType As Integer, _
<Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.Bool)> ByRef pbResult As Boolean)
Overloads Sub GetUINT32(<Runtime.InteropServices.In, _
Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPStruct)> _
guidKey As Guid, ByRef punValue As Integer)
Overloads Sub GetUINT64(<Runtime.InteropServices.In, _
Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPStruct)> _
guidKey As Guid, ByRef punValue As Long)
Overloads Sub GetDouble(<Runtime.InteropServices.In, _
Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPStruct)> _
guidKey As Guid, ByRef pfValue As Double)
Overloads Sub GetGUID(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, ByRef pguidValue As Guid)
Overloads Sub GetStringLength(<Runtime.InteropServices.In, _
Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, ByRef pcchLength As Integer)
Overloads Sub GetString(<Runtime.InteropServices.In, _
Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, _
<Runtime.InteropServices.Out, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPWStr)> _
pwszValue As Text.StringBuilder, cchBufSize As Integer, ByRef pcchLength As Integer)
Overloads Sub GetAllocatedString(<Runtime.InteropServices.In, _
Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPStruct)> _
guidKey As Guid, <Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPWStr)> _
ByRef ppwszValue As String, ByRef pcchLength As Integer)
Overloads Sub GetBlobSize(<Runtime.InteropServices.In, _
Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPStruct)> _
guidKey As Guid, ByRef pcbBlobSize As Integer)
Overloads Sub GetBlob(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, _
<Runtime.InteropServices.Out, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPArray)> pBuf As Byte(), _
cbBufSize As Integer, ByRef pcbBlobSize As Integer)
Overloads Sub GetAllocatedBlob(<Runtime.InteropServices.In, _
Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPStruct)> _
guidKey As Guid, ByRef ip As IntPtr, ByRef pcbSize As Integer)
Overloads Sub GetUnknown(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, _
<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> riid As Guid, _
<Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.IUnknown)> ByRef ppv As Object)
Overloads Sub SetItem(<Runtime.InteropServices.In, _
Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPStruct)> _
guidKey As Guid, Value As IntPtr)
Overloads Sub DeleteItem(<Runtime.InteropServices.In, _
Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid)
Overloads Sub DeleteAllItems()
Overloads Sub SetUINT32(<Runtime.InteropServices.In, _
Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, unValue As Integer)
Overloads Sub SetUINT64(<Runtime.InteropServices.In, _
Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> _
guidKey As Guid, unValue As Long)
Overloads Sub SetDouble(<Runtime.InteropServices.In, _
Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, fValue As Double)
Overloads Sub SetGUID(<Runtime.InteropServices.In, _
Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, _
<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> guidValue As Guid)
Overloads Sub SetString(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> _
guidKey As Guid, <Runtime.InteropServices.In, _
Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPWStr)> _
wszValue As String)
Overloads Sub SetBlob(<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, _
<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPArray, SizeParamIndex:=2)> pBuf As Byte(), cbBufSize As Integer)
Overloads Sub SetUnknown(<Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.LPStruct)> guidKey As Guid, _
<Runtime.InteropServices.In, Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.IUnknown)> pUnknown As Object)
Overloads Sub LockStore()
Overloads Sub UnlockStore()
Overloads Sub GetCount(ByRef pcItems As Integer)
Overloads Sub GetItemByIndex(unIndex As Integer, ByRef pguidKey As Guid, pValue As IntPtr)
Overloads Sub CopyAllItems(<Runtime.InteropServices.In, _
Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.Interface)> pDest As IMFAttributes)
'
Sub GetSampleFlags(ByRef pdwSampleFlags As Integer)
Sub SetSampleFlags(dwSampleFlags As Integer)
Sub GetSampleTime(ByRef phnsSampletime As Long)
Sub SetSampleTime(hnsSampleTime As Long)
Sub GetSampleDuration(ByRef phnsSampleDuration As Long)
Sub SetSampleDuration(hnsSampleDuration As Long)
Sub GetBufferCount(ByRef pdwBufferCount As Integer)
Sub GetBufferByIndex(dwIndex As Integer, ByRef ppBuffer As IMFMediaBuffer)
Sub ConvertToContiguousBuffer(ByRef ppBuffer As IMFMediaBuffer)
Sub AddBuffer(pBuffer As IMFMediaBuffer)
Sub RemoveBuferByindex(dwIndex As Integer)
Sub RemoveAllBuffers()
Sub GetTotalLength(ByRef pcbTotalLength As Integer)
Sub CopyToByffer(pBuffer As IMFMediaBuffer)
End Interface
<Runtime.InteropServices.ComImport, Runtime.InteropServices.InterfaceType( _
Runtime.InteropServices.ComInterfaceType.InterfaceIsIUnknown), _
Runtime.InteropServices.Guid("045FA593-8799-42b8-BC8D-8968C6453507")>
Public Interface IMFMediaBuffer
Sub Lock(ByRef ppbBuffer As IntPtr, ByRef pcbMaxLength As Integer, ByRef pcbCurrentLength As Integer)
Sub Unlock()
Sub GetCurrentLength(ByRef pcbCurrentLength As Integer)
Sub SetCurrentLength(cbCurrentLength As Integer)
Sub GetMaxLength(ByRef pcbMaxLength As Integer)
End Interface
<Runtime.InteropServices.ComImport, Runtime.InteropServices.InterfaceType( _
Runtime.InteropServices.ComInterfaceType.InterfaceIsIUnknown), _
Runtime.InteropServices.Guid("ad4c1b00-4bf7-422f-9175-756693d9130d")>
Public Interface IMFByteStream
Sub GetCapabilities(ByRef pdwCapabiities As Integer)
Sub GetLength(ByRef pqwLength As Long)
Sub SetLength(qwLength As Long)
Sub GetCurrentPosition(ByRef pqwPosition As Long)
Sub SetCurrentPosition(qwPosition As Long)
Sub IsEndOfStream(<Runtime.InteropServices.MarshalAs( _
Runtime.InteropServices.UnmanagedType.Bool)> ByRef pfEndOfStream As Boolean)
Sub Read(pb As IntPtr, cb As Integer, ByRef pcbRead As Integer)
Sub BeginRead(pb As IntPtr, cb As Integer, pCallback As IntPtr, punkState As IntPtr)
Sub EndRead(pResult As IntPtr, ByRef pcbRead As Integer)
Sub Write(pb As IntPtr, cb As Integer, ByRef pcbWritten As Integer)
Sub BeginWrite(pb As IntPtr, cb As Integer, pCallback As IntPtr, punkState As IntPtr)
Sub EndWrite(pResult As IntPtr, ByRef pcbWritten As Integer)
Sub Seek(SeekOrigin As Integer, llSeekOffset As Long, dwSeekFlags As Integer, ByRef pqwCurrentPosition As Long)
Sub Flush()
Sub Close()
End Interface
End Module
注释
将 Await 与 MediaElement 一起使用
在随附的代码中,我提供了一个 Windows 8 应用商店应用程序来演示 IMFSourceReader
。它使用 MediaElement
播放我们生成的 WAV 文件。通常,您通过为 MediaElement
的 Completed 事件注册事件处理程序来处理它。我不喜欢回调或事件处理程序。我更喜欢 Await
一个 MediaElement
。所以我创建了自己的辅助函数
Await MediaElement.EndedAsync()
MediaElement1.SetSource(stream, "audio/wav")
MediaElement1.Play()
Await MediaElement1.EndedAsync()
Visual Studio 2012 中新的 VB/C# Await
和 Async
关键字允许您通过提供辅助函数使任何类型都可等待,即使它本身不可等待。这是我的:
<Extension>
Function EndedAsync(m As MediaElement) As Task
Dim tcs As New TaskCompletionSource(Of Object)
Dim handlerEnded As RoutedEventHandler = Nothing
Dim handlerChanged As RoutedEventHandler = Nothing
Dim handlerFailed As ExceptionRoutedEventHandler = Nothing
handlerEnded =
Sub(s, e)
RemoveHandler m.MediaEnded, handlerEnded
RemoveHandler m.CurrentStateChanged, handlerChanged
RemoveHandler m.MediaFailed, handlerFailed
tcs.TrySetResult(Nothing)
End Sub
handlerChanged =
Sub(s, e)
If m.CurrentState <> MediaElementState.Closed AndAlso m.CurrentState _
<> MediaElementState.Stopped Then Return
RemoveHandler m.MediaEnded, handlerEnded
RemoveHandler m.CurrentStateChanged, handlerChanged
RemoveHandler m.MediaFailed, handlerFailed
tcs.TrySetResult(Nothing)
End Sub
handlerFailed =
Sub(s, e)
RemoveHandler m.MediaEnded, handlerEnded
RemoveHandler m.CurrentStateChanged, handlerChanged
RemoveHandler m.MediaFailed, handlerFailed
tcs.TrySetException(New Exception(e.ErrorMessage))
End Sub
AddHandler m.MediaEnded, handlerEnded
AddHandler m.CurrentStateChanged, handlerChanged
AddHandler m.MediaFailed, handlerFailed
If m.CurrentState = MediaElementState.Closed OrElse m.CurrentState = _
MediaElementState.Stopped Then tcs.TrySetResult(Nothing)
Return tcs.Task
End Function
免责声明:尽管我在 Microsoft 的 VB/C# 语言团队工作,但本文严格来说是基于公开信息和实验的个人业余努力——它不属于我的专业领域,是在我的业余时间撰写的,不代表 Microsoft,Microsoft 和我都不对其正确性做任何声明。