我正在使用C#开发iOS项目。该程序从连接的网络摄像头捕获图像,并通过Socket发送到iPhone / iPad。这一切都很好,我可以成功地让我的流出现在设备上。
但是当客户端断开连接时,必须关闭网络摄像头,在此功能中,程序才会挂断。没有错误消息和没有异常调用......只是挂起!我相信这是多线程的问题但不幸的是我没有在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 Class中定义如下:
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();
。如上所述,没有错误或例外。
在onDataReceive()
函数()中调用onImageCapture
可能是一个问题。
我还在触发thrashOldCamera()
的表单中添加了一个按钮,这非常有效。
真正感谢任何帮助/提示。
答案 0 :(得分:9)
这称为死锁,这是典型的线程问题。我没有看到您在代码段中的任何位置显式调用UI线程,因此死锁可能位于相机固件本身。核心问题是你正在尝试关闭相机,而的回调仍然在执行,没有很多代码可以恢复它。在回调完成之前,Release()调用无法完成。但是,在Release()调用完成之前,回调无法完成。死锁城市。
您需要重新构建代码,以免发生这种情况。延迟释放相机是关键,最好在打开相机的同一个线程上完成。您可能会通过在FormClosed事件中释放它来解决它。或者根本不释放它并将其留在Windows上以自动关闭句柄。
答案 1 :(得分:3)
不知道这是真的应该是评论还是答案,但至少我可以让你走上正轨。
我found the source到你正在使用的图书馆。这是Camera.Dispose()
public void Dispose()
{
StopCapture();
}
好的,那里帮助不大,这里是Camera.StopCapture()
internal void StopCapture()
{
_cameraMethods.StopCamera();
}
再一次,没有多大帮助。 _cameraMethods
是CameraMethods
的一种类型,它来自库WebCamLib
,它是一个与直接显示进行通信的C ++帮助程序库。
以下是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#interop有更多使用经验的人想要编辑这个并添加更多下一步调试问题的话,我会把它变成一个社区维基。
答案 2 :(得分:0)
在设备断开连接时查找要调用的事件。编写代码以关闭那里的网络摄像头。
答案 3 :(得分:0)
万一还有问题,使用 Touchless.RefreshCameraList 断开相机连接,你也可以添加 Touchless.CurrentCamera.Dispose 所以希望。您可能仍需要启用非托管代码调试