转自:http://www.winbile.net/bbs/forums/threads/1000586.aspx
于渊
2006.06.10
适用平台
Windows Mobile 5.0
Windows CE 5.0
开发工具
Microsoft Visual Stuido 2005
摘要
通过本文可以了解如何在.NET CF 2.0中使用COM调用来使用DirectShow对象来实现简单的视音频播放。
正文
.NET CF 1.0中对COM对象的调用本人知道有三种:第一种:使用Odyssey公司的CFCOM控件来调用COM对象。缺点是需要交纳一定费用。第二种:使用本地代码来实现对COM对象操作的逻辑功能并封装成各个函数,并通过P/Invoke来在托管代码中调用这些功能块函数。此中方法比较简单,但是在托管代码中使用不太自由,不能访问到COM对象和接口。第三种:也是使用本地代码做个包装,将COM对象和其接口还有方法均分别曝光给调用者,同时在托管代码中使用P/Invoke来做一一对应。这种方法代码量巨大,很繁琐。但在托管代码中使用方便灵活,例如微软公司的曾经的Poom Sample例子。
由于.NET CF 2.O 对COM调用的支持,使得我们很容易操纵COM对象。
我们以下面一个例子开头来具体介绍。
本例子在托管代码中通过调用DirectShow来播放简单的视音频格式的文件。
1.新建一个Windows mobile 5.0的DeviceApplication项目,项目名称改为DirectShow,如下图所示
2.使用窗口编辑器修改Form1如下图所示
所作改动为Form1的背景色改为黑色,MinimizeBox设置为false方便调试,添加一个菜单名为Play。
3.给工程添加一个代码文件,命名为DSInterface.cs。在这个空白代码文件中复制如下代码进去,这些代码的作用是声明我们用到的DirectShow的一些接口。
using System;
using System.Runtime.InteropServices;
namespace DirectShow
{
[ComVisible(false)]
public enum PinDirection // PIN_DIRECTION
{
Input, // PINDIR_INPUT
Output // PINDIR_OUTPUT
}
public enum DsEvCode
{
None,
Complete = 0x01, // EC_COMPLETE
UserAbort = 0x02, // EC_USERABORT
ErrorAbort = 0x03, // EC_ERRORABORT
Time = 0x04, // EC_TIME
Repaint = 0x05, // EC_REPAINT
StErrStopped = 0x06, // EC_STREAM_ERROR_STOPPED
StErrStPlaying = 0x07, // EC_STREAM_ERROR_STILLPLAYING
ErrorStPlaying = 0x08, // EC_ERROR_STILLPLAYING
PaletteChanged = 0x09, // EC_PALETTE_CHANGED
VideoSizeChanged = 0x0a, // EC_VIDEO_SIZE_CHANGED
QualityChange = 0x0b, // EC_QUALITY_CHANGE
ShuttingDown = 0x0c, // EC_SHUTTING_DOWN
ClockChanged = 0x0d, // EC_CLOCK_CHANGED
Paused = 0x0e, // EC_PAUSED
OpeningFile = 0x10, // EC_OPENING_FILE
BufferingData = 0x11, // EC_BUFFERING_DATA
FullScreenLost = 0x12, // EC_FULLSCREEN_LOST
Activate = 0x13, // EC_ACTIVATE
NeedRestart = 0x14, // EC_NEED_RESTART
WindowDestroyed = 0x15, // EC_WINDOW_DESTROYED
DisplayChanged = 0x16, // EC_DISPLAY_CHANGED
Starvation = 0x17, // EC_STARVATION
OleEvent = 0x18, // EC_OLE_EVENT
NotifyWindow = 0x19, // EC_NOTIFY_WINDOW
// EC_ .
// DVDevCod.h
DvdDomChange = 0x101, // EC_DVD_DOMAIN_CHANGE
DvdTitleChange = 0x102, // EC_DVD_TITLE_CHANGE
DvdChaptStart = 0x103, // EC_DVD_CHAPTER_START
DvdAudioStChange = 0x104, // EC_DVD_AUDIO_STREAM_CHANGE
DvdSubPicStChange = 0x105, // EC_DVD_SUBPICTURE_STREAM_CHANGE
DvdAngleChange = 0x106, // EC_DVD_ANGLE_CHANGE
DvdButtonChange = 0x107, // EC_DVD_BUTTON_CHANGE
DvdValidUopsChange = 0x108, // EC_DVD_VALID_UOPS_CHANGE
DvdStillOn = 0x109, // EC_DVD_STILL_ON
DvdStillOff = 0x10a, // EC_DVD_STILL_OFF
DvdCurrentTime = 0x10b, // EC_DVD_CURRENT_TIME
DvdError = 0x10c, // EC_DVD_ERROR
DvdWarning = 0x10d, // EC_DVD_WARNING
DvdChaptAutoStop = 0x10e, // EC_DVD_CHAPTER_AUTOSTOP
DvdNoFpPgc = 0x10f, // EC_DVD_NO_FP_PGC
DvdPlaybRateChange = 0x110, // EC_DVD_PLAYBACK_RATE_CHANGE
DvdParentalLChange = 0x111, // EC_DVD_PARENTAL_LEVEL_CHANGE
DvdPlaybStopped = 0x112, // EC_DVD_PLAYBACK_STOPPED
DvdAnglesAvail = 0x113, // EC_DVD_ANGLES_AVAILABLE
DvdPeriodAStop = 0x114, // EC_DVD_PLAYPERIOD_AUTOSTOP
DvdButtonAActivated = 0x115, // EC_DVD_BUTTON_AUTO_ACTIVATED
DvdCmdStart = 0x116, // EC_DVD_CMD_START
DvdCmdEnd = 0x117, // EC_DVD_CMD_END
DvdDiscEjected = 0x118, // EC_DVD_DISC_EJECTED
DvdDiscInserted = 0x119, // EC_DVD_DISC_INSERTED
DvdCurrentHmsfTime = 0x11a, // EC_DVD_CURRENT_HMSF_TIME
DvdKaraokeMode = 0x11b // EC_DVD_KARAOKE_MODE
}
[StructLayout(LayoutKind.Sequential, Ch***t = Ch***t.Unicode), ComVisible(false)]
public class FilterInfo // FILTER_INFO
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string achName;
[MarshalAs(UnmanagedType.IUnknown)]
public object pUnk;
}
[StructLayout(LayoutKind.Sequential), ComVisible(false)]
public class AMMediaType // AM_MEDIA_TYPE
{
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 uint cbFormat;
public IntPtr formatPtr;
}
[ComVisible(true), ComImport,
Guid("56a86891-0ad4-11ce-b03a-0020af0ba770"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IPin
{
[PreserveSig]
int Connect(
[In] IPin pReceivePin,
[In, MarshalAs(UnmanagedType.LPStruct)] AMMediaType pmt);
[PreserveSig]
int ReceiveConnection(
[In] IPin pReceivePin,
[In, MarshalAs(UnmanagedType.LPStruct)] AMMediaType pmt);
[PreserveSig]
int Disconnect();
[PreserveSig]
int ConnectedTo([Out] out IPin ppPin);
[PreserveSig]
int ConnectionMediaType(
[Out, MarshalAs(UnmanagedType.LPStruct)] AMMediaType pmt);
[PreserveSig]
int QueryPinInfo(IntPtr pInfo);
[PreserveSig]
int QueryDirection(out PinDirection pPinDir);
[PreserveSig]
int QueryId(
[Out, MarshalAs(UnmanagedType.LPWStr)] out string Id);
[PreserveSig]
int QueryAccept(
[In, MarshalAs(UnmanagedType.LPStruct)] AMMediaType pmt);
[PreserveSig]
int EnumMediaTypes(IntPtr ppEnum);
[PreserveSig]
int QueryInternalConnections(IntPtr apPin, [In, Out] ref int nPin);
[PreserveSig]
int EndOfStream();
[PreserveSig]
int BeginFlush();
[PreserveSig]
int EndFlush();
[PreserveSig]
int NewSegment(long tStart, long tStop, double dRate);
}
[ComVisible(true), ComImport,
Guid("56a86897-0ad4-11ce-b03a-0020af0ba770"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IReferenceClock
{
[PreserveSig]
int GetTime(out long pTime);
[PreserveSig]
int AdviseTime(long baseTime, long streamTime, IntPtr hEvent, out int pdwAdviseCookie);
[PreserveSig]
int AdvisePeriodic(long startTime, long periodTime, IntPtr hSemaphore, out int pdwAdviseCookie);
[PreserveSig]
int Unadvise(int dwAdviseCookie);
}
[ComVisible(true), ComImport,
Guid("56a8689f-0ad4-11ce-b03a-0020af0ba770"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IFilterGraph
{
[PreserveSig]
int AddFilter(
[In] IBaseFilter pFilter,
[In, MarshalAs(UnmanagedType.LPWStr)] string pName);
[PreserveSig]
int RemoveFilter([In] IBaseFilter pFilter);
[PreserveSig]
int EnumFilters([Out] out IEnumFilters ppEnum);
[PreserveSig]
int FindFilterByName(
[In, MarshalAs(UnmanagedType.LPWStr)] string pName,
[Out] out IBaseFilter ppFilter);
[PreserveSig]
int ConnectDirect([In] IPin ppinOut, [In] IPin ppinIn,
[In, MarshalAs(UnmanagedType.LPStruct)] AMMediaType pmt);
[PreserveSig]
int Reconnect([In] IPin ppin);
[PreserveSig]
int Disconnect([In] IPin ppin);
[PreserveSig]
int SetDefaultSyncSource();
}
[ComVisible(true), ComImport,
Guid("56a86892-0ad4-11ce-b03a-0020af0ba770"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IEnumPins
{
[PreserveSig]
int Next(
[In] int cPins,
[Out, MarshalAs(UnmanagedType.LPArray)] out IPin[] ppPins,
[Out] out int pcFetched);
[PreserveSig]
int Skip([In] int cPins);
void Reset();
void Clone([Out] out IEnumPins ppEnum);
}
[ComVisible(true), ComImport,
Guid("56a86895-0ad4-11ce-b03a-0020af0ba770"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IBaseFilter
{
"IPersist Methods"#region "IPersist Methods"
[PreserveSig]
int GetClassID(
[Out] out Guid pClassID);
#endregion
"IMediaFilter Methods"#region "IMediaFilter Methods"
[PreserveSig]
int Stop();
[PreserveSig]
int Pause();
[PreserveSig]
int Run(long tStart);
[PreserveSig]
int GetState(int dwMilliSecsTimeout, [Out] out int filtState);
[PreserveSig]
int SetSyncSource([In] IReferenceClock pClock);
[PreserveSig]
int GetSyncSource([Out] out IReferenceClock pClock);
#endregion
[PreserveSig]
int EnumPins(
[Out] out IEnumPins ppEnum);
[PreserveSig]
int FindPin(
[In, MarshalAs(UnmanagedType.LPWStr)] string Id,
[Out] out IPin ppPin);
[PreserveSig]
int QueryFilterInfo(
[Out] FilterInfo pInfo);
[PreserveSig]
int JoinFilterGraph(
[In] IFilterGraph pGraph,
[In, MarshalAs(UnmanagedType.LPWStr)] string pName);
[PreserveSig]
int QueryVendorInfo(
[Out, MarshalAs(UnmanagedType.LPWStr)] out string pVendorInfo);
}
[ComVisible(true), ComImport,
Guid("56a868a9-0ad4-11ce-b03a-0020af0ba770"),//56a868a9-0ad4-11ce-b03a-0020af0ba770
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IGraphBuilder
{
"IFilterGraph Methods"#region "IFilterGraph Methods"
[PreserveSig]
int AddFilter(
[In] IBaseFilter pFilter,
[In, MarshalAs(UnmanagedType.LPWStr)] string pName);
[PreserveSig]
int RemoveFilter([In] IBaseFilter pFilter);
[PreserveSig]
int EnumFilters([Out] out IEnumFilters ppEnum);
[PreserveSig]
int FindFilterByName(
[In, MarshalAs(UnmanagedType.LPWStr)] string pName,
[Out] out IBaseFilter ppFilter);
/**//// <summary>
/// This method connects the two pins directly (without intervening filters).
/// </summary>
/// <param name="ppinOut"></param>
/// <param name="ppinIn"></param>
/// <param name="pmt">[in] Media type to use for the connection (optional; that is, can be NULL). </param>
/// <returns></returns>
[PreserveSig]
int ConnectDirect([In] IPin ppinOut, [In] IPin ppinIn,
[In, MarshalAs(UnmanagedType.LPStruct)] AMMediaType pmt);
[PreserveSig]
int Reconnect([In] IPin ppin);
[PreserveSig]
int Disconnect([In] IPin ppin);
[PreserveSig]
int SetDefaultSyncSource();
#endregion
[PreserveSig]
int Connect([In] IPin ppinOut, [In] IPin ppinIn);
[PreserveSig]
int Render([In] IPin ppinOut);
[PreserveSig]
int RenderFile(
[In, MarshalAs(UnmanagedType.LPWStr)] string lpcwstrFile,
[In, MarshalAs(UnmanagedType.LPWStr)] string lpcwstrPlayList);
[PreserveSig]
int AddSourceFilter(
[In, MarshalAs(UnmanagedType.LPWStr)] string lpcwstrFileName,
[In, MarshalAs(UnmanagedType.LPWStr)] string lpcwstrFilterName,
[Out] out IBaseFilter ppFilter);
[PreserveSig]
int SetLogFile(IntPtr hFile);
[PreserveSig]
int Abort();
[PreserveSig]
int ShouldOperationContinue();
}
// ---------------------------------------------------------------------------------------
/// <summary>
/// The IFilterGraph::EnumFilters method returns the enumerator interface. It is based on the COM IEnum style of enumerators.
/// </summary>
[ComVisible(true), ComImport,
Guid("56a86893-0ad4-11ce-b03a-0020af0ba770"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IEnumFilters
{
[PreserveSig]
int Next(
[In] int cFilters,
[Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] out IBaseFilter[] ppFilter,
[Out] out int pcFetched);
[PreserveSig]
int Skip([In] int cFilters);
void Reset();
void Clone([Out] out IEnumFilters ppEnum);
}
[ComVisible(true), ComImport,
Guid("56a868c0-0ad4-11ce-b03a-0020af0ba770"),
InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IMediaEventEx
{
"IMediaEvent Methods"#region "IMediaEvent Methods"
[PreserveSig]
int GetEventHandle(out IntPtr hEvent);
[PreserveSig]
int GetEvent(out DsEvCode lEventCode, out int lParam1, out int lParam2, uint msTimeout);
[PreserveSig]
int WaitForCompletion(int msTimeout, [Out] out int pEvCode);
[PreserveSig]
int CancelDefaultHandling(int lEvCode);
[PreserveSig]
int RestoreDefaultHandling(int lEvCode);
[PreserveSig]
int FreeEventParams(DsEvCode lEvCode, int lParam1, int lParam2);
#endregion
[PreserveSig]
int SetNotifyWindow(IntPtr hwnd, int lMsg, IntPtr lInstanceData);
[PreserveSig]
int SetNotifyFlags(int lNoNotifyFlags);
[PreserveSig]
int GetNotifyFlags(out int lplNoNotifyFlags);
}
[ComVisible(true), ComImport,
Guid("56a868b5-0ad4-11ce-b03a-0020af0ba770"),
InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IBasicVideo
{
[PreserveSig]
int get_AvgTimePerFrame(out double pAvgTimePerFrame);
[PreserveSig]
int get_BitRate(out int pBitRate);
[PreserveSig]
int get_BitErrorRate(out int pBitRate);
[PreserveSig]
int get_VideoWidth(out int pVideoWidth);
[PreserveSig]
int get_VideoHeight(out int pVideoHeight);
[PreserveSig]
int put_SourceLeft(int SourceLeft);
[PreserveSig]
int get_SourceLeft(out int pSourceLeft);
[PreserveSig]
int put_SourceWidth(int SourceWidth);
[PreserveSig]
int get_SourceWidth(out int pSourceWidth);
[PreserveSig]
int put_SourceTop(int SourceTop);
[PreserveSig]
int get_SourceTop(out int pSourceTop);
[PreserveSig]
int put_SourceHeight(int SourceHeight);
[PreserveSig]
int get_SourceHeight(out int pSourceHeight);
[PreserveSig]
int put_DestinationLeft(int DestinationLeft);
[PreserveSig]
int get_DestinationLeft(out int pDestinationLeft);
[PreserveSig]
int put_DestinationWidth(int DestinationWidth);
[PreserveSig]
int get_DestinationWidth(out int pDestinationWidth);
[PreserveSig]
int put_DestinationTop(int DestinationTop);
[PreserveSig]
int get_DestinationTop(out int pDestinationTop);
[PreserveSig]
int put_DestinationHeight(int DestinationHeight);
[PreserveSig]
int get_DestinationHeight(out int pDestinationHeight);
[PreserveSig]
int SetSourcePosition(int left, int top, int width, int height);
[PreserveSig]
int GetSourcePosition(out int left, out int top, out int width, out int height);
[PreserveSig]
int SetDefaultSourcePosition();
[PreserveSig]
int SetDestinationPosition(int left, int top, int width, int height);
[PreserveSig]
int GetDestinationPosition(out int left, out int top, out int width, out int height);
[PreserveSig]
int SetDefaultDestinationPosition();
[PreserveSig]
int GetVideoSize(out int pWidth, out int pHeight);
[PreserveSig]
int GetVideoPaletteEntries(int StartIndex, int Entries, out int pRetrieved, IntPtr pPalette);
[PreserveSig]
int GetCurrentImage(ref int pBufferSize, IntPtr pDIBImage);
[PreserveSig]
int IsUsingDefaultSource();
[PreserveSig]
int IsUsingDefaultDestination();
/**//* The following will supported in IBasicVideo2
[PreserveSig]
int GetPreferredAspectRatio(out int plAspectX, out int plAspectY);
*/
}
[ComVisible(true), ComImport,
Guid("56a868b4-0ad4-11ce-b03a-0020af0ba770"),
InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IVideoWindow
{
[PreserveSig]
int put_Caption(string caption);
[PreserveSig]
int get_Caption([Out] out string caption);
[PreserveSig]
int put_WindowStyle(int windowStyle);
[PreserveSig]
int get_WindowStyle(out int windowStyle);
[PreserveSig]
int put_WindowStyleEx(int windowStyleEx);
[PreserveSig]
int get_WindowStyleEx(out int windowStyleEx);
[PreserveSig]
int put_AutoShow(int autoShow);
[PreserveSig]
int get_AutoShow(out int autoShow);
[PreserveSig]
int put_WindowState(int windowState);
[PreserveSig]
int get_WindowState(out int windowState);
[PreserveSig]
int put_BackgroundPalette(int backgroundPalette);
[PreserveSig]
int get_BackgroundPalette(out int backgroundPalette);
[PreserveSig]
int put_Visible(int visible);
[PreserveSig]
int get_Visible(out int visible);
[PreserveSig]
int put_Left(int left);
[PreserveSig]
int get_Left(out int left);
[PreserveSig]
int put_Width(int width);
[PreserveSig]
int get_Width(out int width);
[PreserveSig]
int put_Top(int top);
[PreserveSig]
int get_Top(out int top);
[PreserveSig]
int put_Height(int height);
[PreserveSig]
int get_Height(out int height);
[PreserveSig]
int put_Owner(IntPtr owner);
[PreserveSig]
int get_Owner(out IntPtr owner);
[PreserveSig]
int put_MessageDrain(IntPtr drain);
[PreserveSig]
int get_MessageDrain(out IntPtr drain);
[PreserveSig]
int get_BorderColor(out int color);
[PreserveSig]
int put_BorderColor(int color);
[PreserveSig]
int get_FullScreenMode(out int fullScreenMode);
[PreserveSig]
int put_FullScreenMode(int fullScreenMode);
[PreserveSig]
int SetWindowForeground(int focus);
[PreserveSig]
int NotifyOwnerMessage(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam);
[PreserveSig]
int SetWindowPosition(int left, int top, int width, int height);
[PreserveSig]
int GetWindowPosition(out int left, out int top, out int width, out int height);
[PreserveSig]
int GetMinIdealImageSize(out int width, out int height);
[PreserveSig]
int GetMaxIdealImageSize(out int width, out int height);
[PreserveSig]
int GetRestorePosition(out int left, out int top, out int width, out int height);
[PreserveSig]
int HideCursor(int hideCursor);
[PreserveSig]
int IsCursorHidden(out int hideCursor);
}
[ComVisible(true), ComImport,
Guid("56a868b3-0ad4-11ce-b03a-0020af0ba770"),
InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IBasicAudio
{
[PreserveSig]
int put_Volume(int lVolume);
[PreserveSig]
int get_Volume(out int plVolume);
[PreserveSig]
int put_Balance(int lBalance);
[PreserveSig]
int get_Balance(out int plBalance);
}
[ComVisible(true), ComImport,
Guid("56a868b1-0ad4-11ce-b03a-0020af0ba770"),
InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IMediaControl
{
[PreserveSig]
int Run();
[PreserveSig]
int Pause();
[PreserveSig]
int Stop();
[PreserveSig]
int GetState(int msTimeout, out int pfs);
[PreserveSig]
int RenderFile(string strFilename);
[PreserveSig]
int AddSourceFilter(
[In] string strFilename,
[Out, MarshalAs(UnmanagedType.IDispatch)] out object ppUnk);
[PreserveSig]
int get_FilterCollection(
[Out, MarshalAs(UnmanagedType.IDispatch)] out object ppUnk);
[PreserveSig]
int get_RegFilterCollection(
[Out, MarshalAs(UnmanagedType.IDispatch)] out object ppUnk);
[PreserveSig]
int StopWhenReady();
}
}
4.在Form1的构造函数之前添加如下变量
Guid FilterGraph = new Guid("e436ebb3-524f-11ce-9f53-0020af0ba770");
object comObject = null;
//要播放的文件路径
string clipFile = @"\clock.avi";
IGraphBuilder graphBuilder;
private IVideoWindow videoWin;
private IBasicVideo basicVideo;
private IBasicAudio basicAudio;
private IMediaControl mediaCtl;
private IMediaEventEx mediaEvt;
private const int WM_GRAPHNOTIFY = 0x00008001;
private const int WS_CHILD = 0x40000000;
private const int WS_CLIPCHILDREN = 0x02000000;
private const int WS_CLIPSIBLINGS = 0x04000000;
5.在窗口编辑器中双击Play菜单,在生成的事件处理方法体中添加如下代码
private void menuItem1_Click(object sender, EventArgs e)
{
try
{
//获得DirectShow的接口
GetInterface();
//使用GraphBuilder 的智能链接来自动播放音视频文件。
int hr = graphBuilder.RenderFile(clipFile, null);
//每一次调用Com方法要检查返回的int类型的数据,如果小于0,一般意味着有错误发生
//并通过放回值可以知道何种错误。
CHK(hr);
hr = mediaEvt.SetNotifyWindow(this.Handle, WM_GRAPHNOTIFY, IntPtr.Zero);
CHK(hr);
hr = videoWin.put_Owner(this.Handle);
CHK(hr);
//设置视频播放窗口类型
hr = videoWin.put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
CHK(hr);
Rectangle rc = this.ClientRectangle;
//设置视频播放窗口大小位置
hr = videoWin.SetWindowPosition(0, 0, rc.Right, rc.Bottom);
CHK(hr);
//通过IMediaControl接口的Run方法来使得整个Filter Graph运行从而播放文件
hr = mediaCtl.Run();
CHK(hr);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
同时在Form1.cs文件的最上面添加这段代码
using System.Runtime.InteropServices;
6.添加如下方法
private void CHK(int hr)
{
if (hr < 0)
{
Marshal.ThrowExceptionForHR(hr);
}
}
private void GetInterface()
{
try
{
comObject = CreateComObj(FilterGraph);
graphBuilder = (IGraphBuilder)comObject;
comObject = null;
//通过获得的IGraphBuilder接口来获得其他接口
mediaCtl = (IMediaControl)graphBuilder;
mediaEvt = (IMediaEventEx)graphBuilder;
videoWin = graphBuilder as IVideoWindow;
basicVideo = graphBuilder as IBasicVideo;
basicAudio = graphBuilder as IBasicAudio;
}
finally
{
if (comObject != null)
Marshal.ReleaseComObject(comObject);
comObject = null;
}
}
private object CreateComObj(Guid ClsID)
{
object com = null;
try
{
//通过Com对象的Guid来生成Com对象
Type clsType = Type.GetTypeFromCLSID(ClsID);
com = Activator.CreateInstance(clsType);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
return com;
}
7.代码完成,这时候使用VS2005自带的Remote File Viewer上传视频文件到模拟器或者实机的根文件夹下面,这个视频文件请务必使用桌面机器上面Windows目录夹里面的Clock.avi文件。当上传完毕后,运行程序。程序运行效果如下图所示(此时没有声音播出,原因稍后再讲)
我们现在关闭程序并上传一段wav音频文件到设备中,并修改
string clipFile = @"\clock.avi"指向你上传的wav文件路径,此时再点击Play菜单即可播放出音频文件。如果我们想上传一个Wmv格式的文件并用此程序来播放的话,应用程序总是提示一串错误表示无法播放。这其中的原因是,我们使用DirectShow的智能链接技术来播放视音频,此时GrahpManager会通过要播放的文件格式来选择相应的编解码器(Filter),对于大部分的Windows Mobile 5.0设备来说都没有WMV 解码器,所以自然而然不能播放此种文件。我们检查Clock文件,它的视频格式为MS-RLE,音频格式为DSP group TrueSpeech(TM).我们也可以从Platform Builder中可以推出
由于RLE Video Codec的footprint很小,所以在大部分的设备中都支持此中codec,而由于
WMV的footprint'较大,所以可能在mobile 5.0的设备中很少有支持的。而刚才Clock.avi文件没有播放出声音,也可以推测是没有相关支持其解码的DirectShow Filter的存在而导致。我们也可以用同样的
代码在桌面程序中进行运行将会发现能播放的文件种类将会大大增加。
读者可能会有疑问,到底我的设备中有什么filter,没有什么filter呢,一个简单的方法是使用 VS2005自带的Remote Registry Editor连接到设备中,展开HKEY_CLASSES_ROOT,找到CLSID并单击,然后使用菜单栏中的Registry.Export Registry到桌面机器上面,最后用记事本打开,使用查找功能搜索相关字符串来进行确认。例如我想知道Decoder有关的filter信息,用关键字Decoder进行搜索,会发现有
[HKEY_CLASSES_ROOT\CLSID\{86A495AC-64CE-42DE-A13A-321ACC0F02DB}]
@="MPEG-1 Layer 3 Decoder DMO"
"DMOGuid"="6b928210-84e7-4930-9b33-1eb6f02b526e"
"DMOCategory"="57f2db8b-e6bb-4513-9d43-dcd2a6593125"
"Merit"=dword:00800001
这个表示设备支持MP3 音频解码,但由于是Microsoft® DirectX® Media Objects (DMO). 所以
我们还需要一些额外工作才能进行mp3解码。
再搜索Encoder,会搜索到
[HKEY_CLASSES_ROOT\CLSID\{d23b90d0-144f-46bd-841d-59e4eb19dc59}]
@="WMVideo9 Encoder DMO"
"Merit"=dword:00800000
这个表示wmv编码DMO,我们可以使用这个DMO来对摄像头采集到的数据进行编码从而生成视频文件。
8.现在回顾这个程序,可以发现除了DirectShow的接口的声明很麻烦以外,其他主程序的编写实际上很简单而且也跟本地代码操纵DirectShow很相似。至于DirectShow的接口,网上有一个很好的开源项目
DirectShow.NET 提供大部分的接口声明,虽然是针对桌面机,但是稍加改动就可以为我们所用。
附注:由于本人知识有限,并且时间仓促,难免有不妥之处,敬请指正。另外并不是所有的DirectShow接口进行过验证。附件中示例的源代码。
附件: DirectShow.rar(15.94KB) |