title: Android studio + OpenCV + FFmpeg
body: <p>I have problem with code, which is functional only for Genymotion device (Android 4.1.1), but for Genymotion device 5.0.1 and real device Huawei honor 4c Android 4.4.2 not.</p>
  
  <p>I have imported OpenCV 3.1 to Android studio by: <a href="https://stackoverflow.com/a/27421494/4244605">https://stackoverflow.com/a/27421494/4244605</a><br>
  I added JavaCV with FFmpeg by: <a href="https://github.com/bytedeco/javacv" rel="nofollow noreferrer">https://github.com/bytedeco/javacv</a></p>
  
  <p>Android studio 1.5.1<br>
  minSdkVersion 15<br>
  compileSdkVersion 23</p>
  
  <p>Code is only for test.<br>
  <strong>OpenCVCameraActivity.java:</strong></p>
  
  <pre><code>import android.app.Activity;
  import android.hardware.Camera;
  import android.media.AudioFormat;
  import android.media.AudioRecord;
  import android.media.MediaRecorder;
  import android.os.Bundle;
  import android.os.Environment;
  import android.util.Log;
  import android.view.Menu;
  import android.view.MenuItem;
  import android.view.MotionEvent;
  import android.view.SubMenu;
  import android.view.SurfaceView;
  import android.view.View;
  import android.view.WindowManager;
  import android.widget.Toast;
  
  import org.bytedeco.javacv.FFmpegFrameRecorder;
  import org.bytedeco.javacv.Frame;
  import org.opencv.android.BaseLoaderCallback;
  import org.opencv.android.CameraBridgeViewBase;
  import org.opencv.android.LoaderCallbackInterface;
  import org.opencv.android.OpenCVLoader;
  import org.opencv.core.Mat;
  
  import java.io.File;
  import java.nio.ShortBuffer;
  import java.text.SimpleDateFormat;
  import java.util.Date;
  import java.util.List;
  import java.util.ListIterator;
  
  @SuppressWarnings("ALL")
  public class OpenCVCameraActivity extends Activity implements
          CameraBridgeViewBase.CvCameraViewListener2,
          View.OnTouchListener {
  
      //name of activity, for DEBUGGING
      private static final String TAG = OpenCVCameraActivity.class.getSimpleName();
  
      private OpenCVCameraPreview mOpenCvCameraView;
      private List&lt;Camera.Size&gt; mResolutionList;
      private MenuItem[] mEffectMenuItems;
      private SubMenu mColorEffectsMenu;
      private MenuItem[] mResolutionMenuItems;
      private SubMenu mResolutionMenu;
  
      private static long frameCounter = 0;
  
      long startTime = 0;
      private Mat edgesMat;
      boolean recording = false;
      private int sampleAudioRateInHz = 44100;
      private int imageWidth = 1920;
      private int imageHeight = 1080;
      private int frameRate = 30;
      private Frame yuvImage = null;
      private File ffmpeg_link;
      private FFmpegFrameRecorder recorder;
  
      /* audio data getting thread */
      private AudioRecord audioRecord;
      private AudioRecordRunnable audioRecordRunnable;
      private Thread audioThread;
      volatile boolean runAudioThread = true;
      ShortBuffer[] samples;
  
  
      private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
          @Override
          public void onManagerConnected(int status) {
              switch (status) {
                  case LoaderCallbackInterface.SUCCESS:
                      Log.i(TAG, "OpenCV loaded successfully");
                      mOpenCvCameraView.enableView();
                      mOpenCvCameraView.setOnTouchListener(OpenCVCameraActivity.this);
                  break;
                  default:
                      super.onManagerConnected(status);
                  break;
              }
          }
      };
  
      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          if(Static.DEBUG) Log.i(TAG, "onCreate()");
  
          getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
  
          try {
              setContentView(R.layout.activity_opencv);
  
              mOpenCvCameraView = (OpenCVCameraPreview) findViewById(R.id.openCVCameraPreview);
              mOpenCvCameraView.setVisibility(SurfaceView.VISIBLE);
              mOpenCvCameraView.setCvCameraViewListener(this);
  
              //mOpenCvCameraView.enableFpsMeter();
  
              ffmpeg_link = new File(Environment.getExternalStorageDirectory(), "stream.mp4");
          } catch (Exception e){
              e.printStackTrace();
          }
      }
  
      @Override
      protected void onRestart() {
          if (Static.DEBUG) Log.i(TAG, "onRestart()");
          super.onRestart();
      }
  
      @Override
      protected void onStart() {
          if (Static.DEBUG) Log.i(TAG, "onStart()");
          super.onStart();
      }
  
      @Override
      protected void onResume() {
          if (Static.DEBUG) Log.i(TAG, "onResume()");
          super.onResume();
  
          if (!OpenCVLoader.initDebug()) {
              Log.i(TAG, "Internal OpenCV library not found. Using OpenCV Manager for initialization");
              OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_11, this, mLoaderCallback);
          } else {
              Log.i(TAG, "OpenCV library found inside package. Using it!");
              mLoaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS);
          }
  
      }
  
      @Override
      public boolean onCreateOptionsMenu(Menu menu) {
          if (Static.DEBUG) Log.i(TAG, "onCreateOptionsMenu()");
          super.onCreateOptionsMenu(menu);
  
          List&lt;String&gt; effects = mOpenCvCameraView.getEffectList();
  
          if (effects == null) {
              Log.e(TAG, "Color effects are not supported by device!");
              return true;
          }
  
          mColorEffectsMenu = menu.addSubMenu("Color Effect");
          mEffectMenuItems = new MenuItem[effects.size()];
  
          int idx = 0;
          ListIterator&lt;String&gt; effectItr = effects.listIterator();
          while(effectItr.hasNext()) {
              String element = effectItr.next();
              mEffectMenuItems[idx] = mColorEffectsMenu.add(1, idx, Menu.NONE, element);
              idx++;
          }
  
          mResolutionMenu = menu.addSubMenu("Resolution");
          mResolutionList = mOpenCvCameraView.getResolutionList();
          mResolutionMenuItems = new MenuItem[mResolutionList.size()];
  
          ListIterator&lt;Camera.Size&gt; resolutionItr = mResolutionList.listIterator();
          idx = 0;
          while(resolutionItr.hasNext()) {
              Camera.Size element = resolutionItr.next();
              mResolutionMenuItems[idx] = mResolutionMenu.add(2, idx, Menu.NONE,
                      Integer.valueOf(element.width).toString() + "x" + Integer.valueOf(element.height).toString());
              idx++;
          }
  
          return true;
      }
  
      @Override
      protected void onPause() {
          if (Static.DEBUG) Log.i(TAG, "onPause()");
          super.onPause();
  
          if (mOpenCvCameraView != null)
              mOpenCvCameraView.disableView();
  
      }
  
      @Override
      protected void onStop() {
          if (Static.DEBUG) Log.i(TAG, "onStop()");
          super.onStop();
      }
  
      @Override
      protected void onDestroy() {
          if (Static.DEBUG) Log.i(TAG, "onDestroy()");
          super.onDestroy();
  
          if (mOpenCvCameraView != null)
              mOpenCvCameraView.disableView();
      }
  
      public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {
  
          ++frameCounter;
          //Log.i(TAG, "Frame number: "+frameCounter);
  
          return inputFrame.rgba();
      }
  
  
      @Override
      public void onCameraViewStarted(int width, int height) {
          edgesMat = new Mat();
      }
  
      @Override
      public void onCameraViewStopped() {
          if (edgesMat != null)
              edgesMat.release();
  
          edgesMat = null;
      }
  
      public boolean onOptionsItemSelected(MenuItem item) {
          Log.i(TAG, "called onOptionsItemSelected; selected item: " + item);
          if (item.getGroupId() == 1)
          {
              mOpenCvCameraView.setEffect((String) item.getTitle());
              Toast.makeText(this, mOpenCvCameraView.getEffect(), Toast.LENGTH_SHORT).show();
          } else if (item.getGroupId() == 2) {
              int id = item.getItemId();
              Camera.Size resolution = mResolutionList.get(id);
              mOpenCvCameraView.setResolution(resolution);
              resolution = mOpenCvCameraView.getResolution();
              String caption = Integer.valueOf(resolution.width).toString() + "x" + Integer.valueOf(resolution.height).toString();
              Toast.makeText(this, caption, Toast.LENGTH_SHORT).show();
          }
  
          return true;
      }
  
      @Override
      public boolean onTouch(View v, MotionEvent event) {
          Log.i(TAG,"onTouch event");
          SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");
          String currentDateandTime = sdf.format(new Date());
          String fileName = Environment.getExternalStorageDirectory().getPath() +
                  "/sample_picture_" + currentDateandTime + ".jpg";
          mOpenCvCameraView.takePicture(fileName);
          Toast.makeText(this, fileName + " saved", Toast.LENGTH_SHORT).show();
          return false;
      }
  
      /**
       * Click to ImageButton to start recording.
       */
      public void onClickBtnStartRecord2(View v) {
          if (Static.DEBUG) Log.i(TAG, "onClickBtnStartRecord()");
  
          if(!recording)
              startRecording();
          else
              stopRecording();
      }
  
      private void startRecording() {
          if (Static.DEBUG) Log.i(TAG, "startRecording()");
          initRecorder();
  
          try {
              recorder.start();
              startTime = System.currentTimeMillis();
              recording = true;
              audioThread.start();
          } catch(FFmpegFrameRecorder.Exception e) {
              e.printStackTrace();
          }
      }
  
      private void stopRecording() {
          if (Static.DEBUG) Log.i(TAG, "stopRecording()");
  
          runAudioThread = false;
          try {
              audioThread.join();
          } catch(InterruptedException e) {
              e.printStackTrace();
          }
          audioRecordRunnable = null;
          audioThread = null;
  
          if(recorder != null &amp;&amp; recording) {
  
              recording = false;
              Log.v(TAG, "Finishing recording, calling stop and release on recorder");
              try {
                  recorder.stop();
                  recorder.release();
              } catch(FFmpegFrameRecorder.Exception e) {
                  e.printStackTrace();
              }
              recorder = null;
          }
      }
  
  
      //---------------------------------------
      // initialize ffmpeg_recorder
      //---------------------------------------
      private void initRecorder() {
  
          Log.w(TAG, "init recorder");
          try {
  
              if (yuvImage == null) {
                  yuvImage = new Frame(imageWidth, imageHeight, Frame.DEPTH_UBYTE, 2);
                  Log.i(TAG, "create yuvImage");
              }
  
              Log.i(TAG, "ffmpeg_url: " + ffmpeg_link.getAbsolutePath());
              Log.i(TAG, "ffmpeg_url: " + ffmpeg_link.exists());
              recorder = new FFmpegFrameRecorder(ffmpeg_link, imageWidth, imageHeight, 1);
              recorder.setFormat("mp4");
              recorder.setSampleRate(sampleAudioRateInHz);
              // Set in the surface changed method
              recorder.setFrameRate(frameRate);
  
              Log.i(TAG, "recorder initialize success");
  
              audioRecordRunnable = new AudioRecordRunnable();
              audioThread = new Thread(audioRecordRunnable);
              runAudioThread = true;
          } catch (Exception e){
              e.printStackTrace();
          }
      }
  
      //---------------------------------------------
      // 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;
              ShortBuffer 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 = ShortBuffer.allocate(bufferSize);
  
              Log.d(TAG, "audioRecord.startRecording()");
              audioRecord.startRecording();
  
              /* ffmpeg_audio encoding loop */
              while(runAudioThread) {
                  //Log.v(TAG,"recording? " + recording);
                  bufferReadResult = audioRecord.read(audioData.array(), 0, audioData.capacity());
                  audioData.limit(bufferReadResult);
                  if(bufferReadResult &gt; 0) {
                      Log.v(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.recordSamples(audioData);
                                  //Log.v(TAG,"recording " + 1024*i + " to " + 1024*i+1024);
                              } catch(FFmpegFrameRecorder.Exception e) {
                                  Log.v(TAG, e.getMessage());
                                  e.printStackTrace();
                              }
                      }
                  }
              }
              Log.v(TAG, "AudioThread Finished, release audioRecord");
  
              /* encoding finish, release recorder */
              if(audioRecord != null) {
                  audioRecord.stop();
                  audioRecord.release();
                  audioRecord = null;
                  Log.v(TAG, "audioRecord released");
              }
          }
      }
  }
  </code></pre>
  
  <p><strong>OpenCVCameraPreview.java:</strong></p>
  
  <pre><code>import android.content.Context;
  import android.hardware.Camera;
  import android.util.AttributeSet;
  import android.util.Log;
  
  import org.opencv.android.JavaCameraView;
  
  import java.io.FileOutputStream;
  import java.util.List;
  
  public class OpenCVCameraPreview extends JavaCameraView implements Camera.PictureCallback {
  
      private static final String TAG =  OpenCVCameraPreview.class.getSimpleName();
      private String mPictureFileName;
  
      public OpenCVCameraPreview(Context context, AttributeSet attrs) {
          super(context, attrs);
      }
  
      public List&lt;String&gt; getEffectList() {
          return mCamera.getParameters().getSupportedColorEffects();
      }
  
      public boolean isEffectSupported() {
          return (mCamera.getParameters().getColorEffect() != null);
      }
  
      public String getEffect() {
          return mCamera.getParameters().getColorEffect();
      }
  
      public void setEffect(String effect) {
          Camera.Parameters params = mCamera.getParameters();
          params.setColorEffect(effect);
          mCamera.setParameters(params);
      }
  
      public List&lt;Camera.Size&gt; getResolutionList() {
          return mCamera.getParameters().getSupportedPreviewSizes();
      }
  
      public void setResolution(Camera.Size resolution) {
          disconnectCamera();
          mMaxHeight = resolution.height;
          mMaxWidth = resolution.width;
          connectCamera(getWidth(), getHeight());
      }
  
      public Camera.Size getResolution() {
          return mCamera.getParameters().getPreviewSize();
      }
  
      public void takePicture(final String fileName) {
          Log.i(TAG, "Taking picture");
          this.mPictureFileName = fileName;
          // Postview and jpeg are sent in the same buffers if the queue is not empty when performing a capture.
          // Clear up buffers to avoid mCamera.takePicture to be stuck because of a memory issue
          mCamera.setPreviewCallback(null);
  
          // PictureCallback is implemented by the current class
          mCamera.takePicture(null, null, this);
      }
  
      @Override
      public void onPictureTaken(byte[] data, Camera camera) {
          Log.i(TAG, "Saving a bitmap to file");
          // The camera preview was automatically stopped. Start it again.
          mCamera.startPreview();
          mCamera.setPreviewCallback(this);
  
          // Write the image in a file (in jpeg format)
          try {
              FileOutputStream fos = new FileOutputStream(mPictureFileName);
  
              fos.write(data);
              fos.close();
  
          } catch (java.io.IOException e) {
              Log.e("PictureDemo", "Exception in photoCallback", e);
          }
  
      }
  }
  </code></pre>
  
  <p><strong>Gradle:</strong></p>
  
  <pre><code>apply plugin: 'com.android.application'
  
  android {
      compileSdkVersion 23
      buildToolsVersion "23.0.2"
  
      defaultConfig {
          applicationId "co.example.example"
          minSdkVersion 15
          targetSdkVersion 23
          versionCode 1
          versionName "1.0"
      }
      buildTypes {
          release {
              minifyEnabled false
              proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
          }
      }
  
      packagingOptions {
          exclude 'META-INF/maven/org.bytedeco.javacpp-presets/opencv/pom.properties'
          exclude 'META-INF/maven/org.bytedeco.javacpp-presets/opencv/pom.xml'
          exclude 'META-INF/maven/org.bytedeco.javacpp-presets/ffmpeg/pom.properties'
          exclude 'META-INF/maven/org.bytedeco.javacpp-presets/ffmpeg/pom.xml'
      }
  }
  
  repositories {
      mavenCentral()
  }
  
  dependencies {
      compile fileTree(include: ['*.jar'], dir: 'libs')
      testCompile 'junit:junit:4.12'
      compile 'com.android.support:appcompat-v7:23.1.1'
      compile 'com.google.android.gms:play-services-appindexing:8.1.0'
  
      compile group: 'org.bytedeco', name: 'javacv', version: '1.1'
      compile group: 'org.bytedeco.javacpp-presets', name: 'opencv', version: '3.0.0-1.1', classifier: 'android-arm'
      compile group: 'org.bytedeco.javacpp-presets', name: 'opencv', version: '3.0.0-1.1', classifier: 'android-x86'
      compile group: 'org.bytedeco.javacpp-presets', name: 'ffmpeg', version: '2.8.1-1.1', classifier: 'android-arm'
      compile group: 'org.bytedeco.javacpp-presets', name: 'ffmpeg', version: '2.8.1-1.1', classifier: 'android-x86'
  
      compile project(':openCVLibrary310')
  }
  </code></pre>
  
  <p><strong>proguard-rules.pro</strong>
  Edited by: <a href="https://github.com/bytedeco/javacv/wiki/Configuring-Proguard-for-JavaCV" rel="nofollow noreferrer">link</a></p>
  
  <p><strong>jniLibs:</strong>
  app/src/main/jniLibs:</p>
  
  <pre><code>armeabi armeabi-v7a arm64-v8a mips mips64 x86 x86_64
  </code></pre>
  
  <p><strong>Problem</strong> </p>
  
  <pre><code>02-19 11:57:37.684 1759-1759/ I/OpenCVCameraActivity: onClickBtnStartRecord()
  02-19 11:57:37.684 1759-1759/ I/OpenCVCameraActivity: startRecording()
  02-19 11:57:37.684 1759-1759/ W/OpenCVCameraActivity: init recorder
  02-19 11:57:37.691 1759-1759/ I/OpenCVCameraActivity: create yuvImage
  02-19 11:57:37.691 1759-1759/ I/OpenCVCameraActivity: ffmpeg_url: /storage/emulated/0/stream.mp4
  02-19 11:57:37.696 1759-1759/ I/OpenCVCameraActivity: ffmpeg_url: false
  02-19 11:57:37.837 1759-1759/ W/linker: libjniavutil.so: unused DT entry: type 0x1d arg 0x18cc3
  02-19 11:57:37.837 1759-1759/ W/linker: libjniavutil.so: unused DT entry: type 0x6ffffffe arg 0x21c30
  02-19 11:57:37.837 1759-1759/ W/linker: libjniavutil.so: unused DT entry: type 0x6fffffff arg 0x1
  02-19 11:57:37.838 1759-1759/co.example.example E/art: dlopen("/data/app/co.example.example-2/lib/x86/libjniavutil.so", RTLD_LAZY) failed: dlopen failed: cannot locate symbol "av_version_info" referenced by "libjniavutil.so"...
  02-19 11:57:37.843 1759-1759/co.example.example I/art: Rejecting re-init on previously-failed class java.lang.Class&lt;org.bytedeco.javacpp.avutil&gt;
  02-19 11:57:37.844 1759-1759/co.example.example E/AndroidRuntime: FATAL EXCEPTION: main
                                          Process: co.example.example, PID: 1759
                                          java.lang.IllegalStateException: Could not execute method of the activity
                                              at android.view.View$1.onClick(View.java:4020)
                                              at android.view.View.performClick(View.java:4780)
                                              at android.view.View$PerformClick.run(View.java:19866)
                                              at android.os.Handler.handleCallback(Handler.java:739)
                                              at android.os.Handler.dispatchMessage(Handler.java:95)
                                              at android.os.Looper.loop(Looper.java:135)
                                              at android.app.ActivityThread.main(ActivityThread.java:5254)
                                              at java.lang.reflect.Method.invoke(Native Method)
                                              at java.lang.reflect.Method.invoke(Method.java:372)
                                              at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
                                              at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
                                           Caused by: java.lang.reflect.InvocationTargetException
                                              at java.lang.reflect.Method.invoke(Native Method)
                                              at java.lang.reflect.Method.invoke(Method.java:372)
                                              at android.view.View$1.onClick(View.java:4015)
                                              at android.view.View.performClick(View.java:4780) 
                                              at android.view.View$PerformClick.run(View.java:19866) 
                                              at android.os.Handler.handleCallback(Handler.java:739) 
                                              at android.os.Handler.dispatchMessage(Handler.java:95) 
                                              at android.os.Looper.loop(Looper.java:135) 
                                              at android.app.ActivityThread.main(ActivityThread.java:5254) 
                                              at java.lang.reflect.Method.invoke(Native Method) 
                                              at java.lang.reflect.Method.invoke(Method.java:372) 
                                              at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903) 
                                              at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698) 
                                           Caused by: java.lang.UnsatisfiedLinkError: org.bytedeco.javacpp.avutil
                                              at java.lang.Class.classForName(Native Method)
                                              at java.lang.Class.forName(Class.java:309)
                                              at org.bytedeco.javacpp.Loader.load(Loader.java:413)
                                              at org.bytedeco.javacpp.Loader.load(Loader.java:381)
                                              at org.bytedeco.javacpp.avcodec$AVPacket.&lt;clinit&gt;(avcodec.java:1650)
                                              at org.bytedeco.javacv.FFmpegFrameRecorder.&lt;init&gt;(FFmpegFrameRecorder.java:149)
                                              at org.bytedeco.javacv.FFmpegFrameRecorder.&lt;init&gt;(FFmpegFrameRecorder.java:129)
                                              at co.example.example.OpenCVCameraActivity.initRecorder(OpenCVCameraActivity.java:320)
                                              at co.example.example.OpenCVCameraActivity.startRecording(OpenCVCameraActivity.java:266)
                                              at co.example.example.OpenCVCameraActivity.onClickBtnStartRecord2(OpenCVCameraActivity.java:259)
                                              at java.lang.reflect.Method.invoke(Native Method) 
                                              at java.lang.reflect.Method.invoke(Method.java:372) 
                                              at android.view.View$1.onClick(View.java:4015) 
                                              at android.view.View.performClick(View.java:4780) 
                                              at android.view.View$PerformClick.run(View.java:19866) 
                                              at android.os.Handler.handleCallback(Handler.java:739) 
                                              at android.os.Handler.dispatchMessage(Handler.java:95) 
                                              at android.os.Looper.loop(Looper.java:135) 
                                              at android.app.ActivityThread.main(ActivityThread.java:5254) 
                                              at java.lang.reflect.Method.invoke(Native Method) 
                                              at java.lang.reflect.Method.invoke(Method.java:372) 
                                              at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903) 
                                              at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698) 
  </code></pre>