0. 前言

ffmpeg命令很强大,但是在Android工程中无法执行可执行文件ffmpeg,即无法使用ffmpeg。 
本文介绍把ffmpeg改造成库文件,然后通过JNI调用它,即可实现在Java中使用ffmpeg命令。

PS: 
本工程依赖于前文Android 编译FFmpeg x264。

1. ffmpeg

1.1 main to run

(1)ffmpeg.h 
进入ffmpeg源代码,修改ffmpeg.h,在文件中添加一下代码:

#ifdef FFMPEG_RUN_LIB
int run(int argc, char** argv);
#endif
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

(2)ffmpeg.c 
修改ffmpeg.c 

int main(int argc, char** argv)
  • 1
  • 1

替换为

#ifdef FFMPEG_RUN_LIB
int run(int argc, char **argv)
#else
int main(int argc, char** argv)
#endif
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

1.2 ffmpeg cleanup

ffmpeg 在清理阶段虽然把各个变量释放掉了,但是并没有将其置为null,会出现问题。 
修改ffmpeg_cleanup函数,具体修改方法就是当调用av_freep函数后,在把变量设置为NULL。部分代码如下:

2. 修复直接退出进程

如果只完成上面修改的话,在执行ffmpeg命令会直接结束,因为原始工程作为一个进程,运行结束会进行垃圾回收,以及结束进程。 
解决方法:

找到cmdutils文件,用longjmp替换exit方法

具体操作如下: 
(1)修改cmdutils.c 
在文件include代码块底部添加一下代码:

#ifdef FFMPEG_RUN_LIB
#include <setjmp.h>
extern jmp_buf jmp_exit;
#endif
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

找到并修改exit_program函数:

void exit_program(int ret)
{if (program_exit)program_exit(ret);#ifdef FFMPEG_RUN_LIBav_log(NULL, AV_LOG_INFO, "exit_program code : %d\n", ret);longjmp(jmp_exit, ret);
#elseexit(ret);
#endif
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

(2)修改ffmpeg.c 

exit()
  • 1
  • 1

函数替换为

exit_program()
  • 1
  • 1

(3) 添加ffmpeg_cmd文件

ffmpeg_cmd.h

//
// Created by Taylor Guo on 16/6/24.
//#ifndef FFMPEG_BUILD_LIB_FFMPEG_MAIN_H
#define FFMPEG_BUILD_LIB_FFMPEG_MAIN_Hint run_cmd(int argc, char** argv);#endif //FFMPEG_BUILD_LIB_FFMPEG_MAIN_H
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

ffmpeg_cmd.c

//
// Created by Taylor Guo on 16/6/24.
//#include <setjmp.h>#include "ffmpeg_cmd.h"
#include "ffmpeg.h"
#include "cmdutils.h"jmp_buf jmp_exit;int run_cmd(int argc, char** argv)
{int res = 0;if(res = setjmp(jmp_exit)){return res;}res = run(argc, argv);return res;
}
  • 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
  • 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

3. JNI接口

3.1 JAVA

(1)加载库 
(2)函数接口

public class FFmpegCmd {public static final String TAG = "FFmpegUtils";public static final int R_SUCCESS = 0;public static final int R_FAILED = -1;private static final String STR_DEBUG_PARAM = "-d";public static boolean mEnableDebug = false;static {System.loadLibrary("ffmpeg");System.loadLibrary("ffmpeg_cmd");}public native static int run(String[] cmd);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

3.2 Native

(1)ffmpeg_cmd_wrapper.h

//
// Created by Taylor Guo on 16/6/24.
//#ifndef FFMPEG_BUILD_LIB_FFMPEG_MAIN_H
#define FFMPEG_BUILD_LIB_FFMPEG_MAIN_H#include"jni.h"#ifdef __cplusplus
extern "C" {
#endif/** Class:     org_wi_androidffmpeg_FFmpegCmd* Method:    run* Signature: ([Ljava/lang/String;)I*/JNIEXPORT jint
JNICALL Java_org_wi_androidffmpeg_FFmpegCmd_run(JNIEnv *env, jclass obj, jobjectArray commands);#ifdef __cplusplus
}
#endif#endif //FFMPEG_BUILD_LIB_FFMPEG_MAIN_H
  • 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
  • 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

(2)ffmpeg_cmd_wrapper.c

//
// Created by Taylor Guo on 16/6/24.
//#include "ffmpeg_cmd.h"
#include "ffmpeg_cmd_wrapper.h"
#include "jni.h"#ifdef __cplusplus
extern "C" {
#endifJNIEXPORT jint
JNICALL Java_org_wi_androidffmpeg_FFmpegCmd_run(JNIEnv *env, jclass obj, jobjectArray commands)
{int argc = (*env)->GetArrayLength(env, commands);char *argv[argc];jstring jstr[argc];int i = 0;;for (i = 0; i < argc; i++){jstr[i] = (jstring)(*env)->GetObjectArrayElement(env, commands, i);argv[i] = (char *) (*env)->GetStringUTFChars(env, jstr[i], 0);//CGE_LOG_INFO("argv[%d] : %s", i, argv[i]);}int status = run_cmd(argc, argv);for (i = 0; i < argc; ++i){(*env)->ReleaseStringUTFChars(env, jstr[i], argv[i]);}return status;
}
#ifdef __cplusplus
}
#endif
  • 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
  • 39
  • 40
  • 41
  • 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
  • 39
  • 40
  • 41

5. 编译

修改Android.mk文件,在文件末尾添加:

###############################
#libffmpeg_main
###############################
include $(CLEAR_VARS)FFMPEG_ROOT=../ffmpeg
LOCAL_C_INCLUDES := $(FFMPEG_ROOT) \LOCAL_MODULE := ffmpeg_cmd
LOCAL_SRC_FILES :=  \ffmpeg_cmd.c \ffmpeg_cmd_wrapper.c \$(FFMPEG_ROOT)/cmdutils.c \$(FFMPEG_ROOT)/ffmpeg.c \$(FFMPEG_ROOT)/ffmpeg_opt.c \$(FFMPEG_ROOT)/ffmpeg_filter.cLOCAL_LDLIBS := -llog -lz -ldl
LOCAL_SHARED_LIBRARIES := libffmpegLOCAL_CFLAGS := -march=armv7-a -mfloat-abi=softfp -mfpu=neon -O3 -ffast-math -funroll-loops -DFFMPEG_RUN_LIB -DLOG_TAG=\"FFMPEG\"include $(BUILD_SHARED_LIBRARY)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

6. ffmpeg命令测试代码

(1)这里写一个简单的程序用于测试ffmpeg命令,具体功能是:

通过调用ffmpeg命令实现音视频混合,ffmpeg对应命令为:

ffmpeg -i test.mp4 -i test.mp3 -vcodec copy -acodec aac -map 0:v:0 -map 1:a:0 -shortest mix_test.mp4
  • 1
  • 1

程序如下:

/*** Muxing video stream and audio stream.* This interface is quite complex which is only for adding audio effect.** @param srcVideoName      Input video file name.* @param fvVolume          Input video volume, should not be negative, default is 1.0f.* @param srcAudioName      Input audio file name.* @param faVolume          Input audio volume, should not be negative, default is 1.0f.* @param desVideoName      Output video file name.* @param callback          Completion callback.** @return Negative : Failed*         else : Success.*/public static int mixAV(final String srcVideoName, final float fvVolume, final String srcAudioName, final float faVolume,final String desVideoName, final OnCompletionListener callback) {if (srcAudioName == null || srcAudioName.length() <= 0|| srcVideoName == null || srcVideoName.length() <= 0|| desVideoName == null || desVideoName.length() <= 0) {return R_FAILED;}Runnable runnable = new Runnable() {@Overridepublic void run() {ArrayList<String> cmds = new ArrayList<String>();cmds.add("ffmpeg");cmds.add("-i");cmds.add(srcVideoName);cmds.add("-i");cmds.add(srcAudioName);//Copy Video Streamcmds.add("-c:v");cmds.add("copy");cmds.add("-map");cmds.add("0:v:0");//Deal With Audio Streamcmds.add("-strict");cmds.add("-2");if (fvVolume <= 0.001f) {//Replace audio streamcmds.add("-c:a");cmds.add("aac");cmds.add("-map");cmds.add("1:a:0");cmds.add("-shortest");if (faVolume < 0.99 || faVolume > 1.01) {cmds.add("-vol");cmds.add(String.valueOf((int) (faVolume * 100)));}} else if (fvVolume > 0.001f && faVolume > 0.001f){//Merge audio streamscmds.add("-filter_complex");cmds.add(String.format("[0:a]aformat=sample_fmts=fltp:sample_rates=48000:channel_layouts=stereo,volume=%f[a0]; " +"[1:a]aformat=sample_fmts=fltp:sample_rates=48000:channel_layouts=stereo,volume=%f[a1];" +"[a0][a1]amix=inputs=2:duration=first[aout]", fvVolume, faVolume));cmds.add("-map");cmds.add("[aout]");} else {Log.w(TAG, String.format(Locale.getDefault(), "Illigal volume : SrcVideo = %.2f, SrcAudio = %.2f",fvVolume, faVolume));if (callback != null) {callback.onCompletion(R_FAILED);}return;}cmds.add("-f");cmds.add("mp4");cmds.add("-y");cmds.add("-movflags");cmds.add("faststart");cmds.add(desVideoName);if (mEnableDebug) {cmds.add(STR_DEBUG_PARAM);}String[] commands = cmds.toArray(new String[cmds.size()]);int result = FFmpegCmd.run(commands);if (callback != null) {callback.onCompletion(result);}}};new Thread(runnable).start();return R_SUCCESS;}public interface OnCompletionListener {void onCompletion(int result);}
  • 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
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 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
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103

(2)Activity:

package org.wi.androidffmpeg;import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;import java.io.File;public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}public void run(View view) {Log.d("MainActivity", "MIX AV...");FFmpegCmd.setEnableDebug(true);String folder = Environment.getExternalStorageDirectory().getPath();if (folder == null || folder.length() <=0) {return;}folder += "/libCGE";FFmpegCmd.mixAV(folder + "/MediaResource/test.mp4", 1.0f,folder + "/MediaResource/test.mp3",0.7f, folder + "/new_mix.mp4", new FFmpegCmd.OnCompletionListener() {@Overridepublic void onCompletion(int result) {Log.d("MainActivity", "MIX AV Finish : " + result);}});}
}
  • 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
  • 39
  • 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
  • 39

(3)运行结果: 

7. 项目源码

AndroidFFmpeg

Android Java调用ffmpeg命令相关推荐

  1. java命令截图,GitHub - xuege-cn/fmj: FMJ (FFMpeg for Java)。通过Java调用FFMpeg命令的方式来对音视频进行处理(获取信息、截图等等)。...

    项目介绍 FMJ (FFMpeg for Java) 通过Java调用FFMpeg命令的方式来对音视频进行处理(获取信息.截图等等). FFMpeg安装 建议使用 ffmpeg-2.6.1 版本 Li ...

  2. 使用java调用ffmpeg命令将视频分屏并音视频同时播放(二分屏)

    实现想法 使用ffmpeg命令中的filter_complex(滤镜)参数来进行展示 引入javacv版本 <dependency><groupId>org.bytedeco& ...

  3. 在Android项目中调用FFmpeg命令

    概述 FFmpeg,命令行非常强大.在PC机上,调用一行FFmpeg命令,就可以对视频文件进行剪切.合并.转码等功能.本文将介绍如何在Android中调用FFmpeg命令行. 编译 前面已经有两篇文章 ...

  4. 流媒体方案,技术开源项目,包含Java调用FFMpeg(FFCH4J),推拉流服务器,nginx-http-flv-module,ckplayer,Flv.js,EasyPlayer.js集成

    文章目录 streaming_media 介绍 ckplayer拉流播放 软件介绍 功能介绍 软件架构 安装教程 使用说明 EasyPlayer.js拉流播放 简介 功能说明 集成使用示例 普通集成 ...

  5. java调用FFmpeg实现视屏压缩

    前言 最近做人脸识别,对于过大的视屏(10M)以上,识别失败的几率比较大.找了下相关的视屏压缩资料.首先使用的是jave进行视屏压缩,但是踩坑失败,jave中有转码的过程,虽然压缩成功,各种压缩参数也 ...

  6. java rtmp_搭建rtmp直播流服务之2:使用java实现ffmpeg命令接口化调用(用java执行ffmpeg命令)...

    一.环境搭建 1.安装ffmpeg 下载对应系统的ffmpeg安装包,个人采用windows平台进行开发,所以安装了windows版本(各平台ffmpeg命令都是一样的,无须纠结) 2.ffmpeg的 ...

  7. android java调用_关于Android中Java调用外部命令的三种方式

    此所谓三种方式,只是个人认为.本人还是菜鸟初涉,所以有所错误,请指正. 个人认为,Java调用外部命令.无非三种情况: 一.是只执行命令,不考虑返回值. 二.是执行命令的同时,还需要得到返回值. 三. ...

  8. Android录屏并利用FFmpeg转换成gif(三) 在Android中使用ffmpeg命令

    Android录屏并利用FFmpeg转换成gif(三) 写博客时经常会希望用一段动画来演示app的行为,目前大多数的做法是在电脑上开模拟器,然后用gif录制软件录制模拟器屏幕,对于非开发人员来讲这种方 ...

  9. mysql+视频文件转成流_详解java调用ffmpeg转换视频格式为flv

    详解java调用ffmpeg转换视频格式为flv 注意:下面的程序是在Linux下运行的,如果在windows下rmvb转换成avi会出现问题,想成功需要下载下个drv43260.dll东西放到C:W ...

最新文章

  1. SwfUpload及imgareaselect使用方法
  2. Dancing Stars on Me HDU - 5533
  3. python编程制作接金币游戏_pygame学习笔记(6):完成一个简单的游戏
  4. sharedPreferences的用法
  5. 如何在三个月内获得三年的工作经验
  6. WDS部署服务所用的PXE引导文件
  7. 来自于51CTO的经典学习资料汇总
  8. centos7.x表安装iptables防火墙
  9. MS17010漏洞利用总结
  10. js下载视频(mp4格式)
  11. 破解有道翻译反爬虫机制
  12. intellij idea 插件 开发 新加的mainmenu不显示
  13. 搜狗二季度财报解读:有扎实的现在,也有性感的未来
  14. 【Excel】Excel读取数据时,提示“服务器连接异常”
  15. 微信游戏奇迹暖暖选取服务器失败,奇迹暖暖微信怎么登录失败
  16. X280 工业4g路由器
  17. 计算机视觉(视频追踪检测分类、监控追踪)常用测试数据集
  18. win7 如何锁定计算机,Win7系统如何锁定计算机
  19. 全息投影马戏团,好有爱的科技呀~
  20. 5、TWS API的故障排除和支持

热门文章

  1. Application_Start 不执行
  2. linux使用---automake学习(从原理到实践,一步步完成automake)
  3. pythongui界面实例_wxPython:python首选的GUI库实例分享(5)
  4. 安装go client调用Kubernetes API
  5. 汇编 第二章 寄存器
  6. Java面试常见各种概念区别比较
  7. linux yum 命令 详解
  8. jquery版瀑布流
  9. CDOJ 28 补兵(kill)
  10. 分布式计算、网格计算和云计算