5

C# を使用して iOS プロジェクトに取り組んでいます。このプログラムは、接続された Web カメラから画像をキャプチャし、Socket 経由で iPhone/iPad に送信します。これはすべて正常に機能し、ストリームをデバイスに正常に表示できます。

しかし、クライアントが切断されると、Web カメラをオフにする必要があり、この機能ではプログラムがハングアップします。エラーメッセージも例外呼び出しもありません...ハングするだけです! 複数のスレッドの問題だと思いますが、残念ながら、解決策を見つけるのに C# の経験がありません。ここの誰かが私を正しい軌道に乗せてくれることを願っています...

コード:
onImageCaptured 関数:

public void OnImageCaptured(Touchless.Vision.Contracts.IFrameSource frameSource, Touchless.Vision.Contracts.Frame frame, double fps)
{
    _latestFrame = frame.Image;
    Console.WriteLine("OnImageCaptured");
    if (isConnected)
    {
        Console.WriteLine("OnImageCaptured - isConnected");
        byteArray = new byte[0];
        MemoryStream stream = new MemoryStream();

        _latestFrame.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg);
        stream.Close();
        byteArray = stream.ToArray();

        if (byteArray.Length > 0)
        {
            string eof = "<EOF>";
            byte[] eofByte = Encoding.ASCII.GetBytes(eof);
            Console.WriteLine("OnImageCaptured - sendStream");
            this.onDataSend(byteArray);
            this.onDataSend(eofByte);
            stream.Flush();
        }

        System.Diagnostics.Debugger.Log(0, "1", "\nByte Array Length: " + byteArray.Length.ToString());
    }
    pictureBoxDisplay.Invalidate();
}

Camera クラスで次のように定義されます。

public event EventHandler<CameraEventArgs> OnImageCaptured;

そしてトリガーされました:

OnImageCaptured.Invoke(this, new CameraEventArgs(bitmap, fps));

したがって、この機能-私が信じていること-は、画像が入ってくるときにUIがブロックされないため、別の脅威で実行されます.

次に、クライアントの切断はこの関数で処理されます。

public void onDataSend(byte[] data)
{
    clientReady = false;
    try
    {
        socketWorker.Send(data);
    }
    catch (SocketException se)
    {
        isConnected = false;
        Console.WriteLine("Error: Data Write - SocketException");
        Console.WriteLine(se.ErrorCode.ToString());
        thrashOldCamera() // THIS FUNCTION HANGS THE PROGRAM !!
        onDisconnectServer();

        // onDisconnectServer();
    }
    catch (ObjectDisposedException)
    {
        isConnected = false;
        Console.WriteLine("Error: Data Write - ObjectDisposedException");
        // onDisconnectServer();
    }

}

クライアントが切断され、thrashOldCamera()呼び出されます。これまでのところうまくいきます!今:

private void thrashOldCamera()
{
    Console.WriteLine("TrashOldCamera");
    // Trash the old camera
    if (_frameSource != null)
    {
        try
        {
            _frameSource.NewFrame -= OnImageCaptured;
            Console.WriteLine("TrashOldCamera - 1");
            _frameSource.Camera.Dispose(); // HERE IT HANGS. IT NEVER GOES PAST HERE !!!
            Console.WriteLine("TrashOldCamera - 2");
            setFrameSource(null);
            Console.WriteLine("TrashOldCamera - 3");
            pictureBoxDisplay.Paint -= new PaintEventHandler(drawLatestImage);
        }
        catch (Exception ex)
        {
            Console.WriteLine("End Trash Camera Ex: " + ex);
        }
    }
    Console.WriteLine("End Trash Camera");
}

プログラムは でハングし_frameSource.Camera.Dispose();ます。前述のとおり、エラーや例外はありません。function()onDataReceive()内で呼び出されるのは問題かもしれません。onImageCaptureまた、トリガーするボタンをフォームに追加しましたがthrashOldCamera()、これは完全に機能します。

ヘルプ/ヒントは本当に感謝しています。

4

4 に答える 4

9

これはデッドロックと呼ばれ、典型的なスレッド化の問題です。スニペットのどこにも UI スレッドを明示的に呼び出していないので、デッドロックはカメラのファームウェア自体にある可能性があります。中心的な問題は、コールバックがまだ実行されているにカメラを閉じようとしているということです。それに対して回復力のあるコードはあまりありません。Release() 呼び出しは、コールバックが完了するまで完了できません。ただし、Release() 呼び出しが完了するまで、コールバックは完了できません。デッドロックシティ。

これが起こらないように、コードを再構築する必要があります。カメラのリリースを遅らせることが重要であり、カメラを開いたのと同じスレッドで行うのが最適です。たとえば、 FormClosed イベントで解放することで、おそらく解決するでしょう。または、まったく解放せず、ハンドルを自動的に閉じるために Windows に任せます。

于 2012-05-02T09:35:10.573 に答える
3

これが本当にコメントなのか回答なのかはわかりませんが、少なくとも私はあなたを正しい道に導くことができます.

あなたが使用しているライブラリのソースを見つけました。の内容ですCamera.Dispose()

public void Dispose()
{
    StopCapture();
}

わかりました、あまり役に立ちません。Camera.StopCapture()

internal void StopCapture()
{
    _cameraMethods.StopCamera();
}

もう一度、あまり役に立ちません。直接 show と通信するための C++ ヘルパー ライブラリであるライブラリに由来_cameraMethodsするタイプです。CameraMethodsWebCamLib

ここはCameraMethods::StopCamera()

void CameraMethods::StopCamera()
{
    if (g_pMediaControl != NULL)
    {
        g_pMediaControl->Stop();
        g_pMediaControl->Release();
        g_pMediaControl = NULL;
    }

    g_pfnCaptureCallback = NULL;

    if (g_pIBaseFilterNullRenderer != NULL)
    {
        g_pIBaseFilterNullRenderer->Release();
        g_pIBaseFilterNullRenderer = NULL;
    }

    if (g_pIBaseFilterSampleGrabber != NULL)
    {
        g_pIBaseFilterSampleGrabber->Release();
        g_pIBaseFilterSampleGrabber = NULL;
    }

    if (g_pIBaseFilterCam != NULL)
    {
        g_pIBaseFilterCam->Release();
        g_pIBaseFilterCam = NULL;
    }

    if (g_pGraphBuilder != NULL)
    {
        g_pGraphBuilder->Release();
        g_pGraphBuilder = NULL;
    }

    if (g_pCaptureGraphBuilder != NULL)
    {
        g_pCaptureGraphBuilder->Release();
        g_pCaptureGraphBuilder = NULL;
    }

    this->activeCameraIndex = -1;
}

ネイティブからマネージドの境界で例外が食べられているようです。これがどれだけ役立つかはわかりませんが、少なくともどこを見ればよいかを知るきっかけにはなります。

アンマネージ コードのデバッグを有効にし、ライブラリ ソースをステップ実行して、実際の問題がどこにあるかを確認できるかどうかを確認します。

ここに画像の説明を入力

C++/C# 相互運用の経験が豊富な他の誰かがこれを編集し、問題をデバッグするために次に何をすべきかを追加したい場合は、これをコミュニティ wiki にします。

于 2012-05-02T06:19:19.997 に答える
0

デバイスが切断されている間に呼び出すイベントを見つけます。そこにウェブカメラをオフにするコードを書きます。

于 2012-05-02T03:49:26.363 に答える