很久没动directshow了,现在一直用c#写程序,突然看到directshow在.net下也有library,于是想试试在.net下的directshow。这个播放器是参照directshownet library中的例子改的,自己加了一些控制方面的。
先来看看效果图:
先说一下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 automaticallyhr = this.graphBuilder.RenderFile(filename, null);DsError.ThrowExceptionForHR(hr);// QueryInterface for DirectShow interfacesthis.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 filesthis.videoWindow = this.graphBuilder as IVideoWindow;this.basicVideo = this.graphBuilder as IBasicVideo;// Query for audio interfaces, which may not be relevant for video-only filesthis.basicAudio = this.graphBuilder as IBasicAudio;hr = this.mediaEventEx.SetNotifyWindow(this.Handle, WMGraphNotify, IntPtr.Zero);DsError.ThrowExceptionForHR(hr);// Setup the video windowhr = 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 filehr = 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 sizehr = this.basicVideo.GetVideoSize(out lWidth, out lHeight);if (hr == DsResults.E_NoInterface)return 0;// Account for requests of normal, half, or double sizelWidth = 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 playbackif (this.mediaControl != null)hr = this.mediaControl.Stop();// Free DirectShow interfacesCloseInterfaces();button1.Text = "播放";}private void CloseInterfaces(){int hr = 0;try{lock (this){// Relinquish ownership (IMPORTANT!) after hiding video windowhr = 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 interfacesif (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。
from:https://wuyuans.com/2012/09/simple-media-player-using-csharp