2012-07-24 103 views
26

我需要一種方式來控制Android設備上的相機閃光燈,以便在錄製視頻時進行控制。我正在製作閃光燈應用程序,使用閃爍的閃光燈拍攝視頻會導致能夠記錄高速移動的物體,如風扇葉片。錄製視頻時啓用相機閃光燈

只能通過啓動視頻預覽並在相機參數中設置FLASH_MODE_TORCH來啓用閃光燈。這看起來像這樣:

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

一旦預覽開始,我可以來回翻轉該參數打開和關閉指示燈。這很好,直到我嘗試錄製視頻。麻煩的是,爲了將相機提供給MediaRecorder,我首先必須解鎖它。

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

之後,解鎖,我不能再改變相機參數,因此無法改變閃光燈狀態。

我不知道它實際上是有可能做到這一點,因爲我不是最好的,在Java的黑客,但這裏是我知道的:

  • Camera.unlock()是土生土長的方法,所以我不能真正看到它鎖定我的方式背後的機制
  • Camera.Parameter有一個包含其所有參數的HashMap
  • Camera.setParameters(Parameters)接受HashMap,將其轉換爲字符串,並將其傳遞給本地方法
  • 我可以消除所有參數,但從HashMap中的割炬模式和相機仍然會接受它

所以,我仍然可以訪問相機,但它不會聽我講的任何東西。 (這是一種Camera.unlock()的目的)

編輯:

檢查本機代碼後,我可以看到,在我的CameraService.cpp到Camera.setParameters電話(參數)被拒絕,因爲我的進程ID與攝像機服務記錄的進程ID不匹配。所以看起來這是我的障礙。

EDIT2:

這樣看來,所述MediaPlayerService是主服務,拍攝攝像機的控制當視頻正在記錄。我不知道這是否可行,但如果我可以在我自己的過程中以某種方式啓動該服務,我應該可以跳過Camera.unlock()調用。

EDIT3:

最後一個選擇是,如果我可以某種方式得到的指針CameraHardwareInterface。從外觀上看,這是一個設備特定的接口,可能不包含PID檢查。這個問題的主要問題是唯一可以找到它的指針位於CameraService中,並且CameraService不在說話。

Edit4:(幾個月後)

在這一點上,我不認爲這是可以做到什麼,我本來想。我不想刪除有人會回答的問題,但我不積極尋求答案。 (雖然接收到有效的答案會很棒。)

+1

我真的不明白爲什麼你會認爲這是可能的。我希望視頻錄製可以完全控制攝像機。這需要特殊的編碼才能讓其他東西同時控制相機。 – 2012-10-16 01:08:40

+1

我完全同意,在這一點上我不認爲這是可能的,但我現在只是在這個問題上離開這個問題,而不會有人奇蹟般地找到方法。 – thepenguin77 2012-11-03 01:27:07

回答

10

我遇到了類似的問題。用戶應該能夠在記錄期間改變閃光模式以根據光線情況來滿足他們的需要。經過一些調查研究後,我得出以下解決方案:

我假設您已經設置了適當的SurfaceView和SurfaceHolder及其必要的回調函數。我做的第一件事就是提供這些代碼(不聲明的變量是全局):

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

我的下一步是初始化和準備記錄:

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

必須注意的是重要的,那camera.unlock ()必須在媒體記錄器的整個初始化過程之前調用。這也說明了每個set屬性的正確順序,否則在調用prepare()或start()時會得到一個IllegalStateException異常。談到錄音,我這樣做。這通常會由視圖元素觸發:

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

     //TODO: do stuff.... 

     recording = false; 
    } else { 
     recording = true; 

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

所以現在,我終於可以正確記錄了。但那閃光是什麼?最後但並非最不重要的,來這裏的幕後法寶:

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

每次我調用該方法通過一個onClick動作我可以改變閃光模式,即使在錄製期間。請注意正確鎖定相機。一旦記錄過程中媒體記錄器鎖定了鎖定,就不必再次鎖定/解鎖相機。它甚至不工作。這是在Android版本4.1.2的三星Galaxy S3上測試的。希望這種方法有幫助。

+0

我目前沒有時間嘗試這一點。但爲什麼這個工作?看起來,如果您當前正在錄製,flash()將不會鎖定相機,並且由於它已被解鎖,camera.setParameters()將失敗。並感謝成爲第一個真正回答問題的人。 – thepenguin77 2013-02-14 04:02:27

+0

我在這裏沒有深入的瞭解,但我認爲錄音機會在調用start()和stop()之間獲得一個獨佔鎖。所以在這段時間內,其他進程對此資源的訪問被拒絕,除了記錄發生的ui主線程以外,並且由於它也處理ui動作調用,所以此方法應該工作得很好。 – fje 2013-02-14 21:29:14

+0

哦,所以只有UI線程才能改變flash狀態? – thepenguin77 2013-02-15 02:08:40

-2

要訪問設備相機,您必須在Android清單中聲明CAMERA權限。還要確保包含<uses-feature>清單元素來聲明應用程序使用的相機功能。例如,如果您使用的攝像頭和自動對焦功能,您的清單應包括以下內容:

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

來檢查火炬的支持可能看起來像這樣的例子:

//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; 
} 

要打開對,你只需設置相機參數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); 

要打開的火炬熄滅,火炬設置Camera.Parameters.FLASH_MODE_OFF

+1

這並沒有真正的幫助。我知道如何開啓閃光燈,在錄製視頻時切換閃光燈的麻煩。 – thepenguin77 2012-09-04 05:22:59

+0

這不回答這個問題。問題是如何在錄製視頻時打開閃光燈。 – kunal18 2015-01-20 10:40:53

0

試試這個..希望它會工作.. :)

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

好的,首先,這並不能回答我的問題,而且有很多無用信息。 其次,它是從這裏直接複製/粘貼: http://torch.googlecode.com/svn/trunk/src/com/colinmcdonough/android/torch/Torch.java – thepenguin77 2012-12-16 22:48:04

1

準備好媒體記錄器後,使用camera.lock(),然後設置您想要設置爲相機的任何參數。 但是在開始錄製之前,您需要調用camera.unlock(),並且在停止媒體錄製器之後,您需要調用camera.lock()以開始預覽。 享受!