20230911 完善了開關(guān)屏,釋放內(nèi)存等代碼
前段時間在 WPF 中實現(xiàn)了【MediaElement + 定時器】的自動輪播。用了一段時間之后,沒啥大問題,但是發(fā)現(xiàn),個別 MP4 視頻,在播放的時候,有卡頓的現(xiàn)象,看網(wǎng)上說是 MediaElement 解碼的問題,建議使用 VLC,所以,再次改造,用 VLC 代替 MediaElement 來試試。
很多教程,都是使用二次封裝 VLC 的庫,但我不想使用二次封裝的,所以這里直接使用官方的庫(以下地址都是官方地址,內(nèi)容是英文的,暫時沒有中文翻譯)。
1. 添加引用
<ItemGroup>
<PackageReference Include="LibVLCSharp.WPF" Version="3.7.0" />
<PackageReference Include="VideoLAN.LibVLC.Windows" Version="3.0.18" />
</ItemGroup>
很多教程,都讓安裝最新的 VLC 播放器,然后去安裝目錄找 DLL 什么的,其實沒必要,官方有相應(yīng)的庫,直接在 Nuget 添加引用就好了(VideoLAN.LibVLC.Windows)。
2. WPF 文件
// 就是添加了 VLC 的命名空間,同時添加了 VLC 的控件(VideoView)
<Window x:Class="WpfVlcDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfVlcDemo"
xmlns:vlc="clr-namespace:LibVLCSharp.WPF;assembly=LibVLCSharp.WPF"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<vlc:VideoView x:Name="Wrapper" />
</Grid>
</Window>
3. CS 文件
using LibVLCSharp.Shared;
using LibVLCSharp.WPF;
using System;
using System.IO;
using System.Linq;
using System.Timers;
using System.Windows;
namespace WpfVlcDemo;
public partial class MainWindow : Window
{
private readonly Timer _timerPlay, _timerON, _timerOFF;
private readonly TimeOnly _timeON, _timeOFF;
private string[] _videos;
private readonly LibVLC _libVlc;
private readonly MediaPlayer _player;
private Media _media, _mediaDefault;
private int _idx = 0;
private bool _isDefault = false;
public MainWindow()
{
InitializeComponent();
// 模擬開/關(guān)屏?xí)r間
_timeON = TimeOnly.Parse("21:30");
_timeOFF = TimeOnly.Parse("21:35");
#region 初始化計時器
// 開屏計時器
_timerON = new() { Interval = 1000 };
_timerON.Elapsed += TimerON_Elapsed;
// 關(guān)屏計時器
_timerOFF = new() { Interval = 1000 };
_timerOFF.Elapsed += TimerOFF_Elapsed;
// 素材播放計時器
_timerPlay = new() { Interval = 10 * 1000 };
_timerPlay.Elapsed += (sender, e) =>
{
(sender as Timer).Stop(); // 停止播放計時
_player.Play(_media);
};
#endregion
#region 初始化并加載播放器
// 初始化播放器
_libVlc = new();
_player = new(_libVlc);
_player.Opening += (sender, e) => _media?.Dispose(); // 釋放當(dāng)前播放素材
_player.Playing += Player_Playing;
// 加載播放器
Wrapper.Loaded += (sender, e) =>
{
(sender as VideoView).MediaPlayer = _player;
_timerON.Start(); // 開啟開屏計時器
};
#endregion
#region 獲取素材
// 獲取全部待播放的素材
Loaded += (sender, e) =>
{
_videos = Directory.GetFiles("<素材路徑>");
_mediaDefault = new(_libVlc, "<默認(rèn)素材路徑>");
};
#endregion
}
#region 開屏計時器事件
private void TimerON_Elapsed(object sender, ElapsedEventArgs e)
{
var now = TimeOnly.FromDateTime(DateTime.Now);
if (now < _timeON) // 未到開屏?xí)r間
{
if (!_player.IsPlaying) // 播放默認(rèn)素材
{
_isDefault = true;
_player.Play(_mediaDefault);
}
return;
}
_timerON.Dispose(); // 釋放開屏計時器
if (now > _timeOFF) // 超過關(guān)屏?xí)r間
{
// 播放默認(rèn)素材
_isDefault = true;
_player.Play(_mediaDefault);
return;
}
_isDefault = false;
_timerOFF.Start(); // 開啟關(guān)屏計時器
// 開始播放
_media = new(_libVlc, _videos[_idx++]);
_player.Play(_media);
}
#endregion
#region 關(guān)屏計時器事件
private void TimerOFF_Elapsed(object sender, ElapsedEventArgs e)
{
var now = TimeOnly.FromDateTime(DateTime.Now);
if (now < _timeOFF)
{
return;
}
_timerOFF.Dispose(); // 釋放關(guān)屏計時器
#region 方案一:播放默認(rèn)素材
_isDefault = true;
_player.Play(_mediaDefault);
#endregion
#region 方案二:停止播放
//_timerPlay.Stop(); // 停止播放計時
//// 停止播放,并釋放播放器內(nèi)的素材
//_player.Media.Dispose();
//_player.Stop();
#endregion
}
#endregion
#region 播放器事件
private void Player_Playing(object sender, EventArgs e)
{
if (_isDefault)
{
return;
}
_timerPlay.Start(); // 開啟播放計時
if (_idx == _videos.Length)
{
_idx = 0;
}
_media = new(_libVlc, _videos[_idx++]); // 準(zhǔn)備下一個素材
}
#endregion
protected override void OnClosed(EventArgs e)
{
_media?.Dispose(); // 釋放最后一個播放的素材
_mediaDefault?.Dispose(); // 釋放默認(rèn)素材
_player.Stop();
_player.Dispose();
_libVlc.Dispose();
Wrapper.Dispose();
_timerPlay.Dispose();
base.OnClosed(e);
}
}
至此,代碼就全部完畢了,可以直接運行看效果了。
特別說明:20230911 已完善了開關(guān)屏、釋放內(nèi)存等相關(guān)代碼,并適量優(yōu)化了一下