天天看點

Android Camera開發:掃描二維碼,周期性循環自動聚焦auto focus挂掉原因分析(preview is not enabled)

問題背景:要讓Camera循環聚焦,聚焦完成後進行拍照,在拍照的資料裡截取出一定區域的資料。在initCamera裡設定聚焦模式:

[java] view plain copy print ?

Android Camera開發:掃描二維碼,周期性循環自動聚焦auto focus挂掉原因分析(preview is not enabled)
Android Camera開發:掃描二維碼,周期性循環自動聚焦auto focus挂掉原因分析(preview is not enabled)
  1. <span style="font-family:Comic Sans MS;font-size:18px;">            List<String> allFocus = myParam.getSupportedFocusModes();  
  2.             for(String ff:allFocus){  
  3.                 Log.i(tag, ff + "...FOCUS...");  
  4.             }  
  5.             if(allFocus.contains(Camera.Parameters.FLASH_MODE_AUTO)){  
  6.                 myParam.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);    
  7.                 Focus_Mode = 1;  
  8.             }  
  9.             else if(allFocus.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)){  
  10.                 myParam.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);  // FOCUS_MODE_CONTINUOUS_PICTURE FOCUS_MODE_AUTO  
  11.                 Focus_Mode = 2;  
  12.             }  
  13.             myCamera.setParameters(myParam);</span>  

然後有個GetPictureThread進行每隔一段時間聚焦并且拍照:

[java] view plain copy print ?

Android Camera開發:掃描二維碼,周期性循環自動聚焦auto focus挂掉原因分析(preview is not enabled)
Android Camera開發:掃描二維碼,周期性循環自動聚焦auto focus挂掉原因分析(preview is not enabled)
  1. <span style="font-family:Comic Sans MS;font-size:18px;">    class GetPictureThread implements Runnable{  
  2.         public void run() {  
  3.             // TODO Auto-generated method stub  
  4.             while(!Thread.currentThread().isInterrupted()){  
  5.                 if(myCamera != null && isPreview){  
  6.                     if(Focus_Mode == 1 && (!isFocusing)){  
  7.                         myCamera.autoFocus(mAutoFocusCallback);  
  8.                     }  
  9.                     else if(Focus_Mode == 2){  
  10.                         myCamera.takePicture(myShutterCallback, null, myJpegCallback);  
  11.                     }  
  12.                     try {  
  13.                         Thread.sleep(3000);  
  14.                     } catch (InterruptedException e) {  
  15.                         // TODO Auto-generated catch block  
  16.                         e.printStackTrace();  
  17.                         Thread.currentThread().interrupt();  
  18.                     }  
  19.                 }  
  20.             }  
  21.         }  
  22.     }</span>  

原來設的GetPictureThread是每隔1200毫秒觸發一次,在中興的Geek手機上一切良好。在華為G700上,總是拍一張就挂,挂的log如下:

[java] view plain copy print ?

Android Camera開發:掃描二維碼,周期性循環自動聚焦auto focus挂掉原因分析(preview is not enabled)
Android Camera開發:掃描二維碼,周期性循環自動聚焦auto focus挂掉原因分析(preview is not enabled)
  1. <span style="font-family:Comic Sans MS;font-size:18px;">12-07 18:05:33.227: D/dalvikvm(13589): threadid=11: exiting  
  2. 12-07 18:05:33.227: W/dalvikvm(13589): threadid=11: thread exiting with uncaught exception (group=0x417669a8)  
  3. 12-07 18:05:33.230: E/AndroidRuntime(13589): FATAL EXCEPTION: Thread-1177  
  4. 12-07 18:05:33.230: E/AndroidRuntime(13589): java.lang.RuntimeException: autoFocus failed  
  5. 12-07 18:05:33.230: E/AndroidRuntime(13589):    at android.hardware.Camera.native_autoFocus(Native Method)  
  6. 12-07 18:05:33.230: E/AndroidRuntime(13589):    at android.hardware.Camera.autoFocus(Camera.java:1120)  
  7. 12-07 18:05:33.230: E/AndroidRuntime(13589):    at org.yanzi.rectphoto_wuzhou.RectPhoto$GetPictureThread.run(RectPhoto.java:428)  
  8. 12-07 18:05:33.230: E/AndroidRuntime(13589):    at java.lang.Thread.run(Thread.java:838)  
  9. 12-07 18:05:33.240: I/Camera(13589): handleMessage: 2</span>  

反正就是auto focus出問題了,單看這裡的log看不出是以然來。話說2000元買的G'700還是支援自動聚焦的吧。截取所有的log又看了次,搜尋關鍵字:autofocus,得到以下資訊:

[java] view plain copy print ?

Android Camera開發:掃描二維碼,周期性循環自動聚焦auto focus挂掉原因分析(preview is not enabled)
Android Camera開發:掃描二維碼,周期性循環自動聚焦auto focus挂掉原因分析(preview is not enabled)
  1. <span style="font-family:Comic Sans MS;font-size:18px;">  F:\1.log (12 hits)  
  2.     Line 12829: 12-08 10:14:19.477 D/CameraClient(  142): <strong>autoFocus</strong> (pid 10314)  
  3.     Line 12831: 12-08 10:14:19.477 D/MtkCam/CamDevice(  142): (599)(Default:0)[CamDevice::<strong>autoFocus</strong>] +  
  4.     Line 12834: 12-08 10:14:19.477 D/MtkCam/CamAdapter(  142): (599)(Default)[<strong>autoFocus</strong>] +  
  5.     Line 12861: 12-08 10:14:19.477 D/aaa_hal (  142): [autoFocus()]  
  6.     Line 12877: 12-08 10:14:19.477 D/MtkCam/CamAdapter(  142): (599)(Default)[<strong>autoFocus</strong>] -  
  7.     Line 20489: 12-08 10:14:20.677 D/CameraClient(  142): <strong>autoFocus</strong> (pid 10314)  
  8.     Line 20491: 12-08 10:14:20.677 D/MtkCam/CamDevice(  142): (142)(Default:0)[CamDevice::<strong>autoFocus</strong>] +  
  9.     Line 20503: 12-08 10:14:20.678 E/MtkCam/CamDevice(  142): (142)(Default:0)[CamDevice::<strong>autoFocus</strong>] <span style="color:#ff0000;"><strong>preview is not enabled </strong></span>(autoFocus){#552:mediatek/hardware/camera/device/CamDevice/CamDevice.cpp}  
  10.     Line 20503: 12-08 10:14:20.678 E/MtkCam/CamDevice(  142): (142)(Default:0)[CamDevice::autoFocus] <strong><span style="color:#ff0000;">preview is not enabled (autoFocus){#552:mediatek/hardware/camera/device/CamDevice/CamDevice.cpp}</span></strong>  
  11.     Line 20512: 12-08 10:14:20.679 E/AndroidRuntime(10314): java.lang.RuntimeException: <strong>autoFocus</strong> failed  
  12.     Line 20514: 12-08 10:14:20.679 E/AndroidRuntime(10314):     at android.hardware.Camera.native_<strong>autoFocus</strong>(Native Method)  
  13.     Line 20516: 12-08 10:14:20.679 E/AndroidRuntime(10314):     at android.hardware.Camera.<strong>autoFocus</strong>(Camera.java:1120)</span>  

可以看到,上面提到preview is not enabled,竟然說preview沒有開啟。可我明明preview已經開啟了,而且我在掃描線程裡設定了判斷if(myCamera != null && isPreview)。參考國外這位大大的文章http://www.hitziger.net/blog/android-camera-autofocus-failed/ 上面提到auto focus失敗原因是surfaceholder還沒有被建立,換句話camera還沒有開啟預覽就進行自動聚焦了。但其實我的掃描線程啟動已經加了延遲,確定camera預覽已經開啟,姑且信了吧。把線程開啟的地方加到了surfacechanged,因為我的initcamera是在surfacechanged裡面,initcamera的最後就是startPreview。但依然出錯。我加了個延遲在surfacechanged依舊報錯。後來參考又一個人的文章,在activity的onResume方法裡進行mySurfaceHolder.addCallback(this);確定surfaceview已經建立了再添加回調。這樣幹确實嚴謹一點,但依舊報錯。事實上這樣做不是必須的,因為我把GetPictureThread去掉之後,一切ok。我加個button,拍照的時候自動聚焦,如果聚焦成功再觸發takePicture也是ok的。

問題出在哪呢?最後才恍然大悟,問題在拍照的jpegCallback上,代碼如下:

[java] view plain copy print ?

Android Camera開發:掃描二維碼,周期性循環自動聚焦auto focus挂掉原因分析(preview is not enabled)
Android Camera開發:掃描二維碼,周期性循環自動聚焦auto focus挂掉原因分析(preview is not enabled)
  1. <span style="font-family:Comic Sans MS;font-size:18px;">    PictureCallback myJpegCallback = new PictureCallback()   
  2.     {  
  3.         public void onPictureTaken(byte[] data, Camera camera) {  
  4.             // TODO Auto-generated method stub  
  5.             Log.i(tag, "myJpegCallback:onPictureTaken...");  
  6.             long t1 = System.currentTimeMillis();  
  7.             if(null != data){  
  8.                 mBitmap = BitmapFactory.decodeByteArray(data, 0, data.length);            
  9.                 <strong><span style="color:#ff0000;">myCamera.stopPreview();</span></strong>  
  10.                 isPreview = false;  
  11.             }  
  12.             Matrix matrix = new Matrix();  
  13.             matrix.postRotate((float)90.0);  
  14.             Bitmap rotaBitmap = Bitmap.createBitmap(mBitmap, 0, 0, mBitmap.getWidth(), mBitmap.getHeight(), matrix, false);  
  15.             //Bitmap sizeBitmap = Bitmap.createScaledBitmap(rotaBitmap, 540, 800, true);  
  16.             Bitmap rectBitmap = Bitmap.createBitmap(rotaBitmap, square.left, square.top, square.width(), square.height());  
  17.             if(null != rectBitmap)  
  18.             {             
  19.                 saveThread.setSaveBitmap(rectBitmap);  
  20.             }  
  21.             //ImageUtil.saveJpeg(rotaBitmap);  
  22.             <span style="color:#ff0000;"><strong>myCamera.startPreview();</strong></span>  
  23.             isPreview = true;  
  24.             long t2 = System.currentTimeMillis();  
  25.             Log.i(tag, "本次儲存耗時:" + (t2 - t1) + "毫秒");  
  26.         }  
  27.     };</span>  

注意在拍照時,camera首先停止預覽儲存完照片後再次開啟預覽。盡管我加了isPreview這個标志,但這個标志位是不起啥作用的。推測,stoppreviw和startpreview的時候,camera在底層是異步處理的。也就是說程式執行到startpreview,isPreview為真了,但這時camera還沒有完全開啟預覽,而掃描線程再次觸發auto focus就會報上面的錯誤。後來我對這個myJpegCallback測了下時間,完全同樣的代碼,在geek手機上是900多毫秒左右,在G700上是1800毫秒左右,将近2秒了,是以掃描周期一定得大于這個時間。後來将掃描周期設為3秒,兩個手機都ok了。但G700上偶發的也還是會報錯,這是因為記憶體占用太多,手機速度變慢,myJpegCallback回調的周期超過了3秒,重新開機下手機就好了。在AutoFocusCallback裡設定标志isFocusing也是必須的。

[java] view plain copy print ?

Android Camera開發:掃描二維碼,周期性循環自動聚焦auto focus挂掉原因分析(preview is not enabled)
Android Camera開發:掃描二維碼,周期性循環自動聚焦auto focus挂掉原因分析(preview is not enabled)
  1. <span style="font-family:Comic Sans MS;font-size:18px;">final AutoFocusCallback mAutoFocusCallback = new AutoFocusCallback() {  
  2.         public void onAutoFocus(boolean success, Camera camera) {  
  3.             // TODO Auto-generated method stub  
  4.             isFocusing = true;  
  5.             if(success){  
  6.                 Log.i(tag, "聚焦成功...");  
  7.                 myCamera.takePicture(myShutterCallback, null, myJpegCallback);  
  8.             }  
  9.             else{  
  10.                 Log.i(tag, "聚焦失敗...");  
  11.             }     
  12.             isFocusing = false;  
  13.         }  
  14.     };</span>  

看來,要玩Camera還是得整個高端點的手機啊!!!

參考http://stackoverflow.com/questions/5878042/android-camera-autofocus-on-demand 自從API9,就有了連續聚焦。參考官方對聚焦模式的說明,http://developer.android.com/reference/android/hardware/Camera.Parameters.html#FOCUS_MODE_CONTINUOUS_VIDEO 聚焦最強的是FOCUS_MODE_CONTINUOUS_PICTURE 它是和AutoFocus相容的,其次是

FOCUS_MODE_CONTINUOUS_VIDEO,聚焦強度弱于CONTINUOUS_PICTURE. 是以如果能滿足需要的話,FOCUS_MODE_CONTINUOUS_VIDEO   就ok了!有些資料不建議周期性auto focus,但看今天的掃描二維碼貌似都是用的auto focus模式,而不是連續聚焦,是以可以肯定,在這種模式下,獲得資料是從預覽幀裡截取的,而不是拍照。因為拍照在普通手機上一定得停預覽然後開預覽,這個花費時間太大了!如果是為了高更分辨率,隻能拍照的話一定要控制好掃描周期。