WPF 實現(xiàn)圖片/視頻自動輪播(VLC/定時器)

20230911 完善了開關(guān)屏,釋放內(nèi)存等代碼

前段時間在 WPF 中實現(xiàn)了【MediaElement + 定時器】的自動輪播。用了一段時間之后,沒啥大問題,但是發(fā)現(xiàn),個別 MP4 視頻,在播放的時候,有卡頓的現(xiàn)象,看網(wǎng)上說是 MediaElement 解碼的問題,建議使用 VLC,所以,再次改造,用 VLC 代替 MediaElement 來試試。

前一篇:WPF 實現(xiàn)圖片/視頻自動輪播(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)化了一下

前一篇:WPF 實現(xiàn)圖片/視頻自動輪播(MediaElement/定時器)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容