網路上流傳的C#+DirectX的AudioVideoPlayBack做視頻播放器的代碼邏輯基本都是:
//CSDN yalan 舊項目源碼部分<br /> private void playstream()<br /> {<br /> fileName = pl[currentIndex].ToString().ToLower();<br /> int height;<br /> int width;<br /> try<br /> {<br /> if (PrimaryVideoPlaying)<br /> {<br /> height = panel1.Height;<br /> width = panel1.Width;<br /> PrimaryVideoPlaying = false;<br /> if (audio1 != null)<br /> {<br /> audio1.Dispose();<br /> audio1 = null;<br /> }<br /> if (video1 != null)<br /> {<br /> video1.Dispose();<br /> video1 = null;<br /> }<br /> video1 = Video.FromFile(fileName);<br /> audio1 = video1.Audio;<br /> audio1.Volume = 0; //音量最大<br /> audio1.Balance = 0; //聲道平衡<br /> video1.HideCursor();<br /> lbl_playerstatus.Text = fileName;<br /> panel1.Height = height;<br /> panel1.Width = width;<br /> video1.Owner = panel1;<br /> video1.Play();<br /> timer1.Start();<br /> }<br /> else<br /> {<br /> height = panel1.Height;<br /> width = panel1.Width;<br /> PrimaryVideoPlaying = true;<br /> if (audio != null)<br /> {<br /> audio.Dispose();<br /> audio = null;<br /> }<br /> if (video != null)<br /> {<br /> video.Dispose();<br /> video = null;<br /> }<br /> video = Video.FromFile(fileName);<br /> audio = video.Audio;<br /> audio.Volume = 0; //音量最大<br /> audio.Balance = 0; //聲道平衡<br /> video.HideCursor();<br /> lbl_playerstatus.Text = fileName;<br /> panel1.Height = height;<br /> panel1.Width = width;<br /> video.Owner = panel1;<br /> video.Play();<br /> timer.Start();<br /> }<br /> }<br /> catch (Exception ex)<br /> {<br /> MessageBox.Show(ex.ToString());<br /> }<br /> }</p><p> //播放video的計時器<br /> private void timer_Tick(object sender, EventArgs e)<br /> {<br /> if (video.CurrentPosition >= video.Duration)<br /> {<br /> timer.Stop();<br /> GC.Collect();<br /> //播放結束後釋放資源<br /> try<br /> {<br /> video.Stop();<br /> if (audio != null)<br /> audio.Dispose();<br /> audio = null;<br /> if (video != null)<br /> video.Dispose();<br /> video = null;<br /> }<br /> catch<br /> {<br /> try<br /> {<br /> video = null;<br /> }<br /> catch{}<br /> } </p><p> currentIndex = (currentIndex + 1) % pl.Count;<br /> if (currentIndex == 0)<br /> {<br /> getplaylist();<br /> }<br /> else<br /> {<br /> playstream();<br /> }<br /> }<br /> }<br /> private void timer1_Tick(object sender, EventArgs e)<br /> {<br /> if (video1.CurrentPosition >= video1.Duration)<br /> {<br /> timer1.Stop();<br /> GC.Collect();<br /> //播放結束後釋放資源<br /> try<br /> {<br /> video1.Stop();<br /> if (audio1 != null)<br /> audio1.Dispose();<br /> audio1 = null;<br /> if (video1 != null)<br /> video1.Dispose();<br /> video1 = null;<br /> }<br /> catch<br /> {<br /> try<br /> {<br /> video1 = null;<br /> }<br /> catch{}<br /> }</p><p> currentIndex = (currentIndex + 1) % pl.Count;<br /> if (currentIndex == 0)<br /> {<br /> getplaylist();<br /> }<br /> else<br /> {<br /> playstream();<br /> }<br /> }<br /> }<br />
經過測試,發現改代碼雖然初始化了兩個video和audio執行個體,但是播放清單(我的項目使用泛型List<string>數組儲存視頻路徑)換片時有黑屏間隔,特別是播放網路流的時候更加嚴重,黑屏間隔隨網路上的視頻檔案大小而時間長短不一。
經分析,造成換片黑屏間隔的原因的有兩點:1,清理垃圾耗時;2,video1播放完畢後,video執行個體初始化視頻檔案耗時。
經過改進,下面的代碼明顯優於網路上的代碼,使換片無黑屏:
using System;<br />using System.Collections.Generic;<br />using System.ComponentModel;<br />using System.Data;<br />using System.Data.SqlClient;<br />using System.Drawing;<br />using System.Text;<br />using System.Windows.Forms;<br />using Microsoft.DirectX.AudioVideoPlayback;</p><p>namespace stlive播放器測試<br />{<br /> public partial class Form1 : Form<br /> {<br /> public Form1()<br /> {<br /> InitializeComponent();<br /> Form1.CheckForIllegalCrossThreadCalls = false;<br /> }</p><p> //directx版<br /> private Video video1 = null; //主播<br /> private Audio audio1 = null;<br /> private Video video2 = null; //備播<br /> private Audio audio2 = null;<br /> private int currentIndex = 0; //播放清單播放位置<br /> private bool PrimaryVideoPlaying = true; //判斷主播備播<br /> private List<string> filename = new List<string>(); //視頻路徑<br /> private int height, width;<br /> private string _filename=string.Empty;<br /> private void Form1_Load(object sender, EventArgs e)<br /> {<br /> using (SqlConnection conn = new SqlConnection("data source=192.168.10.250; initial catalog=stlivead; user id=sa; password=sa;"))<br /> {<br /> conn.Open();<br /> using (SqlCommand cmd = new SqlCommand("select * from playlist order by id asc", conn))<br /> {<br /> SqlDataReader dr = cmd.ExecuteReader();<br /> while (dr.Read())<br /> {<br /> filename.Add(dr["filepath"].ToString());<br /> }<br /> }<br /> }<br /> playstream1(filename[currentIndex].ToString());<br /> currentIndex = (currentIndex + 1) % filename.Count;<br /> playstream2(filename[currentIndex].ToString());<br /> }</p><p> private void playstream1(string _filename)<br /> {<br /> height = panel1.Height;<br /> width = panel1.Width;<br /> if (audio1 != null)<br /> {<br /> audio1.Dispose();<br /> audio1 = null;<br /> }<br /> if (video1 != null)<br /> {<br /> video1.Dispose();<br /> video1 = null;<br /> }<br /> video1 = Video.FromFile(_filename);<br /> audio1 = video1.Audio;<br /> audio1.Volume = 0; //音量最大<br /> audio1.Balance = 0; //聲道平衡<br /> video1.HideCursor();<br /> panel1.Height = height;<br /> panel1.Width = width;<br /> video1.Owner = panel1;<br /> if (PrimaryVideoPlaying)<br /> {<br /> panel1.Visible = true;<br /> panel2.Visible = false;<br /> video1.Play();<br /> timer1.Start();<br /> label1.Text = "視頻1";<br /> }<br /> else<br /> {<br /> panel1.Visible = false;<br /> panel2.Visible = true;<br /> video1.Play();<br /> video1.Pause();<br /> }<br /> }</p><p> private void playstream2(string _filename)<br /> {<br /> height = panel2.Height;<br /> width = panel2.Width;<br /> if (audio2 != null)<br /> {<br /> audio2.Dispose();<br /> audio2 = null;<br /> }<br /> if (video2 != null)<br /> {<br /> video2.Dispose();<br /> video2 = null;<br /> }<br /> video2 = Video.FromFile(_filename);<br /> audio2 = video2.Audio;<br /> audio2.Volume = 0; //音量最大<br /> audio2.Balance = 0; //聲道平衡<br /> video2.HideCursor();<br /> panel2.Height = height;<br /> panel2.Width = width;<br /> video2.Owner = panel2;<br /> if (PrimaryVideoPlaying==false)<br /> {<br /> panel1.Visible = false;<br /> panel2.Visible = true;<br /> video2.Play();<br /> timer2.Start();<br /> label1.Text = "視頻2";<br /> }<br /> else<br /> {<br /> panel1.Visible = true;<br /> panel2.Visible = false;<br /> video2.Play();<br /> video2.Pause();<br /> }<br /> }</p><p> private void timer1_Tick(object sender, EventArgs e)<br /> {<br /> if (video1.CurrentPosition >= video1.Duration)<br /> {<br /> timer1.Stop();<br /> video1.Stop();<br /> PrimaryVideoPlaying = false;<br /> panel1.Visible = false;<br /> panel2.Visible = true;<br /> video2.Play();<br /> timer2.Start();<br /> label1.Text = "視頻2";<br /> GC.Collect();<br /> currentIndex = (currentIndex + 1) % filename.Count;<br /> playstream1(filename[currentIndex].ToString());<br /> }<br /> }</p><p> private void timer2_Tick(object sender, EventArgs e)<br /> {<br /> if (video2.CurrentPosition >= video2.Duration)<br /> {<br /> timer2.Stop();<br /> video2.Stop();<br /> PrimaryVideoPlaying = true;<br /> panel1.Visible = true;<br /> panel2.Visible = false;<br /> video1.Play();<br /> timer1.Start();<br /> label1.Text = "視頻1";<br /> GC.Collect();<br /> currentIndex = (currentIndex + 1) % filename.Count;<br /> playstream2(filename[currentIndex].ToString());<br /> }<br /> }</p><p> }<br />}<br />
上面代碼同樣構造了兩個video執行個體,但是它是在一個執行個體播放完畢後立即執行下一個視頻檔案的播放,下一個視頻檔案播放的同時執行個體化新的視頻以等待播放,所以黑屏間隔就消失了。
還未嘗試使用多線程的情況,理論上多線程的情況更優於我貼的新的代碼,邏輯基本相同,需要的朋友可以嘗試修改為多線程測試一下。