私は新しいAndroid camera2 APIでテストしており、カメラから各フレームを制御したいと思っています。これを行うには、ImageReaderを作成します解像度と画像フォーマットを設定します。
ImageReader imageReader = ImageReader.newInstance(1280,720,ImageFormat.YUV_420_888,1);
imageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader reader) {
Image image = reader.acquireLatestImage();
Log.i(MainActivity.LOG_TAG,"imageReader: "+System.currentTimeMillis());
image.close();
}
},null);
その後、パラメーターTEMPLATE_PREVIEWで新しいCaptureRequestを作成し、ターゲットをimageReader
に追加します。 cameraCaptureSessionの場合、このリクエストで新しいsetRepeatingRequestを作成します
try {
final CaptureRequest.Builder builder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
builder.addTarget(imageReader.getSurface());
mCameraDevice.createCaptureSession(
Arrays.asList(imageReader.getSurface()),
new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(CameraCaptureSession session) {
mSession = session;
try {
mSession.setRepeatingRequest(builder.build(),null,null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
@Override
public void onConfigureFailed(CameraCaptureSession session) {
}
},
null
);
} catch (CameraAccessException e) {
e.printStackTrace();
}
カメラを開いてプレビューを表示すると、例外が発生します。例外が発生する前にプレビュー画像が表示され、その後例外が発生しました
10-30 16:00:32.850 1390-1894/.camera2tutorial E/BufferQueueProducer﹕ [unnamed-1390-1] dequeueBuffer: BufferQueue has been abandoned
10-30 16:00:32.850 1390-1894/.camera2tutorial E/Legacy-CameraDevice-JNI﹕ LegacyCameraDevice_nativeProduceFrame: Error while producing frame No such device (-19).
10-30 16:00:32.850 1390-1894/.camera2tutorial W/SurfaceTextureRenderer﹕ Surface abandoned, dropping frame.
Android.hardware.camera2.legacy.LegacyExceptionUtils$BufferQueueAbandonedException
at Android.hardware.camera2.legacy.LegacyExceptionUtils.throwOnError(LegacyExceptionUtils.Java:64)
at Android.hardware.camera2.legacy.LegacyCameraDevice.produceFrame(LegacyCameraDevice.Java:516)
at Android.hardware.camera2.legacy.SurfaceTextureRenderer.drawIntoSurfaces(SurfaceTextureRenderer.Java:699)
at Android.hardware.camera2.legacy.GLThreadManager$1.handleMessage(GLThreadManager.Java:103)
at Android.os.Handler.dispatchMessage(Handler.Java:98)
at Android.os.Looper.loop(Looper.Java:145)
at Android.os.HandlerThread.run(HandlerThread.Java:61)
どうすれば修正できますか?
Samsung Galaxy S5とAndroid API 21を使用しています。
作成したImageReaderへの参照を保持していることを確認してください。おそらく、mSessionが定義されている場所であればどこでもかまいません。
ImageReaderから取得するSurfaceは、弱いポインターとほぼ同じです。ImageReaderがガベージコレクションを取得するのを妨げることはありません。そのため、ほとんどの場合(名前付けに基づいて)ImageReaderが破棄され、放棄エラーが発生します。
アプリでアクティビティを切り替えるときに同じ問題が発生しました。それはonSurfaceTextureDestroyed()
を呼び出した後、falseしか返されませんでしたが、私が行ったのはそれを
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
Log.e(TAG, "onSurfaceTextureDestroyed");
if(cameraDevice != null){
closeCamera();
cameraDevice = null;
}
return false;
}
それでうまくいきました。
私は解決策を見つけました、これは私のために働きました、感染エラーは正しいサイズを選択することですので、MediaRecorder.setVideoSize()を使用しながらこのメソッドを使用して最適なサイズを選択してください
private static Size chooseOptimalSize(Size[] choices, int width, int height) {
Size bigEnough = null;
int minAreaDiff = Integer.MAX_VALUE;
for (Size option : choices) {
int diff = (width*height)-(option.getWidth()*option.getHeight()) ;
if (diff >=0 && diff < minAreaDiff &&
option.getWidth() <= width &&
option.getHeight() <= height) {
minAreaDiff = diff;
bigEnough = option;
}
}
if (bigEnough != null) {
return bigEnough;
} else {
Arrays.sort(choices,new CompareSizeByArea());
return choices[0];
}
}