I have some codes of taking picture which works in Android 2.1 and 2.2. But these codes broke at Android 2.3. After spending time to fix this issue which went in vain, I would like to ask for help here.
My code flow to take picture is like this:
create a class Camlayer extends SurfaceView
public class CamLayer extends SurfaceView implements SurfaceHolder.Callback {
private void init(Context context){
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
mCamera = Camera.open();
}
public CamLayer(Context context) {
super(context);
init(context);
}
public CamLayer(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
Log.i(TAG+".surfaceChanged", "being called!");
Log.i(TAG+".surfaceChanged", "w="+w);
Log.i(TAG+".surfaceChanged", "h="+h);
if (isPreviewRunning) {
mCamera.stopPreview();
}
try {
mCamera.setPreviewDisplay(holder);
mCamera.setPreviewCallback(mPreviewCallback);
} catch (IOException e) {
Log.e(TAG+".surfaceCreated", "mCamera.setPreviewDisplay(holder);");
}
Camera.Parameters p = mCamera.getParameters();
setOptimalSize(p, w, h, SIZEOFPREVIEW);
setOptimalSize(p, w, h, SIZEOFPICTURE);
mCamera.setParameters(p);
mCamera.startPreview();
isPreviewRunning = true;
}
public void takePicture(){
Log.i(TAG+".takePicture", "being called!");
mCamera.takePicture(null, null, mPictureCallback);
Log.i(TAG+".takePicture", "call ended!");
}
}
CamLayer.takePicture()
will be called by external classes to start.
The problem is that at Android 2.3.3, the takePicture
will hang, so an ANR problem is found. In /data/anr/traces.txt
, below are found. As you can see, the native_takePicture
never returns.
DALVIK THREADS:
(mutexes: tll=0 tsl=0 tscl=0 ghl=0 hwl=0 hwll=0)
"main" prio=5 tid=1 NATIVE
| group="main" sCount=1 dsCount=0 obj=0x40022170 self=0xce68
| sysTid=2411 nice=0 sched=0/0 cgrp=default handle=-1345006464
at android.hardware.Camera.native_takePicture(Native Method)
at android.hardware.Camera.takePicture(Camera.java:746)
at android.hardware.Camera.takePicture(Camera.java:710)
at oms.cj.tube.camera.CamLayer.takePicture(CamLayer.java:256)
at oms.cj.tube.camera.DefineColor.takePicture(DefineColor.java:61)
at oms.cj.tube.camera.DefineColor.onKeyUp(DefineColor.java:71)
at android.view.KeyEvent.dispatch(KeyEvent.java:1280)
at android.app.Activity.dispatchKeyEvent(Activity.java:2078)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:16
66)
at android.view.ViewRoot.deliverKeyEventToViewHierarchy(ViewRoot.java:2571)
at android.view.ViewRoot.handleFinishedEvent(ViewRoot.java:2546)
at android.view.ViewRoot.handleMessage(ViewRoot.java:1878)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:123)
at android.app.ActivityThread.main(ActivityThread.java:3691)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:841)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:599)
at dalvik.system.NativeStart.main(Native Method)
Is there anybody having the same problem? And know how to fix it?
I also observed mCamera.takePicture(null, null, handler) to freeze. I tried to clear the preview handler: mCamera.setPreviewCallback(null) before calling takePicture(), and it works now.
I had the exact same problem today when testing our app on a Samsung Exhibit 4G with Android 2.3.3 and solved it using a workaround.
I don't call takepicture anymore but use the last preview callback as the picture.
The problem is that the preview callback sends the data buffer using the NV21 format.
So you have to convert the image using this process: NV21 -> RGB -> Load the Bitmap -> Compress to JPEG
Our code right now looks like this:
camera.setPreviewCallback(new PreviewCallback() {
@Override
public synchronized void onPreviewFrame(byte[] data, Camera arg1) {
if (!mTakePicture) {
CameraPreview.this.invalidate();
} else {
if (mTakePictureCallback != null && !mPictureTaken) {
int rgb[] = new int[previewSize.width*previewSize.height];
decodeYUV420SP(rgb, data, previewSize.width, previewSize.height);
Bitmap memoryImage = Bitmap.createBitmap(rgb, previewSize.width, previewSize.height, Bitmap.Config.ARGB_8888);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
memoryImage.compress(CompressFormat.JPEG, 100, baos);
shutterSound();
setBackgroundDrawable(new BitmapDrawable(getContext().getResources(), memoryImage));
mTakePictureCallback.onPictureTaken(baos.toByteArray(), arg1);
}
mPictureTaken = true;
camera.stopPreview();
}
}
});
The code of decodeYUV420SP is here http://www.41post.com/3470/programming/android-retrieving-the-camera-preview-as-a-pixel-array who found it on Ketai http://code.google.com/p/ketai/
When you take a picture just set the mTakePicture variable on true
I'm working on a better version but this should get you going.
I'm not sure what the setOptimalSize method used in your code, but make sure you have set camera parameter
mCamera.setPictureSize(captureSize.width, captureSize.height);
mCamera.setPictureFormat(ImageFormat.JPEG);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With