title: Unable to record video and take frames from onPreviewFrame callback at the same time
body: <p>I am recording video in my Android application using <code>MediaRecorder</code> and I also want frame data through the <code>onPreviewFrame</code> callback.</p>
  
  <p><strong>The issue is:</strong> If preview is restarted in <code>surfaceChanged</code> callback then video recording stops working. If it is not restarted, by commenting everything inside <code>surfaceChanged</code>, then video recording keeps working but the <code>onPreviewFrame</code> callback stops working.</p>
  
  <p>How can I make both of them work?</p>
  
  <p>CameraActivity.java</p>
  
  <pre><code>import android.app.Activity;
  import android.hardware.Camera;
  import android.media.MediaRecorder;
  import android.os.Bundle;
  import android.os.Environment;
  import android.util.Log;
  import android.view.SurfaceHolder;
  import android.view.SurfaceView;
  import android.view.View;
  import android.widget.Button;
  import android.widget.Toast;
  
  import java.io.File;
  import java.io.FileNotFoundException;
  import java.io.FileOutputStream;
  import java.io.IOException;
  import java.text.SimpleDateFormat;
  import java.util.Date;
  
  public class CameraActivity extends Activity implements SurfaceHolder.Callback, Camera.PreviewCallback {
      private static final String TAG = "CameraActivity";
  
      public static final int MEDIA_TYPE_IMAGE = 1;
      public static final int MEDIA_TYPE_VIDEO = 2;
  
      private Camera mCamera;
      private SurfaceView mPreview;
      private SurfaceHolder mHolder;
      private MediaRecorder mMediaRecorder;
      private boolean isRecording = false;
  
      @Override
      public void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.activity_camera);
  
          // Create an instance of Camera
          mCamera = getCameraInstance();
  
          if (mCamera != null) {
              // Create our Preview view and set it as the content of our activity.
              mPreview = (SurfaceView) findViewById(R.id.camera_preview);
              // Install a SurfaceHolder.Callback so we get notified when the
              // underlying surface is created and destroyed.
              mHolder = mPreview.getHolder();
              mHolder.addCallback(this);
          }
  
          startLockTask();
      }
  
      public void surfaceCreated(SurfaceHolder holder) {
          // The Surface has been created, now tell the camera where to draw the preview.
          try {
              mCamera.setPreviewCallback(this);
              mCamera.setPreviewDisplay(holder);
              mCamera.startPreview();
  
              prepareMediaRecorder();
              startVideoRecording();
          } catch (IOException e) {
              Log.d(TAG, "Error setting camera preview: " + e.getMessage());
          }
      }
  
      public void surfaceDestroyed(SurfaceHolder holder) {
          // empty. Take care of releasing the Camera preview in your activity.
      }
  
      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) {
              // 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
          }
  
          // set preview size and make any resize, rotate or
          // reformatting changes here
  
          // start preview with new settings
          try {
              mCamera.setPreviewCallback(this);
              mCamera.setPreviewDisplay(mHolder);
              mCamera.startPreview();
          } catch (Exception e){
              Log.d(TAG, "Error starting camera preview: " + e.getMessage());
          }
      }
  
      @Override
      public void onPreviewFrame(byte[] bytes, Camera camera) {
  
      }
  
      private boolean prepareMediaRecorder() {
          mMediaRecorder = new MediaRecorder();
  
          mMediaRecorder.setOnErrorListener(new MediaRecorder.OnErrorListener() {
              @Override
              public void onError(MediaRecorder mediaRecorder, int what, int extra) {
                  Log.e(TAG, "Media recorder error");
              }
          });
  
          mMediaRecorder.setOnInfoListener(new MediaRecorder.OnInfoListener() {
              @Override
              public void onInfo(MediaRecorder mr, int what, int extra) {
                  if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) {
                      stopVideoRecording();
                      releaseMediaRecorder();
                      prepareMediaRecorder();
                      startVideoRecording();
                  }
              }
          });
  
          // Step 1: Unlock and set camera to MediaRecorder
          mCamera.unlock();
          mMediaRecorder.setCamera(mCamera);
  
          // Step 2: Set sources
          //mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
          mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
  
          // Step 3: Set a CamcorderProfile (requires API Level 8 or higher)
  //        mMediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_LOW));
  
          mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
          mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP);
          mMediaRecorder.setVideoFrameRate(3);
          mMediaRecorder.setVideoEncodingBitRate(6000000);
          mMediaRecorder.setVideoSize(800, 480);
          mMediaRecorder.setMaxDuration(60000);
  
          // Step 4: Set output file
          mMediaRecorder.setOutputFile(getOutputMediaFile(MEDIA_TYPE_VIDEO).toString());
  
          // Step 5: Set the preview output
  //        mMediaRecorder.setPreviewDisplay(mPreview.getHolder().getSurface());
  
          // Step 6: Prepare configured MediaRecorder
          try {
              mMediaRecorder.prepare();
          } catch (IllegalStateException e) {
              Log.d(TAG, "IllegalStateException preparing MediaRecorder: " + e.getMessage());
              releaseMediaRecorder();
              return false;
          } catch (IOException e) {
              Log.d(TAG, "IOException preparing MediaRecorder: " + e.getMessage());
              releaseMediaRecorder();
              return false;
          }
          return true;
      }
  
      private void startVideoRecording() {
          mMediaRecorder.start();
          isRecording = true;
      }
  
      private void stopVideoRecording() {
          // stop recording and release camera
          mMediaRecorder.stop();  // stop the recording
          isRecording = false;
      }
  
      /** A safe way to get an instance of the Camera object. */
      public static Camera getCameraInstance(){
          Camera c = null;
          try {
              c = Camera.open(); // attempt to get a Camera instance
          }
          catch (Exception e){
              // Camera is not available (in use or does not exist)
          }
          return c; // returns null if camera is unavailable
      }
  
      @Override
      protected void onDestroy() {
          super.onDestroy();
          releaseMediaRecorder();       // if you are using MediaRecorder, release it first
          releaseCamera();              // release the camera immediately on pause event
      }
  
      private void releaseMediaRecorder(){
          if (mMediaRecorder != null) {
              mMediaRecorder.reset();   // clear recorder configuration
              mMediaRecorder.release(); // release the recorder object
              mMediaRecorder = null;
              mCamera.lock();           // lock camera for later use
          }
      }
  
      private void releaseCamera(){
          if (mCamera != null){
              mCamera.release();        // release the camera for other applications
              mCamera = null;
          }
      }
  
      /** Create a File for saving an image or video */
      private static File getOutputMediaFile(int type){
          // To be safe, you should check that the SDCard is mounted
          // using Environment.getExternalStorageState() before doing this.
  
          File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
                  Environment.DIRECTORY_PICTURES), "MyCameraApp");
          // This location works best if you want the created images to be shared
          // between applications and persist after your app has been uninstalled.
  
          // Create the storage directory if it does not exist
          if (! mediaStorageDir.exists()){
              if (! mediaStorageDir.mkdirs()){
                  Log.d("MyCameraApp", "failed to create directory");
                  return null;
              }
          }
  
          // Create a media file name
          String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
          File mediaFile;
          if (type == MEDIA_TYPE_IMAGE){
              mediaFile = new File(mediaStorageDir.getPath() + File.separator +
                      "IMG_"+ timeStamp + ".jpg");
          } else if(type == MEDIA_TYPE_VIDEO) {
              mediaFile = new File(mediaStorageDir.getPath() + File.separator +
                      "VID_"+ timeStamp + ".mp4");
          } else {
              return null;
          }
  
          return mediaFile;
      }
  }
  </code></pre>
  
  <p>activity_camera.xml</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="utf-8"?&gt;
  &lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
      android:orientation="horizontal"
      android:layout_width="fill_parent"
      android:layout_height="fill_parent"
      &gt;
      &lt;SurfaceView
          android:id="@+id/camera_preview"
          android:layout_width="fill_parent"
          android:layout_height="fill_parent"
          android:layout_weight="1"
          /&gt;
  &lt;/LinearLayout&gt;
  </code></pre>