在安卓中用到的三方库:https://github.com/arthenica/ffmpeg-kit
这个库很强大,支持很多平台,每个平台都有各自的分支代码,用了一段时间,稳定性挺好的,
找到安卓下的分支:FFmpegKit for Android FFmpegKit Android 版
引入项目:
            
            
              java
              
              
            
          
          repositories {
    mavenCentral()
}
dependencies {
    implementation 'com.arthenica:ffmpeg-kit-full:6.0-2'
}每个平台下,又分为多个库,每个库包含不同的功能,因为功能越丰富,导入到项目中编译的包体积越大,尽量选择适合自己功能的库进行使用。
📦 FFmpeg 编译配置选项(库依赖分类)
| 配置项 | 说明 | 包含的库 | 
|---|---|---|
| min | 最小化构建 | - | 
| min-gpl | 最小化构建并启用 GPL 库 | vid.stab,x264,x265,xvidcore | 
| https | 启用 HTTPS 支持(使用非-GPL 依赖) | gmp,gnutls | 
| https-gpl | 启用 HTTPS 支持(使用 GPL 兼容依赖) | gmp,gnutls,vid.stab,x264,x265,xvidcore | 
| audio | 启用音频相关编码器/解码器 | lame,libilbc,libvorbis,opencore-amr,opus,shine,soxr,speex,twolame,vo-amrwbenc | 
| video | 启用视频相关编码器/解码器 | dav1d,fontconfig,freetype,fribidi,kvazaar,libass,libiconv,libtheora,libvpx,libwebp,snappy,zimg | 
| full | 启用所有非 GPL 第三方库 | dav1d,fontconfig,freetype,fribidi,gmp,gnutls,kvazaar,libass,libiconv,libilbc,libtheora,libvorbis,libvpx,libwebp,libxml2,opencore-amr,opus,shine,snappy,soxr,speex,twolame,vo-amrwbenc,zimg | 
| full-gpl | 启用所有库(包括 GPL) | dav1d,fontconfig,freetype,fribidi,gmp,gnutls,kvazaar,lame,libass,libiconv,libilbc,libtheora,libvorbis,libvpx,libwebp,libxml2,opencore-amr,opus,shine,snappy,soxr,speex,twolame,vid.stab,vo-amrwbenc,x264,x265,xvidcore,zimg | 
比如你如果只需要保存 rtsp 视频流 和 推流的话,只需要导入 min-gpl即可:
            
            
              java
              
              
            
          
           implementation 'com.arthenica:ffmpeg-kit-min-gpl:6.0-2'如果你想要更多,比如添加水印,就涉及到 FFmpeg 滤镜相关功能,就需要引入full-gpl:
            
            
              java
              
              
            
          
           implementation 'com.arthenica:ffmpeg-kit-full-gpl:6.0-2'具体需要什么功能,可以进去看说明,说明没有涉及到的,并且你不想用全功能库,你也可以一个一个试试,也许就能满足你。
正文开始
由说明可知,使用方式为:
            
            
              java
              
              
            
          
          import com.arthenica.ffmpegkit.FFmpegKit;
FFmpegSession session = FFmpegKit.execute("-i file1.mp4 -c:v mpeg4 file2.mp4");
if (ReturnCode.isSuccess(session.getReturnCode())) {
    // SUCCESS
} else if (ReturnCode.isCancel(session.getReturnCode())) {
    // CANCEL
} else {
    // FAILURE
    Log.d(TAG, String.format("Command failed with state %s and rc %s.%s", session.getState(), session.getReturnCode(), session.getFailStackTrace()));
}或者异步调用:
            
            
              java
              
              
            
          
          FFmpegKit.executeAsync("-i file1.mp4 -c:v mpeg4 file2.mp4", new FFmpegSessionCompleteCallback() {
    @Override
    public void apply(FFmpegSession session) {
        SessionState state = session.getState();
        ReturnCode returnCode = session.getReturnCode();
        // CALLED WHEN SESSION IS EXECUTED
        Log.d(TAG, String.format("FFmpeg process exited with state %s and rc %s.%s", state, returnCode, session.getFailStackTrace()));
    }
}, new LogCallback() {
    @Override
    public void apply(com.arthenica.ffmpegkit.Log log) {
        // CALLED WHEN SESSION PRINTS LOGS
    }
}, new StatisticsCallback() {
    @Override
    public void apply(Statistics statistics) {
        // CALLED WHEN SESSION GENERATES STATISTICS
    }
});与正常 ffmpeg 命令不同的是,在传入命令时,前面不需要加 "ffmpeg" 关键字,只需传入后面的具体命令即可,加上会报错哦!
关键代码:
搞了好久才凑齐的正确代码,这东西真不能听 AI 的一面之辞,不然就被 AI 一条路领到黑,
            
            
              java
              
              
            
          
              private static String buildWatermarkCommand(VideoFile file, VideoTimeRange timeRange, String outputPath, String fontPath) {
        FFmpegKitConfig.setFontconfigConfigurationPath(fontPath);
      
        String drawtextFilter = String.format(
                "drawtext=text='%s':fontfile=%s:fontcolor=white:fontsize=20:x=0:y=30",
                DEFAULT_WATERMARK, fontPath
        );
        List<String> commandList = new ArrayList<>();
        commandList.add("-ss");                              // 指定输入文件的开始时间,格式:HH:MM:SS
        commandList.add(timeRange.startTime);
        commandList.add("-i");                               // 输入文件路径
        commandList.add(file.filePath);
        commandList.add("-t");                               // 指定持续时间,格式:HH:MM:SS
        commandList.add(timeRange.durationStr);
        commandList.add("-vf");                              // 视频滤镜,用于添加水印文字
        commandList.add(drawtextFilter);
        commandList.add("-c:v");                             // 视频编码器设置
        commandList.add(VIDEO_CODEC);                        // 使用H.264软件编码器
        commandList.add("-preset");                          // 编码速度预设
        commandList.add(VIDEO_PRESET);                       // ultrafast:最快编码速度,文件稍大
        commandList.add("-crf");                             // 恒定质量因子(0-51,越小质量越好)
        commandList.add(String.valueOf(VIDEO_CRF));          // 23:平衡质量和文件大小的推荐值
        commandList.add("-c:a");                             // 音频编码器设置
        commandList.add("copy");                             // 直接复制音频流,不重新编码
        commandList.add("-r");
        commandList.add("20");                               // 每秒20帧
        commandList.add("-avoid_negative_ts");               // 避免负时间戳问题
        commandList.add("make_zero");                        // 将负时间戳调整为0
        commandList.add(outputPath);                         // 输出文件路径
        return String.join(" ", commandList);
    }简单介绍下命令作用:对一段现有的视频文件进行剪辑,-ss指定开始时间,比如要剪切的原视频时长为两分钟,所以开始时间到结束时间就是:00:00:00 - 00:02:00 , 假设要剪辑中间一分钟的视频,那么 -ss指定的开始时间为:00:00:30 , -t持续时间就是:00:01:00 , 截取的时间段为:00:00:30 - 00:01:30 ,-c:v设置编码器,一般 H.264 就够了,如果设置其他的编码器,要看你的设备支持不支持了,-r设置帧率,如果你想要剪切的视频大小小一点,一方面就可以通过降低帧率,另一方面就可以降低码率来实现(上述命令码率未指定默认按原视频码率)。
如果你指定的时间范围,超过原视频时长会报错,这很正常,只是报错内容可能看不懂,这是一个问题点!
设置 FFmpegKitConfig.setFontconfigConfigurationPath的作用是 https://github.com/arthenica/ffmpeg-kit/wiki/Tips 参考第四条:ffmpeg 需要有效的 fontconfig 配置才能在使用 drawtext filter 时渲染文本。
这里指定一个存在的字体路径即可 比如:/system/fonts/NotoSansCJK-Regular.ttc
注意:有的字体不支持中文,写入中文水印的时候会乱码!
视频处理性能测试(A133,Android 10)
测试环境
- 设备平台:A133
- 操作系统:Android 10
- 测试内容:视频加水印 vs 无水印处理
- 加水印帧率:15fps
- 视频格式:H.264 (宽高:720x576)(位率:512Kbps)
性能对比数据
| 视频时长 | 处理方式 | 耗时(ms) | 耗时(秒) | 输出文件大小 | 
|---|---|---|---|---|
| 30s | 加水印 | 5214 | 5.21 | 1.5M | 
| 30s | 加水印(15帧) | 3813 | 3.81 | 1.5M | 
| 30s | 不加水印 | 168 | 0.17 | 0.9M | 
| 60s | 加水印 | 12013 | 12.01 | 2.5M | 
| 60s | 加水印(15帧) | 7392 | 7.39 | 2.5M | 
| 60s | 不加水印 | 208 | 0.21 | 1.5M | 
| 120s | 加水印 | 22006 | 22.01 | 5.03M | 
| 120s | 加水印(15帧) | 18404 | 18.40 | 5.03M | 
| 120s | 不加水印 | 277 | 0.28 | 2.8M | 
| 240s | 加水印 | 50547 | 50.55 | 10.57M | 
| 240s | 加水印(15帧) | 37857 | 37.86 | 10.57M | 
| 240s | 不加水印 | 448 | 0.45 | 5.24M | 
在 A133 平台上,加水印操作是性能瓶颈,视频重编码操作对cpu要求比较高。