WPF使用LibVLCSharp制作本地视频文件的视频播放器

1、View

cs 复制代码
<Window x:Class="CommonControls.VideoPlayer"
        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:CommonControls"
        xmlns:vlc="clr-namespace:LibVLCSharp.WPF;assembly=LibVLCSharp.WPF"
        mc:Ignorable="d" ResizeMode="NoResize" 
        WindowStartupLocation="CenterScreen" Closing="Window_Closing"
        Title="VideoPlayer" Width="1200" Height="800" WindowStyle="None" Background="Transparent">   
    <Grid>
         <vlc:VideoView x:Name="vlcPlyer"/>
    </Grid>
</Window>

2、制作播放器完整代码:

包含快进、慢放、暂停、开始和截图功能

cs 复制代码
/// <summary>
/// 监控信息
/// </summary>
public class MonitorInfo
{
    /// <summary>
    /// 摄像机IP
    /// </summary>
    public string IP { get; set; }
    /// <summary>
    /// 摄像机端口
    /// </summary>
    public string Port { get; set; }
    /// <summary>
    /// 用户名
    /// </summary>
    public string UserName { get; set; }
    /// <summary>
    /// 密码
    /// </summary>
    public string Password { get; set; }
    /// <summary>
    /// 通道号
    /// </summary>
    public string ChannelNumber { get; set; }

    /// <summary>
    /// 是否是回放
    /// </summary>
    public string IsBackPlay { get; set; }
    /// <summary>
    /// 监控名称
    /// </summary>
    public string deviceName { get; set; }
    /// <summary>
    /// 报警时间
    /// </summary>
    public DateTime alarmDateTime { get; set; }

    /// <summary>
    /// 厂家id(1:宇视 2:海康 3:大华 4:华为)
    /// </summary>
    public string manufacturerId { get; set; }

    /// <summary>
    /// 设备编码
    /// </summary>
    public string cameraCode { get; set; }

    public string deviceId { get; set; }

    public VideoType VideoType { get; set; }
}

/// <summary>
/// VideoPlayer.xaml 的交互逻辑
/// </summary>
public partial class VideoPlayer : Window, INotifyPropertyChanged
{

    #region 变量

    IBaseVideoControler _videoController = null;
    bool _isPlayingBack = false;
    VideoType _videoType;
    int _timespan = 0;
    string _path = "";

    #endregion

    #region 属性

    private string _playOrPauseSource = "pack://application:,,,/iHCRS.Resources;component/Images/PlayBack/播放@2x.png";

    /// <summary>
    /// 播放或暂停图片地址
    /// </summary>
    public string PlayOrPauseSource
    {
        get { return _playOrPauseSource; }
        set { _playOrPauseSource = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(PlayOrPauseSource))); }
    }

    private double _speed = 1;

    /// <summary>
    /// 速度
    /// </summary>
    public double Speed
    {
        get { return _speed; }
        set { _speed = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Speed))); }
    }

    private double _TotalSeconds;
    /// <summary>
    /// 所有的秒数
    /// </summary>
    public double TotalSeconds
    {
        get { return _TotalSeconds; }
        set { _TotalSeconds = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(TotalSeconds))); }
    }

    private double _SliderValue;
    /// <summary>
    /// 进度条值
    /// </summary>
    public double SliderValue
    {
        get { return _SliderValue; }
        set
        {
            _SliderValue = value;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(SliderValue)));
        }
    }

    private string _StartDateTime;

    public string StartDateTime
    {
        get { return _StartDateTime; }
        set
        {
            if (_StartDateTime != value)
            {
                if ((Convert.ToDateTime(value) >= Convert.ToDateTime(EndDateTime)) && EndDateTime != null)
                {
                    CMessageBox.Show("提示", "开始时间不能晚于结束时间!", false, this);
                }
                else
                {
                    _StartDateTime = value;
                    TotalSeconds = (Convert.ToDateTime(EndDateTime) - Convert.ToDateTime(_StartDateTime)).TotalSeconds;
                    SliderValue = 0;
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(StartDateTime)));
                    if (_StartDateTime == null || EndDateTime == null)
                        return;
                    try
                    {
                        timer?.Stop();
                        PlayBackByTime(Convert.ToDateTime(_StartDateTime), Convert.ToDateTime(EndDateTime));
                    }
                    catch (Exception ex)
                    {
                        GlobalData.logger.Error($"根据时间回放出现异常,异常信息:{ex.Message}");
                    }
                }
            }

        }
    }

    private string _EndDateTime;

    public string EndDateTime
    {
        get { return _EndDateTime; }
        set
        {
            if (_EndDateTime != value)
            {
                if ((Convert.ToDateTime(StartDateTime) >= Convert.ToDateTime(value)) && value != null)
                {
                    CMessageBox.Show("提示", "结束时间不能早于开始时间!", false, this);
                }
                else
                {
                    _EndDateTime = value;
                    TotalSeconds = (Convert.ToDateTime(_EndDateTime) - Convert.ToDateTime(StartDateTime)).TotalSeconds;
                    SliderValue = 0;
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(EndDateTime)));
                    if (_EndDateTime == null || StartDateTime == null)
                        return;
                    try
                    {
                        timer?.Stop();
                        PlayBackByTime(Convert.ToDateTime(StartDateTime), Convert.ToDateTime(_EndDateTime));
                    }
                    catch (Exception ex)
                    {
                        GlobalData.logger.Error($"根据时间回放出现异常,异常信息:{ex.Message}");
                    }
                }
            }
        }
    }

    private bool _IsStartTimeDropDownOpen;

    public bool IsStartTimeDropDownOpen
    {
        get { return _IsStartTimeDropDownOpen; }
        set { _IsStartTimeDropDownOpen = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsStartTimeDropDownOpen))); }
    }

    private bool _IsEndTimeDropDownOpen;

    public bool IsEndTimeDropDownOpen
    {
        get { return _IsEndTimeDropDownOpen; }
        set { _IsEndTimeDropDownOpen = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsEndTimeDropDownOpen))); }
    }


    public event PropertyChangedEventHandler PropertyChanged;

    private bool IsFinishPlay = false;

    private LibVLCSharp.Shared.MediaPlayer _mediaPlayer;

    #endregion

    public VideoPlayer(string videoTitle, string path, VideoType videoType, int timespan)
    {
        _timespan = timespan;
        _videoType = videoType;
        _path = path;
        InitializeComponent();
        this.DataContext = this;
        videoNameTB.Text = videoTitle;
        this.Loaded += PlayerWindow_Loaded;
    }

    private void PlayerWindow_Loaded(object sender, RoutedEventArgs e)
    {
        //StartDateTime = DateTime.Now.ToString("yyyy-MM-dd 00:00:00");
        StartDateTime = "2023/03/20 13:56:52";
        ///设置enddatetime的时候已经执行了回放,所以加载的时候不再执行回放。
        EndDateTime = "2023/03/20 13:57:49"; //DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
        TotalSeconds = (Convert.ToDateTime(EndDateTime) - Convert.ToDateTime(StartDateTime)).TotalSeconds;
        TotalSeconds = _timespan;
        IsStartTimeDropDownOpen = false;
        IsEndTimeDropDownOpen = false;
    }

    private Timer timer;

    /// <summary>
    /// 根据开始和结束时间进行回放
    /// </summary>
    /// <param name="startTime"></param>
    /// <param name="endTime"></param>
    private void PlayBackByTime(DateTime startTime, DateTime endTime)
    {
        try
        {
            vlcPlyer.MediaPlayer = new LibVLCSharp.Shared.MediaPlayer(VlcLibInit.Instance.VlcLib)
            {
                Volume = 0,
                EnableHardwareDecoding = true
            };
            var fromType = FromType.FromLocation;
            if (_videoType == VideoType.LocalVideo)
            {
                fromType = FromType.FromPath;
            }
            var m = new Media(VlcLibInit.Instance.VlcLib, _path, fromType);
            //一下是设置相应的参数,播放rtsp流的生活,设置和不设置是有很大差距的,大家可以注释代码体验一下
            m.AddOption(":rtsp-tcp");
            m.AddOption(":clock-synchro=0");
            m.AddOption(":live-caching=0");
            m.AddOption(":network-caching=100");
            m.AddOption(":file-caching=100");
            m.AddOption(":grayscale");
            m.AddOption(":avcodec-hw=any");
            _mediaPlayer = vlcPlyer.MediaPlayer;
            _mediaPlayer.Play(m);
        }
        catch (Exception ex)
        {
            GlobalData.logger.Error($"按时间回放出现异常,异常信息:{ex.Message}");
        }
        SetVideoPlayState();
    }

    private void SetVideoPlayState()
    {
        Speed = 1;
        _isPlayingBack = true;
        PlayOrPauseSource = "pack://application:,,,/iHCRS.Resources;component/Images/PlayBack/暂停@2x.png";
        if (timer != null)
        {
            timer.Stop();
            timer.Dispose();
            timer = null;
        }
        timer = new Timer();
        timer.Interval = 1000;   //时间间隔为一秒
        timer.Tick += new EventHandler(timer_Tick);
        timer.Start();
    }

    private void timer_Tick(object sender, EventArgs e)
    {
        if (SliderValue > TotalSeconds)
        {
            _mediaPlayer.Stop();
            PlayOrPauseSource = "pack://application:,,,/iHCRS.Resources;component/Images/PlayBack/播放@2x.png";
            _isPlayingBack = false;
            backOffBtn.IsEnabled = false;
            fastForwardBtn.IsEnabled = false;
            snapBtn.IsEnabled = false;
            timer?.Stop();
            timer?.Dispose();
            IsFinishPlay = true;
            return;
        }
        SliderValue++;
    }

    private void headerGrid_MouseDown(object sender, MouseButtonEventArgs e)
    {
        if (e.LeftButton == MouseButtonState.Pressed)
            this.DragMove();
    }

    private void Image_MouseDown(object sender, MouseButtonEventArgs e)
    {
        this.Close();
    }

    private void allScreenBtn_Click(object sender, RoutedEventArgs e)
    {
        this.WindowState = this.WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized;
    }

    /// <summary>
    /// 截图
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void snapBtn_Click(object sender, RoutedEventArgs e)
    {
        if (!_isPlayingBack)
        {
            return;
        }
        var folderPath = System.Windows.Forms.Application.StartupPath + "\\SnapshotPictures";
        if (!Directory.Exists(folderPath))
        {
            DirectoryInfo directoryInfo = new DirectoryInfo(folderPath);
            directoryInfo.Create();
        }
        var filePath = folderPath + $"\\{DateTime.Now.ToString("yyyyMMddHHmmss")}.jpg";

        // 创建一个PngBitmapEncoder并添加帧
        PngBitmapEncoder encoder = new PngBitmapEncoder();
        RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap(
             (int)vlcPlyer.ActualWidth,
             (int)vlcPlyer.ActualHeight,
             96, 96,
             PixelFormats.Pbgra32);

        // 渲染vlcPlayer到RenderTargetBitmap
        renderTargetBitmap.Render(vlcPlyer);
        encoder.Frames.Add(BitmapFrame.Create(renderTargetBitmap));
        using (FileStream fileStream = new FileStream(filePath, FileMode.Create))
        {
            encoder.Save(fileStream);
        }
        CMessageBox.Show("提示", $"截图成功,保存路径:{filePath}");
    }

    /// <summary>
    /// 慢放
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void backOffBtn_Click(object sender, RoutedEventArgs e)
    {
        if (timer == null)
            return;
        if (Speed > 1)
        {
            if (_isPlayingBack)
            {
                Speed = Speed / 2;
                timer.Interval = timer.Interval * 2;
                _mediaPlayer.SetRate((float)Speed);
            }
        }
    }

    /// <summary>
    /// 快放
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void fastForwardBtn_Click(object sender, RoutedEventArgs e)
    {
        if (timer == null)
            return;
        if (Speed < 16)
        {
            if (_isPlayingBack)
            {
                Speed = Speed * 2;
                timer.Interval = timer.Interval / 2;
                _mediaPlayer.SetRate((float)Speed);
            }
        }
    }

    /// <summary>
    /// 播放或暂停
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void playOrPauseBtn_Click(object sender, RoutedEventArgs e)
    {
        if (_isPlayingBack)
        {
            _mediaPlayer.Pause();
            PlayOrPauseSource = "pack://application:,,,/iHCRS.Resources;component/Images/PlayBack/播放@2x.png";
            _isPlayingBack = false;
            backOffBtn.IsEnabled = false;
            fastForwardBtn.IsEnabled = false;
            snapBtn.IsEnabled = false;
            timer?.Stop();
        }
        else
        {
            if (IsFinishPlay && SliderValue >= TotalSeconds)//播放完毕的情况下再次点击播放则从头开始播放
            {
                SliderValue = 0;
            }
            _isPlayingBack = true;
            backOffBtn.IsEnabled = true;
            fastForwardBtn.IsEnabled = true;
            snapBtn.IsEnabled = true;
            _mediaPlayer.Play();
            timer.Start();
            PlayOrPauseSource = "pack://application:,,,/iHCRS.Resources;component/Images/PlayBack/暂停@2x.png";
        }
    }

    private void Window_Closing(object sender, CancelEventArgs e)
    {
        timer?.Stop();
        timer?.Dispose();
        _mediaPlayer?.Stop();
        _mediaPlayer?.Dispose();
    }

    private void Slider_DragCompleted(object sender, System.Windows.Controls.Primitives.DragCompletedEventArgs e)
    {
        _mediaPlayer.Time = (long)SliderValue * 1000;
    }

    private void slider_MouseDown(object sender, MouseButtonEventArgs e)
    {
        var value = (e.GetPosition(slider).X / slider.ActualWidth) * (slider.Maximum - slider.Minimum);
        SliderValue = value;
        _mediaPlayer.Time = (long)SliderValue * 1000;
    }

    private void Close_Click(object sender, RoutedEventArgs e)
    {
        this.Close();
    }
}
相关推荐
darkdragonking4 小时前
FLV视频封装格式详解
音视频
元争栈道5 小时前
webview和H5来实现的android短视频(短剧)音视频播放依赖控件
android·音视频
元争栈道7 小时前
webview+H5来实现的android短视频(短剧)音视频播放依赖控件资源
android·音视频
晚安苏州7 小时前
WPF DataTemplate 数据模板
wpf
MediaTea11 小时前
Pr:音频仪表
音视频
桃园码工11 小时前
13_HTML5 Audio(音频) --[HTML5 API 学习之旅]
音视频·html5·audio
cuijiecheng201816 小时前
音视频入门基础:MPEG2-TS专题(21)——FFmpeg源码中,获取TS流的视频信息的实现
ffmpeg·音视频
γ..17 小时前
基于MATLAB的图像增强
开发语言·深度学习·神经网络·学习·机器学习·matlab·音视频
cuijiecheng201817 小时前
音视频入门基础:AAC专题(13)——FFmpeg源码中,获取ADTS格式的AAC裸流音频信息的实现
ffmpeg·音视频·aac
悟纤20 小时前
Suno Api V4模型无水印开发「高清音频WAV下载」 —— 「Suno Api系列」第6篇
音视频·suno·suno v4·suno ai