You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#摄像头定时存帧异常:‘对象正被其他进程使用’排查与修复

问题成因分析

Let's break down why that random "Object in use by another process" exception is popping up:

  • Thread Safety Conflicts: The NewFrame event fires on a background thread, but your original code modifies pictureBox1.Image directly from that thread. This creates race conditions where the UI thread and background thread might access the same Bitmap instance simultaneously.
  • Bitmap Resource Locking: When you called pictureBox2.Image.Save(), the Bitmap was still referenced by the picture box control. The UI could be trying to render the image while the save operation accesses its resources, leading to a lock conflict.
  • Incomplete Resource Cleanup: You cloned Bitmaps but didn't always dispose of them properly. Over time, leaked resource handles cause unexpected locks.
  • Unreliable Synchronization: The blncapturing flag is a simple boolean without proper thread synchronization, so it might not prevent concurrent execution of the capture logic reliably.
代码修改方案

Here's the fixed code with key improvements explained:

public partial class Form1 : Form
{
    private FilterInfoCollection CaptureDevices;
    private VideoCaptureDevice videoSource;
    private readonly object _syncLock = new object(); // For thread-safe execution
    bool blncapturing;

    public Form1()
    {
        InitializeComponent();
        timer1.Enabled = false;
        timer1.Interval = 5000;
        blncapturing = false;
    }

    private void button1_Click(object sender, EventArgs e)
    {
        videoSource = new VideoCaptureDevice(CaptureDevices[comboBox1.SelectedIndex].MonikerString);
        videoSource.NewFrame += VideoSource_NewFrame;
        videoSource.Start();
        timer1.Enabled = true;
    }

    private void VideoSource_NewFrame(object sender, NewFrameEventArgs eventArgs)
    {
        // Marshal UI updates to the UI thread to avoid cross-thread issues
        if (pictureBox1.InvokeRequired)
        {
            pictureBox1.Invoke(new Action(() => UpdatePictureBox(pictureBox1, (Bitmap)eventArgs.Frame.Clone())));
        }
        else
        {
            UpdatePictureBox(pictureBox1, (Bitmap)eventArgs.Frame.Clone());
        }
    }

    // Helper to safely update picture boxes and clean up old images
    private void UpdatePictureBox(PictureBox pb, Bitmap newImage)
    {
        if (pb.Image != null)
        {
            ((IDisposable)pb.Image).Dispose();
        }
        pb.Image = newImage;
    }

    private void Form1_Load_1(object sender, EventArgs e)
    {
        CaptureDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
        foreach (FilterInfo Device in CaptureDevices)
        {
            comboBox1.Items.Add(Device.Name);
        }
        comboBox1.SelectedIndex = 0;
        videoSource = new VideoCaptureDevice();
    }

    private void button2_Click(object sender, EventArgs e)
    {
        videoSource?.Stop();
        UpdatePictureBox(pictureBox1, null);
        UpdatePictureBox(pictureBox2, null);
    }

    private void button3_Click(object sender, EventArgs e)
    {
        CaptureAndSaveFrame();
    }

    private void button4_Click(object sender, EventArgs e)
    {
        videoSource?.Stop();
        Application.Exit();
    }

    private void timer1_Tick(object sender, EventArgs e)
    {
        CaptureAndSaveFrame();
    }

    private void CaptureAndSaveFrame()
    {
        lock (_syncLock) // Ensure only one capture runs at a time
        {
            if (blncapturing || pictureBox1.Image == null)
                return;

            blncapturing = true;
            try
            {
                // Create an isolated copy of the frame to avoid UI resource conflicts
                using (Bitmap frameCopy = new Bitmap((Bitmap)pictureBox1.Image.Clone()))
                {
                    string savePath = string.Format(@"C:\Users\echristo\Desktop\trial\Snapshot_{0:yyyyMMdd_hhmmss.fff}.jpg", DateTime.Now);
                    frameCopy.Save(savePath, System.Drawing.Imaging.ImageFormat.Jpeg);

                    // Update pictureBox2 safely on the UI thread
                    if (pictureBox2.InvokeRequired)
                    {
                        pictureBox2.Invoke(new Action(() => UpdatePictureBox(pictureBox2, (Bitmap)frameCopy.Clone())));
                    }
                    else
                    {
                        UpdatePictureBox(pictureBox2, (Bitmap)frameCopy.Clone());
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"Capture error: {ex.Message}");
            }
            finally
            {
                blncapturing = false; // Reset flag even if an error occurs
            }
        }
    }
}

Key Fixes:

  • Thread-Safe UI Operations: All picture box updates use Invoke to run on the UI thread, eliminating cross-thread race conditions.
  • Isolated Frame Copies: We save a separate Bitmap copy (wrapped in using to auto-dispose) instead of the UI-bound image, preventing resource locks.
  • Reliable Synchronization: The lock object ensures only one capture operation runs at a time, making the blncapturing flag fully effective.
  • Clean Resource Management: The UpdatePictureBox helper guarantees old Bitmaps are disposed before replacement, preventing leaks.
  • Robust Error Handling: The finally block ensures the capture flag is reset even if an exception occurs, so the feature doesn't get stuck.

内容的提问来源于stack exchange,提问作者Terry24

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:40:23