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

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

 

			List 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);

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

 

 

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

		}
	}

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

 

 

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

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

 

 

  F:.log (12 hits)
	Line 12829: 12-08 10:14:19.477 D/CameraClient(  142): autoFocus (pid 10314)
	Line 12831: 12-08 10:14:19.477 D/MtkCam/CamDevice(  142): (599)(Default:0)[CamDevice::autoFocus] +
	Line 12834: 12-08 10:14:19.477 D/MtkCam/CamAdapter(  142): (599)(Default)[autoFocus] +
	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)[autoFocus] -
	Line 20489: 12-08 10:14:20.677 D/CameraClient(  142): autoFocus (pid 10314)
	Line 20491: 12-08 10:14:20.677 D/MtkCam/CamDevice(  142): (142)(Default:0)[CamDevice::autoFocus] +
	Line 20503: 12-08 10:14:20.678 E/MtkCam/CamDevice(  142): (142)(Default:0)[CamDevice::autoFocus] preview is not enabled (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] preview is not enabled (autoFocus){#552:mediatek/hardware/camera/device/CamDevice/CamDevice.cpp}
	Line 20512: 12-08 10:14:20.679 E/AndroidRuntime(10314): java.lang.RuntimeException: autoFocus failed
	Line 20514: 12-08 10:14:20.679 E/AndroidRuntime(10314): 	at android.hardware.Camera.native_autoFocus(Native Method)
	Line 20516: 12-08 10:14:20.679 E/AndroidRuntime(10314): 	at android.hardware.Camera.autoFocus(Camera.java:1120)

可以看到,上面提到preview is not enabled,竟然說preview沒有開啟。可我明明preview已經開啟瞭,而且我在掃描線程裡設置瞭判斷if(myCamera != null && isPreview)。參考國外這位大大的帖子https://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上,代碼如下:

 

	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);			
				myCamera.stopPreview();
				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);
			myCamera.startPreview();
			isPreview = true;
			long t2 = System.currentTimeMillis();
			Log.i(tag, 本次保存耗時: + (t2 - t1) + 毫秒);
		}
	};

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

 

 

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

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

 

發佈留言