Search code examples
androidc++cameraunreal-engine4

android.hardware.Camera fails to open every second time


Problem background

I am developing a VR Project on Unreal Engine 4, and the project requires the usage of Android's native camera. Since there are no built-in functions in UE4 to iteract with Android's native methods, I customized this plugin under my need.

The original plugin uses the JNI interface to iteract with C++ code. It calls camera.open() and camera.startPreview() on UE4's EventBeginPlay, and calls camera.stopPreview() and camera.Release() on UE4's EventEndPlay. Since it is a known issue that EventEndPlay never fires up on Android platform, I decided to manipulate the camera in onResume() and onPause() methods. Here is the code:

<gameActivityClassAdditions>
<insert>
  /* Unrelevant code goes here */
    ...
    ...
  /* End of unrelevant code */

  public void AndroidThunkJava_startCamera()
  {                        
    surfaceTexture = new SurfaceTexture(10);
    surfaceTexture.setDefaultBufferSize(preferredWidth, preferredHeight);

    if (camera == null){
      try {
        camera = Camera.open();
      } catch (RuntimeException exc) {
        return;
      }
    }               

    try {
      camera.setPreviewTexture(surfaceTexture);
    } catch (IOException t) {
      return;
    }

    Parameters cameraParam = camera.getParameters();

    cameraParam.setPreviewFormat(ImageFormat.NV21);
    cameraParam.setPreviewSize(preferredWidth, preferredHeight);
    cameraParam.setPreviewFpsRange(preferredFPS, preferredFPS);
    cameraParam.setFocusMode(Camera.Parameters.FOCUS_MODE_MACRO);
    if (cameraParam.isVideoStabilizationSupported()) {
      cameraParam.setVideoStabilization(false);
    }
    if (cameraParam.isAutoWhiteBalanceLockSupported()) {
      cameraParam.setAutoWhiteBalanceLock(false);
    }

    camera.setParameters(cameraParam);

    camera.setPreviewCallback(new PreviewCallback() {
      @Override
      public void onPreviewFrame(byte[] data, Camera camera) {
        int Height = camera.getParameters().getPreviewSize().height;
        int Width = camera.getParameters().getPreviewSize().width;

        // calling C++ function via JNI interface
        processFrameData(Width, Height, data);
      }
    });

    camera.startPreview();
  }

  public void AndroidThunkJava_stopCamera()
  {
    if (camera != null)
    {
      camera.stopPreview();
      camera.release();
      camera = null;
    }
  }
</insert>
</gameActivityClassAdditions>

<gameActivityOnPauseAdditions>
<insert>
  AndroidThunkJava_stopCamera();
</insert>
</gameActivityOnPauseAdditions>

<gameActivityOnResumeAdditions>
<insert>  
  AndroidThunkJava_startCamera();
</insert>
</gameActivityOnResumeAdditions>

The problem

The camera works fine every second time. That means:

I open the app, camera is working. I pushed the home button (which triggers onPause() method), then switch back to the app (triggers onResume() method). Pushed the home button again, and then switched back - camera works. And so on, the camera works every second time.

Anybody have any idea about this issue? Is that connected to the fact that android.hardware.Camera is deprecated? I'm using API version 19, so it is not possible to use newer android.hardware.camera2.


Solution

  • Here is my onStop and onResume methods. I'm not using onPause. And it works perfectly:

      @Override
        protected void onResume() {
            super.onResume();
            if (mCamera == null) {
                restartPreview();
            }
        }
        @Override
        public void onStop() {
    
            // stop the preview
            if (mCamera != null) {
                stopCameraPreview();
                mCamera.release();
                mCamera = null;
            }
    
            super.onStop();
        }
    
     private void restartPreview() {
            if (mCamera != null) {
                stopCameraPreview();
                mCamera.release();
                mCamera = null;
            }
    
    
    
                getCamera(mCameraID);
                startCameraPreview();
            }
    
    private void startCameraPreview() {
    
    
            try {
                mCamera.setPreviewDisplay(mSurfaceHolder);
                mCamera.startPreview();
    
                setSafeToTakePhoto(true);
                setCameraFocusReady(true);
            } catch (IOException e) {
                Log.d("st", "Can't start camera preview due to IOException " + e);
                e.printStackTrace();
            }
        }
    
     private void stopCameraPreview() {
            setSafeToTakePhoto(false);
            setCameraFocusReady(false);
    
            // Nulls out callbacks, stops face detection
            mCamera.stopPreview();
            mPreviewView.setCamera(null);
        }
    

    maybe some implementations not equals yours but i think it is help you.