問題背景:要讓Camera循環聚焦,聚焦完成後進行拍照,在拍照的資料裡截取出一定區域的資料。在initCamera裡設定聚焦模式:
[java] view plain copy print ?
- <span style="font-family:Comic Sans MS;font-size:18px;"> List<String> allFocus = myParam.getSupportedFocusModes();
- for(String ff:allFocus){
- Log.i(tag, ff + "...FOCUS...");
- }
- if(allFocus.contains(Camera.Parameters.FLASH_MODE_AUTO)){
- myParam.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
- Focus_Mode = 1;
- }
- else if(allFocus.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)){
- myParam.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); // FOCUS_MODE_CONTINUOUS_PICTURE FOCUS_MODE_AUTO
- Focus_Mode = 2;
- }
- myCamera.setParameters(myParam);</span>
然後有個GetPictureThread進行每隔一段時間聚焦并且拍照:
[java] view plain copy print ?
- <span style="font-family:Comic Sans MS;font-size:18px;"> class GetPictureThread implements Runnable{
- public void run() {
- // TODO Auto-generated method stub
- while(!Thread.currentThread().isInterrupted()){
- if(myCamera != null && isPreview){
- if(Focus_Mode == 1 && (!isFocusing)){
- myCamera.autoFocus(mAutoFocusCallback);
- }
- else if(Focus_Mode == 2){
- myCamera.takePicture(myShutterCallback, null, myJpegCallback);
- }
- try {
- Thread.sleep(3000);
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- Thread.currentThread().interrupt();
- }
- }
- }
- }
- }</span>
原來設的GetPictureThread是每隔1200毫秒觸發一次,在中興的Geek手機上一切良好。在華為G700上,總是拍一張就挂,挂的log如下:
[java] view plain copy print ?
- <span style="font-family:Comic Sans MS;font-size:18px;">12-07 18:05:33.227: D/dalvikvm(13589): threadid=11: exiting
- 12-07 18:05:33.227: W/dalvikvm(13589): threadid=11: thread exiting with uncaught exception (group=0x417669a8)
- 12-07 18:05:33.230: E/AndroidRuntime(13589): FATAL EXCEPTION: Thread-1177
- 12-07 18:05:33.230: E/AndroidRuntime(13589): java.lang.RuntimeException: autoFocus failed
- 12-07 18:05:33.230: E/AndroidRuntime(13589): at android.hardware.Camera.native_autoFocus(Native Method)
- 12-07 18:05:33.230: E/AndroidRuntime(13589): at android.hardware.Camera.autoFocus(Camera.java:1120)
- 12-07 18:05:33.230: E/AndroidRuntime(13589): at org.yanzi.rectphoto_wuzhou.RectPhoto$GetPictureThread.run(RectPhoto.java:428)
- 12-07 18:05:33.230: E/AndroidRuntime(13589): at java.lang.Thread.run(Thread.java:838)
- 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 ?
- <span style="font-family:Comic Sans MS;font-size:18px;"> F:\1.log (12 hits)
- Line 12829: 12-08 10:14:19.477 D/CameraClient( 142): <strong>autoFocus</strong> (pid 10314)
- Line 12831: 12-08 10:14:19.477 D/MtkCam/CamDevice( 142): (599)(Default:0)[CamDevice::<strong>autoFocus</strong>] +
- Line 12834: 12-08 10:14:19.477 D/MtkCam/CamAdapter( 142): (599)(Default)[<strong>autoFocus</strong>] +
- Line 12861: 12-08 10:14:19.477 D/aaa_hal ( 142): [autoFocus()]
- Line 12877: 12-08 10:14:19.477 D/MtkCam/CamAdapter( 142): (599)(Default)[<strong>autoFocus</strong>] -
- Line 20489: 12-08 10:14:20.677 D/CameraClient( 142): <strong>autoFocus</strong> (pid 10314)
- Line 20491: 12-08 10:14:20.677 D/MtkCam/CamDevice( 142): (142)(Default:0)[CamDevice::<strong>autoFocus</strong>] +
- 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}
- 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>
- Line 20512: 12-08 10:14:20.679 E/AndroidRuntime(10314): java.lang.RuntimeException: <strong>autoFocus</strong> failed
- Line 20514: 12-08 10:14:20.679 E/AndroidRuntime(10314): at android.hardware.Camera.native_<strong>autoFocus</strong>(Native Method)
- 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 ?
- <span style="font-family:Comic Sans MS;font-size:18px;"> PictureCallback myJpegCallback = new PictureCallback()
- {
- public void onPictureTaken(byte[] data, Camera camera) {
- // TODO Auto-generated method stub
- Log.i(tag, "myJpegCallback:onPictureTaken...");
- long t1 = System.currentTimeMillis();
- if(null != data){
- mBitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
- <strong><span style="color:#ff0000;">myCamera.stopPreview();</span></strong>
- isPreview = false;
- }
- Matrix matrix = new Matrix();
- matrix.postRotate((float)90.0);
- Bitmap rotaBitmap = Bitmap.createBitmap(mBitmap, 0, 0, mBitmap.getWidth(), mBitmap.getHeight(), matrix, false);
- //Bitmap sizeBitmap = Bitmap.createScaledBitmap(rotaBitmap, 540, 800, true);
- Bitmap rectBitmap = Bitmap.createBitmap(rotaBitmap, square.left, square.top, square.width(), square.height());
- if(null != rectBitmap)
- {
- saveThread.setSaveBitmap(rectBitmap);
- }
- //ImageUtil.saveJpeg(rotaBitmap);
- <span style="color:#ff0000;"><strong>myCamera.startPreview();</strong></span>
- isPreview = true;
- long t2 = System.currentTimeMillis();
- Log.i(tag, "本次儲存耗時:" + (t2 - t1) + "毫秒");
- }
- };</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 ?
- <span style="font-family:Comic Sans MS;font-size:18px;">final AutoFocusCallback mAutoFocusCallback = new AutoFocusCallback() {
- public void onAutoFocus(boolean success, Camera camera) {
- // TODO Auto-generated method stub
- isFocusing = true;
- if(success){
- Log.i(tag, "聚焦成功...");
- myCamera.takePicture(myShutterCallback, null, myJpegCallback);
- }
- else{
- Log.i(tag, "聚焦失敗...");
- }
- isFocusing = false;
- }
- };</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相容的,其次是