2012-05-02 21 views
5

Estoy trabajando en un proyecto de iOS con C#. El programa captura imágenes de una cámara web conectada y las envía a través de Socket al iPhone/iPad. Todo esto funciona bien y puedo hacer que mi transmisión se muestre correctamente en el dispositivo.El programa se cuelga después de llamar a Dispose()

Pero cuando el cliente se desconecta, la cámara web tiene que apagarse y en esta función, el programa simplemente cuelga. No hay mensajes de error ni llamadas de excepción ... ¡simplemente se cuelga! Creo que es un problema con varios subprocesos, pero desafortunadamente no tengo tanta experiencia en C# para encontrar una solución. Espero que alguien aquí me puede llevar en el camino correcto ...

Código:
función 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(); 
} 

Definido como esta en la cámara Clase:

public event EventHandler<CameraEventArgs> OnImageCaptured; 

y provocó:

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

Así que esta función - lo que creo - se ejecuta en una amenaza por separado ya que la interfaz de usuario no se bloquean cuando las imágenes están llegando

Así que la próxima desconexión del cliente se maneja en esta función:.

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

} 

cliente se desconecta, thrashOldCamera() se llama. ¡Funciona bien hasta ahora! Ahora:

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

El programa se cuelga en _frameSource.Camera.Dispose();. Como se indicó anteriormente, no hay error o excepción. Puede ser un problema que se llame a onDataReceive() dentro de la función onImageCapture(). También agregué un botón al formulario que desencadena thrashOldCamera() y esto funciona perfectamente.

Cualquier ayuda/sugerencias son realmente apreciadas.

+0

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

Respuesta

8

Esto se conoce como interbloqueo, un problema típico de subprocesamiento. No veo que invoque explícitamente el subproceso de interfaz de usuario en ningún lugar del fragmento, por lo que el interbloqueo posiblemente se encuentre en el propio firmware de la cámara. El problema principal es que estás tratando de cerrar la cámara mientras que su devolución de llamada aún se está ejecutando, no hay un montón de código que sea resistente a eso. La llamada a Release() no puede completarse hasta que se complete la devolución de llamada. Pero la devolución de llamada no se puede completar hasta que finalice la llamada a Release(). Ciudad sin salida.

Tendrá que reestructurar su código para que esto no pueda suceder. Retrasar la liberación de la cámara es clave, lo mejor es hacerlo en el mismo hilo que abrió la cámara. Probablemente lo resuelva soltándolo en el evento FormClosed, por ejemplo. O no liberarlo en absoluto y dejarlo en manos de Windows para cerrar automáticamente las manijas.

0

Encuentra el evento para invocar mientras el dispositivo está desconectado. Escriba el código para apagar la cámara web allí.

+0

Hola Gijo, ¿no estás muy seguro de lo que quieres decir con eso? – Pascal

+0

Puede haber un evento que pueda usar para escribir código para apagar la cámara web. Puede ser que pueda verificar la lista de eventos disponible con el control. – MACMAN

+0

entonces lo que acabo de notar, hay una función llamada 'void Dispose()' en la clase Camera. Si utilizo el botón para encender la cámara, que funciona bien, este método no se activa. Si un cliente se desconecta, sin embargo activa esta función de eliminación – Pascal

3

No sé si esto realmente debería ser un comentario o una respuesta, pero al menos puedo llegar por el camino correcto.

I found the source en la biblioteca que está utilizando. Este es el contenido de Camera.Dispose()

public void Dispose() 
{ 
    StopCapture(); 
} 

, no ayuda mucho bien allí, aquí es Camera.StopCapture()

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

Una vez más, no ayuda mucho. _cameraMethods es un tipo de CameraMethods que proviene de la biblioteca WebCamLib que es una biblioteca de ayuda de C++ para comunicarse con show directo.

Aquí es 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; 
} 

Parece que su excepción está siendo comido durante el nativo de límite administrado.No sé cuánto te ayudará, pero al menos te da un comienzo de dónde mirar.

Habilite la depuración del código no administrado y vea si puede recorrer el origen de las Bibliotecas y ver dónde está el problema real.

enter image description here

estoy haciendo esto un wiki de la comunidad si alguien que tiene más experiencia con C++/C# interoperabilidad quiere editar esto y añadir más de lo que debe hacer a continuación para depurar el problema.

+0

Hola Scott. Thx por tu respuesta. Seguro que se rompe en algún lugar, pero esto está muy por encima de mi nivel visual C# - C++ para encontrar una solución. Supongo que tengo que buscar otra secuencia de comandos de cámara web que no use directShow. – Pascal

0

Sólo en caso de que todavía hay un problema con él, utilice el Touchless.RefreshCameraList para desconectarse de la cámara también se puede añadir el Touchless.CurrentCamera.Dispose si ya lo deseen. Es posible que aún necesite habilitar la depuración del código no administrado

Cuestiones relacionadas