Как включить вспышку в Camera2 API без создания нового сеанса? - PullRequest
0 голосов
/ 24 июня 2018

Я работаю над приложением на основе Camera2 API.И я хочу добавить функцию включения / выключения вспышки в этом приложении.

Есть некоторые проблемы.Я использую 3 разных потока для рендеринга и поэтому один и общаюсь между этими потоками через обработчики.Когда пользователь нажимает кнопку вспышки, я хочу включить ее, и я могу сделать это следующим образом:

 mPreviewBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_SINGLE);
 mPreviewSession.setRepeatingRequest(mPreviewBuilder.build(), null, null);

Но, как я понимаю, создание нового сеанса предварительного просмотра - дорогостоящая процедура, и я также не хочупотерять все кадры с камеры.

Есть ли способ включить свет вспышки без создания нового сеанса?Или я не прав, и это совсем не требует много ресурсов?

Мне также интересно, как это реализовано в стандартных приложениях для камер.Может быть, есть какой-нибудь открытый исходный код?

Спасибо всем за ответы заранее!

Ответы [ 3 ]

0 голосов
/ 25 июня 2018

Вам нужно только создать один CameraCaptureSession и просто вызвать его capture() или setRepeatingRequest() методы, чтобы отправить на него CaptureRequest s, так что это совсем не дорогая процедура, создается только CameraCaptureSession когда вы открыли CameraDevice и запустили предварительный просмотр, CameraCaptureSession позаботится обо всех отправленных вами CaptureRequest и приложит все усилия, чтобы не потерять ни одного кадра.

См. Код из google / cameraview :

void setFlash(int flash) {
    if (mFlash == flash) {
        return;
    }
    int saved = mFlash;
    mFlash = flash;
    if (mPreviewRequestBuilder != null) {
        updateFlash(); // Set the new flash settings
        if (mCaptureSession != null) {
            try {
                mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(),
                        mCaptureCallback, null);
            } catch (CameraAccessException e) {
                mFlash = saved; // Revert
            }
        }
    }
}

void updateFlash() {
    switch (mFlash) {
        case Constants.FLASH_OFF:
            mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE,
                    CaptureRequest.CONTROL_AE_MODE_ON);
            mPreviewRequestBuilder.set(CaptureRequest.FLASH_MODE,
                    CaptureRequest.FLASH_MODE_OFF);
            break;
        case Constants.FLASH_ON:
            mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE,
                    CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH);
            mPreviewRequestBuilder.set(CaptureRequest.FLASH_MODE,
                    CaptureRequest.FLASH_MODE_OFF);
            break;
        case Constants.FLASH_TORCH:
            mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE,
                    CaptureRequest.CONTROL_AE_MODE_ON);
            mPreviewRequestBuilder.set(CaptureRequest.FLASH_MODE,
                    CaptureRequest.FLASH_MODE_TORCH);
            break;
        case Constants.FLASH_AUTO:
            mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE,
                    CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
            mPreviewRequestBuilder.set(CaptureRequest.FLASH_MODE,
                    CaptureRequest.FLASH_MODE_OFF);
            break;
        case Constants.FLASH_RED_EYE:
            mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE,
                    CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE);
            mPreviewRequestBuilder.set(CaptureRequest.FLASH_MODE,
                    CaptureRequest.FLASH_MODE_OFF);
            break;
    }
}
0 голосов
/ 26 июня 2018

Изменение повторяющегося запроса сеанса совсем не дорого. Он не воссоздает сеанс (это произойдет, только если вы снова вызовете CameraDevice.createCaptureSession), и, как правило, не будет никаких сбоев при изменении параметра, подобного этому. Изменение повторяющегося запроса - это именно то, как вы должны включать фонарик, когда у вас устройство с открытой камерой.

Обратите внимание, что установка режима флэш-памяти на SINGLE в повторяющемся запросе, вероятно, не то, что вам нужно; вам, вероятно, нужен режим вспышки TORCH (для непрерывного сглаживания фонарика, а не для срабатывания основной вспышки), и вам также необходимо убедиться, что настройка CONTROL_AE_MODE не является одним из режимов AE_MODE_ON_FLASH *; в противном случае процедура автоэкспозиции устройства камеры управляет вспышкой, а настройка FLASH_MODE игнорируется.

0 голосов
/ 24 июня 2018

Попробуйте, полный код для съемки с использованием Camera2 API, Fragment_Camera4

public class Fragment_Camera4 extends Fragment implements

        AspectRatioFragment.Listener {
    private View view;
    private static final String TAG = "MainActivity";
    private static final int REQUEST_CAMERA_PERMISSION = 1;
    private static final String FRAGMENT_DIALOG = "dialog";

    private static final int[] FLASH_OPTIONS = {
            CameraView.FLASH_OFF,
            CameraView.FLASH_ON,
    };

    private static final int[] FLASH_ICONS = {

            R.drawable.ic_flash_off,
            R.drawable.ic_flash_on,
    };

    private static final int[] FLASH_TITLES = {
            R.string.flash_auto,
            R.string.flash_off,
            R.string.flash_on,
    };

    private int mCurrentFlash;

    private CameraView mCameraView;

    private Handler mBackgroundHandler;

    private View.OnClickListener mOnClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.take_picture:
                    if (mCameraView != null) {
                        mCameraView.takePicture();
                    }
                    break;
                case R.id.btn_switch_camera:

                    if (mCameraView != null) {
                        int facing = mCameraView.getFacing();
                        mCameraView.setFacing(facing == CameraView.FACING_FRONT ?
                                CameraView.FACING_BACK : CameraView.FACING_FRONT);
                        if (facing == CameraView.FACING_FRONT) {

                            btn_flash_onOff.setVisibility(View.VISIBLE);
                        } else {
                            btn_flash_onOff.setVisibility(View.GONE);
                        }
                    }

                    break;
                case R.id.btn_flash_onOff:
                    if (mCameraView != null) {
                        mCurrentFlash = (mCurrentFlash + 1) % FLASH_OPTIONS.length;
                        btn_flash_onOff.setImageResource(FLASH_ICONS[mCurrentFlash]);
                        mCameraView.setFlash(FLASH_OPTIONS[mCurrentFlash]);
                    }
                    break;
            }
        }
    };
    ImageButton btn_flash_onOff;

    public Fragment_Camera4() {
        // Required empty public constructor
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        view = inflater.inflate(R.layout.fragment_fragment__camera4, container, false);
        mCameraView = (CameraView) view.findViewById(R.id.camera);
        if (mCameraView != null) {
            mCameraView.addCallback(mCallback);

        }
        ImageButton fab = (ImageButton) view.findViewById(R.id.take_picture);

        ImageButton btn_switch_camera = (ImageButton) view.findViewById(R.id.btn_switch_camera);

        btn_flash_onOff = (ImageButton) view.findViewById(R.id.btn_flash_onOff);
        if (fab != null) {
            fab.setOnClickListener(mOnClickListener);
            btn_switch_camera.setOnClickListener(mOnClickListener);
            btn_flash_onOff.setOnClickListener(mOnClickListener);
        }

        return view;
    }

    @Override
    public void onResume() {
        super.onResume();
        mCameraView.start();
    }

    @Override
    public void onPause() {
        mCameraView.stop();
        super.onPause();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (mBackgroundHandler != null) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
                mBackgroundHandler.getLooper().quitSafely();
            } else {
                mBackgroundHandler.getLooper().quit();
            }
            mBackgroundHandler = null;
        }
    }

    @Override
    public void onAspectRatioSelected(@NonNull AspectRatio ratio) {
        if (mCameraView != null) {
            Toast.makeText(getActivity(), ratio.toString(), Toast.LENGTH_SHORT).show();
            mCameraView.setAspectRatio(ratio);
        }
    }

    private Handler getBackgroundHandler() {
        if (mBackgroundHandler == null) {
            HandlerThread thread = new HandlerThread("background");
            thread.start();
            mBackgroundHandler = new Handler(thread.getLooper());
        }
        return mBackgroundHandler;
    }

    private CameraView.Callback mCallback
            = new CameraView.Callback() {

        @Override
        public void onCameraOpened(CameraView cameraView) {
            Log.d(TAG, "onCameraOpened");
        }

        @Override
        public void onCameraClosed(CameraView cameraView) {
            Log.d(TAG, "onCameraClosed");
        }

        @Override
        public void onPictureTaken(CameraView cameraView, final byte[] data) {
            Log.d(TAG, "onPictureTaken " + data.length);
            Toast.makeText(cameraView.getContext(), R.string.picture_taken, Toast.LENGTH_SHORT)
                    .show();

        }

    };

}

Тогда файл Cameraview находится здесь по этой ссылке на github. https://github.com/quicklearner4991/Camera2/blob/master/CameraView получить ресурсы по этой ссылке, я не могу опубликовать этот длинный ответ здесь, я отредактировал свой код для camera2 с опциями вспышки, которые не доступны легко. Ссылка для скачивания ресурсов с использованием этого репо

https://github.com/googlesamples/android-Camera2Basic и xml для просмотров

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/root"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/colorgrey">

    <com.google.android.cameraview.CameraView
        android:id="@+id/camera"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_alignParentTop="true"
        android:adjustViewBounds="true"
        android:background="@android:color/black" />

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_alignParentTop="true" />

    <ImageButton
        android:id="@+id/take_picture"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="20dp"
        android:background="#0000"
        app:srcCompat="@drawable/ic_take_pic" />

    <ImageButton
        android:id="@+id/btn_switch_camera"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:layout_margin="20dp"
        android:background="#0000"
        app:srcCompat="@drawable/ic_reset_camera" />

    <ImageButton
        android:id="@+id/btn_flash_onOff"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_margin="20dp"
        android:background="#0000"
        app:srcCompat="@drawable/ic_flash_off" />
</RelativeLayout>
...