Activación del flash de la cámara durante la grabación de vídeo

Necesito una forma de controlar el flash de la cámara en un dispositivo Android mientras graba vídeo. Estoy haciendo una aplicación de luz estroboscópica, y la toma de vídeos con una luz estroboscópica parpadeante resultaría en la capacidad de grabar objetos que se mueven a altas velocidades, como una paleta de ventilador.

El flash sólo se puede activar iniciando una vista previa de vídeo 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 que la inspección previo ha comenzado, puedo girar ese parámetro hacia adelante y hacia atrás para encender y apagar la luz. Esto funciona bien hasta que intente grabar un video. El problema es que para dar 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-hacking, pero aquí es lo que sé:

  • Camera.unlock () es un método nativo, así que realmente no puedo ver el mecanismo detrás de la forma en que me bloquea
  • Camera.Parameter tiene un HashMap que contiene todos sus parámetros
  • Camera.setParameters (Parameters) toma el HashMap, lo convierte en una cadena y lo pasa a un método nativo
  • Puedo eliminar todos los parámetros, pero TORCH-MODE de la HashMap y la Cámara lo aceptará

Por lo tanto, todavía puedo acceder a la cámara, pero no escuchará nada que decir. (Cuál es la clase del propósito de Camera.unlock ())

Editar:

Después de examinar el código nativo, puedo ver que en CameraService.cpp mis llamadas a Camera.setParameters (Parameters) se rechazan porque mi ID de proceso no coincide con el ID de proceso que el servicio de cámara tiene registrado. Así que parece que ese es mi obstáculo.

Edit2:

Parece que MediaPlayerService es el servicio principal que toma el control de la cámara cuando se está grabando un video. No sé si es posible, pero si pudiera de alguna manera iniciar ese servicio en mi propio proceso, debería ser capaz de saltar la llamada Camera.unlock ().

Editar3:

Una última opción sería si de alguna manera podría obtener un puntero a la CameraHardwareInterface. Desde el aspecto de ello, esta es una interfaz específica del dispositivo y probablemente no incluye las verificaciones PID. El problema principal con esto sin embargo es que el único lugar que puedo encontrar un puntero a él está en CameraService, y CameraService no está hablando.

Edit4: (varios meses después)

En este punto, no creo que sea posible hacer lo que originalmente quería. No quiero borrar la pregunta sobre la posibilidad de que alguien responda, pero no busco una respuesta. (Aunque, recibir una respuesta válida sería impresionante.)

Encontré un problema similar. El usuario debe ser capaz de 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 de investigación llegué a la siguiente solución:

Supongo, que ya ha configurado un SurfaceView adecuado y un SurfaceHolder con sus devoluciones de llamada necesarias. Lo primero que hice fue proporcionar este código (las 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 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 tener en cuenta que camera.unlock () tiene que ser llamado ANTES de todo el proceso de inicialización del grabador de medios. Dicho esto, tenga en cuenta el orden correcto de cada propiedad de conjunto, de lo contrario obtendrá una IllegalStateException al llamar a prepare () oa start (). Cuando se trata de grabación, hago esto. Esto suele ser activado por un elemento view:

 public void record(View view) { if (recording) { recorder.stop(); //TODO: do stuff.... recording = false; } else { recording = true; initialize(); recorder.start(); } } 

Así que ahora, finalmente 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 llamo a ese método a través de una acción onClick puedo cambiar el modo de flash, incluso durante la grabación. Apenas tenga cuidado de bloquear correctamente la cámara. Una vez que el bloqueo es adquirido por el grabador de medios durante la grabación, no tiene que bloquear / desbloquear la cámara de nuevo. Ni siquiera funciona. Esto fue probado en un Samsung Galaxy S3 con Android versión 4.1.2. Espero que este enfoque ayuda.

Después de preparar el grabador de medios, utilice camera.lock () y, a continuación, establezca los parámetros que desee establecer en la cámara. Pero antes de comenzar a grabar necesitas llamar a camera.unlock (), y después de detener la grabadora de medios tienes que llamar a camera.lock () para iniciar la vista previa. ¡¡¡Disfrutar!!!

Prueba esto .. espero que funcione .. 🙂

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

Para acceder a la cámara del dispositivo, debe declarar el permiso CÁMARA en su manifiesto de Android. También asegúrese de incluir el elemento manifesto <uses-feature> para declarar las características de la cámara utilizadas por su aplicación. Por ejemplo, si utiliza la cámara y la función de enfoque automático, su 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 comprueba el soporte de la antorcha puede 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 activar la antorcha, simplemente ajuste 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 apagar la antorcha, ajuste Camera.Parameters.FLASH_MODE_OFF

  • Cuando su BroadcastReceiver se invoca a través de un Intent, ¿en qué proceso se ejecuta?
  • ¿Cómo puedo ver qué wakelocks están activos?
  • Android runtime.getruntime (). Exec () obtener id de proceso
  • ¿Va a correr un servicio Android en un proceso diferente, contribuir al mismo límite de montón?
  • Servicio de Android: proceso vs. no
  • Obtener (real) proceso de primer plano mediante activityManager.getRunningAppProcesses ()
  • GetRunningAppProcesses devuelve la lista vacía en Android M (5.1.1)
  • La actividad de un proceso muerto sigue visible en la lista después de que presionó
  • ¿El nombre del proceso es el mismo que el nombre del paquete en android?
  • Ejecución de un comando de shell para copiar archivos de la aplicación Android
  • Android proceso asesino
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.