android ffmpeg 优点_在Android中使用FFmpeg(android studio环境)
1.首先我们需要一个已经编译好的libffmpeg.so文件。(怎么编译是个大坑,可以参考windows环境下编译android中使用的FFmpeg,也可以用网上下载的现成的,本文相关的github项目里也有。),当然也要下载好ffmpeg的源码,一会要用到。
2.打开你的Android工程,在 src/main/ 目录下新建 jni 目录。并将libffmpeg.so文件丢进去。
3.创建FFmpegKit.java。写入如下代码
package codepig.ffmpegcldemo;
import android.os.AsyncTask;
public class FFmpegKit {
public interface KitInterface{
void onStart();
void onProgress(int progress);
void onEnd(int result);
}
static{
System.loadLibrary("ffmpeg");
System.loadLibrary("ffmpeginvoke");
}
public static int execute(String[] commands){
return run(commands);
}
public static void execute(String[] commands, final KitInterface kitIntenrface){
new AsyncTask(){
@Override
protected void onPreExecute() {
if(kitIntenrface != null){
kitIntenrface.onStart();
}
}
@Override
protected Integer doInBackground(String[]... params) {
return run(params[0]);
}
@Override
protected void onProgressUpdate(Integer... values) {
if(kitIntenrface != null){
kitIntenrface.onProgress(values[0]);
}
}
@Override
protected void onPostExecute(Integer integer) {
if(kitIntenrface != null){
kitIntenrface.onEnd(integer);
}
}
}.execute(commands);
}
public native static int run(String[] commands);
}
这个是用来调用ffmpeg可执行文件的。
4.在终端中切到src/main/java文件夹下,输入:
javah codepig.ffmpegcldemo.FFmpegKit
(这里注意你自己的文件的实际位置)
然后就会在该目录生成 codepig_ffmpegecldemo_FFmpegKit.h 文件,将这个文件移动到 jni 目录。
5.复制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 codepig_ffmpegcldemo_FFmpegKit.c。
6.编辑ffmpeg.c,把
int main(int argc, char **argv)
改名为
int run(int argc, char **argv)
编辑ffmpeg.h, 在文件末尾添加函数申明:
int run(int argc, char **argv)
7.编辑cmdutils.c中的exit_program函数,删掉函数中原来的内容, 添加 return ret;并修改函数的返回类型为int。
长这样:
int exit_program(int ret)
{
return ret;
}
编辑cmdutils.h中exit_program的申明,把返回类型修改为int。
长这样:
int exit_program(int ret);
8.在 codepig_ffmpegcldemo_FFmpegKit.c 中实现 codepig_ffmpegcldemo_FFmpegKit.h 中的方法。
#include
#include "codepig_ffmpegcldemo_FFmpegKit.h"
#include "ffmpeg.h"
#include "logjam.h"
JNIEXPORT jint JNICALL Java_codepig_ffmpegcldemo_FFmpegKit_run
(JNIEnv *env, jclass obj, jobjectArray commands){
//FFmpeg av_log() callback
int argc = (*env)->GetArrayLength(env, commands);
char *argv[argc];
LOGD("Kit argc %d\n", 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);
LOGD("Kit argv %s\n", argv[i]);
}
return run(argc, argv);
}
9.编辑Android.mk
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 := codepig_ffmpegcldemo_FFmpegKit.c ffmpeg.c ffmpeg_opt.c cmdutils.c ffmpeg_filter.c
LOCAL_C_INCLUDES := F:/demo/ffmpeg-3.0
LOCAL_LDLIBS := -llog -lz -ldl
LOCAL_SHARED_LIBRARIES := ffmpeg
include $(BUILD_SHARED_LIBRARY)
其中LOCAL_C_INCLUDES的值为ffmpeg源码文件夹地址
10.编辑Application.mk 文件
APP_ABI := armeabi-v7a
APP_PLATFORM := android-17
其中APP_ABI的值是支持的cpu类型。要支持多种cpu的话,可以把类型写一起用空格隔开,比如
APP_ABI := armeabi-v7a x86
11.在终端中定位到jni目录,执行ndk -build
成功后就会在libs文件夹生成相应的libffmpeg.so和libffmpeginvoke.so文件。这些so文件就是最终我们用来调用的FFmpeg可执行文件。
如果出现如下错误提示
Android NDK: Could not find application project directory !
Android NDK: Please define the NDK_PROJECT_PATH variable to point to it.
则在Application.mk文件中添加
APP_BUILD_SCRIPT := Android.mk
如果出现如下提示
Android NDK: Your Android application project path contains spaces: 'F:/qzd android/Android/workspace/'
Android NDK: The Android NDK build cannot work here. Please move your project to a different location.
那大约是因为项目所在文件夹名称有空格。改名就好了(感觉好弱鸡)
12.在build.gradle文件中修改下库文件地址的指向
android {
sourceSets {
main {
jniLibs.srcDirs = ['src/main/libs']
jni.srcDirs=[]
}
}
}
现在终于可以在android中使用ffmpeg库了。
13.举个栗子
(以下例子里的videoUrl是原始视频文件地址,imageUrl是水印图片地址,musicUrl是音频mp3地址,outputUrl是最终输出视频地址。)
(1) 给视频添加图片水印:
Runnable compoundRun=new Runnable() {
@Override
public void run() {
String[] commands = new String[10];
commands[0] = "ffmpeg";
commands[1] = "-i";
commands[2] = videoUrl;
commands[3] = "-i";
commands[4] = imageUrl;
commands[5] = "-filter_complex";
commands[6] = "overlay=(main_w-overlay_w)/2:(main_h-overlay_h)/2";
commands[7] = "-codec:a";
commands[8] = "copy";
commands[9] = outputUrl;
FFmpegKit.execute(commands, new FFmpegKit.KitInterface() {
@Override
public void onStart() {
Log.d("FFmpegLog LOGCAT","FFmpeg 命令行开始执行了...");
}
@Override
public void onProgress(int progress) {
Log.d("FFmpegLog LOGCAT","done com"+"FFmpeg 命令行执行进度..."+progress);
}
@Override
public void onEnd(int result) {
Log.d("FFmpegLog LOGCAT","FFmpeg 命令行执行完成...");
}
});
}
};
ThreadPoolUtils.execute(compoundRun);
(2) 合成音频视频
Runnable compoundRun=new Runnable() {
@Override
public void run() {
String[] commands = new String[6];
commands[0] = "ffmpeg";
commands[1] = "-i";
commands[2] = videoUrl;
commands[3] = "-i";
commands[4] = musicUrl;
commands[5] = outputUrl;
FFmpegKit.execute(commands, new FFmpegKit.KitInterface() {
@Override
public void onStart() {
Log.d("FFmpegLog LOGCAT","FFmpeg 命令行开始执行了...");
}
@Override
public void onProgress(int progress) {
Log.d("FFmpegLog LOGCAT","done com"+"FFmpeg 命令行执行进度..."+progress);
}
@Override
public void onEnd(int result) {
Log.d("FFmpegLog LOGCAT","FFmpeg 命令行执行完成...");
// getWindow().setFlags(0, WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
// Message msg = new Message();
// msg.what = 1;
// mHandler.sendMessage(msg);
}
});
}
};
ThreadPoolUtils.execute(compoundRun);
(3)把这两个命令写一起
Runnable compoundRun=new Runnable() {
@Override
public void run() {
String[] commands = new String[11];
commands[0] = "ffmpeg";
commands[1] = "-i";
commands[2] = videoUrl;
commands[3] = "-i";
commands[4] = imageUrl;
commands[5] = "-filter_complex";
commands[6] = "overlay=(main_w-overlay_w)/2:(main_h-overlay_h)/2";
commands[7] = "-i";
commands[8] = musicUrl;
commands[9] = "-y";
commands[10] = outputUrl;
FFmpegKit.execute(commands, new FFmpegKit.KitInterface() {
@Override
public void onStart() {
Log.d("FFmpegLog LOGCAT","FFmpeg 命令行开始执行了...");
}
@Override
public void onProgress(int progress) {
Log.d("FFmpegLog LOGCAT","done com"+"FFmpeg 命令行执行进度..."+progress);
}
@Override
public void onEnd(int result) {
Log.d("FFmpegLog LOGCAT","FFmpeg 命令行执行完成...");
// getWindow().setFlags(0, WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
});
}
};
ThreadPoolUtils.execute(compoundRun);
附:ffmpeg命令格式简要说明
基本形式:
ffmpeg -i inputFile -参数名 参数值 …… outputFile;
头尾不变,中间的参数顺序无所谓。但是一个操作的参数必须写一起。
参数是以 -参数名+参数值 这样的成对形式赋值。
android ffmpeg 优点_在Android中使用FFmpeg(android studio环境)相关推荐
- android phone驱动_一文带你掌握 Android 系统架构
引言 本文作为Android系统架构的开篇,起到提纲挈领的作用,从系统整体架构角度概要讲解Android系统的核心技术点,带领大家初探Android系统全貌以及内部运作机制.虽然Android系统非常 ...
- android 指纹添加_如何将手势添加到Android手机的指纹扫描仪
android 指纹添加 So you have a shiny new Android phone, equipped with a security-friendly fingerprint sc ...
- ios和android区别是什么,app测试中ios和Android的区别:
今天偶然看到一个面试题,安卓和ios的测试区别,一下子只能想到几个基础的点,后面百度了一下,答案简单记录一下. app测试中ios和Android的区别: 1.安卓手机针对每一款手机有不一样的操作:苹 ...
- python调用os.system启动anaconda环境_在Mac中PyCharm配置python Anaconda环境过程图解
在 python 开发中我们最常用的IDE就是PyCharm,有关PyCharm的优点这里就不在赘述.在项目开发中我们经常用到许多第三方库,用的最多的命令就是pip install 第三方库名 进行安 ...
- android mkdir失败_在/ sdcard中创建目录失败
将Android手机更新为6.0(API级别23)后,我遇到了同样的问题.以下解决方案对我有效.希望它也对您有帮助. 请检查您的Android版本.如果> = 6.0(API级别23),则不仅需 ...
- android ffmpeg 静态库,在CentOS中编译FFmpeg for Android静态库(含fdk aac,x264)
本文可以编译出集成了x264和fdk_aac的库,而且支持neon 下载源码: fdk_aac目前最新版是0.1.4,详见其ChangeLog,此处用的是0.1.1版 ffmpeg-2.7.2 解压后 ...
- android获取ro._抖音数据采集教程,Android群控黑盒调用,Sekiro使用手册
抖音数据采集教程,Android群控黑盒调用,Sekiro使用手册 0x0 前言 之前尝试用过virjar大佬的hermesagent, 后来大佬又迭代出新的基于长链接的Sekiro, 一直想看都被耽 ...
- python中使用函数的优点_在python中使用自定义初始化函数而不是`__init__`的好处...
野外的一些API(例如setuptools内部)有类似的东西,他们使用它们的优势. __init__调用可以用于低级内部API,而公共构造函数被定义为类方法,用于构造对象的不同方式.例如,在 pkg_ ...
- php ffmpeg截取视频文件,PHP中使用ffmpeg截取视频图片笔记
网上很多介绍的文章乱七八糟,说什么装扩展,还得编译... 等等都是些垃圾. 实现截取视频的封面图片简单的很,只需要3步: 1. 安装ffmpeg软件(什么系统都有对应的安装包),2.PHP中compo ...
最新文章
- matlab求矩阵均值向量,如何求一个矩阵的均值向量
- java 检查pos机状态_POS机故障大全及排查方法
- 二、MySQL连接查询学习笔记(多表连接查询:内连接,外连接,交叉连接详解)
- 树莓派安装mosquitto提示“MOSQ_1.5” not found
- android gradle abi mips x86,NDK android Error:Expected caller to ensure valid ABI: MIPS
- shared memory global memory constant memory in cuda
- java import的作用_Java技术_Java千百问(0030)_package和import作用是什么
- win10系统如何安装Oracle 10G
- linux mysql 备份 压缩_Linux下mysql定时备份压缩
- 现代控制理论4——线性系统状态方程的解
- 元宇宙iwemeta:《时代》杂志新封面,元宇宙将改变一切
- blankcount函数python,统计函数第五讲:计数函数COUNT和COUNTBLANK
- 医学图像分割——Unet
- leetcode:买卖股票的最佳时机2(python)
- Eclipse版本代号
- 在线PHP源码混淆、加密
- AJAX 聊天室实现原理终极解析
- 数显之家快讯:【SHIO世硕心语】华为内部考核尺度爆光!
- PSP开发简明教程(2)
- 导出数据库表信息生成Word文档(数据字典)
热门文章
- Linux下实现多线程异步管道
- Unix/Linux 目录结构的来历
- QQ炫舞登录完后服务器没显示,qq炫舞进入界面后就没有了怎么回?
- python2.7更新pip_CentOS升级Python2.6到Python2.7并安装pip
- 网站如何进行渠道跟踪_网站前期要如何进行SEO优化?
- es6 string includes_蔚来初体验,蔚来ES6用车日记!开着挺轻松的
- c语言中根据数据的组织形式 把文件分为,根据数据的组织形式,C中将文件分为______________和____________.._简答题试题答案...
- 18100出多少取整_关于JavaScript数据类型,你知道多少?
- mysql engine 和type_type=INNODB和engine=INNODB的区别
- java 注入日志_java框架学习日志-5(常见的依赖注入)