1

私はこのトピックに関して多くの質問があることを知っています、そして私はこの問題を解決するのを助けるためにグーグルと同様にそれらのほとんどを調べましたが、役に立ちませんでした。

私がやりたいのは、ビットマップを生成し、ビットマップをレンダリングするコードの関連セクションをUIのPictureBoxに投稿することです。このエラーの具体的な原因を誰かが見つけて、回避する方法を提案できるかどうかを知りたいです。またはそれをバイパスします。

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. FrameTransportからのビデオフレームでマーシャリングするMoveFrameToBitmapは、成功した場合にビットマップを作成し、それを複製してフレームをキューに入れます。

    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クラスの関連するプロパティを示します。このクラスは、2つのビデオレンダラーからのフレームをカプセル化し、制御し、返します。これは、最初のレンダラーのキューに入れられたフレームを公開するプロパティです(videoPreviewRendererへのすべての呼び出しはVPR_Lockでロックされます):

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

2番目のレンダラーのプロパティは、独自のロックオブジェクトを除いて同じです。

次に進むと、MyVideoの2つのキューに入れられたフレームプロパティにアクセスし、2つのPictureBoxにフレームをレンダリングするUIのスレッドとその呼び出しがあります。

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()呼び出しは、メモリリークがあったため、ビットマップメモリ​​を強制的に解放します(まだ1つである可能性があります。複製されたビットマップは手動で破棄されておらず、現時点ではどこに配置すればよいかわかりません。 )。

System.DrawingのInvalidOperationExceptionはどこにありますか?これにより、元のPictureBoxに赤い十字が描画されます。ロックとアクセスに関して何が間違っていますか。このエラーを回避/バイパスするにはどうすればよいですか。

私はcatch例外でそれをバイパスし、スレッドでロジックを続行しようとしていますが、動作を確認しました。。。時折。また、失敗した描画の試行が完了しすぎて、とにかく赤十字を描画する場合もあります。その後、PictureBoxは完全に応答しなくなり、ビデオが正常に実行されている場合でも、新しいフレームを描画できなくなります。

おそらく、新しいフレームを受け入れるようにPictureBoxを更新する方法はありますか?

4

1 に答える 1

0

赤十字に問題がありましたが、これを見つけて助けてくれました。あなたにも役立つことを願っています:

WinForms コントロールと赤い X

于 2013-03-06T13:28:59.583 に答える