Android编译调用FFmpeg API,自己写方法,编译so库
来源:互联网 发布:在生产实践中用于数据 编辑:程序博客网 时间:2024/06/14 07:41
作者:谭东
时间: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-55 SHARED IMPORTED )set_target_properties( avutil-55 PROPERTIES IMPORTED_LOCATION ../../../../src/main/jniLibs/armeabi/libavutil-55.so )add_library( swresample-2 SHARED IMPORTED )set_target_properties( swresample-2 PROPERTIES IMPORTED_LOCATION ../../../../src/main/jniLibs/armeabi/libswresample-2.so )add_library( avcodec-57 SHARED IMPORTED )set_target_properties( avcodec-57 PROPERTIES IMPORTED_LOCATION ../../../../src/main/jniLibs/armeabi/libavcodec-57.so )add_library( avfilter-6 SHARED IMPORTED)set_target_properties( avfilter-6 PROPERTIES IMPORTED_LOCATION ../../../../src/main/jniLibs/armeabi/libavfilter-6.so )add_library( swscale-4 SHARED IMPORTED)set_target_properties( swscale-4 PROPERTIES IMPORTED_LOCATION ../../../../src/main/jniLibs/armeabi/libswscale-4.so )add_library( avdevice-57 SHARED IMPORTED)set_target_properties( avdevice-57 PROPERTIES IMPORTED_LOCATION ../../../../src/main/jniLibs/armeabi/libavdevice-57.so )add_library( avformat-57 SHARED IMPORTED)set_target_properties( avformat-57 PROPERTIES IMPORTED_LOCATION ../../../../src/main/jniLibs/armeabi/libavformat-57.so )set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")add_library( native-lib SHARED src/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} )
#include <jni.h>#include <string>extern "C" JNIEXPORT jstring JNICALLJava_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 JNICALLJava_com_tandong_testffmpeg_MainActivity_stringFromJNI( JNIEnv *env, jobject /* this */) { std::string hello = "Hello from C++"; return env->NewStringUTF(hello.c_str());}JNIEXPORT jstring JNICALLJava_com_tandong_testffmpeg_MainActivity_stringFromJNI2( JNIEnv *env, jobject /* this */) { return env->NewStringUTF("测试");}/** * 获取FFmpeg支持的协议格式 */JNIEXPORT jstring JNICALLJava_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 JNICALLJava_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 JNICALLJava_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 { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Example of a call to a native method TextView 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库
- Ubuntu编译调用FFmpeg so库Api方法例子
- ffmpeg编译android的so库
- Android 编译FFmpeg成单独so库(验证可用)
- Ubuntu下编译android所需ffmpeg的so库
- Android FFMPEG .so 编译过程记录
- Window 平台 FFmpeg Android .so文件编译
- ubuntu 平台 FFmpeg Android .so文件编译
- FFmpeg编译.so
- Linux FFmpeg 编译so动态库
- Ffmpeg编译Android库
- Android源码中编译自己的so库
- Android源码中编译自己的so库
- Android Studio使用NDK编译自己的.so库
- Android源码中编译自己的so库
- Android最简单的基于FFmpeg的例子(三)---编译FFmpeg成一个SO库
- Android最简单的基于FFmpeg的例子(三)---编译FFmpeg成一个SO库
- FFmpeg编译Android/Linux移植库,打包成一个ffmpeg.so
- Matlab的启动方式
- FaceDataset常用的人脸数据库
- 求DAG最长路 板子
- Java异常处理和设计
- jsp内置对象
- Android编译调用FFmpeg API,自己写方法,编译so库
- HDOJ1003(连续最大和)
- 我对产品需求的理解
- 局部变量、全局变量和静态变量的含义和区别
- MySQL中的两种临时表
- Linux管道和命令重定向
- Java实现——数组中连续元素子数组的和最大
- UVA 315
- POJ 3070 Fibonacci (矩阵快速幂)