C#(三)—— WPF播放视频以及GIF

caroly 2020年07月20日 159次浏览

MediaElement

『MediaElement』播放视频时间长会出现卡顿问题,不建议使用。

<Grid Background="Black" x:Name="grid">
    <MediaElement x:Name="mediaElement" LoadedBehavior="Manual" UnloadedBehavior="Manual" MediaEnded="MediaPlayer_MediaOpened" Stretch="Fill" Loaded="MediaElement_Loaded" Visibility="Visible" />
</Grid>
  • LoadedBehavior: 必须设定为Manual,才能以互动方式使用PlayPauseStop方法来控制媒体。
  • UnloadedBehavior: 在卸载媒体时发生,这可确保默认情况下释放所有媒体资源。
  • MediaEnded: 媒体播放到末尾时所触发的事件。
  • Loaded: 对元素进行布局、呈现,且可将其用于交互时触发的事件。此处为对包含MediaElement控件的窗口使用软件渲染。

播放单一视频

『MediaElement』播放视频较为简单,使用『Source』设置媒体源即可:

mediaElement.IsMuted = false;    	     // 视频有声音
mediaElement.Volume = 0.5;			     // 设置声音大小	
mediaElement.Source = new Uri(path);
mediaElement.Play();

注:其中,path为视频资源的绝对路径


播放视频列表

先获取所有要播放的视频路径,再在『MediaEnded』事件中处理:

List<string> list = new List<string>();		// 全局变量
List<string> list1 = new List<string>();	// 全局变量
private void GetAllVideo()
{
    try
    {
        list.Clear();
        list1.Clear();
        List<string> video1 = GetFileListWithExtend(new DirectoryInfo(path), "*.mp4");
        List<string> video2 = GetFileListWithExtend(new DirectoryInfo(path), "*.avi");
        for(int i= 0; i< (video1.Count> video2.Count? video1.Count: video2.Count); i++)
        {
            if(i< video1.Count)
            {
                list.Add(video1[i]);
            }
            if (i< video2.Count)
            {
                list.Add(video2[i]);
            }
        }
        list.ForEach(i => list1.Add(i));
    }
    catch(Exception e)
    {
        _log.Error(e.Message);
    }
}
private void MediaPlayer_MediaOpened(object sender, RoutedEventArgs e)
{
    try
    {
        if (list1.Count > 1)
        {
            list1.RemoveAt(0);
            mediaElement.Source = new Uri(list1[0]);
        }
        else
        {
            mediaElement.Source = new Uri(list[0]);
            list1.RemoveAt(0);
            list.ForEach(i => list1.Add(i));
        }
        mediaElement.Play();
    }
    catch(Exception e)
    {
        _log.Error(e.Message);
    }
}
public static List<string> GetFileListWithExtend(DirectoryInfo directory, string pattern)
{
    List<string> pathList = new List<string>();
    string result = String.Empty;
    if (directory.Exists || pattern.Trim() != string.Empty)
    {

        foreach (FileInfo info in directory.GetFiles(pattern))
        {
            result = info.FullName.ToString();
            pathList.Add(result);
        }
    }
    return pathList;
}

显示GIF

『Image』只会显示『Gif』的第一帧,可以用『MediaElement』来显示:

mediaElement.Source = new Uri(path + gifName + ".gif");
mediaElement.Play();

AxWindowsMediaPlayer

添加引用:

AxInterop.WMPLib

Interop.WMPLib

<Window 
        ... ...
        xmlns:awmp="clr-namespace:AxWMPLib;assembly=AxInterop.WMPLib"
        ... ...>

    <Grid Background="Black" x:Name="grid">
        <WindowsFormsHost x:Name="media" Width="1920" Height="1080">
            <awmp:AxWindowsMediaPlayer x:Name="mediaPlayer" Dock="Fill"/>
        </WindowsFormsHost>
    </Grid>
</Window>

参数设置如下:

public AxWMPLib.AxWindowsMediaPlayer player = null;   // 全局变量
player = media.Child as AxWMPLib.AxWindowsMediaPlayer;
player.BeginInit();  		 		// 开始控件初始化
player.uiMode = "none";   		// 去掉底部菜单栏
player.Enabled = true;
player.settings.volume = 30;      	// 指定音量
player.settings.autoStart = true;    	 // 是否自动播放
player.windowlessVideo = false;         // 显示完整的media player窗口  如为true,则设置成无窗口模式,视频可直接显示在你指定的区域
player.settings.setMode("loop", true);       // 循环播放
player.enableContextMenu = false;  	// 禁用播放器右键
player.stretchToFit = true;	 // 非全屏状态时是否伸展到最佳大小 
player.fullScreen = false;	  // 设播放器全屏播放

注册状态改变事件:

player.PlayStateChange += play_PlayStateChange;
private void play_PlayStateChange(object sender, AxWMPLib._WMPOCXEvents_PlayStateChangeEvent e)
{
    // 状态码如下:
    /**
    	wmppsUndefined = 0;   //未知状态
        wmppsStopped = 1;    //播放停止
        wmppsPaused = 2;     //播放暂停
        wmppsPlaying = 3;     //正在播放
        wmppsScanForward = 4;   //向前搜索
        wmppsScanReverse = 5;   //向后搜索
        wmppsBuffering = 6;     //正在缓冲
        wmppsWaiting = 7;      //正在等待流开始
        wmppsMediaEnded = 8;    //播放流已结束
        wmppsTransitioning = 9;    //准备新的媒体文件
        wmppsReady = 10;      //播放准备就绪
        wmppsReconnecting = 11;   //尝试重新连接流媒体数据
        wmppsLast = 12;       //上一次状态,状态没有改变
    **/
}

播放单一视频

player.URL = path; 			// path为绝对路径
player.Ctlcontrols.play();

注:不能在状态改变事件里使用『URL』,将不起作用。


播放视频列表

public IWMPPlaylist playList;			// 全局变量
private IWMPPlaylist GetAllVideo(int isFirst)
{
    try
    {
        playList = player.playlistCollection.newPlaylist("list");      // 视频列表
        List<string> video1 = GetFileListWithExtend(new DirectoryInfo(path), "*.mp4");
        List<string> video2 = GetFileListWithExtend(new DirectoryInfo(path), "*.avi");

        if (isFirst == 0)
        {
            playList.appendItem(player.newMedia(path + "a.avi"));
        }

        for (int i= 0; i< (video1.Count > video2.Count ? video1.Count : video2.Count); i++)
        {
            if(i< video1.Count)
            {
                playList.appendItem(player.newMedia(video1[i]));
            }
            if (i< video2.Count)
            {
                playList.appendItem(player.newMedia(video2[i]));
            }
        }
        return playList;
    }
    catch(Exception e)
    {
        _log.Error(e.Message);
        return null;
    }    
}
public static List<string> GetFileListWithExtend(DirectoryInfo directory, string pattern)
{
    List<string> pathList = new List<string>();
    string result = String.Empty;
    if (directory.Exists || pattern.Trim() != string.Empty)
    {

        foreach (FileInfo info in directory.GetFiles(pattern))
        {
            result = info.FullName.ToString();
            pathList.Add(result);
        }
    }
    return pathList;
}

一开始的时候调用此列表,参数为『0』:

player.PlayStateChange += play_PlayStateChange;
player.currentPlaylist = GetAllVideo(0);
player.Ctlcontrols.play();

在第一个视频结束后进入状态改变事件:

private bool isflag = true;                         // 是否更换播放列表
private void play_PlayStateChange(object sender, AxWMPLib._WMPOCXEvents_PlayStateChangeEvent e)
{
    if (isflag && e.newState == 8)
    {
        isflag= false;
        // 更改播放列表
        this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart)delegate () {
            player.currentPlaylist = GetAllVideo(1);
        });
    }
}

上面的方法适用于轮播视频列表并在第一个视频播放结束后更换视频列表(只更改一次)。整体功能表述为:轮播视频列表,并且第二次及以后的轮播去掉首个视频。

实现这个功能还有一种方法,就是使用『IWMPPlaylist.removeItem』。在第一次轮播结束前去掉第一个视频,往后的轮播就不会播放第一个视频。但是此方法删除不了,会报一个异常。

切换视频(点播)

player.Ctlcontrols.stop();
player.URL = path + "a.avi";
player.Ctlcontrols.play();

显示GIF

WpfAnimatedGif

通过控制台或者Nuget安装:

Install-Package WpfAnimatedGif
<Window 
        ... ...
        xmlns:gif="http://wpfanimatedgif.codeplex.com" gif:ImageBehavior.AnimateInDesignMode="True"
        ... ...>

    <Grid Background="Black" x:Name="grid">
        <Image x:Name="img" gif:ImageBehavior.AnimatedSource="/Image/a.gif" gif:ImageBehavior.RepeatBehavior="Forever" Stretch="Fill"/>
    </Grid>
</Window>
var image = new BitmapImage();
image.BeginInit();
image.UriSource = new Uri(path + "a.gif", UriKind.Absolute);
image.EndInit();
WpfAnimatedGif.ImageBehavior.SetAnimatedSource(img, image);

注:听说这个方法会导致内存泄漏,没试过。


XamlAnimatedGif

通过控制台或者Nuget安装:

Install-Package XamlAnimatedGif
<Window 
        ... ...
        xmlns:gif="https://github.com/XamlAnimatedGif/XamlAnimatedGif" 
        ... ...>

    <Grid Background="Black" x:Name="grid">
        <Image x:Name="img" gif:AnimationBehavior.SourceUri="/Image/02002.gif" Stretch="Fill"/>
    </Grid>
</Window>
var image = new BitmapImage();
image.BeginInit();
image.UriSource = new Uri(path + "a.gif", UriKind.Absolute);
image.EndInit();
WpfAnimatedGif.ImageBehavior.SetAnimatedSource(img, image);

还有一种写法,但是不建议使用:

AnimationBehavior.SetSourceUri(img, new Uri(path + "a.gif", UriKind.Absolute));