android 動画圧縮ライブラリについて調べたこと
Androidで動画の圧縮をしたくてライブラリを探してみたが思ったより少なかった。iOSだと標準のライブラリであっさりできた記憶があったのに...。試したのはassetsにmp4ファイルを同梱してそれを圧縮してかかった時間と圧縮後のサイズを検証した。どれくらい圧縮するのかの指定がそれぞれあるのかないのかまでまだドキュメントやソースを読み込めておらず、検証方法としてもしかしたら正しくないのかもしれないがとりあえず現時点の結果をメモしておく
検証したライブラリ
android-transcoder(star : 488)
https://github.com/ypresto/android-transcoder
SiliCompressor(star : 471)
https://github.com/Tourenathan-G5organisation/SiliCompressor
VideoCompressor(star : 206)
https://github.com/fishwjy/VideoCompressor
検証端末(シュミレータ含む)と動画ファイル
端末1 : F05-J、CPU 1.2GHz、メモリ 16GB、Android7
端末2 : SO-01G、CPU 2.5GHz、メモリ 32GB、Android6
端末3 : Nexus7、CPU 1.5GHz、メモリ 2GB
端末4 : シュミレータ Android9
端末5 : シュミレータ Android8
動画時間 : 30秒
動画サイズ : 66949244バイト
検証結果
圧縮後のファイルサイズと処理時間は下記のようになった。検証方法として正しいか自信ないけどこの結果だけみると、SiliCompressorがいいのかな。
android-transcoder
圧縮後のサイズ : 約46%
端末1 サイズ : 30962714, 時間 : 33秒
端末2 サイズ : 31064902, 時間 : 18秒
端末3 サイズ : 30941680, 時間 : 63秒
端末4 サイズ : 31392115, 時間 : 28秒
端末5 サイズ : 31371824, 時間 : 32秒
SiliCompressor
圧縮後のサイズ : 約4%
端末1 サイズ : 2316402, 時間 : 32秒
端末2 サイズ : 2315986, 時間 : 26秒
端末3 サイズ : 2661474, 時間 : 23秒
端末4 サイズ : 2651027, 時間 : 26秒
端末5 サイズ : 2673228, 時間 : 25秒
VideoCompressor
https://github.com/fishwjy/VideoCompressor
圧縮後のサイズ : 約10%
端末1 サイズ : 5534250, 時間 : 41秒
端末2 サイズ : 5536037, 時間 : 29秒
端末3 サイズ : 6523136, 時間 : 24秒
端末4 サイズ : 7160129, 時間 : 28秒
端末5 サイズ : 6760777, 時間 : 28秒
ソース
検証に使ったソース。つっこんでいただきたい
android-transcoder
package xxx.yyy.zzz.android_transcoder_demo; import android.content.res.AssetManager; import android.os.ParcelFileDescriptor; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.widget.MediaController; import android.widget.VideoView; import net.ypresto.androidtranscoder.MediaTranscoder; import net.ypresto.androidtranscoder.format.MediaFormatStrategyPresets; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final long startTime = System.currentTimeMillis(); final String inputPath = getCacheDir() + "/sample.mp4"; final String outputPath = getCacheDir() + "/sample_out.mp4"; File cacheFile = new File(inputPath); AssetManager assetManager = getResources().getAssets(); InputStream inputStream; try { inputStream = assetManager.open("sample.mp4"); int size = inputStream.available(); byte[] buffer = new byte[size]; inputStream.read(buffer); inputStream.close(); FileOutputStream fileOutputStream = new FileOutputStream(cacheFile); fileOutputStream.write(buffer); fileOutputStream.close(); MediaTranscoder.Listener listener = new MediaTranscoder.Listener() { @Override public void onTranscodeProgress(double progress) { } @Override public void onTranscodeCompleted() { long fileSize = MainActivity.this.getFileSize(inputPath); Log.d("","##### 圧縮前 " + String.valueOf(fileSize)); fileSize = MainActivity.this.getFileSize(outputPath); Log.d("","##### 圧縮後 " + String.valueOf(fileSize)); long endTime = System.currentTimeMillis(); long time = (endTime - startTime) / 1000; Log.d("","##### 処理時間 " + String.valueOf(time)); } @Override public void onTranscodeCanceled() { } @Override public void onTranscodeFailed(Exception exception) { exception.printStackTrace(); } }; MediaTranscoder.getInstance().transcodeVideo( inputPath, outputPath, MediaFormatStrategyPresets.createAndroid720pStrategy(), listener ); } catch (IOException e){ e.printStackTrace(); } } private long getFileSize(String path) { File file = new File(path); return file.length(); } }
SiliCompressor
package xxx.yyy.zzz.silicompressor_demo; import android.content.Context; import android.content.res.AssetManager; import android.os.AsyncTask; import android.os.Trace; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.widget.MediaController; import android.widget.VideoView; import com.iceteck.silicompressorr.SiliCompressor; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.URISyntaxException; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final String inputPath = getCacheDir() + "/sample.mp4"; final String outputDir = getCacheDir() + ""; File cacheFile = new File(inputPath); AssetManager assetManager = getResources().getAssets(); InputStream inputStream; try { inputStream = assetManager.open("sample.mp4"); int size = inputStream.available(); byte[] buffer = new byte[size]; inputStream.read(buffer); inputStream.close(); FileOutputStream fileOutputStream = new FileOutputStream(cacheFile); fileOutputStream.write(buffer); fileOutputStream.close(); VideoCompressTask task = new VideoCompressTask(getApplicationContext(), inputPath, outputDir); task.execute(); } catch(IOException e) { e.printStackTrace(); } } class VideoCompressTask extends AsyncTask<Void, String, String> { Context context; String inputPath; String outputDir; final long startTime = System.currentTimeMillis(); public VideoCompressTask(Context context, String inputPath, String outputDir) { this.context = context; this.inputPath = inputPath; this.outputDir = outputDir; } @Override protected String doInBackground(Void... params) { String filePath = null; try { filePath = SiliCompressor.with(context).compressVideo(this.inputPath, this.outputDir); } catch (Exception e) { cancel(true); e.printStackTrace(); } return filePath; } @Override protected void onPostExecute(String filePath) { long fileSize = MainActivity.this.getFileSize(inputPath); Log.d("","##### 圧縮前 " + String.valueOf(fileSize)); fileSize = MainActivity.this.getFileSize(filePath); Log.d("","##### 圧縮後 " + String.valueOf(fileSize)); long endTime = System.currentTimeMillis(); long time = (endTime - startTime) / 1000; Log.d("","##### 処理時間 " + String.valueOf(time)); } @Override protected void onCancelled() { } } private long getFileSize(String path) { File file = new File(path); return file.length(); } }
**
package xxx.yyy.zzz.video_compressor_demo; import android.content.res.AssetManager; import android.provider.MediaStore; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.widget.MediaController; import android.widget.VideoView; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import xxx.yyy.zzz.video_compressor_demo.videocompressor.VideoCompress; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final long startTime = System.currentTimeMillis(); final String inputPath = getCacheDir() + "/sample.mp4"; final String outputPath = getCacheDir() + "/sample_out.mp4"; File cacheFile = new File(inputPath); AssetManager assetManager = getResources().getAssets(); InputStream inputStream; try { inputStream = assetManager.open("sample.mp4"); int size = inputStream.available(); byte[] buffer = new byte[size]; inputStream.read(buffer); inputStream.close(); FileOutputStream fileOutputStream = new FileOutputStream(cacheFile); fileOutputStream.write(buffer); fileOutputStream.close(); VideoCompress.compressVideoLow(inputPath, outputPath, new VideoCompress.CompressListener() { @Override public void onStart() { } @Override public void onSuccess() { long fileSize = MainActivity.this.getFileSize(inputPath); Log.d("","##### 圧縮前 " + String.valueOf(fileSize)); fileSize = MainActivity.this.getFileSize(outputPath); Log.d("","##### 圧縮後 " + String.valueOf(fileSize)); long endTime = System.currentTimeMillis(); long time = (endTime - startTime) / 1000; Log.d("","##### 処理時間 " + String.valueOf(time)); } @Override public void onFail() { } @Override public void onProgress(float percent) { } }); } catch (IOException e){ e.printStackTrace(); } } private long getFileSize(String path) { File file = new File(path); return file.length(); } }
以上です