【VB.NET】使用 VlcLib(VlcDotNet)播放在内存中的视频流
在WPF程序中,我们可以使用
即便Windows系统中没有相关的解码器,我们也可以通过安装一些解码器补丁程序(如 K-Lite Basic ),来增强和补完系统的媒体解码器。
虽然播放格式的问题可以通过第三方插件解决,然而
好在我们可以通过使用第三方的媒体库
首先,我们需要获取
VlcLib 采用 LGPL 协议,如果没有修改过源码,可以将其用于闭源或商业程序。
我们要使用 VlcLib,只需要调用它的
VlcLib 分为x86与x64两个版本,你可以根据需求选择,或者将两个版本集合到一起。
我个人觉得 3.x 版不仅容量大,而且启动速度也比 2.x 版慢上许多,所以我推荐您使用 2.2.5.1 版。
https://www.videolan.org/vlc/releases/
2. 在官方资源站上可以找到所有的源码与VLC安装程序,按照上面的方法提取 VlcLib 库文件即可。
https://download.videolan.org/vlc/
其二,安装
在 nuget 上安装
https://www.nuget.org/packages/Vlc.DotNet.Core/
https://www.nuget.org/packages/Vlc.DotNet.Core.Interops/
https://www.nuget.org/packages/Vlc.DotNet.Forms/
https://www.nuget.org/packages/Vlc.DotNet.Wpf/
将 VlcLib 的资源文件(
如果你想包含x86版本的,还可以将x86类库放到
在工程项目中添加引用(nuget会自动引用):
至此,VLC的运行环境便已经搭好!
首先,我们在窗体主标签中添加对Vlc命名空间的引用:
需要注意的是:
除了解析本地媒体之外,VLC可以很容易地解析网络与流媒体!
WPF 程序在窗体的
其中:
其他事件请参考
一个简易示例:
应用到 VlcLib 的时候记得去掉前面的
MediaElement
控件播放视频,只要我们的系统中拥有相应的解码器即可。即便Windows系统中没有相关的解码器,我们也可以通过安装一些解码器补丁程序(如 K-Lite Basic ),来增强和补完系统的媒体解码器。
虽然播放格式的问题可以通过第三方插件解决,然而
MediaElement
有一个致命的缺点,那就是它仅支持从本地或是网络地址来加载媒体文件,并不能通过数据流加载媒体,因此在使用时有许多的限制。好在我们可以通过使用第三方的媒体库
VlcLib
来解决这个问题,让我们的 WPF 或是 WinForm 程序实现从文件流、内存流中加载媒体文件,并且其自身就拥有丰富的解码器插件,因此并不需要第三方或是系统解码器的支持,即可播放绝大部分的视频格式!首先,我们需要获取 VlcLib
媒体库
VlcLib 采用 LGPL 协议,如果没有修改过源码,可以将其用于闭源或商业程序。我们要使用 VlcLib,只需要调用它的
libvlc.dll
、libvlccore.dll
与 plugins
文件夹。VlcLib 分为x86与x64两个版本,你可以根据需求选择,或者将两个版本集合到一起。
在 nuget 上可以找到最新 3.0+ 版的 VlcLib
https://www.nuget.org/packages/VideoLAN.LibVLC.Windows/我个人觉得 3.x 版不仅容量大,而且启动速度也比 2.x 版慢上许多,所以我推荐您使用 2.2.5.1 版。
旧版本 VlcLib 获取方式
1. 在官方网站下载旧版本的 VLC 播放器,提取里面的libvlc.dll
、libvlccore.dll
与 plugins
文件夹即可!https://www.videolan.org/vlc/releases/
2. 在官方资源站上可以找到所有的源码与VLC安装程序,按照上面的方法提取 VlcLib 库文件即可。
https://download.videolan.org/vlc/
其二,安装 VlcDotNet
,部署 VlcLib
在 nuget 上安装 Vlc.DotNet.Core
、Vlc.DotNet.Core.Interops
两个库文件,并根据你所编写的程序类型,选择安装Vlc.DotNet.Forms
、Vlc.DotNet.Wpf
库!https://www.nuget.org/packages/Vlc.DotNet.Core/
https://www.nuget.org/packages/Vlc.DotNet.Core.Interops/
https://www.nuget.org/packages/Vlc.DotNet.Forms/
https://www.nuget.org/packages/Vlc.DotNet.Wpf/
将 VlcLib 的资源文件(
libvlc.dll
、libvlccore.dll
与plugins
文件夹)丢入程序目录下的 \libvlc\win64\
文件夹下,这个路径你可以自己定义!如果你想包含x86版本的,还可以将x86类库放到
\libvlc\win32\
文件夹下!在工程项目中添加引用(nuget会自动引用):
Vlc.DotNet.Core
Vlc.DotNet.Core.Interops
Vlc.DotNet.Wpf
或是 Vlc.DotNet.Forms
至此,VLC的运行环境便已经搭好!
使用 VlcDotNet 播放视频
以下所有示例全部采用 WPF,WinForm 可直接使用工具栏中的Vlc控件,基本的操作流程应该是差不多的!首先,我们在窗体主标签中添加对Vlc命名空间的引用:
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="519" Width="693"
xmlns:Vlc="clr-namespace:Vlc.DotNet.Wpf;assembly=Vlc.DotNet.Wpf"
>
...
之后可以在主容器内添加VLC控件:<Grid Name="GridMain">
<Vlc:VlcControl Name="vlcControl" Background="Transparent" />
</Grid>
然后,我们在窗体的 Loaded
事件中进行一些基本的设置:Dim WithEvents MediaPlayer As Vlc.DotNet.Core.VlcMediaPlayer
Private Sub Window_Loaded(sender As System.Object, e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded
' 根据当前系统设置 VlcLib 的目录
Dim vlcLibDirectory = New DirectoryInfo(Path.Combine(Environment.CurrentDirectory, "libvlc", If(IntPtr.Size = 4, "win32", "win64")))
' 不准备支持32位系统的话直接用这行代码
'Dim vlcLibDirectory = New DirectoryInfo(Path.Combine(Environment.CurrentDirectory, "libvlc\win64"))
' 创建播放器实例
Dim options = New String() {}
vlcControl.SourceProvider.CreatePlayer(vlcLibDirectory, options)
' 从实例中获取播放器本体
MediaPlayer = vlcControl.SourceProvider.MediaPlayer
End Sub
再之后,请在窗体内添加一个按钮,我们使用此按钮来加载一个视频:Private Sub Button1_Click(sender As System.Object, e As System.Windows.RoutedEventArgs) Handles Button1.Click
Dim mediaPath As String = "文件路径,可以是任何常规的视频媒体,即便Windows系统内没有安装过该解码器!"
' 音量控制
MediaPlayer.Audio.Volume = 25
' 播放速度
MediaPlayer.Rate = 3.5
' 自动重播
Dim opts As String()
If MediaPlayer.Manager.VlcVersionNumber.Major < 3 Then
opts = {"input-repeat=-1"} '2.x版
Else
opts = {"input-repeat=65535"} '3.x版
End If
' 播放本地文件(参数必须是FileInfo)
MediaPlayer.SetMedia(New FileInfo(mediaPath), opts)
' 开始播放
MediaPlayer.Play()
End Sub
如果一切正常,那么你窗体上的VLC播放器便会开始启动,并且会以25%音量、3.5倍速、循环播放你所设置的视频!需要注意的是:
- VLC3的循环需要设置参数为
input-repeat=65535
,而VLC2可以设置为input-repeat=-1
。 - 音量控制似乎对 VLC2.2 以下版本无效?
- 设置媒体文件时,如果是本地文件,则必须以
FileInfo
对象包裹,否则Vlc会把它当作网络路径来解析,导致程序出错!
除了解析本地媒体之外,VLC可以很容易地解析网络与流媒体!
解析网络路径的视频
' 其他代码参考上面,只需要在播放时添加一个网络URL即可
MediaPlayer.Play("http://download.blender.org/peach/bigbuckbunny_movies/big_buck_bunny_480p_h264.mov")
播放文件流、内存流视频
' 播放内存流(注意:必要时务必清除内存流)
Dim bs As Byte() = File.ReadAllBytes(mediaPath)
MediaStream = New MemoryStream(bs)
MediaStream.Position = 0 '内存流需重定向位置
MediaPlayer.Play(MediaStream, opts)
' 播放文件流(注意:必要时务必关闭文件流)
MediaStream = New FileStream(mediaPath, FileMode.Open)
MediaPlayer.Play(MediaStream, opts)
最后需要注意的事情
结束程序前,记得关闭 VLC 播放器
不管你是用 WPF 还是 WinForm,我们本质上都是在调用 VLC 为我们提供的播放器控件,所以当我们要关闭自己的程序前,一定要记得先关闭 VLC 的播放器控件,否则程序会出现报错、或者导致内存泄漏等问题!WPF 程序在窗体的
Closing
事件中添加下面的代码即可:Private Sub MainWindow_Closing(sender As Object, e As System.ComponentModel.CancelEventArgs) Handles Me.Closing
If vlcControl IsNot Nothing Then
vlcControl.SourceProvider.Dispose()
vlcControl.Dispose()
End If
End Sub
如何获得进度条进度?如何得知视频即将播放完毕?
我将 MediaPlayer 写成Dim WithEvents MediaPlayer As Vlc.DotNet.Core.VlcMediaPlayer
,在VB中即可使用后期绑定来获取 MediaPlayer 的事件!其中:
PositionChanged
可获得视频的播放进度,但是请注意,你无法获得 100% 这个进度,最多到9x%。EndReached
在视频播放完毕时激活,但是它无法阻止视频停止,你也不能在播放完毕后重新定位视频位置。Stopped
在强制停止、关闭媒体时发生。其他事件请参考
Vlc.DotNet.Core.VlcMediaPlayer
对象。如何在媒体播放完毕前暂停、或者重新调整内容的位置?
EndReached
无法阻止VLC对于媒体的自动关闭行为,因此我们需要使用VLC的内部命令 play-and-pause
来让VLC在播放完毕后自动暂停,然后在 MediaPlayer.Paused
的暂停事件中判断当前位置是否为媒体的最后一帧内容,再决定是否要重新设置媒体的播放位置并重新播放!一个简易示例:
' 设置播放器命令参数
Dim opts As String() = {"play-and-pause"} '播放完毕后自动暂停,而不是立刻关闭媒体
MediaPlayer.SetMedia(New FileInfo(mediaPath), opts)
MediaPlayer.Play()
' 在 Paused 事件中重定位
Private Sub MediaPlayer_Paused(sender As Object, e As Vlc.DotNet.Core.VlcMediaPlayerPausedEventArgs) Handles MediaPlayer.Paused
' 在这里判断是否是最后一帧(我自己的判断方法也不完美,就不分享了)
' 重新定位并播放
MediaPlayer.Position = 0
MediaPlayer.SetPause(False)
End Sub
注意:此方法虽然可以让媒体自动重播,然而效率并不如 "input-repeat"
命令,因此不推荐使用此方法设置重播。如何获得更多的媒体信息?
' 在获取媒体信息之前,必须要先设置过媒体
MediaPlayer.SetMedia(New FileInfo(mediaPath))
MediaInfo = MediaPlayer.GetMedia
MediaInfo.Parse() '开始解析媒体数据
MsgBox(MediaInfo.Duration.ToString) '总长度
MsgBox(MediaPlayer.Length) '媒体文件总长度,ms
MsgBox(MediaPlayer.Time) '当前播放时间
MediaInfo 可以获得一些内置信息,请自行参考 Vlc.DotNet.Core.VlcMedia
。如何跳转播放位置
MediaPlayer.Time = 62 * 1000 '62s
MediaPlayer.Position = 0.12 '12%
如何切换播放、暂停视频?
MediaPlayer.SetPause(MediaPlayer.IsPlaying)
如何关闭当前的媒体并清除资源?
MediaPlayer.ResetMedia()
更多VLC内部命令行指令
https://wiki.videolan.org/VLC_command-line_help/应用到 VlcLib 的时候记得去掉前面的
--
。最后,再来贴一个完整的VLC重载流程
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="519" Width="693"
xmlns:Vlc="clr-namespace:Vlc.DotNet.Wpf;assembly=Vlc.DotNet.Wpf"
>
<Grid Name="GridMain">
<Vlc:VlcControl Name="vlcControl" Background="Transparent" />
</Grid>
</Window>
' 一个完整的重载流程
Imports System.IO
Dim WithEvents MediaPlayer As Vlc.DotNet.Core.VlcMediaPlayer
Dim WithEvents MediaInfo As Vlc.DotNet.Core.VlcMedia
Dim MediaStream As Stream
Dim MediaPath As String = ""
' 初始化控件
If vlcControl IsNot Nothing Then
GridMain.Children.Remove(vlcControl) '从容器中移除
vlcControl.Dispose()
vlcControl = Nothing
If MediaStream IsNot Nothing Then '关闭媒体流
MediaStream.Dispose()
MediaStream = Nothing
End If
'GC.Collect() 'GC回收,会拖慢速度
End If
vlcControl = New Vlc.DotNet.Wpf.VlcControl()
vlcControl.Background = Brushes.Transparent
GridMain.Children.Insert(0, vlcControl) '重新插入容器
' 重建播放器
Dim vlcLibDirectory = New DirectoryInfo(Path.Combine(Environment.CurrentDirectory, "libvlc", If(IntPtr.Size = 4, "win32", "win64")))
Dim options = New String() {}
vlcControl.SourceProvider.CreatePlayer(vlcLibDirectory, options)
' 初始化变量
MediaPlayer = vlcControl.SourceProvider.MediaPlayer
' 播放
MediaPath = "媒体路径..."
MediaPlayer.Audio.Volume = 25
MediaPlayer.Rate = 3.5
Dim opts = If(
MediaPlayer.Manager.VlcVersionNumber.Major < 3,
{"input-repeat=-1"},
{"input-repeat=65535"}
)
MediaPlayer.SetMedia(New FileInfo(MediaPath), opts)
MediaInfo = MediaPlayer.GetMedia()
MediaInfo.Parse() '解析媒体信息
MediaPlayer.Play()
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。
已有 1 条评论