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,這就要用到虛擬攝像頭了。這一部份,可以看我後續的博客

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章