Android最简单的基于FFmpeg的例子(四)---以命令行的形式来使用ffmpeg
FFmpeg使用第四步,以命令行的形式来使用ffmpeg.
编译环境
- Mac OS X Capitan 10.11.3
- NDK-r10e (64-bit)
- FFmpeg 3.0
简介
在前面编译FFmpeg类库编译ffmpeg时,编译脚本中使用了参数 –disable-ffmpeg,所以是不会生成ffmpeg工具的,即使生成了,
在android应用下也无法直接使用。
但是,FFmpeg 命令行是十分强大易用的,我们可以用命令行完成大部分的需求,So,Let’s Do it.
Let’s Do it !
在编译FFmpeg成一个SO库一文中,已经将 libffmpeg.so 编译好了,这里直接复用这个文件.
Step 1: 新建工程
新建一个Android工程,在 src/main/ 目录下新建 jni 目录,如图:
编写 FFmpegKit.java 代码:
1 2 3 4 5 6 7 8 9 10 11 | package com.ihubin.ffmpegstudy; public class FFmpegKit { static{ System.loadLibrary( "ffmpeg"); System.loadLibrary( "ffmpeginvoke"); } public native static int run(String[] commands); } |
获取C语言的接口函数声明
在命令行中切换到src/main/java文件夹下,输入如下命令:
1 | javah com.ihubin.ffmpegstudy.FFmpegKit |
在 src/main/java 目录生成了 com_ihubin_ffmpegstudy_FFmpegKit.h 文件,将这个文件移动到 jni 目录.
Step 2: 拷贝文件
将编译FFmpeg成一个SO库生成的 libffmpeg.so 文件拷贝至 jni 目录.
复制FFmpeg源码文件 ffmpeg.h, ffmpeg.c, ffmpeg_opt.c, ffmpeg_filter.c,cmdutils.c, cmdutils.h, cmdutils_common_opts.h 到jni目录下.
在 jni 目录新建文件 Android.mk Application.mk com_ihubin_ffmpegstudy_FFmpegKit.c
此时,工程目录是这样的,如图:
Step 3: 代码实现
修改ffmpeg.c和ffmpeg.h
找到ffmpeg.c,把int main(int argc, char argv) 改名为 int run(int argc, char argv)
找到ffmpeg.h, 在文件末尾添加函数申明: int run(int argc, char **argv);
修改cmdutils.c 和 cmdutils.h
找到cmdutils.c中的exit_program函数,删掉函数中原来的内容, 添加 return ret;并修改函数的返回类型为int
修改前:
修改后:
找到cmdutils.h中exit_program的申明,也把返回类型修改为int。
修改前:
修改后:
在 com_ihubin_ffmpegstudy_FFmpegKit.c 中实现 com_ihubin_ffmpegstudy_FFmpegKit.h 中的方法
com_ihubin_ffmpegstudy_FFmpegKit.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | JNIEXPORT jint JNICALL Java_com_ihubin_ffmpegstudy_FFmpegKit_run (JNIEnv *env, jclass obj, jobjectArray commands){ int argc = (*env)->GetArrayLength(env, commands); char *argv[argc]; int i; for (i = 0; i < argc; i++) { jstring js = (jstring) (*env)->GetObjectArrayElement(env, commands, i); argv[i] = ( char*) (*env)->GetStringUTFChars(env, js, 0); } return run(argc, argv); } |
编写 Android.mk
Android.mk
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := ffmpeg LOCAL_SRC_FILES := libffmpeg.so include $(PREBUILT_SHARED_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := ffmpeginvoke LOCAL_SRC_FILES := com_ihubin_ffmpegstudy_FFmpegKit.c ffmpeg.c ffmpeg_opt.c cmdutils.c ffmpeg_filter.c # 这里的地址改成自己的 FFmpeg 源码目录 LOCAL_C_INCLUDES := /Users/hubin/Desktop/ffmpeg-3.0 LOCAL_LDLIBS := -llog -lz -ldl LOCAL_SHARED_LIBRARIES := ffmpeg include $(BUILD_SHARED_LIBRARY) |
编写 Application.mk 文件
Application.mk
1 2 | APP_ABI := armeabi-v7a APP_PLATFORM := android-14 |
Step 4: 编译
在命令行中定位到 src/main/jni 目录中,直接执行脚本
1 | ndk-build |
编译完成后就生成了所要的SO库文件:
做个Demo测试一下
△ Demo需要SD卡读写权限,所以先加两个权限:SD卡读写权限
1 2 | <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> |
△ Demo需要SD卡上有 input.mp4 和 input.mp3 两个文件
如果没有小文件,可以使用我提供的这两个文件:
input.mp3
input.mp4
Demo中的功能是:将input.mp4 和 input.mp3 两个文件合并成一段以input.mp3为背景音乐的 merge.mp4 文件
△ Demo运行命令行在主线程,操作文件比较大就会ANR,直接点取消别关闭,为了Demo简单,就不加异步了,需要的自己实现 3Q
MainActivity.java
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 30 31 32 33 34 35 36 37 38 | package com.ihubin.ffmpegstudy; import android.os.Environment; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Toast; import com.ihubin.ffmpeg_command_line.R; public class MainActivity extends AppCompatActivity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void run(View view){ String base = Environment.getExternalStorageDirectory().getPath(); Log.e( "PATH", base); String[] commands = new String[ 9]; commands[ 0] = "ffmpeg"; commands[ 1] = "-i"; commands[ 2] = base + "/input.mp4"; commands[ 3] = "-i"; commands[ 4] = base + "/input.mp3"; commands[ 5] = "-strict"; commands[ 6] = "-2"; commands[ 7] = "-y"; commands[ 8] = base + "/merge.mp4"; int result = FFmpegKit.run(commands); if(result == 0){ Toast.makeText(MainActivity. this, "命令行执行完成", Toast.LENGTH_SHORT).show(); } } } |
activity_main.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools= "http://schemas.android.com/tools" android:layout_width= "match_parent" android:layout_height= "match_parent" android:orientation= "vertical" tools:context= "com.ihubin.ffmpegstudy.MainActivity"> <Button android:onClick= "run" android:layout_width= "match_parent" android:layout_height= "wrap_content" android:text= "Run"/> LinearLayout> |
FFmpeg 命令行都可以执行了,还不赶紧做个App玩玩 !!
源码
源码地址在这里
Module:FFmpeg-Command-Line
Demo APK下载地址:https://www.pgyer.com/FFmpegCommandLine
也可以扫码下载体验:
来源地址:
http://www.ihubin.com/blog/android-ffmpeg-demo-4/
参考资料
- 编译可供Android使用的FFmpeg库
- Compile FFmpeg for Android
- Github FFmpegKit
更多相关文章
- C语言函数的递归(上)
- 史上最易懂的Android(安卓)jni开发资料--NDK环境搭建
- [Android(安卓)UI] shape和selector的结合使用
- Android(安卓)多渠道打包提速
- [Android(安卓)Studio] Gradle fails to resolve dependencies i
- Android关于Dex拆分 MultiDex 技术详解
- mac平台adb、tcpdump捕手android移动网络数据包
- Android(安卓)install apk 兼容至 Android(安卓)8
- Android: 如何打开assets or raw文件夹下的数据库文件