JNI调用及回调(参数传递字节数组)

最近协助同事解决了JNI调用及回调问题,在此做个记录,备忘。

问题是这样子的:同事要开发一个java程序,用来控制摄像头的抓拍,且要通过回调字节流的方式,将抓拍的图片吐给java模块,然后再调人脸识别服务。期间遇到不少问题,最开始用JNA实现了整体功能,但是测试过程发现回调总是不稳定,照片有些时候传不回来。无耐之下,只要改用JNI再试,谁知JNI果然比JNA复杂,又是各种问题,不过还好问题都解决了,在此总结下JNI调用及回调流程。

JNI使用步骤:

1、编写Java代码,其中要注明调用DLL的native方法;

2、通过javah命令,针对java代码生成c头文件;

3、基于c头文件,编写对应的函数实现,一般通过在此实现中调用真正需要交互的dll函数;

完成这3步,基本就可以完成dll调用了。对于回调,需要在c代码中,基于jni api获取要调用的类名、方法名、参数等,特别要注意参数类型的对应关系。

实例分享:

1、编写Java类

import java.io.FileOutputStream;
import java.io.IOException;

//摄像机控制类
public class CameraCtl {
    
    //加载dll库,注意需要将库放入项目根目录,或者设置native library路径到dll目录
	static {
		System.loadLibrary("HwCameraSdk");
	}

    //映射到C的本地方法
	public native void startHwCamera();

    //C的回调方法,通过参数传递字节数组,其实是图片信息
	public void hwCameraCallback(byte[] byteAry) {
		FileOutputStream out = null;
		try {
			out = new FileOutputStream("./test3.jpg");
			out.write(byteAry);
			out.flush();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (null != out) {
				try {
					out.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

    //用于测试的回调
	public void hwCameraCallback(boolean[] booleanAry) {
		for (int i = 0; i < booleanAry.length; i++) {
			System.out.println(booleanAry[i]);
		}
	}

    //用于测试的无参回调
	public void hwCameraCallback() {
		System.out.println("触发无参回调");
	}

	public static void main(String args[]) {
		(new CameraCtl()).startHwCamera();
	}
}

2、针对第1步的java代码,通过javah工具生成c头文件

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

#ifndef _Included_upup_ajni_CameraCtl
#define _Included_upup_ajni_CameraCtl
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     upup_ajni_CameraCtl
 * Method:    startHwCamera
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_upup_ajni_CameraCtl_startHwCamera
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

3、编写具体实现,需要引入jni.h,jni_md.h代码结果如下:

具体实现:

#include "jni.h"
#include "CameraCtl.h"
#include <stdio.h>
#include <stdlib.h>
using namespace std;

void writeFile(char* msg){
	FILE *fp = NULL;
   	fp = fopen("./test.txt", "w+");
   	fprintf(fp, msg);
   	//fputs("This is testing for fputs...\n", fp);
   	fclose(fp);
}
void readFile(){
	FILE *fp = NULL;
   	char buff[255];
 
   	fp = fopen("./test.txt", "r");
   	fscanf(fp, "%s", buff);
   	printf("1: %s\n", buff );
 
   	fgets(buff, 255, (FILE*)fp);
   	printf("2: %s\n", buff );
   
   	fgets(buff, 255, (FILE*)fp);
   	printf("3: %s\n", buff );
   	fclose(fp);
}

void testReadWriteFile(){
	//读文件 
	char a[]="aaaafadsafasdfsfasd";
	char* c=a;
	writeFile(c);
	//写文件 
	readFile();
}

void read_write_file(){  
    const int MAXLEN =1024;  
    FILE * outfile, *infile;  
    outfile = fopen("./test2.jpg", "wb" );  
    infile = fopen("./test1.jpg", "rb");  
    unsigned char buf[MAXLEN];  
    if( outfile == NULL || infile == NULL )  {  
        //  printf(%s, %s,argv[1],not exit\n);  
        printf("exit");
        exit(1);  
    }     
	int rc;  
    while( (rc = fread(buf,sizeof(unsigned char), MAXLEN,infile)) != 0 )  { 
        fwrite( buf, sizeof( unsigned char ), rc, outfile );  
    }   
    fclose(infile);  
    fclose(outfile);  
    printf("read,write succes"); 
}  

unsigned char* readImgFile(){  
    const int MAXLEN =1024*1000;  
    FILE *infile;  
    infile = fopen("./test1.jpg", "rb");  
    unsigned char buf[MAXLEN];
    if(infile == NULL )  {  
        exit(1);  
    }     
    fread(buf,sizeof(unsigned char), MAXLEN,infile); 
    fclose(infile);  
    printf("read success"); 
    printf("%d",sizeof(buf));
    unsigned char *pBuf=buf; 
    printf("%d",sizeof(pBuf));
    return pBuf;
} 

jbyteArray as_byte_array(JNIEnv *env, unsigned char* buf, int size) {

    jbyteArray array = env->NewByteArray(size);

    //HERE I GET THE ERROR, I HAVE BEEN TRYING WITH len/2 and WORKS , PROBABLY SOME BYTS ARE GETTING LOST.
    env->SetByteArrayRegion(array, 0, size, (jbyte*)(buf));

    return array;
}

void hwCameraCallback(JNIEnv *env,jobject obj){
	printf("callback begin\n");
	
	//获取类引用 
	jclass thisClass = env->GetObjectClass(obj);
	
	/* 
	//无参回调 
	jmethodID midCallBack = env->GetMethodID(thisClass, "hwCameraCallback", "()V");//获取方法id 
    if (NULL == midCallBack) {
    	printf("回调方法为空");
		return;
	}
	env->CallVoidMethod(obj, midCallBack);//调用方法 
	*/
	
	jmethodID midCallBack = env->GetMethodID(thisClass, "hwCameraCallback", "([B)V");//获取方法id 
    if (NULL == midCallBack) {
    	printf("回调方法为空");
		return;
	}
	
	//方法1 
	unsigned char p1[]="222223232323232";
	unsigned char* p2=p1;
    //jbyteArray buffer=as_byte_array(env,p2,sizeof(p2));
    unsigned char* p3=readImgFile();
	jbyteArray buffer=as_byte_array(env,p3,1024*1000);
	    
    /* 
    方法2 
	jbyteArray buffer = env->NewByteArray(3);
	jbyte *bytes = env->GetByteArrayElements( buffer, 0);
	bytes[0]=1;
	bytes[1]=2;
	bytes[2]=3;
	env->SetByteArrayRegion(buffer,0,3,bytes);
	*/
	
	env->CallVoidMethod(obj, midCallBack,buffer);//调用方法 
	
	testReadWriteFile();
	read_write_file();
	printf("callback end\n");
}

JNIEXPORT void JNICALL 
Java_upup_ajni_CameraCtl_startHwCamera(JNIEnv *env, jobject obj) 
{
    printf("camera start\n");
    hwCameraCallback(env,obj);
    return;
}

4、运行java程序,会看到通过c代码传回的字节数组,可以生成一个图片文件。

猜你喜欢

转载自blog.csdn.net/tobearc/article/details/88371883