2012-07-24 18 views
26

Necesito una forma de controlar el flash de la cámara en un dispositivo Android mientras está grabando video. Estoy haciendo una aplicación de luz estroboscópica, y tomar videos con una luz estroboscópica intermitente daría como resultado la capacidad de grabar objetos que se mueven a altas velocidades, como una hoja de ventilador.Activación de la cámara Flash durante la grabación de video

El flash solo se puede habilitar iniciando una vista previa de video y configurando FLASH_MODE_TORCH en los parámetros de la cámara. Que se vería así:

Camera c = Camera.open(); 
Camera.Parameters p = c.getParameters(); 
p.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH); 
c.setParameters(p); 
c.startPreview(); 

Una vez iniciada la vista previa, que puede voltear ese parámetro de ida y vuelta para encender la luz de encendido y apagado. Esto funciona bien hasta que intento grabar un video. El problema es que para poder entregar la cámara al MediaRecorder, primero tengo que desbloquearlo.

MediaRecorder m = new MediaRecorder(); 
c.unlock();  // the killer 
m.setCamera(c); 

Después de ese desbloqueo, ya no puedo cambiar los parámetros de la cámara y, por lo tanto, no tengo forma de cambiar el estado del flash.

No sé si es realmente posible hacer esto ya que no soy el mejor en java-piratería, pero aquí es lo que sé:

  • Camera.unlock() es un nativo método, por lo que no puede ver realmente el mecanismo detrás de la forma en que me encierra a cabo
  • Camera.Parameter tiene un HashMap que contiene todos sus parámetros
  • Camera.setParameters (parámetros) realiza el HashMap, la convierte en una cadena, y lo pasa a un método nativo
  • Puedo eliminar todos los parámetros, pero TORCH-MODE del HashMap y la cámara fija la aceptará

Por lo tanto, todavía puede acceder a la cámara, pero no va a escuchar nada de lo cuento. (Que es una especie de la finalidad del Camera.unlock())

Editar:

Después de examinar el código nativo, puedo ver que en CameraService.cpp mis llamadas a Camera.setParameters (parámetros) son rechazados porque mi ID de proceso no coincide con la ID de proceso que el servicio de la cámara tiene en el registro. Entonces parece que ese es mi obstáculo.

Edit2:

Parecería que la MediaPlayerService es el servicio principal que toma el control de la cámara cuando un vídeo está grabando. No sé si es posible, pero si de alguna manera pudiera comenzar ese servicio en mi propio proceso, debería poder omitir la llamada Camera.unlock().

Edit3:

Una última opción sería si pudiera de alguna manera obtener un puntero a la CameraHardwareInterface. Por lo que parece, esta es una interfaz específica del dispositivo y probablemente no incluya las comprobaciones PID. El principal problema con esto es que el único lugar donde puedo encontrar un puntero está en CameraService, y CameraService no está hablando.

Edit4: (varios meses después)

En este punto, creo que no es posible hacer lo que yo quería. No quiero eliminar la pregunta sobre la posibilidad de que alguien la responda, pero no estoy buscando activamente una respuesta. (Sin embargo, recibir una respuesta válida sería increíble.)

+1

Realmente no veo por qué piensas que esto es posible. Yo esperaría que la grabación de video tomara el control completo de la cámara. Se requeriría una codificación especial para permitir que otra cosa controle la cámara al mismo tiempo. –

+1

Estoy totalmente de acuerdo, no creo que sea posible en este punto tampoco, solo estoy dejando la pregunta aquí en este momento, en caso de que alguien encuentre milagrosamente la manera. – thepenguin77

Respuesta

10

me encontré con un problema similar. El usuario debería poder cambiar el modo de flash durante la grabación para satisfacer sus necesidades dependiendo de la situación de la luz. Después de algunas investigaciones, llegué a la siguiente solución:

Supongo que ya ha configurado un SurfaceView adecuado y un SurfaceHolder con sus devoluciones de llamada necesarias. La primera cosa que hice estaba proporcionando el código (variables no declaradas son globales):

public void surfaceCreated(SurfaceHolder holder) { 
    try { 
     camera = Camera.open(); 

     parameters = camera.getParameters(); 
     parameters.setFlashMode(Parameters.FLASH_MODE_OFF); 

     camera.setParameters(parameters); 
     camera.setPreviewDisplay(holder); 
     camera.startPreview(); 

     recorder = new MediaRecorder(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    }  
} 

Mi siguiente paso fue la inicialización y la preparación de la grabadora:

private void initialize() { 
    camera.unlock(); 

    recorder.setCamera(camera); 
    recorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER); 
    recorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); 
    recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); 
    recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC); 
    recorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264); 
    recorder.setVideoFrameRate(20); 
    recorder.setOutputFile(filePath); 

    try { 
     recorder.prepare(); 
    } catch (IllegalStateException e) { 
     e.printStackTrace(); 
     finish(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
     finish(); 
    } 
} 

Es importante señalar, que camera.unlock() debe llamarse ANTES de todo el proceso de inicialización del grabador de medios. Dicho esto, también tenga en cuenta el orden correcto de cada propiedad del conjunto; de lo contrario, obtendrá una IllegalStateException cuando llame a prepare() o start(). Cuando se trata de grabar, hago esto. Esto suele ser provocada por un elemento de vista:

public void record(View view) { 
    if (recording) { 
     recorder.stop(); 

     //TODO: do stuff.... 

     recording = false; 
    } else { 
     recording = true; 

     initialize(); 
     recorder.start(); 
    } 
} 

Así que ahora, por fin puedo grabar correctamente. Pero, ¿qué pasa con ese flash? Por último, pero no menos importante, aquí viene la magia detrás de las escenas:

public void flash(View view) { 
    if(!recording) { 
     camera.lock(); 
    } 

    parameters.setFlashMode(parameters.getFlashMode().equals(Parameters.FLASH_MODE_TORCH) ? Parameters.FLASH_MODE_OFF : Parameters.FLASH_MODE_TORCH); 
    camera.setParameters(parameters); 

    if(!recording) { 
     camera.unlock(); 
    } 
} 

Cada vez que llame a ese método a través de una acción onClick puedo cambiar el modo de flash, incluso durante la grabación. Solo tenga cuidado de bloquear la cámara correctamente. Una vez que la grabadora de medios adquiera la cerradura durante la grabación, no tendrá que bloquear/desbloquear la cámara nuevamente. Ni siquiera funciona. Esto fue probado en un Samsung Galaxy S3 con Android-Version 4.1.2. Espero que este enfoque ayude.

+0

Actualmente no tengo tiempo para probar esto afuera. Pero, ¿por qué funciona esto? Parece que si está grabando actualmente, flash() no bloqueará la cámara, y como ya se ha desbloqueado, la cámara.setParameters() fallará. Y gracias por ser la primera persona en responder la pregunta. – thepenguin77

+0

No tengo una visión profunda aquí, pero supongo que la grabadora adquiere un bloqueo exclusivo entre las llamadas start() y stop(). Entonces el acceso para otros procesos a este recurso es denegado durante ese tiempo, excepto por el hilo principal de ui donde ocurre la grabación y dado que también maneja las llamadas de acción de la interfaz de usuario, este enfoque debería funcionar bien. – fje

+0

Ah, entonces ¿solo el subproceso de interfaz de usuario puede cambiar el estado del flash? – thepenguin77

-2

Para acceder a la cámara del dispositivo, debe declarar el permiso de CAMERA en su manifiesto de Android. También asegúrese de incluir el elemento de manifiesto <uses-feature> para declarar las características de la cámara utilizadas por su aplicación. Por ejemplo, si se utiliza la función de cámara y enfoque automático, el Manifiesto debe incluir lo siguiente:

<uses-permission android:name="android.permission.CAMERA" /> 
<uses-feature android:name="android.hardware.camera" /> 
<uses-feature android:name="android.hardware.camera.autofocus" /> 

Una muestra que los controles de soporte del soplete podría ser algo como esto:

//Create camera and parameter objects 
private Camera mCamera; 
private Camera.Parameters mParameters; 
private boolean mbTorchEnabled = false; 

//... later in a click handler or other location, assuming that the mCamera object has already been instantiated with Camera.open() 
mParameters = mCamera.getParameters(); 

//Get supported flash modes 
List flashModes = mParameters.getSupportedFlashModes(); 

//Make sure that torch mode is supported 
//EDIT - wrong and dangerous to check for torch support this way 
//if(flashModes != null && flashModes.contains("torch")){ 
if(flashModes != null && flashModes.contains(Camera.Parameters.FLASH_MODE_TORCH)){ 
    if(mbTorchEnabled){ 
     //Set the flash parameter to off 
     mParameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF); 
    } 
    else{ 
     //Set the flash parameter to use the torch 
     mParameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH); 
    } 

    //Commit the camera parameters 
    mCamera.setParameters(mParameters); 

    mbTorchEnabled = !mbTorchEnabled; 
} 

Para encender la antorcha, sólo tiene que establecer el parámetro de la cámara Camera.Parameters.FLASH_MODE_TORCH

Camera mCamera; 
Camera.Parameters mParameters; 

//Get a reference to the camera/parameters 
mCamera = Camera.open(); 
mParameters = mCamera.getParameters(); 

//Set the torch parameter 
mParameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH); 

//Comit camera parameters 
mCamera.setParameters(mParameters); 

Para encender la antorcha fuera, establece Camera.Parameters.FLASH_MODE_OFF

+1

Esto realmente no ayuda en absoluto. Sé cómo encender el flash, el problema es alternar el flash mientras se está grabando un video. – thepenguin77

+0

Esto no responde la pregunta. La pregunta es cómo encender el flash mientras se está grabando un video. – kunal18

0

probar este .. espero que trabajar .. :)

private static Torch torch; 

      public Torch() { 
      super(); 
      torch = this; 
      } 

      public static Torch getTorch() { 
      return torch; 
      } 

      private void getCamera() { 
      if (mCamera == null) { 
       try { 
       mCamera = Camera.open(); 
       } catch (RuntimeException e) { 
       Log.e(TAG, "Camera.open() failed: " + e.getMessage()); 
       } 
      } 
      } 
     public void toggleLight(View view) { 
      toggleLight(); 
      } 

      private void toggleLight() { 
      if (lightOn) { 
       turnLightOff(); 
      } else { 
       turnLightOn(); 
      } 
      } 

      private void turnLightOn() { 
      if (!eulaAgreed) { 
       return; 
      } 
      if (mCamera == null) { 
       Toast.makeText(this, "Camera not found", Toast.LENGTH_LONG); 
        button.setBackgroundColor(COLOR_WHITE); 
       return; 
      } 
      lightOn = true; 
      Parameters parameters = mCamera.getParameters(); 
      if (parameters == null) { 
        button.setBackgroundColor(COLOR_WHITE); 
       return; 
     } 
      List<String> flashModes = parameters.getSupportedFlashModes(); 
       if (flashModes == null) { 
        button.setBackgroundColor(COLOR_WHITE); 
       return; 
      } 
      String flashMode = parameters.getFlashMode(); 
      Log.i(TAG, "Flash mode: " + flashMode); 
      Log.i(TAG, "Flash modes: " + flashModes); 
      if (!Parameters.FLASH_MODE_TORCH.equals(flashMode)) { 
        if (flashModes.contains(Parameters.FLASH_MODE_TORCH)) { 
       parameters.setFlashMode(Parameters.FLASH_MODE_TORCH); 
       mCamera.setParameters(parameters); 
       button.setBackgroundColor(COLOR_LIGHT); 
       startWakeLock(); 
       } else { 
       Toast.makeText(this, "Flash mode (torch) not supported", 
        Toast.LENGTH_LONG); 
         button.setBackgroundColor(COLOR_WHITE); 
       Log.e(TAG, "FLASH_MODE_TORCH not supported"); 
       } 
      } 
      } 
     private void turnLightOff() { 
      if (lightOn) { 
        button.setBackgroundColor(COLOR_DARK); 
       lightOn = false; 
       if (mCamera == null) { 
       return; 
       } 
       Parameters parameters = mCamera.getParameters(); 
       if (parameters == null) { 
       return; 
       } 
       List<String> flashModes = parameters.getSupportedFlashModes(); 
       String flashMode = parameters.getFlashMode(); 
        if (flashModes == null) { 
       return; 
       } 
       Log.i(TAG, "Flash mode: " + flashMode); 
       Log.i(TAG, "Flash modes: " + flashModes); 
       if (!Parameters.FLASH_MODE_OFF.equals(flashMode)) { 
         if (flashModes.contains(Parameters.FLASH_MODE_OFF)) { 
        parameters.setFlashMode(Parameters.FLASH_MODE_OFF); 
        mCamera.setParameters(parameters); 
        stopWakeLock(); 
       } else { 
        Log.e(TAG, "FLASH_MODE_OFF not supported"); 
       } 
       } 
      } 
      } 
    private void startPreview() { 
     if (!previewOn && mCamera != null) { 
      mCamera.startPreview(); 
      previewOn = true; 
     } 
     } 

     private void stopPreview() { 
     if (previewOn && mCamera != null) { 
      mCamera.stopPreview(); 
      previewOn = false; 
     } 
     } 

     private void startWakeLock() { 
     if (wakeLock == null) { 
      Log.d(TAG, "wakeLock is null, getting a new WakeLock"); 
      PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); 
      Log.d(TAG, "PowerManager acquired"); 
      wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKE_LOCK_TAG); 
      Log.d(TAG, "WakeLock set"); 
     } 
     wakeLock.acquire(); 
     Log.d(TAG, "WakeLock acquired"); 
     } 

     private void stopWakeLock() { 
     if (wakeLock != null) { 
      wakeLock.release(); 
      Log.d(TAG, "WakeLock released"); 
     } 
     } 
    @Override 
     public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     if (Eula.show(this)) { 
      eulaAgreed = true; 
     } 
     setContentView(R.layout.main); 
     button = findViewById(R.id.button); 
     surfaceView = (SurfaceView) this.findViewById(R.id.surfaceview); 
     surfaceHolder = surfaceView.getHolder(); 
     surfaceHolder.addCallback(this); 
     surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 
     disablePhoneSleep(); 
     Log.i(TAG, "onCreate"); 
     } 
+0

Ok, entonces, antes que nada, esto no responde mi pregunta en absoluto y tiene mucha información inútil. En segundo lugar, es un copiar y pegar directamente desde aquí: http://torch.googlecode.com/svn/trunk/src/com/colinmcdonough/android/torch/Torch.java – thepenguin77

1

Después de preparar la grabadora de medios, use camera.lock(), y luego establezca los parámetros que desee establecer en la cámara. Pero antes de comenzar a grabar necesita llamar a camera.unlock(), y después de detener el grabador multimedia, debe llamar a camera.lock() para comenzar la vista previa. ¡¡¡Disfruta !!!

Cuestiones relacionadas