Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

Illegal argument exception and thread issues on lockCanvas

I am attempting to take a picture, and in the onPictureTaken I atempt to make some layout changes and then pass the image data to a new activity. When making layout changes the app crashes with an illegal argument error that traces back to the cameraworker thread running in javacameraview. Can anyone help me with the proper way to handle this issue?

Any help would be immensely appreciated. For more information.

https://stackoverflow.com/questions/52076862/why-is-lockcanvas-throwing-illegal-argument-exceptions

Illegal argument exception and thread issues on lockCanvas

I am attempting to take a picture, and in the onPictureTaken I atempt to make some layout changes and then pass the image data to a new activity. When making layout changes the app crashes with an illegal argument error that traces back to the cameraworker CameraWorker thread running in javacameraview. Can anyone help JavaCameraView.

I know this is kind of long but I'm really stumped. I'd really appreciate any help.

The idea is like this: When the onPictureTaken is called i freeze the preview (to show the user the image he captured) and display an "ok" button and a "retry" button. However when I attempt to change the layout (i.e make the buttons visible) the app crashes wit the above error and the following stacktrace:

E/SurfaceHolder: Exception locking surface
                 java.lang.IllegalArgumentException
                     at android.view.Surface.nativeLockCanvas(Native Method)
                     at android.view.Surface.lockCanvas(Surface.java:267)
                     at android.view.SurfaceView$4.internalLockCanvas(SurfaceView.java:973)
                     at android.view.SurfaceView$4.lockCanvas(SurfaceView.java:941)
                     at org.opencv.android.CameraBridgeViewBase.deliverAndDrawFrame(CameraBridgeViewBase.java:405)
                     at org.opencv.android.JavaCameraView$CameraWorker.run(JavaCameraView.java:308)
                     at java.lang.Thread.run(Thread.java:818)

The methods are in CameraBridgeViewBase and are called via a thread that is running in JavaCameraView which is why I think this is a thread issue. Unfortunately I dont know where to go from here.

My methods that cause the crash are here:

@Override
    public void onPictureTaken(byte[] data, Camera camera) {
        Log.i(TAG, "Saving a bitmap to file");
        Toast.makeText(context,"Not Starting New Activity. Look at me now error!",Toast.LENGTH_LONG).show();;
        //attempt to export all this to JavaCameraView, i have a feeling that there is a conflict with his thread....maybe that will help
        buttonManager(data);

    }

    private void buttonManager(byte[] data) {
        //find buttons
        final byte[] img_data = data;
        final int width = this.getWidth();
        final int height = this.getHeight();

        okButton.setVisibility(View.VISIBLE);
        retryButton.setVisibility(View.VISIBLE);
        captureImageButton.setVisibility(View.GONE);


        okButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent startImgProc = new Intent(context,ImageProcessing.class);
                startImgProc.putExtra("image",img_data);
                startImgProc.putExtra("width",width);
                startImgProc.putExtra("height",height);
                disconnectCamera();
                context.startActivity(startImgProc);
                ((Activity) context).finish();
            }
        });

        retryButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                captureImageButton.setVisibility(View.VISIBLE);
                okButton.setVisibility(View.GONE);
                retryButton.setVisibility(View.GONE);
            }
        });
    }

The call to deliverAndDrawFrame is from JavaCameraView here:

private class CameraWorker implements Runnable {

        @Override
        public void run() {
            do {
                boolean hasFrame = false;
                synchronized (JavaCameraView.this) {
                    try {
                        while (!mCameraFrameReady && !mStopThread) {
                            JavaCameraView.this.wait();
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    if (mCameraFrameReady)
                    {
                        mChainIdx = 1 - mChainIdx;
                        mCameraFrameReady = false;
                        hasFrame = true;
                    }
                }

                if (!mStopThread && hasFrame) {
                    if (!mFrameChain[1 - mChainIdx].empty())
                        deliverAndDrawFrame(mCameraFrame[1 - mChainIdx]);
                }
            } while (!mStopThread);
            Log.d(TAG, "Finish processing thread");
        }
    }

and the proper way to handle this issue?method itself

Any help would be immensely appreciated. For more information.

https://stackoverflow.com/questions/52076862/why-is-lockcanvas-throwing-illegal-argument-exceptions

protected void deliverAndDrawFrame(CvCameraViewFrame frame) {
    Mat modified;

    if (mListener != null) {
        modified = mListener.onCameraFrame(frame);
    } else {
        modified = frame.rgba();
    }

    boolean bmpValid = true;
    if (modified != null) {
        try {
            Utils.matToBitmap(modified, mCacheBitmap);
        } catch(Exception e) {
            Log.e(TAG, "Mat type: " + modified);
            Log.e(TAG, "Bitmap type: " + mCacheBitmap.getWidth() + "*" + mCacheBitmap.getHeight());
            Log.e(TAG, "Utils.matToBitmap() throws an exception: " + e.getMessage());
            bmpValid = false;
        }
    }

    if (bmpValid && mCacheBitmap != null) {

            Canvas canvas = getHolder().lockCanvas();
            if (canvas != null) {
                canvas.drawColor(0, android.graphics.PorterDuff.Mode.CLEAR);
                Log.d(TAG, "mStretch value: " + mScale);

                if (mScale != 0) {
                    canvas.drawBitmap(mCacheBitmap, new Rect(0, 0, mCacheBitmap.getWidth(), mCacheBitmap.getHeight()),
                            new Rect((int) ((canvas.getWidth() - mScale * mCacheBitmap.getWidth()) / 2),
                                    (int) ((canvas.getHeight() - mScale * mCacheBitmap.getHeight()) / 2),
                                    (int) ((canvas.getWidth() - mScale * mCacheBitmap.getWidth()) / 2 + mScale * mCacheBitmap.getWidth()),
                                    (int) ((canvas.getHeight() - mScale * mCacheBitmap.getHeight()) / 2 + mScale * mCacheBitmap.getHeight())), null);
                } else {
                    canvas.drawBitmap(mCacheBitmap, new Rect(0, 0, mCacheBitmap.getWidth(), mCacheBitmap.getHeight()),
                            new Rect((canvas.getWidth() - mCacheBitmap.getWidth()) / 2,
                                    (canvas.getHeight() - mCacheBitmap.getHeight()) / 2,
                                    (canvas.getWidth() - mCacheBitmap.getWidth()) / 2 + mCacheBitmap.getWidth(),
                                    (canvas.getHeight() - mCacheBitmap.getHeight()) / 2 + mCacheBitmap.getHeight()), null);
                }

                if (mFpsMeter != null) {
                    mFpsMeter.measure();
                    mFpsMeter.draw(canvas, 20, 30);
                }
                getHolder().unlockCanvasAndPost(canvas);
            }
        }