WUYUANS
Just for Sharing

用c#写的directshow简易视频播放器

2012年09月10日 分类:学习笔记C#

很久没动directshow了,现在一直用c#写程序,突然看到directshow在.net下也有library,于是想试试在.net下的directshow。这个播放器是参照directshownet library中的例子改的,自己加了一些控制方面的。
先来看看效果图: directshow

先说一下directshownet,这是一个用c#写的directshow类库,是一个开源项目,sourceforge主页:http://directshownet.sourceforge.net/ 不过这个项目关注的人不是很多,代码也很久没更新了,毕竟使用directshow的大都是c++项目,实现起来也是c++更高效。在.net里也可以调用VB的directshow类库来实现,不过我觉得这样太麻烦了,还是用directshownet这个现成的类库来的快。

首先从上面的sourceforge主页里下载directshownet library,现在最新的版本是2.1(还是2010的,汗),加入c#项目的引用中,然后using DirectShowLib,就可以使用其中的类了。

上完整代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using DirectShowLib;
using System.Threading;
using System.Runtime.InteropServices;

namespace DirectShow
{
    public partial class Form1 : Form
    {
        private const int WMGraphNotify = 0x0400 + 13;
        private Thread t = null;
        private IGraphBuilder graphBuilder = null;
        private IMediaControl mediaControl = null;
        private IMediaEventEx mediaEventEx = null;
        private IVideoWindow videoWindow = null;
        private IBasicAudio basicAudio = null;
        private IBasicVideo basicVideo = null;
        private IMediaSeeking mediaSeeking = null;
        private IMediaPosition mediaPosition = null;
        private IVideoFrameStep frameStep = null;

        public Form1()
        {
            InitializeComponent();
            trackBar2.SetRange(-1000, 0);
        }

        private void updateTimeBar(double current)
        {

        }

        private void updateTimeBarThread()
        {
            double time;
            int volu;
            while (true)
            {
                mediaPosition.get_CurrentPosition(out time);
                Console.WriteLine(time);
                basicAudio.get_Volume(out volu);
                Console.WriteLine(volu);
                this.BeginInvoke(new MethodInvoker(() =>
                {
                    trackBar1.Value = (int)time;
                }));
                Thread.Sleep(1000);
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            int hr = 0;
            if (this.graphBuilder == null)
            {
                String filename = textBox1.Text;

                this.graphBuilder = (IGraphBuilder)new FilterGraph();

                // Have the graph builder construct its the appropriate graph automatically
                hr = this.graphBuilder.RenderFile(filename, null);
                DsError.ThrowExceptionForHR(hr);

                // QueryInterface for DirectShow interfaces
                this.mediaControl = (IMediaControl)this.graphBuilder;
                this.mediaEventEx = (IMediaEventEx)this.graphBuilder;
                this.mediaSeeking = (IMediaSeeking)this.graphBuilder;
                this.mediaPosition = (IMediaPosition)this.graphBuilder;

                // Query for video interfaces, which may not be relevant for audio files
                this.videoWindow = this.graphBuilder as IVideoWindow;
                this.basicVideo = this.graphBuilder as IBasicVideo;

                // Query for audio interfaces, which may not be relevant for video-only files
                this.basicAudio = this.graphBuilder as IBasicAudio;

                hr = this.mediaEventEx.SetNotifyWindow(this.Handle, WMGraphNotify, IntPtr.Zero);
                DsError.ThrowExceptionForHR(hr);
                // Setup the video window
                hr = this.videoWindow.put_Owner(this.Handle);
                DsError.ThrowExceptionForHR(hr);

                hr = this.videoWindow.put_WindowStyle(WindowStyle.Child |
                    WindowStyle.ClipSiblings | WindowStyle.ClipChildren);
                DsError.ThrowExceptionForHR(hr);

                this.Focus();

                hr = InitVideoWindow(1, 1);
                DsError.ThrowExceptionForHR(hr);
                double time;
                mediaPosition.get_Duration(out time);
                trackBar1.SetRange(0, (int)time);
                t = new Thread(new ThreadStart(updateTimeBarThread));
                t.IsBackground = true;
                t.Start();
            }
            if (button1.Text.Equals("播放"))
            {
                // Run the graph to play the media file
                hr = this.mediaControl.Run();
                DsError.ThrowExceptionForHR(hr);
                button1.Text = "暂停";

            }
            else
            {
                hr = this.mediaControl.Pause();
                DsError.ThrowExceptionForHR(hr);
                button1.Text = "播放";
            }

        }

        private int InitVideoWindow(int nMultiplier, int nDivider)
        {
            int hr = 0;
            int lHeight, lWidth;

            if (this.basicVideo == null)
                return 0;

            // Read the default video size
            hr = this.basicVideo.GetVideoSize(out lWidth, out lHeight);
            if (hr == DsResults.E_NoInterface)
                return 0;

            // Account for requests of normal, half, or double size
            lWidth = lWidth * nMultiplier / nDivider;
            lHeight = lHeight * nMultiplier / nDivider;

            this.ClientSize = new Size(lWidth, lHeight + 75);
            Application.DoEvents();

            hr = this.videoWindow.SetWindowPosition(0, 30, lWidth, lHeight);

            return hr;
        }

        private void closeVideo()
        {
            int hr = 0;

            // Stop media playback
            if (this.mediaControl != null)
                hr = this.mediaControl.Stop();

            // Free DirectShow interfaces
            CloseInterfaces();
            button1.Text = "播放";
        }

        private void CloseInterfaces()
        {
            int hr = 0;

            try
            {
                lock (this)
                {
                    // Relinquish ownership (IMPORTANT!) after hiding video window

                    hr = this.videoWindow.put_Visible(OABool.False);
                    DsError.ThrowExceptionForHR(hr);
                    hr = this.videoWindow.put_Owner(IntPtr.Zero);
                    DsError.ThrowExceptionForHR(hr);


                    if (this.mediaEventEx != null)
                    {
                        hr = this.mediaEventEx.SetNotifyWindow(IntPtr.Zero, 0, IntPtr.Zero);
                        DsError.ThrowExceptionForHR(hr);
                    }

                    // Release and zero DirectShow interfaces
                    if (this.mediaEventEx != null)
                        this.mediaEventEx = null;
                    if (this.mediaSeeking != null)
                        this.mediaSeeking = null;
                    if (this.mediaPosition != null)
                        this.mediaPosition = null;
                    if (this.mediaControl != null)
                        this.mediaControl = null;
                    if (this.basicAudio != null)
                        this.basicAudio = null;
                    if (this.basicVideo != null)
                        this.basicVideo = null;
                    if (this.videoWindow != null)
                        this.videoWindow = null;
                    if (this.frameStep != null)
                        this.frameStep = null;
                    if (this.graphBuilder != null)
                        Marshal.ReleaseComObject(this.graphBuilder); this.graphBuilder = null;

                    GC.Collect();
                }
            }
            catch
            {
            }
        }

        private void buttonStop_Click(object sender, EventArgs e)
        {
            closeVideo();
            t.Abort();
        }

        private void trackBar1_ValueChanged(object sender, EventArgs e)
        {

        }

        private void trackBar1_Scroll(object sender, EventArgs e)
        {
            if (mediaPosition != null)
            {
                mediaPosition.put_CurrentPosition(trackBar1.Value);
            }

        }

        private void trackBar2_Scroll(object sender, EventArgs e)
        {
            if (basicAudio != null)
            {
                basicAudio.put_Volume(trackBar2.Value);
            }
        }
    }
}

开头的成员变量都是directshow的接口,接触过directshow的一看他们的名字就应该知道他们的作用,我就不多说了。在点击开始播放按键后,接口实例化,然后我开启了一个线程——用于更新进度条。停止键就是开始键的反过程了,销毁接口和线程。
能力有限写的很简单,还有很多用法可以参考他自带的sample,都是很实用的demo。

作者:wuyuan 本文来自Wuyuan's Blog 转载请注明,谢谢! 文章地址: https://www.wuyuans.com/blog/detail/95