Ening
Ening

Reputation: 465

How to enable flash light in Camera2 API without building new session?

I'm working on app based on Camera2 API. And I want to add feature of enabling/disabling flash light in this app.

There are some problems. I use 3 different threads for rendering and so one and communicate between this threads via Handlers. When user pree flash light button I want to enable it, and I can do it like this:

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

But , as I understand creating new prewiew session is expensive procedure, and I also don't want to loose any frames from camera.

Is there any way of enabling flash light without building new session? Or I'm wrong and it doesn't take a lot of resources at all?

I also wonder how it's implemented in standart camera applications. Maybe there is any open source code?

Thanks everyone for answers in advance!

Upvotes: 0

Views: 2704

Answers (3)

Eddy Talvala
Eddy Talvala

Reputation: 18137

Changing the repeating request of a session is not expensive at all. It doesn't re-create the session (that would only happen if you call CameraDevice.createCaptureSession again), and there won't generally be any glitches from changing a setting like this. Changing the repeating request is exactly how you should be turning on the flashlight when you have an open camera device.

Note that setting the flash mode to SINGLE in a repeating request is probably not what you want; you probably want flash mode of TORCH (For continuous smooth flashlight, not strobing main flash firing), and you'll also need to make sure you CONTROL_AE_MODE setting is not one of the AE_MODE_ON_FLASH* modes; otherwise the camera device's autoexposure routine is in control of the flash and the FLASH_MODE setting is ignored.

Upvotes: 2

Hong Duan
Hong Duan

Reputation: 4304

You only need to create one CameraCaptureSession, and just call its capture() or setRepeatingRequest() methods to send CaptureRequests to it, so it's not an expensive procedure at all, the only CameraCaptureSession is created when you have opened the CameraDevice and started your preview, the CameraCaptureSession will take care of all the CaptureRequests you send and do it's best to not cause any frames lost.

See the code from 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;
    }
}

Upvotes: 2

Quick learner
Quick learner

Reputation: 11477

Try this , Full code for taking picture using 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();

        }

    };

}

Then Cameraview file is here from this github link of mine https://github.com/quicklearner4991/Camera2/blob/master/CameraView get the resources from this link , i cant post that much long answer here , I have edited my code for camera2 with flash options which is not available easily . Link to download resources using this repo

https://github.com/googlesamples/android-Camera2Basic and xml for the views

<?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>

Upvotes: -1

Related Questions