有的时候,客户需求在同一个app内的两个texttureview上,显示同一个camera画面。也就是将同一份camera预览数据,分发到不同的TexttureView上。针对这个需求,实现非常简单。我们先来普及一下camera api2的预览基本流程。
1.)CameraManager调用openCamera()打开指定相机设备,并返回一个CameraDevice对象,后续通过该CameraDevice对象操控具体的相机设备。
2.)使用CameraDevice对象的createCaptureSession()创建一个session,数据请求(预览、拍照等)都是通过session进行。在创建session时,需要提供Surface作为参数,用于接收返回的图像。
3.)........
我们先看下createCaptureSession的代码:
public void createCaptureSession(List<Surface> outputs,
CameraCaptureSession.StateCallback callback, Handler handler)
throws CameraAccessException {
List<OutputConfiguration> outConfigurations = new ArrayList<>(outputs.size());
for (Surface surface : outputs) {
outConfigurations.add(new OutputConfiguration(surface));
}
createCaptureSessionInternal(null, outConfigurations, callback,
checkAndWrapHandler(handler), /*operatingMode*/ICameraDeviceUser.NORMAL_MODE,
/*sessionParams*/ null);
}
在这里,将Surface转化为OutputConfiguration,OutputConfiguration是一个描述camera输出数据的类,其中包括Surface和捕获camera会话的特定设置。createCaptureSession传入的Surface列表有几个呢?
这儿的一个Surface表示输出流,Surface表示有多个输出流,我们有几个显示载体,就需要几个输出流。对于拍照而言,有两个输出流:一个用于预览、一个用于拍照。对于录制视频而言,有两个输出流:一个用于预览、一个用于录制视频。
重点来了,这里的surface,不是只能有2个,你可以有多个。比如你想在2个texttureView上显示,那就就可以有2个,当然也可以有3个4个。以google的camera2Basic为例,下面详细说明下怎么处理。
1.)修改fragment_camera2_basic.xml这个文件,新增一个TextureView
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="300dp"
android:orientation="horizontal">
<com.example.android.camera2basic.AutoFitTextureView
android:id="@+id/texture"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="fill_parent" />
<com.example.android.camera2basic.AutoFitTextureView
android:id="@+id/texture2"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_marginLeft="5dp"
android:layout_height="fill_parent" />
</LinearLayout>
<FrameLayout
android:id="@+id/control"
android:layout_width="match_parent"
android:layout_height="112dp"
android:layout_alignParentBottom="true"
android:layout_alignParentStart="true"
android:visibility="gone"
android:background="@color/control_background">
<Button
android:id="@+id/picture"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="gone"
android:text="@string/picture" />
<ImageButton
android:id="@+id/info"
android:contentDescription="@string/description_info"
style="@android:style/Widget.Material.Light.Button.Borderless"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
android:layout_gravity="center_vertical|right"
android:padding="20dp"
android:src="@drawable/ic_action_info" />
</FrameLayout>
</RelativeLayout>
上面的texture2就是我新增加的第二个显示surface.
2.)在Camera2BasicFragment.java里添加一行代码:
private AutoFitTextureView mTextureView2;
3.)在onViewCreated函数里添加我们的控件:
@Override
public void onViewCreated(final View view, Bundle savedInstanceState) {
mTextureView = (AutoFitTextureView) view.findViewById(R.id.texture);
mTextureView2 = (AutoFitTextureView) view.findViewById(R.id.texture2);
}
4.)在createCameraPreviewSession() 函数里,将我们的控件添加到CaptureSession里去。
private void createCameraPreviewSession() {
try {
SurfaceTexture texture = mTextureView.getSurfaceTexture();
SurfaceTexture texture2 = mTextureView2.getSurfaceTexture();
assert texture != null;
Log.d(TAG, "createCameraPreviewSession mPreviewSize is: "+mPreviewSize.getWidth()+"*"+mPreviewSize.getHeight());
// We configure the size of default buffer to be the size of camera preview we want.
texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
texture2.setDefaultBufferSize(320, 240);
// This is the output Surface we need to start preview.
Surface surface = new Surface(texture);
Surface surface2 = new Surface(texture2);
// We set up a CaptureRequest.Builder with the output Surface.
mPreviewRequestBuilder
= mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
mPreviewRequestBuilder.addTarget(surface);
mPreviewRequestBuilder.addTarget(surface2);
mPreviewRequestBuilder.addTarget(mImageReader.getSurface());
//在一份预览,可以同时显示在多个textureview上。
mCameraDevice.createCaptureSession(Arrays.asList(surface, surface2, mImageReader.getSurface()),
new CameraCaptureSession.StateCallback() {
........
}
}
}
按上面这样处理后,就可以将同一份camera的预览数据,发送到不同的texttureView上去了,且不同的texttureView显示的画面可以有不同的分辨率。最终的效果如下图:
附上一篇很不错的博客,大伙可以去学习学习:
https://www.jianshu.com/p/3d88711a6911
上面这些是在同一个app里,多个texttureView共用同一个camera数据的例子。如果想要在不同的app间共用同一个camera,这就要用到虚拟摄像头了。这一部份,可以看我后续的博客
本人建了个android camera系统 微信群,不过现在群成员超200了,不能通过二维码扫码加入,有兴趣的,可以加我微信号:xuhui_7810,到时拉你们入群。