具有多个输出的 Camera2
Camera2 With Multiple Outputs
这是我的问题,在调用捕获后,我目前无法使用来自 Camera2API 的静态捕获图像填充 3 个表面之一。我使用 Google Camera2 入门(需要 link)来设置样板,因此这段代码的大部分内容可能看起来很熟悉。
Camera2 capture 声明:
Each request will produce one CaptureResult and produce new frames for one or more target Surfaces, set with the CaptureRequest builder's addTarget(Surface) method. The target surfaces (set with addTarget(Surface)) must be a subset of the surfaces provided when this capture session was created.
好的Android,我会遵守的
// in order to use a surface they must be registered when creating the session
List<Surface> surfaces = new ArrayList<>(previewSurfaces); //size + 1
surfaces.addAll(displaySurfaces); // size + 1
surfaces.add(mImageReader.getSurface()); //size + 1
try {
mCameraDevice.createCaptureSession(surfaces, mCaptureSessionCallback , null);
...
然后这样做
// Add the display surfaces along with the internal image reader
captureBuilder.addTarget(mImageReader.getSurface());
for(Surface surface : this.displaySurfaces) {
captureBuilder.addTarget(surface); //theres only one
}
CaptureRequest captureRequest = captureBuilder.build();
mCaptureSession.capture(captureRequest, captureCallback, mBackgroundHandler);
此时,添加到传递给捕获方法的请求的表面 将 将相机缓冲区输出到所有表面。但是,我只看到 mImageReader 的回调被调用,而 displaySurfaces 没有得到爱。
所以我开始研究调试器并注意到传递给捕获的请求有一组大小为 2 的输出,并且相机会话的内部输出集的大小为 3(均正确) .然而,显示表面什么也没有显示。另一个表面显示预览并且工作正常。
我检查过的东西:
a) 是的,视图是可见的,它的表面已经准备好了
b) 视图具有相机支持的分辨率,并已使用 setFixedSize()
设置
这里发生了什么我觉得我错过了什么。求助!
编辑1
表面的生成方式如下;
private SurfaceView getPreviewView(Context context) throws CameraAccessException {
// TODO set z overlay?
Size previewSize = mCameraController.determineLargestSize();
Log.d(LOG_TAG, "Setting preview dimensions to: \n" +
"width: " + Integer.toString(previewSize.getWidth()) + "\n" +
"height " + Integer.toString(previewSize.getHeight()));
SurfaceView view = new SurfaceView(context);
view.getHolder().addCallback(mPreviewViewCallback);
view.getHolder().setFixedSize(previewSize.getWidth(),previewSize.getHeight());
view.setOnTouchListener(mZoomFocusListener);
return view;
}
private SurfaceView getDisplayTile(Context context) throws CameraAccessException {
SurfaceView previewTile = new SurfaceView(context);
Size smallest = mCameraController.determineSmallestSize();
int width = smallest.getWidth();
int height = smallest.getHeight();
Log.d(LOG_TAG, "Setting display tile dimensions to: \n" +
"width: " + Integer.toString(smallest.getWidth()) + "\n" +
"height " + Integer.toString(smallest.getHeight()));
previewTile.getHolder().addCallback(mDisplayCallback);
previewTile.getHolder().setFixedSize(width,height);
previewTile.setZOrderMediaOverlay(true);
previewTile.getHolder().setFormat(PixelFormat.TRANSLUCENT);
previewTile.setBackgroundColor(Color.BLUE);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(width,height);
params.addRule(RelativeLayout.ALIGN_PARENT_TOP);
params.addRule(RelativeLayout.ALIGN_PARENT_END);
params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
params.setMargins(7,7,7,7);
previewTile.setLayoutParams(params);
return previewTile;
}
这就是我将所有内容整合在一起的方法
private void initViews(Context context) throws CameraAccessException {
mFrameLayout = new FrameLayout(context);
// Add the view for the camera preview
FrameLayout.LayoutParams surfaceParams = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT);
mPreviewView = this.getPreviewView(context);
mFrameLayout.addView(mPreviewView,surfaceParams);
// Add the preview tile to the layout
FrameLayout.LayoutParams displayParams = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.WRAP_CONTENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
displayParams.gravity = Gravity.BOTTOM | Gravity.RIGHT;
RelativeLayout layout = new RelativeLayout(context);
mCapturedTile = this.getDisplayTile(context);
layout.addView(mCapturedTile);
mFrameLayout.addView(layout, displayParams);
}
这是应用程序未预览时的屏幕截图 运行。我将右下角的框涂成蓝色,这是不显示相机输出的显示表面。
我还附上了 Logcat,让您了解正在发生的事情
12-19 16:00:33.185 29863-29863/ngc.com.camera2app I/CameraController: This device has 2 available cameras
12-19 16:00:33.202 29863-29863/ngc.com.camera2app D/CameraController: Retrieveing current crop region
12-19 16:00:33.206 29863-29863/ngc.com.camera2app D/CameraView: Setting preview dimensions to:
width: 3264
height 2448
12-19 16:00:33.208 29863-29863/ngc.com.camera2app D/CameraView: Setting display tile dimensions to:
width: 176
height 144
12-19 16:00:33.948 29863-29863/ngc.com.camera2app D/CameraView: Surface created
12-19 16:00:33.949 29863-29863/ngc.com.camera2app D/CameraView: preview surface changed dimensions are
12-19 16:00:33.950 29863-29863/ngc.com.camera2app D/CameraView: width : 3264 | height : 2448
12-19 16:00:33.964 29863-29863/ngc.com.camera2app D/CameraView: Surface created
12-19 16:00:33.964 29863-29863/ngc.com.camera2app D/CameraView: display surface changed dimensions are
12-19 16:00:33.964 29863-29863/ngc.com.camera2app D/CameraView: width : 176 | height : 144
12-19 16:00:33.973 29863-29863/ngc.com.camera2app I/CameraController: Attempting to open camera
12-19 16:00:34.048 29863-29929/ngc.com.camera2app I/CameraController: Camera 0 is open for business
12-19 16:00:34.055 29863-29863/ngc.com.camera2app W/PathParser: Points are too far apart 4.000000596046461
12-19 16:00:34.065 29863-29929/ngc.com.camera2app D/CameraView: Camera ready
12-19 16:00:48.343 29863-29929/ngc.com.camera2app I/CameraController: Image available
我仍然卡住了,想解决这个非常微妙的复杂错误,并简单地从 ImageReader 的回调中加载图像。但是API说可以,为什么不呢!!
编辑2
当来自表面的两个回调都经过 onChanged() 时调用此方法
private synchronized void openCamera(){
if(displayReady && previewReady){
try {
List<Surface> displaySurfaces = new ArrayList<>();
//uncommenting this line adds a nasty bug
displaySurfaces.add(mPreviewView.getHolder().getSurface());
List<Surface> previewSurfaces = new ArrayList<>();
previewSurfaces.add(mCapturedTile.getHolder().getSurface());
mCameraController.openCamera(displaySurfaces, previewSurfaces);
} catch (CameraAccessException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
编辑3
将两个显示器的分辨率更改为相同,结果相同。 SystemUI 变得非常扭曲(顶部的通知栏在整个屏幕上重复,底部的软按钮移动到屏幕中间,非常奇怪)。我试图拍下这种行为的照片,但这是我得到的
请注意,上面的屏幕截图不是 UI 显示给我的。此外,在应用程序关闭并重新启动后,预览屏幕的一半是绿色的(同样,无法通过屏幕截图捕捉到这一点)。有什么想法吗?我开始认为 Camera2 API 有一个错误,但是,我也开始认为需要在这些表面上设置一些配置。不确定为什么奇怪的 UI 行为...
谢谢@EddyTalvala,原来问题是由于分辨率不匹配造成的。
预览表面:3264 x 2446
显示表面:176 X 148
我在中间遇到了,把这两个的分辨率都改成了 640,480,问题就解决了。
这是我的问题,在调用捕获后,我目前无法使用来自 Camera2API 的静态捕获图像填充 3 个表面之一。我使用 Google Camera2 入门(需要 link)来设置样板,因此这段代码的大部分内容可能看起来很熟悉。
Camera2 capture 声明:
Each request will produce one CaptureResult and produce new frames for one or more target Surfaces, set with the CaptureRequest builder's addTarget(Surface) method. The target surfaces (set with addTarget(Surface)) must be a subset of the surfaces provided when this capture session was created.
好的Android,我会遵守的
// in order to use a surface they must be registered when creating the session
List<Surface> surfaces = new ArrayList<>(previewSurfaces); //size + 1
surfaces.addAll(displaySurfaces); // size + 1
surfaces.add(mImageReader.getSurface()); //size + 1
try {
mCameraDevice.createCaptureSession(surfaces, mCaptureSessionCallback , null);
...
然后这样做
// Add the display surfaces along with the internal image reader
captureBuilder.addTarget(mImageReader.getSurface());
for(Surface surface : this.displaySurfaces) {
captureBuilder.addTarget(surface); //theres only one
}
CaptureRequest captureRequest = captureBuilder.build();
mCaptureSession.capture(captureRequest, captureCallback, mBackgroundHandler);
此时,添加到传递给捕获方法的请求的表面 将 将相机缓冲区输出到所有表面。但是,我只看到 mImageReader 的回调被调用,而 displaySurfaces 没有得到爱。
所以我开始研究调试器并注意到传递给捕获的请求有一组大小为 2 的输出,并且相机会话的内部输出集的大小为 3(均正确) .然而,显示表面什么也没有显示。另一个表面显示预览并且工作正常。
我检查过的东西: a) 是的,视图是可见的,它的表面已经准备好了 b) 视图具有相机支持的分辨率,并已使用 setFixedSize()
设置这里发生了什么我觉得我错过了什么。求助!
编辑1
表面的生成方式如下;
private SurfaceView getPreviewView(Context context) throws CameraAccessException {
// TODO set z overlay?
Size previewSize = mCameraController.determineLargestSize();
Log.d(LOG_TAG, "Setting preview dimensions to: \n" +
"width: " + Integer.toString(previewSize.getWidth()) + "\n" +
"height " + Integer.toString(previewSize.getHeight()));
SurfaceView view = new SurfaceView(context);
view.getHolder().addCallback(mPreviewViewCallback);
view.getHolder().setFixedSize(previewSize.getWidth(),previewSize.getHeight());
view.setOnTouchListener(mZoomFocusListener);
return view;
}
private SurfaceView getDisplayTile(Context context) throws CameraAccessException {
SurfaceView previewTile = new SurfaceView(context);
Size smallest = mCameraController.determineSmallestSize();
int width = smallest.getWidth();
int height = smallest.getHeight();
Log.d(LOG_TAG, "Setting display tile dimensions to: \n" +
"width: " + Integer.toString(smallest.getWidth()) + "\n" +
"height " + Integer.toString(smallest.getHeight()));
previewTile.getHolder().addCallback(mDisplayCallback);
previewTile.getHolder().setFixedSize(width,height);
previewTile.setZOrderMediaOverlay(true);
previewTile.getHolder().setFormat(PixelFormat.TRANSLUCENT);
previewTile.setBackgroundColor(Color.BLUE);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(width,height);
params.addRule(RelativeLayout.ALIGN_PARENT_TOP);
params.addRule(RelativeLayout.ALIGN_PARENT_END);
params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
params.setMargins(7,7,7,7);
previewTile.setLayoutParams(params);
return previewTile;
}
这就是我将所有内容整合在一起的方法
private void initViews(Context context) throws CameraAccessException {
mFrameLayout = new FrameLayout(context);
// Add the view for the camera preview
FrameLayout.LayoutParams surfaceParams = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT);
mPreviewView = this.getPreviewView(context);
mFrameLayout.addView(mPreviewView,surfaceParams);
// Add the preview tile to the layout
FrameLayout.LayoutParams displayParams = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.WRAP_CONTENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
displayParams.gravity = Gravity.BOTTOM | Gravity.RIGHT;
RelativeLayout layout = new RelativeLayout(context);
mCapturedTile = this.getDisplayTile(context);
layout.addView(mCapturedTile);
mFrameLayout.addView(layout, displayParams);
}
这是应用程序未预览时的屏幕截图 运行。我将右下角的框涂成蓝色,这是不显示相机输出的显示表面。
我还附上了 Logcat,让您了解正在发生的事情
12-19 16:00:33.185 29863-29863/ngc.com.camera2app I/CameraController: This device has 2 available cameras
12-19 16:00:33.202 29863-29863/ngc.com.camera2app D/CameraController: Retrieveing current crop region
12-19 16:00:33.206 29863-29863/ngc.com.camera2app D/CameraView: Setting preview dimensions to:
width: 3264
height 2448
12-19 16:00:33.208 29863-29863/ngc.com.camera2app D/CameraView: Setting display tile dimensions to:
width: 176
height 144
12-19 16:00:33.948 29863-29863/ngc.com.camera2app D/CameraView: Surface created
12-19 16:00:33.949 29863-29863/ngc.com.camera2app D/CameraView: preview surface changed dimensions are
12-19 16:00:33.950 29863-29863/ngc.com.camera2app D/CameraView: width : 3264 | height : 2448
12-19 16:00:33.964 29863-29863/ngc.com.camera2app D/CameraView: Surface created
12-19 16:00:33.964 29863-29863/ngc.com.camera2app D/CameraView: display surface changed dimensions are
12-19 16:00:33.964 29863-29863/ngc.com.camera2app D/CameraView: width : 176 | height : 144
12-19 16:00:33.973 29863-29863/ngc.com.camera2app I/CameraController: Attempting to open camera
12-19 16:00:34.048 29863-29929/ngc.com.camera2app I/CameraController: Camera 0 is open for business
12-19 16:00:34.055 29863-29863/ngc.com.camera2app W/PathParser: Points are too far apart 4.000000596046461
12-19 16:00:34.065 29863-29929/ngc.com.camera2app D/CameraView: Camera ready
12-19 16:00:48.343 29863-29929/ngc.com.camera2app I/CameraController: Image available
我仍然卡住了,想解决这个非常微妙的复杂错误,并简单地从 ImageReader 的回调中加载图像。但是API说可以,为什么不呢!!
编辑2
当来自表面的两个回调都经过 onChanged() 时调用此方法
private synchronized void openCamera(){
if(displayReady && previewReady){
try {
List<Surface> displaySurfaces = new ArrayList<>();
//uncommenting this line adds a nasty bug
displaySurfaces.add(mPreviewView.getHolder().getSurface());
List<Surface> previewSurfaces = new ArrayList<>();
previewSurfaces.add(mCapturedTile.getHolder().getSurface());
mCameraController.openCamera(displaySurfaces, previewSurfaces);
} catch (CameraAccessException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
编辑3 将两个显示器的分辨率更改为相同,结果相同。 SystemUI 变得非常扭曲(顶部的通知栏在整个屏幕上重复,底部的软按钮移动到屏幕中间,非常奇怪)。我试图拍下这种行为的照片,但这是我得到的
请注意,上面的屏幕截图不是 UI 显示给我的。此外,在应用程序关闭并重新启动后,预览屏幕的一半是绿色的(同样,无法通过屏幕截图捕捉到这一点)。有什么想法吗?我开始认为 Camera2 API 有一个错误,但是,我也开始认为需要在这些表面上设置一些配置。不确定为什么奇怪的 UI 行为...
谢谢@EddyTalvala,原来问题是由于分辨率不匹配造成的。 预览表面:3264 x 2446 显示表面:176 X 148
我在中间遇到了,把这两个的分辨率都改成了 640,480,问题就解决了。