因工作需要,近期开始接触DirectShow开发的相关技术,由于本人较青睐于C#,因此从网上找了一些关于.NET版的DirectShow库及实例,之后参考相关源码编写了一个用于测试的MP3播放器,源码主要参考了SourceForge(http://sourceforge.net/)上的一份关于DirectShow的源码实例。
这篇文章展示的是一个初步的不完善的MP3播放器Demo,包括两部分:播放控制部分和播放列表部分。其中播放控制部分的基本功能包括:播放/暂停、停止、上一曲、下一曲、播放进度条、当前播放时间、播放时长、播放标题。播放列表部分包括:播放列表、添加、删除。此外,还增加了顺序播放和随机播放两种播放模式,默认为顺序播放模式。
因无法上传图片,这里贴出主要代码:
using System;
using System.Windows.Forms;
using System.IO;
using QuartzTypeLib;
namespace MyMp3Player
{
public partial class FrmPlayer : Form
{
private const int WM_APP = 0x8000;
private const int WM_GRAPHNOTIFY = WM_APP + 1;
private const int EC_COMPLETE = 0x01;
private const int WS_CHILD = 0x40000000;
private const int WS_CLIPCHILDREN = 0x2000000;
private FilgraphManager m_objFilterGraph = null;
private IBasicAudio m_objBasicAudio = null;
private IVideoWindow m_objVideoWindow = null;
private IMediaEvent m_objMediaEvent = null;
private IMediaEventEx m_objMediaEventEx = null;
private IMediaPosition m_objMediaPosition = null;
private IMediaControl m_objMediaControl = null;
enum MediaStatus { None, Stopped, Paused, Running };
private MediaStatus m_CurrentStatus = MediaStatus.None;
private string m_strFilePath; // 文件路径
private bool m_blnRandomPlay = false; // 随机播放模式
public FrmPlayer()
{
InitializeComponent();
this.UpdatePlayTime();
this.UpdatePlayList();
this.UpdateButtonStatus();
}
private void FrmPlayer_Load(object sender, EventArgs e)
{
}
private void FrmPlayer_FormClosing(object sender, FormClosingEventArgs e)
{
this.CleanUp();
}
///
/// 播放/暂停
///
///
///
private void btnPlayPause_Click(object sender, EventArgs e)
{
if (m_CurrentStatus == MediaStatus.Running)
{
this.Pause();
}
else
{
this.Play();
}
}
///
/// 停止
///
///
///
private void btnStop_Click(object sender, EventArgs e)
{
this.Stop();
}
///
/// 上一曲
///
///
///
private void btnPrevious_Click(object sender, EventArgs e)
{
this.Previous();
}
///
/// 下一曲
///
///
///
private void btnNext_Click(object sender, EventArgs e)
{
this.Next();
}
///
/// 定时器
///
///
///
private void timer1_Tick(object sender, EventArgs e)
{
if (m_CurrentStatus == MediaStatus.Running)
{
this.UpdatePlayTime();
}
}
///
/// 播放进度条控制
///
///
///
private void trackBarPlay_Scroll(object sender, EventArgs e)
{
if (m_CurrentStatus != MediaStatus.None)
{
m_objMediaPosition.CurrentPosition = m_objMediaPosition.Duration * trackBarPlay.Value / 100;
}
}
///
/// 添加播放文件
///
///
///
private void btnAdd_Click(object sender, EventArgs e)
{
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = "MP3文件(*.mp3)|*.mp3";
openFileDialog.Multiselect = true;
if (DialogResult.OK == openFileDialog.ShowDialog())
{
string[] fileNames = openFileDialog.FileNames;
if (fileNames != null)
{
foreach (string fileName in fileNames)
{
lstPlayList.Items.Add(fileName);
}
if (lstPlayList.SelectedIndex < 0) // 当前播放列表为空
{
// 选中第一个文件并进行播放
lstPlayList.SelectedIndex = 0;
this.InitPlayer();
this.Play();
}
this.UpdatePlayList();
}
}
}
///
/// 双击选中文件并播放
///
///
///
private void lstPlayList_DoubleClick(object sender, EventArgs e)
{
if (lstPlayList.Items.Count > 0)
{
this.InitPlayer();
this.Play();
}
}
///
/// 随机播放模式
///
///
///
private void btnPlayRandom_Click(object sender, EventArgs e)
{
m_blnRandomPlay = true;
btnPlayOrder.Enabled = true;
btnPlayRandom.Enabled = false;
}
///
/// 顺序播放模式
///
///
///
private void btnPlayOrder_Click(object sender, EventArgs e)
{
m_blnRandomPlay = false;
btnPlayOrder.Enabled = false;
btnPlayRandom.Enabled = true;
}
///
/// 清空播放列表
///
///
///
private void btnClear_Click(object sender, EventArgs e)
{
lstPlayList.Items.Clear();
btnPlayOrder.Enabled = false;
btnPlayRandom.Enabled = false;
btnClear.Enabled = false;
}
#region private methods
///
/// 更新播放时间及播放进度
///
private void UpdatePlayTime()
{
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);
lblTotalTime.Text = String.Format("{0:D2}:{1:D2}", m, s);
s = (int)m_objMediaPosition.CurrentPosition;
h = s / 3600;
m = (s - (h * 3600)) / 60;
s = s - (h * 3600 + m * 60);
lblCurrentTime.Text = String.Format("{0:D2}:{1:D2}", m, s);
trackBarPlay.Value = (int)(100 * (m_objMediaPosition.CurrentPosition / m_objMediaPosition.Duration));
}
else
{
lblTotalTime.Text = "00:00";
lblCurrentTime.Text = "00:00";
}
}
///
/// 根据播放列表状态更新相应按钮状态
///
private void UpdatePlayList()
{
if (lstPlayList.Items.Count > 0)
{
btnPrevious.Enabled = true;
btnNext.Enabled = true;
btnClear.Enabled = true;
btnPlayRandom.Enabled = true;
}
else
{
btnPrevious.Enabled = false;
btnNext.Enabled = false;
btnClear.Enabled = false;
btnPlayRandom.Enabled = false;
}
}
///
/// 更新播放按钮状态
///
private void UpdateButtonStatus()
{
switch (m_CurrentStatus)
{
case MediaStatus.None:
btnPlayPause.Enabled = false;
btnStop.Enabled = false;
break;
case MediaStatus.Paused:
case MediaStatus.Running:
btnPlayPause.Enabled = true;
btnStop.Enabled = true;
break;
case MediaStatus.Stopped:
btnPlayPause.Enabled = true;
btnStop.Enabled = false;
lblCurrentTime.Text = "00:00";
lblTotalTime.Text = "00:00";
trackBarPlay.Value = 0;
break;
}
}
///
/// 初始化播放
///
private void InitPlayer()
{
this.CleanUp();
m_strFilePath = lstPlayList.SelectedItem.ToString();
m_objFilterGraph = new FilgraphManager();
m_objFilterGraph.RenderFile(m_strFilePath);
m_objBasicAudio = m_objFilterGraph as IBasicAudio;
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;
}
///
/// 播放
///
private void Play()
{
FileInfo fi = new FileInfo(m_strFilePath);
string fileName = fi.Name;
fileName = fileName.Substring(0, fileName.Length - 4);
if (fileName.IndexOf("&") > 0)
{
fileName = fileName.Replace("&", "&&");
}
lblTitle.Text = fileName;
m_objMediaControl.Run();
m_CurrentStatus = MediaStatus.Running;
btnPlayPause.Text = "暂停";
this.UpdatePlayTime();
this.UpdateButtonStatus();
}
///
/// 暂停
///
private void Pause()
{
m_objMediaControl.Pause();
m_CurrentStatus = MediaStatus.Paused;
btnPlayPause.Text = "播放";
this.UpdatePlayTime();
this.UpdateButtonStatus();
}
///
/// 停止
///
private void Stop()
{
m_objMediaControl.Stop();
m_objMediaPosition.CurrentPosition = 0;
m_CurrentStatus = MediaStatus.Stopped;
btnPlayPause.Text = "播放";
this.UpdateButtonStatus();
}
///
/// 上一曲
///
private void Previous()
{
if (m_blnRandomPlay) // 随机播放模式
{
Random random = new Random();
lstPlayList.SelectedIndex = random.Next(lstPlayList.Items.Count);
}
else // 顺序播放模式
{
if (lstPlayList.SelectedIndex == 0)
{
// 已移到最前面,不做任何事情
}
else
{
lstPlayList.SelectedIndex -= 1;
}
}
this.InitPlayer();
this.Play();
}
///
/// 下一曲
///
private void Next()
{
if (m_blnRandomPlay) // 随机播放模式
{
Random random = new Random();
lstPlayList.SelectedIndex = random.Next(lstPlayList.Items.Count);
}
else // 顺序播放模式
{
if (lstPlayList.SelectedIndex == lstPlayList.Items.Count - 1)
{
// 已移到最后面,不做任何事情
}
else
{
lstPlayList.SelectedIndex += 1;
}
}
this.InitPlayer();
this.Play();
}
///
/// 清理
///
private void CleanUp()
{
if (m_objMediaControl != null)
m_objMediaControl.Stop();
m_CurrentStatus = MediaStatus.Stopped;
if (m_objMediaEventEx != null)
m_objMediaEventEx.SetNotifyWindow(0, 0, 0);
if (m_objVideoWindow != null)
{
m_objVideoWindow.Visible = 0;
m_objVideoWindow.Owner = 0;
}
if (m_objMediaControl != null) m_objMediaControl = null;
if (m_objMediaPosition != null) m_objMediaPosition = null;
if (m_objMediaEventEx != null) m_objMediaEventEx = null;
if (m_objMediaEvent != null) m_objMediaEvent = null;
if (m_objVideoWindow != null) m_objVideoWindow = null;
if (m_objBasicAudio != null) m_objBasicAudio = null;
if (m_objFilterGraph != null) m_objFilterGraph = null;
}
///
/// 重写WndProc
///
///
protected 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)
{
this.Next(); // 自动切换到下一曲
}
}
catch (Exception)
{
break;
}
}
}
base.WndProc(ref m);
}
#endregion
}
}
上面实例使用到了Interop.QuartzTypeLib.dll,并没有完全使用DirectShow的一些内部机制,仅仅是一个简单例子,在后面如有时间将会对该播放器进行逐步完善。