用c#写的directshow简易视频播放器
很久没动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 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。
from:https://wuyuans.com/2012/09/simple-media-player-using-csharp