2012-05-02 45 views
5

Tôi đang làm việc trên một dự án iOS với C#. Chương trình sẽ chụp ảnh từ một webcam được kết nối và gửi nó qua Socket tới iPhone/iPad. Điều này tất cả hoạt động tốt và tôi có thể thành công có được dòng của tôi hiển thị trên thiết bị.Chương trình bị treo sau khi gọi Dispose()

Nhưng khi khách hàng ngắt kết nối, webcam phải tắt và trong chức năng này, chương trình sẽ bị treo. Không có thông báo lỗi và không có cuộc gọi ngoại lệ ... chỉ bị treo! Tôi tin rằng đó là một vấn đề với nhiều chủ đề nhưng tiếc là tôi không phải là kinh nghiệm trong C# để tìm một giải pháp. Tôi hy vọng ai đó ở đây có thể mang lại cho tôi đi đúng hướng ...

Code:
chức năng 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(); 
} 

Defined như thế này trong Máy ảnh Class:

public event EventHandler<CameraEventArgs> OnImageCaptured; 

Và kích hoạt:

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

Vì vậy, chức năng này - những gì tôi tin - chạy trong một mối đe dọa riêng từ giao diện người dùng không bị chặn khi những hình ảnh đang đến trong

Vì vậy, hôm sau ngắt kết nối khách hàng được xử lý trong hàm này:.

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(); 
    } 

} 

ngắt kết nối Client, thrashOldCamera() được gọi. Hoạt động tốt cho đến nay! Bây giờ:

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"); 
} 

Chương trình bị treo tại _frameSource.Camera.Dispose();. Như đã nêu ở trên, không có lỗi hoặc ngoại lệ. Có thể là một vấn đề mà onDataReceive() được gọi trong hàm onImageCapture(). Tôi cũng đã thêm một nút vào biểu mẫu kích hoạt thrashOldCamera() và điều này hoạt động hoàn hảo.

Bất kỳ trợ giúp/gợi ý nào thực sự được đánh giá cao.

+0

http://channel9.msdn.com/Series/-NET-Debugging-Stater-Kit-for-the-Production-Environment/Diagnosing-Application-Issues-01 –

Trả lời

8

Đây được gọi là bế tắc, một vấn đề luồng điển hình. Tôi không thấy bạn gọi một cách rõ ràng đến chuỗi giao diện người dùng ở bất kỳ nơi nào trong đoạn mã để khóa chết có thể nằm trong chính chương trình cơ sở của máy ảnh. Vấn đề cốt lõi là bạn đang cố gắng đóng máy ảnh trong khi gọi lại của nó vẫn đang thực thi, không có nhiều mã linh hoạt cho điều đó. Cuộc gọi Release() không thể hoàn thành cho đến khi cuộc gọi hoàn tất. Nhưng cuộc gọi lại không thể hoàn thành cho đến khi cuộc gọi Release() hoàn tất. Thành phố bế tắc.

Bạn sẽ cần phải cấu trúc lại mã của mình để điều này không thể xảy ra. Việc trì hoãn phát hành máy ảnh là chìa khóa, được thực hiện tốt nhất trên cùng một chủ đề đã mở máy ảnh. Có thể bạn sẽ giải quyết nó bằng cách phát hành nó trong sự kiện FormClosed chẳng hạn. Hoặc không phát hành nó ở tất cả và để nó lên đến Windows để tự động đóng chốt.

0

Tìm sự kiện để gọi trong khi thiết bị bị ngắt kết nối. Viết mã để tắt cam web ở đó.

+0

Xin chào Gijo, không chắc chắn ý anh là sao? – Pascal

+0

Có thể có một sự kiện mà bạn có thể sử dụng để viết mã để tắt cam web. Có thể bạn có thể kiểm tra danh sách sự kiện có sẵn với điều khiển. – MACMAN

+0

vì vậy những gì tôi vừa nhận thấy, có một chức năng gọi là 'void Dispose()' trong lớp Camera. Nếu tôi sử dụng nút để bật máy ảnh - hoạt động tốt - phương pháp này không được kích hoạt. Nếu một khách hàng ngắt kết nối, nó sẽ kích hoạt chức năng này dispose – Pascal

3

Không biết nếu điều này thực sự phải là một nhận xét hoặc câu trả lời, nhưng ít nhất tôi có thể giúp bạn đi đúng hướng.

I found the source vào thư viện bạn đang sử dụng. Đây là nội dung của Camera.Dispose()

public void Dispose() 
{ 
    StopCapture(); 
} 

Ok, không giúp ích nhiều cho có, đây là Camera.StopCapture()

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

Một lần nữa, không thể giúp ích nhiều. _cameraMethods là một loại CameraMethods xuất phát từ thư viện WebCamLib là thư viện trợ giúp C++ để giao tiếp với chương trình trực tiếp.

Đây là 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; 
} 

Nó xuất hiện ngoại trừ của bạn đang được ăn trong suốt có nguồn gốc từ ranh giới quản lý.Tôi không biết bao nhiêu điều này sẽ giúp bạn nhưng ít nhất nó mang đến cho bạn một khởi đầu của nơi để tìm.

Bật gỡ lỗi mã không được quản lý và xem liệu bạn có thể duyệt qua nguồn Thư viện và xem vấn đề thực sự ở đâu không.

enter image description here

Tôi đang làm cho một cộng đồng wiki nếu bất kỳ ai khác có nhiều kinh nghiệm với C++/C# interop muốn chỉnh sửa này và thêm nhiều hơn những gì phải làm tiếp theo để gỡ lỗi vấn đề này.

+0

Xin chào Scott. Thx cho câu trả lời của bạn. Nó chắc chắn phá vỡ một nơi nào đó trong đó, nhưng đây là cách trên C# - C++ mức độ thị giác của tôi để tìm một giải pháp. Tôi đoán tôi phải tìm một tập lệnh webcam khác không sử dụng directShow. – Pascal

0

Chỉ trong trường hợp vẫn còn là một vấn đề với nó, Sử dụng Touchless.RefreshCameraList để ngắt kết nối từ máy ảnh bạn cũng có thể thêm các Touchless.CurrentCamera.Dispose nếu ya rất muốn. Bạn vẫn có thể cần bật gỡ lỗi mã không được quản lý

Các vấn đề liên quan