title: Recording video on Android using JavaCV (Updated 2014 02 17)
body: <p>I'm trying to record a video in Android using the JavaCV lib.
  I need to record the video in 640x360.</p>
  
  <p>I have installed everything as described in README.txt file and I followed the example as below:
  <a href="https://code.google.com/p/javacv/source/browse/samples/RecordActivity.java" rel="nofollow">https://code.google.com/p/javacv/source/browse/samples/RecordActivity.java</a>
  In this example, the video size is this:
  private int imageWidth = 320;
  private int imageHeight = 240;</p>
  
  <p>In my case, I need to record a video in 640x360 H.264.</p>
  
  <p>(UPDATE) I have reverted my code and kept exactly like in the example, just changing imageWidth and imageHeight to 640x360.
  Now I'm getting the video like this image:
  <a href="http://bergmann.net.br/img/screenshot_video_error.png" rel="nofollow">http://bergmann.net.br/img/screenshot_video_error.png</a></p>
  
  <p>Here is my code:</p>
  
  <pre><code>import static com.googlecode.javacv.cpp.opencv_core.IPL_DEPTH_8U;
  
  import java.io.IOException;
  import java.nio.ShortBuffer;
  
  import android.app.Activity;
  import android.content.Context;
  import android.content.pm.ActivityInfo;
  import android.hardware.Camera;
  import android.hardware.Camera.PreviewCallback;
  import android.media.AudioFormat;
  import android.media.AudioRecord;
  import android.media.MediaRecorder;
  import android.os.Bundle;
  import android.os.PowerManager;
  import android.util.Log;
  import android.view.Display;
  import android.view.KeyEvent;
  import android.view.LayoutInflater;
  import android.view.SurfaceHolder;
  import android.view.SurfaceView;
  import android.view.View;
  import android.view.View.OnClickListener;
  import android.view.WindowManager;
  import android.widget.Button;
  import android.widget.LinearLayout;
  import android.widget.RelativeLayout;
  
  import com.autosonvideo.helpers.Helpers;
  import com.autosonvideo.logic.CameraHelpers;
  import com.googlecode.javacv.FFmpegFrameRecorder;
  import com.googlecode.javacv.cpp.opencv_core.IplImage;
  
  public class FFmpegRecordActivity extends Activity implements OnClickListener {
  
      private final static String CLASS_LABEL = "RecordActivity";
      private final static String LOG_TAG = CLASS_LABEL;
  
      private PowerManager.WakeLock mWakeLock;
  
      private String ffmpeg_link;
  
      long startTime = 0;
      boolean recording = false;
  
      private volatile FFmpegFrameRecorder recorder;
  
      private boolean isPreviewOn = false;
  
      private int sampleAudioRateInHz = 44100;
      private int imageWidth = 640;
      private int imageHeight = 480;
  
      private int finalImageWidth = 640;
      private int finalImageHeight = 360;
  
      private int frameRate = 30;
  
      /* audio data getting thread */
      private AudioRecord audioRecord;
      private AudioRecordRunnable audioRecordRunnable;
      private Thread audioThread;
      volatile boolean runAudioThread = true;
  
      /* video data getting thread */
      private Camera cameraDevice;
      private CameraView cameraView;
  
      private IplImage yuvIplimage = null;
  
      /* layout setting */
      private final int bg_screen_bx = 232;
      private final int bg_screen_by = 128;
      private final int bg_screen_width = 700;
      private final int bg_screen_height = 500;
      private final int bg_width = 1123;
      private final int bg_height = 715;
      private final int live_width = 1280;
      private final int live_height = 960;
      private int screenWidth, screenHeight;
      private Button btnRecorderControl;
  
      @Override
      public void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
  
          setContentView(R.layout.main);
  
          PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
          mWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
                  CLASS_LABEL);
          mWakeLock.acquire();
  
          initLayout();
          initRecorder();
      }
  
      @Override
      protected void onResume() {
          super.onResume();
  
          if (mWakeLock == null) {
              PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
              mWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
                      CLASS_LABEL);
              mWakeLock.acquire();
          }
      }
  
      @Override
      protected void onPause() {
          super.onPause();
  
          if (mWakeLock != null) {
              mWakeLock.release();
              mWakeLock = null;
          }
      }
  
      @Override
      protected void onDestroy() {
          super.onDestroy();
  
          recording = false;
  
          if (cameraView != null) {
              cameraView.stopPreview();
              cameraDevice.release();
              cameraDevice = null;
          }
  
          if (mWakeLock != null) {
              mWakeLock.release();
              mWakeLock = null;
          }
      }
  
      private void initLayout() {
  
          /* get size of screen */
          Display display = ((WindowManager) getSystemService(Context.WINDOW_SERVICE))
                  .getDefaultDisplay();
          screenWidth = display.getWidth();
          screenHeight = display.getHeight();
          RelativeLayout.LayoutParams layoutParam = null;
          LayoutInflater myInflate = null;
          myInflate = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
          RelativeLayout topLayout = new RelativeLayout(this);
          setContentView(topLayout);
          LinearLayout preViewLayout = (LinearLayout) myInflate.inflate(
                  R.layout.main, null);
          layoutParam = new RelativeLayout.LayoutParams(screenWidth, screenHeight);
          topLayout.addView(preViewLayout, layoutParam);
  
          /* add control button: start and stop */
          btnRecorderControl = (Button) findViewById(R.id.recorder_control);
          btnRecorderControl.setText("Start");
          btnRecorderControl.setOnClickListener(this);
  
          /* add camera view */
          int display_width_d = (int) (1.0 * bg_screen_width * screenWidth / bg_width);
          int display_height_d = (int) (1.0 * bg_screen_height * screenHeight / bg_height);
          int prev_rw, prev_rh;
          if (1.0 * display_width_d / display_height_d &gt; 1.0 * live_width
                  / live_height) {
              prev_rh = display_height_d;
              prev_rw = (int) (1.0 * display_height_d * live_width / live_height);
          } else {
              prev_rw = display_width_d;
              prev_rh = (int) (1.0 * display_width_d * live_height / live_width);
          }
          layoutParam = new RelativeLayout.LayoutParams(prev_rw, prev_rh);
          layoutParam.topMargin = (int) (1.0 * bg_screen_by * screenHeight / bg_height);
          layoutParam.leftMargin = (int) (1.0 * bg_screen_bx * screenWidth / bg_width);
  
          cameraDevice = Camera.open();
          Log.i(LOG_TAG, "cameara open");
          cameraView = new CameraView(this, cameraDevice);
          topLayout.addView(cameraView, layoutParam);
          Log.i(LOG_TAG, "cameara preview start: OK");
      }
  
      // ---------------------------------------
      // initialize ffmpeg_recorder
      // ---------------------------------------
      private void initRecorder() {
  
          Log.w(LOG_TAG, "init recorder");
  
          if (yuvIplimage == null) {
              yuvIplimage = IplImage.create(finalImageWidth, finalImageHeight,
                      IPL_DEPTH_8U, 2);
              Log.i(LOG_TAG, "create yuvIplimage");
          }
  
          ffmpeg_link = CameraHelpers.getOutputMediaFile(
                  CameraHelpers.MEDIA_TYPE_VIDEO).toString();
  
          Log.i(LOG_TAG, "ffmpeg_url: " + ffmpeg_link);
          recorder = new FFmpegFrameRecorder(ffmpeg_link, finalImageWidth,
                  finalImageHeight, 1);
          recorder.setFormat("mp4");
          recorder.setSampleRate(sampleAudioRateInHz);
          // Set in the surface changed method
          recorder.setFrameRate(frameRate);
  
          Log.i(LOG_TAG, "recorder initialize success");
  
          audioRecordRunnable = new AudioRecordRunnable();
          audioThread = new Thread(audioRecordRunnable);
      }
  
      public void startRecording() {
  
          try {
              recorder.start();
              startTime = System.currentTimeMillis();
              recording = true;
              audioThread.start();
  
          } catch (FFmpegFrameRecorder.Exception e) {
              e.printStackTrace();
          }
      }
  
      public void stopRecording() {
  
          runAudioThread = false;
  
          if (recorder != null &amp;&amp; recording) {
              recording = false;
              Log.v(LOG_TAG,
                      "Finishing recording, calling stop and release on recorder");
              try {
                  recorder.stop();
                  recorder.release();
              } catch (FFmpegFrameRecorder.Exception e) {
                  e.printStackTrace();
              }
              recorder = null;
  
          }
      }
  
      @Override
      public boolean onKeyDown(int keyCode, KeyEvent event) {
  
          if (keyCode == KeyEvent.KEYCODE_BACK) {
              if (recording) {
                  stopRecording();
              }
  
              finish();
  
              return true;
          }
  
          return super.onKeyDown(keyCode, event);
      }
  
      // ---------------------------------------------
      // audio thread, gets and encodes audio data
      // ---------------------------------------------
      class AudioRecordRunnable implements Runnable {
  
          @Override
          public void run() {
              android.os.Process
                      .setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
  
              // Audio
              int bufferSize;
              short[] audioData;
              int bufferReadResult;
  
              bufferSize = AudioRecord
                      .getMinBufferSize(sampleAudioRateInHz,
                              AudioFormat.CHANNEL_IN_MONO,
                              AudioFormat.ENCODING_PCM_16BIT);
              audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC,
                      sampleAudioRateInHz, AudioFormat.CHANNEL_IN_MONO,
                      AudioFormat.ENCODING_PCM_16BIT, bufferSize);
  
              audioData = new short[bufferSize];
  
              Log.d(LOG_TAG, "audioRecord.startRecording()");
              audioRecord.startRecording();
  
              /* ffmpeg_audio encoding loop */
              while (runAudioThread) {
                  // Log.v(LOG_TAG,"recording? " + recording);
                  bufferReadResult = audioRecord.read(audioData, 0,
                          audioData.length);
                  if (bufferReadResult &gt; 0) {
                      Log.v(LOG_TAG, "bufferReadResult: " + bufferReadResult);
                      // If "recording" isn't true when start this thread, it
                      // never get's set according to this if statement...!!!
                      // Why? Good question...
                      if (recording) {
                          try {
                              recorder.record(ShortBuffer.wrap(audioData, 0,
                                      bufferReadResult));
                              // Log.v(LOG_TAG,"recording " + 1024*i + " to " +
                              // 1024*i+1024);
                          } catch (FFmpegFrameRecorder.Exception e) {
                              Log.v(LOG_TAG, e.getMessage());
                              e.printStackTrace();
                          }
                      }
                  }
              }
              Log.v(LOG_TAG, "AudioThread Finished, release audioRecord");
  
              /* encoding finish, release recorder */
              if (audioRecord != null) {
                  audioRecord.stop();
                  audioRecord.release();
                  audioRecord = null;
                  Log.v(LOG_TAG, "audioRecord released");
              }
          }
      }
  
      // ---------------------------------------------
      // camera thread, gets and encodes video data
      // ---------------------------------------------
      class CameraView extends SurfaceView implements SurfaceHolder.Callback,
              PreviewCallback {
  
          private SurfaceHolder mHolder;
          private Camera mCamera;
  
          public CameraView(Context context, Camera camera) {
              super(context);
              Log.w("camera", "camera view");
              mCamera = camera;
              mHolder = getHolder();
              mHolder.addCallback(CameraView.this);
              mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
              mCamera.setPreviewCallback(CameraView.this);
          }
  
          @Override
          public void surfaceCreated(SurfaceHolder holder) {
              try {
                  stopPreview();
                  mCamera.setPreviewDisplay(holder);
              } catch (IOException exception) {
                  mCamera.release();
                  mCamera = null;
              }
          }
  
          public void surfaceChanged(SurfaceHolder holder, int format, int width,
                  int height) {
              Log.v(LOG_TAG, "Setting imageWidth: " + imageWidth
                      + " imageHeight: " + imageHeight + " frameRate: "
                      + frameRate);
              Camera.Parameters camParams = mCamera.getParameters();
              camParams.setPreviewSize(imageWidth, imageHeight);
  
              Log.v(LOG_TAG,
                      "Preview Framerate: " + camParams.getPreviewFrameRate());
  
              camParams.setPreviewFrameRate(frameRate);
              mCamera.setParameters(camParams);
              startPreview();
          }
  
          @Override
          public void surfaceDestroyed(SurfaceHolder holder) {
              try {
                  mHolder.addCallback(null);
                  mCamera.setPreviewCallback(null);
              } catch (RuntimeException e) {
                  // The camera has probably just been released, ignore.
              }
          }
  
          public void startPreview() {
              if (!isPreviewOn &amp;&amp; mCamera != null) {
                  isPreviewOn = true;
                  mCamera.startPreview();
              }
          }
  
          public void stopPreview() {
              if (isPreviewOn &amp;&amp; mCamera != null) {
                  isPreviewOn = false;
                  mCamera.stopPreview();
              }
          }
  
          @Override
          public void onPreviewFrame(byte[] data, Camera camera) {
              /* get video data */
              if (yuvIplimage != null &amp;&amp; recording) {
                  // yuvIplimage.getByteBuffer().put(data);
  
                  final int startY = 640 * (480 - 360) / 2;
                  final int lenY = 640 * 360;
                  yuvIplimage.getByteBuffer().put(data, startY, lenY);
                  final int startVU = 640 * 480 + 320 * 2 * (240 - 180) / 2;
                  final int lenVU = 320 * 180 * 2;
                  yuvIplimage.getByteBuffer().put(data, startVU, lenVU);
  
                  Log.v(LOG_TAG, "Writing Frame");
                  try {
                      long t = 1000 * (System.currentTimeMillis() - startTime);
                      if (t &gt; recorder.getTimestamp()) {
                          recorder.setTimestamp(t);
                      }
                      recorder.record(yuvIplimage);
                  } catch (FFmpegFrameRecorder.Exception e) {
                      Log.v(LOG_TAG, e.getMessage());
                      e.printStackTrace();
                  }
              }
          }
      }
  
      @Override
      public void onClick(View v) {
          if (!recording) {
              startRecording();
              Log.w(LOG_TAG, "Start Button Pushed");
              btnRecorderControl.setText("Stop");
          } else {
              // This will trigger the audio recording loop to stop and then set
              // isRecorderStart = false;
              stopRecording();
              Log.w(LOG_TAG, "Stop Button Pushed");
              btnRecorderControl.setText("Start");
          }
      }
  }
  </code></pre>