在.NET中使用DirectShow

下载源程序:【北方网通】  【电信或网通】

【下载说明】
1、单击上面这个地址,打开下载页面。
2、点普通下载--等待30秒--点“下载”按钮--保存


摘要

这个实验性的代码展示了怎么在C#中使用DirectShow技术。它包含一个简单的媒体播放器、DVD播放器、抓取视频画面至硬盘和简单的截屏工具。

备注,这篇文章不会节省你详细阅读DirectShowSDK文档的时间。在这里,我不会解释什么是DirectShow,仅仅是使用了.NET的互操作技术。

DirectShow

DirectShow是一个微软Win32 API的标准,是为了能够在你的程序中使用兼容的视频或音频设备而开发的。DirectShowxpwindows 98/me/2000上都可以使用,目前的DirectX版本是8.1b。请安装最新的版本,这篇文章的代码仅适用于8.1版本。

·                                下载DirectX

再次强调下,我不会描述任何DirectShow接口,通过安装C++版本的SDK、阅读SDK文档和理解SDK实例,你会了解到它们。

·                                MSDN上的DirectX SDK

·                                MSDN上的DirectShow文档

DirectShow是作为COM组件和接口来使用的,它们包括两个分类:

·                                DirectShow自定义接口 主要是为C++编程者

·                                DirectShow VB组件 VB6设计,提供一个类库

在.NET里面,你也可以使用DirectShow的VB6组件。

.NET互操作技术

.NET里面,使用VB6组件是很方便的。况且没有直接的方法去使用自定义DirectShow接口。我们需要使用以下几种互操作方法:

·                                Use 'Managed Extensions for C++', as done e.g.by DirectX.NET

·                                使用“C++的托管扩展”,比如DirectX.NET

·                                Rewrite all the interfaces from IDL to e.g. C#!

·                                IDL重新写所有的接口,比如使用C#写。

I chose the second strategyfor this reasons :

由于这些原因,我选择了第二条策略:

·                                仅用一种语言,比如C#

·                                大多数的DirectShow接口并不复杂

·                                简单的播放、抓取等DirectShow方法对时间要求并不苛刻

·                                我们可以自由的使用接口,不需要扩展类

当然,也有一些缺陷:

·                                重写接口需要大量的初始化工作

·                                为了正确的使用,必须理解互操作技术

·                                不是很像.NET的面向对象编程

一个典型的用C#重写一个IDL的接口的代码是这样的:

// ======== IDL of ICaptureGraphBuilder2 (AXExtend.idl) ======
[
    object,
    uuid(93E5A4E0-2D50-11d2-ABFA-00A0C9C6E38D),
    pointer_default(unique)
]
interface ICaptureGraphBuilder2 : IUnknown {
 
    // Use this filtergraph
    HRESULT SetFiltergraph( [in] IGraphBuilder *pfg );
 
    // what filtergraph are you using?
    // *ppfg->Release() when you're done with it
    HRESULT GetFiltergraph( [out] IGraphBuilder **ppfg);
    ....

省略的代码中使用互操作属性,在C#中是这样的;

// ======== C# version of ICaptureGraphBuilder2 (DsExtend.cs) ======
 
   [ComVisible(true), ComImport,
    Guid("93E5A4E0-2D50-11d2-ABFA-00A0C9C6E38D"),
    InterfaceType( ComInterfaceType.InterfaceIsIUnknown )]
public interface ICaptureGraphBuilder2
{
        [PreserveSig]
   int SetFiltergraph( [In] IGraphBuilder pfg );
 
        [PreserveSig]
   int GetFiltergraph( [Out] out IGraphBuilder ppfg );
   ....

一旦你有了这些接口的C#定义,你就可以像在C++中调用DirectShow一样调用它们。

// ======== C++ code to create the COM instance of Filter Graph ========
 
    JIF(CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, 
                         IID_IGraphBuilder, (void **)&pGB));
 
    // Have the graph builder construct its the 
    // appropriate graph automatically
    JIF(pGB->RenderFile(wFile, NULL));
 
    // QueryInterface for DirectShow interfaces
    JIF(pGB->QueryInterface(IID_IMediaControl, (void **)&pMC));
    ....

我们使用Activator.CreateInstance来替换CoCreateInstanceQueryInterfaceC#中仅仅是一个简单的cast操作。

// ======== C# code to create the COM instance of Filter Graph ========
 
    Type comtype = null;
    object comobj = null;
    try {
        comtype = Type.GetTypeFromCLSID( Clsid.FilterGraph );
        if( comtype == null )
            throw new NotSupportedException( 
                "DirectX (8.1 or higher) not installed?" );
        comobj = Activator.CreateInstance( comtype );
        graphBuilder = (IGraphBuilder) comobj; comobj = null;
        
        int hr = graphBuilder.RenderFile( clipFile, null );
        if( hr < 0 )
            Marshal.ThrowExceptionForHR( hr );
 
        mediaCtrl    = (IMediaControl)  graphBuilder;
     ....

工程结构

下载的C#源代码中包含了所有的文件:

\DirectShow\
     \DShowNET\              // the DirectShow interface definitions :
              \DsBugWO.cs      // workaround for a bug 
              \DsControl.cs    // ported from control.odl 
              \DsCore.cs       // ported from axcore.idl 
              \DsDevice.cs     // device enumerator, helper functions 
              \DsDVD.cs        // DVD interfaces from dvdif.idl 
              \DsExtend.cs     // ported from axextend.idl 
              \DsUtils.cs      // utility classes, SDK Common sources 
              \DsUuids.cs      // UUIDs and CLSIDs from uuids.h 
              \QEdit.cs        // grabber interfaces from qedit.idl 
 
     \CaptureNET\            // video stream capture sample 
     \DVDPlayerNET\          // DVD player sample 
     \PlayWndNET\            // simple media file playback 
     \SampleGrabberNET\      // picture grabber 

Playback

下载的文件中第一个例子就是PlayWndNET。它可以播放一个视频或音频格式的文件,像AVIMPGWAVMID等等。


DVD播放器

下一个例子是DVDPlayerNET,你必须安装一个第三方的DVD编码器,比如WinDVD或者PowerDVD。然后,这个C#例子使用DirectShowDVD接口来播放电影。它也支持导航菜单。


抓图

最复杂的一个例子就是SampleGrabberNET了。它可以显示一个实时的视频流,比如DV摄像头、WEB摄像头或者TV卡。通过点击工具栏上面的“Grab”按钮,你可以抓取一个静态图片,保存成24位的RGB位图。

这个实例也支持TV卡的IAMTVTuner接口,因此,你可以选择电视的频道。


捕捉

最后一个例子是CaptureNET,它可以被用来将一个实时的视频流保存到硬盘上。备注,一旦启动之后,有较少的参数可以调整,并且立即开始捕捉,并写入到一个AVI文件中。


受限的地方

·                                实验阶段!在量产代码中,请不要使用。

·                                例子仅仅提供部分非常基础的功能。

·                                我在xp上做了很多的测试,但是很少在me上测试。

·                                仅仅在少数的设备上测试过少数的媒体格式。我使用了Logitech QuickCamSony DV camcorderHauppauge WinTV PCIWinDVD.

·                                Get the latest driver(WDM) from manufacturer.

·                                从制造商那里获取最新的驱动。

·                                如果你在对话框上选择了不支持的设置的话,某些设备可能会不能正常使用。

·                                这些代码不会帮助你饿任何DirectShowWDM配置问题。

·                                使用大于128MB的内存,大于400MHz的处理器,快而大的硬盘

【更多阅读】
  1. [译]用C#检测你的打印机是否连接
  2. [译]在C#中使用J#运行时来压缩与解压缩
  3. [原]PjConvertImageFormat:用FreeImage.NET写的一个35种图像格式转换程序
  4. [原]Hotkey.cs:为应用程序添加热键
  5. [译]使用WM_COPYDATA消息在C++和C#程序之间互传数据
  6. [原]QQHelper:QQ大家来找茬 辅助工具 外挂
  7. [原]WMICodeCreator:C#产生WMI代码的工具
  8. [原]Baidu:C#利用百度来搜索网页、图片、视频等等
  9. [原]ManageStartUpApps:C#操作注册表来读取和修改开机启动项
  10. [译]在C# .NET2.0实现单实例应用程序

你可能感兴趣的:(C#)