目標是控制 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();
}
}
它作業正常,但太快了。我想使用計時器,或者可以讓我控制幀提取速度的東西。
uj5u.com熱心網友回復:
我建議對當前代碼進行一些更改(實際上很多:)。
要點:
- 創建一個異步方法來執行視頻播放。VideoFileReader在 ThreadPool 執行緒(實際上是 2)上作業,它不會導致表單凍結
- 使用IProgress<T>委托(型別
Progress<Bitmap>為,此處命名videoProgress)將新資料編組到 UI 執行緒,用于更新 PictureBox 控制元件。委托方法名為Updater - 使用單個 Bitmap 物件,設定為
ImagePictureBox 的屬性 - 使用從該 Bitmap 派生的 Graphics 物件來繪制視頻幀。這允許包含使用的資源。PictureBox 被簡單地無效化,以顯示 Bitmap 的當前內容
- 允許視頻播放方法接受幀速率值,此處設定為每秒 25 幀。當然,它可以適應減慢或加快播放(注意,設定超過每秒 32~35 幀,你開始丟失一些幀)
- 使用CancellationTokenSource向視頻播放方法發出信號以停止播放并終止,無論是在按下停止按鈕還是在播放處于活動狀態時關閉表單時
重要筆記:
VideoFileReader回傳的 Bitmap必須被釋放。如果不這樣做,您將看到圖形資源消耗的增加,并且不會停止- 使用單個位圖并使用派生的 Graphics 物件繪制每個新幀,可以保留圖形資源。如果您在播放視頻時保持“診斷工具”窗格打開,您會注意到您沒有泄漏任何資源并且記憶體使用量保持不變。
當然在打開這個Form創建容器Bitmap的時候會有一點點的增加,但是當Form關閉的時候,那少量的資源就被回收了 - 這也允許更平滑的過渡和更快的渲染速度(在播放視頻時移動表單)。另外,嘗試錨定/停靠 PictureBox,設定
SizeMode = Zoom并最大化 Form(設定ZoomPictureBox 的模式會影響性能,您應該調整 Bitmap 的大小)
buttonStart_Click,buttonStop_Click并且buttonPause_Click是用于開始、停止和暫停播放的 Button 的 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);
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 (true) {
if (token.IsCancellationRequested) break;
// Resumes on a ThreadPool Thread
await Task.Delay(intervalMs).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);
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/522146.html
標籤:C#。网表格图形
