2

I am displaying Camera Preview on a Fragment through Surface View. I got everything working fine but the thing that is annoying me is that it takes about 4-5 seconds to start the Preview and things like 'Stop ' during the duration : My XML Files for the SurfaceView which i host in FrameLayout is actually a FrameLayout Instead of a SurfaceView . Is it due to this the Preview takes time. If not So , What May be the Reason behind the Lag. Any Help would be greatly appreciated

The Code for the CameraPreview is :

class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {

    // SurfaceHolder
    private SurfaceHolder mHolder;

    // Our Camera.
    private Camera mCamera;

    // Parent Context.
    private Context mContext;

    // Camera Sizing (For rotation, orientation changes)
    private Camera.Size mPreviewSize;

    // List of supported preview sizes
    private List<Camera.Size> mSupportedPreviewSizes;

    // Flash modes supported by this camera
    private List<String> mSupportedFlashModes;

    // View holding this camera.
    private View mCameraView;

    public CameraPreview(Context context, Camera camera, View cameraView) {
        super(context);

        // Capture the context
        mCameraView = cameraView;
        mContext = context;
        setCamera(camera);

        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        mHolder = getHolder();
        mHolder.addCallback(this);
        mHolder.setKeepScreenOn(true);
        // deprecated setting, but required on Android versions prior to 3.0
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    /**
     * Begin the preview of the camera input.
     */
    public void startCameraPreview()
    {
        try{
            mCamera.setPreviewDisplay(mHolder);
            new Thread(new Runnable() {
                @Override
                public void run() {
                        mCamera.startPreview();

                }
            }).start();
        }
        catch(Exception e){
            e.printStackTrace();
        }
    }

    /**
     * Extract supported preview and flash modes from the camera.
     * @param camera
     */
    private void setCamera(Camera camera)
    {
        // Source: http://stackoverflow.com/questions/7942378/android-camera-will-not-work-startpreview-fails
        mCamera = camera;
        mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
        mSupportedFlashModes = mCamera.getParameters().getSupportedFlashModes();

        // Set the camera to Auto Flash mode.
        if (mSupportedFlashModes != null && mSupportedFlashModes.contains(Camera.Parameters.FLASH_MODE_AUTO)){
            Camera.Parameters parameters = mCamera.getParameters();
            parameters.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);
            mCamera.setParameters(parameters);
        }

        requestLayout();
    }

    /**
     * The Surface has been created, now tell the camera where to draw the preview.
     * @param holder
     */
    public void surfaceCreated(SurfaceHolder holder) {
        try {
            if(mCamera!=null){
                mCamera.setPreviewDisplay(holder);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * Dispose of the camera preview.
     * @param holder
     */
    public void surfaceDestroyed(SurfaceHolder holder) {
        if (mCamera != null){
            mCamera.stopPreview();
        }
    }

    /**
     * React to surface changed events
     * @param holder
     * @param format
     * @param w
     * @param h
     */
    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        // If your preview can change or rotate, take care of those events here.
        // Make sure to stop the preview before resizing or reformatting it.

        if (mHolder.getSurface() == null ||mCamera==null){
            // preview surface does not exist
            return;
        }

        // stop preview before making changes
        try {
            Camera.Parameters parameters = mCamera.getParameters();

            // Set the auto-focus mode to "continuous"
            parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);

            // Preview size must exist.
            if(mPreviewSize != null) {
                Camera.Size previewSize = mPreviewSize;
                parameters.setPreviewSize(previewSize.width, previewSize.height);
            }
            if(cameratype==Camera.CameraInfo.CAMERA_FACING_BACK){
                mCamera.setParameters(parameters);   //Nothing to be done for the Front Camera here
            }
            new Thread(new Runnable() {
                @Override
                public void run() {
                    mCamera.startPreview();

                }
            }).start();
        } catch (Exception e){
            e.printStackTrace();
        }


        //The Rotating Proble,
        if (mHolder.getSurface() == null) {
            // preview surface does not exist
            return;
        }

        // stop preview before making changes
        try {
            mCamera.stopPreview();
        } catch (Exception e) {
            // ignore: tried to stop a non-existent preview
        }

        // make any resize, rotate or reformatting changes here
        if (this.getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE) {

            mCamera.setDisplayOrientation(90);

        } else {
            mCamera.setDisplayOrientation(0);
        }
        // start preview with new settings
        try {
            mCamera.setPreviewDisplay(mHolder);

            new Thread(new Runnable() {
                @Override
                public void run() {
                    mCamera.startPreview();

                }
            }).start();

        } catch (Exception e) {
            Log.d("Newly Added", "Error starting camera preview: " + e.getMessage());
        }
    }

    /**
     * Calculate the measurements of the layout
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        // Source: http://stackoverflow.com/questions/7942378/android-camera-will-not-work-startpreview-fails
        final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
        final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
        setMeasuredDimension(width, height);

        if (mSupportedPreviewSizes != null){
            mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
        }
    }

    /**
     * Update the layout based on rotation and orientation changes.
     * @param changed
     * @param left
     * @param top
     * @param right
     * @param bottom
     */
    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom)
    {
        // Source: http://stackoverflow.com/questions/7942378/android-camera-will-not-work-startpreview-fails
        if (changed) {
            final int width = right - left;
            final int height = bottom - top;

            int previewWidth = width;
            int previewHeight = height;

            if (mPreviewSize != null){
                Display display = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();

                switch (display.getRotation())
                {
                    case Surface.ROTATION_0:
                        previewWidth = mPreviewSize.height;
                        previewHeight = mPreviewSize.width;
                        mCamera.setDisplayOrientation(90);
                        break;
                    case Surface.ROTATION_90:
                        previewWidth = mPreviewSize.width;
                        previewHeight = mPreviewSize.height;
                        break;
                    case Surface.ROTATION_180:
                        previewWidth = mPreviewSize.height;
                        previewHeight = mPreviewSize.width;
                        break;
                    case Surface.ROTATION_270:
                        previewWidth = mPreviewSize.width;
                        previewHeight = mPreviewSize.height;
                        mCamera.setDisplayOrientation(180);
                        break;
                }
            }

            final int scaledChildHeight = previewHeight * width / previewWidth;
            mCameraView.layout(0, height - scaledChildHeight, width, height);
        }
    }

    /**
     *
     * @param sizes
     * @param width
     * @param height
     * @return
     */
    private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int width, int height)
    {
        // Source: http://stackoverflow.com/questions/7942378/android-camera-will-not-work-startpreview-fails
        Camera.Size optimalSize = null;

        final double ASPECT_TOLERANCE = 0.1;
        double targetRatio = (double) height / width;

        // Try to find a size match which suits the whole screen minus the menu on the left.
        for (Camera.Size size : sizes){

            if (size.height != width) continue;
            double ratio = (double) size.width / size.height;
            if (ratio <= targetRatio + ASPECT_TOLERANCE && ratio >= targetRatio - ASPECT_TOLERANCE){
                optimalSize = size;
            }
        }

        // If we cannot find the one that matches the aspect ratio, ignore the requirement.
        if (optimalSize == null) {
            // TODO : Backup in case we don't get a size.
        }

        return optimalSize;
    }
}

/**
 * Picture Callback for handling a picture capture and saving it out to a file.
 */
private Camera.PictureCallback mPicture = new Camera.PictureCallback() {

    @Override
    public void onPictureTaken(byte[] data, Camera camera) {

        //This One is Just for Getting a File Named after it
        ProgressDialog loading=new ProgressDialog(BaseImagesContainer.reference);
        loading.setMessage("Getting Image Ready");
        loading.show();
        File pictureFile = getOutputMediaFile();
        if (pictureFile == null){
            Toast.makeText(getActivity(), "Image retrieval failed.", Toast.LENGTH_SHORT)
            .show();
            return;
        }
        Bitmap bmp = BitmapFactory.decodeByteArray(data,0, data.length);
        bmp=rotateImage(90,bmp);
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        bmp.compress(Bitmap.CompressFormat.PNG,1, stream);
        byte[] flippedImageByteArray = stream.toByteArray();
        try {
            FileOutputStream fos = new FileOutputStream(pictureFile);
            fos.write(flippedImageByteArray);
            fos.close();
            // Restart the camera preview.
            safeCameraOpenInView(mCameraView);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        //Intent filter=new Intent(BaseImagesContainer.reference, FilterActivity.class);
        //filter.putExtra("Bitmap",String.valueOf(pictureFile.getPath()));
        //getActivity().startActivity(filter);

       // loading.dismiss();
     Uri destination = Uri.fromFile(new File(getActivity().getCacheDir(), "cropped"));
        Uri source = Uri.fromFile(new File(pictureFile.getPath()));
        Crop.of(source, destination).withMaxSize(800,800).start(getActivity());
    }
};
  • Try to check whether activity is restarting during create surfaceview (and this do the lag) – Majkl Nov 10 '15 at 13:01
  • No Activity is not Restarting, I have kept the SurfaceView under Fragment , Viewpager to be more specific. and Checked that Fragments and Activities both are not restarted :) – facebook-1590302711235435 Nov 10 '15 at 14:00
  • *My XML Files for the SurfaceView which i host in FrameLayout is actually a FrameLayout Instead of a SurfaceView* is not quite clear. Maybe you could paste this XML here, that would make it easier to understand your question. – Alex Cohn Nov 11 '15 at 15:32
  • One problem with your approach is that you handle the camera and all its callbacks on the main (UI) thread. On some devices, the effect is minimal; on other devices, **Camera.open()** can take long enough to trigger the **ANR** system popup. Consider [switching to a background handler thread](http://stackoverflow.com/questions/18149964/best-use-of-handlerthread-over-other-similar-classes/19154438#19154438). – Alex Cohn Nov 11 '15 at 15:36
  • @AlexCohn I Read somewhere that Camera.open () process happens in the UI Thread Itself . Isn't it so ?? – facebook-1590302711235435 Nov 11 '15 at 17:18
  • Not at all! See the official doc – Alex Cohn Nov 11 '15 at 18:27
  • 1
    did you find solution for this? please update if you found. i am also facing the same issue. too slow. http://stackoverflow.com/questions/39585670/takes-long-time-to-open-in-custom-camera-android – Star Sep 20 '16 at 10:19

0 Answers0