static int width = 1920, height = 1080; int videoWidth = 639, videoHeight = 479; int YUVWidth = 640, YUVHeight = 480; bool bPause = false; bool bPlayStop = false;
ILog log \= LogManager.GetLogger("ErrorLog"); int fps = 15, fpsMain = 15, fpsBase = 15; int msPerFrameCamera = 66, msPerFrameCameraBase = 66, msPerFrameCameraMain = 66; //相机每一帧的时间,25帧即40毫秒
public frmPlay()
{
InitializeComponent(); #region 解码器相关初始化,一般在窗口load中进行初始化 decAttr \= new H264Dec.hiH264\_DEC\_ATTR\_S();
decAttr.uPictureFormat \= 0;
decAttr.uStreamInType \= 0;
decAttr.uPicWidthInMB \= (uint)width;
decAttr.uPicHeightInMB \= (uint)height;
decAttr.uBufNum \= 8;
decAttr.uWorkMode \= 16; //创建、初始化解码器句柄
\_decHandle = H264Dec.Hi264DecCreate(ref decAttr); #endregion InitVars();
frmPlay\_Resize(null, null); this.Resize += new System.EventHandler(this.frmPlay\_Resize);
} long offsetPlay = 0; int iFramePlay = 0;
Image<Bgr, Byte> imageYUV = new Image<Bgr, Byte>(640, 480);
Image<Bgr, Byte> imgNowShow = new Image<Bgr, Byte>(640, 480); int iFontSize16 = 12, iFontSize20 = 15, iFontSize24 = 18; string fontname = "仿宋\_GB2312"; private delegate void SetPicVideo(Image<Bgr, Byte> val);//跨线程修改图片框
private Thread SetPicVideoThread;
FileStream fs \= null; private delegate void SetProgressLabel(string val);
Thread SetLabelThread; string labelValue = string.Empty; string sTotalTime = ""; int iFrameCnt = 0;
Thread showThread; void SetPic(Emgu.CV.Image<Bgr, Byte> val)
{ if (bPause || bPlayStop || bAbortPlayThread)
{
Graphics g \= imgBox.CreateGraphics();
g.Clear(Color.Black);
imageVideoOverLay.Visible \= true;
} else
if (imageVideoOverLay.Visible)
{
imageVideoOverLay.Visible \= false;
} if (val != null && !bAbortPlayThread)
{ this.imgBox.Image = val;
imgBox.Refresh();
}
} private void setPicVideo()
{ if (bPause || bPlayStop || bAbortPlayThread) return; if (imgBox.InvokeRequired)
{
SetPicVideo d \= new SetPicVideo(SetPic); object\[\] arg = new object\[\] { imgNowShow }; this.Invoke(d, arg);
} else {
SetPic(imgNowShow);
}
}
List<BufferPlay> BufferPlayList = new List<BufferPlay>(); private void DrawnShow()
{
iFramePlay \= 0; while (!bAbortPlayThread)
{ if (BufferPlayList.Count > 0)
{
DateTime dtStart \= DateTime.Now;
realstaticinfo \= BufferPlayList\[0\].info;
GCHandle handle \= GCHandle.Alloc(BufferPlayList\[0\].yuvs, GCHandleType.Pinned); using (Image<Bgr, Byte> yuv420p = new Image<Bgr, byte\>(YUVWidth, (YUVHeight >> 1) \* 3, YUVWidth, handle.AddrOfPinnedObject()))
{
CvInvoke.CvtColor(yuv420p, imageYUV, Emgu.CV.CvEnum.ColorConversion.Yuv420P2Bgr);
} if (handle.IsAllocated)
handle.Free(); if (imageYUV == null) continue;
Bitmap bmp \= imageYUV.Bitmap; if (bmp == null) continue; lock (bmp)
{ if (bShowLine)
{
DrawInVideo(bmp);
}
imageYUV.Bitmap \= bmp;
imgNowShow \= imageYUV;
SetPicVideoThread \= new Thread(new ThreadStart(setPicVideo));
SetPicVideoThread.IsBackground \= true;
SetPicVideoThread.Start();
} if (BufferPlayList.Count > 0) BufferPlayList.RemoveAt(0);
iFramePlay++; if (iFramePlay % fps == 0)
{ int seconds = (int)((double)iFramePlay / fps); int h = (int)Math.Floor((double)seconds / 3600); int m = (int)Math.Floor((double)(seconds - h \* 3600) / 60); int s = (int)Math.Floor((double)(seconds - h \* 3600 - m \* 60)); string sNowPlayTime = h.ToString().PadLeft(2, '0') + ":" + m.ToString().PadLeft(2, '0') + ":" + s.ToString().PadLeft(2, '0');
labelValue \= sNowPlayTime + "/" + sTotalTime;
SetLabelThread \= new Thread(new ThreadStart(setLableValue));
SetLabelThread.IsBackground \= true;
SetLabelThread.Start();
}
DateTime timeStop2 \= DateTime.Now;
TimeSpan ts2 \= new TimeSpan();
ts2 \= timeStop2 - dtStart; if (ts2.TotalMilliseconds < msPerFrameCamera)
{
Thread.Sleep((int)(msPerFrameCamera - ts2.TotalMilliseconds));
}
}
}
} private void Play(object ofs)
{
FileStream fsTmp \= ofs as FileStream; try {
offsetPlay \= 0;
DateTime timeStart \= DateTime.Now;
DateTime timeStop \= DateTime.Now; while (!bAbortPlayThread && fsTmp.Length > offsetPlay + 4 + 378 + 174)
{ try { if (bPause)
{
Thread.Sleep(msPerFrameCamera); continue;
}
timeStart \= DateTime.Now; byte\[\] intdata = new byte\[4\];
fsTmp.Read(intdata, 0, 4);
offsetPlay \= offsetPlay + 4;
fsTmp.Seek(offsetPlay, SeekOrigin.Begin); int frameLen = (int)FVD.Common.Common.bytes2uintNoRe(intdata, 0, 4); byte\[\] buffer = new byte\[frameLen\];
fsTmp.Read(buffer, 0, frameLen);
offsetPlay \= offsetPlay + frameLen;
fsTmp.Seek(offsetPlay, SeekOrigin.Begin);
GCHandle hObject2 \= GCHandle.Alloc(buffer, GCHandleType.Pinned);
IntPtr pStreamData \= hObject2.AddrOfPinnedObject(); if (fsTmp.Length > offsetPlay + 500)
{ byte\[\] datas= new byte\[500\]; //获取叠加数据
fsTmp.Read(datas, 0, 500);
Getdatas(datas);
} if (H264Dec.Hi264DecAU(\_decHandle, pStreamData, (uint)frameLen, 0, ref \_decodeFrame, 0) == 0)
{ int yLength = (int)(\_decodeFrame.uHeight \* \_decodeFrame.uYStride); int uLength = (int)(\_decodeFrame.uHeight \* \_decodeFrame.uUVStride / 2);
IntPtr y \= \_decodeFrame.pY;
IntPtr v \= \_decodeFrame.pV;
IntPtr u \= \_decodeFrame.pU; byte\[\] ys = new byte\[yLength\];
Marshal.Copy(y, ys, 0, yLength); byte\[\] vs = new byte\[uLength\];
Marshal.Copy(v, vs, 0, uLength); byte\[\] us = new byte\[uLength\];
Marshal.Copy(u, us, 0, uLength); byte\[\] yuvs = new byte\[ys.Length + vs.Length + us.Length\];
ys.CopyTo(yuvs, 0);
vs.CopyTo(yuvs, ys.Length);
us.CopyTo(yuvs, ys.Length + vs.Length);
BufferPlay bp;
bp.info \= realstaticinfoTmp;
bp.yuvs \= yuvs;
BufferPlayList.Add(bp);
} if (hObject2.IsAllocated)
hObject2.Free();
pStreamData \= IntPtr.Zero; if (BufferPlayList.Count > 0)
{
Thread.Sleep((int)((BufferPlayList.Count - 1) \* msPerFrameCamera));
}
} catch (System.Exception ex)
{
log.ErrorFormat("播放出错:" + ex.Message); continue;
}
}
} catch (System.Exception ex)
{
log.ErrorFormat("播放出错:" + ex.Message);
MessageBox.Show("播放出错:" + ex.Message);
} while (BufferPlayList.Count > 0)
{
Thread.Sleep(msPerFrameCamera);
} if (bLoopPlay) //**循环播放**,重新初始化
{ if (bAbortPlayThread) return;
bPlayStop \= true;
bAbortPlayThread \= true;
Thread.Sleep(500);
bPlayStop \= false;
bAbortPlayThread \= false;
labelValue \= "00:00:00/" + sTotalTime;
SetLabelThread \= new Thread(new ThreadStart(setLableValue));
SetLabelThread.IsBackground \= true;
SetLabelThread.Start();
fsTmp.Seek(0, SeekOrigin.Begin);
playThread \= new Thread(new ParameterizedThreadStart(Play));
playThread.IsBackground \= true;
playThread.Start(fsTmp);
showThread \= new Thread(new ThreadStart(DrawnShow));
showThread.IsBackground \= true;
showThread.Start();
} else {
fsTmp.Close();
fsTmp.Dispose();
bPlayStop \= true;
labelValue \= "00:00:00/00:00:00";
SetLabelThread \= new Thread(new ThreadStart(setLableValue));
SetLabelThread.IsBackground \= true;
SetLabelThread.Start();
}
} private void trackBar1\_ValueChanged(object sender, EventArgs e)
{ if (!string.IsNullOrEmpty(sTotalTime) && fs != null && btnStop.Enabled == true && fs.CanRead && iFrameCnt > 0)
{
bPause \= true;
Thread.Sleep(msPerFrameCamera); int iNowFrame = (int)((double)trackBar1.Value / trackBar1.Maximum \* (double)iFrameCnt); if (iNowFrame <= 0)
{
iNowFrame \= 1;
}
BufferPlayList.Clear();
fs.Seek(0, SeekOrigin.Begin); long offsetTmp = 0; int iFrame = 0; byte\[\] intdata = new byte\[4\]; while (fs.Length > offsetTmp + 504)
{
fs.Read(intdata, 0, 4); int frameLen = (int)(intdata\[0\] | intdata\[1\] << 8 | intdata\[2\] << 16 | intdata\[3\] << 24);
offsetTmp \= offsetTmp + frameLen + 504; //504 = 4 + 500
fs.Seek(offsetTmp, SeekOrigin.Begin);
iFrame++; if (iFrame == iNowFrame)
{
offsetPlay = offsetTmp;
iFramePlay = iNowFrame; break;
}
}
bPause \= false;
}
} void SetStatuslabel(string val)
{ if (bPlayStop) //自动播放完成,跨线程修改状态
{
btnStop.Enabled = false;
btnPause.Enabled = false; this.Text = “视频播放”;
trackBar1.ValueChanged \-= new System.EventHandler(trackBar1\_ValueChanged);
trackBar1.Value \= 0;
trackBar1.ValueChanged += new System.EventHandler(trackBar1\_ValueChanged);
trackBar1.Enabled \= false;
iFramePlay \= 0;
imageVideoOverLay.Visible \= true;
bPlayStop \= false;
} if (bPause || bPlayStop || bAbortPlayThread) return; this.labelProgress.Text = val; if (iFrameCnt > 0 && iFramePlay > 0 && iFramePlay <= iFrameCnt)
{
trackBar1.ValueChanged \-= new System.EventHandler(trackBar1\_ValueChanged);
trackBar1.Value \= (int)((double)iFramePlay / (double)iFrameCnt \* trackBar1.Maximum);
trackBar1.ValueChanged += new System.EventHandler(trackBar1\_ValueChanged);
}
} private void setLableValue()
{ if (bPause || bAbortPlayThread) return; if (labelProgress.InvokeRequired)
{
SetProgressLabel d \= new SetProgressLabel(SetStatuslabel); object\[\] arg = new object\[\] { labelValue };//要传入的参数值
this.Invoke(d, arg);
} else {
SetStatuslabel(labelValue);
}
} private void btnOpen\_Click(object sender, EventArgs e)
{ if (rbMainVideo.Checked)
{
YUVWidth \= width;
YUVHeight \= height;
msPerFrameCamera \= msPerFrameCameraMain;
fps \= fpsMain;
} else {
YUVWidth \= videoWidth + 1;
YUVHeight \= videoHeight + 1;
msPerFrameCamera \= msPerFrameCameraBase;
fps \= fpsBase;
}
transX \= YUVWidth / (videoWidth + 1);
transY \= YUVHeight / (videoHeight + 1);
frmPlay\_Resize(null, null);
openFileDialog1.Filter \= "Zenith视频文件(\*.dat)|\*.dat";
openFileDialog1.FileName \= "";
openFileDialog1.Multiselect \= false;
openFileDialog1.InitialDirectory \= Application.StartupPath; if (openFileDialog1.ShowDialog() == DialogResult.OK)
{ this.labelProgress.Text = "00:00:00/00:00:00";
bAbortPlayThread \= true;
Thread.Sleep(200); if (playThread != null && playThread.IsAlive)
{
playThread.Abort();
} string filename = openFileDialog1.FileName;
fs \= new FileStream(filename, FileMode.OpenOrCreate, FileAccess.Read); if (fs.Length <= 512)
{
MessageBox.Show("请确认文件是否有效!" + filename); return;
} if (!fs.CanRead || !fs.CanSeek)
{
MessageBox.Show("文件不可读,请确认!" + filename); return;
}
imageYUV \= new Image<Bgr, Byte>(YUVWidth, YUVHeight); this.Cursor = Cursors.WaitCursor; try { this.Text = "视频播放 " + filename;
log.ErrorFormat("视频播放 " + filename); if (bPause)
{
bPause \= false;
btnPause.Text \= "暂停";
}
bPlayStop \= false;
bAbortPlayThread \= false;
btnStop.Enabled \= true;
btnPause.Enabled \= true;
trackBar1.ValueChanged \-= new System.EventHandler(trackBar1\_ValueChanged);
trackBar1.Value \= 0;
trackBar1.ValueChanged += new System.EventHandler(trackBar1\_ValueChanged);
trackBar1.Enabled \= true;
fs.Seek(0, SeekOrigin.Begin);
//获取文件长度 long offset = 0;
iFrameCnt = 0; byte[] intdata = new byte[4]; while (fs.Length > offset + 556)
{
fs.Read(intdata, 0, 4); int frameLen = (int)(intdata[0] | intdata[1] << 8 | intdata[2] << 16 | intdata[3] << 24);
offset = offset + frameLen + 556; //556 = 4 + 378 + 174
fs.Seek(offset, SeekOrigin.Begin);
iFrameCnt++;
} int seconds = (int)((double)iFrameCnt / fps); int h = (int)Math.Floor((double)seconds / 3600); int m = (int)Math.Floor((double)(seconds - h * 3600) / 60); int s = (int)Math.Floor((double)(seconds - h * 3600 - m * 60));
sTotalTime \= h.ToString().PadLeft(2, '0') + ":" + m.ToString().PadLeft(2, '0') + ":" + s.ToString().PadLeft(2, '0'); this.labelProgress.Text = "00:00:00/" + sTotalTime;
fs.Seek(0, SeekOrigin.Begin);
playThread \= new Thread(new ParameterizedThreadStart(Play));
playThread.IsBackground \= true;
playThread.Start(fs);
showThread \= new Thread(new ThreadStart(DrawnShow));
showThread.IsBackground \= true;
showThread.Start();
} catch (System.Exception ex)
{
log.ErrorFormat("视频初始化错误!" + ex.Message);
MessageBox.Show("视频初始化错误!");
} finally { this.Cursor = Cursors.Default;
}
}
} private void btnStop\_Click(object sender, EventArgs e)
{
labelValue \= "00:00:00/00:00:00";
SetLabelThread \= new Thread(new ThreadStart(setLableValue));
SetLabelThread.IsBackground \= true;
SetLabelThread.Start(); this.Text = "视频播放";
trackBar1.ValueChanged \-= new System.EventHandler(trackBar1\_ValueChanged);
trackBar1.Value \= 0;
trackBar1.ValueChanged += new System.EventHandler(trackBar1\_ValueChanged);
trackBar1.Enabled \= false; if (fs != null )
{
fs.Close();
fs.Dispose();
}
bAbortPlayThread \= true;
btnStop.Enabled \= false;
btnPause.Enabled \= false; if (bPause)
{
bPause \= false;
btnPause.Text \= "暂停";
}
}