目标是控制BackGroundWorker的DoWork
事件中的帧提取速度。
我尝试了Thread.Sleep()
,但它抛出了一个异常。
这就是我想做的。上面和下面都有描述。
using Accord.Video;
using Accord.Video.FFMPEG;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
using (var vFReader = new VideoFileReader())
{
vFReader.Open(@"C:\Users\Chocolade 1972\Downloads\MyVid.mp4");
trackBar1.Maximum = (int)vFReader.FrameCount;
}
}
private void button1_Click(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
using (var vFReader = new VideoFileReader())
{
vFReader.Open(@"C:\Users\Chocolade 1972\Downloads\MyVid.mp4");
for (var i = 0; i < vFReader.FrameCount; i++)
{
backgroundWorker1.ReportProgress(0, vFReader.ReadVideoFrame());
}
// Not sure that this would be required as it might happen implicitly at the end of the 'using' block.
vFReader.Close();
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
pictureBox1.Image?.Dispose();
pictureBox1.Image = (Image)e.UserState;
}
private void Form1_Resize(object sender, EventArgs e)
{
label1.Text = this.Size.ToString();
}
}
它工作正常,但太快了。我如何使用定时器,或其他可以控制帧提取速度的东西?
1条答案
按热度按时间0md85ypi1#
我建议对当前代码做一些修改(实际上是很多)。
要点:
1.创建一个异步方法来执行视频播放。VideoFileReader在ThreadPool线程(实际上是2)上工作,它不会导致Form冻结
1.使用IProgress委托(类型为
Progress<Bitmap>
,此处命名为videoProgress
),将用于更新PictureBox控件的新数据封送到UI线程。委托方法名为Updater
1.使用单个位图对象,设置为PictureBox的
Image
属性1.使用从此位图派生的Graphics对象绘制视频帧。这允许包含所使用的资源。PictureBox只是失效,以显示位图的当前内容
1.允许视频播放方法接受帧速率值,此处设置为每秒25帧。当然,它可以适应放慢或加快播放(注意,设置超过32~35帧每秒,你开始失去一些帧)
1.使用CancellationTokenSource向视频播放方法发出信号,以在播放处于活动状态时按下停止按钮或关闭窗体时停止播放并终止
重要提示:
VideoFileReader
返回的Bitmap必须处理。如果不这样做,您将看到图形资源的消耗量不断增加,而且不会停止当然,当您打开这个窗体并创建容器Bitmap时,会有一点增加,但是当窗体关闭时,会回收少量的资源
SizeMode = Zoom
并最大化Form(设置PictureBox的Zoom
模式会影响性能,您应该调整位图的大小)buttonStart_Click
、buttonStop_Click
和buttonPause_Click
是用于开始、停止和暂停播放的按钮的Click处理程序。syncRoot
对象在这里不是严格必需的,但是保留它,它可能在某些时候会变得有用。