Camera#addCallbackBuffer(byte[])と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 の生成をやってしまっているので更に遅かったです。