一个用C#开发的DirectShow媒体播放器(作者:Daniel Strigl)

diskonline 2008-04-15 11:15:36
演示程序

介绍;
由于我第一次写关于代码介绍方面的文章,请原谅我的英语很差。我只是在学校中和一些工作中接触过英文。
我希望每个人可以理解这篇文章的内容。如果有问题我很愿意解答。如果发现有错,请即使纠正-感谢帮助我学习英文;-)。
好现在开始
这个小程序演示了,用C#开发的一个DirectShow的播放软件可以播放视频和声音。
该程序包含以下控制:MainMenu, ToolBar, StatusBar, Panel, ImageList,和一个 Timer。
这些属性都是在属性栏中填好了,所以我建议你下载该项目,除非你并不是一个初学者。
另一方面,事例程序包含 DirectShow类用来播放视频和声音。

...
程序演示了以下内容:
怎样用OpenFileDialog类来在磁盘上选择一个媒体文件。
怎样激活工具栏桑的按钮。
怎样状态栏的信息。
怎样使用一个Timer控键。
怎样使用时钟控制事件。
这样使用主菜单事件。
怎样使用工具栏事件。
怎样使用窗口事件。
怎样用DirectShow播放媒体。
怎样判定媒体是否已经播放完了。

用户界面
除了3个按钮用来播放,停止视频和声音的播放,同时用菜单来选择要播放的媒体文件,所以在你要播放一个媒体文件之前,你必须打开文件在菜单"File -> Open..."下。如果文件成功加载,就可以通过按 "Play"按钮来播放。在播放过程中,程序在状态栏上显示播放进度。如果播放结束,你可以按"Play"重新播放或选择另一个文件。

菜单的"Info"命令用来显示信息对话框。


关于DirectShow:

我们通常用DirectShow类来播放视频和声音,它是DirectX中的一个开发工具。通过DirectShow可以非常容易的播放视频和声音文件,使用它只需要正确设置参数和方法。
不幸的是.NET和C#在DirectX中不包含官方的支持平台,所以DirectX 9中不包含DirectShow。我们用C#开发DirectX通过使用Visual Basic的类型库API版本是7到8。该文章介绍如何在C#中使用DirectX VB类库。
在开始.NET DirectShow开发之前,我们需要建立一个到DirectShow COM DLL的引用。拷贝"Interop.QuartzTypeLib.dll"到你的项目文件夹中。在 Visual Studio.NET中通过在项目菜单中选择和添加来完成。

按"Browse..." 选择DirectShow COM DLL。
using QuartzTypeLib;

关于代码:
怎样建立DirectShow并选择媒体文件?
在选择了主菜单下的"File -> Open..."后,显示"Open File"对话框然后用户可以选择一个媒体文件。在C#中通过建立一个OpenFileDialog类对象并使用ShowDialog()方法来实现。
OpenFileDialog openFileDialog = new OpenFileDialog();

openFileDialog.Filter = "Media Files|*.mpg;*.avi;*.wma;*.mov;" +
"*.wav;*.mp2;*.mp3|All Files|*.*";

if (DialogResult.OK == openFileDialog.ShowDialog())
{
.
.
.


在以上完成之后,我们开始建立了DirectShow并开始渲染媒体文件。
通过以下几步完成:

建立图象过滤管理(FGM)
建立图象过滤(通过FGM)
播放图象并返回事件
以下代码演示怎样建立图象过滤管理和图象过滤:
CollapseCleanUp();

m_objFilterGraph = new FilgraphManager();
m_objFilterGraph.RenderFile(openFileDialog.FileName);

m_objBasicAudio = m_objFilterGraph as IBasicAudio;

try
{
m_objVideoWindow = m_objFilterGraph as IVideoWindow;
m_objVideoWindow.Owner = (int) panel1.Handle;
m_objVideoWindow.WindowStyle = WS_CHILD | WS_CLIPCHILDREN;
m_objVideoWindow.SetWindowPosition(panel1.ClientRectangle.Left,
panel1.ClientRectangle.Top,
panel1.ClientRectangle.Width,
panel1.ClientRectangle.Height);
}
catch (Exception ex)
{
m_objVideoWindow = null;
}

m_objMediaEvent = m_objFilterGraph as IMediaEvent;

m_objMediaEventEx = m_objFilterGraph as IMediaEventEx;
m_objMediaEventEx.SetNotifyWindow((int) this.Handle, WM_GRAPHNOTIFY, 0);

m_objMediaPosition = m_objFilterGraph as IMediaPosition;

m_objMediaControl = m_objFilterGraph as IMediaControl;


通过CleanUp()我们删除对象,如果对象存在。在我们可以开始渲染一个文件时,我们必须建立FilterGraphManager的几个新对象用新的方法。RenderFile()方法建立了一个图象过滤器用来渲染指定文件。IBasicAudio类用来设定声音的大小和质量。IVideoWindow类用来设定窗口风格,窗口位置。该函数是附加的,如果你播放声音文件,你如果调用该方法。可是播放声音文件不需要IVideoWindow类,所以将m_objVideoWindow设置成NULL。IMediaEvent和IMediaEventEx类用来侦听消息,用来发送DirectShow信息到父窗口。通过IMediaPosition类,可以设置当前的位置。通过IMediaControl类来控制开始,停止视频和声音的播放。
想了解更多关于DirectShow的内容请读一下MSDN的文档。
怎样播放媒体文件?

用IMediaControl类的Run()方法来开始播放一个视频或声音文件。
m_objMediaControl.Run();


怎样暂停播放?

如果你想要暂停播放一个视频或声音文件,使用IMediaControl类的Pause()方法。
m_objMediaControl.Pause();


怎样停止播放?

用IMediaControl类的Stop()方法来停止播放一个视频或声音。
m_objMediaControl.Stop();



怎样得到文件的播放进度和持续时间?

当媒体文件被播放时,我们在状态栏指定当前的播放进度和文件长度。我们读取全部100MS内IMediaPosition类得到的当前进度并将大小显示在状态栏。为了得到文件长度我们读取了IMediaPosition类的Duration成员变量。
private void timer1_Tick(object sender, System.EventArgs e)
{
if (m_CurrentStatus == MediaStatus.Running)
{
UpdateStatusBar();
}
}


时间函数每隔100MS调用UpdateStatusBar()方法,用来显示当前位置和文件进度。
Collapseprivate void UpdateStatusBar()
{
switch (m_CurrentStatus)
{
case MediaStatus.None : statusBarPanel1.Text = "Stopped"; break;
case MediaStatus.Paused : statusBarPanel1.Text = "Paused "; break;
case MediaStatus.Running: statusBarPanel1.Text = "Running"; break;
case MediaStatus.Stopped: statusBarPanel1.Text = "Stopped"; break;
}

if (m_objMediaPosition != null)
{
int s = (int) m_objMediaPosition.Duration;
int h = s / 3600;
int m = (s - (h * 3600)) / 60;
s = s - (h * 3600 + m * 60);

statusBarPanel2.Text = String.Format("{0:D2}:{1:D2}:{2:D2}", h, m, s);

s = (int) m_objMediaPosition.CurrentPosition;
h = s / 3600;
m = (s - (h * 3600)) / 60;
s = s - (h * 3600 + m * 60);

statusBarPanel3.Text = String.Format("{0:D2}:{1:D2}:{2:D2}", h, m, s);
}
else
{
statusBarPanel2.Text = "00:00:00";
statusBarPanel3.Text = "00:00:00";
}
}


当文件播放结束时会怎样?
为了判定,文件是在结束状态,我们重写了WndProc函数,处理EC_COMPLETE消息,当文件结束播放时,将向窗口发送DirectShow消息。
Collapseprotected override void WndProc(ref Message m)
{
if (m.Msg == WM_GRAPHNOTIFY)
{
int lEventCode;
int lParam1, lParam2;

while (true)
{
try
{
m_objMediaEventEx.GetEvent(out lEventCode,
out lParam1,
out lParam2,
0);

m_objMediaEventEx.FreeEventParams(lEventCode, lParam1, lParam2);

if (lEventCode == EC_COMPLETE)
{
m_objMediaControl.Stop();
m_objMediaPosition.CurrentPosition = 0;
m_CurrentStatus = MediaStatus.Stopped;
UpdateStatusBar();
UpdateToolBar();
}
}
catch (Exception)
{
break;
}
}
}

base.WndProc(ref m);
}
...全文
2254 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
ring_rain 2012-08-15
  • 打赏
  • 举报
回复
怎么改变视频的声音大小呀???
loseing_ 2011-03-10
  • 打赏
  • 举报
回复
同15楼问题
xgxhells 2010-12-27
  • 打赏
  • 举报
回复
研究研究!
lkx_2010 2010-12-26
  • 打赏
  • 举报
回复
如何实现声道切换?
LostTemples 2010-10-15
  • 打赏
  • 举报
回复
看的有点懵诶搞不懂
iComputerLion 2010-06-10
  • 打赏
  • 举报
回复
兄弟 在视频捕捉后 播放时 速度飞快 怎么解决!

参考时钟 和 帧率 都已经设置 但不见效果!
ilgouli 2010-05-23
  • 打赏
  • 举报
回复
我想问一下,m_objVideoWindow.Owner = (int) panel1.Handle;我的程序运行到这里的时候总是提示指定的转换无效,为什么句柄没有转换成功
兜老底 2010-05-05
  • 打赏
  • 举报
回复
支持哈。。。
兜老底 2010-05-05
  • 打赏
  • 举报
回复
一知半解啊。。。。。。。。。。。
scdn8311 2010-05-05
  • 打赏
  • 举报
回复
可以看看
缭绕飘渺 2010-04-06
  • 打赏
  • 举报
回复
好高深
不过确实是好东西啊
siegebaoniu 2010-04-06
  • 打赏
  • 举报
回复
好难好难。
xy123z 2010-01-19
  • 打赏
  • 举报
回复
图片怎么看不到
starj1 2009-12-21
  • 打赏
  • 举报
回复
虽然很想学DirectShow,但看不懂LZ在说啥。走人,找高点的楼跳去……
gjl0211 2009-06-03
  • 打赏
  • 举报
回复
看的不太懂耶,55555555555.。。。。。。。
  • 打赏
  • 举报
回复
有点迷糊
knowledge_Is_Life 2008-05-01
  • 打赏
  • 举报
回复
有点难度哦
rageliu 2008-04-15
  • 打赏
  • 举报
回复
呵呵,支持下

2,543

社区成员

发帖
与我相关
我的任务
社区描述
专题开发/技术/项目 多媒体/流媒体开发
社区管理员
  • 多媒体/流媒体开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧