本人之前很多的文章中均提到了使用libvlc为播放器内核制作的播放器,也许有些朋友对此感兴趣,于是我用c#写了一个调用libvlc api实现的万能视频播放器,与大家分享一下。说它“万能”,当然是因为我们站在了vlc的肩膀上。
vlc是一个强大而且开源的多媒体播放器,也可以说是一个多媒体平台。它支持非常广泛的媒体格式的本地播放,完全可以媲美mplayer,其对视频网络流的处理能力更是非常强悍。libvlc就是指的vlc的核心,它向外提供了一系列的接口,通过接口,来实现视频播放等复杂的功能。libvlc对外提供了c语言的接口,也有其他语言,包括.net的绑定,在其官网上就有,不过已经“年久失修”。我之前用Qt, MFC实现过基于libvlc的播放器,不过鉴于园子里c#开发人员较多,遂用c#封装了一下libvlc的API接口,并实现了一个视频播放器。
先上鉴赏图,外表很简单,不过,外表不是重点:)
首先是libvlc的一些导出函数,我在注释里对它们的功能都有说明
1 // 创建一个libvlc实例,它是引用计数的 2 [DllImport("libvlc", CallingConvention = CallingConvention.StdCall, ExactSpelling = true)] 3 [SuppressUnmanagedCodeSecurity] 4 private static extern IntPtr libvlc_new(int argc, IntPtr argv); 5 6 // 释放libvlc实例 7 [DllImport("libvlc", CallingConvention = CallingConvention.StdCall, ExactSpelling = true)] 8 [SuppressUnmanagedCodeSecurity] 9 public static extern void libvlc_release(IntPtr libvlc_instance); 10 11 [DllImport("libvlc", CallingConvention = CallingConvention.StdCall, ExactSpelling = true)] 12 [SuppressUnmanagedCodeSecurity] 13 public static extern String libvlc_get_version(); 14 15 // 从视频来源(例如Url)构建一个libvlc_meida 16 [DllImport("libvlc", CallingConvention = CallingConvention.StdCall, ExactSpelling = true)] 17 [SuppressUnmanagedCodeSecurity] 18 private static extern IntPtr libvlc_media_new_location(IntPtr libvlc_instance, IntPtr path); 19 20 // 从本地文件路径构建一个libvlc_media 21 [DllImport("libvlc", CallingConvention = CallingConvention.StdCall, ExactSpelling = true)] 22 [SuppressUnmanagedCodeSecurity] 23 private static extern IntPtr libvlc_media_new_path(IntPtr libvlc_instance, IntPtr path); 24 25 [DllImport("libvlc", CallingConvention = CallingConvention.StdCall, ExactSpelling = true)] 26 [SuppressUnmanagedCodeSecurity] 27 public static extern void libvlc_media_release(IntPtr libvlc_media_inst); 28 29 // 创建libvlc_media_player(播放核心) 30 [DllImport("libvlc", CallingConvention = CallingConvention.StdCall, ExactSpelling = true)] 31 [SuppressUnmanagedCodeSecurity] 32 public static extern IntPtr libvlc_media_player_new(IntPtr libvlc_instance); 33 34 // 将视频(libvlc_media)绑定到播放器上 35 [DllImport("libvlc", CallingConvention = CallingConvention.StdCall, ExactSpelling = true)] 36 [SuppressUnmanagedCodeSecurity] 37 public static extern void libvlc_media_player_set_media(IntPtr libvlc_media_player, IntPtr libvlc_media); 38 39 // 设置图像输出的窗口 40 [DllImport("libvlc", CallingConvention = CallingConvention.StdCall, ExactSpelling = true)] 41 [SuppressUnmanagedCodeSecurity] 42 public static extern void libvlc_media_player_set_hwnd(IntPtr libvlc_mediaplayer, Int32 drawable); 43 44 [DllImport("libvlc", CallingConvention = CallingConvention.StdCall, ExactSpelling = true)] 45 [SuppressUnmanagedCodeSecurity] 46 public static extern void libvlc_media_player_play(IntPtr libvlc_mediaplayer); 47 48 [DllImport("libvlc", CallingConvention = CallingConvention.StdCall, ExactSpelling = true)] 49 [SuppressUnmanagedCodeSecurity] 50 public static extern void libvlc_media_player_pause(IntPtr libvlc_mediaplayer); 51 52 [DllImport("libvlc", CallingConvention = CallingConvention.StdCall, ExactSpelling = true)] 53 [SuppressUnmanagedCodeSecurity] 54 public static extern void libvlc_media_player_stop(IntPtr libvlc_mediaplayer); 55 56 // 解析视频资源的媒体信息(如时长等) 57 [DllImport("libvlc", CallingConvention = CallingConvention.StdCall, ExactSpelling = true)] 58 [SuppressUnmanagedCodeSecurity] 59 public static extern void libvlc_media_parse(IntPtr libvlc_media); 60 61 // 返回视频的时长(必须先调用libvlc_media_parse之后,该函数才会生效) 62 [DllImport("libvlc", CallingConvention = CallingConvention.StdCall, ExactSpelling = true)] 63 [SuppressUnmanagedCodeSecurity] 64 public static extern Int64 libvlc_media_get_duration(IntPtr libvlc_media); 65 66 // 当前播放的时间 67 [DllImport("libvlc", CallingConvention = CallingConvention.StdCall, ExactSpelling = true)] 68 [SuppressUnmanagedCodeSecurity] 69 public static extern Int64 libvlc_media_player_get_time(IntPtr libvlc_mediaplayer); 70 71 // 设置播放位置(拖动) 72 [DllImport("libvlc", CallingConvention = CallingConvention.StdCall, ExactSpelling = true)] 73 [SuppressUnmanagedCodeSecurity] 74 public static extern void libvlc_media_player_set_time(IntPtr libvlc_mediaplayer, Int64 time); 75 76 [DllImport("libvlc", CallingConvention = CallingConvention.StdCall, ExactSpelling = true)] 77 [SuppressUnmanagedCodeSecurity] 78 public static extern void libvlc_media_player_release(IntPtr libvlc_mediaplayer); 79 80 // 获取和设置音量 81 [DllImport("libvlc", CallingConvention = CallingConvention.StdCall, ExactSpelling = true)] 82 [SuppressUnmanagedCodeSecurity] 83 public static extern int libvlc_audio_get_volume(IntPtr libvlc_media_player); 84 85 [DllImport("libvlc", CallingConvention = CallingConvention.StdCall, ExactSpelling = true)] 86 [SuppressUnmanagedCodeSecurity] 87 public static extern void libvlc_audio_set_volume(IntPtr libvlc_media_player, int volume); 88 89 // 设置全屏 90 [DllImport("libvlc", CallingConvention = CallingConvention.StdCall, ExactSpelling = true)] 91 [SuppressUnmanagedCodeSecurity] 92 public static extern void libvlc_set_fullscreen(IntPtr libvlc_media_player, int isFullScreen);
要使用libvlc api进行播放,首先需要创建一个libvlc的实例,就是lbvlc_instance,之后所有的操作都是基于这个实例来完成。
每一个播放窗口,对应一个libvlc_media_player,而每一个媒体文件,就是一个libvlc_media。所以,调用的步骤就是:
- 创建libvlc_instance
- 创建libvlc_media_player
- 开始播放时,创建libvlc_media,通知libvlc_media_player要播放的媒体文件,之后就可以释放libvlc_media了
- 操作libvlc_media_player,实现播放、暂停等功能
下面对这些操作进行封装,以供上层使用。
1 class VlcPlayer 2 { 3 private IntPtr libvlc_instance_; 4 private IntPtr libvlc_media_player_; 5 6 private double duration_; 7 8 public VlcPlayer(string pluginPath) 9 { 10 string plugin_arg = "--plugin-path=" + pluginPath; 11 string[] arguments = { "-I", "dummy", "--ignore-config", "--no-video-title", plugin_arg }; 12 libvlc_instance_ = LibVlcAPI.libvlc_new(arguments); 13 14 libvlc_media_player_ = LibVlcAPI.libvlc_media_player_new(libvlc_instance_); 15 } 16 17 public void SetRenderWindow(int wndHandle) 18 { 19 if (libvlc_instance_ != IntPtr.Zero && wndHandle != 0) 20 { 21 LibVlcAPI.libvlc_media_player_set_hwnd(libvlc_media_player_, wndHandle); 22 } 23 } 24 25 public void PlayFile(string filePath) 26 { 27 IntPtr libvlc_media = LibVlcAPI.libvlc_media_new_path(libvlc_instance_, filePath); 28 if (libvlc_media != IntPtr.Zero) 29 { 30 LibVlcAPI.libvlc_media_parse(libvlc_media); 31 duration_ = LibVlcAPI.libvlc_media_get_duration(libvlc_media) / 1000.0; 32 33 LibVlcAPI.libvlc_media_player_set_media(libvlc_media_player_, libvlc_media); 34 LibVlcAPI.libvlc_media_release(libvlc_media); 35 36 LibVlcAPI.libvlc_media_player_play(libvlc_media_player_); 37 } 38 } 39 40 public void Pause() 41 { 42 if (libvlc_media_player_ != IntPtr.Zero) 43 { 44 LibVlcAPI.libvlc_media_player_pause(libvlc_media_player_); 45 } 46 } 47 48 public void Stop() 49 { 50 if (libvlc_media_player_ != IntPtr.Zero) 51 { 52 LibVlcAPI.libvlc_media_player_stop(libvlc_media_player_); 53 } 54 } 55 56 public double GetPlayTime() 57 { 58 return LibVlcAPI.libvlc_media_player_get_time(libvlc_media_player_) / 1000.0; 59 } 60 61 public void SetPlayTime(double seekTime) 62 { 63 LibVlcAPI.libvlc_media_player_set_time(libvlc_media_player_, (Int64)(seekTime * 1000)); 64 } 65 66 public int GetVolume() 67 { 68 return LibVlcAPI.libvlc_audio_get_volume(libvlc_media_player_); 69 } 70 71 public void SetVolume(int volume) 72 { 73 LibVlcAPI.libvlc_audio_set_volume(libvlc_media_player_, volume); 74 } 75 76 public void SetFullScreen(bool istrue) 77 { 78 LibVlcAPI.libvlc_set_fullscreen(libvlc_media_player_, istrue ? 1 : 0); 79 } 80 81 public double Duration() 82 { 83 return duration_; 84 } 85 86 public string Version() 87 { 88 return LibVlcAPI.libvlc_get_version(); 89 } 90 }
封装为VlcPlayer之后,调用就会变得非常简单。
- 首先确定好vlc的插件目录
- 在你的代码里创建VlcPlayer对象
- 调用SetRenderWindow,以设置视频显示的窗口,否则会变成一个独立的播放窗口
- 调用PlayFile,即可开始播放
程序做好之后,需要带上libvlc.dll和libvlccore.dll,这两个是vlc的播放内核,因为vlc把编解码和格式解析的支持设计成了插件的形式,所以还必须要带上vlc的plugins目录里的插件。
我把整个工程打包(包括libvlc.dll和libvlccore.dll)上传到了博客上,点击这里,就可以下载。
plugins目录文件有点大(因为libvlc支持的格式和功能非常多,如果你不需要,删掉对应插件即可),我放到了115网盘,下载地址是http://115.com/file/dnre4jg7#plugins.7z。下载后放到“bin/Debug”目录即可调试运行。