Dan*_*Lip 3 .net c# graphics winforms
目标是控制 BackGroundWorkerDoWork事件中的帧提取速度。
我尝试过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();
}
}
Run Code Online (Sandbox Code Playgroud)
它工作正常,但太快了。如何使用计时器或允许我控制帧提取速度的东西?
我建议对当前代码进行一些更改(实际上是很多更改:)。
要点:
Progress<Bitmap>,videoProgress此处命名)将新数据编组到 UI 线程,用于更新 PictureBox 控件。委托方法被命名为UpdaterImagePictureBox 的属性重要笔记:
VideoFileReader返回的 Bitmap必须被释放。如果不这样做,您将看到图形资源消耗的增加,而且这种情况不会停止SizeMode = Zoom并最大化窗体(设置ZoomPictureBox 的模式会影响性能,您应该调整位图的大小)buttonStart_Click、buttonStop_Click和buttonPause_Click是用于开始、停止和暂停播放的按钮的单击处理程序。
此处syncRoot并不严格要求该对象,但将其保留在那里,在某些时候它可能会变得有用
using System.Drawing;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Accord.Video.FFMPEG;
public partial class Form1 : Form
{
Bitmap frame = null;
Graphics frameGraphics = null;
bool isVideoRunning = false;
IProgress<Bitmap> videoProgress = null;
private CancellationTokenSource cts = null;
private readonly object syncRoot = new object();
private static long pause = 0;
public Form1() => InitializeComponent();
private async void buttonStart_Click(object sender, EventArgs e) {
string fileName = "[The Video File Path]";
if (isVideoRunning) return;
isVideoRunning = true;
using (var videoReader = new VideoFileReader()) {
videoReader.Open(fileName);
// Adds two pixels, to see the Frame's boundaries in the container
frame = new Bitmap(videoReader.Width + 2, videoReader.Height + 2);
trackBar1.Maximum = (int)videoReader.FrameCount;
}
videoProgress = new Progress<Bitmap>(Updater);
cts = new CancellationTokenSource();
pictureBox1.Image = frame;
try {
frameGraphics = Graphics.FromImage(frame);
// Set the frame rate to 25 frames per second
int frameRate = 1000 / 25;
await GetVideoFramesAsync(videoProgress, fileName, frameRate, cts.Token);
}
finally {
StopPlayback(false);
frameGraphics?.Dispose();
pictureBox1.Image?.Dispose();
pictureBox1.Image = null;
buttonPause.Text = "Pause";
pause = 0;
isVideoRunning = false;
}
}
private void buttonStop_Click(object sender, EventArgs e) => StopPlayback(true);
private void buttonPause_Click(object sender, EventArgs e)
{
if (pause == 0) {
buttonPause.Text = "Resume";
Interlocked.Increment(ref pause);
}
else {
Interlocked.Decrement(ref pause);
buttonPause.Text = "Pause";
}
}
private void StopPlayback(bool cancel) {
lock (syncRoot) {
if (cancel) cts?.Cancel();
cts?.Dispose();
cts = null;
}
}
private void Updater(Bitmap videoFrame) {
using (videoFrame) frameGraphics.DrawImage(videoFrame, Point.Empty);
pictureBox1.Invalidate();
}
private async Task GetVideoFramesAsync(IProgress<Bitmap> updater, string fileName, int intervalMs, CancellationToken token = default) {
using (var videoReader = new VideoFileReader()) {
if (token.IsCancellationRequested) return;
videoReader.Open(fileName);
while (!token.IsCancellationRequested) {
// Resumes on a ThreadPool Thread
await Task.Delay(intervalMs, token).ConfigureAwait(false);
if (Interlocked.Read(ref pause) == 0) {
var frame = videoReader.ReadVideoFrame();
if (frame is null) break;
updater.Report(frame);
}
}
}
}
protected override void OnFormClosing(FormClosingEventArgs e) {
if (isVideoRunning) StopPlayback(true);
base.OnFormClosing(e);
}
}
Run Code Online (Sandbox Code Playgroud)