使用 Windows Media Foundation 进行视频编码器和元数据读取






4.33/5 (4投票s)
使用 Windows Media Foundation 进行视频编码器和元数据读取
1996-1997年,随着 Internet Explorer 3.0 的发布,微软发布了一套用于处理媒体内容(例如电影)的 API。他们当时称之为 Quartz。这是一个非常方便的接口集合,因此被业界广泛使用。现在我们称之为 DirectShow
。 岁月流逝,但 DirectShow
仍然保持不变。它运行良好,而且运行得非常好。几年前,微软决定需要改变,并开始为 Windows Vista、7 和 8 设计一个新的基于 COM 的多媒体框架。他们称之为 Media Foundation。这个框架更加通用和可扩展,但也更加复杂。今天,我们将学习如何使用 Media Foundation 检测视频或音频文件的编解码器信息,并与 DirectShow SDK 进行比较。那么,让我们开始吧...
使用 DirectShow 检测媒体文件的编解码器
这很简单。创建一个新的媒体检测器实例
var mediaDet = (IMediaDet)new MediaDet();
将你的文件放入其中
var hr = mediaDet.put_Filename(fileName);
枚举媒体流
int streamCount;
hr = mediaDet.get_OutputStreams(out streamCount);
获取每个流
for (int i = 0; i < streamCount; i++) {
hr = mediaDet.put_CurrentStream(i);
检测其类型
Guid streamType;
hr = mediaDet.get_StreamType(out streamType);
如果类型是视频,则获取 FourCC 编解码器代码 并解密
if (streamType == MediaType.Video) {
var mediaType = new AMMediaType();
hr = mediaDet.get_StreamMediaType(mediaType);
if (mediaType.formatType == FormatType.VideoInfo) {
var videoHeader = (VideoInfoHeader)Marshal.PtrToStructure
(mediaType.formatPtr, typeof(VideoInfoHeader));
var fourCC = FourCCToString(videoHeader.BmiHeader.Compression);
}
你还可以获取流长度并检索其他属性。
double streamLength;
hr = mediaDet.get_StreamLength(out streamLength);
关于此 API 的托管签名呢?没问题,它来了 + FourCC 解码器作为奖励。
private static string FourCCToString(int fourcc) {
byte[] bytes = new byte[4];
bytes[0] = (byte)(fourcc & 0x000000ff); fourcc = fourcc >> 8;
bytes[1] = (byte)(fourcc & 0x000000ff); fourcc = fourcc >> 8;
bytes[2] = (byte)(fourcc & 0x000000ff); fourcc = fourcc >> 8;
bytes[3] = (byte)(fourcc & 0x000000ff);
return Encoding.ASCII.GetString(bytes);
}
static public class MediaType {
public static readonly Guid Null = Guid.Empty;
public static readonly Guid Video = new Guid(0×73646976,
0×0000, 0×0010, 0×80, 0×00, 0×00,
0xaa, 0×00, 0×38, 0x9b, 0×71);
public static readonly Guid Audio = new Guid(0×73647561,
0×0000, 0×0010, 0×80, 0×00, 0×00,
0xaa, 0×00, 0×38, 0x9b, 0×71);
}
static public class FormatType {
public static readonly Guid Null = Guid.Empty;
public static readonly Guid None = new Guid(0x0F6417D6, 0xc318,
0x11d0, 0xa4, 0x3f, 0×00, 0xa0, 0xc9, 0×22, 0×31, 0×96);
public static readonly Guid VideoInfo = new Guid(0x05589f80, 0xc356,
0x11ce, 0xbf, 0×01, 0×00, 0xaa, 0×00, 0×55, 0×59, 0x5a);
public static readonly Guid VideoInfo2 = new Guid(0xf72a76A0, 0xeb0a,
0x11d0, 0xac, 0xe4, 0×00, 0×00, 0xc0, 0xcc, 0×16, 0xba);
public static readonly Guid WaveEx = new Guid(0x05589f81, 0xc356,
0x11ce, 0xbf, 0×01, 0×00, 0xaa, 0×00, 0×55, 0×59, 0x5a);
public static readonly Guid MpegVideo = new Guid(0x05589f82, 0xc356,
0x11ce, 0xbf, 0×01, 0×00, 0xaa, 0×00, 0×55, 0×59, 0x5a);
public static readonly Guid MpegStreams = new Guid(0x05589f83, 0xc356,
0x11ce, 0xbf, 0×01, 0×00, 0xaa, 0×00, 0×55, 0×59, 0x5a);
public static readonly Guid DvInfo = new Guid(0x05589f84, 0xc356,
0x11ce, 0xbf, 0×01, 0×00, 0xaa, 0×00, 0×55, 0×59, 0x5a);
public static readonly Guid AnalogVideo = new Guid(0x0482dde0,
0×7817, 0x11cf, 0x8a, 0×03, 0×00, 0xaa, 0×00, 0x6e, 0xcb, 0×65);
public static readonly Guid Mpeg2Video = new Guid(0xe06d80e3,
0xdb46, 0x11cf, 0xb4, 0xd1, 0×00, 0×80, 0x5f, 0x6c, 0xbb, 0xea);
public static readonly Guid DolbyAC3 = new Guid(0xe06d80e4, 0xdb46,
0x11cf, 0xb4, 0xd1, 0×00, 0×80, 0x5f, 0x6c, 0xbb, 0xea);
public static readonly Guid Mpeg2Audio = new Guid(0xe06d80e5, 0xdb46,
0x11cf, 0xb4, 0xd1, 0×00, 0×80, 0x5f, 0x6c, 0xbb, 0xea);
public static readonly Guid WSS525 = new Guid(0xc7ecf04d, 0×4582,
0×4869, 0x9a, 0xbb, 0xbf, 0xb5, 0×23, 0xb6, 0x2e, 0xdf);
public static readonly Guid ETDTFilter_Tagged = new Guid(0xC4C4C4D1,
0×0049, 0x4E2B, 0×98, 0xFB, 0×95,
0×37, 0xF6, 0xCE, 0×51, 0x6D);
public static readonly Guid CPFilters_Processed = new Guid(0x6739b36f,
0x1d5f, 0x4ac2, 0×81, 0×92, 0×28, 0xbb, 0xe, 0×73, 0xd1, 0x6a);
}
[ComImport, Guid("65BD0711-24D2-4ff7-9324-ED2E5D3ABAFA")]
public class MediaDet {
}
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
Guid("65BD0710-24D2-4ff7-9324-ED2E5D3ABAFA")]
public interface IMediaDet {
[PreserveSig]
int get_Filter([MarshalAs(UnmanagedType.IUnknown)] out object pVal);
[PreserveSig]
int put_Filter([MarshalAs(UnmanagedType.IUnknown)] object newVal);
[PreserveSig]
int get_OutputStreams(out int pVal);
[PreserveSig]
int get_CurrentStream(out int pVal);
[PreserveSig]
int put_CurrentStream(int newVal);
[PreserveSig]
int get_StreamType(out Guid pVal);
[PreserveSig]
int get_StreamTypeB([MarshalAs(UnmanagedType.BStr)] out string pVal);
[PreserveSig]
int get_StreamLength(out double pVal);
[PreserveSig]
int get_Filename([MarshalAs(UnmanagedType.BStr)] out string pVal);
[PreserveSig]
int put_Filename([MarshalAs(UnmanagedType.BStr)] string newVal);
[PreserveSig]
int GetBitmapBits(double StreamTime, out int pBufferSize,
[In] IntPtr pBuffer, int Width, int Height);
[PreserveSig]
int WriteBitmapBits(double StreamTime, int Width, int Height,
[In, MarshalAs(UnmanagedType.BStr)] string ilename);
[PreserveSig]
int get_StreamMediaType([Out, MarshalAs(UnmanagedType.LPStruct)] AMMediaType pVal);
[PreserveSig]
int GetSampleGrabber(out ISampleGrabber ppVal);
[PreserveSig]
int get_FrameRate(out double pVal);
[PreserveSig]
int EnterBitmapGrabMode(double SeekTime);
}
[ComImport, Guid("6B652FFF-11FE-4fce-92AD-0266B5D7C78F"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface ISampleGrabber {
[PreserveSig]
int SetOneShot([In, MarshalAs(UnmanagedType.Bool)] bool OneShot);
[PreserveSig]
int SetMediaType([In, MarshalAs(UnmanagedType.LPStruct)] AMMediaType pmt);
[PreserveSig]
int GetConnectedMediaType([Out, MarshalAs(UnmanagedType.LPStruct)] AMMediaType pmt);
[PreserveSig]
int SetBufferSamples([In, MarshalAs(UnmanagedType.Bool)] bool BufferThem);
[PreserveSig]
int GetCurrentBuffer(ref int pBufferSize, IntPtr pBuffer);
[PreserveSig]
int GetCurrentSample(out IMediaSample ppSample);
[PreserveSig]
int SetCallback(ISampleGrabberCB pCallback, int WhichMethodToCallback);
}
[ComImport, Guid("0579154A-2B53-4994-B0D0-E773148EFF85"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface ISampleGrabberCB {
[PreserveSig]
int SampleCB(double SampleTime, IMediaSample pSample);
[PreserveSig]
int BufferCB(double SampleTime, IntPtr pBuffer, int BufferLen);
}
[ComImport, Guid("56a8689a-0ad4-11ce-b03a-0020af0ba770"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IMediaSample {
[PreserveSig]
int GetPointer([Out] out IntPtr ppBuffer);
[PreserveSig]
int GetSize();
[PreserveSig]
int GetTime([Out] out long pTimeStart, [Out] out long pTimeEnd);
[PreserveSig]
int SetTime([In, MarshalAs(UnmanagedType.LPStruct)] LONG pTimeStart,
[In, MarshalAs(UnmanagedType.LPStruct)] LONG pTimeEnd);
[PreserveSig]
int IsSyncPoint();
[PreserveSig]
int SetSyncPoint([In, MarshalAs(UnmanagedType.Bool)] bool bIsSyncPoint);
[PreserveSig]
int IsPreroll();
[PreserveSig]
int SetPreroll([In, MarshalAs(UnmanagedType.Bool)] bool bIsPreroll);
[PreserveSig]
int GetActualDataLength();
[PreserveSig]
int SetActualDataLength([In] int len);
[PreserveSig]
int GetMediaType([Out, MarshalAs(UnmanagedType.LPStruct)] out AMMediaType ppMediaType);
[PreserveSig]
int SetMediaType([In, MarshalAs(UnmanagedType.LPStruct)] AMMediaType pMediaType);
[PreserveSig]
int IsDiscontinuity();
[PreserveSig]
int SetDiscontinuity([In, MarshalAs(UnmanagedType.Bool)] bool bDiscontinuity);
[PreserveSig]
int GetMediaTime([Out] out long pTimeStart, [Out] out long pTimeEnd);
[PreserveSig]
int SetMediaTime([In, MarshalAs(UnmanagedType.LPStruct)]
LONG pTimeStart, [In, MarshalAs(UnmanagedType.LPStruct)] LONG pTimeEnd);
}
[StructLayout(LayoutKind.Sequential)]
public class AMMediaType {
public Guid majorType;
public Guid subType;
[MarshalAs(UnmanagedType.Bool)]
public bool fixedSizeSamples;
[MarshalAs(UnmanagedType.Bool)]
public bool temporalCompression;
public int sampleSize;
public Guid formatType;
public IntPtr unkPtr;
public int formatSize;
public IntPtr formatPtr;
}
[StructLayout(LayoutKind.Sequential)]
public class VideoInfoHeader {
public RECT SrcRect;
public RECT TargetRect;
public int BitRate;
public int BitErrorRate;
public long AvgTimePerFrame;
public BitmapInfoHeader BmiHeader;
}
[StructLayout(LayoutKind.Sequential, Pack = 2)]
public class BitmapInfoHeader {
public int Size;
public int Width;
public int Height;
public short Planes;
public short BitCount;
public int Compression;
public int ImageSize;
public int XPelsPerMeter;
public int YPelsPerMeter;
public int ClrUsed;
public int ClrImportant;
}
[StructLayout(LayoutKind.Sequential)]
public class RECT {
public int left;
public int top;
public int right;
public int bottom;
}
[StructLayout(LayoutKind.Sequential)]
public class LONG {
private long Value;
}
}
看起来很简单吗?确实很简单。但是有两个问题。一个是微软已经将所有这些接口 定义为已弃用。第二个(这可能是 DirectShow 被弃用的原因),这些接口并非真正可扩展。现在让我们看看如何在 Media Foundation 中完成。
使用 Media Foundation 检测媒体文件的编解码器
首先,我们需要创建解析器的源
IMFSourceResolver res;
var hr = MFCreateSourceResolver(out res);
然后创建实际的解析器对象
IMFMediaSource source = null;
var objectType = MF_OBJECT_TYPE.Invalid;
object srs;
hr = res.CreateObjectFromURL(filePath, MFResolution.MediaSource, null, out objectType, out srs);
objectType == MF_OBJECT_TYPE.MediaSource;
source = (IMFMediaSource)srs;
有了它,我们需要创建描述符。
IMFPresentationDescriptor desc;
source.CreatePresentationDescriptor(out desc);
现在我们拥有了获取流计数和检索流所需的一切。
int count;
desc.GetStreamDescriptorCount(out count);
for (int i = 0; i < count; i++) {
IMFStreamDescriptor descriptor;
bool selected;
desc.GetStreamDescriptorByIndex(i, out selected, out descriptor);
if (selected) {
让我们获取类型处理程序以获取格式
IMFMediaTypeHandler handler;
descriptor.GetMediaTypeHandler(out handler);
IMFMediaType type;
handler.GetCurrentMediaType(out type);
Guid mediaType;
type.GetMajorType(out mediaType);
if (mediaType == MFMediaType.Video) {
然后获取实际的媒体类型和解码器代码
hr = MFCreateMFVideoFormatFromMFMediaType(type, out format, out size));
var fourCC = FourCCToString(format.surfaceInfo.Format);
看起来比 DirectShow
方法更复杂。让我们看看实际的接口定义。
[DllImport("mfplat.dll", ExactSpelling = true, PreserveSig = false)]
public static extern void MFShutdown();
[DllImport("mfplat.dll", ExactSpelling = true, PreserveSig = false)]
public static extern void MFStartup(int Version, MFSTARTUP dwFlags);
[DllImport("mfplat.dll", ExactSpelling = true, PreserveSig = false)]
public static extern int MFCreateMFVideoFormatFromMFMediaType([In]
IMFMediaType pMFType, out MFVIDEOFORMAT ppMFVF, out int pcbSize);
[DllImport("mf.dll", ExactSpelling = true, PreserveSig = false)]
public static extern int MFCreateSourceResolver(out IMFSourceResolver ppISourceResolver);
[DllImport("mf.dll", ExactSpelling = true, PreserveSig = false)]
public static extern void MFGetService
([In, MarshalAs(UnmanagedType.Interface)] object punkObject,
[In, MarshalAs(UnmanagedType.LPStruct)] Guid guidService,
[In, MarshalAs(UnmanagedType.LPStruct)] Guid riid,
[Out, MarshalAs(UnmanagedType.Interface)] out object ppvObject);
#region INTERFACES
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
Guid("FBE5A32D-A497-4B61-BB85-97B1A848A6E3")]
public interface IMFSourceResolver {
int CreateObjectFromURL([In, MarshalAs(UnmanagedType.LPWStr)] string pwszURL,
[In] MFResolution dwFlags, IPropertyStore pProps, out MF_OBJECT_TYPE pObjectType,
[MarshalAs(UnmanagedType.IUnknown)] out object ppObject);
int CreateObjectFromByteStream([In, MarshalAs(UnmanagedType.Interface)]
IMFByteStream pByteStream, [In, MarshalAs(UnmanagedType.LPWStr)] string pwszURL,
[In] MFResolution dwFlags,
[In, MarshalAs(UnmanagedType.Interface)] IPropertyStore pProps,
out MF_OBJECT_TYPE pObjectType, [MarshalAs(UnmanagedType.IUnknown)] out object ppObject);
int BeginCreateObjectFromURL([In, MarshalAs(UnmanagedType.LPWStr)] string pwszURL,
MFResolution dwFlags, IPropertyStore pProps,
[MarshalAs(UnmanagedType.IUnknown)] out object ppIUnknownCancelCookie,
IMFAsyncCallback pCallback, [In, MarshalAs(UnmanagedType.IUnknown)] object punkState);
int EndCreateObjectFromURL(IMFAsyncResult pResult, out MF_OBJECT_TYPE pObjectType,
[MarshalAs(UnmanagedType.Interface)] out object ppObject);
int BeginCreateObjectFromByteStream([In, MarshalAs(UnmanagedType.Interface)]
IMFByteStream pByteStream, [In, MarshalAs(UnmanagedType.LPWStr)] string pwszURL,
[In] MFResolution dwFlags, IPropertyStore pProps, [MarshalAs(UnmanagedType.IUnknown)]
out object ppIUnknownCancelCookie, IMFAsyncCallback pCallback,
[MarshalAs(UnmanagedType.IUnknown)] object punkState);
int EndCreateObjectFromByteStream(IMFAsyncResult pResult,
out MF_OBJECT_TYPE pObjectType, [MarshalAs(UnmanagedType.IUnknown)]
out object ppObject);
int CancelObjectCreation([In, MarshalAs(UnmanagedType.IUnknown)]
object pIUnknownCancelCookie);
}
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
Guid("AD4C1B00-4BF7-422F-9175-756693D9130D")]
public interface IMFByteStream {
void GetCapabilities(out MFBYTESTREAM pdwCapabilities);
void GetLength(out long pqwLength);
void SetLength([In] long qwLength);
void GetCurrentPosition(out long pqwPosition);
void SetCurrentPosition([In] long qwPosition);
void IsEndOfStream([MarshalAs(UnmanagedType.Bool)] out bool pfEndOfStream);
void Read(IntPtr pb, [In] int cb, out int pcbRead);
void BeginRead(IntPtr pb, [In] int cb,
[In, MarshalAs(UnmanagedType.Interface)]
IMFAsyncCallback pCallback, [In, MarshalAs(UnmanagedType.IUnknown)]
object pUnkState);
void EndRead([In, MarshalAs(UnmanagedType.Interface)]
IMFAsyncResult pResult, out int pcbRead);
void Write(IntPtr pb, [In] int cb, out int pcbWritten);
void BeginWrite(IntPtr pb, [In] int cb,
[In, MarshalAs(UnmanagedType.Interface)] IMFAsyncCallback pCallback,
[In, MarshalAs(UnmanagedType.IUnknown)] object pUnkState);
void EndWrite([In, MarshalAs(UnmanagedType.Interface)]
IMFAsyncResult pResult, out int pcbWritten);
void Seek([In] MFBYTESTREAM_SEEK_ORIGIN SeekOrigin,
[In] long llSeekOffset, [In] MFBYTESTREAM_SEEK_FLAG dwSeekFlags,
out long pqwCurrentPosition);
void Flush();
void Close();
}
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99")]
public interface IPropertyStore {
[MethodImpl(MethodImplOptions.InternalCall,
MethodCodeType = MethodCodeType.Runtime)]
void GetCount(out uint cProps);
[MethodImpl(MethodImplOptions.InternalCall,
MethodCodeType = MethodCodeType.Runtime)]
void GetAt([In] uint iProp, out PROPERTYKEY pkey);
[MethodImpl(MethodImplOptions.InternalCall,
MethodCodeType = MethodCodeType.Runtime)]
void GetValue([In] PROPERTYKEY key, out PROPVARIANT pv);
[MethodImpl(MethodImplOptions.InternalCall,
MethodCodeType = MethodCodeType.Runtime)]
void SetValue([In] PROPERTYKEY key, [In] ref PROPVARIANT pv);
[MethodImpl(MethodImplOptions.InternalCall,
MethodCodeType = MethodCodeType.Runtime)]
void Commit();
}
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
Guid("A27003CF-2354-4F2A-8D6A-AB7CFF15437E")]
public interface IMFAsyncCallback {
void GetParameters(out MFASYNC pdwFlags, out MFASYNC_CALLBACK_QUEUE pdwQueue);
void Invoke([In, MarshalAs(UnmanagedType.Interface)] IMFAsyncResult pAsyncResult);
}
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
Guid("AC6B7889-0740-4D51-8619-905994A55CC6")]
public interface IMFAsyncResult {
void GetState([MarshalAs(UnmanagedType.IUnknown)] out object ppunkState);
[PreserveSig]
int GetStatus();
void SetStatus([In, MarshalAs(UnmanagedType.Error)] int hrStatus);
void GetObject([MarshalAs(UnmanagedType.Interface)] out object ppObject);
[PreserveSig]
IntPtr GetStateNoAddRef();
}
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
Guid("DF598932-F10C-4E39-BBA2-C308F101DAA3")]
public interface IMFMediaEvent : IMFAttributes {
#region IMFAttributes methods
new void GetItem([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, IntPtr pValue);
new void GetItemType([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, out MF_ATTRIBUTE_TYPE pType);
new void CompareItem([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, IntPtr Value, [MarshalAs(UnmanagedType.Bool)] out bool pbResult);
new void Compare([MarshalAs(UnmanagedType.Interface)]
IMFAttributes pTheirs, MF_ATTRIBUTES_MATCH_TYPE MatchType,
[MarshalAs(UnmanagedType.Bool)] out bool pbResult);
new void GetUINT32([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, out int punValue);
new void GetUINT64([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, out long punValue);
new void GetDouble([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, out double pfValue);
new void GetGUID([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, out Guid pguidValue);
new void GetStringLength([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, out int pcchLength);
new void GetString([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pwszValue,
int cchBufSize, out int pcchLength);
new void GetAllocatedString([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, [MarshalAs(UnmanagedType.LPWStr)] out string ppwszValue, out int pcchLength);
new void GetBlobSize([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, out int pcbBlobSize);
new void GetBlob([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey,
[Out, MarshalAs(UnmanagedType.LPArray)] byte[] pBuf, int cbBufSize, out int pcbBlobSize);
// Use GetBlob instead of this
new void GetAllocatedBlob([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, out IntPtr ip, out int pcbSize);
new void GetUnknown([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, [In, MarshalAs(UnmanagedType.LPStruct)] Guid riid,
[MarshalAs(UnmanagedType.IUnknown)] out object ppv);
new void SetItem([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, IntPtr Value);
new void DeleteItem([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey);
new void DeleteAllItems();
new void SetUINT32([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, int unValue);
new void SetUINT64([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, long unValue);
new void SetDouble([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, double fValue);
new void SetGUID([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, [In, MarshalAs(UnmanagedType.LPStruct)] Guid guidValue);
new void SetString([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, [In, MarshalAs(UnmanagedType.LPWStr)] string wszValue);
new void SetBlob([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, [In, MarshalAs(UnmanagedType.LPArray,
SizeParamIndex = 2)] byte[] pBuf, int cbBufSize);
new void SetUnknown([MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, [In, MarshalAs(UnmanagedType.IUnknown)] object pUnknown);
new void LockStore();
new void UnlockStore();
new void GetCount(out int pcItems);
new void GetItemByIndex(int unIndex, out Guid pguidKey, IntPtr pValue);
new void CopyAllItems([In, MarshalAs(UnmanagedType.Interface)] IMFAttributes pDest);
#endregion
void GetType(out MediaEventType pmet);
void GetExtendedType(out Guid pguidExtendedType);
void GetStatus([MarshalAs(UnmanagedType.Error)] out int phrStatus);
void GetValue([In, Out] ref object pvValue);
}
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
Guid("03CB2711-24D7-4DB6-A17F-F3A7A479A536")]
public interface IMFPresentationDescriptor : IMFAttributes {
#region IMFAttributes methods
new void GetItem([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, IntPtr pValue);
new void GetItemType([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, out MF_ATTRIBUTE_TYPE pType);
new void CompareItem([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, IntPtr Value, [MarshalAs(UnmanagedType.Bool)] out bool pbResult);
new void Compare([MarshalAs(UnmanagedType.Interface)]
IMFAttributes pTheirs, MF_ATTRIBUTES_MATCH_TYPE MatchType,
[MarshalAs(UnmanagedType.Bool)] out bool pbResult);
new void GetUINT32([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, out int punValue);
new void GetUINT64([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, out long punValue);
new void GetDouble([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, out double pfValue);
new void GetGUID([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, out Guid pguidValue);
new void GetStringLength([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, out int pcchLength);
new void GetString([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pwszValue,
int cchBufSize, out int pcchLength);
new void GetAllocatedString([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, [MarshalAs(UnmanagedType.LPWStr)]
out string ppwszValue, out int pcchLength);
new void GetBlobSize([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, out int pcbBlobSize);
new void GetBlob([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey,
[Out, MarshalAs(UnmanagedType.LPArray)] byte[] pBuf, int cbBufSize, out int pcbBlobSize);
// Use GetBlob instead of this
new void GetAllocatedBlob([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, out IntPtr ip, out int pcbSize);
new void GetUnknown([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, [In, MarshalAs(UnmanagedType.LPStruct)] Guid riid,
[MarshalAs(UnmanagedType.IUnknown)] out object ppv);
new void SetItem([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, IntPtr Value);
new void DeleteItem([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey);
new void DeleteAllItems();
new void SetUINT32([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, int unValue);
new void SetUINT64([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, long unValue);
new void SetDouble([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, double fValue);
new void SetGUID([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, [In, MarshalAs(UnmanagedType.LPStruct)] Guid guidValue);
new void SetString([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, [In, MarshalAs(UnmanagedType.LPWStr)] string wszValue);
new void SetBlob([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, [In, MarshalAs(UnmanagedType.LPArray,
SizeParamIndex = 2)] byte[] pBuf, int cbBufSize);
new void SetUnknown([MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, [In, MarshalAs(UnmanagedType.IUnknown)] object pUnknown);
new void LockStore();
new void UnlockStore();
new void GetCount(out int pcItems);
new void GetItemByIndex(int unIndex, out Guid pguidKey, IntPtr pValue);
new void CopyAllItems([In, MarshalAs(UnmanagedType.Interface)] IMFAttributes pDest);
#endregion
void GetStreamDescriptorCount(out int pdwDescriptorCount);
void GetStreamDescriptorByIndex([In] int dwIndex,
[MarshalAs(UnmanagedType.Bool)] out bool pfSelected,
[MarshalAs(UnmanagedType.Interface)] out IMFStreamDescriptor ppDescriptor);
void SelectStream([In] int dwDescriptorIndex);
void DeselectStream([In] int dwDescriptorIndex);
void Clone([MarshalAs(UnmanagedType.Interface)]
out IMFPresentationDescriptor ppPresentationDescriptor);
}
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
Guid("56C03D9C-9DBB-45F5-AB4B-D80F47C05938")]
public interface IMFStreamDescriptor : IMFAttributes {
#region IMFAttributes methods
new void GetItem([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, IntPtr pValue);
new void GetItemType([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, out MF_ATTRIBUTE_TYPE pType);
new void CompareItem([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, IntPtr Value, [MarshalAs(UnmanagedType.Bool)] out bool pbResult);
new void Compare([MarshalAs(UnmanagedType.Interface)]
IMFAttributes pTheirs, MF_ATTRIBUTES_MATCH_TYPE MatchType,
[MarshalAs(UnmanagedType.Bool)] out bool pbResult);
new void GetUINT32([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, out int punValue);
new void GetUINT64([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, out long punValue);
new void GetDouble([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, out double pfValue);
new void GetGUID([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, out Guid pguidValue);
new void GetStringLength([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, out int pcchLength);
new void GetString([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, [Out, MarshalAs(UnmanagedType.LPWStr)]
StringBuilder pwszValue, int cchBufSize, out int pcchLength);
new void GetAllocatedString([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, [MarshalAs(UnmanagedType.LPWStr)] out string ppwszValue, out int pcchLength);
new void GetBlobSize([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, out int pcbBlobSize);
new void GetBlob([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey,
[Out, MarshalAs(UnmanagedType.LPArray)] byte[] pBuf, int cbBufSize, out int pcbBlobSize);
// Use GetBlob instead of this
new void GetAllocatedBlob([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, out IntPtr ip, out int pcbSize);
new void GetUnknown([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey,
[In, MarshalAs(UnmanagedType.LPStruct)] Guid riid,
[MarshalAs(UnmanagedType.IUnknown)] out object ppv);
new void SetItem([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, IntPtr Value);
new void DeleteItem([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey);
new void DeleteAllItems();
new void SetUINT32
([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, int unValue);
new void SetUINT64
([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, long unValue);
new void SetDouble
([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, double fValue);
new void SetGUID
([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey,
[In, MarshalAs(UnmanagedType.LPStruct)] Guid guidValue);
new void SetString([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey,
[In, MarshalAs(UnmanagedType.LPWStr)] string wszValue);
new void SetBlob([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey,
[In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] byte[] pBuf, int cbBufSize);
new void SetUnknown([MarshalAs(UnmanagedType.LPStruct)] Guid guidKey,
[In, MarshalAs(UnmanagedType.IUnknown)] object pUnknown);
new void LockStore();
new void UnlockStore();
new void GetCount(out int pcItems);
new void GetItemByIndex(int unIndex, out Guid pguidKey, IntPtr pValue);
new void CopyAllItems
([In, MarshalAs(UnmanagedType.Interface)] IMFAttributes pDest);
#endregion
void GetStreamIdentifier(out int pdwStreamIdentifier);
void GetMediaTypeHandler([MarshalAs(UnmanagedType.Interface)]
out IMFMediaTypeHandler ppMediaTypeHandler);
}
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
Guid("44AE0FA8-EA31-4109-8D2E-4CAE4997C555")]
public interface IMFMediaType : IMFAttributes {
#region IMFAttributes methods
new void GetItem([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey,
IntPtr pValue);
new void GetItemType([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, out MF_ATTRIBUTE_TYPE pType);
new void CompareItem([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, IntPtr Value, [MarshalAs(UnmanagedType.Bool)] out bool pbResult);
new void Compare([MarshalAs(UnmanagedType.Interface)]
IMFAttributes pTheirs, MF_ATTRIBUTES_MATCH_TYPE MatchType,
[MarshalAs(UnmanagedType.Bool)] out bool pbResult);
new void GetUINT32([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, out int punValue);
new void GetUINT64([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, out long punValue);
new void GetDouble([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, out double pfValue);
new void GetGUID([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, out Guid pguidValue);
new void GetStringLength([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, out int pcchLength);
new void GetString([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey,
[Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pwszValue,
int cchBufSize, out int pcchLength);
new void GetAllocatedString([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey,
[MarshalAs(UnmanagedType.LPWStr)] out string ppwszValue, out int pcchLength);
new void GetBlobSize([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey,
out int pcbBlobSize);
new void GetBlob([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey,
[Out, MarshalAs(UnmanagedType.LPArray)] byte[] pBuf, int cbBufSize, out int pcbBlobSize);
// Use GetBlob instead of this
new void GetAllocatedBlob([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey,
out IntPtr ip, out int pcbSize);
new void GetUnknown([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey,
[In, MarshalAs(UnmanagedType.LPStruct)] Guid riid,
[MarshalAs(UnmanagedType.IUnknown)] out object ppv);
new void SetItem([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, IntPtr Value);
new void DeleteItem([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey);
new void DeleteAllItems();
new void SetUINT32
([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, int unValue);
new void SetUINT64
([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, long unValue);
new void SetDouble
([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, double fValue);
new void SetGUID
([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey,
[In, MarshalAs(UnmanagedType.LPStruct)] Guid guidValue);
new void SetString
([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey,
[In, MarshalAs(UnmanagedType.LPWStr)] string wszValue);
new void SetBlob([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey,
[In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] byte[] pBuf, int cbBufSize);
new void SetUnknown([MarshalAs(UnmanagedType.LPStruct)] Guid guidKey,
[In, MarshalAs(UnmanagedType.IUnknown)] object pUnknown);
new void LockStore();
new void UnlockStore();
new void GetCount(out int pcItems);
new void GetItemByIndex(int unIndex, out Guid pguidKey, IntPtr pValue);
new void CopyAllItems([In, MarshalAs(UnmanagedType.Interface)] IMFAttributes pDest);
#endregion
void GetMajorType(out Guid pguidMajorType);
void IsCompressedFormat([MarshalAs(UnmanagedType.Bool)] out bool pfCompressed);
[PreserveSig]
int IsEqual([In, MarshalAs(UnmanagedType.Interface)]
IMFMediaType pIMediaType, out MF_MEDIATYPE_EQUAL pdwFlags);
void GetRepresentation([In, MarshalAs(UnmanagedType.Struct)]
Guid guidRepresentation, out IntPtr ppvRepresentation);
void FreeRepresentation([In, MarshalAs(UnmanagedType.Struct)]
Guid guidRepresentation, [In] IntPtr pvRepresentation);
}
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
Guid("2CD2D921-C447-44A7-A13C-4ADABFC247E3")]
public interface IMFAttributes {
void GetItem([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, IntPtr pValue);
void GetItemType([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, out MF_ATTRIBUTE_TYPE pType);
void CompareItem([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, IntPtr Value, [MarshalAs(UnmanagedType.Bool)] out bool pbResult);
void Compare([MarshalAs(UnmanagedType.Interface)]
IMFAttributes pTheirs, MF_ATTRIBUTES_MATCH_TYPE MatchType,
[MarshalAs(UnmanagedType.Bool)] out bool pbResult);
void GetUINT32([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, out int punValue);
void GetUINT64([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, out long punValue);
void GetDouble([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, out double pfValue);
void GetGUID([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, out Guid pguidValue);
void GetStringLength([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, out int pcchLength);
void GetString([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey,
[Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pwszValue,
int cchBufSize, out int pcchLength);
void GetAllocatedString([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, [MarshalAs(UnmanagedType.LPWStr)] out string ppwszValue, out int pcchLength);
void GetBlobSize([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, out int pcbBlobSize);
void GetBlob([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey,
[Out, MarshalAs(UnmanagedType.LPArray)] byte[] pBuf, int cbBufSize, out int pcbBlobSize);
void GetAllocatedBlob([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, out IntPtr ip, out int pcbSize);
void GetUnknown([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey,
[In, MarshalAs(UnmanagedType.LPStruct)] Guid riid,
[MarshalAs(UnmanagedType.IUnknown)] out object ppv);
void SetItem([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, IntPtr Value);
void DeleteItem([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey);
void DeleteAllItems();
void SetUINT32([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, int unValue);
void SetUINT64([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, long unValue);
void SetDouble([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, double fValue);
void SetGUID([In, MarshalAs(UnmanagedType.LPStruct)]
Guid guidKey, [In, MarshalAs(UnmanagedType.LPStruct)] Guid guidValue);
void SetString([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey,
[In, MarshalAs(UnmanagedType.LPWStr)] string wszValue);
void SetBlob([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey,
[In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] byte[] pBuf, int cbBufSize);
void SetUnknown([MarshalAs(UnmanagedType.LPStruct)] Guid guidKey,
[In, MarshalAs(UnmanagedType.IUnknown)] object pUnknown);
void LockStore();
void UnlockStore();
void GetCount(out int pcItems);
void GetItemByIndex(int unIndex, out Guid pguidKey, IntPtr pValue);
void CopyAllItems([In, MarshalAs(UnmanagedType.Interface)] IMFAttributes pDest);
}
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
Guid("2CD0BD52-BCD5-4B89-B62C-EADC0C031E7D")]
public interface IMFMediaEventGenerator {
void GetEvent([In] IMFMediaEvent dwFlags,
[MarshalAs(UnmanagedType.Interface)] out IMFMediaEvent ppEvent);
void BeginGetEvent([In, MarshalAs(UnmanagedType.Interface)]
IMFAsyncCallback pCallback, [In, MarshalAs(UnmanagedType.IUnknown)] object o);
void EndGetEvent(IMFAsyncResult pResult, out IMFMediaEvent ppEvent);
void QueueEvent([In] MediaEventType met,
[In, MarshalAs(UnmanagedType.LPStruct)] Guid guidExtendedType,
[In] int hrStatus, [In] ref object pvValue);
}
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
Guid("E93DCF6C-4B07-4E1E-8123-AA16ED6EADF5")]
public interface IMFMediaTypeHandler {
void IsMediaTypeSupported([In, MarshalAs(UnmanagedType.Interface)]
IMFMediaType pMediaType, IntPtr ppMediaType);
void GetMediaTypeCount(out int pdwTypeCount);
void GetMediaTypeByIndex([In] int dwIndex,
[MarshalAs(UnmanagedType.Interface)] out IMFMediaType ppType);
void SetCurrentMediaType([In, MarshalAs(UnmanagedType.Interface)]
IMFMediaType pMediaType);
void GetCurrentMediaType([MarshalAs(UnmanagedType.Interface)] out
IMFMediaType ppMediaType);
void GetMajorType(out Guid pguidMajorType);
}
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
Guid("279A808D-AEC7-40C8-9C6B-A6B492C78A66")]
public interface IMFMediaSource : IMFMediaEventGenerator {
#region IMFMediaEventGenerator methods
#pragma warning disable 109
new void GetEvent([In] MF_EVENT_FLAG dwFlags,
[MarshalAs(UnmanagedType.Interface)] out IMFMediaEvent ppEvent);
#pragma warning restore 109
new void BeginGetEvent([In, MarshalAs(UnmanagedType.Interface)]
IMFAsyncCallback pCallback, [In, MarshalAs(UnmanagedType.IUnknown)] object o);
new void EndGetEvent(IMFAsyncResult pResult, out IMFMediaEvent ppEvent);
new void QueueEvent([In] MediaEventType met,
[In, MarshalAs(UnmanagedType.LPStruct)] Guid guidExtendedType,
[In] int hrStatus, [In] ref object pvValue);
#endregion
void GetCharacteristics(out MFMEDIASOURCE_CHARACTERISTICS pdwCharacteristics);
void CreatePresentationDescriptor
(out IMFPresentationDescriptor ppPresentationDescriptor);
void Start([In, MarshalAs(UnmanagedType.Interface)]
IMFPresentationDescriptor pPresentationDescriptor,
[In, MarshalAs(UnmanagedType.LPStruct)] Guid pguidTimeFormat,
[In] ref object pvarStartPosition);
void Stop();
void Pause();
void Shutdown();
}
#endregion
还有一些数据对象
#region WM
#region STRUCTS
#pragma warning restore 618
[StructLayout(LayoutKind.Sequential, Pack = 8)]
public class MFVIDEOFORMAT {
public int dwSize;
public MFVideoInfo videoInfo;
public Guid guidFormat;
public MFVideoCompressedInfo compressedInfo;
public MFVideoSurfaceInfo surfaceInfo;
}
[StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct MFVideoSurfaceInfo {
public int Format;
public int PaletteEntries;
public MFPaletteEntry[] Palette;
}
[StructLayout(LayoutKind.Explicit, Pack = 1)]
public struct MFPaletteEntry {
[FieldOffset(0)]
public MFARGB ARGB;
[FieldOffset(0)]
public MFAYUVSample AYCbCr;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct MFAYUVSample {
public byte bCrValue;
public byte bCbValue;
public byte bYValue;
public byte bSampleAlpha8;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct MFARGB {
public byte rgbBlue;
public byte rgbGreen;
public byte rgbRed;
public byte rgbAlpha;
}
[StructLayout(LayoutKind.Sequential, Pack = 8)]
public struct MFVideoCompressedInfo {
public long AvgBitrate;
public long AvgBitErrorRate;
public int MaxKeyFrameSpacing;
}
[StructLayout(LayoutKind.Sequential, Pack = 8)]
public struct MFVideoInfo {
public int dwWidth;
public int dwHeight;
public MFRatio PixelAspectRatio;
public MFVideoChromaSubsampling SourceChromaSubsampling;
public MFVideoInterlaceMode InterlaceMode;
public MFVideoTransferFunction TransferFunction;
public MFVideoPrimaries ColorPrimaries;
public MFVideoTransferMatrix TransferMatrix;
public MFVideoLighting SourceLighting;
public MFRatio FramesPerSecond;
public MFNominalRange NominalRange;
public MFVideoArea GeometricAperture;
public MFVideoArea MinimumDisplayAperture;
public MFVideoArea PanScanAperture;
public MFVideoFlags VideoFlags;
}
[StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct MFRatio {
public int Numerator;
public int Denominator;
public MFRatio(int n, int d) {
Numerator = n;
Denominator = d;
}
}
[StructLayout(LayoutKind.Sequential, Pack = 4)]
public class MFVideoArea {
public MFOffset OffsetX;
public MFOffset OffsetY;
public SIZE Area;
public MFVideoArea() {
OffsetX = new MFOffset();
OffsetY = new MFOffset();
}
public MFVideoArea(float x, float y, int width, int height) {
OffsetX = new MFOffset(x);
OffsetY = new MFOffset(y);
Area = new SIZE(width, height);
}
public void MakeArea(float x, float y, int width, int height) {
OffsetX.MakeOffset(x);
OffsetY.MakeOffset(y);
Area.cx = width;
Area.cy = height;
}
}
[StructLayout(LayoutKind.Sequential, Pack = 2)]
public class MFOffset {
public short fract;
public short Value;
public MFOffset() {
}
public MFOffset(float v) {
Value = (short)v;
fract = (short)(65536 * (v – Value));
}
public void MakeOffset(float v) {
Value = (short)v;
fract = (short)(65536 * (v – Value));
}
public float GetOffset() {
return ((float)Value) + (((float)fract) / 65536.0f);
}
}
#endregion
#region ENUMS
public enum MFVideoInterlaceMode {
FieldInterleavedLowerFirst = 4,
FieldInterleavedUpperFirst = 3,
FieldSingleLower = 6,
FieldSingleUpper = 5,
ForceDWORD = 0x7fffffff,
Last = 8,
MixedInterlaceOrProgressive = 7,
Progressive = 2,
Unknown = 0
}
public enum MFVideoChromaSubsampling {
Cosited = 7,
DV_PAL = 6,
ForceDWORD = 0x7fffffff,
Horizontally_Cosited = 4,
Last = 8,
MPEG1 = 1,
MPEG2 = 5,
ProgressiveChroma = 8,
Unknown = 0,
Vertically_AlignedChromaPlanes = 1,
Vertically_Cosited = 2
}
public enum MFVideoTransferFunction {
Func10 = 1,
Func18 = 2,
Func20 = 3,
Func22 = 4,
Func240M = 6,
Func28 = 8,
Func709 = 5,
ForceDWORD = 0x7fffffff,
Last = 9,
sRGB = 7,
Unknown = 0
}
public enum MFVideoPrimaries {
BT470_2_SysBG = 4,
BT470_2_SysM = 3,
BT709 = 2,
EBU3213 = 7,
ForceDWORD = 0x7fffffff,
Last = 9,
reserved = 1,
SMPTE_C = 8,
SMPTE170M = 5,
SMPTE240M = 6,
Unknown = 0
}
public enum MFVideoTransferMatrix {
BT601 = 2,
BT709 = 1,
ForceDWORD = 0x7fffffff,
Last = 4,
SMPTE240M = 3,
Unknown = 0
}
public enum MFVideoLighting {
Bright = 1,
Dark = 4,
Dim = 3,
ForceDWORD = 0x7fffffff,
Last = 5,
Office = 2,
Unknown = 0
}
public enum MFNominalRange {
MFNominalRange_0_255 = 1,
MFNominalRange_16_235 = 2,
MFNominalRange_48_208 = 3,
MFNominalRange_ForceDWORD = 0x7fffffff,
MFNominalRange_Last = 4,
MFNominalRange_Normal = 1,
MFNominalRange_Unknown = 0,
MFNominalRange_Wide = 2
}
[Flags]
public enum MFVideoFlags : long {
PAD_TO_Mask = 0×0001 | 0×0002,
PAD_TO_None = 0 * 0×0001,
PAD_TO_4x3 = 1 * 0×0001,
PAD_TO_16x9 = 2 * 0×0001,
SrcContentHintMask = 0×0004 | 0×0008 | 0×0010,
SrcContentHintNone = 0 * 0×0004,
SrcContentHint16x9 = 1 * 0×0004,
SrcContentHint235_1 = 2 * 0×0004,
AnalogProtected = 0×0020,
DigitallyProtected = 0×0040,
ProgressiveContent = 0×0080,
FieldRepeatCountMask = 0×0100 | 0×0200 | 0×0400,
FieldRepeatCountShift = 8,
ProgressiveSeqReset = 0×0800,
PanScanEnabled = 0×20000,
LowerFieldFirst = 0×40000,
BottomUpLinearRep = 0×80000,
DXVASurface = 0×100000,
RenderTargetSurface = 0×400000,
ForceQWORD = 0x7FFFFFFF
}
[Flags]
public enum MF_EVENT_FLAG {
None = 0,
NoWait = 0×00000001
}
public enum MFASYNC_CALLBACK_QUEUE {
Undefined = 0×00000000,
Standard = 0×00000001,
RT = 0×00000002,
IO = 0×00000003,
Timer = 0×00000004,
LongFunction = 0×00000007,
PrivateMask = unchecked((int)0xFFFF0000),
All = unchecked((int)0xFFFFFFFF)
}
[Flags]
public enum MFASYNC {
None = 0,
FastIOProcessingCallback = 0×00000001,
SignalCallback = 0×00000002
}
public enum MFSTARTUP {
NoSocket = 0×1,
Lite = 0×1,
Full = 0
}
[Flags]
public enum MFResolution {
None = 0×0,
MediaSource = 0×00000001,
ByteStream = 0×00000002,
ContentDoesNotHaveToMatchExtensionOrMimeType = 0×00000010,
KeepByteStreamAliveOnFail = 0×00000020,
Read = 0×00010000,
Write = 0×00020000
}
[Flags]
public enum MFBYTESTREAM {
None = 0×00000000,
IsReadable = 0×00000001,
IsWritable = 0×00000002,
IsSeekable = 0×00000004,
IsRemote = 0×00000008,
IsDirectory = 0×00000080,
HasSlowSeek = 0×00000100,
IsPartiallyDownloaded = 0×00000200
}
public enum MFBYTESTREAM_SEEK_ORIGIN {
Begin,
Current
}
[Flags]
public enum MFBYTESTREAM_SEEK_FLAG {
None = 0,
CancelPendingIO = 1
}
public enum MF_OBJECT_TYPE {
MediaSource,
ByteStream,
Invalid
}
public enum MediaEventType {
MEUnknown = 0,
MEError = (MEUnknown + 1),
MEExtendedType = (MEError + 1),
MESessionUnknown = 100,
MESessionTopologySet = (MESessionUnknown + 1),
MESessionTopologiesCleared = (MESessionTopologySet + 1),
MESessionStarted = (MESessionTopologiesCleared + 1),
MESessionPaused = (MESessionStarted + 1),
MESessionStopped = (MESessionPaused + 1),
MESessionClosed = (MESessionStopped + 1),
MESessionEnded = (MESessionClosed + 1),
MESessionRateChanged = (MESessionEnded + 1),
MESessionScrubSampleComplete = (MESessionRateChanged + 1),
MESessionCapabilitiesChanged = (MESessionScrubSampleComplete + 1),
MESessionTopologyStatus = (MESessionCapabilitiesChanged + 1),
MESessionNotifyPresentationTime = (MESessionTopologyStatus + 1),
MENewPresentation = (MESessionNotifyPresentationTime + 1),
MELicenseAcquisitionStart = (MENewPresentation + 1),
MELicenseAcquisitionCompleted = (MELicenseAcquisitionStart + 1),
MEIndividualizationStart = (MELicenseAcquisitionCompleted + 1),
MEIndividualizationCompleted = (MEIndividualizationStart + 1),
MEEnablerProgress = (MEIndividualizationCompleted + 1),
MEEnablerCompleted = (MEEnablerProgress + 1),
MEPolicyError = (MEEnablerCompleted + 1),
MEPolicyReport = (MEPolicyError + 1),
MEBufferingStarted = (MEPolicyReport + 1),
MEBufferingStopped = (MEBufferingStarted + 1),
MEConnectStart = (MEBufferingStopped + 1),
MEConnectEnd = (MEConnectStart + 1),
MEReconnectStart = (MEConnectEnd + 1),
MEReconnectEnd = (MEReconnectStart + 1),
MERendererEvent = (MEReconnectEnd + 1),
MESessionStreamSinkFormatChanged = (MERendererEvent + 1),
MESourceUnknown = 200,
MESourceStarted = (MESourceUnknown + 1),
MEStreamStarted = (MESourceStarted + 1),
MESourceSeeked = (MEStreamStarted + 1),
MEStreamSeeked = (MESourceSeeked + 1),
MENewStream = (MEStreamSeeked + 1),
MEUpdatedStream = (MENewStream + 1),
MESourceStopped = (MEUpdatedStream + 1),
MEStreamStopped = (MESourceStopped + 1),
MESourcePaused = (MEStreamStopped + 1),
MEStreamPaused = (MESourcePaused + 1),
MEEndOfPresentation = (MEStreamPaused + 1),
MEEndOfStream = (MEEndOfPresentation + 1),
MEMediaSample = (MEEndOfStream + 1),
MEStreamTick = (MEMediaSample + 1),
MEStreamThinMode = (MEStreamTick + 1),
MEStreamFormatChanged = (MEStreamThinMode + 1),
MESourceRateChanged = (MEStreamFormatChanged + 1),
MEEndOfPresentationSegment = (MESourceRateChanged + 1),
MESourceCharacteristicsChanged = (MEEndOfPresentationSegment + 1),
MESourceRateChangeRequested = (MESourceCharacteristicsChanged + 1),
MESourceMetadataChanged = (MESourceRateChangeRequested + 1),
MESequencerSourceTopologyUpdated = (MESourceMetadataChanged + 1),
MESinkUnknown = 300,
MEStreamSinkStarted = (MESinkUnknown + 1),
MEStreamSinkStopped = (MEStreamSinkStarted + 1),
MEStreamSinkPaused = (MEStreamSinkStopped + 1),
MEStreamSinkRateChanged = (MEStreamSinkPaused + 1),
MEStreamSinkRequestSample = (MEStreamSinkRateChanged + 1),
MEStreamSinkMarker = (MEStreamSinkRequestSample + 1),
MEStreamSinkPrerolled = (MEStreamSinkMarker + 1),
MEStreamSinkScrubSampleComplete = (MEStreamSinkPrerolled + 1),
MEStreamSinkFormatChanged = (MEStreamSinkScrubSampleComplete + 1),
MEStreamSinkDeviceChanged = (MEStreamSinkFormatChanged + 1),
MEQualityNotify = (MEStreamSinkDeviceChanged + 1),
MESinkInvalidated = (MEQualityNotify + 1),
MEAudioSessionNameChanged = (MESinkInvalidated + 1),
MEAudioSessionVolumeChanged = (MEAudioSessionNameChanged + 1),
MEAudioSessionDeviceRemoved = (MEAudioSessionVolumeChanged + 1),
MEAudioSessionServerShutdown = (MEAudioSessionDeviceRemoved + 1),
MEAudioSessionGroupingParamChanged = (MEAudioSessionServerShutdown + 1),
MEAudioSessionIconChanged = (MEAudioSessionGroupingParamChanged + 1),
MEAudioSessionFormatChanged = (MEAudioSessionIconChanged + 1),
MEAudioSessionDisconnected = (MEAudioSessionFormatChanged + 1),
MEAudioSessionExclusiveModeOverride = (MEAudioSessionDisconnected + 1),
METrustUnknown = 400,
MEPolicyChanged = (METrustUnknown + 1),
MEContentProtectionMessage = (MEPolicyChanged + 1),
MEPolicySet = (MEContentProtectionMessage + 1),
MEWMDRMLicenseBackupCompleted = 500,
MEWMDRMLicenseBackupProgress = 501,
MEWMDRMLicenseRestoreCompleted = 502,
MEWMDRMLicenseRestoreProgress = 503,
MEWMDRMLicenseAcquisitionCompleted = 506,
MEWMDRMIndividualizationCompleted = 508,
MEWMDRMIndividualizationProgress = 513,
MEWMDRMProximityCompleted = 514,
MEWMDRMLicenseStoreCleaned = 515,
MEWMDRMRevocationDownloadCompleted = 516,
MEReservedMax = 10000
}
public enum MF_ATTRIBUTE_TYPE {
None = 0×0,
Blob = 0×1011,
Double = 0×5,
Guid = 0×48,
IUnknown = 13,
String = 0x1f,
Uint32 = 0×13,
Uint64 = 0×15
}
public enum MF_ATTRIBUTES_MATCH_TYPE {
OurItems,
TheirItems,
AllItems,
InterSection,
Smaller
}
[Flags]
public enum MFMEDIASOURCE_CHARACTERISTICS {
None = 0,
IsLive = 0×1,
CanSeek = 0×2,
CanPause = 0×4,
HasSlowSeek = 0×8
}
[Flags]
public enum MF_MEDIATYPE_EQUAL {
None = 0,
MajorTypes = 0×00000001,
FormatTypes = 0×00000002,
FormatData = 0×00000004,
FormatUserData = 0×00000008
}
#endregion
#endregion
有些繁琐,对吧?确实如此!但是这些接口是可扩展的。例如,这种方法增加了一些价值。
使用 Media Foundation 读取媒体元数据
现在,当我们完成了大部分工作后,元数据就变得轻而易举了。我们所需要做的就是获取服务句柄...
object s;
MFGetService(source, MFServices.MF_PROPERTY_HANDLER_SERVICE, typeof(IPropertyStore).GUID, out s);
var store = (IPropertyStore)s;
...并从属性包中获取信息
track.Album = _getInfo<string>(store, MFPropertyKeys.AlbumTitle);
track.Name = _getInfo<string>(store, MFPropertyKeys.Title);
track.Comments = _getInfo<string>(store, MFPropertyKeys.Comment);
track.Duration = TimeSpan.FromTicks(_getInfo<long>(store, Interop.MFPropertyKeys.MediaDuration));
…
这些接口使用 COM
属性包来检索不变类型的信息
private static T _getInfo<T>(IPropertyStore store, PROPERTYKEY key) {
PROPVARIANT val;
store.GetValue(key, out val);
return (T)val.Value;
}
这是此对象在托管代码中的外观
[StructLayout(LayoutKind.Sequential)]
public class PROPERTYKEY {
public PROPERTYKEY(Guid tid, uint id) {
fmtid = tid;
pid = id;
}
public Guid fmtid;
public uint pid;
}
#pragma warning disable 618
[StructLayout(LayoutKind.Explicit)]
public struct PROPVARIANT {
[FieldOffset(0)]
short vt;
[FieldOffset(2)]
short wReserved1;
[FieldOffset(4)]
short wReserved2;
[FieldOffset(6)]
short wReserved3;
[FieldOffset(8)]
sbyte cVal;
[FieldOffset(8)]
byte bVal;
[FieldOffset(8)]
short iVal;
[FieldOffset(8)]
ushort uiVal;
[FieldOffset(8)]
int lVal;
[FieldOffset(8)]
uint ulVal;
[FieldOffset(8)]
int intVal;
[FieldOffset(8)]
uint uintVal;
[FieldOffset(8)]
long hVal;
[FieldOffset(8)]
long uhVal;
[FieldOffset(8)]
float fltVal;
[FieldOffset(8)]
double dblVal;
[FieldOffset(8)]
bool boolVal;
[FieldOffset(8)]
int scode;
[FieldOffset(8)]
DateTime date;
[FieldOffset(8)]
FILETIME filetime;
[FieldOffset(8)]
BLOB blobVal;
[FieldOffset(8)]
IntPtr pwszVal;
private byte[] _getBlob() {
var result = new byte[blobVal.cbSize];
Marshal.Copy(blobVal.pBlobData, result, 0, result.Length);
return result;
}
public object Value {
get {
VarEnum ve = (VarEnum)vt;
switch (ve) {
case VarEnum.VT_I1:
return bVal;
case VarEnum.VT_I2:
return iVal;
case VarEnum.VT_I4:
return lVal;
case VarEnum.VT_I8:
return hVal;
case VarEnum.VT_INT:
return iVal;
case VarEnum.VT_UI4:
return ulVal;
case VarEnum.VT_UI8:
return uhVal;
case VarEnum.VT_LPWSTR:
return Marshal.PtrToStringUni(pwszVal);
case VarEnum.VT_BLOB:
return _getBlob();
case VarEnum.VT_EMPTY:
case VarEnum.VT_NULL:
return null;
}
throw new NotImplementedException("PROPVARIANT: " + ve.ToString());
}
}
}
还有一些额外的类和 GUID 来完成解决方案
public static class MFAttributesClsid {
public static readonly Guid MF_PD_DURATION = new Guid
(0x6c990d33, 0xbb8e, 0x477a, 0×85,
0×98, 0xd, 0x5d, 0×96, 0xfc, 0xd8, 0x8a);
public static readonly Guid MF_MT_SUBTYPE =
new Guid(0xf7e34c9a, 0x42e8, 0×4714, 0xb7, 0x4b, 0xcb,
0×29, 0xd7, 0x2c, 0×35, 0xe5);
public static readonly Guid MF_MT_AVG_BITRATE =
new Guid(0×20332624, 0xfb0d, 0x4d9e, 0xbd, 0x0d, 0xcb, 0xf6,
0×78, 0x6c, 0×10, 0x2e);
}
public static class MFMediaType {
public static readonly Guid Default = new Guid(0x81A412E6,
0×8103, 0x4B06, 0×85, 0x7F, 0×18, 0×62,
0×78, 0×10, 0×24, 0xAC);
public static readonly Guid Audio = new Guid(0×73647561,
0×0000, 0×0010, 0×80, 0×00, 0×00,
0xAA, 0×00, 0×38, 0x9B, 0×71);
public static readonly Guid Video = new Guid(0×73646976,
0×0000, 0×0010, 0×80, 0×00, 0×00,
0xAA, 0×00, 0×38, 0x9B, 0×71);
}
public static class MFServices {
public static readonly Guid MF_PROPERTY_HANDLER_SERVICE =
new Guid(0xa3face02, 0x32b8, 0x41dd, 0×90, 0xe7, 0x5f, 0xef,
0x7c, 0×89, 0×91, 0xb5);
}
public static class MFPropertyKeys {
public static readonly PROPERTYKEY Title = new PROPERTYKEY
(new Guid(0xf29f85e0, 0x4ff9, 0×1068, 0xab, 0×91,
0×08, 0×00, 0x2b, 0×27, 0xb3, 0xd9), 2);
public static readonly PROPERTYKEY AlbumTitle = new PROPERTYKEY
(new Guid(0x56A3372E, 0xCE9C, 0x11D2, 0x9F, 0x0E, 0×00,
0×60, 0×97, 0xC6, 0×86, 0xF6), 4);
public static readonly PROPERTYKEY Author = new PROPERTYKEY
(new Guid(0xF29F85E0, 0x4FF9, 0×1068, 0xAB, 0×91,
0×08, 0×00, 0x2B, 0×27, 0xB3, 0xD9), 4);
public static readonly PROPERTYKEY AudioCompression =
new PROPERTYKEY(new Guid(0×64440490, 0x4C8B, 0x11D1, 0x8B,
0×70, 0×08, 0×00, 0×36, 0xB1, 0x1A, 0×03), 10);
public static readonly PROPERTYKEY AudioFormat = new PROPERTYKEY
(new Guid(0×64440490, 0x4C8B, 0x11D1, 0x8B, 0×70,
0×08, 0×00, 0×36, 0xB1, 0x1A, 0×03), 2);
public static readonly PROPERTYKEY Category = new PROPERTYKEY
(new Guid(0xD5CDD502, 0x2E9C, 0x101B, 0×93, 0×97,
0×08, 0×00, 0x2B, 0x2C, 0xF9, 0xAE), 2);
public static readonly PROPERTYKEY Company = new PROPERTYKEY
(new Guid(0xD5CDD502, 0x2E9C, 0x101B, 0×93, 0×97,
0×08, 0×00, 0x2B, 0x2C, 0xF9, 0xAE), 15);
public static readonly PROPERTYKEY Copyright =
new PROPERTYKEY(new Guid(0×64440492, 0x4C8B, 0x11D1, 0x8B,
0×70, 0×08, 0×00, 0×36, 0xB1, 0x1A, 0×03), 11);
public static readonly PROPERTYKEY Comment = new PROPERTYKEY
(new Guid(0xF29F85E0, 0x4FF9, 0×1068, 0xAB, 0×91,
0×08, 0×00, 0x2B, 0×27, 0xB3, 0xD9), 6);
public static readonly PROPERTYKEY MediaDuration = new PROPERTYKEY
(new Guid(0×64440490, 0x4C8B, 0x11D1, 0x8B, 0×70, 0×08,
0×00, 0×36, 0xB1, 0x1A, 0×03), 3);
public static readonly PROPERTYKEY VideoCompression = new PROPERTYKEY
(new Guid(0×64440491, 0x4C8B, 0x11D1, 0x8B, 0×70, 0×08,
0×00, 0×36, 0xB1, 0x1A, 0×03), 10);
public static readonly PROPERTYKEY VideoDirector = new PROPERTYKEY
(new Guid(0×64440492, 0x4C8B, 0x11D1, 0x8B, 0×70, 0×08,
0×00, 0×36, 0xB1, 0x1A, 0×03), 20);
public static readonly PROPERTYKEY VideoFourCC = new PROPERTYKEY
(new Guid(0×64440491, 0x4C8B, 0x11D1, 0x8B, 0×70, 0×08,
0×00, 0×36, 0xB1, 0x1A, 0×03), 44);
}
我们几乎完成了。唯一不要忘记的是释放所有 COM 对象(Marshal.ReleaseComObject(…)
)以防止内存泄漏,并初始化和关闭 Media Foundation
MFStartup(0×10070, Interop.MFSTARTUP.Lite);
…
MFShutdown();
你选择使用哪种方法:简单但不受支持,或者复杂但可扩展的方法。两者都会产生相同的结果。祝你愉快,做一个好人。