В предыдущей части мы расмотрели основу для построения работы с камерой. Теперь мы продолжим изучать новый интерфейс для работы.
Итак, мы можем открывать для работы наши камеры. Для этого в классе CameraHelper создадим вспомогательные методы и поля:
private CameraDevice mCameraDevice = null;
public boolean isOpen() {
if (mCameraDevice == null) {
return false;
} else {
return true;
}
}
public void openCamera() {
try {
mCameraManager.openCamera(mCameraID,mCameraCallback,null);
} catch (CameraAccessException e) {
Log.e(MainActivity.LOG_TAG,e.getMessage());
//e.printStackTrace();
}
}
public void closeCamera() {
if (mCameraDevice != null) {
mCameraDevice.close();
mCameraDevice = null;
}
}
private CameraDevice.StateCallback mCameraCallback = new CameraDevice.StateCallback() {
@Override
public void onOpened(CameraDevice camera) {
mCameraDevice = camera;
Log.i(MainActivity.LOG_TAG, "Open camera with id:"+mCameraDevice.getId());
}
@Override
public void onDisconnected(CameraDevice camera) {
mCameraDevice.close();
Log.i(MainActivity.LOG_TAG, "disconnect camera with id:"+mCameraDevice.getId());
mCameraDevice = null;
}
@Override
public void onError(CameraDevice camera, int error) {
Log.i(MainActivity.LOG_TAG, "error! camera id:"+camera.getId()+" error:"+error);
}
};
В методе openCamera() с помощью нашего менеджера открываем камеры. В параметрах метода указываем, какую камеру открывать, а также обработчик, который будет отслеживать состояния открытия камеры.
Затем создадим 2 кнопки и повесим на них обработку открытий камер.
Добавим необходимые поля в нашем Activity
private final int CAMERA1 = 0;
private final int CAMERA2 = 1;
private CameraHelper[] myCameras = null;
private Button mButtonOpenCamera1 = null;
private Button mButtonOpenCamera2 = null;
и в методе onCreate инициализируем наши кнопки
mButtonOpenCamera1 = (Button) findViewById(R.id.btn_open_camera1);
mButtonOpenCamera2 = (Button) findViewById(R.id.btn_open_camera2);
mButtonOpenCamera1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (myCameras[CAMERA2].isOpen()) myCameras[CAMERA2].closeCamera();
if (myCameras[CAMERA1] != null) {
if (!myCameras[CAMERA1].isOpen()) myCameras[CAMERA1].openCamera();
}
}
});
mButtonOpenCamera2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (myCameras[CAMERA1].isOpen()) myCameras[CAMERA1].closeCamera();
if (myCameras[CAMERA2] != null) {
if (!myCameras[CAMERA2].isOpen()) myCameras[CAMERA2].openCamera();
}
}
});
также необходимо добавить в activity_main.xml файл описание разметки:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/btn_open_camera1"
android:text="@string/open_camera_1"
/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/btn_open_camera2"
android:text="@string/open_camera_2"
/>
<TextureView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/image_view"
android:background="#BDBDBD"
android:layout_margin="10dp"
/>
</LinearLayout>
</RelativeLayout>
Запускаем и смотрим на консоль наши уведомления о том, что камеры были открыты.
Для того, чтобы можно было просматривать или делать снимки, необходимо создать сессию для работы с камерой. У выбранной камеры необходимо вызвать метод createCaptureSession()
Давайте рассмотрим его поподробней. Данный метод имеет 3 параметра.
List<Surface> outputs — набор отображений, в которые будет складываться изображения.
Что это значит. Если посмотреть на модель камеры, которая используется, то можно заметить, что для выходного потока может использоваться несколько источников приема.
В табличке «Output stream destinations» указано большое количество объектов, которые могут принимать изображения. Каждое назначение может принимать определенный размер изображения. В документации указано, что список поддерживаемых разришений можно просмотреть, используя вышеописанный метод, к примеру, getOutputSizes(MediaRecorder.class), только здесь мы уже указали MediaRecorder.class в качестве параметра.
Далее необходимо создать в CameraHelper переменную и свойство на TextureView для того что бы указывать помощнику куда закладывать изображение:
private TextureView mTextureView = null;
….
public void setTextureView(TextureView textureView){
mTextureView = textureView;
}
Добавляем через MainActivity компонент для прорисовки нашего изображения и передаем его нашему помощнику для отображения изображений с камеры.
private TextureView mImageView = null;
….
mImageView = (TextureView) findViewById(R.id.image_view);
В цикле, где мы инициальзировали наши камеры нужно теперь кое-что добавить:
// устанавливаем текстуру для отображения
myCameras[id].setTextureView(mImageView);
Основной метод для прорисовки в CameraHelper
private void createCameraPreviewSession() {
SurfaceTexture texture = mTextureView.getSurfaceTexture();
texture.setDefaultBufferSize(1920,1080);
Surface surface = new Surface(texture);
try {
final CaptureRequest.Builder builder =
mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
builder.addTarget(surface);
mCameraDevice.createCaptureSession(
Arrays.asList(surface),
new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(CameraCaptureSession session) {
mSession = session;
try {
mSession.setRepeatingRequest(builder.build(),null,null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
@Override
public void onConfigureFailed(CameraCaptureSession session) {
}
},
null
);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
После того как наша камера открылась, нам необходимо создать вызвать этот метод
public void onOpened(CameraDevice camera) {
mCameraDevice = camera;
createCameraPreviewSession();
//mCameraDevice.createCaptureSession();
Log.i(MainActivity.LOG_TAG, "Open camera with id:"+mCameraDevice.getId());
}
Теперь, если мы запустим приложения и нажмем на кнопку, то увидим изображения с нашей камеры!
См. так же "Разработка Android приложений в Студии Интерактивного Дизайна"
Комментарий (5)
andrey
13 Марта 2019 в 16:37утеряно объявление переменной mSession
Антон Тарасов
12 Мая 2017 в 10:47>@dimen/activity_horizontal_margin Откуда брать вот это и чему они равны?
sidadmin
Антон Тарасов, Они по 16dp и создаются в res/values/dimen.xml
Антон
29 Сентября 2016 в 16:29Спасибо за гайд, помог разобраться по быстрому, но есть некоторые неточности. 1. В предпоследнем куске кода указан метод класа CameraHelper setTextureView(TextureView mImageView), но не вижу, чтоб он где-нибудь реализовался. 2. В конце первого куска кода в инициализации CameraDevice.StateCallback, метод onDisconnected, эти две строчки следует поменять местами mCameraDevice = null; Log.i(MainActivity.LOG_TAG, "disconnect camera with id:" + mCameraDevice.getId());
sidadmin
Антон, Спасибо вам за отзыв. 1. Статья обновлена и метод был благополучно реализован в статье. 2. Тоже верное замечание. Исправлено.