単純にカメラのプレビュー画像をアプリケーション上で表示したいなら、SurfaceViewを生成してCamera#setPreviewDisplay()でSurfaceHolderを渡してあげれば良いんだけど、それだとプレビュー画像をいじれない。
プレビュー画像を横取りするには、Camera.PreviewCallbackを利用します。
紆余曲折いろいろなサイトを参考にこんなん作ってみました。
layout/main.xml
<?xml version="1.0" encoding="utf-8"?> <framelayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" > <com.example.CameraView android:layout_width="fill_parent" android:layout_height="fill_parent" android:id="@+id/SurfaceView01" /> </FrameLayout>
CameraTest.java
package com.example; import android.app.Activity; import android.os.Bundle; import android.view.Window; public class CameraTest extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.main); } }
CameraView.java
package com.example; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.hardware.Camera; import android.view.SurfaceView; import android.view.SurfaceHolder; import android.util.AttributeSet; public class CameraView extends SurfaceView implements SurfaceHolder.Callback { private SurfaceHolder holder; private Camera camera; private Bitmap bitmap; private int[] rgb; private int width, height; /** * プレビューコールバック * prepareSavePreviewImageコールバックで登録され、プレビュー画像を取得する */ private final Camera.PreviewCallback _previewCallback = new Camera.PreviewCallback() { public void onPreviewFrame(byte[] data, Camera camera) { decodeYUV420SP(rgb, data, width, height); bitmap.setPixels(rgb, 0, width, 0, 0, width, height); // 描画 Canvas canv = holder.lockCanvas(); canv.drawBitmap(bitmap, 0, 0, null); holder.unlockCanvasAndPost(canv); } }; // コンストラクタ public CameraView(Context context) { super(context); this.initialize(); } // コンストラクタ public CameraView(Context context, AttributeSet attrs) { super(context, attrs); this.initialize(); } // 初期化処理 private void initialize() { // サーフェイスホルダーの生成 holder=getHolder(); holder.addCallback(this); // サーフェイスホルダーのタイプを設定 holder.setType(SurfaceHolder.SURFACE_TYPE_NORMAL); // 画像を読み込んでおく } // サーフェイス生成イベントの処理 public void surfaceCreated(SurfaceHolder holder) { // カメラの初期化 try { camera=Camera.open(); camera.setPreviewCallback(_previewCallback); } catch (Exception e) { } } // サーフェイス変更イベントの処理 public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { // 描画データの準備 width = w; height = h; bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); rgb = new int[w * h]; // カメラのプレビュー開始 Camera.Parameters parameters = camera.getParameters(); parameters.setPreviewSize(w, h); camera.setParameters(parameters); camera.startPreview(); } //サーフェイス解放イベントの処理 public void surfaceDestroyed(SurfaceHolder holder) { // カメラのプレビュー停止 camera.stopPreview(); camera.setPreviewCallback(null); camera.release(); camera = null; } // YUV420 to BMP static public void decodeYUV420SP(int[] rgb, byte[] yuv420sp, int width, int height) { final int frameSize = width * height; for (int j = 0, yp = 0; j < height; j++) { int uvp = frameSize + (j >> 1) * width, u = 0, v = 0; for (int i = 0; i < width; i++, yp++) { int y = (0xff & ((int) yuv420sp[yp])) - 16; if (y < 0) y = 0; if ((i & 1) == 0) { v = (0xff & yuv420sp[uvp++]) - 128; u = (0xff & yuv420sp[uvp++]) - 128; } int y1192 = 1192 * y; int r = (y1192 + 1634 * v); int g = (y1192 - 833 * v - 400 * u); int b = (y1192 + 2066 * u); if (r < 0) r = 0; else if (r > 262143) r = 262143; if (g < 0) g = 0; else if (g > 262143) g = 262143; if (b < 0) b = 0; else if (b > 262143) b = 262143; rgb[yp] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) & 0xff00) | ((b >> 10) & 0xff); } } } }
少し動かすとOutOfMemoryになってちゃんと動かない。Camera.Parameters#setPreviewFrameRate(1)とかやってやると落ちずに動く。
実機でやるとまた違う結果が出るかしら。
0 件のコメント:
コメントを投稿