2013年7月12日金曜日

Android 4.xにしたらonPreviewFrameが呼ばれなくなったので対策した

画像認識やAR用途などでカメラからの映像をキャプチャしたい場合、onPreviewFrameで行うことがあると思う。
しかしAndroid 2.x (Gingerbread)では呼ばれていたonPreviewFrameが、Android 4.x (Ice Cream Sandwich)で動かしたら呼ばれなくなっていた。 その対策方法を見つけたのでメモしておく。

問題の起こるコード
class CameraPreviewSurface implements SurfaceHolder.Callback, Camera.PreviewCallback {

    // 中略
    
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        mCamera = Camera.open();
        if (mCamera != null) {
            try {
                mCamera.setPreviewDisplay(holder);
                mCamera.setPreviewCallback(this);
            } catch (IOException e) {
                if(camera != null) {
                    mCamera.release();
                    mCamera = null;
                }
            }
        }
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        mCamera.stopPreview();

        // 中略

        mCamera.setParameters(params);
        mCamera.startPreview();

    }

    @Override
    public void onPreviewFrame(byte[] data, Camera camera) {

        // 中略

    }
}

そして、以下が対策済みのコード
class CameraPreviewSurface implements SurfaceHolder.Callback, Camera.PreviewCallback {

    // 中略
    
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        mCamera = Camera.open();
        if (mCamera != null) {
            try {
                mCamera.setPreviewDisplay(holder);
                // 不要 mCamera.setPreviewCallback(this);
            } catch (IOException e) {
                if(camera != null) {
                    mCamera.release();
                    mCamera = null;
                }
            }
        }
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        mCamera.stopPreview();

        // 中略

        mCamera.setParameters(params);
        mCamera.setPreviewCallback(this); // stopPreviewを呼んだら、startPreviewを呼ぶ前にsetPreviewCallback
        mCamera.startPreview();

    }

   @Override
   public void onPreviewFrame(byte[] data, Camera camera) {

        // 中略

     }
}

stopPreviewを呼ぶとそれ以前のsetPreviewCallbackは無効になるらしい。

参考にしたページ
Android Camera - A Problem I Spent Almost Twenty Hours On
Thanks!