java jni ffmpeg_Ubuntu下,在Eclipse中使用JNI调用ffmpeg

本文介绍了如何在Ubuntu环境下,使用Eclipse通过JNI调用FFmpeg库。首先,需要安装配置Android NDK并编译FFmpeg为libffmpeg.so。接着,创建Android项目,定义JNI接口并在Java中加载库。然后,编写C/C++代码实现接口,用NDK编译生成so库。最后,在Java代码中加载并调用so库函数,实现FFmpeg功能。
摘要由CSDN通过智能技术生成

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,如下图:

96c618ca33c253d672cec047c1acb15d.png

3,定义JNI接口

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

f4f8aabcda8c3e32f8ebfd24b78b6faf.png

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

2019ab52653100e1a09286895e0110ee.png

编辑文件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,如下图:

e32aaf626b06e28650c32e9a3ee1a968.png

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

/* DO NOT EDIT THIS FILE - it is machine generated */

#include

/* 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

#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库文件了。如下图:

51fbdeed644e66e59b6e06abd29e8bf8.png

编译成功的话会在目录./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();

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值