首页 > 其他分享 >基于WPF开发视频播放器

基于WPF开发视频播放器

时间:2024-11-18 11:57:15浏览次数:1  
标签:播放器 视频 media MediaElement 所示 WPF 播放 Model

在实际应用中,视频播放功能在很多软件中都会用到,将音频和视频集成到应用程序中不仅可以增强用户体验,还能起到事半功倍的效果。今天本文以一个简单的小例子,简述如何通过WPF中的MediaElement开发视频播放器,仅供学习分享使用,如有不足之处,还请指正!

涉及知识点

在本实例中,开发视频播放器,主要用到MediaElement控件,而MediaElement 是受 Layout 支持的 UIElement,并可用作许多控件的内容。涉及知识点如下:

  • LoadedBehavior,UnloadedBehavior 主要用于控制IsLoaded属性为true和false时的视频播放行为,即视频加载成功和没有加载时的播放行为。此两个属性为MediaState类型,共有五种值供选择,Manual,Play,Stop,Pause,Close。 例如,默认 LoadedBehavior 为 Play,默认 UnloadedBehavior 为 Close。 这意味着,一旦加载 MediaElement 并且预滚完成,媒体开始播放。 一旦播放完毕,媒体就会关闭并且发布所有媒体资源。
  • Source,主要用于指定视频播放源路径,Uri类型。
  • Play、Pause 和 Stop 方法分别用于播放、暂停和停止媒体。 更改 MediaElement 的 Position 属性可让你在媒体中跳转。 最后,Volume 和 SpeedRatio 属性用于调整媒体的音量和播放速度。

注意:MediaElement 的 LoadedBehavior 属性必须设置为 Manual 才能以交互方式停止、暂停和播放媒体。

依赖库

所谓麻雀虽小,五脏俱全,本实例虽然是一个视频播放器的小例子,但是也遵循MVVM的设计思想。主要采用CommunityToolkit.Mvvm,可通过Nuget包管理器进行安装,如下所示:

关于CommunityToolkit.Mvvm的使用方法,可参考相关文档,在此不在赘述。

UI布局

虽然MediaElement控件可以实现视频的播放,但是要实现完整的功能,还需要其他的页面布局控件。在本实例中,主要分为三个组成部分:

  • 播放区,主要用于显示视频的播放内容,时长,播放进度等内容
  • 视频列表,主要用于显示播放的视频的列表,以及手动添加视频到列表中,双击列表项进行播放等。
  • 视频控制,主要用于控制视频的播放,暂停,停止,速度,音量等内容。

视频播放器UI源码如下所示:

<Window x:Class="DemoMedia.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:i="http://schemas.microsoft.com/xaml/behaviors"
        xmlns:local="clr-namespace:DemoMedia"
        mc:Ignorable="d"
        Title="Windows Media Player" Height="450" Width="800" Background="AliceBlue">
    <Window.Resources>
        <ResourceDictionary Source="\Resources\Icons.xaml"></ResourceDictionary>
    </Window.Resources>
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="Loaded">
            <i:InvokeCommandAction Command="{Binding LoadedCommand}" PassEventArgsToCommand="True"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition Width="Auto" MinWidth="150" MaxWidth="200"></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition></RowDefinition>
                <RowDefinition Height="Auto"></RowDefinition>
                <RowDefinition Height="Auto"></RowDefinition>
            </Grid.RowDefinitions>
            <Border Grid.Row="0" Background="AliceBlue"></Border>
            <MediaElement Grid.Row="0" Name="mediaElement" MinHeight="300" MinWidth="300"
                          Source="{Binding Model.CurSource}"
                          LoadedBehavior="Manual" UnloadedBehavior="Manual" Stretch="Uniform">
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="MediaOpened">
                        <i:InvokeCommandAction Command="{Binding MediaOpenedCommand}"/>
                    </i:EventTrigger>
                    <i:EventTrigger EventName="MediaEnded">
                        <i:InvokeCommandAction Command="{Binding MediaEndedCommand}"/>
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </MediaElement>
            <Button Command="{Binding PlayCommand}" HorizontalAlignment="Center" VerticalAlignment="Center" Opacity="0.6" Visibility="{Binding Model.PlayButtonVisibility}" Cursor="Hand">
                <Button.Template>
                    <ControlTemplate>
                        <Border Background="AliceBlue">
                            <Path Data="{StaticResource play}" Fill="#3259CE" Stroke="#3259CE" Width="30" Height="30" Stretch="Fill" ></Path>
                        </Border>
                    </ControlTemplate>
                </Button.Template>
            </Button>
            <Grid Grid.Row="1" VerticalAlignment="Bottom" Margin="2 0 2 4">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto"></ColumnDefinition>
                    <ColumnDefinition></ColumnDefinition>
                    <ColumnDefinition Width="Auto"></ColumnDefinition>
                </Grid.ColumnDefinitions>
                <TextBlock Grid.Column="0" Text="00:00" VerticalAlignment="Bottom"></TextBlock>
                <ProgressBar Grid.Column="1"  Height="5" Background="Black"  Foreground="White" Value="{Binding Model.Position}" Minimum="0" Maximum="{Binding Model.MediaMaximum}"></ProgressBar>
                <StackPanel Grid.Column="2" Orientation="Horizontal" VerticalAlignment="Bottom">
                    <!--<TextBlock  Text="时长:"></TextBlock>-->
                    <TextBlock  Text="{Binding Model.TimeLen}"></TextBlock>
                </StackPanel>
            </Grid>
            <StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Center">
                <Button x:Name="btnPlay" Margin="5" Command="{Binding PlayCommand}">
                    <Button.Template>
                        <ControlTemplate>
                            <Border Background="AliceBlue">
                                <Path Data="{StaticResource play}" Fill="#3259CE" Stroke="#3259CE" Width="30" Height="30" Stretch="Fill"></Path>
                            </Border>
                        </ControlTemplate>
                    </Button.Template>
                </Button>
                <Button x:Name="btnPause" Margin="5"  Command="{Binding PauseCommand}">
                    <Button.Template>
                        <ControlTemplate>
                            <Border Background="AliceBlue">
                                <Path Data="{StaticResource pause}" Fill="#3259CE" Stroke="#3259CE" Width="30" Height="30" Stretch="Fill"></Path>
                            </Border>
                        </ControlTemplate>
                    </Button.Template>
                </Button>
                <Button x:Name="btnStop" Margin="5"  Command="{Binding StopCommand}">
                    <Button.Template>
                        <ControlTemplate>
                            <Border Background="AliceBlue">
                                <Path Data="{StaticResource stop}" Fill="#3259CE" Stroke="#3259CE" Width="30" Height="30" Stretch="Fill"></Path>
                            </Border>
                        </ControlTemplate>
                    </Button.Template>
                </Button>
                <TextBlock Foreground="#3259CE" VerticalAlignment="Center" Margin="5" Text="音量"></TextBlock>
                <Slider Name="volumeSlider" VerticalAlignment="Center" Value="{Binding ElementName=mediaElement, Path=Volume, Mode=TwoWay}" 
                        Minimum="0" Maximum="1" Width="70"/>
                <TextBlock Foreground="#3259CE" Margin="5"  VerticalAlignment="Center" Text="速度"></TextBlock>
                <Slider Name="speedRatioSlider" VerticalAlignment="Center"  Value="{Binding ElementName=mediaElement, Path=SpeedRatio, Mode=TwoWay}"  Width="70" />
            </StackPanel>
        </Grid>
        <GridSplitter Grid.Column="0" HorizontalAlignment="Right" Width="2"></GridSplitter>
        <Grid Grid.Column="1" Background="AliceBlue">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" MinHeight="30"></RowDefinition>
                <RowDefinition></RowDefinition>
            </Grid.RowDefinitions>
            <Border Background="Transparent" BorderBrush="White" BorderThickness="1" Grid.Row="0"></Border>
            <Grid Grid.Row="0" Margin="2">
                <TextBlock Text="播放列表" VerticalAlignment="Center" HorizontalAlignment="Left"></TextBlock>
                <Button x:Name="btnOpen" Width="18" Height="18" Command="{Binding BrowserCommand}" Margin="5" HorizontalAlignment="Right">
                    <Button.Template>
                        <ControlTemplate>
                            <Border Background="AliceBlue">
                                <Path Data="{StaticResource browser}" Stroke="#27A2DF" Fill="White" Width="18" Height="18" Stretch="Fill"></Path>
                            </Border>
                        </ControlTemplate>
                    </Button.Template>
                </Button>
            </Grid>
            <ListView Grid.Row="1" Margin="2" ItemsSource="{Binding Model.Movies}" BorderThickness="0" SelectionMode="Single" Background="AliceBlue">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <TextBlock Text="{Binding Id, StringFormat='[00]'}" Margin="2 3"></TextBlock>
                            <TextBlock Text="{Binding Name}" Margin="3 3" ToolTip="{Binding Url}"></TextBlock>
                        </StackPanel>
                    </DataTemplate>
                </ListView.ItemTemplate>
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="MouseDoubleClick">
                        <i:InvokeCommandAction Command="{Binding MouseDoubleCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListView}, Path=SelectedItem}"/>
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </ListView>
        </Grid>
    </Grid>
</Window>

在本实例中,为了UI美观,所有按钮都采用图标显示,而图标的实现方式采用几何图形,具体实现方式可参考相关文章。

核心源码

在本实例中,业务逻辑和UI分离,主要实现手动添加视频,及视频的播放,暂停,停止,音量,进度等功能。

浏览视频并加入到播放列表,如下所示:

private void Browser()
{
	OpenFileDialog dialog = new OpenFileDialog();
	dialog.Title = "请选择要播放的影片";
	dialog.Filter = "MP4|*.mp4";
	dialog.Multiselect = true;
	if (dialog.ShowDialog()==true)
	{
		var files=dialog.FileNames;
		foreach (var file in files)
		{
			var maxId = this.Model.Movies.Count>0 ? this.Model.Movies.Max(x => x.Id):0;
			if (this.Model.Movies.FirstOrDefault(item => item.Url == file) == null)
			{
				this.Model.Movies.Add(new Movie()
				{
					Id = maxId + 1,
					Name = Path.GetFileNameWithoutExtension(file),
					Url = file
				});
			}
		}
	}
}

视频播放功能,开始播放后,单独打开一个线程,用来刷新播放的进度,如下所示:

private void Play()
{
	//影片播放,如果没有,则打开选择文件夹
	if (this.Model.CurMovie == null)
	{
		this.Browser();
		if (this.Model.Movies.Count < 1)
		{
			return;
		}
		this.Model.CurMovie = this.Model.Movies.Last();
	}
	this.Model.CurSource = new Uri(this.Model.CurMovie.Url, UriKind.RelativeOrAbsolute);
	if (this.media.NaturalDuration != Duration.Automatic && this.media.Position.TotalSeconds == this.media.NaturalDuration.TimeSpan.TotalSeconds)
	{
		this.media.Position=new TimeSpan(0,0,0);
	}
	this.media.Play();
	this.IsRunning = true;
	this.Model.PlayButtonVisibility = Visibility.Collapsed;
	//
	this.mediaTask = Task.Run(() =>
	{
		while (this.IsRunning)
		{
			Application.Current.Dispatcher.Invoke(() =>
			{
				this.Model.Position = this.media.Position.TotalSeconds;
			});
			Thread.Sleep(100);
		}
	});
}

注意,MediaElement的Position并非依赖属性,无法进行绑定,所以采用后台线程刷新的方式进行实现。

视频暂停功能,通过MediaElement的Pause方法即可控制视频的暂停,如下所示:

private void Pause()
{
	if (this.Model.CurMovie == null)
	{
		return;
	}
	this.media.Pause();
	this.IsRunning = false;
}

视频停止功能,通过MediaElement的Stop方法即可控制视频的停止,如下所示:

private void Stop()
{
	if (this.Model.CurMovie == null)
	{
		return;
	}
	this.media.Stop();
	this.IsRunning= false;
}

注意,暂停功能是将播放位置保持在当前位置;停止功能是将视频的播放位置重置到初始位置。

视频打开事件,即当视频开始时触发的路由事件,如下所示:

private void MediaOpened()
{
	if (this.media.NaturalDuration.TimeSpan.TotalMinutes < 60)
	{
		this.Model.TimeLen = this.media.NaturalDuration.TimeSpan.ToString(@"mm\:ss");
	}
	else
	{
		this.Model.TimeLen = this.media.NaturalDuration.TimeSpan.ToString(@"hh\:mm\:ss");
	}
	this.Model.MediaMaximum = this.media.NaturalDuration.TimeSpan.TotalSeconds;
}

注意:在这里,视频开始时,初始化播放时长等内容。

视频结束事件,当视频播放结束时触发的路由事件,如下所示:

private void MediaEnded()
{
	this.Model.PlayButtonVisibility = Visibility.Visible;
	this.IsRunning = false;
}

注意,视频播放结束时,将播放状态置为flase,不在监控播放位置。

视频播放器效果

视频播放器初始化页面,如下图所示:

添加视频到播放列表,如下所示:

视频播放效果截图,如下所示:

源码下载

WPF版本的视频播放器,可通过两种方式获取源码:

1. 关注“老码识途”公众号,并回复关键字“WMEDIA”进行获取,如下所示:

2. 通过Gitee仓库【下载网址:https://gitee.com/ahsiang/wpf-media】进行下载,如下所示:

以上就是《基于WPF开发视频播放器》的全部内容,旨在抛砖引玉,一起学习,共同进步!

标签:播放器,视频,media,MediaElement,所示,WPF,播放,Model
From: https://www.cnblogs.com/hsiang/p/18550163

相关文章

  • ISUP协议视频平台EasyCVR视频融合平台与4G/5G应急布控球在多场景中的智能联动
    随着科技的飞速发展,视频监控技术已经成为公共安全、交通管理、城市管理等领域不可或缺的一部分。在这一背景下,ISUP协议视频平台EasyCVR与应急布控球的结合使用,为各行各业带来了更为高效、智能的监控解决方案。EasyCVR平台是一款具有强大拓展性、灵活视频能力和轻便部署的安防视......
  • 伯索云学堂视频课件课程下载工具,如何在电脑端下载伯索云学堂视频课程课件资料PDF,PPT
    一.安装伯索云课程下载器1.获取学无止下载器https://www.xuewuzhi.cn/plaso_downloader2.下载安装后,然后点击桌面快捷方式运行即可。注意:杀毒软件可能会阻止外部exe文件运行,并将其当做成病毒,直接添加信任即可,本软件绝对没有木马病毒。二.使用说明1.学无止下载器介绍学无......
  • 短视频全自动智能处理工具
    一款短视频全自动智能处理APP,它提供多素材混剪、一键解析无水印视频等功能,助力创作者提高原创度。同时,软件还支持针对单个片段完成镜像处理,并支持保存部分场景片段镜像处理后的完整视频。......
  • 程序设计2596基于ASP.NET的滑雪网站的设计与实现【源码+讲解视频】滑雪产品租赁网站/
    项目包含:源码、讲解视频、说明文档,部署录像开发环境开发工具:VisualStudio2010或以上版本数据库:SQLServer2005或以上版本开发语言:c#操作系统:windows7或以上浏览器:GoogleChrome(推荐)、Edge、360浏览器系统用户分为:管理员、普通用户界面设计......
  • 视频流——背后技术介绍
    文章目录前言一、视频流的工作原理1.视频采集与编码2.视频存储与传输4.视频播放与解码二、视频流的类型1.直播流(LiveStreaming)2.点播流(VOD,VideoOnDemand)三、视频流的关键技术1.带宽与延迟2.自适应比特率(ABR,AdaptiveBitrateStreaming)3.缓存机制四、常......
  • 海康视频监控云台位置切换与拍照图片下载
    以下是一篇关于如何通过API控制摄像头并获取照片的文章。文章详细介绍了整个过程,包括设置摄像头位置、获取照片以及保存照片的步骤。如何通过API控制摄像头并获取照片引言随着物联网技术的发展,摄像头在各种应用场景中变得越来越重要,从家庭安全监控到工业自动化,再到智能交......
  • WPF ItemsControl.AlternationIndex AlternationCount
    <StyleTargetType="{x:TypeControl}"x:Key="lbxStyle"><Style.Triggers><TriggerProperty="ItemsControl.AlternationIndex"Value="0"><SetterProperty="Background&quo......
  • WPF Static ToolBar.ButtonStyleKey
    <Windowx:Class="WpfApp33.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.......
  • 【视频讲解】Python深度神经网络DNNs-K-Means(K-均值)聚类方法在MNIST等数据可视化对比
    全文链接:https://tecdat.cn/?p=38289原文出处:拓端数据部落公众号分析师:CucuSun近年来,由于诸如自动编码器等深度神经网络(DNN)的高表示能力,深度聚类方法发展迅速。其核心思想是表示学习和聚类可以相互促进:好的表示会带来好的聚类效果,而好的聚类为表示学习提供良好的监督信号。关......
  • WPF style BasedOn base style
    <Windowx:Class="WpfApp32.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.......