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. 基于jQuery的前端如何做到无伤迁移

    首先,解释一下我个人对前端无伤迁移的理解,即移动端和PC端使用同一套代码,或者说原本在PC端运行得很完美的代码,只要修改少许,就可以在移动端完美运行. 当然,大部分的公司会专门为移动端设计了一套,同时 ...

  2. 关于Char* ,CString ,WCHAR*之间的转换问题

    GDI+所有类的接口函数如果要传递字符串作为参数的话,似乎都用UNICODE串,即WCHAR*.我开始也被整得晕头转向,因为窗口编程所用往往是CString,用IO流读文件数据又得到char *.得益 ...

  3. Java调用.dll文件

    因为项目的需求,要在JAVA项目中调用Windows的Dll(动态链接库)文件,之前用Jni调用过C写的Dll文件,比较麻烦,这里不多说,网上也有很多这方面的文档.在网上找到一个开源的组件JNativ ...

  4. 数据库设计与SQL优化的建议

    1. 用程序中,保证在实现功能的基础上,尽量减少对数据库的访问次数:通过搜索参数,尽量减少对表的访问行数,最小化结果集,从而减轻网络负担:能够分开的操作尽量分开处理,提高每次的响应速度:在数据窗口使用 ...

  5. php操作路径的经典方法

    function create_folders($dir){    return is_dir($dir) or ( create_folders( dirname( $dir ) ) and mkd ...

  6. MGTemplateEngine 模版引擎简单使用(转)

    原文:http://blog.csdn.net/crazy_srufboy/article/details/21748995 要实现的效果 首先上图中间的 标题至内容 都是使用UIWebView显示, ...

  7. C# webservice开发

      一.Webservice简介Web Service也叫XML Web Service. Web Service是一种可以接收从Internet或者Intranet上的其它系统中传递过来的请求,轻量 ...

  8. Code First Entity Framework 6化被动为主动之explicit loading模式实战分析( 附源码)

    在使用Entity Framework加载关联实体时,可以有三种方式: 1.懒加载(lazy Loading); 2.贪婪加载(eager loading); 3.显示加载(explicit load ...

  9. Linux下终端利器tmux(转)

    “君子生非异也,善假于物也” .–语出<荀子·劝学> 如果记得没错的话,<荀子·劝学>我们这一代高中的时候应该都读过这篇文章.原意大概是君子的资质与一般人没有什么区别,君子之所 ...

  10. TreeSet()详解

    TreeSet()详解   1.TreeSet原理:   /* * TreeSet存储对象的时候, 可以排序, 但是需要指定排序的算法 *  * Integer能排序(有默认顺序), String能排 ...