如何在Android中压缩视频?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。
使用方法
基本原理:将android环境下可执行文件ffmpeg存放在本地,代码执行ffmpeg的压缩命令。
//将开源库中asset目录的ffmpeg可执行文件,拷贝到 app的data/data/files目录 FFmpeg.getInstance(this).loadBinary(null);
执行ffmpeg的一个命令:比如查看ffmpeg的当前版本:./ffmpeg -version
接着就可以在代码中,使用ffmpeg的各种命令了:把命令写入String[],然后调用fFmpeg.execute 即可
获取视频文件的信息
String[] command = new String[]{"-i", arg.filePath}; try { fFmpeg.execute(commands, new ExecuteBinaryResponseHandler(){ @Override public void onStart() {} @Override public void onProgress(String message) { Log.e("dml", "onProgress: message is " + message); } @Override public void onFailure(String message) { Log.e("dml", "onFailure: message is " + message); } @Override public void onSuccess(String message) { Log.e("dml", "onSuccess: message is " + message); } @Override public void onFinish() { Log.e("dml", "onFinish: "); } }); } catch (FFmpegCommandAlreadyRunningException e) { e.printStackTrace(); }
压缩视频:
String[] commands = new String[]{"-threads","1","-i", arg.filePath, "-c:v", "libx264","-crf","30","-preset", "superfast" ,"-y", "-acodec","libmp3lame",arg.thumbVideoPath}; fFmpeg.execute(commands, new ExecuteBinaryResponseHandler(){});
参数解释:
-threads: 执行线程数,传入1 单线程压缩
-i:input路径,传入视频文件的路径
-c:v:编码格式,一般都是指定libx264
-crf: 编码质量,取值范围是0-51,默认值为23,数字越小输出视频的质量越高。这里的30是我们经过测试得到的经验值
-preset:转码速度,ultrafast,superfast,veryfast,faster,fast,medium,slow,slower,veryslow和placebo。ultrafast编码速度最快,但压缩率低,生成的文件更大,placebo则正好相反。x264所取的默认值为medium。需要说明的是,preset主要是影响编码的速度,并不会很大的影响编码出来的结果的质量。
-acodec:音频编码,一般采用libmp3lame
arg.thumbVideoPath:最后传入的是视频压缩后保存的路径
-y:输出时覆盖输出目录已存在的同名文件(如果不加此参数,就不会覆盖)
问题解决
此开源库用于视频压缩在实际开发中存在不少问题,下面一一解决
1.压缩进度反馈
执行转码命令后,onProgress只是不停输出字符串,而且文本很长 需要正则表达式从中截取转码进度反馈:
@Override public void onProgress(String s) { Pattern timePattern = Pattern.compile("(?<=time=)[\\d:.]*"); Scanner sc = new Scanner(s); String match = sc.findWithinHorizon(timePattern, 0); if (match != null) { String[] matchSplit = match.split(":"); if (duration!= 0) { float progress = (Integer.parseInt(matchSplit[0]) * 3600 + Integer.parseInt(matchSplit[1]) * 60 + Float.parseFloat(matchSplit[2])) / duration; int showProgress = (int) (progress * 100); if(showProgress>100){ showProgress = 100; } notify.compressProgress(getTag(),showProgress); } } }
2.低码率视频压缩会变大
实际中发现有些原质量较差的视频压缩后,体积反而变大。
处理方法:压缩前先执行对视频提取信息的命令,小于1024kb/s的视频 不压缩:
@Override public void onProgress(String s) { //Log.d("dml","pre onProgress = " + s); if(s.contains("Stream #0:0")){ String tem = s.substring(0, s.indexOf("kb/s")); String type ; int pos = tem.lastIndexOf(","); if (pos != -1) { type = tem.substring(pos + 1,tem.length()).trim(); try { Integer integer = Integer.parseInt(type); if(integer > 1024){ pressV(fFmpeg);//执行压缩 }else { //放弃压缩,直接使用原文件 } }catch (Exception e){ } } } }
并且在压缩成功后,检查压缩后的文件和原文件大小,如果变大了,直接使用原文件。
3.多线程压缩多个视频
开源库中执行ffmpeg的命令是在AsycTask执行的:
ffmpegExecuteAsyncTask = new FFmpegExecuteAsyncTask(command , timeout, ffmpegExecuteResponseHandler); ffmpegExecuteAsyncTask.execute();
execute 方法在api 11之后是串行方法,就是说开源库已经限制为单线程。
改为:ffmpegExecuteAsyncTask.executeOnExecutor(Executors.newCachedThreadPool()); 可以使用多线程
测试中发现多个视频同时压缩,手机会严重发热,强烈建议采用原设计 。
看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注亿速云行业资讯频道,感谢您对亿速云的支持。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。