c/c++ java 相互调用

# mkdir -p /data/jni/src/com/example/
# cd /data/jni/src/com/example

编写java源文件

# vi HelloNative.java

package com.example;

import java.io.UnsupportedEncodingException;

public class HelloNative {
    static {
        System.loadLibrary("HelloJNI");// java.library.path
        //System.load("/data/jni/Test/HelloJNI");// 绝对路径
    }

    public native void sayHello();
    public native int sum(int a, int b);
    public native String concat(String a, String b);

    public static void main(String[] args) {
        HelloNative hello = new HelloNative();
        hello.sayHello();
        System.out.println(hello.sum(1,2));
        try {
            String result = hello.concat("apple is ", "一种水果");
            System.out.println(result);
            System.out.println(new String(result.getBytes("UTF-8")));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }
}

# cd /data/jni/src

编译java源文件为class文件,Windows CMD命令行默认为GBK编码

# javac -encoding UTF-8 com/example/HelloNative.java

从 class 文件生成C/C++语言的函数接口, .h 头文件

# javah com.example.HelloNative

com_example_HelloNative.h 由包名+类名组成,注意下划线,不是点。

JNIEnv * : JNI接口本身的一个对象

jobject: 代表native方法的调用者,即HelloNative。具体值取决于当前方法是静态方法还是实例方法,若是静态方法,则表示类对象,若是实例方法,则表示实例对象

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_HelloNative */

#ifndef _Included_com_example_HelloNative
#define _Included_com_example_HelloNative
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_example_HelloNative
 * Method:    sayHello
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_example_HelloNative_sayHello
  (JNIEnv *, jobject);

/*
 * Class:     com_example_HelloNative
 * Method:    sum
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_com_example_HelloNative_sum
  (JNIEnv *, jobject, jint, jint);

/*
 * Class:     com_example_HelloNative
 * Method:    concat
 * Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_example_HelloNative_concat
  (JNIEnv *, jobject, jstring, jstring);

#ifdef __cplusplus
}
#endif
#endif

编写Hello.cpp源文件,实现.h接口。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "com_example_HelloNative.h"  

char* jstringToChar(JNIEnv *env, jstring jstr)
{
    char * rtn = NULL;
    jclass clsstring = env->FindClass("java/lang/String");
    jstring strencode = env->NewStringUTF("UTF-8");
    jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");
    jbyteArray barr= (jbyteArray)env->CallObjectMethod(jstr,mid,strencode);
    jsize alen = env->GetArrayLength(barr);
    jbyte * ba = env->GetByteArrayElements(barr,JNI_FALSE);
    if(alen > 0)
    {
        rtn = (char*)malloc(alen+1); //new char[alen+1];
        memcpy(rtn,ba,alen);
        rtn[alen]=0;
    }
    env->ReleaseByteArrayElements(barr,ba,0);
    printf("char is %s\n", rtn);
    return rtn;
} 

jstring charTojstring(JNIEnv* env, const char* pat) {
    //定义java String类 strClass
    jclass strClass = (env)->FindClass("java/lang/String");
    //获取String(byte[],String)的构造器,用于将本地byte[]数组转换为一个新String
    jmethodID ctorID = (env)->GetMethodID(strClass, "<init>", "([BLjava/lang/String;)V");
    //建立byte数组
    jbyteArray bytes = (env)->NewByteArray(strlen(pat));
    //将char* 转换为byte数组
    (env)->SetByteArrayRegion(bytes, 0, strlen(pat), (jbyte*) pat);
    // 设置String, 保存语言类型,用于byte数组转换至String时的参数
    jstring encoding = (env)->NewStringUTF("utf-8");
    //将byte数组转换为java String,并输出
    return (jstring) (env)->NewObject(strClass, ctorID, bytes, encoding);
}

JNIEXPORT void JNICALL Java_com_example_HelloNative_sayHello(JNIEnv *env, jobject obj)
{
    printf("Hello Native World。中文显示@&*\n");
}
  
JNIEXPORT jint  JNICALL Java_com_example_HelloNative_sum(JNIEnv *env, jobject obj, jint x, jint y)  
{  
    return x+y;  
}

JNIEXPORT jstring JNICALL Java_com_example_HelloNative_concat(JNIEnv *env, jobject obj, jstring javaStringOne, jstring javaStringTwo)
{
    //const char *nativeStringOne = env->GetStringUTFChars(javaStringOne, NULL);
    //const char *nativeStringTwo = env->GetStringUTFChars(javaStringTwo, NULL);

    char *nativeStringOne = jstringToChar(env,javaStringOne);
    char *nativeStringTwo = jstringToChar(env,javaStringTwo);
    strcat(nativeStringOne, nativeStringTwo);//拼接字符串
    // int length = sizeof(nativeStringOne) + sizeof(nativeStringTwo) + 1;
    // char* concatstring = (char*)malloc(length * sizeof(char));
    // memset(concatstring, 0, length);
    // strcat(concatstring, nativeStringOne);
    // strcat(concatstring, nativeStringTwo);

    // printf("cast string is %s\n", concatstring);
    // free(concatstring);
    
    //env->ReleaseStringUTFChars(javaStringOne, nativeStringOne);
    //env->ReleaseStringUTFChars(javaStringTwo, nativeStringTwo);

    printf("nativeStringOne is %s\n", nativeStringOne);
    //jstring result = (env)->NewStringUTF( nativeStringOne);
    jstring result = charTojstring(env, nativeStringOne);

    return result;
}

gcc(g++)编译选项

-shared :指定生成动态链接库。
-static :指定生成静态链接库。
-fPIC :表示编译为位置独立的代码,用于编译共享库。目标文件需要创建成位置无关码, 念上就是在可执行程序装载它们的时候,它们可以放在可执行程序的内存里的任何地方。
-L. :表示要连接的库所在的目录。
-l:指定链接时需要的动态库。编译器查找动态连接库时有隐含的命名规则,即在给出的名字前面加上lib,后面加上.a/.so来确定库的名称。
-Wall :生成所有警告信息。
-ggdb :此选项将尽可能的生成gdb 的可以使用的调试信息。
-g :编译器在编译的时候产生调试信息。
-c :只激活预处理、编译和汇编,也就是把程序做成目标文件(.o文件) 。
-Wl,options :把参数(options)传递给链接器ld 。如果options 中间有逗号,就将options分成多个选项,然后传递给链接程序

从Hello.cpp生成Hello.o目标文件(windows)

64位MingGW: https://sourceforge.net/projects/mingw-w64/ x86_64-8.1.0-release-posix-seh-rt_v6-rev0.7z

# gcc -fPIC -I"%JAVA_HOME%\include" -I"%JAVA_HOME%\include\win32" -c Hello.cpp

从Hello.o生成动态链接库,Linux是.so文件,Windows是.dll文件,文件名为System.loadLibrary("HelloJNI")中的名称HelloJNI

# gcc -shared Hello.o -o HelloJNI.dll
# gcc -shared Hello.o -o HelloJNI.so

直接从cpp生成动态链接库

# gcc -I"%JAVA_HOME%\include" -I"%JAVA_HOME%\include\win32" -shared -o HelloJNI.dll Hello.cpp

调用方法

# java com.example.HelloNative

C/C++ 调用java,参考:https://www.jianshu.com/p/3d68d65db468.

HelloNative.java

package com.example;

import java.io.UnsupportedEncodingException;

public class HelloNative {
    static {
        System.loadLibrary("HelloJNI");// java.library.path
        //System.load("/data/jni/Test/HelloJNI");// 绝对路径
    }

    public native void sayHello();
    public native int sum(int a, int b);
    public native String concat(String a, String b);
    
    /**
     * 供c/c++代码调用的一个类成员方法
     */
    public void printDescription() {
        System.out.println("printDescription called by c/c++");
    }

    /**
     * 供c/c++代码调用的一个类静态方法
     */
    public static void notifyJava(String msg) {
        System.out.println("notifyJava called by c/c++. " + msg);
    }
    
    public static void main(String[] args) {
        HelloNative hello = new HelloNative();
        hello.sayHello();
        System.out.println(hello.sum(1,2));
        try {
            String result = hello.concat("apple is ", "一种水果");
            System.out.println(result);
            System.out.println(new String(result.getBytes("UTF-8")));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }
}

Hello.cpp

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "com_example_HelloNative.h"  

int callObjectMethod(JNIEnv *, jobject);
int callStaticMethod(JNIEnv *, jobject);

/**
 * 调用 类成员方法
 * @return
 */
int callObjectMethod(JNIEnv *pEnv, jobject obj) {
    jclass ndktestclass = pEnv->GetObjectClass(obj);
    // 获取方法printDescription 方法id,()V为返回值参数
    jmethodID methodID = pEnv->GetMethodID(ndktestclass, "printDescription", "()V");
    // CallVoidMethod没有返回值
    pEnv->CallVoidMethod(obj, methodID);
    return 0;
}

/**
 * 调用 类静态方法
 * @param pEnv
 * @param obj
 * @return
 */
int callStaticMethod(JNIEnv *pEnv, jobject obj) {
    jclass ndktestclass = pEnv->GetObjectClass(obj);
    jmethodID methodID = pEnv->GetStaticMethodID(ndktestclass, "notifyJava", "(Ljava/lang/String;)V");
    pEnv->CallStaticVoidMethod(ndktestclass, methodID, pEnv->NewStringUTF("new msg from jni"));
    return 0;
}

char* jstringToChar(JNIEnv *env, jstring jstr)
{
    char * rtn = NULL;
    jclass clsstring = env->FindClass("java/lang/String");
    jstring strencode = env->NewStringUTF("UTF-8");
    jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");
    jbyteArray barr= (jbyteArray)env->CallObjectMethod(jstr,mid,strencode);
    jsize alen = env->GetArrayLength(barr);
    jbyte * ba = env->GetByteArrayElements(barr,JNI_FALSE);
    if(alen > 0)
    {
        rtn = (char*)malloc(alen+1); //new char[alen+1];
        memcpy(rtn,ba,alen);
        rtn[alen]=0;
    }
    env->ReleaseByteArrayElements(barr,ba,0);
    printf("char is %s\n", rtn);
    return rtn;
} 

jstring charTojstring(JNIEnv* env, const char* pat) {
    //定义java String类 strClass
    jclass strClass = (env)->FindClass("Ljava/lang/String;");
    //获取String(byte[],String)的构造器,用于将本地byte[]数组转换为一个新String
    jmethodID ctorID = (env)->GetMethodID(strClass, "<init>", "([BLjava/lang/String;)V");
    //建立byte数组
    jbyteArray bytes = (env)->NewByteArray(strlen(pat));
    //将char* 转换为byte数组
    (env)->SetByteArrayRegion(bytes, 0, strlen(pat), (jbyte*) pat);
    // 设置String, 保存语言类型,用于byte数组转换至String时的参数
    jstring encoding = (env)->NewStringUTF("utf-8");
    //将byte数组转换为java String,并输出
    return (jstring) (env)->NewObject(strClass, ctorID, bytes, encoding);
}

JNIEXPORT void JNICALL Java_com_example_HelloNative_sayHello(JNIEnv *env, jobject obj)
{
    printf("Hello Native World。中文显示@&*\n");
}
  
JNIEXPORT jint  JNICALL Java_com_example_HelloNative_sum(JNIEnv *env, jobject obj, jint x, jint y)  
{  
    return x+y;  
}

JNIEXPORT jstring JNICALL Java_com_example_HelloNative_concat(JNIEnv *env, jobject obj, jstring javaStringOne, jstring javaStringTwo)
{
    // 调用java的方法
    callObjectMethod(env, obj);
    callStaticMethod(env, obj);
    
    //const char *nativeStringOne = env->GetStringUTFChars(javaStringOne, NULL);
    //const char *nativeStringTwo = env->GetStringUTFChars(javaStringTwo, NULL);

    char *nativeStringOne = jstringToChar(env,javaStringOne);
    char *nativeStringTwo = jstringToChar(env,javaStringTwo);
    strcat(nativeStringOne, nativeStringTwo);//拼接字符串
    // int length = sizeof(nativeStringOne) + sizeof(nativeStringTwo) + 1;
    // char* concatstring = (char*)malloc(length * sizeof(char));
    // memset(concatstring, 0, length);
    // strcat(concatstring, nativeStringOne);
    // strcat(concatstring, nativeStringTwo);

    // printf("cast string is %s\n", concatstring);
    // free(concatstring);
    
    //env->ReleaseStringUTFChars(javaStringOne, nativeStringOne);
    //env->ReleaseStringUTFChars(javaStringTwo, nativeStringTwo);

    printf("nativeStringOne is %s\n", nativeStringOne);
    //jstring result = (env)->NewStringUTF( nativeStringOne);
    jstring result = charTojstring(env, nativeStringOne);

    return result;
}


安装opencv

http://opencv-java-tutorials.readthedocs.io/en/latest/01-installing-opencv-for-java.html#install-opencv-3-x-under-linux

https://www.vultr.com/docs/how-to-install-opencv-on-centos-7

Step 1: Install dependencies for OpenCV

yum groupinstall "Development Tools" -y

yum install cmake gcc gtk2-devel numpy pkconfig -y

Step 2: Download the OpenCV 2.4.9 archive

cd /opt

wget https://github.com/opencv/opencv/archive/2.4.9.zip(或者上传opencv-2.4.9.zip)

unzip opencv-2.4.9.zip

Step 3: Compile and install OpenCV 2.4.9

cd opencv-2.4.9

mkdir build

cd build

cmake -D CMAKE_BUILD_TYPE=DEBUG -D CMAKE_INSTALL_PREFIX=/usr/local/ ..

make

make install

Step 4: Configure required variables

export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig/

echo '/usr/local/lib/' >> /etc/ld.so.conf.d/opencv.conf

ldconfig

Step 5 (optional): Run tests

cd /home/xxxx

git clone https://github.com/opencv/opencv_extra.git

export OPENCV_TEST_DATA_PATH=/home/xxxx/opencv_extra/testdata

In the cmake build directory, you will find several test executables named in the same kind of format opencv_test_*. Run any one you are interested in to perform a test. For example:

cd /home/xxxx/opencv-2.4.9/build/bin

ls

./opencv_test_photo

添加动态链接库

//拷贝libopencv_softcascade.so.2.4.9和libopencv_ts.so.2.4.9到/usr/local/lib目录
//生成软链接
<pre><code>
chmod 777 libopencv_softcascade.so.2.4.9
ln -s libopencv_softcascade.so.2.4.9 libopencv_softcascade.so.2.4
ln -s libopencv_softcascade.so.2.4 libopencv_softcascade.so

chmod 777 libopencv_ts.so.2.4.9
ln -s libopencv_ts.so.2.4.9 libopencv_ts.so.2.4
ln -s libopencv_ts.so.2.4 libopencv_ts.so
</pre></code>

//使动态链接库生效

/sbin/ldconfig -v

安装ffmpg

https://www.jianshu.com/p/2b98e0f87720

1.升级系统

sudo yum install epel-release -y

2.安装Nux Dextop Yum 源

sudo rpm --import http://li.nux.ro/download/nux/RPM-GPG-KEY-nux.ro  
sudo rpm -Uvh http://li.nux.ro/download/nux/dextop/el7/x86_64/nux-dextop-release-0-5.el7.nux.noarch.rpm

3.安装FFmpeg 和 FFmpeg开发包

sudo yum install ffmpeg ffmpeg-devel -y

4.测试是否安装成功

ffmpeg

使用FFmpeg将flv转为mp4

ffmpeg -i input.flv output.mp4
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容