【问题标题】:Bitmap Clones -> PictureBox = InvalidOperationException, "Object is currently in use elsewhere", red cross (Windows Forms)位图克隆 -> PictureBox = InvalidOperationException,“对象当前正在其他地方使用”,红十字(Windows 窗体)
【发布时间】:2012-12-04 18:37:59
【问题描述】:

我知道关于这个主题有很多问题,我已经查看了大部分问题以及谷歌搜索来帮助我解决这个问题,但无济于事。

我想做的是将生成位图并将位图渲染到 UI 中的 PictureBoxes 的代码的相关部分发布,我想知道是否有人可以发现具体导致此错误的原因,并可以提出建议如何避免或绕过它。

我将从我的 VideoRenderer 类中的相关位 (3) 开始:

  1. 视频运行时不断调用 MoveFrameToBitmap 的定时器事件:

    private void TimerTick(object sender, EventArgs e)
    {
        if (frameTransport.IsNewFrameAvailable())
        {
            if (frameTransport.GetFrame())
            {
                if (MoveFrameToBitmap())
                {
                    double msSinceLastFrame = (Int32)DateTime.Now.Subtract(lastFrameTimestamp).TotalMilliseconds;
                    fps = 1000 / msSinceLastFrame;
                    lastFrameTimestamp = DateTime.Now;
                }
            }
            else
            {
                if (frameTransport.channelKeyBufferBufidMismatch)
                {
                    needsRestart = true;
                }
            }
        }
    }
    
  2. MoveFrameToBitmap,它从 FrameTransport 编组视频帧,如果成功则创建位图,克隆它并将帧排队:

    internal bool MoveFrameToBitmap()
    {
        bool result = false;
    
        try
        {
            if (frameTransport.bitmapDataSize == 0)
            {
                return false;
            }
    
            bool ResolutionHasChanged = ((videoWidth != frameTransport.width) | (videoHeight != frameTransport.height));
    
            videoHeight = frameTransport.height;
            videoWidth = frameTransport.width;
    
            Bitmap bitmap = new System.Drawing.Bitmap(videoWidth, videoHeight);
            Rectangle rectangle = new System.Drawing.Rectangle(0, 0, videoWidth, videoHeight);
            BitmapData bitmapData = new System.Drawing.Imaging.BitmapData();
            bitmapData.Width = videoWidth;
            bitmapData.Height = videoHeight;
            bitmapData.PixelFormat = PixelFormat.Format24bppRgb;
    
            bitmap.LockBits(rectangle, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb, bitmapData);
    
            Marshal.Copy(frameTransport.bitmapData, 0, bitmapData.Scan0, frameTransport.bitmapDataSize);
    
            lock (frameQueueLock)
            {
                if (frameQueue.Count == 0)
                {
                    frameQueue.Enqueue(bitmap.Clone());
                }
            }
    
            bitmap.UnlockBits(bitmapData);
    
            if (ResolutionHasChanged) skypeRef.events.FireOnVideoResolutionChanged(this, new RootEvents.OnVideoResolutionChangedArgs(videoWidth, videoHeight));
    
            bitmap.Dispose();
    
            result = true;
        }
        catch (Exception) { }
    
        GC.Collect();
        return result;
    }
    
  3. 公开排队帧的属性,即使帧当前未排队也可以安全访问:

    public Bitmap QueuedFrame
    {
        get
        {
            try
            {
                lock (frameQueueLock)
                {
                    return frameQueue.Dequeue() as Bitmap;
                }
            }
            catch (Exception)
            {
                return null;
            }
        }
    }
    

这就是 VideoRenderer 的全部内容。现在我将展示静态 MyVideo 类的相关属性,它封装、控制和返回来自两个视频渲染器的帧。这是公开第一个渲染器的排队帧的属性(对 videoPreviewRenderer 的每次调用都被 VPR_Lock 锁定):

    public static Bitmap QueuedVideoPreviewFrame
    {
        get
        {
            lock (VPR_Lock) { return videoPreviewRenderer.QueuedFrame; }
        }
    }

第二个渲染器的属性是一样的,除了它自己的锁对象。

继续,这是我的 UI 中的线程及其调用,它访问 MyVideo 中的两个排队帧属性并将帧呈现给两个 PictureBox:

ThreadStart renderVCONF3501VideoThreadStart = new ThreadStart(new Action(() =>
    {
        while (MyAccount.IsLoggedIn)
        {
            if (MyVideo.VideoPreviewIsRendering)
            {
                if (MyVideo.VideoPreviewRenderer.NeedsRestart)
                {
                    MyVideo.VideoPreviewRenderer.Stop();
                    MyVideo.VideoPreviewRenderer.Start();
                    MyVideo.VideoPreviewRenderer.NeedsRestart = false;
                }
                else
                {
                    try
                    {
                        Bitmap newVideoPreviewFrame = MyVideo.QueuedVideoPreviewFrame;

                        if (newVideoPreviewFrame != null)
                        {
                            lock (VCONF3501_VPI_Lock)
                            {
                                VCONF3501_VideoPreview.Image = newVideoPreviewFrame;
                            }
                        }
                    }
                    catch (Exception) { continue; }
                }
            }
            else
            {
                lock (VCONF3501_VPI_Lock)
                {
                    VCONF3501_VideoPreview.Image = null;
                }
            }

            if (MyVideo.LiveSessionParticipantVideoIsRendering)
            {
                if (MyVideo.LiveSessionParticipantVideoRenderer.NeedsRestart)
                {
                    MyVideo.LiveSessionParticipantVideoRenderer.Stop();
                    MyVideo.LiveSessionParticipantVideoRenderer.Start();
                    MyVideo.LiveSessionParticipantVideoRenderer.NeedsRestart = false;
                }
                else
                {
                    try
                    {
                        Bitmap newLiveSessionParticipantVideoFrame = MyVideo.QueuedLiveSessionParticipantVideoFrame;

                        if (newLiveSessionParticipantVideoFrame != null)
                        {
                            lock (VCONF3501_LSPVI_Lock)
                            {
                                VCONF3501_Video.Image = newLiveSessionParticipantVideoFrame;
                            }
                        }
                    }
                    catch (Exception) { continue; }
                }
            }
            else
            {
                lock (VCONF3501_LSPVI_Lock)
                {
                    VCONF3501_Video.Image = null;
                }
            }

            GC.Collect();
        }
    }));

new Thread(renderVCONF3501VideoThreadStart).Start();

GC.Collect() 调用是强制位图内存释放,因为存在内存泄漏(并且仍然可能是一个 - 克隆的位图没有被手动处理,我不知道去哪里,此时)。

System.Drawing 中的 InvalidOperationException 在哪里,这会导致在 PictureBox 上画一个红十字,我在锁定和访问方面做错了什么,如何避免/绕过这个错误?

我试图用 catch 异常绕过它并继续线程中的逻辑,并且我已经确认可以工作。 . .有时。在其他时候,失败的绘制尝试似乎完成得太远并且无论如何都会绘制红十字,并且在那之后,PictureBox 完全没有响应并且无法绘制新帧,即使视频仍然运行良好。

也许有办法刷新 PictureBox 以便它接受新帧?

【问题讨论】:

    标签: windows winforms bitmap picturebox invalidoperationexception


    【解决方案1】:

    我遇到了红十字的问题,然后我找到了这个,它对我有帮助,我希望它也对你有帮助:

    WinForms controls and the red X

    【讨论】:

      猜你喜欢
      • 2010-11-06
      • 1970-01-01
      • 2020-10-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多