ビデオ入力を処理している TextureView から取得したビットマップ画像を使用して、いくつかの画像処理テストを行っています。私のテストでは、 TextureView.getBitmap(Bitmap) の実行にかかる時間が実行ごとに異なる場合があることに気付きました。
問題を実証するために、 TextureView APIリファレンスからサンプルを変更しました。以下のコードでは、カメラを TextureView への入力として使用し、ビットマップを取得して SurfaceView にレンダリングし、所要時間を測定しています。Android 4.2.2 を実行している Nexus 7 デバイスのペアでテストしました。私は実際に、遅いパターンと速いパターンの 2 つのパターンに気付きました。
実行が「遅い」場合、getBitmap(Bitmap) は約 20ms かかります。実行が「高速」の場合、getBitmap(Bitmap) は約 15ms かかります。
ほとんどの場合、このアプリは「低速」モードで実行されます。デバイスをいじったり、アプリを再コンパイル/再インストールしたりすると、「高速」モードで動作することがあります。しかし、その後はゆっくりと再び走り出します。速度は、プログラムの再起動後にのみ変更され、実行中に変更されることはありません。
ところで、Bitmap を SurfaceView にダンプするのに約 8 ミリ秒しかかかりません。ビットマップを TextureView から取得するのに、なぜその 2 倍以上の時間がかかるのでしょうか。
質問:
- この実行時間の不一致はなぜ起こるのでしょうか?
- getBitmap(Bitmap) が常に可能な限り高速に実行されるようにする方法はありますか?
- SurfaceView への書き込みが TextureView からの読み取りよりも 2 倍高速であることは合理的ですか?
ありがとうございました。
――ラファエル
追伸: Android Developers Google Group に既に投稿しましたが、先週からほどほどにとどまっているようです。クロスポストすみません。
編集:
より簡単に試してみたい方のために、サンプル プロジェクトを GitHub に追加しました。
アクティビティ:
import java.io.IOException;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.SurfaceTexture;
import android.hardware.Camera;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.TextureView;
public class LiveCameraActivity extends Activity implements TextureView.SurfaceTextureListener {
private Camera mCamera;
private TextureView mTextureView;
private SurfaceView mSurfaceView;
private final int imgW = 640;
private final int imgH = 480;
private Bitmap bmp = Bitmap.createBitmap(imgW, imgH, Bitmap.Config.ARGB_8888);
private Canvas canvas = new Canvas(bmp);
private Paint paint1 = new Paint();
private SurfaceHolder mSurfaceHolder;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main2);
mSurfaceView = (SurfaceView) findViewById(R.id.surfaceview);
mSurfaceHolder = mSurfaceView.getHolder();
mTextureView = (TextureView) findViewById(R.id.textureview);
mTextureView.setSurfaceTextureListener(this);
final int textSize = 24;
paint1.setColor(0xff00ffff);
paint1.setTextSize(textSize);
}
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
mCamera = Camera.open(Camera.getNumberOfCameras()-1);
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(imgW, imgH);
mCamera.setParameters(parameters);
try {
mCamera.setPreviewTexture(surface);
mCamera.startPreview();
} catch (IOException ioe) {
// Something bad happened
}
}
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
// Ignored, Camera does all the work for us
}
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
mCamera.stopPreview();
mCamera.release();
return true;
}
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
// Invoked every time there's a new Camera preview frame
long time0 = System.currentTimeMillis();
mTextureView.getBitmap(bmp);
long time1 = System.currentTimeMillis() - time0;
final Canvas c = mSurfaceHolder.lockCanvas();
if ( c != null) {
canvas.drawText("getBmp= " + time1, 10, 40, paint1);
c.drawBitmap(bmp, 0, 0, null);
mSurfaceHolder.unlockCanvasAndPost(c);
}
long total = System.currentTimeMillis() - time0;
long time2 = total -time1;
Log.i("onFrame", "timing: getBmp= " + time1 + " blit= " + time2 + " total= " + total);
}
}
レイアウト:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin" >
<SurfaceView
android:id="@+id/surfaceview"
android:layout_width="640px"
android:layout_height="480px" />
<TextureView
android:id="@+id/textureview"
android:layout_width="640px"
android:layout_height="480px" />
</LinearLayout>