Android的应用层开发大部分还是采用JAVA,如果想使用ffmpeg库,就必须利用JNI,使得Java可以调用C/C++的库。

JNI其实就是定义的一个转接接口,可以让Java的代码调用C/C++的库,我的理解有点像C#中调用C/C++的DLL需要一个proxy工程一样。编译好的ffmpeg库文件名为:libffmpeg.so,它是一个普通的C/C++动态链接库。下面以libffmpeg.lib为例子,讲述在Android开发中,如果使用JNI调用C/C++的库。

1,准备工作

在做JNI开发之前,需要安装配置Android NDK,并且将ffmpeg编译成动态链接库libffmpeg.so。这个步骤在网上有很多资料,在此不再重复。我们假定NDK已经配置好、文件libffmpeg.so已经得到,下面的步骤都是基于这个条件来实现的。

2,新建Android Project

启动Eclipse,创建一个默认类型的Android Project,设置Application Name为mplayer,如下图:

3,定义JNI接口

为工程添加JNI接口函数,这些函数就是需要用C/C++来实现的功能。我们可以选在左侧的Package Explorer中选中src目录,然后通过右键菜单:New->Class打开新建类的对话框。然后在Package栏输入“com.example.jni”;在Name栏输入“JNI”。如下图:

然后点击确定,在工程里就添加好了接口定义文件JNI.java。如下图:

编辑文件JNI.java,在该文件中定义需要JNI实现的函数接口,如下:

package com.example.jni;

public class JNI {
public native boolean ffmpegInit();
public native boolean ffmpegUninit();
public native int ffmpegGetavcodecversion();
}

4,编译JNI接口

定义好JNI接口之后,需要通过Project菜单、选择"Build Project"来build一下工程,这样确保文件./mplayer/bin/classes/com/example/jni/JNI.class是最新的。

然后打开终端,把当前目录切换至:./mplayer/bin/classes/,然后在提示符后输入:classes# javah -classpath . -jni com.example.jni.JNI,如下图:

回车确定之后,将在目录./mplayer/bin/classes/下生成一个C/C++的头文件:com_example_jni_JNI.h。这个头文件时间上是之前我们定的JNI接口函数的C/C++表示形式,其函数名是根据JNI的规则自动生成的,我们不要去修改。文件内容如下:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_jni_JNI */ #ifndef _Included_com_example_jni_JNI
#define _Included_com_example_jni_JNI
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_example_jni_JNI
* Method: ffmpegInit
* Signature: ()Z
*/
JNIEXPORT jboolean JNICALL Java_com_example_jni_JNI_ffmpegInit
(JNIEnv *, jobject); /*
* Class: com_example_jni_JNI
* Method: ffmpegUninit
* Signature: ()Z
*/
JNIEXPORT jboolean JNICALL Java_com_example_jni_JNI_ffmpegUninit
(JNIEnv *, jobject); /*
* Class: com_example_jni_JNI
* Method: ffmpegGetavcodecversion
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_com_example_jni_JNI_ffmpegGetavcodecversion
(JNIEnv *, jobject); #ifdef __cplusplus
}
#endif
#endif

5,编译JNI的C/C++库
     下面我们需要把com_example_jni_JNI.h定义的函数用C/C++实现,并且编译成so库文件,这样Java代码可以通过调用这个so库,来获取ffmpeg的功能。

首先我们通过左侧的Package Explorer,在mplayer目录下新建一个目录:jni,这个名字必须是这样,不能改成其他的。然后把头文件com_example_jni_JNI.h拷贝到这个目录下,之后再创建对应的c文件:com_example_jni_JNI.c,然后手动添加每个函数的实现。大体代码如下:

#include <string.h>
#include "ffmpeg/libavcodec/avcodec.h"  
#include "ffmpeg/libavformat/avformat.h"
#include "com_example_jni_JNI.h" /*
* Class: com_example_jni_JNI
* Method: ffmpegInit
* Signature: ()V
*/
JNIEXPORT jboolean JNICALL Java_com_example_jni_JNI_ffmpegInit
(JNIEnv *env, jobject thiz)
{
av_register_all();
return 1;
}
/*
* Class: com_example_jni_JNI
* Method: ffmpegUninit
* Signature: ()V
*/
JNIEXPORT jboolean JNICALL Java_com_example_jni_JNI_ffmpegUninit
(JNIEnv *env, jobject thiz)
{
return 1;
} /*
* Class: com_example_jni_JNI
* Method: ffmpegGetavcodecversion
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_com_example_jni_JNI_ffmpegGetavcodecversion
(JNIEnv *env, jobject thiz)
{
return (int)avcodec_version();
}

准备好这两个文件之后,需要使用NDK编译成so库文件。具体步骤如下:

a.先将ffmpeg整个代码目录拷贝到目录./mplayer/jni下,因为编译的时候需要用到ffmpeg的头文件;

b.将之前编译好的文件libffmpeg.so拷贝到ffmpeg目录下:./mplayer/jni/ffmpeg/

c.然后在./mplayer/jni目录下创建文件Androdi.mk,文件内容如下:

LOCAL_PATH :=$(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := ffmpeg_jni
LOCAL_SRC_FILES := com_example_jni_JNI.c
LOCAL_C_INCLUDES += $(LOCAL_PATH)/ffmpeg/ $(LOCAL_PATH)/ffmpeg/libavutil/ $(LOCAL_PATH)/ffmpeg/libavcodec/ $(LOCAL_PATH)/ffmpeg/libavformat/ $(LOCAL_PATH)/ffmpeg/libavcodec/ $(LOCAL_PATH)/ffmpeg/libswscale/
LOCAL_LDLIBS +=-L$(LOCAL_PATH)/ffmpeg -lffmpeg -llog
include $(BUILD_SHARED_LIBRARY)

d.打开终端,把当前目录切换至:./mplayer,也就是jni目录的上一级目录。然后在提示符后输入“ndk-build”回车,这样就把JNI接口编译成so库文件了。如下图:

编译成功的话会在目录./mplayer/libs/armeabi/ 下生成库文件:libffmpeg_jni.so。将最开始准备的libffmpeg.so这个文件也拷贝到这个目录下,因为这两个文件有依赖关系,最终都要打包到pak里的。

6,Java中调用so库

现在到了最后一步,所有的准备工作都做好了,就等Java代码里使用so库了。

a.先在Java代码里加载so库,在文件MainActivity.java中加入如下代码:

	static {
System.loadLibrary("ffmpeg_jni");
System.loadLibrary("ffmpeg");
}

注意:文件名前面没有了lib、后面没有了.so。

b.再定义JNI接口对象

        JNI ffmpegJNI;

c.通过接口对象调用so里的函数

    @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); TextView tv = (TextView)findViewById(R.id.tv);
TextView tv2 = (TextView)findViewById(R.id.tv2);
ffmpegJNI = new JNI();
if (ffmpegJNI.ffmpegInit())
{
tv.setText("FFmpeg is initliazed!");
tv2.setText(String.valueOf("avcodec verison:" + ffmpegJNI.ffmpegGetavcodecversion()));
}
else
{
tv.setText("FFmpeg is initliaze failed!");
}
}

这样我们就实现了JNI对ffmpeg的调用。如果Java和C/C++的都是由自己开发实现的,那么就不用像这里用到两个so,完全可以使用一个so来实现接口的定义和函数功能。由于ffmpeg是前人已经写好了的代码,对话的函数都不能修改的,所以我们这里需要一个转接的so。最后整个Java代码如下:

package com.example.mplayer;

import com.example.jni.JNI;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.widget.TextView; public class MainActivity extends Activity {
JNI ffmpegJNI; static {
System.loadLibrary("ffmpeg_jni");
System.loadLibrary("ffmpeg");
} @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); TextView tv = (TextView)findViewById(R.id.tv);
TextView tv2 = (TextView)findViewById(R.id.tv2);
ffmpegJNI = new JNI();
if (ffmpegJNI.ffmpegInit())
{
tv.setText("FFmpeg is initliazed!");
tv2.setText(String.valueOf("avcodec verison:" + ffmpegJNI.ffmpegGetavcodecversion()));
}
} @Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
} @Override
protected void onDestroy() {
ffmpegJNI.ffmpegUninit(); super.onDestroy();
}
}

Ubuntu下,在Eclipse中使用JNI调用ffmpeg的更多相关文章

  1. ubuntu下整合eclipse和javah生成jni头文件开发android的native程序

    0:前言: 这两天一直在研究用android的jni调用第三方库,上网搜方法,但是都是泛泛而谈,没有demo,经过我几番折磨,写了n多的helloword工程,总是不成功,工程名字也就由helloow ...

  2. Ubuntu下在Eclipse IDE for C/C++ Developers中怎样执行C语言的GTK程序?(已解决)

    (已解决.详见Ubuntu 12.04下在Eclipse IDE for C/C++ Developers中执行C语言的GTK程序) 按"Ubuntu下GTK的安装.编译和測试"( ...

  3. ubuntu下不用eclipse开发cocos2d-x(命令行)

    之前在ubuntu下通过eclipse搭建开发cocos2d-x的环境,但是由于eclipse界面在ubuntu显得很丑,在里面写代码,完全没有感觉,后来我转到了win7上通过vs2010和eclip ...

  4. ubuntu下安装eclipse IDE for C/C++ developers

     序 linux的GUI和windos比起来实在逊色,虽然它的终端模式(命令行模式)非常强大.linux发行版ubuntu的GUI相对其他版本要华丽一些,所以最近由redhat转向ubuntu进行li ...

  5. Ubuntu下增加eclipse菜单图标并配置java path(解决点击图标不能启动eclipse的问题)

    Ubuntu下增加eclipse菜单图标 Ubuntu的菜单图标在/usr/share/applications目录下. 1. 在/usr/share/applications目录下新建eclipse ...

  6. (转)Ubuntu下用eclipse cdt编写多线程程序的简单设置

    在Ubuntu下用eclipse cdt编写了一个多线程程序,但是总是出现pthread_create函数未定义! 查找了下原因,原来是要对eclipse进行一些简单的设置: 右键单击项目->P ...

  7. 【转】在Ubuntu下建立Eclipse的Android开发环境

    本文将介绍如何建立Ubuntu下基于Eclipse的Android开发环境的方法. 大部分的Android开发者都是使用Eclipse来开发Android,本文将向各位介绍一下建立Ubuntu下基于E ...

  8. ubuntu 下安装eclipse &amp;java环境配置

    前面有一篇的博客写的是ubuntu下安装eclipse和java环境的配置.当时是安装网上的攻略进行的 ,当然也是能够成功的. 近期把那台电脑送人了 ,仅仅好在自己的这台电脑上又一次安装一次了 ,唯一 ...

  9. 在Ubuntu下的OpenStack中配置使用Spice协议

    在Ubuntu下的OpenStack中配置使用Spice协议 by 无若 ####控制节点#安装apt-get install nova-spiceproxy spice-html5 spice-vd ...

随机推荐

  1. php 日期 - 计算2个日期的差值

    /** * 日期-计算2个日期的差值 * @return int */ public function get_difference($date, $new_date) { $date = strto ...

  2. TCP粘包拆包问题

    阿π 专注于网络协议,系统底层,服务器软件 C++博客 | 首页 | 发新随笔 | 发新文章 | | | 管理 Socket粘包问题 这两天看csdn有一些关于socket粘包,socket缓冲区设置 ...

  3. WPF Bug清单之(13)——应该出现却没有出现的ListView水平滚动条

    转载地址:http://www.cnblogs.com/nankezhishi/archive/2010/03/17/wpfbug13.html 我们知道ListView在内容超出控件本身范围时,默认 ...

  4. Qt 多线程与数据库操作需要注意的几点问题(QSqlDatabase对象只能在当前线程里使用)

    彻底抛弃MFC, 全面应用Qt 已经不少时间了.除了自己看书按步就班做了十几个验证性的应用,还正式做了3个比较大的行业应用,总体感觉很好.Native C++ 下, Qt 基本是我用过的最简便的界面库 ...

  5. 新浪IP归属地API

    之前用过腾讯的AIP,但是官方暂停这个服务了,新浪的API时间很久了,稳定性也很好,但愿能一劳永逸. ''' '''

  6. DTW-js版

    最近想试试语音识别,然后看到了DTW这个算法 主要参考:http://www.cnblogs.com/rockyf/articles/4519352.html function dtw(arr1, a ...

  7. java双线程调用同一个对象+锁

    两个线程(Thread)调用同一个对象(使用Runnable接口的对象ThreadJob) 误区:下一个线程会从上一个线程结束的地方开始 正解:如 public domd implements Run ...

  8. Spring流程

    Spring Web Flow是Spring框架的子项目,作用是让程序按规定流程运行. 1 安装配置Spring Web Flow 虽然Spring Web Flow是Spring框架的子项目,但它并 ...

  9. ios 后台模式

    1.在后台可以继续播放音频 To play sound in the background, make sure to add the following to the Info.plist file ...

  10. java中文乱码解决之道(一)—–认识字符集

    原文出处:http://cmsblogs.com/?p=1395 沉寂了许久(大概有三个多月了吧),LZ“按捺不住”开始写博了! java编码中的中文问题是一个老生常谈的问题了,每次遇到中文乱码LZ要 ...