title: Fast video compression like Whatsapp
body: <p>I need to speed up video compression in my Android app. I'm using FFMPEG and it takes 3 minutes to compress 80MB video. Does anyone knows a better solution?</p>
  
  <p>The command I'm using is:</p>
  
  <pre><code>/data/data/com.moymer/app_bin/ffmpeg -y -i /storage/emulated/0/DCIM/Camera/VID_20150803_164811363.mp4 -s 640x352 -r 25 -vcodec mpeg4 -ac 1 -preset ultrafast -strict -2 /storage/emulated/0/DCIM/Camera/compressed_video.mp4
  </code></pre>
  
  <p>I'm running this command using FFMPEG for Android from this github repo: <a href="https://github.com/guardianproject/android-ffmpeg-java" rel="nofollow noreferrer">https://github.com/guardianproject/android-ffmpeg-java</a></p>
  
  <p>The code to use FFMPEG in my project is inside an AsyncTask and is copied below:</p>
  
  <pre><code>@Override
  protected Object doInBackground(Object... params) {
  
      ItemRoloDeCamera compressedVideo = new ItemRoloDeCamera();
  
      File videoInputFile = new File(video.getSdcardPath());
  
      File videoFolderFile = videoInputFile.getParentFile();
  
      File videoOutputFile = new File(videoFolderFile, "video_comprimido_moymer.mp4");
  
      if (videoFolderFile.exists())
          android.util.Log.e("COMPRESS VIDEO UTILS", "video folder exist");
      else
          android.util.Log.e("COMPRESS VIDEO UTILS", "video folder DON'T exist");
  
      if (videoInputFile.exists())
          android.util.Log.e("COMPRESS VIDEO UTILS", "video input file exist");
      else
          android.util.Log.e("COMPRESS VIDEO UTILS", "video input file DON'T exist");
  
      if (videoOutputFile.exists())
          android.util.Log.e("COMPRESS VIDEO UTILS", "video output file exist");
      else
          android.util.Log.e("COMPRESS VIDEO UTILS", "video output file DON'T exist");
  
      FfmpegController ffmpegController;
  
      try {
  
          ffmpegController = new FfmpegController(context, videoFolderFile);
  
          Clip clipIn = new Clip(videoInputFile.getAbsolutePath());
  
          ffmpegController.getInfo(clipIn, new ShellUtils.ShellCallback() {
              @Override
              public void shellOut(String shellLine) {
                  videoInfo.add(shellLine);
              }
  
              @Override
              public void processComplete(int exitValue) {
                  videoInfo.add(String.valueOf(exitValue));
              }
          });
  
          int rotate = getRotateMetadata();
  
          Clip clipOut = new Clip(videoOutputFile.getAbsolutePath());
          clipOut.videoFps = "24";
          clipOut.videoBitrate = 512;
          clipOut.audioChannels = 1;
          clipOut.width = 640;
          clipOut.height = 352;
  
          if (rotate == 90)
              clipOut.videoFilter = "transpose=1";
          else if (rotate == 180)
              clipOut.videoFilter = "transpose=1,transpose=1";
          else if (rotate == 270)
              clipOut.videoFilter = "transpose=1,transpose=1,transpose=1";
  
          millisDuration = getVideoDuration(videoInputFile.getAbsolutePath());
  
          float secondsDuration = millisDuration / 1000f;
  
          clipOut.duration = secondsDuration;
  
          ffmpegController.processVideo(clipIn, clipOut, true, new ShellUtils.ShellCallback() {
              @Override
              public void shellOut(String shellLine) {
  
                  android.util.Log.e("COMPRESS VIDEO UTILS", "shellOut - " + shellLine);
  
                  float percentage = getTimeMetadata(shellLine);
  
                  if (percentage &gt;= 0f)
                      publishProgress(percentage);
  
              }
  
              @Override
              public void processComplete(int exitValue) {
                  android.util.Log.e("COMPRESS VIDEO UTILS", "proccess complete - " + exitValue);
              }
          });
  
  
      } catch (IOException e) {
          e.printStackTrace();
      } catch (Exception e) {
          e.printStackTrace();
      } finally {
  
          if (videoOutputFile.exists()) {
  
              android.util.Log.e("COMPRESS VIDEO UTILS", "finished ffmpeg ---&gt; video output file exist");
  
              compressedVideo.setSdcardPath(videoOutputFile.getAbsolutePath());
  
              return compressedVideo;
  
          } else
              android.util.Log.e("COMPRESS VIDEO UTILS", "finished ffmpeg ---&gt; video output file DON'T exist");
  
      }
  
      return compressedVideo;
  
  }
  
  private float getTimeMetadata(String shellLine) {
  
      float percentage = -1;
  
      if (shellLine.contains("time=")) {
  
          String[] timeLine = shellLine.split("=");
  
          String time = timeLine[5];
          time = time.replace("bitrate", "");
          time = time.trim();
  
      //            String source = "00:10:17";
          String[] tokens = time.split(":");
          int secondsToMs = (int) (Float.parseFloat(tokens[2]) * 1000);
          int minutesToMs = Integer.parseInt(tokens[1]) * 60000;
          int hoursToMs = Integer.parseInt(tokens[0]) * 3600000;
          long timeInMillis = secondsToMs + minutesToMs + hoursToMs;
  
          percentage = (timeInMillis * 100.0f) / millisDuration;
  
      }
  
      return percentage;
  
  }
  
  private int getRotateMetadata() {
  
      int rotate = 0;
  
      String durationString = "";
  
      for (String shellLine : videoInfo) {
  
          if (shellLine.contains("rotate")) {
  
              //rotate          : 270
  
              String[] rotateLine = shellLine.split(":");
  
              rotate = Integer.parseInt(rotateLine[1].trim());
  
          }
  
      }
  
      return rotate;
  
  }
  
  public static long getVideoDuration(String videoPath) {
  
      MediaMetadataRetriever retriever = new MediaMetadataRetriever();
  
      retriever.setDataSource(videoPath);
  
      String time = retriever
              .extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
  
      long timeInmillisec = Long.parseLong(time);
  
      return timeInmillisec;
  
  }
  </code></pre>
  
  <p>The only change I made in the processVideo method was to add the following lines when building the commmand:</p>
  
  <pre><code>cmd.add("-preset");
  cmd.add("ultrafast");
  </code></pre>