Разработка Android приложений для Lollipop используя Camera2 API Часть 2

4.463 (8)

В предыдущей части мы расмотрели основу для построения работы с камерой. Теперь мы продолжим изучать новый интерфейс для работы. 

Итак, мы можем открывать для работы наши камеры. Для этого в классе 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());
}

Теперь, если мы запустим приложения и нажмем на кнопку, то увидим изображения с нашей камеры!

Часть 1 Часть3

См. так же "Разработка Android приложений в Студии Интерактивного Дизайна"

Комментарий (5)

andrey

13 Марта 2019 в 16:37

утеряно объявление переменной mSession

0/ 0
ответить

Антон Тарасов

12 Мая 2017 в 10:47

>@dimen/activity_horizontal_margin Откуда брать вот это и чему они равны?

0/ 0
ответить

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());

0/ 0
ответить

sidadmin

Антон, Спасибо вам за отзыв. 1. Статья обновлена и метод был благополучно реализован в статье. 2. Тоже верное замечание. Исправлено.

Войдите с помощью соцсетей:
или
введите свои данные: