最近wpf项目用到视频播放,首先想到的就是vlc了,简单方便,网上教程也很多,实现也很顺利,但是正在和项目结合时候发现问题了,项目需求要视频帧上画出目标对象。使用vlc时发现。vlc的播放事件时按秒来的,且播放事件取到的帧和帧率无法对应,最后结果就是画上去的目标对象存在延迟,且不准确。

   没办法,老老实实用opencv来实现把,比较opencv时可以取到每一帧图片的。

其效果如下:

 

 

1、首先准备opencv的库,wpf当然用得到的就是emgu.cv。只应用emgu.cv肯定不行。opencv的依赖库也要放到可执行文件里面。

 

以上这些都是必须的。不然会报错。

2、创建videocapture,并获取视频相关基本信息

private bool StartPlay(string videoPath)

{

bool result = true;

try

{

videoCapture = new VideoCapture(videoPath);

if (videoCapture.IsOpened)

{

videoInfo.Filename = fileName;

videoInfo.Width = (int) videoCapture.GetCaptureProperty(CapProp.FrameWidth);

videoInfo.Height = (int) videoCapture.GetCaptureProperty(CapProp.FrameHeight);

videoInfo.FrameCount = (int) videoCapture.GetCaptureProperty(CapProp.FrameCount);

videoInfo.Fps = (int) videoCapture.GetCaptureProperty(CapProp.Fps);

videoInfo.CurrentFrame = 0;

myTimer.Interval = videoInfo.Fps == 0 ? 300 : 1000 / videoInfo.Fps;

IsStartPlay = true;

myTimer.Start();

totalTime = TimeSpan.FromSeconds(videoInfo.FrameCount / videoInfo.Fps);

this.tbTotalTimeLength.Text = $"{totalTime.Hours:00}:{totalTime.Minutes:00}:{totalTime.Seconds:00}";

this.process.Minimum = 0;

this.process.Maximum = totalTime.TotalSeconds;

this.process.SmallChange = 1;

}

else

{

MessageBox.Show("视频源异常");

result = false;

}

}

catch (Exception e)

{

result = false;

}


return result;

}

3、通过定时器,根据帧率获取视频帧,并给界面显示。

private void MyTimerElapsed(object sender, ElapsedEventArgs e)

{

if (IsStartPlay)

{

lock (LockHelper)

{

var frame = videoCapture.QueryFrame();

if (frame != null)

{

videoInfo.CurrentFrame = (int)videoCapture.GetCaptureProperty(CapProp.PosFrames);

this.SetVideoCapture(frame);

videoInfo.PlaySate = PlaySate.Playing;

}

}

}

}

private void SetVideoCapture(Mat frame)

{

Application.Current?.Dispatcher.Invoke(() =>

{

currtenTime = TimeSpan.FromSeconds(videoInfo.CurrentFrame / videoInfo.Fps);

if (videoInfo.CurrentFrame >= videoInfo.FrameCount)

{

this.process.Value = totalTime.TotalSeconds;

this.StopPlay();

return;

}


var bitImage = frame.Clone();

this.process.Value = currtenTime.TotalSeconds;

this.VideoShow.Source = BitmapSourceConvert.ToBitmapSource(bitImage);

});

}

4、播放、暂停、停止通过定时器来控制,播放进度滑动通过videoCapture.SetCaptureProperty(Emgu.CV.CvEnum.CapProp.PosFrames, value); 来控制。

 

详细的查看项目共工程。