48 Star 420 Fork 149

AnJoiner / FFmpegCommand

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
使用.md 8.65 KB
一键复制 编辑 原始数据 按行查看 历史
AnJoiner 提交于 2020-11-26 09:55 . 修改使用

引入

根据最新版本替换下面的${latestVersion},当前最新版本 Download

implementation 'com.coder.command:ffmpeg:${latestVersion}'

如果对apk大小有严格的要求,可以使用mini版本

implementation 'com.coder.command:ffmpeg-mini:${latestVersion}'

配置

一般我们使用CPU_ABI时只需要armeabi-v7aarm64-v8a就行了,所以只需要在app的bulid.gradle下加入如下代码:

android {
    ...
    defaultConfig {
        ...
        ndk {
            abiFilters 'armeabi-v7a', 'arm64-v8a'
            moduleName "app"
        }
    }
}

Debug模式

可以在Application或者使用之前设置Debug模式

 FFmpegCommand.setDebug(true);

使用之后将会打印类似如下信息,正式上线建议关闭

2020-04-14 11:24:34.316 15221-15304/com.coder.ffmpegtest D/ffmpeg-cmd: Input #0, mp3, from '/storage/emulated/0/Android/data/com.coder.ffmpegtest/cache/test.mp3':
2020-04-14 11:24:34.316 15221-15304/com.coder.ffmpegtest D/ffmpeg-cmd:   Metadata:
2020-04-14 11:24:34.316 15221-15304/com.coder.ffmpegtest D/ffmpeg-cmd:     track           : 
2020-04-14 11:24:34.316 15221-15304/com.coder.ffmpegtest D/ffmpeg-cmd: 4
2020-04-14 11:24:34.316 15221-15304/com.coder.ffmpegtest D/ffmpeg-cmd:     album           : 
2020-04-14 11:24:34.316 15221-15304/com.coder.ffmpegtest D/ffmpeg-cmd: 老妖的奇异之旅
2020-04-14 11:24:34.316 15221-15304/com.coder.ffmpegtest D/ffmpeg-cmd:     artist          : 
2020-04-14 11:24:34.316 15221-15304/com.coder.ffmpegtest D/ffmpeg-cmd: 音频怪物
2020-04-14 11:24:34.316 15221-15304/com.coder.ffmpegtest D/ffmpeg-cmd:     title           : 
2020-04-14 11:24:34.316 15221-15304/com.coder.ffmpegtest D/ffmpeg-cmd: 琴师
2020-04-14 11:24:34.316 15221-15304/com.coder.ffmpegtest D/ffmpeg-cmd:     comment         : 
2020-04-14 11:24:34.317 15221-15304/com.coder.ffmpegtest D/ffmpeg-cmd: 163 key(Don't modify):L64FU3W4YxX3ZFTmbZ+8/XaHu4ttkjqeshXxH3KzUJIjW7TiQPO7yhdBvVocH3+T10bijFQrb4/8IlKOGmuqVuqY66JjiWF+FKWZIAtFkegR9A1hA0/PQDlrk3QgW2ecLZDxWBvu4ei9113YaekyVuHRKrPI+2wF4Bvt6VS8oTFrOPTNN2kZa8OZq0PUedCDDqfXUU1SGPu6yJt7rwpEOSCMI2WbS1OrwXRuyJQ43
2020-04-14 11:24:34.317 15221-15304/com.coder.ffmpegtest D/ffmpeg-cmd:     encoder         : 
2020-04-14 11:24:34.317 15221-15304/com.coder.ffmpegtest D/ffmpeg-cmd: Lavf58.20.100
2020-04-14 11:24:34.317 15221-15304/com.coder.ffmpegtest D/ffmpeg-cmd:   Duration: 
2020-04-14 11:24:34.317 15221-15304/com.coder.ffmpegtest D/ffmpeg-cmd: 00:00:39.99
2020-04-14 11:24:34.317 15221-15304/com.coder.ffmpegtest D/ffmpeg-cmd: , start: 
2020-04-14 11:24:34.317 15221-15304/com.coder.ffmpegtest D/ffmpeg-cmd: 0.011995
2020-04-14 11:24:34.317 15221-15304/com.coder.ffmpegtest D/ffmpeg-cmd: , bitrate: 
2020-04-14 11:24:34.317 15221-15304/com.coder.ffmpegtest D/ffmpeg-cmd: 320 kb/s
2020-04-14 11:24:34.317 15221-15304/com.coder.ffmpegtest D/ffmpeg-cmd:     Stream #0:0
2020-04-14 11:24:34.317 15221-15304/com.coder.ffmpegtest D/ffmpeg-cmd: , 50, 1/14112000
2020-04-14 11:24:34.317 15221-15304/com.coder.ffmpegtest D/ffmpeg-cmd: : Audio: mp3, 44100 Hz, stereo, fltp, 320 kb/s
2020-04-14 11:24:34.317 15221-15304/com.coder.ffmpegtest D/ffmpeg-cmd:     Metadata:
2020-04-14 11:24:34.317 15221-15304/com.coder.ffmpegtest D/ffmpeg-cmd:       encoder         : 
2020-04-14 11:24:34.317 15221-15304/com.coder.ffmpegtest D/ffmpeg-cmd: Lavc57.89
2020-04-14 11:24:34.317 15221-15304/com.coder.ffmpegtest D/ffmpeg-cmd: Successfully opened the file.

调用

FFmpegCommand方法

方法 功能
FFmpegCommand->setDebug(debug: Boolean) Dubug模式,可打印日志,默认true
FFmpegCommand->runCmd(cmd: Array<String?>) 执行ffmpeg命令,无回调
FFmpegCommand->runCmd(cmd: Array<String?> callBack: IFFmpegCallBack?) 执行ffmpeg命令,并回调 开始,完成,取消,进度,错误
FFmpegCommand->getMediaInfo(path: String?, @MediaAttribute type: Int) 获取媒体信息:视频宽高、比特率...
FFmpegCommand->getSupportFormat(@FormatAttribute formatType: Int) 获取当前库支持的封装、解封装格式
FFmpegCommand->getSupportCodec(@CodecAttribute codecType: Int) 获取当前库支持的编解码
FFmpegCommand->cancel() 退出FFmpeg命令执行

runCmd

runCmd调用FFmpeg为同步执行FFmpeg命令,外部需增加线程,否则会造成应用无响应。 直接调用FFmpegCommand.runCmd(cmd: Array<String?> callBack: IFFmpegCallBack?)方法,其中第一个参数由FFmpegUtils工具类提供,也可以自己添加

不支持异步执行FFmpeg命令,毕竟C是面向过程语言,会出现资源占用问题

GlobalScope.launch {
    FFmpegCommand.runCmd(FFmpegUtils.transformAudio(audioPath, targetPath), callback("音频转码完成", targetPath))
}

第二个参数是回调方法

open class CommonCallBack : IFFmpegCallBack {
    // 开始回调
    override fun onStart() {}
    // 进度回调
    override fun onProgress(progress: Int, pts: Long) {}
    // 取消回调
    override fun onCancel() {}
    // 完成回调
    override fun onComplete() {}
    // 错误回调
    override fun onError(errorCode: Int, errorMsg: String?) {}
}

需要注意的是在onProgress方法中,可以看到回调回了2个值:

  • progress:进度,参考第一个输入文件(即是第1个i之后的输入文件)计算得出,多个输入文件时可能出现不正确的情况
  • pts:已执行时间,progress出现不正确的使用当前值进行计算,计算方法如下
var duration :Int? = FFmpegCommand.getMediaInfo(mAudioPath,MediaAttribute.DURATION)
var progress = pts/duration!!

自定义FFmpeg命令

这里只是演示了音频剪切,很多如上述功能请自行查阅FFmpegUtils 如果其中不满足需求,可添加自己的FFmpeg命令.例如:

var command = "ffmpeg -y -i %s -vn -acodec copy -ss %d -t %d %s"
command = String.format(command, srcFile, startTime, duration, targetFile)

GlobalScope.launch {
    FFmpegCommand.runCmd(command.split(" ").toTypedArray(), callback("音频剪切完成", targetPath))
}

多进程执行

由于底层暂时无法实现多线程(毕竟C是面向过程的语言),所以如果需要在推流的同时,是无法再同时执行其他命令。 为了解决这个问题,可以使用如下多进程方法:

  1. 定义与主进程不同的其他进程
<service android:name=".service.FFmpegCommandService" android:process=":ffmpegCommand" />
<service android:name=".service.FFmpegCommandService2" android:process=":ffmpegCommand2" />
  1. 在其他进程中执行推流的操作
class FFmpegCommandService : Service() {
    override fun onBind(intent: Intent): IBinder? {
        return null
    }

    override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
        val videoPath = File(externalCacheDir, "test.mp4").absolutePath
        val output = File(externalCacheDir, "output.yuv").absolutePath
        val cmd = "ffmpeg -y -i %s -an -c:v rawvideo -pixel_format yuv420p %s"
        val result = String.format(Locale.CHINA, cmd, videoPath, output)
        val strings: Array<String?> = result.split(" ").toTypedArray()
        FFmpegCommand.runCmd(strings)
        return super.onStartCommand(intent, flags, startId)
    }
}

取消执行

执行下面方法后将会回调 CommonCallBack->onCancel() 方法

FFmpegCommand.cancel();

使用getMediaInfo

FFmpegCommand.getMediaInfo(path: String?, @MediaAttribute type: Int)提供了获取媒体文件大小,视频宽高,比特率,音频采样率等属性值方法

val AV_TIME_BASE = 1000000;
val duration = FFmpegCommand.getInfoSync(mVideoPath, Attribute.DURATION)
var secs = duration / AV_TIME_BASE
al us = duration % AV_TIME_BASE
var mins = secs / 60
secs %= 60
val hours = mins / 60
mins %= 60

val result = String.format("%02d:%02d:%02d.%02d", hours, mins, secs, (100 * us) / AV_TIME_BASE)
tvContent?.text = result

参考

【KFFmpegCommandActivity-命令使用参考】 【KFFmpegInfoActivity-媒体信息参考】 【KFFmppegFormatActivity-支持封装格式】 【KFFmpegCodecActivity-支持编解码】

Android
1
https://gitee.com/anjoiner/FFmpegCommand.git
git@gitee.com:anjoiner/FFmpegCommand.git
anjoiner
FFmpegCommand
FFmpegCommand
master

搜索帮助