diff --git a/README-CN.md b/README-CN.md index 22c375e..923b80a 100644 --- a/README-CN.md +++ b/README-CN.md @@ -22,10 +22,30 @@ 如果访问不了全部信息,请跳转[【国内镜像】](https://gitee.com/anjoiner/FFmpegCommand) +## 交叉编译 +* Macos 13.2 + GCC + Cmake + NDK 21 + +| 第三方库 | 版本 | 下载地址 | +|------------|--------------------|------------------------------------------------------------------------------------------------------| +| ffmpeg | 6.0 | https://ffmpeg.org/releases/ffmpeg-6.0.tar.xz | +| x264 | X264-20191217.2245 | http://download.videolan.org/pub/videolan/x264/snapshots/x264-snapshot-20191217-2245-stable.tar.bz2 | +| mp3lame | 3.100 | https://sourceforge.net/projects/lame/files/latest/download | +| fdkaac | 2.0.1-ff69b4 | https://downloads.sourceforge.net/opencore-amr/fdk-aac-2.0.1.tar.gz | +| opencore-amr | 1.1.5 | https://sourceforge.net/projects/opencore-amr/files/opencore-amr/opencore-amr-0.1.5.tar.gz | +| ndk | 21 | https://dl.google.com/android/repository/android-ndk-r21e-darwin-x86_64.zip | + ## 主要功能 -[![](https://jitpack.io/v/AnJoiner/FFmpegCommand.svg)](https://jitpack.io/#AnJoiner/FFmpegCommand)[![License](https://img.shields.io/badge/license-Apache%202-informational.svg)](https://www.apache.org/licenses/LICENSE-2.0)[ ![FFmpeg](https://img.shields.io/badge/FFmpeg-4.2.1-orange.svg)](https://ffmpeg.org/releases/ffmpeg-4.2.1.tar.bz2)[ ![X264](https://img.shields.io/badge/X264-20191217.2245-yellow.svg)](http://download.videolan.org/pub/videolan/x264/snapshots/x264-snapshot-20191217-2245-stable.tar.bz2)[ ![mp3lame](https://img.shields.io/badge/mp3lame-3.100-critical.svg)](https://sourceforge.net/projects/lame/files/latest/download)[ ![fdk-aac](https://img.shields.io/badge/fdkaac-2.0.1-ff69b4.svg)](https://downloads.sourceforge.net/opencore-amr/fdk-aac-2.0.1.tar.gz)[ ![fdk-aac](https://img.shields.io/badge/opencoreamr-1.1.5-critical.svg)](https://sourceforge.net/projects/opencore-amr/files/opencore-amr/opencore-amr-0.1.5.tar.gz) +[![](https://jitpack.io/v/AnJoiner/FFmpegCommand.svg)](https://jitpack.io/#AnJoiner/FFmpegCommand)[![License](https://img.shields.io/badge/license-Apache%202-informational.svg)](https://www.apache.org/licenses/LICENSE-2.0)[ ![FFmpeg](https://img.shields.io/badge/FFmpeg-6.0-orange.svg)](https://ffmpeg.org/releases/ffmpeg-6.0.tar.xz)[ ![X264](https://img.shields.io/badge/X264-20191217.2245-yellow.svg)](http://download.videolan.org/pub/videolan/x264/snapshots/x264-snapshot-20191217-2245-stable.tar.bz2)[ ![mp3lame](https://img.shields.io/badge/mp3lame-3.100-critical.svg)](https://sourceforge.net/projects/lame/files/latest/download)[ ![fdk-aac](https://img.shields.io/badge/fdkaac-2.0.1-ff69b4.svg)](https://downloads.sourceforge.net/opencore-amr/fdk-aac-2.0.1.tar.gz)[ ![fdk-aac](https://img.shields.io/badge/opencoreamr-1.1.5-critical.svg)](https://sourceforge.net/projects/opencore-amr/files/opencore-amr/opencore-amr-0.1.5.tar.gz) + +| 特色功能 | 支持 | 描述 | +|------|--------------------|------------------------| +| ffmpeg命令 | :white_check_mark: | 支持所有的ffmpeg命令 | +| 进度回调 | :white_check_mark: | 支持所有命令的回调 | +| 命令取消 | :white_check_mark: | 支持在命令执行过程中取消命令执行 | +| debug模式 | :white_check_mark: | 支持开启/关闭调试模式 | +| 获取媒体信息 | :white_check_mark: | 获取媒体信息(宽、高...) | +| 支持GPU | :white_check_mark: | 支持MediaCodec(v1.2.3) | -* **支持所有FFmpeg命令** * **支持视频格式转换 mp4->flv** * **支持音频编解码 mp3->pcm pcm->mp3 pcm->aac** * **支持音频转码 mp3->aac mp3->amr** @@ -39,9 +59,9 @@ * **支持获取媒体文件信息** * **支持连续执行FFmpeg命令** -|执行FFmpeg|获取媒体信息| -|---------| ----------------------------------| -|图-1:命令行展示|图-2:命令行执行| +| 执行FFmpeg | 获取媒体信息 | +|----------------------------------------------------------|---------------------------------------------------------| +| 图-1:命令行展示 | 图-2:命令行执行 | ## 引入 @@ -63,9 +83,9 @@ allprojects { ```groovy // 全部编解码-体积较大 -implementation 'com.github.AnJoiner:FFmpegCommand:1.2.1' -// 部分常用编解码-体积较小,比上面引入减少大约6M -implementation 'com.github.AnJoiner:FFmpegCommand:1.2.1-lite' +implementation 'com.github.AnJoiner:FFmpegCommand:1.2.3' +// 部分常用编解码-体积较小,比上面引入减少大约5M +implementation 'com.github.AnJoiner:FFmpegCommand:1.2.3-lite' ``` 更改module下build.gradle,当前库只支持`armeabi-v7a`和`arm64-v8a`,当然也可以只使用一种(一般使用`armeabi-v7a`可以向下兼容),可以参考[【Android ABI】](https://developer.android.com/ndk/guides/abis) @@ -89,21 +109,21 @@ android { ### FFmpegCommand方法 -|方法 |功能 | -|:---|----| -|FFmpegCommand->setDebug(debug: Boolean)|Dubug模式,可打印日志| -|FFmpegCommand->runCmd(cmd: Array)|执行ffmpeg命令,无回调| -|FFmpegCommand->runCmd(cmd: Array callBack: IFFmpegCallBack?)|执行ffmpeg命令,并回调 开始,完成,取消,进度,错误| -|FFmpegCommand->getMediaInfo(path: String?, @MediaAttribute type: Int)|获取媒体信息:视频宽高、比特率...| -|FFmpegCommand->getSupportFormat(@FormatAttribute formatType: Int)|获取当前库支持的封装、解封装格式| -|FFmpegCommand->getSupportCodec(@CodecAttribute codecType: Int)| 获取当前库支持的编解码 | -|FFmpegCommand->cancel()|退出FFmpeg命令执行| +| 方法 | 功能 | +|-----------------------------------------------------------------------|-------------------------------| +| FFmpegCommand->setDebug(debug: Boolean) | Dubug模式,可打印日志调试 | +| FFmpegCommand->runCmd(cmd: Array) | 执行ffmpeg命令,无回调 | +| FFmpegCommand->runCmd(cmd: Array 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 callBack: IFFmpegCallBack?)`方法,其中第一个参数由`FFmpegUtils`工具类提供,也可以自己添加 -**不支持异步执行FFmpeg命令,毕竟C是面向过程语言,会出现资源占用问题** +**不支持异步执行FFmpeg命令** ```kotlin GlobalScope.launch { @@ -143,17 +163,31 @@ var progress = pts/duration!! 如果其中不满足需求,可添加自己的FFmpeg命令.例如: ```kotlin -var command = "ffmpeg -y -i %s -vn -acodec copy -ss %d -t %d %s" -command = String.format(command, srcFile, startTime, duration, targetFile) +val command = CommandParams() + .append("-i") + .append(srcFile) + .append("-vn") + .append("-c:a") + .append("copy") + .append("-ss") + .append(startTime) + .append("-t") + .append(duration) + .append(targetPath) + .get() GlobalScope.launch { - FFmpegCommand.runCmd(command.split(" ").toTypedArray(), callback("音频剪切完成", targetPath)) + FFmpegCommand.runCmd(command, callback("音频剪切完成", targetPath)) } +``` +最好使用`CommandParams`构建我们的命令参数,这样能保证参数不被路径中空格影响,导致命令执行不成功。也可以使用如下方式构造我们的参数 +```kotlin +val command = arrayOf("ffmpeg","-y","-i",inputPath,outputPath) ``` ### 多进程执行 -由于底层暂时无法实现多线程(毕竟C是面向过程的语言),所以如果需要在推流的同时,是无法再同时执行其他命令。 +由于底层暂时无法实现多线程,所以如果需要在推流的同时,是无法再同时执行其他命令。 为了解决这个问题,可以使用如下多进程方法: 1. 定义与主进程不同的其他进程 @@ -163,7 +197,7 @@ GlobalScope.launch { ``` 2. 在其他进程中执行推流的操作 -``` +```kotlin class FFmpegCommandService : Service() { override fun onBind(intent: Intent): IBinder? { return null @@ -171,11 +205,15 @@ class FFmpegCommandService : Service() { 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 = result.split(" ").toTypedArray() - FFmpegCommand.runCmd(strings) + val output = File(externalCacheDir, "leak.avi").absolutePath + val command = CommandParams() + .append("-i") + .append(videoPath) + .append("-b:v") + .append("600k") + .append(output) + .get() + FFmpegCommand.runCmd(command) return super.onStartCommand(intent, flags, startId) } } @@ -184,8 +222,8 @@ class FFmpegCommandService : Service() { ### 取消执行 执行下面方法后将会回调 `CommonCallBack->onCancel()` 方法 -```java -FFmpegCommand.cancel(); +```kotlin +FFmpegCommand.cancel() ``` **[【常见问题】](ffmpeg-wiki/常见问题.md)** @@ -232,7 +270,7 @@ FFmpegCommand.cancel(); ## License ``` -Copyright 2019 AnJoiner +Copyright 2019-2023 AnJoiner Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index 7439b33..4f7dfc3 100644 --- a/README.md +++ b/README.md @@ -21,8 +21,29 @@ In our development, audio and video related content is often used, generally we If you can’t access all the information, please go to[【Domestic Mirror】](https://gitee.com/anjoiner/FFmpegCommand) +## Cross Compile +* Macos 13.2 + GCC + Cmake + NDK 21 + +| 第三方库 | 版本 | 下载地址 | +|------------|--------------------|------------------------------------------------------------------------------------------------------| +| ffmpeg | 6.0 | https://ffmpeg.org/releases/ffmpeg-6.0.tar.xz | +| x264 | X264-20191217.2245 | http://download.videolan.org/pub/videolan/x264/snapshots/x264-snapshot-20191217-2245-stable.tar.bz2 | +| mp3lame | 3.100 | https://sourceforge.net/projects/lame/files/latest/download | +| fdkaac | 2.0.1-ff69b4 | https://downloads.sourceforge.net/opencore-amr/fdk-aac-2.0.1.tar.gz | +| opencore-amr | 1.1.5 | https://sourceforge.net/projects/opencore-amr/files/opencore-amr/opencore-amr-0.1.5.tar.gz | +| ndk | 21 | https://dl.google.com/android/repository/android-ndk-r21e-darwin-x86_64.zip | + ## The main function -[![](https://jitpack.io/v/AnJoiner/FFmpegCommand.svg)](https://jitpack.io/#AnJoiner/FFmpegCommand)[![License](https://img.shields.io/badge/license-Apache%202-informational.svg)](https://www.apache.org/licenses/LICENSE-2.0)[ ![FFmpeg](https://img.shields.io/badge/FFmpeg-4.2.1-orange.svg)](https://ffmpeg.org/releases/ffmpeg-4.2.1.tar.bz2)[ ![X264](https://img.shields.io/badge/X264-20191217.2245-yellow.svg)](http://download.videolan.org/pub/videolan/x264/snapshots/x264-snapshot-20191217-2245-stable.tar.bz2)[ ![mp3lame](https://img.shields.io/badge/mp3lame-3.100-critical.svg)](https://sourceforge.net/projects/lame/files/latest/download)[ ![fdk-aac](https://img.shields.io/badge/fdkaac-2.0.1-ff69b4.svg)](https://downloads.sourceforge.net/opencore-amr/fdk-aac-2.0.1.tar.gz)[ ![fdk-aac](https://img.shields.io/badge/opencoreamr-1.1.5-critical.svg)](https://sourceforge.net/projects/opencore-amr/files/opencore-amr/opencore-amr-0.1.5.tar.gz) +[![](https://jitpack.io/v/AnJoiner/FFmpegCommand.svg)](https://jitpack.io/#AnJoiner/FFmpegCommand)[![License](https://img.shields.io/badge/license-Apache%202-informational.svg)](https://www.apache.org/licenses/LICENSE-2.0)[ ![FFmpeg](https://img.shields.io/badge/FFmpeg-6.0-orange.svg)](https://ffmpeg.org/releases/ffmpeg-6.0.tar.xz)[ ![X264](https://img.shields.io/badge/X264-20191217.2245-yellow.svg)](http://download.videolan.org/pub/videolan/x264/snapshots/x264-snapshot-20191217-2245-stable.tar.bz2)[ ![mp3lame](https://img.shields.io/badge/mp3lame-3.100-critical.svg)](https://sourceforge.net/projects/lame/files/latest/download)[ ![fdk-aac](https://img.shields.io/badge/fdkaac-2.0.1-ff69b4.svg)](https://downloads.sourceforge.net/opencore-amr/fdk-aac-2.0.1.tar.gz)[ ![fdk-aac](https://img.shields.io/badge/opencoreamr-1.1.5-critical.svg)](https://sourceforge.net/projects/opencore-amr/files/opencore-amr/opencore-amr-0.1.5.tar.gz) + +| 特色功能 | 支持 | 描述 | +|------|--------------------|-------------------------------------------| +| ffmpeg命令 | :white_check_mark: | Support all FFmpeg commands | +| 进度回调 | :white_check_mark: | Support callback of ffmpeg commands | +| 命令取消 | :white_check_mark: | Support cancel the commands that is doing | +| debug模式 | :white_check_mark: | Support debug model for develop | +| 获取媒体信息 | :white_check_mark: | Support to get media info | +| 支持GPU | :white_check_mark: | Support MediaCodec of android gpu(v1.2.3) | * **Support all FFmpeg commands** * **Support video format conversion : mp4->flv** @@ -61,9 +82,9 @@ Choose only one of the following two introductions, and replace the following ac ```groovy // All codecs-larger size -implementation 'com.github.AnJoiner:FFmpegCommand:1.2.1' -// Some commonly used codecs-smaller in size, about 6M less than the introduction above -implementation 'com.github.AnJoiner:FFmpegCommand:1.2.1-lite' +implementation 'com.github.AnJoiner:FFmpegCommand:1.2.3' +// Some commonly used codecs-smaller in size, about 5M less than the introduction above +implementation 'com.github.AnJoiner:FFmpegCommand:1.2.3-lite' ``` Change build.gradle under module, the current library only supports `armeabi-v7a` and `arm64-v8a`, of course you can use only one (usually using `armeabi-v7a` for backward compatibility). You can Can refer to [【Android ABI】](https://developer.android.com/ndk/guides/abis) @@ -140,13 +161,22 @@ This is just a demonstration of audio cutting, many functions such as the above, If the requirements are not met, you can add your own FFmpeg command, E.g: ```kotlin -var command = "ffmpeg -y -i %s -vn -acodec copy -ss %d -t %d %s" -command = String.format(command, srcFile, startTime, duration, targetFile) +val command = CommandParams() + .append("-i") + .append(srcFile) + .append("-vn") + .append("-c:a") + .append("copy") + .append("-ss") + .append(startTime) + .append("-t") + .append(duration) + .append(targetPath) + .get() GlobalScope.launch { - FFmpegCommand.runCmd(command.split(" ").toTypedArray(), callback("Audio cut is complete", targetPath)) + FFmpegCommand.runCmd(command, callback("Audio cut is complete", targetPath)) } - ``` ### Multi-process execution @@ -160,7 +190,7 @@ To solve this problem, you can use the following multi-process method: ``` 2. Perform push operations in other processes -``` +```kotlin class FFmpegCommandService : Service() { override fun onBind(intent: Intent): IBinder? { return null @@ -168,11 +198,15 @@ class FFmpegCommandService : Service() { 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 = result.split(" ").toTypedArray() - FFmpegCommand.runCmd(strings) + val output = File(externalCacheDir, "leak.avi").absolutePath + val command = CommandParams() + .append("-i") + .append(videoPath) + .append("-b:v") + .append("600k") + .append(output) + .get() + FFmpegCommand.runCmd(command) return super.onStartCommand(intent, flags, startId) } } @@ -181,8 +215,8 @@ class FFmpegCommandService : Service() { ### Cancel execution After executing the following method, the `CommonCallBack->onCancel()` method will be called back -```java -FFmpegCommand.cancel(); +```kotlin +FFmpegCommand.cancel() ``` **[【common problem】](ffmpeg-wiki/常见问题.md)** @@ -229,7 +263,7 @@ If you think it is helpful to you, give a star to support it, and welcome a lot ## License ``` -Copyright 2019 AnJoiner +Copyright 2019-2023 AnJoiner Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/app/src/main/java/com/coder/ffmpegtest/service/FFmpegCommandService.kt b/app/src/main/java/com/coder/ffmpegtest/service/FFmpegCommandService.kt index 480a9b6..63a28e8 100644 --- a/app/src/main/java/com/coder/ffmpegtest/service/FFmpegCommandService.kt +++ b/app/src/main/java/com/coder/ffmpegtest/service/FFmpegCommandService.kt @@ -8,6 +8,7 @@ import android.util.Log import com.coder.ffmpeg.annotation.MediaAttribute import com.coder.ffmpeg.call.CommonCallBack import com.coder.ffmpeg.jni.FFmpegCommand +import com.coder.ffmpeg.utils.CommandParams import com.coder.ffmpegtest.utils.FileUtils import com.coder.ffmpegtest.utils.ToastUtils import kotlinx.coroutines.GlobalScope @@ -41,10 +42,15 @@ class FFmpegCommandService : IntentService("") { override fun onHandleIntent(intent: Intent?) { val videoPath = File(externalCacheDir, "test.mp4").absolutePath val output = File(externalCacheDir, "leak.avi").absolutePath - val cmd = "ffmpeg -y -i %s -b:v 600k %s" - val result = String.format(Locale.CHINA, cmd, videoPath, output) - val strings: Array = result.split(" ").toTypedArray() - FFmpegCommand.runCmd(strings, callback("测试内存抖动", output)) +// val cmd = "ffmpeg -y -i %s -b:v 600k %s" + val command = CommandParams() + .append("-i") + .append(videoPath) + .append("-b:v") + .append("600k") + .append(output) + .get() + FFmpegCommand.runCmd(command, callback("测试内存抖动", output)) } private fun callback(msg: String, targetPath: String?): CommonCallBack? { diff --git a/ffmpeg/src/main/jniLibs/arm64-v8a/libffmpeg-command.so b/ffmpeg/src/main/jniLibs/arm64-v8a/libffmpeg-command.so index a7949b7..4c6c2c4 100755 Binary files a/ffmpeg/src/main/jniLibs/arm64-v8a/libffmpeg-command.so and b/ffmpeg/src/main/jniLibs/arm64-v8a/libffmpeg-command.so differ diff --git a/ffmpeg/src/main/jniLibs/armeabi-v7a/libffmpeg-command.so b/ffmpeg/src/main/jniLibs/armeabi-v7a/libffmpeg-command.so index bdda4c9..008b3ed 100755 Binary files a/ffmpeg/src/main/jniLibs/armeabi-v7a/libffmpeg-command.so and b/ffmpeg/src/main/jniLibs/armeabi-v7a/libffmpeg-command.so differ