camera api2 同一个应用内,在多个TextureView上显示同一个camera

        有的时候,客户需求在同一个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,这就要用到虚拟摄像头了。这一部份,可以看我后续的博客

猜你喜欢

转载自blog.csdn.net/xuhui_7810/article/details/106057066