Android 接入FFmpeg命令-低成本完成各类音视频操作
xsobi 2024-12-25 16:14 46 浏览
一、导入资源和编译
1.1、导入相关源文件
FFmpge源码下有一个fftools目录,里面就是一些ffmpeg的命令行程序,我们将他们导入进来,进行一定的修改后再自行编译成我们的lib。
首先是对库文件进行相应的修改,因为ffmpeg.c在windows上的目的是编译成一个可执行的应用,所以它的入口是main 通过命令行传参,所以我们这里需要把main函数改一下,改成一个我们具体功能的名字,例如我喜欢叫它exc,然后再再头文件中声明我们刚改的函数名,这样它就变成了一个库文件。我们在jni的地方调用exc进行传参,就达到了电脑端命令行的效果。
还有一个地方,ffmpeg如果指令执行出错是执行的退出程序指令,我们在Android端肯定不行,那不然指令执行不成功就一个闪退这谁都顶不住,所以我们需要把exit_program函数的exit(ret);去掉,这里我们可以做我们自己的逻辑,进行自己的错误码回调。
【更多音视频学习资料,点击下方链接免费领取↓↓,先码住不迷路~】
原代码
void exit_program(int ret)
{
if (program_exit)
program_exit(ret);
exit(ret);
}
修改后
void exit_program(int ret)
{
if (program_exit)
program_exit(ret);
}
编译过程中发现会有些库丢失,可以删掉也可以把库引进来.主要看这些库是否是你所需要的功能,例如有些是一些打印函数缺失的我不需要我就直接删掉也懒得导包了。
1.2、cmdkelist的编写
首先是引入头文件目录 以我的文件目录为例我的为 include_directories(ffmpeg/fftools),后续的依赖完整如下:
add_library( # Sets the name of the library.
ffmpeg-cmd
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
ffmpeg/fftools/cmdutils.c
ffmpeg/fftools/ffmpeg.c
ffmpeg/fftools/ffmpeg_opt.c
ffmpeg/fftools/ffmpeg_filter.c
ffmpeg/fftools/ffmpeg_hw.c
ffmpeg-cmd.c
)
target_link_libraries( # Specidefies the target library.
ffmpeg-cmd
# Links the target library to the log library
# included in the NDK.
fdk-aac
mp3lame
avdevice
postproc
avfilter
avformat
avcodec
avutil
swresample
swscal
)
cmdutils.c、ffmpeg.c、ffmpeg_opt.c、ffmpeg_filter.c、ffmpeg_hw.c、ffmpeg-cmd.c都有一定的依赖关系,这几个C文件共同编译成一个库ffmpeg-cmd,ffmpeg-cmd是我的JNI层方法,负责双边沟通,fftools中依赖了其它例如解码,滤镜,重采样等外部库,也是我们之前编译了的其它库,我们需要把它们作为ffmpeg-cmd的库链接进去。
二、加入执行回调
对于命令的执行很多时候是一个耗时操作,我们UI不可能在那里干等,所以我们需要给命令执行加入回调,告诉Java层指令的执行状态,好做一些进度的变更,成功或失败的处理。最基本的我们给指令执行加入进度,失败,成功的回调。
2.1、执行进度回调
ffmpeg.c里有一个print_report方法,里面主要是一个它自身进度的打印,我们看其中一段主要代码
【更多音视频学习资料,点击下方链接免费领取↓↓,先码住不迷路~】
static void print_report(int is_last_report, int64_t timer_start, int64_t cur_time)
{
......
secs = FFABS(pts) / AV_TIME_BASE;
us = FFABS(pts) % AV_TIME_BASE;
mins = secs / 60;
secs %= 60;
hours = mins / 60;
mins %= 60;
hours_sign = (pts < 0) ? "-" : "";
//program_progress(secs); //本身没有,这是我们自己加的,这是简单逻辑,可以自己再写逻辑
bitrate = pts && total_size >= 0 ? total_size * 8 / (pts / 1000.0) : -1;
speed = t != 0.0 ? (double)pts / AV_TIME_BASE / t : -1;
......
}
在这里它计算出了已经执行完成的文件时长,同样的我们传入函数指针,把这个时长传到Java层,稍加计算就能得到我们需要的进度。
//ffmpeg.h
/**
* Register a register_progress.
*/
void register_progress(void (*cb)(long progress));
//ffmpeg.c
static void (*program_progress)(long progress);
void register_progress(void (*cb)(long progress))
{
program_progress = cb;
}
2.1、执行成功/失败回调
不管成功还是失败,ffmpeg都会走void exit_program(int ret) 方法,它自身会先走一个ffmpeg_cleanup方法,做一些他自己的收尾工作。我们可以在它自身方法的后面插入我们自己的回调方法,就是我们自己传入一个函数指针,其实就是我们重写一个相同签名的方法然后把这个方法的地址传过去,程序自己进行地址切换,跳转执行。回调0表示成功,回调其它表示失败。
//cmdutils.h
/**
* Register a register_status.
*/
void register_status(void (*cb)(int ret));
//cmdutils.c
static void (*program_status)(int ret);
void register_status(void (*cb)(int ret))
{
program_status = cb;
}
void exit_program(int ret)
{
if (program_exit)
program_exit(ret);
if (program_status)//加入我们的状态回调
program_status(ret);
}
使用时我们把这两个函数指针传进去即可。执行一段命令就会有进度和状态的回调,我们可以把它展示到UI上。
static void exit_call(int ret){
LOGE("exit_call %d", ret);
}
static void cmd_progress(long progress){
LOGE("onProgress %d", progress);
}
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved){
JNIEnv* jniEnv= NULL;
int result=(*vm)->GetEnv((vm),(void **)&jniEnv,JNI_VERSION_1_4);
if (result!=JNI_OK){
return -1;
}
av_log_set_callback(log_callback_test2);
register_status(exit_call);//传入函数指针
register_progress(cmd_progress);//传入函数指针
return JNI_VERSION_1_4;
}
三、常见音频操作命令
当然命令还是得看FFmpeg官方文档,但是官方有些好像并没有中文文档,大家可以找找中文翻译的。我这里列出几个我在用的一些命令,包括音频操作和音频滤镜,其余的大家可以自由发挥。
//在任意位置混音
//"ffmpeg -i %s -i %s -filter_complex " +"[1]adelay=delays=%s|%s[aud1];[0][aud1]amix=inputs=2 -y %s";
/**
* 音频操作
*/
//裁剪
private final String cropCmd="ffmpeg -i %s -ss %s -t %s -acodec copy %s";
//pcm转MP3
private final String pcm2Mp3="ffmpeg -f s16le -ar 44100 -ac 2 -i %s -ar 44100 -ac 2 -y %s";
//静音移除 大于间隔0.3s的静音全部移除
private final String muteRemove="ffmpeg -i %s -af silenceremove=stop_periods=-1:stop_duration=0.3:stop_threshold=-30dB %s";
private final String highPassCmd="ffmpeg -i %s -af highpass=300 %s";//低切300 150 75
private final String gateCmd="ffmpeg -i %s -filter agate=knee=1:ratio=1.5:range=0.08 %s";//降噪
/**
* chorus例子
* 一个延迟(二人合唱效果):
* chorus=0.7:0.9:55:0.4:0.25:2
* 2个延迟(三人合唱效果):
* chorus=0.6:0.9:50|60:0.4|0.32:0.25|0.4:2|1.3
* 3个延迟(四人及更多合唱效果):
* chorus=0.5:0.9:50|60|40:0.4|0.32|0.3:0.25|0.4|0.3:2|2.3|1.3
*/
private final String chorusCmd="ffmpeg -i %s -filter chorus=0.6:0.9:50|60:0.4|0.32:0.25|0.4:2|1.3 %s";//三人合唱效果 没什么效果
/**
* 滤镜
*/
private final String echoMountainCmd="ffmpeg -i %s -filter aecho=0.8:0.9:1000:0.3 %s";//山间回音特效
private final String echoRobotCmd="ffmpeg -i %s -filter aecho=0.8:0.88:6:0.4 %s";//机器人特效
private final String afadeCmd="ffmpeg -i %s -filter afade=t=%s:ss=%:ns=%ld:st=%d:d=%d:curve=tri %s";
private final String volumeCmd="ffmpeg -i %s -filter volume=%s %s";//音量
private final String vibratoCmd="ffmpeg -i %s -filter vibrato=f=%f:d=%f %s";//颤音
private final String asetrateCmd="ffmpeg -i %s -filter asetrate=sample_rate=%s,atempo=%s %s";//男低音 30000 1.25变调 44100
private final String asetrate2Cmd="ffmpeg -i %s -filter asetrate=sample_rate=%s,atempo=%s %s";//娃娃音 73500 0.6 44100
private final String atempo2Cmd="ffmpeg -i %s -filter atempo=%s %s";//变速
private final String karaokeCmd="ffmpeg -i %s -filter stereotools=mlev=0.015625 %s";//卡拉OK
private final String compandCmd=""ffmpeg -i %s -filter compand=.3|.3:1|1:-90/-60|-60/-40|-40/-30|-20/-20:6:0:-90:0.2 %s";//感觉像声音加强了
private final String flangeCmd="ffmpeg -i %s -filter flanger=delay=0 %s";//环绕效果
如果你对音视频开发感兴趣,觉得文章对您有帮助,别忘了点赞、收藏哦!或者对本文的一些阐述有自己的看法,有任何问题,欢迎在下方评论区讨论!
相关推荐
- 我把家搬进了NAS?家庭资产数字化革命,现在连袜子都有编号了!
-
本内容来源于@什么值得买APP,观点仅代表作者本人|作者:羊刀仙家里东西一多,总有一种“我记得我有这个,但我不知道放哪了”的错觉。...
- Mega Run第3关通关攻略-跳上高空(mega运动)
-
错过火炮等于失败,这是MegaRun在上一关中给玩家的一点小挑战,那在后面的关卡中,这中挑战会给你造成什么困难呢?具体请看MegaRun第3关通关攻略-跳上高空。MegaRun第3关在一开始我...
- Axure高保真教程:中继器表格自动合计模板
-
编辑导语:合计作为日常使用频率比较高的一个功能,但在Axure里面传统的表格如果做合计是很麻烦的,遇到数据多的时候很耗费时间,那么该如何优化,提高工作效率?本文以中继器表格为核心,教大家如何制作一个自...
- 多角色登录原型(分角色登录)
-
编辑导读:多角色登录是很多系统都需要具备的功能,例如在招聘网站里,登录的角色包括、求职者、招聘企业的hr、猎头、内部员工等等。本文作者分享了如何在Axure里面制作多角色登录的原型模板,希望对你有帮助...
- 利用Axure+js创建可配置地图页面(axure地址选择)
-
编辑导语:如何利用Axure实现自定义地图展示?本篇文章里,作者结合Axure与高德地图,对如何在Axure中设置相应参数、进而预览时实现自定义地图展示效果的操作流程进行了示范和总结,一起来看一下。本...
- 纬地智能模板的一些基础与概念(纬地智能模板的一些基础与概念是什么)
-
对于公路及相关土木工程的勘测设计工作,虽然基础的理论和方法是基本相同的,但是受到各国家、地区文化、制图习惯等方面因素的影响,不同地域公路勘测设计的习惯和表达方式有着很大的差异,当然语言方面的不同和差...
- WPF界面开发第三方控件入门指南——菜单项
-
点击“了解更多”获取工具DevExpressWPFSubscription拥有120+个控件和库,将帮助您交付满足甚至超出企业需求的高性能业务应用程序。通过DevExpressWPF能创建有着强...
- 鸿蒙开发:自定义一个搜索模版(鸿蒙系统怎么添加百度搜索条)
-
前言代码案例基于Api13。...
- 简单介绍一下前端各框架中的模板标签
-
在各大前端框架、小程序中,此类标签的作用主要是用来帮助我们包裹多个元素。在浏览器实际渲染中会将其移除只渲染其包裹的DOM元素,所以说不会增加额外的DOM节点...
- 法媒:简单的几个步骤让你的运动鞋更加炫酷
-
【环球网综合报道】有没有觉得自己的运动鞋样式单调,希望它变得更加炫酷?法媒《ELLE》推荐了一种简单易行的装饰方法,让您的运动鞋更加时尚。制作前,您需要准备一张细毡子、一张闪光热胶合布、胶水、两个银夹...
- Blazor 代码隐藏(blazor 操作dom)
-
Razor组件通常是在单个.razor文件中创作的,这样就存在页面中包含html代码和后台代码(@code标记指定的代码)。如下...
- DevExpress WPF入门指南:DXBars, DXRibbon中使用MVVM的两种方式
-
你也可以下载Universal安装包或者到DevExpress中文网查看更多示例和教程哦本文档介绍在DXBars,DXRibbon和GalleryControl这三个控件中使用MVVM框架的...
- 干货,Uploadfive插件上传,Python接收存储
-
在Web开发工作中,经常遇到上传需求,上传照片,文件等,网上的上传插件有很多,我使用的是一款H5上传插件Uploadfive,与之对应的是Uploadify,后者是基于Flash的,不过现在越来越多的...
- 用DevExpress实现基于HTML&CSS的桌面应用程序的UI(二)
-
DevExpressWinForm拥有180+组件和UI库,能为WindowsForms...
- 一周热门
- 最近发表
- 标签列表
-
- grid 设置 (58)
- 移位运算 (48)
- not specified (45)
- 导航栏 (58)
- context xml (46)
- scroll (43)
- dedecms模版 (53)
- c 视频教程下载 (33)
- listview排序 (33)
- characterencodingfilter (33)
- getmonth (34)
- label换行 (33)
- android studio 3 0 (34)
- html转js (35)
- 索引的作用 (33)
- checkedlistbox (34)
- xmlhttp (35)
- mysql更改密码 (34)
- 权限777 (33)
- htmlposition (33)
- 学校网站模板 (34)
- textarea换行 (34)
- 轮播 (34)
- asp net三层架构 (38)
- bash (34)