2017-07-08 116 views
0

我是新来的Java和Android。我试图在不执行按钮点击的情况下开始录制视频。但是我得到一个错误。Android Camera2无法启动活动自动记录视频

我试图使用方法startCapture(),但它失败。什么可能是错误的?

错误:

java.lang.NullPointerException: Attempt to invoke virtual method 'void android.media.MediaRecorder.start()' on a null object reference

的活动:

public class CameraActivity extends AppCompatActivity { 

    private static final String TAG = "CameraAction"; 

    private static final int REQUEST_CAMERA_PERMISSION_RESULT = 0; 
    private static final int REQUEST_WRITE_EXTERNAL_STORAGE_PERMISSION_RESULT = 1; 
    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); 
      connectCamera(); 
     } 

     @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() { 
         mChronometer.setBase(SystemClock.elapsedRealtime()); 
         mChronometer.setVisibility(View.VISIBLE); 
         mChronometer.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 Chronometer mChronometer; 
    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())); 
     } 
    } 

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

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

     createVideoFolder(); 

     mChronometer = (Chronometer) 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) { 
       if (mIsRecording || mIsTimelapse) { 
        mChronometer.stop(); 
        mChronometer.setVisibility(View.INVISIBLE); 
        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(); 

       } else { 
        mIsRecording = true; 
        checkWriteStoragePermission(); 
       } 
      } 
     }); 

     /* 
     mRecordButton.setOnLongClickListener(new View.OnLongClickListener() { 
      @Override 
      public boolean onLongClick(View v) { 
       mIsTimelapse =true; 
       checkWriteStoragePermission(); 
       return true; 
      } 
     }); 
     */ 

    } 


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

     startBackgroundThread(); 

     if(mTextureView.isAvailable()) { 
      setupCamera(mTextureView.getWidth(), mTextureView.getHeight()); 
      connectCamera(); 
     } else { 
      mTextureView.setSurfaceTextureListener(mSurfaceTextureListener); 
     } 

     startCapture(); 
    } 

    @Override 
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { 
     super.onRequestPermissionsResult(requestCode, permissions, grantResults); 
     if(requestCode == REQUEST_CAMERA_PERMISSION_RESULT) { 
      if(grantResults[0] != PackageManager.PERMISSION_GRANTED) { 
       Toast.makeText(getApplicationContext(), 
         "Application will not run without camera services", Toast.LENGTH_SHORT).show(); 
      } 
      if(grantResults[1] != PackageManager.PERMISSION_GRANTED) { 
       Toast.makeText(getApplicationContext(), 
         "Application will not have audio on record", Toast.LENGTH_SHORT).show(); 
      } 
     } 
     if(requestCode == REQUEST_WRITE_EXTERNAL_STORAGE_PERMISSION_RESULT) { 
      if(grantResults[0] == PackageManager.PERMISSION_GRANTED) { 
       if(mIsRecording || mIsTimelapse) { 
        mIsRecording = true; 
       } 
       Toast.makeText(this, 
         "Permission successfully granted!", Toast.LENGTH_SHORT).show(); 
      } else { 
       Toast.makeText(this, 
         "App needs to save video to run", Toast.LENGTH_SHORT).show(); 
      } 
     } 
    } 

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

     stopBackgroundThread(); 

     super.onPause(); 
    } 

    @Override 
    public void onWindowFocusChanged(boolean hasFocas) { 
     super.onWindowFocusChanged(hasFocas); 
     View decorView = getWindow().getDecorView(); 
     if(hasFocas) { 
      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 startCapture() { 

     mIsRecording = true; 
     checkWriteStoragePermission(); 

    } 

    private void connectCamera() { 
     CameraManager cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); 
     try { 
      if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 
       if(ContextCompat.checkSelfPermission(this, android.Manifest.permission.CAMERA) == 
         PackageManager.PERMISSION_GRANTED) { 
        cameraManager.openCamera(mCameraId, mCameraDeviceStateCallback, mBackgroundHandler); 
       } else { 
        if(shouldShowRequestPermissionRationale(android.Manifest.permission.CAMERA)) { 
         Toast.makeText(this, 
           "Video app required access to camera", Toast.LENGTH_SHORT).show(); 
        } 
        requestPermissions(new String[] {android.Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO 
        }, REQUEST_CAMERA_PERMISSION_RESULT); 
       } 

      } else { 
       cameraManager.openCamera(mCameraId, mCameraDeviceStateCallback, mBackgroundHandler); 
      } 
     } catch (CameraAccessException e) { 
      e.printStackTrace(); 
     } 
    } 

    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(); 
     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 void createVideoFolder() { 
     File movieFile = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES); 
     mVideoFolder = new File(movieFile, "JobConvoVideos"); 
     if(!mVideoFolder.exists()) { 
      mVideoFolder.mkdirs(); 
     } 
    } 

    private File createVideoFileName() throws IOException { 
     String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); 
     String prepend = "VIDEO_" + timestamp + "_"; 
     File videoFile = File.createTempFile(prepend, ".mp4", mVideoFolder); 
     mVideoFileName = videoFile.getAbsolutePath(); 
     return videoFile; 
    } 

    private void checkWriteStoragePermission() { 
     if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 
      if(ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) 
        == PackageManager.PERMISSION_GRANTED) { 
       try { 
        createVideoFileName(); 
       } catch (IOException e) { 
        e.printStackTrace(); 
       } 
       if(mIsTimelapse || mIsRecording) { 
        startRecord(); 
        mMediaRecorder.start(); 
        mChronometer.setBase(SystemClock.elapsedRealtime()); 
        mChronometer.setVisibility(View.VISIBLE); 
        mChronometer.start(); 
       } 
      } else { 
       if(shouldShowRequestPermissionRationale(Manifest.permission.WRITE_EXTERNAL_STORAGE)) { 
        Toast.makeText(this, "app needs to be able to save videos", Toast.LENGTH_SHORT).show(); 
       } 
       requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_WRITE_EXTERNAL_STORAGE_PERMISSION_RESULT); 
      } 
     } else { 
      try { 
       createVideoFileName(); 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 
      if(mIsRecording || mIsTimelapse) { 
       startRecord(); 
       mMediaRecorder.start(); 
       mChronometer.setBase(SystemClock.elapsedRealtime()); 
       mChronometer.setVisibility(View.VISIBLE); 
       mChronometer.start(); 
      } 
     } 
    } 

    private void setupMediaRecorder() throws IOException { 
     mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE); 
     mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); 
     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.H264); 
     mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC); 
     mMediaRecorder.setOrientationHint(mTotalRotation); 
     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() { 

     mainModel.questions.remove(0); 

     if (mainModel.questions.isEmpty()) 
     { 
      //END 
      Intent endSuccess = new Intent(this, SuccessActivity.class); 
      endSuccess.putExtra("serialized_data", mainModel); 
      startActivity(endSuccess); 
     } 
     else{ 

      Intent goToInterview = new Intent(this, InterviewActivity.class); 
      goToInterview.putExtra("serialized_data", mainModel); 
      startActivity(goToInterview); 

     } 

    } 

} 

回答

0

我能够通过简单地在onCreate方法的末尾添加该线,使其:mIsRecording = TRUE;

代码

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

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

    createVideoFolder(); 

    mChronometer = (Chronometer) 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) { 
      if (mIsRecording || mIsTimelapse) { 
       mChronometer.stop(); 
       mChronometer.setVisibility(View.INVISIBLE); 
       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(); 

      } else { 
       mIsRecording = true; 
       checkWriteStoragePermission(); 
      } 
     } 
    }); 
    mIsRecording = true; 

}