博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

QuartzTypeLib.dll 文件

Posted on 2012-08-07 16:40  hyruur  阅读(632)  评论(0编辑  收藏  举报

要使 C# 代码引用 COM 对象和接口,需要在 C# 内部版本中包含 COM 接口的 .NET 框架定义。完成此操作的最简单方法是使用 TlbImp.exe(类型库导入程序),它是一个包括在 .NET 框架 SDK 中的命令行工具。TlbImp 将 COM 类型库转换为 .NET 框架元数据,从而有效地创建一个可以从任何托管语言调用的托管包装。用 TlbImp 创建的 .NET 框架元数据可以通过 /R 编译器选项包括在 C# 内部版本中。如果使用 Visual Studio 开发环境,则只需添加对 COM 类型库的引用,将为您自动完成此转换。 
例如,我们要播放当前目录下的demo.avi文件,需要用到包含在位于 Windows 系统目录中的 Quartz.dll 中的媒体播放机。(c:/winnt/system32/quartz.dll)。可在命令行中运行TlbImp文件(D:/ Microsoft Visual Studio .NET/FrameworkSDK/Bin/Tlbimp.exe) 
tlbimp c:/winnt/system32/quartz.dll /out:QuartzTypeLib.dll 
请注意,得到的 DLL 需要命名为 QuartzTypeLib,以便 .NET 框架可以在运行时正确加载包含类型。 
生成程序时使用 C# 编译器选项 /R 以包含 QuartzTypeLib.dll 文件;如果使用 Visual Studio 开发环境,直接添加引用即可(using QuartzTypeLib)。 
然后就可以使用此程序显示影片了。 
具体编写代码时,用到了RenderFile 和 Run 方法。例: 
private void menuItemOpen_Click(object sender, System.EventArgs e) 

FilgraphManager m_FilGraphManager = null; 
IBasicAudio m_BasicAudio = null; 
IVideoWindow m_VideoWindow = null; 
IMediaEvent m_MediaEvent = null; 
IMediaEventEx m_MediaEventEx = null; 
IMediaPosition m_MediaPosition = null; 
IMediaControl m_MediaControl = null; 
OpenFileDialog OpenDialog = new OpenFileDialog(); 
OpenDialog.Filter = "Media Files|*.mpg;*.avi;*.wma;*.mov;*.wav;*.mp2;*.mp3|All Files|*.*";                //本例用对话框读入要显示的影片文件名 
if (DialogResult.OK == OpenDialog.ShowDialog()) 

m_FilGraphManager = new FilgraphManager();               
m_FilGraphManager.RenderFile(OpenDialog.FileName); 
m_BasicAudio = m_FilGraphManager as IBasicAudio ; 
try 

m_VideoWindow = m_FilGraphManager as IVideoWindow; 
m_VideoWindow.Owner = (int) panel1.Handle; 
m_VideoWindow.WindowStyle = WS_CHILD | WS_CLIPCHILDREN; 
//此设置可以不显示播放器的title,使播放器像嵌在窗体中。 
//可设置 private const int WS_CHILD = 0x40000000; 
//      private const int WS_CLIPCHILDREN = 0x2000000; 
m_VideoWindow.SetWindowPosition(panel1.ClientRectangle.Left, 
panel1.ClientRectangle.Top, 
panel1.ClientRectangle.Width, 
panel1.ClientRectangle.Height); 
// 在panel1中显示,要求影片可随panel1大小而变化。 

catch (Exception) 

m_VideoWindow = null; 
}

m_MediaEvent = m_FilGraphManager as IMediaEvent; 
m_MediaEventEx = m_FilGraphManager as IMediaEventEx; 
m_MediaEventEx.SetNotifyWindow((int) this.Handle,WM_GRAPHNOTIFY, 0); 
m_MediaPosition = m_FilGraphManager as IMediaPosition; 
m_MediaControl = m_FilGraphManager as IMediaControl; 
this.Text = "DirectShow - [" + OpenDialog.FileName + "]"; 
m_MediaControl.Run(); 

}

也可以加入pause,stop命令来控制影片的播放。 
m_MediaControl.Pause() 
m_MediaControl.Stop()

摘要:了解如何在 Microsoft Visual C# .NET 中使用 DirectShow 控件,如何开发一个媒体播放器。按照本文介绍的操作步骤,您可以创建一个简单 Visual C# 应用程序,用来播放数字音频和视频。    

简介 

  Microsoft Visual C# 是世界上最流行的编程语言,利用 Visual C# 的最新版本 Visual C# .NET,您能够快速、有效地开发基于 Windows 窗体的应用程序,还可以为嵌入了 Microsoft Windows Media? Player 9 Series ActiveX 控件的应用程序添加新鲜、有趣而又非常实用的功能。 

  DirectShow 控件是一个标准的 ActiveX 控件,提供了大量的功能。DirectShow控件提供的功能包括: 

  · 数字媒体文件和流媒体的高级播放功能。      

  · 使用播放列表的功能。 
  · 播放 DVD 和 CD 的功能。 
  · 访问 Windows Media Player 中的 Media Library(媒体库)。 
  · 处理元数据的功能。 
  · 支持字幕。 
  · 支持多种语言的音频。 
  · 控制网络连通性和访问相关统计信息的功能。 

  下面我们来看看构造这个媒体播放器要达到什么样的目标,确定了目标也就确定了代码量和程序的复杂程度。本文的媒体播放器要达到如下目标: 

  · 是一个菜单驱动的简单AWT应用。 
  · 包含一个“文件”菜单,文件菜单包含三个菜单项: 
  · “打开”,用来打开媒体文件。 
  · “循环”,是播放一次(默认),还是重复播放。 
  · “退出”,退出程序。 
  · 可以在多种平台上运行。 
  · 核心功能通过JMF(Java Media Framework)API实现。 

  按照本文介绍的步骤,您将创建一个基于 Windows 窗体的基本应用程序,并在其中嵌入 Player 控件。您创建的示例应用程序具有如下特点: 

  · 创建 DirectShow 控件的一个实例。 
  · 利用 Windows Media Player 主互操作程序集提供组件对象模型 (COM) 互操作性。 
  · 允许用户打开并播放 Windows Media 文件,尤其是文件扩展名为 .wma 或 .wmv 的文件。 
  · 创建供用户播放、暂停和停止数字媒体内容的传输控制按钮。 
  · 显示当前数字媒体文件的标题。 
  · 演示如何使用 Player 对象模型,包括使用属性、方法和事件的示例。 

  我的这个程序仅仅只是告诉大家如何用DirectShow 在C#中做一个播放机, 

  在这个程序中我们经要解决的一些小问题: 

  1.如何从你的磁盘上打开媒体文件 

  2.如何让工具条上的按钮起用和禁用 

  3.如何设置状态栏的显示文字 

  4.如何控制时间  

  5.如何使用时间控件的事件 
  
  6.如何用DirectShow来播放媒体文件 

  7.如何确定播放状态等等... 

  下图显示了您将要创建的应用程序,其中正在播放名为“Melow”的数字音频文件,同时呈现了可视化效果。 


图 1 

  · 本文假设您已经具备一定的 Visual C# 和 Visual Studio.NET 集成开发环境知识。 
准备工作 

  在开始创建应用程序之前,您需要安装必要的软件并注册主互操作程序集 (QuartzTypeLib)。 

  这里简单介绍DirectShow 接口: 

  播放视屏和声音文件我们要用到DiectX为我们提供的DirectShow组件.使用这个接口可以让你方便的播放那些共用的影像和声音文件.你要做的仅仅只是安装DirectShow接口和使用它的功能函数和配置正确的接口参数而已. 

  不幸的是.NET并不正式支持DirectX.是的也许你听说DirectX9支持是吗?是的,不过在最终版敲定的那一天还没来,我们都得不到最好的效果.但无论如何我们还是要用的不是吗?要不这篇文章得作废了.是的,也许你用过VB,对了,就是它,我们正是要用到那个. 

  开始项目 

  在安装必要软件并注册 QuartzTypeLib之后,您就可以启动 Visual C#,开始为示例应用程序创建项目。下面我将给大家介绍这一过程的操作步骤。 

  创建项目 

  按以下步骤创建一个空的项目: 

  1. 启动 Visual Studio .NET,然后单击 New Project(新建项目)。 

  2. 在 Visual C# Projects(Visual C# 项目)文件夹中单击 Windows Application(Windows 应用程序),键入新项目的名称(最好为 DirectShow),然后单击 OK(确定)。 

  Visual C# 使用默认的 Windows 窗体“Form1”创建一个新的项目。 

  3. 这个名称并没有特别的意义或用处,所以请在 Properties(属性)窗口中将窗体名称更改为 frmPlayMedia,将窗体文本更改为“媒体播放器”。 

  在项目中添加对 DirectShow的引用 

  按照以下步骤在项目中添加一个对 DirectShow的引用: 

  1. 打开 Visual Studio 工具箱,然后单击 Components(组件)显示该面板。 

  2. 右击面板,然后单击 Customize Toolbox(自定义工具箱),显示对话框。 

  3. 在 COM Components(COM 组件)选项卡上,选中 Interop.QuartzTypeLib.dll。(如果 Interop.QuartzTypeLib.dll 由于某种原因未列出,则单击 Browse [浏览] 并查找名为 QuartzTypeLib.dll的文件。) 

  4. 单击 OK(确定)关闭对话框。 


图 2 

  要在代码中使用 DirectShow,您需要添加一行代码,以引用 DirectShow命名空间。在窗体代码窗口的顶部,将以下代码添加到所有声明语句之前: 

using QuartzTypeLib; 

  using语句必须在所有 Options 语句(本项目中并未使用)之后,并且在所有其他代码之前。添加该语句后。 
开发应用程序 

  创建通过 PIA 与 Framework 连接的 Player 控件实例之后,您可以向窗体中添加所需的其他元素,并编写完成实际操作的代码。 
添加 Windows 窗体控件 

  1. 在 View(视图)菜单中,单击 Designer(设计器),或者单击 Solution Explorer(解决方案资源管理器)中的 View Designer(视图设计器)按钮,切换到窗体设计器。 

  2. 在窗体上增加文件、播放、信息等菜单。 

  3. 在工具箱的 Windows Forms(Windows 窗体)面板中,为您的窗体添加一个工具栏、一个状态栏和图片imageList。 

  4. 在 Properties(属性)窗口中,将工具栏的名称更改为 toolBar1,将在Buttons上增加4个按钮。状态栏的名称更改为 statusBar1,并分别增加三个Panel。 

  5. 在工具箱的面板中,为您的窗体添加一个面版panel1。 

  6. 增加一个定时器timer1。 

  7. 调整控件在窗体中的排列方式,使之符合您的需要而且方便用户使用。下图为 Visual Studio Designer(设计器)中完成后的窗体布局。 


图 3 

  编写代码 

  如何打开你想要媒体文件? 

  第一步是编写在 frmPlayMedia中打开 Windows Media 文件的代码。要自动切换到 Code(代码)视图并编辑打开菜单的 Click 事件处理程序 (menuItem2_Click) 的代码,请双击窗体上的“工具栏”按钮。将以下代码添加到事件处理程序中:

  还记得吗"文件 -> 打开..." 是的几乎每个使用windows的人都会这样操作.如何实现? 

  很简单看看下面的代码: 

OpenFileDialog openFileDialog = new OpenFileDialog(); 
openFileDialog.Filter = "Media Files|*.mpg;*.avi;*.wma;*.mov;*.wav;*.mp2;*.mp3|All Files|*.*"; 
if (DialogResult.OK == openFileDialog.ShowDialog()) 

…. 


  看吧很简单是吗?记得写一个函数把它放进去。当你点击OK按钮的时候,DirectShow接口就会得到你想要播放的文件。下图解释了它是如何工作的。 

  DirectShow为多媒体流回放提供最基本的服务,这些多媒体流可以是本地文件,还可以是服务器传输过来的。特别的,DirectShow可以支持视频回放,支持以不同的文件和流格式压缩视频内容,包括Windows Media、MPEG、AVI和WAV。 

  在DirectShow的核心处,服务是组件的模块化集合,称为过滤器,可以根据媒体类型排列成过滤器图。过滤器可以操作数据流,如读入、分析、解码、格式化或渲染。 

  过滤器以树型进行排列,这棵树称为过滤器树,通过过滤器树管理器(Filter Graph Manager,简称FGM)进行管理。使用FGM应用程序可以通过使用Microsoft Windows Media Player控件间接控制过滤器树,还可以通过调用COM接口方法直接控制。DirectShow过滤器树(参阅图1)由从源到目标渲染器的有向过滤器序列组成,所有这些通过输入和输出过滤器引脚连接。过滤器引脚协商它们将支持哪些媒体类型。FGM控制树过滤器之间的多媒体数据流。因为DirectShow有一个灵活的、可重配置的过滤器树体系结构,因此DirectShow可以使用同样的软件成分支持多种媒体类型的回放和分流。开发人员还可以通过编写自己的过滤器扩展DirectShow多媒体支持。 

  过滤器 

  过滤器是注册的DirectShow类,它执行许多媒体信息处理任务。这些任务包括: 

   获得源信息(例如,获得媒体流) 
   分析(例如,在流上执行包读入、分离和格式化) 
   转换(例如,解码WMA和MPEG-4音频和视频流) 
   渲染(例如,在适当的时候产生音频PCM或者视频RGB/YUV输出,将数据传给DirectSound和DirectDraw) 

  过滤器使用几种类型的接口,例如引脚、计数器、传送器和时钟接口,来执行它们的任务。过滤器实现和开放了许多接口。FGM可以使用这些接口创建、连接和控制树。过滤器经常实现包含下列方法的IBaseFilter接口: 

   运行、停止和暂停过滤器状态。 
   恢复过滤器和厂商信息。 
   得到和设置参考时钟。 
   恢复过滤器状态信息。 
   枚举过滤器引线。 
   重建过滤器树时定位引脚 

  用户单击“打开”时,这段代码将显示一个对话框,供用户在计算机上浏览并选择要播放的 .wma 或 .wmv 文件。用户选择文件(并单击“确定”)时,代码将 Player 的 URL 属性设置为用户选择的文件。由于 Player 的 autoStart 属性在默认情况下设置为 True,所以 Player 立即打开并播放用户选择的数字媒体文件。 

  接下来,添加播放/暂停按钮的代码。在代码窗口中,在停止、暂停菜单中单击,然后,在方法名称列表中单击 Click。将以下代码添加到 Visual C# 为您创建的Click 事件处理程序中: 

  看看下面的代码是如何实现的: 

CleanUp(); 
m_objFilterGraph = new FilgraphManager(); 
m_objFilterGraph.RenderFile(openFileDialog.FileName); 
m_objBasicAudio = m_objFilterGraph as IBasicAudio; 
try 

 m_objVideoWindow = m_objFilterGraph as IVideoWindow; 
 m_objVideoWindow.Owner = (int) panel1.Handle; 
 m_objVideoWindow.WindowStyle = WS_CHILD | WS_CLIPCHILDREN; 
 m_objVideoWindow.SetWindowPosition(panel1.ClientRectangle.Left, 
 panel1.ClientRectangle.Top, 
 panel1.ClientRectangle.Width, 
 panel1.ClientRectangle.Height); 

catch (Exception ex) 

 m_objVideoWindow = null; 

m_objMediaEvent = m_objFilterGraph as IMediaEvent; 
m_objMediaEventEx = m_objFilterGraph as IMediaEventEx; 
m_objMediaEventEx.SetNotifyWindow((int) this.Handle, WM_GRAPHNOTIFY, 0); 
m_objMediaPosition = m_objFilterGraph as IMediaPosition; 
m_objMediaControl = m_objFilterGraph as IMediaControl; 

// 

如何来播放,暂停,停止? 
简单这些函数看字面也知道. 
// 

m_objMediaControl.Run();//播放 
m_objMediaControl.Pause();//暂停 
m_objMediaControl.Stop();//停止 

// 这段代码非常简单。当用户单击播放/暂停按钮时,代码将检查 Player 的 playState 属性。如果 Player 正在播放数字媒体文件,代码就会暂停文件的播放; 如果 Player 已经暂停或停止,代码就再次启动 Player 播放文件。 
OK,在来看我们是如何控制时间进度的? 
// 

private void timer1_Tick(object sender, System.EventArgs e) 

 if (m_CurrentStatus == MediaStatus.Running) 
 { 
  UpdateStatusBar(); 
 } 


  看见上面那个 UpdateStatusBar();这里是让它没100ms更新一次状态栏. 

  代码如下: 

private void UpdateStatusBar() 

 switch (m_CurrentStatus) 
 { 
  case MediaStatus.None : statusBarPanel1.Text = "Stopped"; break; 
  case MediaStatus.Paused : statusBarPanel1.Text = "Paused "; break; 
  case MediaStatus.Running: statusBarPanel1.Text = "Running"; break; 
  case MediaStatus.Stopped: statusBarPanel1.Text = "Stopped"; break; 
 } 
 if (m_objMediaPosition != null) 
 { 
  int s = (int) m_objMediaPosition.Duration; 
  int h = s / 3600; 
  int m = (s - (h * 3600)) / 60; 
  s = s - (h * 3600 + m * 60); 
  statusBarPanel2.Text = String.Format("{0:D2}:{1:D2}:{2:D2}", h, m, s); 
  s = (int) m_objMediaPosition.CurrentPosition; 
  h = s / 3600; 
  m = (s - (h * 3600)) / 60; 
  s = s - (h * 3600 + m * 60); 
  statusBarPanel3.Text = String.Format("{0:D2}:{1:D2}:{2:D2}", h, m, s); 
 } 
 else 
 { 
  statusBarPanel2.Text = "00:00:00"; 
  statusBarPanel3.Text = "00:00:00"; 
 } 


  还有一个问题程序怎么能够知道它播放完了? 

  这会有点麻烦了,想想看有什么办法呢?对了,windows是消息驱动的。那找找看有什么消息。有的就EC_COMPLETE。还记得"WndProc" 它吗?是的,我的老朋友,这次我们必须要改写它来捕获EC_COMPLETE消息。这个消息是DirectShow通知父窗体,播放结束了。 

protected override void WndProc(ref Message m) 

 if (m.Msg == WM_GRAPHNOTIFY) 
 { 
  int lEventCode; 
  int lParam1, lParam2; 
  while (true) 
  { 
   try 
   { 
    m_objMediaEventEx.GetEvent(out lEventCode,out lParam1,out lParam2,0); 
    m_objMediaEventEx.FreeEventParams(lEventCode, lParam1, lParam2); 
    if (lEventCode == EC_COMPLETE) 
    { 
     m_objMediaControl.Stop(); 
     m_objMediaPosition.CurrentPosition = 0; 
     m_CurrentStatus = MediaStatus.Stopped; 
     UpdateStatusBar(); 
     UpdateToolBar(); 
    } 
   } 
   catch (Exception) 
   { 
    break; 
   } 
  } 
 } 
 base.WndProc(ref m); 


  只要播放状态改变,上述代码就会运行。如果 Player 正在播放(用户打开文件时就处于播放状态,因为 autoStart 设置为 True),代码将启用播放/暂停按钮和停止按钮,以便用户执行操作。之后,代码将播放/暂停按钮的文字更改为“暂停”,这样用户就可以使用该按钮暂停播放过程。最后,代码检索当前数字媒体文件的标题,并更新标题标签的文字以显示标题。 

  如果 Player 被暂停(用户单击了播放/暂停按钮),代码会将播放/暂停按钮的文字更改为“播放”,以提示用户使用该按钮可以恢复播放。 

  如果 Player 被停止(用户单击了停止按钮),代码将禁用停止按钮(因 Player 已经停止工作)并将播放/暂停按钮的文字恢复为默认值“播放”。 

  一切都结束了,现在要做的事就是做些来找一部影片来享受一下自己的成果了. 

  编写完示例项目的代码之后,您可以生成并运行解决方案。 

  生成解决方案 

  在 Build(生成)菜单中单击 Build Solution(生成解决方案)。Visual Studio 开始编译并生成项目。如果键入内容全部正确,生成过程将顺利完成,不会出现任何错误。如果生成报告错误,则请检查您的代码并纠正错误。 

  使用示例应用程序 

  要在调试器中运行项目,请按键盘上的 F5 键。如果出现“查看生成的代码”主题中介绍的未处理的异常,则应该停止调试会话,删除或注释掉生成代码中的相应行,然后再按 F5 键。 

  您可以单击“打开”查找 .wma 或 .wmv 文件(究竟选择何种文件,取决于您在“打开”对话框中选择的文件类型)。选择某个文件并单击“确定”之后,“打开”对话框关闭,开始播放数字媒体文件,传输控制按钮的状态也随之改变。这时您就可以利用传输控制按钮来暂停、重新开始或完全停止播放。   

前公司在制作播客系统(Web程序)中,用到从视频截图功能. 

下边是截图CatchImg方法,可从大多数的视频文件中截图成功,大家可测试; 
如果截图不成功,大多是因为视频本身的问题,如编码标准或加了密. 
但从在线录制的视频Flv文件中截图,还未发现截图失败; 

----------------------------------------------------------------------------------------------------------------------------

/// <summary> 
/// @从视频文件截图,生成在视频文件所在文件夹 
/// 在Web.Config 中需要两个前置配置项: 
/// 1.ffmpeg.exe文件的路径 
/// <add key="ffmpeg" value="E:/ffmpeg/ffmpeg.exe" /> 
/// 2.截图的尺寸大小 
/// <add key="CatchFlvImgSize" value="240x180" /> 
/// 3.视频处理程序ffmpeg.exe 
/// </summary> 
/// <param name="vFileName">视频文件地址,如:/Web/FlvFile/User1/00001.Flv</param> 
/// <returns>成功:返回图片虚拟地址; 失败:返回空字符串</returns> 
public string CatchImg(string vFileName) 

//取得ffmpeg.exe的路径,路径配置在Web.Config中,如:<add key="ffmpeg" value="E:/ffmpeg/ffmpeg.exe" /> 
string ffmpeg=System.Configuration.ConfigurationSettings.AppSettings["ffmpeg"]; 

if ( (!System.IO.File.Exists(ffmpeg)) || (!System.IO.File.Exists(vFileName)) ) 

return ""; 


//获得图片相对路径/最后存储到数据库的路径,如:/Web/FlvFile/User1/00001.jpg 
string flv_img = System.IO.Path.ChangeExtension(vFileName,".jpg") ; 

//图片绝对路径,如:D:/Video/Web/FlvFile/User1/0001.jpg 
string flv_img_p = HttpContext.Current.Server.MapPath(flv_img); 

//截图的尺寸大小,配置在Web.Config中,如:<add key="CatchFlvImgSize" value="240x180" /> 
string FlvImgSize=System.Configuration.ConfigurationSettings.AppSettings["CatchFlvImgSize"]; 

System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo(ffmpeg); 
startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden; 

//此处组合成ffmpeg.exe文件需要的参数即可,此处命令在ffmpeg 0.4.9调试通过 
startInfo.Arguments = " -i " + vFileName + " -y -f image2 -t 0.001 -s " + FlvImgSize + " " + flv_img_p ; 

try 

System.Diagnostics.Process.Start(startInfo); 

catch 

return ""; 


///注意:图片截取成功后,数据由内存缓存写到磁盘需要时间较长,大概在3,4秒甚至更长; 
///这儿需要延时后再检测,我服务器延时8秒,即如果超过8秒图片仍不存在,认为截图失败; 
///此处略去延时代码.如有那位知道如何捕捉ffmpeg.exe截图失败消息,请告知,先谢过! 
if ( System.IO.File.Exists(flv_img_p)) 

return flv_img; 


return ""; 


待解决问题: 
就是我无法从ffmpeg.exe捕捉截图失败消息~ 
不知能看到这篇日志的行家可否有办法取得,我目前只能通过检测图片是否生成来判断成功与否,但时间较慢,因为这个检测程序就让用户要多等大概4,5秒时间.

 

转自:http://blog.csdn.net/yandong19861103/article/details/3960003