http://www.ihubin.com/blog/android-ffmpeg-demo-4/
编译环境
- 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
|
#include <stdio.h>
#include "com_ihubin_ffmpegstudy_FFmpegKit.h"
#include "ffmpeg.h"
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
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 目录中,直接执行脚本
编译完成后就生成了所要的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 {
@Override
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
也可以扫码下载体验:
参考资料