Giter Site home page Giter Site logo

jnisample's People

Contributors

a284628487 avatar

Watchers

 avatar  avatar

jnisample's Issues

Other

注册本地方法

RegisterNatives

jint RegisterNatives(JNIEnv *env, jclass clazz, const JNINativeMethod *methods, jint nMethods);
向clazz参数指定的类注册本地方法。methods参数将指定JNINativeMethod结构的数组,其中包含本地方法的名称、签名和函数指针。nMethods参数将指定数组中的本地方法数。JNINativeMethod 结构定义如下所示:
typedef struct {
char *name;
char *signature;
void *fnPtr;
} JNINativeMethod;
函数指针通常必须有下列签名:
ReturnType (*fnPtr)(JNIEnv *env, jobject objectOrClass, ...);
参数:env:JNI接口指针。clazz:Java类对象。methods:类中的本地方法。nMethods:类中的本地方法数。
返回值:成功时返回 “0”;失败时返回负数。
抛出:NoSuchMethodError:如果找不到指定的方法或方法不是本地方法。
UnregisterNatives

jint UnregisterNatives(JNIEnv *env, jclass clazz);
取消注册类的本地方法。类将返回到链接或注册了本地方法函数前的状态。该函数不应在常规平台相关代码中使用。相反,它可以为某些程序提供一种重新加载和重新链接本地库的途径。
参数:env:JNI接口指针。clazz:Java类对象。
返回值:成功时返回“0”;失败时返回负数。
监视程序操作

MonitorEnter

jint MonitorEnter(JNIEnv *env, jobject obj);
进入与obj所引用的基本Java对象相关联的监视程序。每个Java对象都有一个相关联的监视程序。如果当前线程已经拥有与obj相关联的监视程 序,它将使指示该线程进入监视程序次数的监视程序计数器增 1。如果与 obj 相关联的监视程序并非由某个线程所拥有,则当前线程将变为该监视程序的所有者,同时将该监视程序的计数器设置为 1。如果另一个线程已拥有与 obj 关联的监视程序,则在监视程序被释放前当前线程将处于等待状态。监视程序被释放后,当前线程将尝试重新获得所有权。
参数:env:JNI接口指针。obj:常规Java对象或类对象。
返回值:成功时返回“0”;失败时返回负数。
MonitorExit

jint MonitorExit(JNIEnv *env, jobject obj);
当前线程必须是与obj所引用的基本Java对象相关联的监视程序的所有者。线程将使指示进入监视程序次数的计数器减 1。如果计数器的值变为 0,当前线程释放监视程序。
参数:env:JNI接口指针。obj:常规Java对象或类对象。
返回值:成功时返回“0”;失败时返回负数。
Java虚拟机接口

GetJavaVM

jint GetJavaVM(JNIEnv *env, JavaVM **vm);
返回与当前线程相关联的Java虚拟机接口(用于调用API中)。结果将放在第二个参数vm所指向的位置。
参数:env:JNI接口指针。vm:指向放置结果的位置的指针。
返回值:成功时返回“0”;失败时返回负数。
调用API
调用API允许软件厂商将Java虚拟机加载到任意的本地程序中。厂商可以交付支持Java的应用程序,而不必链接Java虚拟机源代码。本章首先 概述了调用API。然后是所有调用API函数的引用页。若要增强Java虚拟机的嵌入性,可以用几种方式来扩展JDK 1.1.2中的调用API。
概述

以下代码示例说明了如何使用调用API中的函数。在本例中,C++代码创建Java虚拟机并且调用名为Main.test的静态方法。为清楚起见,我们略去了错误检查。
#include <jni.h>
/* 其中定义了所有的事项 /
...
JavaVM jvm;
/
表示 Java 虚拟机
/
JNIEnv env;
/
指向本地方法接口的指针 /
JDK1_1InitArgs vm_args; /
JDK 1.1 虚拟机初始化参数 /
vm_args.version = 0x00010001; /
1.1.2 中新增的:虚拟机版本 /
/
获得缺省的初始化参数并且设置类路径 /
JNI_GetDefaultJavaVMInitArgs(&vm_args);
vm_args.classpath = ...;
/
加载并初始化 Java 虚拟机,返回env中的JNI 接口指针 /
JNI_CreateJavaVM(&jvm, &env, &vm_args);
/
用 JNI 调用 Main.test 方法 /
jclass cls = env->FindClass("Main");
jmethodID mid = env->GetStaticMethodID(cls, "test", "(I)V");
env->CallStaticVoidMethod(cls, mid, 100);
/
结束。*/
jvm->DestroyJavaVM();
本例使用了API中的三个函数。调用API允许本地应用程序用JNI接口指针来访问虚拟机特性。其设计类似于Netscape的JRI嵌入式接口。
创建虚拟机

JNI_CreateJavaVM()函数加载并初始化Java虚拟机,然后将指针返回到JNI接口指针。调用JNI_CreateJavaVM()的线程被看作主线程。
连接虚拟机

JNI接口指针(JNIEnv)仅在当前线程中有效。如果另一个线程需要访问Java虚拟机,则该线程首先必须调用 AttachCurrentThread()以将自身连接到虚拟机并且获得JNI接口指针。连接到虚拟机之后,本地线程的工作方式就与在本地方法内运行的 普通Java线程一样了。本地线程保持与虚拟机的连接,直到调用DetachCurrentThread()时才断开连接。
卸载虚拟机

主线程不能自己断开与虚拟机的连接。而是必须调用DestroyJavaVM()来卸载整个虚拟机。
虚拟机等到主线程成为唯一的用户线程时才真正地卸载。用户线程包括Java线程和附加的本地线程。之所以存在这种限制是因为Java线程或附加的本 地线程可能正占用着系统资源,例如锁,窗口等。虚拟机不能自动释放这些资源。卸载虚拟机时,通过将主线程限制为唯一的运行线程,使释放任意线程所占用系统 资源的负担落到程序员身上。
初始化结构

不同的Java虚拟机实现可能会需要不同的初始化参数。很难提出适合于所有现有和将来的Java虚拟机的标准初始化结构。作为一种折衷方式,我们保 留了第一个域(version)来识别初始化结构的内容。嵌入到JDK 1.1.2中的本地应用程序必须将版本域设置为0x00010001。尽管其它实现可能会忽略某些由JDK所支持的初始化参数,我们仍然鼓励虚拟机实现使 用与JDK一样的初始化结构。0x80000000到0xFFFFFFFF之间的版本号需保留,并且不为任何虚拟机实现所识别。
以下代码显示了初始化JDK 1.1.2中的Java虚拟机所用的结构。
typedef struct JavaVMInitArgs {
/* 前两个域在 JDK 1.1 中保留,并在 JDK 1.1.2 中正式引入。/
/
Java 虚拟机版本 /
jint version;
/
系统属性。/
char *properties;
/
是否检查 Java 源文件与已编译的类文件之间的新旧关系。
/
jint checkSource;
/* Java 创建的线程的最大本地堆栈大小。/
jint nativeStackSize;
/
最大 Java 堆栈大小。/
jint javaStackSize;
/
初始堆大小。/
jint minHeapSize;
/
最大堆大小。/
jint maxHeapSize;
/
控制是否校验 Java 字节码:0 无,1 远程加载的代码,2 所有代码。/
jint verifyMode;
/
类加载的本地目录路径。/
const char classpath;
/
重定向所有虚拟机消息的函数的钩子。
/
jint (vfprintf)(FILE fp, const char format, va_list args);
/
虚拟机退出钩子。
/
void (exit)(jint code);
/
虚拟机放弃钩子。
/
void (abort)();
/
是否启用类 GC。/
jint enableClassGC;
/
GC 消息是否出现。/
jint enableVerboseGC;
/
是否允许异步 GC。/
jint disableAsyncGC;
/
三个保留的域。/
jint reserved0;
jint reserved1;
jint reserved2;
} JDK1_1InitArgs;
在JDK 1.1.2中,初始化结构提供了钩子,这样在虚拟机终止时,本地应用程序可以重定向虚拟机消息并获得控制权。当本地线程与JDK 1.1.2中的Java虚拟机连接时,以下结构将作为参数进行传递。实际上,本地线程与JDK 1.1.2连接时不需要任何参数。JDK1_1AttachArgs 结构仅由C编译器的填充槽组成,而C编译器不允许空结构。
typedef struct JDK1_1AttachArgs {
/

* JDK 1.1 不需要任何参数来附加本地线程。此处填充的作用是为了满足不允许空结构的C编译器的要求。
*/
void *__padding;
} JDK1_1AttachArgs;
调用API函数

JavaVM类型是指向调用API函数表的指针。以下代码示例显示了这种函数表。
typedef const struct JNIInvokeInterface *JavaVM;

const struct JNIInvokeInterface ... = {
NULL,
NULL,
NULL,
DestroyJavaVM,
AttachCurrentThread,
DetachCurrentThread,
};
注意,JNI_GetDefaultJavaVMInitArgs()、JNI_GetCreatedJavaVMs()和JNI_CreateJavaVM() 这三个调用API函数不是JavaVM函数表的一部分。不必先有JavaVM结构,就可以使用这些函数。
JNI_GetDefaultJavaVMInitArgs

jint JNI_GetDefaultJavaVMInitArgs(void *vm_args);
返回Java虚拟机的缺省配置。在调用该函数之前,平台相关代码必须将vm_args->version 域设置为它所期望虚拟机支持的JNI版本。在JDK 1.1.2中,必须将vm_args->version设置为0x00010001。(JDK 1.1不要求平台相关代码设置版本域。为了向后兼容性,如果没有设置版本域,则JDK 1.1.2假定所请求的版本为0x00010001。JDK的未来版本将要求把版本域设置为适当的值。)该函数返回后,将把 vm_args->version设置为虚拟机支持的实际JNI版本。
参数:vm_args:指向VM-specific initialization(特定于虚拟机的初始化)结构的指针,缺省参数填入该结构。
返回值:如果所请求的版本得到支持,则返回“0”;如果所请求的版本未得到支持,则返回负数。
JNI_GetCreatedJavaVMs

jint JNI_GetCreatedJavaVMs(JavaVM **vmBuf, jsize bufLen, jsize nVMs);
返回所有已创建的Java虚拟机。将指向虚拟机的指针依据其创建顺序写入vmBuf缓冲区。最多写入bufLen项。在
nVMs中返回所创建虚拟机的总数。JDK 1.1不支持在单个进程中创建多个虚拟机。
参数:vmBuf:指向将放置虚拟机结构的缓冲区的指针。bufLen:缓冲区的长度。nVMs:指向整数的指针。
返回值:成功时返回“0”;失败则返回负数。
JNI_CreateJavaVM

jint JNI_CreateJavaVM(JavaVM **p_vm, JNIEnv **p_env, void *vm_args);
加载并初始化Java虚拟机。当前线程成为主线程。将env参数设置为主线程的JNI接口指针。JDK 1.1.2不支持在单个进程中创建多个虚拟机。必须将vm_args中的版本域设置为0x00010001。
参数:p_vm:指向位置(其中放置所得到的虚拟机结构)的指针。p_env:指向位置(其中放置主线程的 JNI 接口指针)的指针。vm_args: Java 虚拟机初始化参数。
返回值:成功时返回“0”;失败则返回负数。
DestroyJavaVM

jint DestroyJavaVM(JavaVM *vm);
卸载Java虚拟机并回收资源。只有主线程能够卸载虚拟机。调用DestroyJavaVM() 时,主线程必须是唯一的剩余用户线程。
参数:vm:将销毁的Java虚拟机。
返回值:成功时返回“0”;失败则返回负数。
JDK 1.1.2 不支持卸载虚拟机。
AttachCurrentThread

jint AttachCurrentThread(JavaVM *vm, JNIEnv **p_env, void *thr_args);
将当前线程连接到Java虚拟机。在JNIEnv参数中返回JNI接口指针。试图连接已经连接的线程将不执行任何操作。本地线程不能同时连接到两个Java虚拟机上。
参数:vm:当前线程所要连接到的虚拟机。p_env:指向位置(其中放置当前线程的 JNI 接口指针)的指针。thr_args:特定于虚拟机的线程连接参数。
返回值:成功时返回“0”;失败则返回负数。
DetachCurrentThread

jint DetachCurrentThread(JavaVM *vm);
断开当前线程与Java虚拟机之间的连接。释放该线程占用的所有Java监视程序。通知所有等待该线程终止的Java线程。主线程(即创建Java 虚拟机的线程)不能断开与虚拟机之间的连接。作为替代,主线程必须调用JNI_DestroyJavaVM()来卸载整个虚拟机。
参数:vm:当前线程将断开连接的虚拟机。
返回值:成功时返回“0”;失败则返回负数。
CreateFile

(1)函数原型
HANDLE CreateFile(
LPCTSTR lpfileName,
DWORD deDesiredAccess,
DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes
DWORD dwCreationDesposition,
DWORD dwFlagsAndAtrributes,
HANDLE hTemplateFile
);
(2)函数说明
该函数创建、打开或截断一个文件,并返回一个能够被用来存取该文件的句柄。此句柄允许读书据、写数据以及移动文件的指针。CreateFile函数既可以做为一个宽自负函数使用,也可以作为一个ANSI函数来用。
(3)参数说明
lpFileName:指向文件字符串的指针。dwDesireAccess:制定文件的存取模式,可以取下列值:0:制定可以查询对象。 GENERIC_READ:指定可以从文件中度去数据。GENERIC_WRITE:指定可以向文件中写数据。dwShareMode:指定文件的共享模 式,可以取下列值:
0:不共享。
FILE_SHARE_DELETE:在 Windows NT 系统中,只有为了删除文件而进行的打开操作才会成功。
FILE_SHARE_READ:只有为了从文件中度去数据而进行的打开操作才会成功。
FILE_SHARE_WRITE:只有为了向文件中写数据而进行的打开操作才会成功。
lpSecurityAttributes:指定文件的安全属性。dwCreationDisopsition:指定创建文件的方式,可以取以下值:
CREATE_NEW:创建新文件,如果文件已存在,则函数失败。
CREATE_ALWAYS:创建爱内心文件,如果文件已存在,则函数将覆盖并清除旧文件。
OPEN_EXISTING:打开文件,如果文件不存在,函数将失败。
OPEN_ALWAYS:打开文件,如果文件不存在,则函数将创建一个新文件。
TRUNCATE_EXISTING:打开外呢间,如果文件存在,函数将文件的大小设为零,如果文件不存在,函数将失败返回。
dwFlagsAndAtrributes:指定新建文件的属性和标志,它可以取以下值:1. FILE_ATTRIBUTE_ARCHIVE:归档属性。2. FILE_ATTRIBUTE_HIDDEN:隐藏属性。3. FILE_ATTRIBUTE_NORMAL:正常属性。4. FILE_ATTRIBUTE_READONLY:只读属性。5. FILE_ATTRIBUTE_SYSTEM:系统文件。6. FILE_ATTRIBUTE_TEMPORARY:临时存储文件,系统总是将临时文件的所有数据读入内存中,以加速对该文件的访问速度。用户应该尽快删 除不再使用的临时文件。7. FILE_FLAG_OVERLAPPED:用户可以通过一个 OVERLAPPED 结构变量来保存和设置文件读写指针,从而可以完成重叠式的读和写。一般用于数量比较大的读些操作。
hTemplateFile:指向一个具有GENERIC_READ属性的文件的句柄,该文件为要创建的文件提供文件属性和文件扩展属性。
(4)注意事项
函数成功将返回指定文件的句柄,否则返回NULL。
(5)典型示例:
...
char szFile[64];
HANDLE handle;
unsigned long lWritten,lRead;

handle = CreateFile("c:\\windows\\desktop\\example.txt",GENERIC_READ|GENERIC_W
					RITE,FILE_SHARE_READ,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);

if(handle==INVALID_HANDLE_VALUE){
	MessageBox(NULL,"Error Create File!","Error",MB_OK);
	break;
}else
	MessageBox(NULL,"Open file Success!","Open file",MB_OK);

数据类型

基本数据类型

/* Primitive types that match up with Java equivalents. */
typedef uint8_t  jboolean; /* unsigned 8 bits */
typedef int8_t   jbyte;    /* signed 8 bits */
typedef uint16_t jchar;    /* unsigned 16 bits */
typedef int16_t  jshort;   /* signed 16 bits */
typedef int32_t  jint;     /* signed 32 bits */
typedef int64_t  jlong;    /* signed 64 bits */
typedef float    jfloat;   /* 32-bit IEEE 754 */
typedef double   jdouble;  /* 64-bit IEEE 754 */

/* "cardinal indices and sizes" */
typedef jint     jsize;

#define JNI_FALSE   0
#define JNI_TRUE    1

值类型

typedef union jvalue {
    jboolean    z;
    jbyte       b;
    jchar       c;
    jshort      s;
    jint        i;
    jlong       j;
    jfloat      f;
    jdouble     d;
    jobject     l;
} jvalue;

类型签名

类型签名	 	Java 类型	 

 	类型签名	 	Java 类型	 
 	Z	 		boolean	 
 	B	 		byte	 
 	C	 		char	 
 	S	 		short	 
 	I	 		int	 
 	J	 		long	 
 	F	 		float	 
 	D	 		double	 
 	L fully-qualified-class ;	 	全限定的类	 
 	[ type	 	type[]

签名规则:( arg-types ) ret-type
例如Java方法:long f (int n, String s, int[] arr); 对应的类型签名: (ILjava/lang/String;[I)J

JNINativeInterface & _JNIEnv & JNIEnv

C 中使用 JNINativeInterface

struct _JNIEnv;
struct _JavaVM;
typedef const struct JNINativeInterface* C_JNIEnv;

#if defined(__cplusplus)
typedef _JNIEnv JNIEnv;
typedef _JavaVM JavaVM;
#else
typedef const struct JNINativeInterface* JNIEnv;
typedef const struct JNIInvokeInterface* JavaVM;
#endif

/*
 * Table of interface function pointers.
 */
struct JNINativeInterface {
    void*       reserved0;
    void*       reserved1;
    void*       reserved2;
    void*       reserved3;

    jint        (*GetVersion)(JNIEnv *);

    jclass      (*DefineClass)(JNIEnv*, const char*, jobject, const jbyte*,
                        jsize);
    jclass      (*FindClass)(JNIEnv*, const char*);
    // ...

C++ 中使用 JNIEnv

/*
 * C++ object wrapper.
 *
 * This is usually overlaid on a C struct whose first element is a
 * JNINativeInterface*.  We rely somewhat on compiler behavior.
 */
struct _JNIEnv {
    /* do not rename this; it does not seem to be entirely opaque */
    const struct JNINativeInterface* functions;

#if defined(__cplusplus)

    jint GetVersion()
    { return functions->GetVersion(this); }

    jclass DefineClass(const char *name, jobject loader, const jbyte* buf,
        jsize bufLen)
    { return functions->DefineClass(this, name, loader, buf, bufLen); }
    // ...

在开发中不论是使用C/C++,上述两个 Struct 都被定义成了 JNIEnv

字符串操作&基本数据类型数组操作

字符串操作

NewString

利用Unicode字符数组构造新的java.lang.String对象。

jstring NewString(JNIEnv *env, const jchar *unicodeChars, jsize len);
  • unicodeChars:指向Unicode字符串的指针。
  • len:Unicode字符串的长度。
    返回值:Java字符串对象。如果无法构造该字符串,则为NULL。

GetStringLength

返回Java字符串的长度(Unicode字符数)。

jsize GetStringLength(JNIEnv *env, jstring string);
  • string:Java字符串对象。
    返回值:Java 字符串的长度。

GetStringChars

返回指向字符串的Unicode字符数组的指针。该指针在调用ReleaseStringchars()前一直有效。如果isCopy非空,则在复制完成后将*isCopy设为JNI_TRUE。如果没有复制,则设为JNI_FALSE。

const jchar * GetStringChars(JNIEnv *env, jstring string, jboolean *isCopy);
  • string:Java字符串对象。
  • isCopy:指向布尔值的指针。
    返回值:指向Unicode字符串的指针,如果操作失败,则返回NULL。

ReleaseStringChars

通知虚拟机平台相关代码无需再访问chars。参数chars是一个指针,可通过GetStringChars()从string获得。

void ReleaseStringChars(JNIEnv *env, jstring string, const jchar *chars);
  • string:Java字符串对象。
  • chars:指向Unicode字符串的指针。

NewStringUTF

利用UTF-8字符数组构造新java.lang.String对象。

jstring NewStringUTF(JNIEnv *env, const char *bytes);
  • bytes:指向UTF-8字符串的指针。
    返回值:Java字符串对象。如果无法构造该字符串,则为NULL。

###GetStringUTFLength
以字节为单位返回字符串的UTF-8长度。

jsize GetStringUTFLength(JNIEnv *env, jstring string);
  • string:Java字符串对象。
    返回值:返回字符串的UTF-8长度。

GetStringUTFChars

返回指向字符串的UTF-8字符数组的指针。该数组在被ReleaseStringUTFChars()释放前将一直有效。如果isCopy不是 NULL,*isCopy在复制完成后即被设为JNI_TRUE。如果未复制,则设为JNI_FALSE。

const char* GetStringUTFChars(JNIEnv *env, jstring string, jboolean *isCopy);
  • string:Java字符串对象。
  • isCopy:指向布尔值的指针。
    返回值:指向UTF-8字符串的指针。如果操作失败,则为NULL。

ReleaseStringUTFChars

通知虚拟机平台相关代码无需再访问utf。utf参数是一个指针,可利用GetStringUTFChars()从string获得。

void ReleaseStringUTFChars(JNIEnv *env, jstring string, const char *utf);
  • string:Java字符串对象。
  • utf:指向UTF-8字符串的指针。

数组操作

GetArrayLength

返回数组中的元素数。

jsize GetArrayLength(JNIEnv *env, jarray array);
  • array:Java数组对象。
    返回值:数组的长度。

NewObjectArray

构造新的数组,它将保存类elementClass中的对象。所有元素初始值均设为initialElement。

jarray NewObjectArray(JNIEnv *env, jsize length, jclass elementClass, jobject initialElement);
  • length:数组大小。
  • elementClass:数组元素类。
  • initialElement:初始值。
    返回值:Java数组对象。如果无法构造数组,则为NULL。

GetObjectArrayElement

返回Object数组的元素。

jobject GetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize index);
  • array:Java数组。
  • index:数组下标。
    返回值:Java对象。

SetObjectArrayElement

设置Object数组的元素。

void SetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize index, jobject value);
  • array:Java数组。
  • index:数组下标。
  • value:新值。

NewArray

用于构造新基本类型数组对象的一系列操作。

ArrayType New<PrimitiveType>Array(JNIEnv *env, jsize length);
  • length:数组长度。
    返回值:Java数组。如果无法构造该数组,则为NULL。
 	*NewArray例程*	 	数组类型	 
 	NewBooleanArray()	 	jbooleanArray	 
 	NewByteArray()	 	jbyteArray	 
 	NewCharArray()	 	jcharArray	 
 	NewShortArray()	 	jshortArray	 
 	NewIntArray()	 	jintArray	 
 	NewLongArray()	 	jlongArray	 
 	NewFloatArray()	 	jfloatArray	 
 	NewDoubleArray()	 	jdoubleArray

GetArrayElements

返回基本类型数组体的函数。结果在调用相应的ReleaseArrayElements()函数前将一直有效。由于返回的数组可能是Java数组的副本,因此对返回数组的更改不必在基本类型数组中反映出来,直到调用了ReleaseArrayElements()。如果isCopy不是 NULL,*isCopy在复制完成后即被设为JNI_TRUE。如果未复制,则设为JNI_FALSE。

NativeType *Get<PrimitiveType>ArrayElements(JNIEnv *env, ArrayType array, jboolean *isCopy);
  • array:Java字符串对象。
  • isCopy:指向布尔值的指针。
    返回值:返回指向数组元素的指针,如果操作失败,则为NULL。

不管布尔数组在Java虚拟机中如何表示,GetBooleanArrayElements()将始终返回一个jboolean类型的指针,其中每一字节代表一个元素(开包表示)。内存中将确保所有其它类型的数组为连续的。

 	*GetArrayElements例程*	 	数组类型	 	本地类型	 
 	GetBooleanArrayElements()	 	jbooleanArray	 	jboolean	 
 	GetByteArrayElements()	 	jbyteArray	 	jbyte	 
 	GetCharArrayElements()	 	jcharArray	 	jchar	 
 	GetShortArrayElements()	 	jshortArray	 	jshort	 
 	GetIntArrayElements()	 	jintArray	 	jint	 
 	GetLongArrayElements()	 	jlongArray	 	jlong	 
 	GetFloatArrayElements()	 	jfloatArray	 	jfloat	 
 	GetDoubleArrayElements()	 	jdoubleArray	 	jdouble	 

ReleaseArrayElements

void Release<PrimitiveType>ArrayElements(JNIEnv *env, ArrayType array, NativeType *elems, jint mode);
  • array:Java数组对象。
  • elems:指向数组元素的指针。
  • mode:释放模式。

通知虚拟机平台相关代码无需再访问elems的一组函数。elems参数是一个通过使用对应的GetArrayElements()函数由 array导出的指针。
必要时,该函数将把对elems的修改复制回基本类型数组。mode参数将提供有关如何释放数组缓冲区的信息。如果elems不是 array中数组元素的副本,mode将无效。否则,mode将具有下表所述的功能:

 	基本类型数组释放模	 	动作	 
 	0	 	复制回内容并释放elems缓冲区	 
 	JNI_COMMIT	 	复制回内容但不释放elems缓冲区	 
 	JNI_ABORT	 	释放缓冲区但不复制回变化	 

多数情况下,编程人员将把“0”传给mode参数以确保固定的数组和复制的数组保持一致。其它选项可以使编程人员进一步控制内存管理,但使用时务必慎重。

 	*ReleaseArrayElements例程*	 	数组类型	 	本地类型	 
 	ReleaseBooleanArrayElements()	 	jbooleanArray	 	jboolean	 
 	ReleaseByteArrayElements()	 	jbyteArray	 	jbyte	 
 	ReleaseCharArrayElements()	 	jcharArray	 	jchar	 
 	ReleaseShortArrayElements()	 	jshortArray	 	jshort	 
 	ReleaseIntArrayElements()	 	jintArray	 	jint	 
 	ReleaseLongArrayElements()	 	jlongArray	 	jlong	 
 	ReleaseFloatArrayElements()	 	jfloatArray	 	jfloat	 
 	ReleaseDoubleArrayElements()	 	jdoubleArray	 	jdouble	 

GetArrayRegion

将基本类型数组某一区域复制到缓冲区中。

void Get<PrimitiveType>ArrayRegion(JNIEnv *env, ArrayType array, jsize start, jsize len, NativeType *buf);
  • array:Java指针。
  • start:起始下标。
  • len:要复制的元素数。
  • buf:目的缓冲区。
 	*GetArrayRegion例程*	 	数组类型	 	本地类型	 
 	GetBooleanArrayRegion()	 	jbooleanArray	 	jboolean	 
 	GetByteArrayRegion()	 	jbyteArray	 	jbyte	 
 	GetCharArrayRegion()	 	jcharArray	 	jchar	 
 	GetShortArrayRegion()	 	jshortArray	 	jshort	 
 	GetIntArrayRegion()	 	jintArray	 	jint	 
 	GetLongArrayRegion()	 	jlongArray	 	jlong	 
 	GetFloatArrayRegion()	 	jfloatArray	 	jfloat	 
 	GetDoubleArrayRegion()	 	jdoubleArray	 	jdouble	 

SetArrayRegion例程

将基本类型数组的某一区域从缓冲区中复制回来的一组函数。

void Set<PrimitiveType>ArrayRegion(JNIEnv *env, ArrayType array, jsize start, jsize len, NativeType *buf);
  • array: Java数组。
  • start:起始下标。
  • len:要复制的元素数。
  • buf:源缓冲区。
 	*SetArrayRegion例程*	 	数组类型	 	本地类型	 
 	SetBooleanArrayRegion()	 	jbooleanArray	 	jboolean	 
 	SetByteArrayRegion()	 	jbyteArray	 	jbyte	 
 	SetCharArrayRegion()	 	jcharArray	 	jchar	 
 	SetShortArrayRegion()	 	jshortArray	 	jshort	 
 	SetIntArrayRegion()	 	jintArray	 	jint	 
 	SetLongArrayRegion()	 	jlongArray	 	jlong	 
 	SetFloatArrayRegion()	 	jfloatArray	 	jfloat	 
 	SetDoubleArrayRegion()	 	jdoubleArray	 	jdouble	 

Demo 示例

Cpp调用C

invoker.cpp

#include <jni.h>
#include <string>
#include "jcf.h"

namespace ccf {
    void whatS2(JNIEnv *env, jobject jthiz);
}
using namespace ccf;

extern "C" JNIEXPORT jstring

JNICALL
Java_com_example_hoperun1_MainActivity_stringFromJNI(
        JNIEnv *env, jobject thiz) {
    std::string hello = "Hello from C++";
    //
    // using namespace
    whatS2(env, thiz);
    // 
    // JNIJcf
    JNIJcf *j;
    jint grade = j->GetGrade(thiz);
    // end
    return env->NewStringUTF(hello.c_str());
}

如果在C中调用JNIJcf,则:

#include "jcf.h"
// ...

// JNIJcf
JNIJcf *jcf;
(*jcf)->GetGrade(jcf, jthiz);
// end

实现namespace方法

whatS2.cpp

#include "jni.h"

namespace ccf {

void whatS2(JNIEnv *env, jobject jthiz) {
    jintArray intArray = env->NewIntArray(2);
    jint buf[2];
    buf[0] = 1;
    buf[1] = 3;
    // this, jintArray array, jsize start, jsize len, const jint* buf
    env->SetIntArrayRegion(intArray, 0, 2, buf);
    // 从jintArray中获取数值并赋值给int数组
    env->GetIntArrayRegion(intArray, 0, 2, buf);
    // 从jintArray中获取数值并把数值以数组形式返回
    jint *newBuf = env->GetIntArrayElements(intArray, NULL);
    // 释放intArray
    env->ReleaseIntArrayElements(intArray, newBuf, 0);
}

}

定义C/C++适用函数

jcf.h

#include "jni.h"

#ifndef HOPERUN1_JCF_H
#define HOPERUN1_JCF_H

struct _JNIJcf;
typedef const struct JNIJcfInterface* C_JNIJcf;

#if defined(__cplusplus)
typedef _JNIJcf JNIJcf;
#else
typedef const struct JNIJcfInterface* JNIJcf;
#endif

struct JNIJcfInterface {
    jint (*GetGrade)(JNIJcf*, jobject);
};

struct _JNIJcf {
    const struct JNIJcfInterface* functions;

#if defined(__cplusplus)
    jint GetGrade(jobject obj) {
        return functions->GetGrade(this, obj);
    }
#endif

};

#endif //HOPERUN1_JCF_H

Camera

/Users/ccfyyn/Downloads/android-6.0.1_r72/developers/samples/android/media/Camera2Video
/Users/ccfyyn/Downloads/android-6.0.1_r72/development/samples/B*
/Users/ccfyyn/Downloads/android-6.0.1_r72/external/aac/documentation
/Users/ccfyyn/Downloads/android-6.0.1_r72/hardware/libhardware/modules/camera
/Users/ccfyyn/Downloads/android-6.0.1_r72/packages/apps/Camera

NDK:
/Users/ccfyyn/Library/Android/sdk/ndk-bundle
/Users/ccfyyn/Library/Android/sdk/ndk-bundle/platforms/android-24/arch-arm64/usr/include

javah com.jni.JniTeach 命令生成头文件, 该头文件引用了 jni.h, 以及定义好了对应的 Native 方法。
javap -s com.jni.JniTeach 命令生成Java文件中的方法签名。

jstring (NewString)(JNIEnv, const jchar*, jsize);
jsize (GetStringLength)(JNIEnv, jstring);
const jchar* (GetStringChars)(JNIEnv, jstring, jboolean*);
void (ReleaseStringChars)(JNIEnv, jstring, const jchar*);
jstring (NewStringUTF)(JNIEnv, const char*);
jsize (GetStringUTFLength)(JNIEnv, jstring);

类操作&对象操作

类操作

DefineClass

从原始类数据的缓冲区中加载类。

jclass DefineClass(const char *name, jobject loader, const jbyte* buf, jsize bufLen)
  • loader:分派给所定义的类的类加载器
  • buf:包含.class文件数据的缓冲区
  • bufLen:缓冲区长度。

返回值:返回Java类对象。如果出错则返回NULL。
抛出:ClassFormatError:如果类数据指定的类无效。ClassCircularityError:如果类或接口是自身的超类或超接口。OutOfMemoryError:如果系统内存不足。

FindClass

加载本地定义的类。它将搜索由CLASSPATH环境变量为具有指定名称的类所指定的目录和zip文件。

jclass FindClass(JNIEnv *env, const char *name);
  • name:类全名(即包名后跟类名,之间由“/”分隔)。如果该名称以“[”(数组签名字符)打头,则返回一个数组类。
    返回值:返回类对象全名。如果找不到该类,则返回NULL。

GetSuperclass

如果clazz代表类而非类object,则该函数返回由clazz所指定的类的超类。如果clazz指定类object或代表某个接口,则该函数返回NULL。

jclass GetSuperclass(JNIEnv *env, jclass clazz);
  • clazz:Java类对象。
    返回值:由clazz所代表的类的超类或NULL。

IsAssignableFrom

确定clazz1的对象是否可安全地强制转换为clazz2。

jboolean IsAssignableFrom(JNIEnv *env, jclass clazz1, jclass clazz2);
  • clazz1:第一个类参数。
  • clazz2:第二个类参数。
    返回值:下列某个情况为真时返回JNI_TRUE:第一及第二个类参数引用同一个Java类。第一个类是第二个类的子类。第二个类是第一个类的某个接口。

全局或局部引用

NewGlobalRef

创建obj参数所引用对象的新全局引用。obj参数既可以是全局引用,也可以是局部引用。全局引用通过调用DeleteGlobalRef()来显式撤消。

jobject NewGlobalRef(JNIEnv *env, jobject obj);
  • obj:全局或局部引用。
    返回值:返回全局引用。如果系统内存不足则返回NULL。

DeleteGlobalRef

删除globalRef所指向的全局引用。

void DeleteGlobalRef(JNIEnv *env, jobject globalRef);
  • globalRef:全局引用。

DeleteLocalRef

删除localRef所指向的局部引用。

void DeleteLocalRef(JNIEnv *env, jobject localRef);
  • localRef:局部引用。

对象操作

AllocObject

分配新Java对象而不调用该对象的任何构造函数。返回该对象的引用。clazz参数务必不要引用数组类。

jobject AllocObject(JNIEnv *env, jclass clazz);
  • clazz:Java类对象。
    返回值:返回Java对象。如果无法构造该对象,则返回NULL。

NewObject NewObjectA NewObjectV

jobject NewObject(JNIEnv *env, jclass clazz, jmethodID methodID, ...);
jobject NewObjectA(JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args);
jobject NewObjectV(JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);
  • clazz:Java类对象。
  • methodID:构造函数的方法ID。
    方法ID指示应调用的构造函数方法。该ID必须通过调用**GetMethodID()**获得,且调用时的方法名必须为构造方法,而返回类型必须为void(V)。clazz参数务必不要引用数组类。

NewObjectA#args,将所有参数放到jvalue类型的数组当中。
NewObjectV#args,将所有参数放到va_list类型的参数当中。

GetObjectClass

返回对象的类。

jclass GetObjectClass(JNIEnv *env, jobject obj);

IsInstanceOf

测试对象是否为某个类的实例。

jboolean IsInstanceOf(JNIEnv *env, jobject obj, jclass clazz);
  • obj:Java对象。
  • clazz:Java类对象。

IsSameObject

测试两个引用是否引用同一Java对象。

jboolean IsSameObject(JNIEnv *env, jobject ref1, jobject ref2);
  • ref1:Java对象。
  • ref2:Java对象。

读&写 Field

GetFieldID

返回类的实例对象的字段ID。该字段由其名称及签名指定。访问器函数的GetField及SetField系列使用域ID检索对象域。 GetFieldID()将未初始化的类初始化。

jfieldID GetFieldID(JNIEnv *env, jclass clazz, const char *name, const char *sig);
  • clazz:Java类对象。
  • name: 字段名。
  • sig:字段签名(类型)。

GetFieldID()不能用于获取数组的长度属性。应使用GetArrayLength()

GetTypeField

NativeType Get<type>Field(JNIEnv *env, jobject obj, jfieldID fieldID);
  • obj:Java对象(不能为 NULL)。
  • fieldID:有效的字段ID。
 	*GetField例程名*	 	返回类型	 
 	GetObjectField()	 	jobject	 
 	GetBooleanField()	 	jboolean	 
 	GetByteField()	 	jbyte	 
 	GetCharField()	 	jchar	 
 	GetShortField()	 	jshort	 
 	GetIntField()	 	jint	 
 	GetLongField()	 	jlong	 
 	GetFloatField()	 	jfloat	 
 	GetDoubleField()	 	jdouble	 

SettypeField

void Set<type>Field(JNIEnv *env, jobject obj, jfieldID fieldID, NativeType value);
  • obj:Java对象(不能为 NULL)。
  • fieldID:有效的域ID。
 	*SetField例程名*	 	本地类型	 
 	SetObjectField()	 	jobject	 
 	SetBooleanField()	 	jboolean	 
 	SetByteField()	 	jbyte	 
 	SetCharField()	 	jchar	 
 	SetShortField()	 	jshort	 
 	SetIntField()	 	jint	 
 	SetLongField()	 	jlong	 
 	SetFloatField()	 	jfloat	 
 	SetDoubleField()	 	jdouble

调用Method

GetMethodID

jmethodID GetMethodID(JNIEnv *env, jclass clazz, const char *name, const char *sig);

返回类或接口实例(非静态)方法的方法ID。方法可在某个clazz的超类中定义,也可从clazz继承。该方法由其名称和签名决定。GetMethodID()可使未初始化的类初始化。要获得构造函数的方法ID,应将作为方法名,同时将void (V)作为返回类型。

  • clazz:Java类对象。
  • name:方法名。
  • sig:方法签名。
    返回值:方法ID,如果找不到指定的方法,则为NULL。

CallMethod,CallMethodA,CallMethodV

从本地方法调用Java实例方法。它们的差别仅在于向其所调用的方法传递参数时所用的机制。这三个操作将根据所指定的方法ID 调用Java对象的实例(非静态)方法。参数methodID必须通过调用GetMethodID()来获得。

NativeType Call<type>Method(JNIEnv *env, jobject obj, jmethodID methodID, ...);
NativeType Call<type>MethodA(JNIEnv *env, jobject obj, jmethodID methodID, jvalue *args);
NativeType Call<type>MethodV(JNIEnv *env, jobject obj, jmethodID methodID, va_list args);
  • obj:Java对象。
  • methodID:方法ID。

当这些函数用于调用私有方法和构造函数时,方法ID必须从obj的真实类派生而来,而不应从其某个超类派生。

 	*CallMethod例程名*	 	                                    返回类型	 
 	CallVoidMethod() CallVoidMethodA() CallVoidMethodV()	 	void	 
 	CallObjectMethod() CallObjectMethodA() CallObjectMethodV()	 	jobject	 
 	CallBooleanMethod() CallBooleanMethodA() CallBooleanMethodV()	 	jboolean	 
 	CallByteMethod() CallByteMethodA() CallByteMethodV()	 	jbyte	 
 	CallCharMethod() CallCharMethodA() CallCharMethodV()	 	jchar	 
 	CallShortMethod() CallShortMethodA() CallShortMethodV()	 	jshort	 
 	CallIntMethod() CallIntMethodA() CallIntMethodV()	 	jint	 
 	CallLongMethod() CallLongMethodA() CallLongMethodV()	 	jlong	 
 	CallFloatMethod() CallFloatMethodA() CallFloatMethodV()	 	jfloat	 
 	CallDoubleMethod() CallDoubleMethodA() CallDoubleMethodV()	 	jdouble	 

CallNonvirtualMethod,CallNonvirtualMethodA,CallNonvirtualMethodV例程

根据指定的类和方法ID调用某Java对象的实例(非静态)方法。参数methodID必须通过调用clazz类的 GetMethodID()获得。CallNonvirtualMethodCallMethod并不相同。
CallMethod根据对象的实例调用方法,而CallNonvirtualMethod则根据获得方法ID的(由clazz参数指定)类调用方法。方法ID必须从对象的真实类或 其某个超类获得。

NativeType CallNonvirtual<type>Method(JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);
NativeType CallNonvirtual<type>MethodA(JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, jvalue *args);
NativeType CallNonvirtual<type>MethodV(JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, va_list args);
  • clazz:Java类。
  • obj: Java对象。
  • methodID:方法ID。
 	*CallNonvirtualMethod例程名*	                                                    	返回类型	 
 	CallNonvirtualVoidMethod() CallNonvirtualVoidMethodA() CallNonvirtualVoidMethodV()	 	void	 
 	CallNonvirtualObjectMethod() CallNonvirtualObjectMethodA() CallNonvirtualObjectMethodV()	 	jobject	 
 	CallNonvirtualBooleanMethod() CallNonvirtualBooleanMethodA() CallNonvirtualBooleanMethodV()	 	jboolean	 
 	CallNonvirtualByteMethod() CallNonvirtualByteMethodA() CallNonvirtualByteMethodV()	 	jbyte	 
 	CallNonvirtualCharMethod() CallNonvirtualCharMethodA() CallNonvirtualCharMethodV()	 	jchar	 
 	CallNonvirtualShortMethod() CallNonvirtualShortMethodA() CallNonvirtualShortMethodV()	 	jshort	 
 	CallNonvirtualIntMethod() CallNonvirtualIntMethodA() CallNonvirtualIntMethodV()	 	jint	 
 	CallNonvirtualLongMethod() CallNonvirtualLongMethodA() CallNonvirtualLongMethodV()	 	jlong	 
 	CallNonvirtualFloatMethod() CallNonvirtualFloatMethodA() CallNonvirtualFloatMethodV()	 	jfloat	 
 	CallNonvirtualDoubleMethod() CallNonvirtualDoubleMethodA() CallNonvirtualDoubleMethodV()	 	jdouble	 

访问静态字段

GetStaticFieldID

返回类的静态域的域ID。域由其名称和签名指定。GetStaticField和SetStaticField访问器函数系列使用域ID检索静态域。GetStaticFieldID()将未初始化的类初始化。

jfieldID GetStaticFieldID(JNIEnv *env, jclass clazz, const char *name, const char *sig);
  • clazz:Java类对象。
  • name: 字段名。
  • sig:字段类型签名。
    返回值:域ID。如果找不到指定的静态域,则为NULL。

GetStaticField

NativeType GetStatic<type>Field(JNIEnv *env, jclass clazz, jfieldID fieldID);
  • clazz:Java类对象。
  • fieldID:静态域ID。
    返回值:静态域的内容。
 	*GetStaticField例程名*	 	本地类型	 
 	GetStaticObjectField()	 	jobject	 
 	GetStaticBooleanField()	 	jboolean	 
 	GetStaticByteField()	 	jbyte	 
 	GetStaticCharField()	 	jchar	 
 	GetStaticShortField()	 	jshort	 
 	GetStaticIntField()	 	jint	 
 	GetStaticLongField()	 	jlong	 
 	GetStaticFloatField()	 	jfloat	 
 	GetStaticDoubleField()	 	jdouble	 

SetStaticField

该访问器例程系列设置对象的静态字段的值。要访问的域由通过调用GetStaticFieldID()而得到的域ID指定。

void SetStatic<type>Field(JNIEnv *env, jclass clazz, jfieldID fieldID, NativeType value);
  • clazz:Java类对象。
  • fieldID:静态域ID。
  • value:域的新值。
 	*SetStaticField例程名*	 	本地类型	 
 	SetStaticObjectField()	 	jobject	 
 	SetStaticBooleanField()	 	jboolean	 
 	SetStaticByteField()	 	jbyte	 
 	SetStaticCharField()	 	jchar	 
 	SetStaticShortField()	 	jshort	 
 	SetStaticIntField()	 	jint	 
 	SetStaticLongField()	 	jlong	 
 	SetStaticFloatField()	 	jfloat	 
 	SetStaticDoubleField()	 	jdouble	 

静态方法

GetStaticMethodID

返回类的静态方法的方法ID。方法由其名称和签名指定。GetStaticMethodID()将未初始化的类初始化。

jmethodID GetStaticMethodID(JNIEnv *env, jclass clazz, const char *name, const char *sig);
  • clazz:Java类对象。
  • name:静态的方法名。
  • sig:方法签名。
    返回值:方法ID,如果操作失败,则为NULL。

CallStaticMethod,CallStaticMethodA,CallStaticMethodV

这些操作将根据指定的方法ID调用Java对象的静态方法。methodID参数必须通过调用GetStaticMethodID()得到。方法ID必须从clazz派生,而不能从其超类派生。

NativeType CallStatic<type>Method(JNIEnv *env, jclass clazz, jmethodID methodID, ...);
NativeType CallStatic<type>MethodA(JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args);
NativeType CallStatic<type>MethodV(JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);
  • clazz:Java类对象。
  • methodID:静态方法ID。
 	*CallStaticMethod例程名*	 	本地类型	 
 	CallStaticVoidMethod() CallStaticVoidMethodA() CallStaticVoidMethodV()	 	void	 
 	CallStaticObjectMethod() CallStaticObjectMethodA() CallStaticObjectMethodV()	 	jobject	 
 	CallStaticBooleanMethod() CallStaticBooleanMethodA() CallStaticBooleanMethodV()	 	jboolean	 
 	CallStaticByteMethod() CallStaticByteMethodA() CallStaticByteMethodV()	 	jbyte	 
 	CallStaticCharMethod() CallStaticCharMethodA() CallStaticCharMethodV()	 	jchar	 
 	CallStaticShortMethod() CallStaticShortMethodA() CallStaticShortMethodV()	 	jshort	 
 	CallStaticIntMethod() CallStaticIntMethodA() CallStaticIntMethodV()	 	jint	 
 	CallStaticLongMethod() CallStaticLongMethodA() CallStaticLongMethodV()	 	jlong	 
 	CallStaticFloatMethod() CallStaticFloatMethodA() CallStaticFloatMethodV()	 	jfloat	 
 	CallStaticDoubleMethod() CallStaticDoubleMethodA() CallStaticDoubleMethodV()	 	jdouble	 

CMakeLists

cmake_minimum_required(VERSION 3.4.1)

# app/src/main/cpp
set(PATH_TO_MEDIACORE ${CMAKE_SOURCE_DIR}/src/main/cpp)
# app/src/main/cpp/thirdparty
set(PATH_TO_THIRDPARTY ${PATH_TO_MEDIACORE}/thirdparty)
# app/src/main/jni
set(PATH_TO_JNI_LAYER ${CMAKE_SOURCE_DIR}/src/main/jni)

include_directories( ${PATH_TO_MEDIACORE}/)
include_directories(BEFORE ${PATH_TO_THIRDPARTY}/ffmpeg/include/)
# app/src/main/cpp/thirdparty/prebuilt/armeabi-v7a/
set(PATH_TO_PRE_BUILT ${PATH_TO_THIRDPARTY}/prebuilt/${ANDROID_ABI})

# app/src/main/cpp
file(GLOB FILES_TEST "${PATH_TO_MEDIACORE}/*.cpp")
# app/src/main/jni/
file(GLOB FILES_JNI_LAYER "${PATH_TO_JNI_LAYER}/*.cpp")

add_library(native-lib
            SHARED
            ${FILES_TEST}
            ${FILES_JNI_LAYER})

target_link_libraries(native-lib
                      # 引入系统的动态库
                      log
                      android
                      GLESv2
                      EGL
                      z
                      OpenSLES
                      # 引入ffmpeg相关静态库
                      ${PATH_TO_PRE_BUILT}/libavfilter.a
                      ${PATH_TO_PRE_BUILT}/libavformat.a
                      ${PATH_TO_PRE_BUILT}/libavcodec.a
                      ${PATH_TO_PRE_BUILT}/libpostproc.a
                      ${PATH_TO_PRE_BUILT}/libswresample.a
                      ${PATH_TO_PRE_BUILT}/libswscale.a
                      ${PATH_TO_PRE_BUILT}/libavutil.a
                      ${PATH_TO_PRE_BUILT}/libpostproc.a
                      ${PATH_TO_PRE_BUILT}/libfdk-aac.a
                      ${PATH_TO_PRE_BUILT}/libvo-aacenc.a
                      ${PATH_TO_PRE_BUILT}/libx264.a
                      ${PATH_TO_PRE_BUILT}/libsox.a
					  )
## https://github.com/ViewMikeZhou/ffmpeg_demo

YUVtoARGB

YUVtoARGB

Java代码:

public static native void YUVtoARGB(byte[] yuv, int width, int height, int[] out);

C代码:

#include <jni.h>
#include <android/log.h>

JNIEXPORT void JNICALL
Java_com_ccflying_JNIBitmap_YUVtoARGB(JNIEnv *env, jobject obj,
                                 jbyteArray yuv420sp,
                                 jint width, jint height,
                                 jintArray rgbOut) {
    // byte[] yuv, int width, int height, int[] out
    int sz;
    int i;
    int j;
    int Y;
    int U = 0;
    int V = 0;
    int pixPtr = 0;
    int jDiv2 = 0;
    int R = 0;
    int G = 0;
    int B = 0;
    int cOff;
    //
    int w = width;
    int h = height;
    // 总像素点个数
    sz = w * h;
    // 输出结果: pixels
    jint *rgbData = (jint *) ((*env)->GetPrimitiveArrayCritical(env, rgbOut, 0));
    // Camera原始byte数据
    jbyte *yuv = (jbyte *) (*env)->GetPrimitiveArrayCritical(env, yuv420sp, 0);

    for (j = 0; j < h; j++) { // height: 从上到下
        pixPtr = j * w; // 第 j 行左侧位置索引
        jDiv2 = j >> 1; // jDiv2为j整除2
        for (i = 0; i < w; i++) { // width: 从左到右
            Y = yuv[pixPtr]; // Y 行第 i 个像素点
            if (Y < 0) Y += 255;
            // ? (i & 0x1) 表示 i 为单数(奇数),1, 3, 5, 7, 9
            if ((i & 0x1) != 1) {
                cOff = sz + jDiv2 * w + (i >> 1) * 2;
                U = yuv[cOff]; // U
                V = yuv[cOff + 1]; // V
                if (U < 0) U += 127; else U -= 128;
                if (V < 0) V += 127; else V -= 128;
            } // 使用的是 comment#2 中的4:2:2采样格式

            //ITU-R BT.601 conversion
            //
            //R = 1.164*(Y-16) + 2.018*(U-128);
            //G = 1.164*(Y-16) - 0.813*(V-128) - 0.391*(U-128);
            //B = 1.164*(Y-16) + 1.596*(V-128);
            //
            Y = Y + (Y >> 3) + (Y >> 5) + (Y >> 7);
            // R
            R = Y + (int)(1.4f * U);
            R = limitRGBValue(R);
            // G
            G = Y - (int)(0.344f * V + 0.714f * U);
            G = limitRGBValue(G);
            // B
            B = Y + (int)(1.77f * V);
            B = limitRGBValue(B);
            // 写入进结果 pixels
            rgbData[pixPtr++] = 0xff000000 + (R << 16) + (G << 8) + B;
            // ARBG?
            // rgbData[pixPtr++] = 0xff000000 + (B << 16) + (G << 8) + R;
        }
    }
    // release
    (*env)->ReleasePrimitiveArrayCritical(env, rgbOut, rgbData, 0);
    (*env)->ReleasePrimitiveArrayCritical(env, yuv420sp, yuv, 0);
}

// 限制RGB值的范围为[0-255]
int limitRGBValue(int input) {
    if (input < 0)
        input = 0;
    else if (input > 255)
        input = 255;
    return input;
}

Link

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.