位图克隆->PictureBox=InvalidOperationException,“对象当前正在其他地方使用”,红十字会(Windows窗体)

位图克隆->PictureBox=InvalidOperationException,“对象当前正在其他地方使用”,红十字会(Windows窗体),windows,winforms,bitmap,picturebox,invalidoperationexception,Windows,Winforms,Bitmap,Picturebox,Invalidoperationexception,我知道在这个话题上有很多问题,我已经浏览了大部分问题,还通过谷歌搜索帮助我解决了这个问题,但都没有用 我想做的是发布我的代码中生成位图和将位图渲染到UI中的PictureBoxes的相关部分,我想知道是否有人能够发现导致此错误的具体原因,并建议如何避免或绕过它 我将从视频渲染器类中的相关位3开始: 在视频运行时连续调用MoveFrameToBitmap的计时器事件: private void TimerTick(object sender, EventArgs e) { if (fram

我知道在这个话题上有很多问题,我已经浏览了大部分问题,还通过谷歌搜索帮助我解决了这个问题,但都没有用

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

我将从视频渲染器类中的相关位3开始:

在视频运行时连续调用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;
            }
        }
    }
}
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;
}
公开排队帧的属性,即使帧当前未排队,也可以安全访问排队帧:

public Bitmap QueuedFrame
{
    get
    {
        try
        {
            lock (frameQueueLock)
            {
                return frameQueue.Dequeue() as Bitmap;
            }
        }
        catch (Exception)
        {
            return null;
        }
    }
}
视频渲染器就这些了。现在我将展示静态MyVideo类的相关属性,它封装、控制并返回来自两个视频渲染器的帧。以下属性公开了第一个渲染器的排队帧,每次调用videoPreviewRenderer都会被VPR_锁锁定:

    public static Bitmap QueuedVideoPreviewFrame
    {
        get
        {
            lock (VPR_Lock) { return videoPreviewRenderer.QueuedFrame; }
        }
    }
第二个渲染器的属性相同,但其自身的锁定对象除外

接下来,我的UI中的线程及其调用访问MyVideo中的两个排队帧属性,并将帧渲染到两个PictureBoxe:

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();
Collect调用将强制释放位图内存,因为存在内存泄漏,并且可能仍然存在一个内存泄漏。此时,克隆的位图没有被手动处理,我不确定要在哪里进行处理

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

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


也许有一种方法可以刷新PictureBox,使其能够接受新的帧?

我在红十字会遇到问题,然后我发现这对我有帮助,我希望它也能帮助你: