Camera#setPreviewCallbackWithBuffer(Camera.PreviewCallback)ですが、
使い方がわかりにくかったのでメモしておきます。
まず準備として以下の記述を消します。
自分で Canvas に描画するので必要がないのですね。
mCamera.setPreviewDisplay(holder);
そして全体は以下のような感じで実装します。
private Camera mCamera; private int mPictureOrientation; // デバイスの向きから計算した写真の向き private Camera.Size mPreviewSize; // Preview サイズ private Camera.Size mScaledPreviewSize; // Preview サイズを縦横比を維持しつつ画面サイズに拡大したサイズ private byte[] mCallbackBuffer; private void startPreview(){ int size = mPreviewSize.width * mPreviewSize.height * ImageFormat.getBitsPerPixel(mCamera.getParameters().getPreviewFormat()) / 8; mCallbackBuffer = new byte[size]; mCamera.addCallbackBuffer(mCallbackBuffer); mCamera.setPreviewCallbackWithBuffer(this); } private void stopPreview(){ mCamera.setPreviewCallbackWithBuffer(null); } @Override public void onPreviewFrame(byte[] data, Camera camera){ // 画像変換処理 Bitmap bitmap = BitmapUtils.createBitmapFromYuv(mContext, data, mPreviewSize.width, mPreviewSize.height); bitmap = BitmapUtils.rotate(bitmap, mPictureOrientation); bitmap = BitmapUtils.resize(bitmap, mScaledPreviewSize.width, mScaledPreviewSize.height); // 描画処理 Canvas canvas = mHolder.lockCanvas(); if(canvas != null){ canvas.drawBitmap(bitmap, 0, 0, null); mHolder.unlockCanvasAndPost(canvas); } // 次のフレームのコールバックの設定 mCamera.addCallbackBuffer(mCallbackBuffer); }BitmapUtils.createBitmapFromYuv などは wada811/AndroidLibrary@wada811からです。
本当は Bitmap を毎フレーム生成するのは嫌なんですが
YUV データを Bitmap#setPixels を通して Bitmap に変換する方法がよくわからず…。
JavaFilter#decodeYUV420SP · youten/YUV420SP を使えばいけるかもしれない。
youten さんが書かれている通り、速度は出ないので RenderScript を使いたいところ。
やってみた
private Camera mCamera; private int mPictureOrientation; // デバイスの向きから計算した写真の向き private Camera.Size mPreviewSize; // Preview サイズ private Camera.Size mScaledPreviewSize; // Preview サイズを縦横比を維持しつつ画面サイズに拡大したサイズ private byte[] mCallbackBuffer; private int[] mRgbDatas; private Bitmap mPreviewBitmap; private void startPreview(){ mRgbDatas = new int[mPreviewSize.width * mPreviewSize.height]; mPreviewBitmap = BitmapUtils.createNewBitmap(mPreviewSize.width, mPreviewSize.height); int size = mPreviewSize.width * mPreviewSize.height * ImageFormat.getBitsPerPixel(mCamera.getParameters().getPreviewFormat()) / 8; mCallbackBuffer = new byte[size]; mCamera.addCallbackBuffer(mCallbackBuffer); mCamera.setPreviewCallbackWithBuffer(this); } private void stopPreview(){ mCamera.setPreviewCallbackWithBuffer(null); } @Override public void onPreviewFrame(byte[] data, Camera camera){ // 画像変換処理 BitmapUtils.decodeYUV420SP(mRgbDatas, data, mPreviewSize.width, mPreviewSize.height); mPreviewBitmap.setPixels(mRgbDatas, 0, mPreviewSize.width, 0, 0, mPreviewSize.width, mPreviewSize.height); Bitmap bitmap = BitmapUtils.rotate(mPreviewBitmap, mPictureOrientation); bitmap = BitmapUtils.resize(bitmap, mScaledPreviewSize.width, mScaledPreviewSize.height); // 描画処理 Canvas canvas = mHolder.lockCanvas(); if(canvas != null){ canvas.drawBitmap(bitmap, 0, 0, null); mHolder.unlockCanvasAndPost(canvas); } // 次のフレームのコールバックの設定 mCamera.addCallbackBuffer(mCallbackBuffer); }BitmapUtils#decodeYUV420SP も遅かったですが、
BitmapUtils#rotate と BitmapUtils#resize で Bitmap の生成をやってしまっているので更に遅かったです。