开发者

takepicture hangs on Android 2.3.3

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:18开发者_运维百科78)

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


The problem lie in the fact that below codes are writen.

  1. There is a PreviewCallback defined,

    PreviewCallback mPreviewCallback = new PreviewCallback() {
    
        @Override
            public void onPreviewFrame(byte[] data, Camera camera) {
                //Log.i(TAG+".mPreviewCallback.onPreviewFrame", "being called!");
            }
    };
    
  2. mCamera.setPreviewCallback(mPreviewCallback);

  3. mCamera.takePicture()

That works in 2.1/2.2, but not in 2.3.

Not sure if Android team supported this way of using camera. If the above flow is expected, then Android team should fix this problem.


I ran into this issue with GB phones, and for me, it turned out to be because I was calling camera.startPreview() right after calling camera.takePicture(), and this was causing some thread locking in Android. The fix was to move camera.startPreview() into the callback passed into camera.takePicture(), such that it only got called once the picture data was in (example code below). This is of course only relevant if you're interested in restarting the preview after the picture is taken.

// BAD BAD DON'T DO THIS!
public void myTakePicture(Camera.PictureCallback callback) {
  mCamera.takePicture(null, null, null, callback);
  mCamera.startPreview();
}

// ...
// The way that worked for me
public void myTakePicture(final Camera.PictureCallback callback) {
  mCamera.takePicture(null, null, null, new Camera.PictureCallback() {
    @Override
    public void onPictureTaken(byte[] pictureData, Camera camera) {
      callback.onPictureTaken(pictureData, camera);
      mCamera.takePicture();
    }
  });
}

This not only made the ANR go away when calling takePicture, but also fixed a native crash on startPreview that was happening on some higher end phones (particularly a >=4.3 Nexus 5). Hope it helps!

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜