最近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); 来控制。
详细的查看项目共工程。