首页 > 代码库 > 针对监控摄像机(海康、大华等)进行手动录像的录像文件播放器功能设计

针对监控摄像机(海康、大华等)进行手动录像的录像文件播放器功能设计

 

参考上一篇:

针对监控摄像机(海康、大华等)进行手动录像的功能设计

 

录像后需要自定义一个播放器来播放录像文件。

简单设计界面如下:

 技术分享

打开文件,可暂停,可停止,可以拖动进度条。

 

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 = http://www.mamicode.com/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 = http://www.mamicode.com/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 = http://www.mamicode.com/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 = http://www.mamicode.com/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 = "暂停";
            }
        }

 

针对监控摄像机(海康、大华等)进行手动录像的录像文件播放器功能设计