三星设备上的Android Camera2问题

时间:2017-07-26 11:53:57

标签: java android android-camera2

我有一个Android视频捕获应用,但在三星设备中,我收到以下错误。

我试图从mRecordButton.click中移除startPreview()(这是实际停止录制的按钮),但没有成功。

我可以做些什么?

错误:

Fatal Exception: java.lang.NullPointerException: Attempt to invoke virtual method 'android.hardware.camera2.CaptureRequest$Builder android.hardware.camera2.CameraDevice.createCaptureRequest(int)' on a null object reference
       at com.jobconvo.www.newjcapp.CameraActivity.startPreview(CameraActivity.java:427)
       at com.jobconvo.www.newjcapp.CameraActivity.access$800(CameraActivity.java:53)
       at com.jobconvo.www.newjcapp.CameraActivity$5.onClick(CameraActivity.java:268)
       at android.view.View.performClick(View.java:5716)
       at android.widget.TextView.performClick(TextView.java:10926)
       at android.view.View$PerformClick.run(View.java:22596)
       at android.os.Handler.handleCallback(Handler.java:739)
       at android.os.Handler.dispatchMessage(Handler.java:95)
       at android.os.Looper.loop(Looper.java:148)
       at android.app.ActivityThread.main(ActivityThread.java:7325)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)

我的相机活动代码:

public class CameraActivity extends AppCompatActivity {

private static final int STATE_PREVIEW = 0;
private static final int STATE_WAIT_LOCK = 1;
private int mCaptureState = STATE_PREVIEW;

private TextureView mTextureView;
private TextureView.SurfaceTextureListener mSurfaceTextureListener = new TextureView.SurfaceTextureListener() {
    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
        setupCamera(width, height);
        try {
            connectCamera();
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {

    }

    @Override
    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
        return false;
    }

    @Override
    public void onSurfaceTextureUpdated(SurfaceTexture surface) {

    }
};

private CameraDevice mCameraDevice;
private CameraDevice.StateCallback mCameraDeviceStateCallback = new CameraDevice.StateCallback() {
    @Override
    public void onOpened(CameraDevice camera) {
        mCameraDevice = camera;
        mMediaRecorder = new MediaRecorder();
        if (mIsRecording) {
            try {
                createVideoFileName();
            } catch (IOException e) {
                e.printStackTrace();
            }
            startRecord();
            mMediaRecorder.start();
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    countDownTimer.start();
                }
            });
        } else {
            startPreview();
        }
    }

    @Override
    public void onDisconnected(CameraDevice camera) {
        camera.close();
        mCameraDevice = null;
    }

    @Override
    public void onError(CameraDevice camera, int error) {
        camera.close();
        mCameraDevice = null;
    }
};


private HandlerThread mBackgroundHandlerThread;
private Handler mBackgroundHandler;
private String mCameraId;
private Size mPreviewSize;
private Size mVideoSize;

private MediaRecorder mMediaRecorder;
private int mTotalRotation;
private CameraCaptureSession mPreviewCaptureSession;
private CameraCaptureSession.CaptureCallback mPreviewCaptureCallback = new
        CameraCaptureSession.CaptureCallback() {

            private void process(CaptureResult captureResult) {
                switch (mCaptureState) {
                    case STATE_PREVIEW:
                        // Do nothing
                        break;
                    case STATE_WAIT_LOCK:
                        mCaptureState = STATE_PREVIEW;
                        Integer afState = captureResult.get(CaptureResult.CONTROL_AF_STATE);
                        if (afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED ||
                                afState == CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED) {
                            Toast.makeText(getApplicationContext(), "AF Locked!", Toast.LENGTH_SHORT).show();
                        }
                        break;
                }
            }

            @Override
            public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
                super.onCaptureCompleted(session, request, result);

                process(result);
            }
        };

private CameraCaptureSession mRecordCaptureSession;

private CameraCaptureSession.CaptureCallback mRecordCaptureCallback = new
        CameraCaptureSession.CaptureCallback() {

            private void process(CaptureResult captureResult) {
                switch (mCaptureState) {
                    case STATE_PREVIEW:
                        // Do nothing
                        break;
                    case STATE_WAIT_LOCK:
                        mCaptureState = STATE_PREVIEW;
                        Integer afState = captureResult.get(CaptureResult.CONTROL_AF_STATE);
                        if (afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED ||
                                afState == CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED) {
                            Toast.makeText(getApplicationContext(), "AF Locked!", Toast.LENGTH_SHORT).show();
                        }
                        break;
                }
            }

            @Override
            public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
                super.onCaptureCompleted(session, request, result);

                process(result);
            }
        };

private CaptureRequest.Builder mCaptureRequestBuilder;

private Button mRecordButton;
private boolean mIsRecording = false;
private boolean mIsTimelapse = false;

private File mVideoFolder;
private String mVideoFileName;

private MainModel mainModel;

private static SparseIntArray ORIENTATIONS = new SparseIntArray();

static {
    ORIENTATIONS.append(Surface.ROTATION_0, 0);
    ORIENTATIONS.append(Surface.ROTATION_90, 90);
    ORIENTATIONS.append(Surface.ROTATION_180, 180);
    ORIENTATIONS.append(Surface.ROTATION_270, 270);
}

private static class CompareSizeByArea implements Comparator<Size> {

    @Override
    public int compare(Size lhs, Size rhs) {
        return Long.signum((long) (lhs.getWidth() * lhs.getHeight()) -
                (long) (rhs.getWidth() * rhs.getHeight()));
    }
}

int questionId;
int questionAnswerTime;
String interviewId;
TextView showTimer;

private static String formatTime(int elapsed) {
    int ss = elapsed % 60;
    elapsed /= 60;
    int min = elapsed % 60;
    elapsed /= 60;
    int hh = elapsed % 24;
    return strzero(min) + ":" + strzero(ss);
}

private static String strzero(int n) {
    if (n < 10)
        return "0" + String.valueOf(n);
    return String.valueOf(n);
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_camera);

    Fabric.with(this, new Crashlytics());

    mainModel = (MainModel) getIntent().getSerializableExtra("serialized_data");

    interviewId = mainModel.getInterviewID();
    final ScriptQuestion getQuestion = mainModel.questions.get(0);
    questionId = getQuestion.getQuestionId();
    questionAnswerTime = getQuestion.getQuestionAnswerTime();

    showTimer = (TextView) findViewById(R.id.chronometer);
    mTextureView = (TextureView) findViewById(R.id.textureView);
    mRecordButton = (Button) findViewById(R.id.videoButton);

    mRecordButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            countDownTimer.cancel();
            mIsRecording = false;
            mIsTimelapse = false;

            // Starting the preview prior to stopping recording which should hopefully
            // resolve issues being seen in Samsung devices.

            startPreview();
            mMediaRecorder.stop();
            mMediaRecorder.reset();


            Intent mediaStoreUpdateIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
            mediaStoreUpdateIntent.setData(Uri.fromFile(new File(mVideoFileName)));
            sendBroadcast(mediaStoreUpdateIntent);

            goNext();
        }
    });

}

private CountDownTimer countDownTimer = new CountDownTimer(600000, 1000) {
    public void onTick(long millisUntilFinished) {
        // 600000 = 10 minutes
        int restTime = questionAnswerTime * 60 - (600 - ((int) (millisUntilFinished) / 1000));
        String tmpRest = formatTime(restTime);

        showTimer.setText(tmpRest);
        if (restTime < 1) {
            onFinish();
        }
    }

    public void onFinish() {
        mRecordButton.performClick();
    }
};

@Override
protected void onResume() {
    super.onResume();

    startBackgroundThread();

    if (mTextureView.isAvailable()) {
        setupCamera(mTextureView.getWidth(), mTextureView.getHeight());

    } else {
        mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
    }

    mIsRecording = true;

}

@Override
protected void onPause() {
    closeCamera();

    stopBackgroundThread();

    super.onPause();
}

@Override
public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);
    View decorView = getWindow().getDecorView();
    if (hasFocus) {
        decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
                | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                | View.SYSTEM_UI_FLAG_FULLSCREEN
                | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
    }
}

private void setupCamera(int width, int height) {
    CameraManager cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
    try {
        for (String cameraId : cameraManager.getCameraIdList()) {
            CameraCharacteristics cameraCharacteristics = cameraManager.getCameraCharacteristics(cameraId);
            if (cameraCharacteristics.get(CameraCharacteristics.LENS_FACING) ==
                    CameraCharacteristics.LENS_FACING_BACK) {
                continue;
            }
            StreamConfigurationMap map = cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
            int deviceOrientation = getWindowManager().getDefaultDisplay().getRotation();
            mTotalRotation = sensorToDeviceRotation(cameraCharacteristics, deviceOrientation);
            boolean swapRotation = mTotalRotation == 90 || mTotalRotation == 270;
            int rotatedWidth = width;
            int rotatedHeight = height;
            if (swapRotation) {
                rotatedWidth = height;
                rotatedHeight = width;
            }
            mPreviewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class), rotatedWidth, rotatedHeight);
            mVideoSize = chooseOptimalSize(map.getOutputSizes(MediaRecorder.class), rotatedWidth, rotatedHeight);

            mCameraId = cameraId;
            return;
        }
    } catch (CameraAccessException e) {
        e.printStackTrace();
    }
}

private void connectCamera() throws CameraAccessException {
    CameraManager cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
        return;
    }
    cameraManager.openCamera(mCameraId, mCameraDeviceStateCallback, mBackgroundHandler);
}

private void startRecord() {

    try {
        if(mIsRecording) {
            setupMediaRecorder();
        } else if(mIsTimelapse) {
            setupTimelapse();
        }
        SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture();
        surfaceTexture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
        Surface previewSurface = new Surface(surfaceTexture);
        Surface recordSurface = mMediaRecorder.getSurface();
        mCaptureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
        mCaptureRequestBuilder.addTarget(previewSurface);
        mCaptureRequestBuilder.addTarget(recordSurface);

        mCameraDevice.createCaptureSession(Arrays.asList(previewSurface, recordSurface),
                new CameraCaptureSession.StateCallback() {
                    @Override
                    public void onConfigured(CameraCaptureSession session) {
                        mRecordCaptureSession = session;
                        try {
                            mRecordCaptureSession.setRepeatingRequest(
                                    mCaptureRequestBuilder.build(), null, null
                            );
                        } catch (CameraAccessException e) {
                            e.printStackTrace();
                        }
                    }

                    @Override
                    public void onConfigureFailed(CameraCaptureSession session) {
                        //Log.d(TAG, "onConfigureFailed: startRecord");
                    }
                }, null);

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

private void startPreview() {

    SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture();
    assert surfaceTexture != null;
    surfaceTexture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
    Surface previewSurface = new Surface(surfaceTexture);

    try {
        mCaptureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
        mCaptureRequestBuilder.addTarget(previewSurface);

        mCameraDevice.createCaptureSession(Arrays.asList(previewSurface),
                new CameraCaptureSession.StateCallback() {
                    @Override
                    public void onConfigured(CameraCaptureSession session) {
                        //Log.d(TAG, "onConfigured: startPreview");
                        mPreviewCaptureSession = session;
                        try {
                            mPreviewCaptureSession.setRepeatingRequest(mCaptureRequestBuilder.build(),
                                    null, mBackgroundHandler);
                        } catch (CameraAccessException e) {
                            e.printStackTrace();
                        }
                    }

                    @Override
                    public void onConfigureFailed(CameraCaptureSession session) {
                        //Log.d(TAG, "onConfigureFailed: startPreview");

                    }
                }, null);
    } catch (CameraAccessException e) {
        e.printStackTrace();
    }
}

private void closeCamera() {
    if(mCameraDevice != null) {
        mCameraDevice.close();
        mCameraDevice = null;
    }
    if(mMediaRecorder != null) {
        mMediaRecorder.release();
        mMediaRecorder = null;
    }
}

private void startBackgroundThread() {
    mBackgroundHandlerThread = new HandlerThread("Camera2VideoImage");
    mBackgroundHandlerThread.start();
    mBackgroundHandler = new Handler(mBackgroundHandlerThread.getLooper());
}

private void stopBackgroundThread() {
    mBackgroundHandlerThread.quitSafely();
    try {
        mBackgroundHandlerThread.join();
        mBackgroundHandlerThread = null;
        mBackgroundHandler = null;
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

private static int sensorToDeviceRotation(CameraCharacteristics cameraCharacteristics, int deviceOrientation) {
    int sensorOrienatation = cameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
    deviceOrientation = ORIENTATIONS.get(deviceOrientation);
    return (sensorOrienatation + deviceOrientation + 360) % 360;
}

private static Size chooseOptimalSize(Size[] choices, int width, int height) {
    List<Size> bigEnough = new ArrayList<Size>();
    for(Size option : choices) {
        if(option.getHeight() == option.getWidth() * height / width &&
                option.getWidth() >= width && option.getHeight() >= height) {
            bigEnough.add(option);
        }
    }
    if(bigEnough.size() > 0) {
        return Collections.min(bigEnough, new CompareSizeByArea());
    } else {
        return choices[0];
    }
}

private File createVideoFileName() throws IOException {

    File mediaStorageDir = new File(Environment.getExternalStorageDirectory(), "JobConvoVideos");
    mVideoFolder = new File(mediaStorageDir, "JobConvoVideos");
    if(!mVideoFolder.exists()) {
        mVideoFolder.mkdirs();
    }

    String prepend = "android-" + interviewId + "-" + String.valueOf(questionId) + ".mp4";
    File videoFile = new File(mediaStorageDir.getPath() + File.separator + prepend);
    mVideoFileName = videoFile.getAbsolutePath();

    return videoFile;
}

public static File getOutputMediaFile(String _interviewId, int qstId, Context _context){

    String idInterview = _interviewId;
    idInterview =  "android-" + idInterview + "-" + String.valueOf(qstId) + ".mp4";

    File mediaStorageDir = new File(Environment.getExternalStorageDirectory(), "JobConvoVideos");
    _context.getExternalFilesDir("JobConvoVideos");
    File f = new File(mediaStorageDir.getPath() + File.separator + idInterview);
    return f;
}

private void setupMediaRecorder() throws IOException {
    mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
    mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
    mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
    mMediaRecorder.setOutputFile(mVideoFileName);
    mMediaRecorder.setVideoEncodingBitRate(1000000);
    mMediaRecorder.setVideoFrameRate(30);
    mMediaRecorder.setVideoSize(mVideoSize.getWidth(), mVideoSize.getHeight());
    mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP);
    mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
    mMediaRecorder.setOrientationHint(mTotalRotation);
    mMediaRecorder.getMaxAmplitude();
    mMediaRecorder.prepare();
}

private void setupTimelapse() throws IOException {
    mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
    mMediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_QVGA));
    mMediaRecorder.setOutputFile(mVideoFileName);
    mMediaRecorder.setCaptureRate(2);
    mMediaRecorder.setOrientationHint(mTotalRotation);
    mMediaRecorder.prepare();
}


private void goNext() {

    finish();

    Intent goUpload = new Intent(this, VideoUploadActivity.class);
    goUpload.putExtra("serialized_data", mainModel);
    startActivity(goUpload);

}

@Override
public void onBackPressed() {
    Toast.makeText(getApplicationContext(), R.string.getBack, Toast.LENGTH_LONG).show();
}

}

1 个答案:

答案 0 :(得分:0)

I added a try catch here in which the app has shown a great improvement. Nonetheless it still crashes sometimes. Not very often.

 <input id="inputfield1">
    <input id="inputfield2">
相关问题