有的時候,客戶需求在同一個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,這就要用到虛擬攝像頭了。這一部份,可以看我後續的博客