关于相机:Android 2.3.3 上拍照挂起

takepicture hangs on Android 2.3.3

我有一些适用于 Android 2.1 和 2.2 的拍照代码。
但是这些代码在 Android 2.3 中被破坏了。
在花了时间解决这个徒劳的问题后,我想在这里寻求帮助。

我的拍照代码流程是这样的:

创建一个Camlayer类扩展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() 将被外部类调用来启动。

问题是在Android 2.3.3,takePicture会挂掉,所以发现了ANR问题。在 /data/anr/traces.txt 中,可以找到以下内容。如您所见, native_takePicture 永远不会返回。

达尔维克线:

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

有人遇到同样的问题吗?并且知道如何解决它?

相关讨论

  • 如果您包含作为错误来源的代码段,将会有所帮助。您不包含您的自定义 PictureCallback 类,甚至不创建它的实例。 mPictureCallback 在哪里定义,它的类的来源在哪里?最重要的是,您的 CamLayer 类的其余部分在哪里,现在编写的代码甚至无法编译,更不用说您遇到的错误了。我非常乐意提供帮助,但如果没有所有细节,这几乎是不可能的。
  • 在 HTC Sensation 上,我的自定义相机应用程序在全屏空间显示预览。当用户点击屏幕时,会调用焦点。当焦点完成并成功时,我调用 mCamera.takePicture 。有时它可以工作,我得到保存 JPG 数据的回调,其他时候它只是停留在 takePicture 中,没有超时也没有任何调试消息。这太烦人了,每次都要重启手机,不知道是什么问题。 SettingsPreviewCallback 到 null 没有帮助。还有其他想法吗?

我还观察到 mCamera.takePicture(null, null, handler) 冻结。我试图在调用 takePicture() 之前清除预览处理程序:mCamera.setPreviewCallback(null),现在它可以工作了。


我今天在装有 Android 2.3.3 的三星 Exhibit 4G 上测试我们的应用程序时遇到了完全相同的问题,并使用解决方法解决了它。

我不再调用 takepicture 而是使用最后一个预览回调作为图片。

问题是预览回调使用 NV21 格式发送数据缓冲区。

所以你必须使用这个过程来转换图像:NV21 -> RGB -> 加载位图 -> 压缩为 JPEG

我们现在的代码如下所示:

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

decodeYUV420SP 的代码在这里 http://www.41post.com/3470/programming/android-retrieving-the-camera-preview-as-a-pixel-array 谁在科泰找到的 http://code .google.com/p/ketai/

当你拍照时,只需将 mTakePicture 变量设置为 true

我正在开发一个更好的版本,但这应该能让你继续前进。

相关讨论

  • 您可以使用 YuvImage 类,但它仅适用于 API >= 8、developer.android.com/reference/android/graphics/YuvImage.ht??ml
  • 这太可笑了,Camera.takePicture 工作得很好,当它返回时你会得到一个全分辨率的 JPEG。你到底为什么要花如此多的精力来生成你自己的超低分辨率版本?
  • 此修复仅与 takePicture 挂起的某些相机有关。这是我们在 10 个不同的设备/操作系统版本上使用 android 测试我们的应用程序时遇到的问题。但是,正如您所说,生成的图像分辨率较低,无论如何这总比没有图片或应用挂起要好
  • 是的,所以你在 10 种不同的设备上测试了你的应用程序,但它们都不能正常工作,所以很明显它们都是有缺陷的,不可能是代码编写不当。
  • 不,其中一个操作系统/设备版本(阅读第一段:Samsung Exhibit 4G with Android 2.3.3)有问题。顺便说一句,我们当时有 3 种不同的情况 1)一些工作完美地调用了系统摄像头 2)一些工作实现了我们自己的摄像头 3)这个操作系统/设备。我们本可以忽略它,我们最终做到了。然而,这是我们发现适用于该特定案例的唯一解决方案,这就是我在这里发布它的原因。
  • 不是最好的方法,因为我们有时需要全分辨率的 jpeg,而与预览数据无关。
  • 这种方法适用于相机上的超级连拍模式(例如每秒 10 次快照,甚至每秒更多图像)

我不确定您的代码中使用了什么 setOptimalSize 方法,但请确保您已设置相机参数

mCamera.setPictureSize(captureSize.width, captureSize.height);
mCamera.setPictureFormat(ImageFormat.JPEG);

我在使用 GB 手机时遇到了这个问题,对我来说,这是因为我在调用 camera.takePicture() 之后立即调用了 camera.startPreview(),这导致了 Android 中的一些线程锁定。修复方法是将 camera.startPreview() 移动到传递给 camera.takePicture() 的回调中,这样它只会在图片数据进入后才被调用(下面的示例代码)。当然,这仅在您有兴趣在拍摄照片后重新开始预览时才相关。

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

这不仅使 ANR 在调用 takePicture 时消失,而且还修复了一些高端手机(尤其是 >=4.3 Nexus 5)上发生的 startPreview 原生崩溃。希望对您有所帮助!


问题在于下面的代码是写的。

  • 定义了一个 PreviewCallback,

    PreviewCallback mPreviewCallback = new PreviewCallback() {

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

  • mCamera.setPreviewCallback(mPreviewCallback);

  • mCamera.takePicture()
  • 这在 2.1/2.2 中有效,但在 2.3 中无效。

    不确定 Android 团队是否支持这种使用相机的方式。
    如果上述流程是预期的,那么 Android 团队应该解决这个问题。

    相关讨论

    • 因此,如果您取出此代码,您的相机活动是否有效并且您是否可以拍照?

    以上是关于相机:Android 2.3.3 上拍照挂起的全部内容。
    THE END
    分享
    二维码
    < <上一篇
    下一篇>>