Android编译调用FFmpeg API,自己写方法,编译so库
作者:谭东
时间:2017年9月19日
环境:Windows 8.1专业版
NDK版本:android-ndk-r14b
FFmpeg版本:FFmpeg 3.0.2 “Einstein”
我这里使用的Android Studio为2.3.3版本。
大名鼎鼎的FFmpeg可以说全球出名,基本上视频处理都是它,但是使用FFmpeg的技术门槛和难度也相对要求高一些。
那么我就先给大家简单引用别人的描述简单介绍下FFmpeg吧:
FFmpeg是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。采用LGPL或GPL许可证。它提供了录制、转换以及流化音视频的完整解决方案。它包含了非常先进的音频/视频编解码库libavcodec,为了保证高可移植性和编解码质量,libavcodec里很多code都是从头开发的。多媒体视频处理工具FFmpeg有非常强大的功能包括视频采集功能、视频格式转换、视频抓图、给视频加水印等。
FFmpeg被许多开源项目采用,比如ffmpeg2theora,VLC, MPlayer, HandBrake, Blender, Google Chrome等。还有DirectShow/VFW的ffdshow(external project)和QuickTime的Perian (external project)也采用了FFmpeg。
由于FFmpeg是在LGPL/GPL协议下发布的(如果使用了其中一些使用GPL协议发布的模块则必须使用GPL协议),任何人都可以自由使用,但必须严格遵守LGPL/GPL协议。有很多播放软件都使用了FFmpeg的代码,但它们并没有遵守LGPL/GPL协议,没有公开任何源代码。我们应该对这种侵权行为表示耻辱。
2009年加入FFmpeg耻辱黑名单的播放软件:暴风影音、QQ影音、KMP、GOM Player、PotPlayer(2010)都在其列。
2009年2月,韩国名软KMPlayer被FFmpeg开源项目发现使用了它们的代码和二进制文件,但是没有按照规定/惯例开放相应说明/源码。因此被人举报,进入了FFmpeg官网上的耻辱黑名单。
2009年11月,网友roo_zhou向FFmpeg举报,指出QQ影音的credit只给出了修改的FFmpeg源码下载,声称是LGPL许可证。但实际是修改过的ffdshow,采用的是GPL许可证,之后QQ影音被正式加入到FFmpeg耻辱名单之列。
Libav项目启动之后,FFmpeg官方版本也仍然在一直维护中。FFmpeg与libav属于独立的两个项目。
-------------------------------------------------------------------------------------------------------------------------
就先介绍到这里。
FFmpeg大致有两种使用方式,第一种是命令行,这个最简单也最直接。不过这个比较适合Linux下,移动平台和Windows下还是需要单独编译源码,自己写C方法调用FFmpeg的API,然后编译成库,例如Android平台要编译成so库。这样难度和门槛就加大了,你要读懂和了解FFmpeg的C方法,C源码和API文档。其实很多用法可以看下官方英文文档,官方也有很多参考资料。我这里以Android平台为例,但是大同小异,毕竟方法都是C++的方法,IOS、Linux、Windows都通用的。
好了。接下来给大家讲解下编译和调用FFmpeg的C的API。
首先肯定是先要去FFmpeg官网下载最新的源码,然后在Linux下进行编译了。Android平台需要编译so库。
官网源码下载地址:http://ffmpeg.org/download.html
我之前写过一篇文章,讲解如何编译FFmpeg的。
《Ubuntu下编译Android版本的ffmepg so库及源码》
以及
《Ubuntu编译调用FFmpeg so库Api方法例子》
具体如何编译我就不说了,编译好后,进行下面的步骤。
1、Android Studio新建支持C++的项目。勾选Include C++ support。
2、新建好的项目大致结构这样。主要关注下图里红色的几个部分。
3.、接下来在项目的src下的main目录新建jniLibs目录,再新建对应的架构平台的文件夹名,然后把so库放进去。我这里只编译了armeabi平台的so库,所以结构是下图这样的。
4、把FFmpeg编译后的源码.h头文件拷贝到项目的libs目录里。
5、可以大致看下里面的,h里的方法和定义。
6、接下来就是编写配置我们的CMakeLists.txt了。下面是我写好的配置,大家可以参考。
# Sets the minimum version of CMake required to build the native
# library. You should either keep the default value or only pass a
# value of 3.4.0 or lower.cmake_minimum_required(VERSION 3.4.1)find_library( # Sets the name of the path variable.log-lib# Specifies the name of the NDK library that# you want CMake to locate.log )set(distribution_DIR ${CMAKE_SOURCE_DIR}/../../../../libs)add_library( avutil-55SHAREDIMPORTED )
set_target_properties( avutil-55PROPERTIES IMPORTED_LOCATION../../../../src/main/jniLibs/armeabi/libavutil-55.so )add_library( swresample-2SHAREDIMPORTED )
set_target_properties( swresample-2PROPERTIES IMPORTED_LOCATION../../../../src/main/jniLibs/armeabi/libswresample-2.so )
add_library( avcodec-57SHAREDIMPORTED )
set_target_properties( avcodec-57PROPERTIES IMPORTED_LOCATION../../../../src/main/jniLibs/armeabi/libavcodec-57.so )
add_library( avfilter-6SHAREDIMPORTED)
set_target_properties( avfilter-6PROPERTIES IMPORTED_LOCATION../../../../src/main/jniLibs/armeabi/libavfilter-6.so )
add_library( swscale-4SHAREDIMPORTED)
set_target_properties( swscale-4PROPERTIES IMPORTED_LOCATION../../../../src/main/jniLibs/armeabi/libswscale-4.so )
add_library( avdevice-57SHAREDIMPORTED)
set_target_properties( avdevice-57PROPERTIES IMPORTED_LOCATION../../../../src/main/jniLibs/armeabi/libavdevice-57.so )
add_library( avformat-57SHAREDIMPORTED)
set_target_properties( avformat-57PROPERTIES IMPORTED_LOCATION../../../../src/main/jniLibs/armeabi/libavformat-57.so )set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")add_library( native-libSHAREDsrc/main/cpp/native-lib.cpp )include_directories(libs/include)#target_include_directories(native-lib PRIVATE libs/include)target_link_libraries( native-lib swresample-2 avcodec-57 avfilter-6 swscale-4 avdevice-57 avformat-57${log-lib} )
7、接下来我们看下默认生成的cpp文件夹里的native-lib.cpp的里面的C方法例子规范。
#include <jni.h>
#include <string>extern "C" JNIEXPORT jstring JNICALL
Java_com_tandong_testffmpeg_MainActivity_stringFromJNI(JNIEnv *env,jobject /* this */) {std::string hello = "Hello from C++";return env->NewStringUTF(hello.c_str());
}
很简单对不对。我们可以按照这个规范写我们的其他测试和调用FFmpeg的API的C++方法了。
#include <jni.h>
#include <string>extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavfilter/avfilter.h>JNIEXPORT jstring JNICALL
Java_com_tandong_testffmpeg_MainActivity_stringFromJNI(JNIEnv *env,jobject /* this */) {std::string hello = "Hello from C++";return env->NewStringUTF(hello.c_str());
}JNIEXPORT jstring JNICALL
Java_com_tandong_testffmpeg_MainActivity_stringFromJNI2(JNIEnv *env,jobject /* this */) {return env->NewStringUTF("测试");
}/*** 获取FFmpeg支持的协议格式*/
JNIEXPORT jstring JNICALL
Java_com_tandong_testffmpeg_MainActivity_getUrlProtocolInfo(JNIEnv *env, jobject) {char info[40000] = {0};av_register_all();struct URLProtocol *pup = NULL;struct URLProtocol **p_temp = &pup;avio_enum_protocols((void **) p_temp, 0);while ((*p_temp) != NULL) {sprintf(info, "%sInput: %s\n", info, avio_enum_protocols((void **) p_temp, 0));}pup = NULL;avio_enum_protocols((void **) p_temp, 1);while ((*p_temp) != NULL) {sprintf(info, "%sInput: %s\n", info, avio_enum_protocols((void **) p_temp, 1));}return env->NewStringUTF(info);
}/*** 获取avcodec的库的版本号*/
JNIEXPORT jstring JNICALL
Java_com_tandong_testffmpeg_MainActivity_getAvCodecVersion(JNIEnv *env, jobject) {char version[50];avcodec_register_all();sprintf(version, "%d", avcodec_version());return env->NewStringUTF(version);
}/*** 获取avformat的库的协议*/
JNIEXPORT jstring JNICALL
Java_com_tandong_testffmpeg_MainActivity_getAvFormatLicense(JNIEnv *env, jobject) {std::string license = avformat_license();return env->NewStringUTF(license.c_str());
}}
这些是我写的几个调用API的方法,这些都是很简单的,后面有很多复杂的功能,写法就会更加的复杂,难度也会更大。
我们可以根据它的.h头文件或者官方源码文档,查看这个方法传入的参数含义和类型以及返回的类型及作用。
下面是官方文档查看及源码。
8、紧接着,我们编写我们的JAVA来调用JNI的方法。
package com.tandong.testffmpeg;import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// Example of a call to a native methodTextView tv = (TextView) findViewById(R.id.sample_text);tv.setText(getUrlProtocolInfo());}/*** A native method that is implemented by the 'native-lib' native library,* which is packaged with this application.*/public native String stringFromJNI();public native String stringFromJNI2();public native String getUrlProtocolInfo();public native String getAvCodecVersion();public native String getAvFormatLicense();// Used to load the 'native-lib' library on application startup.static {System.loadLibrary("native-lib");}
}
这个就很简单了,就不给大家解释了。
9、最后就是编译打包运行了,编译运行后,就会生成我们的so库。
调用编译就先给大家讲解到这里,请继续关注
Android编译调用FFmpeg API,自己写方法,编译so库相关推荐
- axios vue 回调函数_VUE使用axios调用后台API接口的方法
VUE使用axios调用后台API接口的方法 引言 Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式JavaScript框架.与其它大型框架不同的是,Vue 被设计为可 ...
- FFmpeg Android 学习(一):Android 如何调用 FFMPEG 编辑音视频
一.概述 在Android开发中,我们对一些音视频的处理比较无力,特别是编辑音视频这部分.而且在Android上对视频编辑方面,几乎没有任何API做支持,MediaCodec(硬编码)也没有做支持.那 ...
- Android Java调用ffmpeg命令
0. 前言 ffmpeg命令很强大,但是在Android工程中无法执行可执行文件ffmpeg,即无法使用ffmpeg. 本文介绍把ffmpeg改造成库文件,然后通过JNI调用它,即可实现在Java中 ...
- Android之调用第三方API导航(高德,百度,google)
一:效果图(点击路线调用API) 二:实现步骤: 1.判断是否安装各个地图软件 /*** 判断是否安装目标应用** @param packageName 目标应用安装后的包名* @return 是否已 ...
- android ffmpeg编译动态库,最简单的android studio调用ffmpeg动态库
准备工作: 1.编译好的ffmpeg动态库.so文件,以及ffmpeg的头文件: 2.android studio开发环境,包括NDK等可用环境: 步骤一: 新建一个android studio工程, ...
- Android P 调用隐藏API限制原理
随着Android P预览版的发布,谷歌在改进系统稳定性的措施上又增加了新的限制,即应用程序引用非SDK接口,无论采用直接.反射.JNI获取等手段都将受到限制.在谷歌提供的预览版文档&& ...
- Android Studio调用百度API(图片文字识别)
1.登录百度AI平台(https://ai.baidu.com/),下载license文件 包名填写内容: 下载好的文件夹内包含四个文件 (OCR-Android-SDK.md文件里有使用说明) (1 ...
- Android Fragment 调用宿主Activity 里面的方法
方法 1 : 直接在Fragment 写 MainActivity main = (MainActivity) getActivity();main.xx; // xx 是 MainActivity ...
- android aidl调用进程间服务的方法
我就拿最近做的项目来说明了,首先创建一个IFMService.aidl的接口文件,在R.java的目录下会自动生成IFMService.java 的文件, 接口文件的内容如下: package net ...
最新文章
- oracle 字符集 AL32UTF8、UTF8
- YII2 载入默认值 loadDefaultValues
- react native windows 搭建(完整版)
- 使用WordPress的Kyma plugin同Kyma断开连接的实现
- Python网路请求(GET示例)
- asp.net在动态网页中的使用技巧
- delphi中webbrowser的用法
- 如何对全站进行死链接检测?
- VC6 VS2010 环境变量
- 企业级Docker Registry —— Harbor搭建和使用
- PHP require、include、require_once、include_once用法及区别
- freemarker 遍历 map
- Ubuntu下bazel卸载与安装
- 无剑100SOC(wujian100)挂UART外设之④修改SDK
- 4.2 Python 实例5-身体质量指数BMI
- Java实现将字符串进行Base64跟GZip结合解密 Java实现Base64 + GZIP解密处理并且输出明文字符
- MySQL性能优化(四):SQL优化
- 大容量邮箱如何注册?TOM VIP邮箱帮你轻松搞定
- 第七周——复数模板类
- MindNode 5.0.1 pro for mac 破解版
热门文章
- vue3 diff算法优化
- HiCopyTrader跟单系统启动失败,错误提示:api ms win crt xxxx.dll 之类文件缺失,怎么办
- “远程网络教学系统”
- 不动产登记:摈除“黑暗的大数据”
- kali的root账户的密码是多少?
- parseFloat() 函数
- 2022制冷与空调设备运行操作特种作业证考试题库模拟考试平台操作
- 浅谈千万级PV/IP规模高性能高并发网站架构(转自老男孩)
- 高并发:线程、线程锁与线程池(精华),文中附上一个手写代码实现线程池视频(c/c++语言)
- 5G时代必学的WebRTC音视频通话技术