DirectShow编程2--最简单的例子

What can be done with DirectShow and C#

We would like to start by asking why there is no managed wrapper for DirectShow. The DirectShow SDK documentation contains a FAQ with this answer: "There are no current plans to implement a "Managed DirectShow" platform. You can use COM interop to create DirectShow client applications in managed code, but creating filters that depend on the Common Language Runtime (CLR) is not recommended for performance reasons."

Should we buy this answer like it would be "words from the Gospels"? I like the motto "trust but verify". One thing is sure, when we create a GraphBuilder object and run a stream through it, we end up creating a lot of threads and mixing native COM and managed code might not be an ideal mix for people who don‘t want to work more than what they have to get the job done.

So, we‘re not going to write filters in C#. But DirectShow client applications are an interesting possibility. The SDK already contains samples written in VB and there is no reason why we couldn‘t write similar applications in C#. So how do we go about it. There are a few samples at www.codeproject.com that use C# and DirectShow.

The easiest way to write a DirectShow client application is simply to wrap the library "quartz.dll" (with the tool tlbimp from the .Net SDK or by adding a reference to in a VS project). That‘s the easiest way but the methods we‘d like might not be exposed this way. So we have a couple of alternatives. There a library called "FSFWrap.dll" that adds some of the missing APIs or we can look at DShowNet (available on the CodeProject web site).

上面这段话的意思就是,DirectShow并不支持托管的代码,所以我们也不用托管的代码来实现filter,但是我们可以使用相应的DLL来写DirectShow的客户端程序。先来看一个C++的版本,首先编程环境要进行配置,前面的博客已经介绍过了。

Playing a file using DirectShow in C++ is illustrated in the SDK documentation as:

#include <dshow.h>
void main(void)
{
    IGraphBuilder *pGraph = NULL;
    IMediaControl *pControl = NULL;
    IMediaEvent   *pEvent = NULL;

    // Initialize the COM library.
    HRESULT hr = CoInitialize(NULL);
    if (FAILED(hr))
    {
        printf("ERROR - Could not initialize COM library");
        return;
    }

    // Create the filter graph manager and query for interfaces.
    hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
                        IID_IGraphBuilder, (void **)&pGraph);
    if (FAILED(hr))
    {
        printf("ERROR - Could not create the Filter Graph Manager.");
        return;
    }

    hr = pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl);
    hr = pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent);

    // Build the graph. IMPORTANT: Change this string to a file on your system.
    hr = pGraph->RenderFile(L"C:\\Example.avi", NULL);
    if (SUCCEEDED(hr))
    {
        // Run the graph.
        hr = pControl->Run();
        if (SUCCEEDED(hr))
        {
            // Wait for completion.
            long evCode;
            pEvent->WaitForCompletion(INFINITE, &evCode);

            // Note: Do not use INFINITE in a real application, because it
            // can block indefinitely.
        }
    }
    pControl->Release();
    pEvent->Release();
    pGraph->Release();
    CoUninitialize();
}

Here‘s is the equivalent code in C# using interop and quartz.dll:

using System;
using QuartzTypeLib;

class PlayFile
{
	public static void Main( string [] args )
	{
		FilgraphManagerClass graphClass = null;
		  try
		  {
				graphClass = new FilgraphManagerClass();
				graphClass.RenderFile( args[0] );
				graphClass.Run();
				int evCode;
				graphClass.WaitForCompletion( -1, out evCode );
		  }
		  catch( Exception ) {}
		  finally
		  {
			  graphClass = null;
		  }
  }
}

  利用前面说的csc编译器的使用,就可以播放args[0]参数代表的视频文件了。http://www.cnblogs.com/stemon/p/4562581.html

编译的命令:

csc /debug /t:exe /r:interop.quartztypelib.dll test.cs

  这样就能生成对应的exe文件,然后在DOS下运行这个test.exe然后紧跟着视频文件的路径作为参数,就OK了。

There is also a window version of this program where this code is called from a button on a form (the code can be found in the following). We passed the file name to play on the command line instead of hardcoding the name in the source as the example from the SDK. Also the first argument to WaitForCompletion is -1 because INFINITE is defined as 0xfffffff.

The interop version uses the FilgraphManagerClass to do all the work.

.Net Master (at CodeProject) decided that the COM interfaces for DirectShow are sufficiantly simple to write wrappers for them using the IDL provided with the SDK. The advantage of this approach is that you have more control on which members of the interfaces that you can access. The disadvantages are the code can be rather ugly and you have to think in term of native COM and managed code at the same time. Here is a C# version using DShowNet from .Net Master at CodeProject:

using System;
using System.Runtime.InteropServices;

using DShowNET;

class PlayFile {
  public static void Main( string [] args ) {
    IGraphBuilder graphBuilder = null;
    IMediaControl mediaCtrl = null;
    IMediaEvent mediaEvt = null;

    Type comtype = null;
    object comobj = null;

    try {
    comtype = Type.GetTypeFromCLSID( Clsid.FilterGraph );
    comobj = Activator.CreateInstance( comtype );
    graphBuilder = (IGraphBuilder) comobj; comobj = null;

    mediaCtrl = (IMediaControl)  graphBuilder;
    mediaEvt = (IMediaEvent)  graphBuilder;

    graphBuilder.RenderFile( args[0], null );
    mediaCtrl.Run();
    int evCode;
    mediaEvt.WaitForCompletion( -1, out evCode );
    }
    catch(Exception) {}
    finally {
      if( comobj != null )
	Marshal.ReleaseComObject( comobj );
      comobj = null;
      mediaCtrl = null;
      mediaEvt = null;
      graphBuilder = null;
    }
  }
}

The call to GetTypeFromCLSID of the Type class, the call to CreateInstance of the Activator class and ReleaseComOjbect of the Marshall class are examples of what I meant by having to keep track of native COM and managed code. If the DShowNet implementation give you access to what you need but not the plain Quartz interop. Then DShowNet is the way to go. At the time of writing this tutorial, there was a Beta version of an open source extension to the DShowNet library. The version 1.1 is now released, we‘ll show some uses of this new library in the following tutorials.

We‘ll stop here for our first look at DirectShow and C#.

the form code:

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

using QuartzTypeLib;

namespace CsPlayer
{
  /// <summary>
  /// Summary description for Form1.
  /// </summary>
  public class Form1 : System.Windows.Forms.Form
  {
    private System.Windows.Forms.Button button1;
    /// <summary>
    /// Required designer variable.
    /// </summary>
    private System.ComponentModel.Container components = null;

    public Form1()
    {
      //
      // Required for Windows Form Designer support
      //
      InitializeComponent();

      //
      // TODO: Add any constructor code after InitializeComponent call
      //
    }

    /// <summary>
    /// Clean up any resources being used.
    /// </summary>
    protected override void Dispose( bool disposing )
    {
      if( disposing )
      {
        if (components != null)
        {
          components.Dispose();
        }
      }
      base.Dispose( disposing );
    }

		#region Windows Form Designer generated code
    /// <summary>
    /// Required method for Designer support - do not modify
    /// the contents of this method with the code editor.
    /// </summary>
    private void InitializeComponent()
    {
      this.button1 = new System.Windows.Forms.Button();
      this.SuspendLayout();
      //
      // button1
      //
      this.button1.Location = new System.Drawing.Point(16, 16);
      this.button1.Name = "button1";
      this.button1.Size = new System.Drawing.Size(88, 32);
      this.button1.TabIndex = 0;
      this.button1.Text = "Play";
      this.button1.Click += new System.EventHandler(this.button1_Click);
      //
      // Form1
      //
      this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
      this.ClientSize = new System.Drawing.Size(216, 86);
      this.Controls.AddRange(new System.Windows.Forms.Control[] {
                                                                  this.button1});
      this.Name = "Form1";
      this.Text = "Form1";
      this.ResumeLayout(false);

    }
		#endregion

    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
      Application.Run(new Form1());
    }

    private void button1_Click(object sender, System.EventArgs e)
    {
      OpenFileDialog ofd = new OpenFileDialog();
      if( ofd.ShowDialog() == DialogResult.OK )
      {

        FilgraphManagerClass graphClass = null;
        try
        {
          graphClass = new FilgraphManagerClass();
          graphClass.RenderFile( ofd.FileName );
          graphClass.Run();
          int evCode;
          graphClass.WaitForCompletion( -1, out evCode );
        }
        catch( Exception ) {}
        finally
        {
          graphClass = null;
        }
      }
    }
  }
}

  

时间: 2024-10-09 22:55:07

DirectShow编程2--最简单的例子的相关文章

Java 多线程编程两个简单的例子

/** * @author gao */ package gao.org; public class RunnableDemo implements Runnable{ @Override public void run() { // TODO Auto-generated method stub for(int i=0;i<10;i++){ System.out.println("新线程输出:"+i); } } public static void main(String []

Java编程思想-泛型-简单泛型例子

基本类型无法做为类型参数 代码如下: /** * */ package test.thinkinjava.Generics; import java.util.ArrayList; import java.util.List; /** * @author Luo * */ public class Abc<T> { private List<T> list = new ArrayList<T>(); private T element; @Override public

[转载]通达信插件选股(基于通达信插件编程规范的简单分析)

[转载]通达信插件选股(基于通达信插件编程规范的简单分析) 原文地址:通达信插件选股(基于通达信插件编程规范的简单分析)作者:哈尔滨猫猫 首先声明,鄙人是编程人员,不是股民.对选股概念了解甚少.本文仅作编程人员学习借鉴之用.不对选股理论进行探讨和解释. 以前有客户找我做过通达信插件选股的小任务,当时第一次接触面向接口(此类“接口”)编程,也是第一次接触到股票里相关的概念.最近由于接手一个任务,与上次开发相类似,故旧事重提,仔细研究一番.将个人学习研究所得知识与大家分享.在网上搜相关资料,可用的.

Android中关于JNI 的学习(零)简单的例子,简单地入门

Android中JNI的作用,就是让Java能够去调用由C/C++实现的代码,为了实现这个功能,需要用到Anrdoid提供的NDK工具包,在这里不讲如何配置了,好麻烦,配置了好久... 本质上,Java去调用C/C++的代码其实就是去调用C/C++提供的方法,所以,第一步,我们要创建一个类,并且定义一个Native方法,如下: JniTest类: public class JniTest { public native String getTestString(); } 可以看到,在这个方法的前

Android中关于JNI 的学习(四)简单的例子,温故而知新

在第零篇文章简单地介绍了JNI编程的模式之后,后面两三篇文章,我们又针对JNI中的一些概念做了一些简单的介绍,也不知道我到底说的清楚没有,但相信很多童鞋跟我一样,在刚开始学习一个东西的时候,入门最好的方式就是一个现成的例子来参考,慢慢研究,再学习概念,再回过来研究代码,加深印象,从而开始慢慢掌握. 今天我们就再来做一个小Demo,这个例子会比前面稍微复杂一点,但是如果阅读过前面几篇文章的话,理解起来也还是很简单的.很多东西就是这样,未知的时候很可怕,理解了就很简单了. 1)我们首先定义一个Jav

【Python】一个简单的例子

问题描述: Python基础篇 参考资料: (1)http://www.cnblogs.com/octobershiner/archive/2012/12/04/2801670.html (2)http://www.cnblogs.com/itech/archive/2010/06/20/1760345.html 例子: 求解Fibonacci glb_var.py gl_count=1 path.py # coding:utf-8 ''' Created on 2014-4-28 @autho

Learn Prolog Now 翻译 - 第一章 - 事实,规则和查询 - 第一节, 一些简单的例子

 该系列文章是网上的Prolog学习资料:www.learnprolognow.org的中文翻译.希望能够通过翻译此学习资料,达到两个目的:第一.系统学习prolog的知识:第二.提升英文文章理解 和翻译能力. 内容摘要: 给出一些Prolog编程的简单例子: Prolog的基本结构:事实,规则和查询: 环境说明: 本系列文章使用的Prolog运行环境是:SWI-Prolog,官网地址是:http://www.swi-prolog.org. Prolog中只有三种基础结构:事实(facts),规

用最简单的例子理解对象为Null模式(Null Object Pattern)

所谓的"对象为Null模式",就是要求开发者考虑对象为Null的情况,并设计出在这种情况下的应对方法. 拿"用最简单的例子理解策略模式(Strategy Pattern) "中的例子来说,在我们的客户端程序中只考虑了用户输入1,2,3的情况,如果用户输入其它数字,比如4,就没有一个对应的IBall接口实现类实例产生,于是会报如下的错: 为了应对这种情况,我们专门设计一个类,当用户输入1,2,3以上的数字,就产生该类的实例.该类同样实现IBall接口. public

gedit变身为编程利器的简单配置

本文由fcbruce个人原创整理,转载请注明出处:http://blog.csdn.net/u012965890/article/details/38472149.>_< 用了linux有半年多了(ubuntu->debian),之前敲代码都是通过IDE来编译运行,一直有转Vim的想法,可是那玩意太高端,暂时玩不过来.前两天发现gedit加上各种插件简直就是神器,这两天一直在抽空配置,试用了下,感觉很爽,哈哈哈哈哈哈哈,下面来分享下我的心得.>_< 操作系统:Debian 7

C#调用存储过程简单完整例子

CREATE PROC P_TEST@Name VARCHAR(20),@Rowcount INT OUTPUTASBEGIN SELECT * FROM T_Customer WHERE [email protected] SET  @[email protected]@ROWCOUNTENDGO------------------------------------------------------------------------------------------存储过程调用如下:-