前言

本文讨论的不是类似秒拍的短视频录制,而是用户选择本地一个现有视频,压缩后上传。秒拍的实现其实是自定义视频录制功能,从而控制录制时长,分辨率,码率等,生成体积很小的视频再上传。而我们则没办法控制原视频的参数,可能是一个很大的视频需要压缩处理。

思路

利用ffmpeg对视频转码,通过设定参数生成分辨率和码率更小的视频,实现压缩。当然,ffmpeg的功能远不止如此,这是一个很大的专题。

用到的开源库:https://github.com/WritingMinds/ffmpeg-android-java

使用方法

基本原理:将android环境下可执行文件ffmpeg存放在本地,代码执行ffmpeg的压缩命令。

?

1

2

3

//将开源库中asset目录的ffmpeg可执行文件,拷贝到 app的data/data/files目录

FFmpeg.getInstance(this).loadBinary(null);

这个方法是异步执行,所以最好在Application中执行。方法有执行成功与否的回调,这里我传入null不关心结果。执行完看下手机中的目录:

既然是可执行文件,那么在android shell环境下肯定可以执行了。adb shell进入手机看下(前提是手机已经获取root权限):

执行ffmpeg的一个命令:比如查看ffmpeg的当前版本:./ffmpeg -version

接着就可以在代码中,使用ffmpeg的各种命令了:把命令写入String[],然后调用fFmpeg.execute 即可

获取视频文件的信息

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

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();

    }

压缩视频:

?

1

2

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(){});

参数解释:

  1. -threads: 执行线程数,传入1 单线程压缩
  2. -i:input路径,传入视频文件的路径
  3. -c:v:编码格式,一般都是指定libx264
  4. -crf: 编码质量,取值范围是0-51,默认值为23,数字越小输出视频的质量越高。这里的30是我们经过测试得到的经验值
  5. -preset:转码速度,ultrafast,superfast,veryfast,faster,fast,medium,slow,slower,veryslow和placebo。ultrafast编码速度最快,但压缩率低,生成的文件更大,placebo则正好相反。x264所取的默认值为medium。需要说明的是,preset主要是影响编码的速度,并不会很大的影响编码出来的结果的质量。
  6. -acodec:音频编码,一般采用libmp3lame
  7. arg.thumbVideoPath:最后传入的是视频压缩后保存的路径
  8. -y:输出时覆盖输出目录已存在的同名文件(如果不加此参数,就不会覆盖)

问题解决

此开源库用于视频压缩在实际开发中存在不少问题,下面一一解决

1.压缩进度反馈

执行转码命令后,onProgress只是不停输出字符串,而且文本很长 需要正则表达式从中截取转码进度反馈:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

@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的视频 不压缩:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

@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执行的:

?

1

2

ffmpegExecuteAsyncTask = new FFmpegExecuteAsyncTask(command , timeout, ffmpegExecuteResponseHandler);

ffmpegExecuteAsyncTask.execute();

execute 方法在api 11之后是串行方法,就是说开源库已经限制为单线程。

改为:ffmpegExecuteAsyncTask.executeOnExecutor(Executors.newCachedThreadPool()); 可以使用多线程

测试中发现多个视频同时压缩,手机会严重发热,强烈建议采用原设计 。

4.压缩速度和质量

手机性能有限,压缩视频速度不太理想,即使在PC端用 格式工厂压缩转码视频也不是很快。

压缩质量还可以,基本能保持和原视频一样的清晰度。下面是测试数据:

原文链接:https://www.jianshu.com/p/4f82b058c8ec

Android本地视频压缩方案相关推荐

  1. android 储存方案,Android本地数据存储方案(一)

    Android系列的博客主要是记录和总结自己在平时学习之中遇到的问题,方便日后用到时查看,同时也希望对读者有所帮助.不足之处,欢迎指正~ 在说到Android数据存储之前,先提一下数据持久化,所谓数据 ...

  2. android 本地提醒功能,android中的本地定时推送到通知栏

    一.使用系统定义的Notification 以下是使用示例代码: import android.app.Notification; import android.app.NotificationMan ...

  3. android fota解决方案,Android智能终端FOTA方案的制作方法

    技术特征: 1.android智能终端fota方案发明专利权利要求 1.一种智能终端连续增量升级实现方法. 2.其特征在于所有任何终端设备可以一次性增量升级到最新版本,也可以对部分版本一次性增量升级到 ...

  4. 2021年最详细的Android屏幕适配方案汇总

    1 Android屏幕适配的度量单位和相关概念 建议在阅读本文章之前,可以先阅读快乐李同学写的文章<Android屏幕适配的度量单位和相关概念>,这篇文章包含了阅读本文的一些基础知识,推荐 ...

  5. Android 热修复方案Tinker(五) SO补丁加载

    基于Tinker V1.7.5 Android 热修复方案Tinker(一) Application改造 Android 热修复方案Tinker(二) 补丁加载流程 Android 热修复方案Tink ...

  6. Android投屏方案(基于cling)

    一 .前言 最近做了一个浏览器&视频播放的项目,是在73.0.3683.90版本的chrome源码上修改而来,涉及到抓取网页里视频的播放地址.播放视频.视频投屏.视频下载.网页内广告屏蔽等方面 ...

  7. 业务逻辑组件化android,AppJoint 极简 Android 组件化方案

    AppJoint 极简 Android 组件化方案.仅包含 3 个注解加 1 个 API,超低学习成本,支持渐进式组件化. 开始接入 在项目根目录的 build.gradle 文件中添加 AppJoi ...

  8. 浅入浅出 Android 安全:第三章 Android 本地用户空间层安全

    第三章 Android 本地用户空间层安全 来源:Yury Zhauniarovich | Publications 译者:飞龙 协议:CC BY-NC-SA 4.0 本地用户空间层在 Android ...

  9. Android 从 Android 本地图库选择多个图片

    原文地址 本文说明如何从 Android 本地图库选择多个图片.作者考虑很多解决方案. 演示从 Android 本地图库选择多个图片,有两个方法可以实现从图库中选择多个图片: 用 Intent 获取多 ...

  10. 实现在Android本地视频播放器开发

    在Android本地视频播放器开发中的搜索本地视频章节中,我们能够搜索本地视频并且显示每个视频的图片.标题.时间长度,当然如果需要添加其他的例如视频的长度和宽度可以使用Video类中的方法,既然我们获 ...

最新文章

  1. mysql参数文件选项组_my.cnf文件关于组选项的总结
  2. [java]窗口的创建
  3. live messenger与稀疏文件—Sparse File Bit
  4. CSS 温故知新 CSS垂直居中
  5. Little Sub and Enigma
  6. thinkphp5项目--个人博客(六)
  7. HDU 6579 Operation (前缀线性基模板题)
  8. 组件 模块 插件_播放2 –模块,插件有什么区别?
  9. [Android]解决Fragment无法使用android:onClick属性
  10. WORD样式保存为主题集?
  11. python读写excel的图片_python解析excel中图片+提取图片
  12. 利用BioEdit做多序列一致性比对
  13. OMNeT学习之TicToc2-7详解
  14. linux的火狐浏览器怎么用,火狐浏览器怎么用 火狐浏览器使用方法大全
  15. IOS 验证手机号格式
  16. centos是arm还是amd_amd系列cpu安装linux
  17. vs2013下git的使用
  18. BC61 金字塔图案
  19. asp毕业设计——基于asp+access的学生排课管理系统设计与实现(毕业论文+程序源码)——学生排课管理系统
  20. 皮革行业分销渠道管理系统有效缩短供销链,提升渠道运营收益

热门文章

  1. Python 3.7.1 模块 文本处理 正则表达式 re
  2. 关于计算机学院 公众号的名字,好听的公众号名称大全
  3. 优制网亮相“2016工业软件与制造业融合发展论坛”
  4. 【Scratch案例教学】Scratch九九乘法表 少儿编程Scratch创意编程案例教学
  5. android 数据线有几种,安卓数据线有几种
  6. 用SQL表达并交差操作
  7. 常用工具类之十一 XML报文加签工具类 http://www.w3.org/2000/09/xmldsig
  8. android高仿ios控制中心,仿 iOS 11原生控制中心
  9. 针对宝塔面板一个站点多个域名使用SSL证书的解决方案
  10. 如何压缩图片呢?这两种方法很管用