Androidのカメラプレビューをそのまま使って動画処理とか。
をやろうとしたら本当に大変だったorz
Androidのカメラプレビューを取ろうと思ったら、なんか、
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height){ dw = width; dh = height; Camera.Parameters parameters = mCamera.getParameters(); parameters.setPreviewSize(width, height); mCamera.setParameters(parameters); mCamera.startPreview(); mCamera.setPreviewCallback(new Camera.PreviewCallback() { public void onPreviewFrame(byte[] data, Camera camera) { // Write in process } }); }
な事をしなきゃいけないらしく、とりあえずそれを差し込んでみて、適当にいつも通りピクセル弄りの画像処理をしようとしたら、メモリエラーで落ちまくり…。
何でだろう?と思うと、どうやらonPreviewFrameでプロセスしている間、Threadが立っていて他のViewを破棄している訳ではなく、たんまりとバッファに入れまくってるためすぐ落ちるそうで…。そんなん手前でやっとけよと突っ込みを入れたくなりつつ、仕方ないのでThreadを立てて外部のクラスにプロセスを飛ばすことに
try { if (!camproc.isProcess()) { // 処理時間を設定 debugtext = " " + ((System.nanoTime() - t) / 1000000000D) + " sec"; t = System.nanoTime(); // スレッド実行 camproc.initProcess(data, dw, dh); Thread thread = new Thread(camproc); thread.start(); } } catch (Exception e) { e.printStackTrace(); }
中に入れたのはこんな感じ。(参考: ももいろあたまさいと Thx!)
で、Thread用のクラスを作って、やっとこさバイナリ弄りを…としたところ、
class CamCoding implements Runnable{ private boolean flag; byte[] buf; int[] bmpbuf; int w, h; int tw, th; public CamCoding(){ flag = false; w = 0; h = 0; bmpbuf = null; buf = null; } public boolean isProcess(){ return flag; } public void initProcess(byte[] code,int width, int height){ w = (int)width/4; h = (int)height/4; tw = width; th = height; bmpbuf = new int[h*w]; buf = code; } public void run() { flag = true; for (int j =0; j < h; j++){ for(int i = 0; i < w; i++){ int ii = i*4; int jj = j*4; int pixel = 0xFF000000; int val = 0; if(i!=0 && j!=0 && i != w-1 && j != h-1){ for(int k = 0; k < 3; k++){ for(int l = 0; l<3; l++){ val = (int)buf[(jj-l-1)*(tw+10) + (ii-k-1)]*lap[l*3 + k]; } } val = Math.abs(val) / 4; if(val > 0xFF) val = 0xFFFFFF; else val = (val << 16) + (val << 8) + val; } bmpbuf[j*w + i] = pixel + val; } } bmp = Bitmap.createBitmap(bmpbuf, w, h, Bitmap.Config.ARGB_8888); bmpable = true; flag = false; } }
なげぇよ。
まぁ、やりたいのは、3x3のフィルタを掛けたいだけなんですけど。
掛けるための時間を節約するために、キャプチャで取ったサイズを縦横1/4(面積的に1/16)まで落としてやったにも関わらず、これで1フレーム辺り0.5秒。長い…。
そして、これで2時間くらい格闘した。
val = (int)buf[(jj-l-1)*(tw+10) + (ii-k-1)]*lap[l*3 + k];
twって言うのは画像の横幅。buf[]がonPreviewFrameの時に取ってきたバイト列。こいつがYUV420なのは別に良いんだけど、普通、buf[j * tw + i] 見たいな感じで流せるはずなのに…なんで(tw+10)なんて10pxのOffsetがついてるんだ?IS01…。
とりあえず何とか画像処理は遅いけれども出来るようで…RGB変換とかはしないデス。メンドイ。別にYUVそのままで画像処理してもかまわんだろう?(何