C#编写的基于VLC的播放器
首先看一下最终的程序效果
实现的功能:
1:打开播放的音视频文件((1)菜单栏“文件”->“打开”,(2)工具栏(下面)“打开”(3)播放器右键->打开)
2:暂停,继续播放,停止音视频文件
3:进度条和右下角文本框显示播放进度
4:拖动进度条对视频定位播放
5:工具栏(下面)“快进”,“快退”均为5s
6:音量调节
7:菜单栏“文件”下可记录最近播放的三个文件
8:在有记录的情况下,初始状态时双击视频播放区或单击“播放”播放上次关闭时播放的视频
需准备的东西:
VLC的动态链接库*.dll
1,在网上直接下载VLC播放器安装http://www.videolan.org点击打开链接/
2,安装好后在VLC安装目录下libvlc.dll,libvlccore.dll及plugins目录下的所有文件拷贝到C#的debug目录下(下左图VLC安装目录,右图C#项目debug目录)
若是release 也需放到release目录
C#编程
(1)创建一个C#的winform项目
(2)c#封装libvlc的API接口
新建一个类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
using System.Threading.Tasks;namespace WindowsFormsApplication1
{class VlcPlayer{private IntPtr libvlc_instance_;private IntPtr libvlc_media_player_;private double duration_;public VlcPlayer(string pluginPath){string plugin_arg = "--plugin-path=" + pluginPath;string[] arguments = { "-I", "dummy", "--ignore-config", "--no-video-title", plugin_arg };libvlc_instance_ = LibVlcAPI.libvlc_new(arguments);libvlc_media_player_ = LibVlcAPI.libvlc_media_player_new(libvlc_instance_);}public void SetRenderWindow(int wndHandle){if (libvlc_instance_ != IntPtr.Zero && wndHandle != 0){LibVlcAPI.libvlc_media_player_set_hwnd(libvlc_media_player_, wndHandle);}}public void PlayFile(string filePath){IntPtr libvlc_media = LibVlcAPI.libvlc_media_new_path(libvlc_instance_, filePath);if (libvlc_media != IntPtr.Zero){LibVlcAPI.libvlc_media_parse(libvlc_media);duration_ = LibVlcAPI.libvlc_media_get_duration(libvlc_media) / 1000.0;LibVlcAPI.libvlc_media_player_set_media(libvlc_media_player_, libvlc_media);LibVlcAPI.libvlc_media_release(libvlc_media);LibVlcAPI.libvlc_media_player_play(libvlc_media_player_);}}public void Pause(){if (libvlc_media_player_ != IntPtr.Zero){LibVlcAPI.libvlc_media_player_pause(libvlc_media_player_);}}public void Play(){if (libvlc_media_player_ != IntPtr.Zero){LibVlcAPI.libvlc_media_player_play(libvlc_media_player_);// LibVlcAPI.libvlc_media_player_pause(libvlc_media_player_);}}public void Stop(){if (libvlc_media_player_ != IntPtr.Zero){LibVlcAPI.libvlc_media_player_stop(libvlc_media_player_);}}// public void FastForward()// {// if (libvlc_media_player_ != IntPtr.Zero)// {// LibVlcAPI.libvlc_media_player_fastforward(libvlc_media_player_);// }// }public double GetPlayTime(){return LibVlcAPI.libvlc_media_player_get_time(libvlc_media_player_) / 1000.0;}public void SetPlayTime(double seekTime){LibVlcAPI.libvlc_media_player_set_time(libvlc_media_player_, (Int64)(seekTime * 1000));}public int GetVolume(){return LibVlcAPI.libvlc_audio_get_volume(libvlc_media_player_);}public void SetVolume(int volume){LibVlcAPI.libvlc_audio_set_volume(libvlc_media_player_, volume);}public void SetFullScreen(bool istrue){LibVlcAPI.libvlc_set_fullscreen(libvlc_media_player_, istrue ? 1 : 0);}public double Duration(){return duration_;}public string Version(){return LibVlcAPI.libvlc_get_version();}}internal static class LibVlcAPI{internal struct PointerToArrayOfPointerHelper{[MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)]public IntPtr[] pointers;}public static IntPtr libvlc_new(string[] arguments){PointerToArrayOfPointerHelper argv = new PointerToArrayOfPointerHelper();argv.pointers = new IntPtr[11];for (int i = 0; i < arguments.Length; i++){argv.pointers[i] = Marshal.StringToHGlobalAnsi(arguments[i]);}IntPtr argvPtr = IntPtr.Zero;try{int size = Marshal.SizeOf(typeof(PointerToArrayOfPointerHelper));argvPtr = Marshal.AllocHGlobal(size);Marshal.StructureToPtr(argv, argvPtr, false);return libvlc_new(arguments.Length, argvPtr);}finally{for (int i = 0; i < arguments.Length + 1; i++){if (argv.pointers[i] != IntPtr.Zero){Marshal.FreeHGlobal(argv.pointers[i]);}}if (argvPtr != IntPtr.Zero){Marshal.FreeHGlobal(argvPtr);}}}public static IntPtr libvlc_media_new_path(IntPtr libvlc_instance, string path){IntPtr pMrl = IntPtr.Zero;try{byte[] bytes = Encoding.UTF8.GetBytes(path);pMrl = Marshal.AllocHGlobal(bytes.Length + 1);Marshal.Copy(bytes, 0, pMrl, bytes.Length);Marshal.WriteByte(pMrl, bytes.Length, 0);return libvlc_media_new_path(libvlc_instance, pMrl);}finally{if (pMrl != IntPtr.Zero){Marshal.FreeHGlobal(pMrl);}}}public static IntPtr libvlc_media_new_location(IntPtr libvlc_instance, string path){IntPtr pMrl = IntPtr.Zero;try{byte[] bytes = Encoding.UTF8.GetBytes(path);pMrl = Marshal.AllocHGlobal(bytes.Length + 1);Marshal.Copy(bytes, 0, pMrl, bytes.Length);Marshal.WriteByte(pMrl, bytes.Length, 0);return libvlc_media_new_path(libvlc_instance, pMrl);}finally{if (pMrl != IntPtr.Zero){Marshal.FreeHGlobal(pMrl);}}}// ----------------------------------------------------------------------------------------// 以下是libvlc.dll导出函数// 创建一个libvlc实例,它是引用计数的[DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)][SuppressUnmanagedCodeSecurity]private static extern IntPtr libvlc_new(int argc, IntPtr argv);// 释放libvlc实例[DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)][SuppressUnmanagedCodeSecurity]public static extern void libvlc_release(IntPtr libvlc_instance);[DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)][SuppressUnmanagedCodeSecurity]public static extern String libvlc_get_version();// 从视频来源(例如Url)构建一个libvlc_meida[DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)][SuppressUnmanagedCodeSecurity]private static extern IntPtr libvlc_media_new_location(IntPtr libvlc_instance, IntPtr path);// 从本地文件路径构建一个libvlc_media[DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)][SuppressUnmanagedCodeSecurity]private static extern IntPtr libvlc_media_new_path(IntPtr libvlc_instance, IntPtr path);[DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)][SuppressUnmanagedCodeSecurity]public static extern void libvlc_media_release(IntPtr libvlc_media_inst);// 创建libvlc_media_player(播放核心)[DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)][SuppressUnmanagedCodeSecurity]public static extern IntPtr libvlc_media_player_new(IntPtr libvlc_instance);// 将视频(libvlc_media)绑定到播放器上[DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)][SuppressUnmanagedCodeSecurity]public static extern void libvlc_media_player_set_media(IntPtr libvlc_media_player, IntPtr libvlc_media);// 设置图像输出的窗口[DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)][SuppressUnmanagedCodeSecurity]public static extern void libvlc_media_player_set_hwnd(IntPtr libvlc_mediaplayer, Int32 drawable);[DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)][SuppressUnmanagedCodeSecurity]public static extern void libvlc_media_player_play(IntPtr libvlc_mediaplayer);/// <summary>/// /// </summary>/// <param name="libvlc_mediaplayer"></param>//[DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]//[SuppressUnmanagedCodeSecurity]// public static extern void libvlc_media_player_fastforward(IntPtr libvlc_mediaplayer);[DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)][SuppressUnmanagedCodeSecurity]public static extern void libvlc_media_player_pause(IntPtr libvlc_mediaplayer);[DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)][SuppressUnmanagedCodeSecurity]public static extern void libvlc_media_player_stop(IntPtr libvlc_mediaplayer);// 解析视频资源的媒体信息(如时长等)[DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)][SuppressUnmanagedCodeSecurity]public static extern void libvlc_media_parse(IntPtr libvlc_media);// 返回视频的时长(必须先调用libvlc_media_parse之后,该函数才会生效)[DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)][SuppressUnmanagedCodeSecurity]public static extern Int64 libvlc_media_get_duration(IntPtr libvlc_media);// 当前播放的时间[DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)][SuppressUnmanagedCodeSecurity]public static extern Int64 libvlc_media_player_get_time(IntPtr libvlc_mediaplayer);// 设置播放位置(拖动)[DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)][SuppressUnmanagedCodeSecurity]public static extern void libvlc_media_player_set_time(IntPtr libvlc_mediaplayer, Int64 time);[DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)][SuppressUnmanagedCodeSecurity]public static extern void libvlc_media_player_release(IntPtr libvlc_mediaplayer);// 获取和设置音量[DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)][SuppressUnmanagedCodeSecurity]public static extern int libvlc_audio_get_volume(IntPtr libvlc_media_player);[DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)][SuppressUnmanagedCodeSecurity]public static extern void libvlc_audio_set_volume(IntPtr libvlc_media_player, int volume);// 设置全屏[DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)][SuppressUnmanagedCodeSecurity]public static extern void libvlc_set_fullscreen(IntPtr libvlc_media_player, int isFullScreen);}
}
(3)窗口布局编辑
(3)选几个要点说说,其余参考附件的源码
1,播放过程中的窗口右键菜单问题
注意窗口布局中黑色panel那块有两个panel,一个panel1,一个panel2,panel1位于底层,panel2位于表层,panel2背景色设置为transparent,这么做的原因是panel1在指定成播放后contextMenuStrip属性失效,为了能在播放后仍能在播放区使用右键并且不影响播放,故添加透明的panel2
2,记录之前打开的三次文件
/// <summary>/// 菜单栏文件实现功能/// 1 打开待播放文件/// 2 记录历史信息/// 3 历史信息最多不超过3条/// 4 点击历史信息可以实现播放menuitem_Click()/// 5 如果点击历史信息不能播放(出现错误)则删除该历史信息item和Menu.ini (方法:try catch)/// 6 Menu.ini记录的信息最多不超过3条,不重复记录/// 7 在历史信息中右键可以选择删除/// </summary>/// <param name="sender"></param>/// <param name="e"></param>/// #region 菜单栏-文件/// <summary>/// 打开ToolStripMenuItem_Click/// 打开文件并将文件目录添加到Menu.ini/// 若打开相同文件则不添加(这个有Bug,这样的话按tsBtn_play打开的就不是上一个了,因为打开相同的不添加)/// 若记录行数超过3个,则先记录后三个数据,再重新建一个Menu.ini(清除数据),接着讲记录的后三个数据写入/// </summary>/// <param name="sender"></param>/// <param name="e"></param>/// private void 打开ToolStripMenuItem_Click(object sender, EventArgs e){//bool isSame = false;openFileDialog1.FileName = "";if(this.openFileDialog1.ShowDialog()==DialogResult.OK){ //StreamReader sr0 = new StreamReader(address + "\\Menu.ini", true);// while (sr0.Peek() > -1)// {// if ((sr0.ReadLine() == openFileDialog1.FileName)|(openFileDialog1.FileName==""))// {// isSame = true;// }// }// sr0.Close();// if (isSame == false)// 若打开相同文件则不添加// {StreamWriter s = new StreamWriter(address + "\\Menu.ini", true);s.WriteLine(openFileDialog1.FileName);s.Flush();s.Close();// }string[] text = File.ReadAllLines(address + "\\Menu.ini");int row = text.Length;//行int rowcount;string[] tempdata = new string[] {"","",""};if (row > 3)// 若记录行数超过3个,则先记录后三个数据,再重新建一个Menu.ini(清除数据),接着讲记录的后三个数据写入{StreamReader sr1 = new StreamReader(address + "\\Menu.ini", true);while (sr1.Peek() > -1){sr1.ReadLine();//空读,跳过原始的第一个数据,从第二个数据开始读for (rowcount = 0; rowcount < 3; rowcount++){tempdata[rowcount] = sr1.ReadLine();}}sr1.Close();FileStream fs = new FileStream(address + "\\Menu.ini", FileMode.Create, FileAccess.Write);fs.Close();StreamWriter s1 = new StreamWriter(address + "\\Menu.ini", true);s1.WriteLine(tempdata[0]);s1.WriteLine(tempdata[1]);s1.WriteLine(tempdata[2]);s1.Flush();s1.Close();}// StreamReader sr2 = new StreamReader(address + "\\Menu.ini", true);// while(sr2.Pee)vlcPlayer.PlayFile(openFileDialog1.FileName);trackBar1.SetRange(0, (int)vlcPlayer.Duration());trackBar1.Value = 0;timer1.Start();is_playinig = true;tSBtn_play.Image = Properties.Resources.暂停;tSBtn_play.Text = "暂停";media_is_open = true; //label_media_name.Text = openFileDialog1.FileName.Substring(openFileDialog1.FileName.LastIndexOf('\\') + 1, openFileDialog1.FileName.Length - 1 - openFileDialog1.FileName.LastIndexOf('\\'));//获取文件名的另一种方法,不带后缀label_media_name.Text = Path.GetFileNameWithoutExtension(openFileDialog1.FileName);label_media_name.Show();}}/// <summary>/// 将Menu.ini中的历史记录添加到文件菜单栏/// </summary>private void readFilePath(){int items_count = this.文件ToolStripMenuItem.DropDownItems.Count;switch (items_count){case 4:this.文件ToolStripMenuItem.DropDownItems.RemoveAt(1);break;case 5:this.文件ToolStripMenuItem.DropDownItems.RemoveAt(1);//移走第一项后原本第二项又成第一项了,所以继续移走第一项this.文件ToolStripMenuItem.DropDownItems.RemoveAt(1);break;case 6:this.文件ToolStripMenuItem.DropDownItems.RemoveAt(1);this.文件ToolStripMenuItem.DropDownItems.RemoveAt(1);this.文件ToolStripMenuItem.DropDownItems.RemoveAt(1);break;default:break;}StreamReader sr = new StreamReader(address + "\\Menu.ini", true);int i =1;while (sr.Peek() > -1)//peek是用来确定你read的文件是否结束了,如果结束了会返回int型 -1 {ToolStripMenuItem menuitem = new ToolStripMenuItem(sr.ReadLine());this.文件ToolStripMenuItem.DropDownItems.Insert(i, menuitem);i++;menuitem.Click += new EventHandler(menuitem_Click); }sr.Close();}/// <summary>/// 打开历史记录并播放/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void menuitem_Click(object sender, EventArgs e){try{ToolStripMenuItem menu = (ToolStripMenuItem)sender;vlcPlayer.PlayFile(menu.Text);trackBar1.SetRange(0, (int)vlcPlayer.Duration());trackBar1.Value = 0;timer1.Start();is_playinig = true;tSBtn_play.Image = Properties.Resources.暂停;tSBtn_play.Text = "暂停";media_is_open = true;label_media_name.Text = Path.GetFileNameWithoutExtension(menu.Text);label_media_name.Show();}catch{MessageBox.Show("文件不存在", "提示");}}private void 文件ToolStripMenuItem_Click(object sender, EventArgs e){readFilePath();}#endregion
这段代码中这个地方注意:
<span style="white-space:pre"> </span> this.文件ToolStripMenuItem.DropDownItems.RemoveAt(1);this.文件ToolStripMenuItem.DropDownItems.RemoveAt(1);this.文件ToolStripMenuItem.DropDownItems.RemoveAt(1);
这段原因是每移除菜单选项标号1的历史记录后,原本的标号2又变成标号1,所以继续删除标号1,而不是删除标号2;
3,在有以前播放记录情况下打开软件直接点击播放时播放上次打开的音视频实现代码
private void tSBtn_play_Click(object sender, EventArgs e){if (is_playinig){vlcPlayer.Pause();timer1.Stop();is_playinig = false;tSBtn_play.Image = Properties.Resources.开始;tSBtn_play.Text = "播放";}else{try{string[] text = File.ReadAllLines(address + "\\Menu.ini");string openfilepath="";int row = text.Length;//行StreamReader sr1 = new StreamReader(address + "\\Menu.ini", true);switch (row){case 1:openfilepath=sr1.ReadLine();break;case 2:sr1.ReadLine();openfilepath = sr1.ReadLine();break;case 3:sr1.ReadLine();sr1.ReadLine();openfilepath = sr1.ReadLine();break;default:break;}if(row==1||row==2||row==3){if (!media_is_open) {vlcPlayer.PlayFile(openfilepath);}trackBar1.SetRange(0, (int)vlcPlayer.Duration());vlcPlayer.SetPlayTime(trackBar1.Value);vlcPlayer.Play();trackBar1.Value = (int)vlcPlayer.GetPlayTime();// trackBar1.Value = 0;timer1.Start();is_playinig = true;tSBtn_play.Image = Properties.Resources.暂停;tSBtn_play.Text = "暂停";media_is_open = true;label_media_name.Text = Path.GetFileNameWithoutExtension(openfilepath);label_media_name.Show();}sr1.Close();}catch (Exception er){MessageBox.Show("文件不存在", "提示");}}}
4,快进和快退实现方法,以快进为例
private void tSB_forward_Click(object sender, EventArgs e){vlcPlayer.Pause();int time = (int)vlcPlayer.GetPlayTime() + 5;if (time < trackBar1.Maximum){vlcPlayer.SetPlayTime(time);}else{vlcPlayer.SetPlayTime(trackBar1.Maximum);}vlcPlayer.Play();trackBar1.Value = (int)vlcPlayer.GetPlayTime();}
VLC的库中并没有快进快退方法(这个我不太确定,我没发现,若有麻烦告知我下,非常感谢)
所以可以先将视频暂停,然后在重新设置视频的播放时间,再播放即可
其余未说到的地方可以参考源码,欢迎跟帖交流
参考帖子:
http://www.cnblogs.com/haibindev/archive/2011/12/21/2296173.html
http://blog.csdn.net/leixiaohua1020/article/details/42363079
http://bbs.csdn.net/topics/390936942
附源码
http://download.csdn.net/detail/u012342996/9505082
C#编写的基于VLC的播放器相关推荐
- 基于VLC的播放器开发
VLC的C++封装 因为工作需要,研究了一段时间的播放器开发,如果从头开始做,可以学习下FFmpeg(http://www.ffmpeg.org/),很多播放器都是基于FFmpeg开发的,但是这样工作 ...
- VLC媒体播放器系统结构
http://blog.csdn.net/buffi/article/details/7174421 VLC媒体播放器系统结构 VLC是免费和 开源跨平台多媒体播放器,一个可以播放大部分多媒体格式如D ...
- 基于android音乐播放器的设计
本科毕业论文(设计)诚信声明 本人郑重声明:所呈交的毕业论文(设计),题目<---基于android音乐播放器的设计----------->是本人在指导教师的指导下,进行研究工作所取得的成 ...
- 基于android的音乐播放器毕业设计,基于android音乐播放器的毕业设计ppt
<基于android音乐播放器的毕业设计ppt>由会员分享,可在线阅读,更多相关<基于android音乐播放器的毕业设计ppt(29页珍藏版)>请在人人文库网上搜索. 1.1. ...
- VLC媒体播放器介绍
VLC媒体播放器介绍 VLC媒体播放器是一高度便携的多媒体播放器,可播放多种音视频格式,如:MPEG-1.MPEG-2.MPEG-4.DivX.mp3.ogg等,也支持DVD.VCD和各种流协议.它还 ...
- 基于android音频感知系统,本科毕业论文—基于android音乐播放器的设计与实现专科.doc...
本科毕业论文-基于android音乐播放器的设计与实现专科.doc 专科毕业设计(论文) 题 目 基于Android的音乐播放器设计与实现 毕业论文(设计)原创性声明 本人所呈交的毕业论文(设计)是我 ...
- 安卓实训项目:基于储存卡音乐播放器实训报告5.0
安卓实训项目:基于储存卡音乐播放器实训报告5.0 (一)功能要求 在基于存储卡音乐播放器V0.4基础上,作如下修改: 1.创建应用程序常量接口保存广播频道常量 2.在音乐播放器应用程序类里添加两个属性 ...
- 安卓实训项目:基于储存卡音乐播放器实训报告4.0
功能要求 在基于存储卡音乐播放器V0.3基础上,作如下修改: 1.创建方法能扫描存储卡上所有mp3文件(采用递归算法) ----完成 2.用自定义应用程序类存放全局数据和方法 ----完成 3.利用异 ...
- 安卓第一阶段实训项目:基于存储卡音乐播放器(更新中……)
文章目录 一.项目功能要求 二.涉及知识点 三.实现思路 1.基于存储卡音乐播放器V0.1 2.基于存储卡音乐播放器V0.2 3.基于存储卡音乐播放器V0.3 4.基于存储卡音乐播放器V0.4 5.基 ...
最新文章
- 远程桌面连接“发生身份验证错误。 无法连接到本地安全机构”解决方法
- 【Android 内存优化】Bitmap 图像尺寸缩小 ( 设置 Options 参数 | inJustDecodeBounds | inSampleSize | 工具类实现 )
- Nginx的index指令
- php判断表单提交是否为空,JS判断提交表单不能为空代码 多种方案
- 全世界的狗都没有“生殖隔离” | 今日趣图
- 入侵网站简单方法总结
- Linux操作系统基础解析之(四)——Linux基本命令剖析(2)
- Linux系统管理(10)——Centos8 重启网络服务 网络相关命令
- android手机慢,Android手机运行慢?!教你一秒“提速”50%
- android中LayoutInflater详解与使用
- 阶段3 1.Mybatis_06.使用Mybatis完成DAO层的开发_8 properties标签的使用及细节
- 洛谷 1984 [SDOI2008]烧水问题
- linux vim修改字符串,Linux的vim查找和替换字符串
- 让机器耳濡目染:MIT提出跨模态机器学习模型
- jsp学习 jdbc连接数据库实现登录注册
- 一文了解二进制和CPU工作原理
- 傲慢的上校的fragment讲解
- 1,什么是JESD204
- 社区电脑计算机培训即将结束,电脑培训感言(2页)-原创力文档
- 检测整数是否含有7 或 是7的倍数