Ijklayer是目前最火的手机玩家。它同时支持Android和iOS。这是一个开源的播放器库,来自著名的bilibili。它在GitHub上有15.2K的启动。
之所以这么流行,主要是代码太漂亮了。把它当艺术品看,我觉得不过分,没看过它代码的同学可以了解一下。
Ijkplayer做了很多优化来提高性能,其中一个关键点就是使用了JNI。边缘广播最关键的部分都是用C实现的..
今天,我们来看看jikplayer是如何使用JNI的。
导入动态库当ijkplayer创建一个IJKMediaPlayer对象时,它将被转移到其构造函数中的loadLibrariesOnce方法。代码如下:
loadLibrariesOnce方法中的libLoader是由ijkplayer定义的IjkLibLoader类对象。这个对象的loadLibrary方法最终将调用System.loadLibrary函数来完成共享库的加载。
在上述操作之后,ijkffmpeg、ijdsdk和ijkplayer被加载到JavaVM中。
在Android系统下,每一个进程只能有一个JavaVM。第一步是看如何通过ijkplayer中的Java代码调至C/C++接口。
在Java层定义本地方法如果想通过Java代码调用C/C++代码,需要让Java程序知道哪些C/C++接口可以使用。这有点像C/C++里经常说的符号表(名字和地址的对应表)。怎么才能做到这一点?方法很简单,就是在Java类方法前面加上关键字“native”。让我们看看IJKPlayer提供的本地方法:
这是不是很简单的一步?
当然,你不能只在这一步调用C/C++接口,因为你还没有告诉JavaVM你的C/C++接口在哪里。让我们开始第二步。
注册C/C++方法在Java层定义本地方法只是工作的一半。当Java代码实际调用“本机”方法时,JavaVM虚拟机会在其符号表中搜索Java程序想要调用的任何函数。如果此时不可用,JavaVM将报告一个错误。所以现在需要把C/C++提供的接口注册到JavaVM中。
首先,建立一个函数对应表。该表中的每一项都包括三个元素,即外部调用的接口名称、签名和真实的内部实现函数。
signature 后面有专门的讲解。代码如下:
看看这里的外部调用函数名和Java层上面定义的方法名是不是一样的?只有一件事,他们才能建立相应的关系。
然后,将上表中的方法注册到JavaVM中。代码如下:
上面的代码看起来是不是有点混乱?尤其是宏定义IJK_FIND_JAVA_CLASS?其实没关系,只要我们知道上面代码的核心是通过findcast找到定义局部方法的java类,然后通过RegisterNatives函数把C/C++接口注册到JavaVM中,和findcast找到的类绑定。
在哪儿注册最好以上,我们知道如何注册C/C++,那么在哪里注册呢?答案在JNI函数中。在加载DLL的时候,JavaVM会主动调用JNI_(JavaVM * jvm,void * reserved)(如果实现JNI_函数的话),所以这里是注册的最好的地方。看看ijkplayer的实现:
先在JNI_函数中获取JNIEnv,然后找到ijkmediplayer类,最后注册C/C++方法,将注册的方法与ijkmediplayer类关联。
当然,有了JNI_,就一定有JNI_OnUnload功能。卸载共享库时调用,这里可以释放一些资源。
通过以上操作,我们可以从Java调用C++代码。你有快速尝试的冲动吗?不用担心,现在只介绍如何从Java调用C/C++的方法。那么如何从C/C++调优Java代码呢?
C/C++调用Java方法在ijkplayer中,它会用c来调用android下的MediaCodec类中的方法。让我们以此为例,看看它是如何从c调用java方法的。
首先,通过FindClass获取要处理的类的jclass对象。然后获取对象的全局引用,删除局部引用。
这些方法的调用都要做异常判断,如果出现异常所有的结果都是无效的值。获得jclass后,您可以获得
最后,打电话
现在C/C++也可以调用Java方法。_
最后,我们来看看C/C++如何访问java字段,这就更简单了。
C/C++访问Java字段有了C/C++访问Java的基础,访问Java字段就容易多了。它也是先获取jclass,然后通过jclass获取jfieldID,最后获取/设置Java字段。我们不会谈论获取jclass,但会重点关注获取jfieldID和Get/Set。
上面的代码通过GetFieldID方法得到了我们想要的jfieldID。下一步是看如何获取/设置。
很简单,JNI的电话
至此,我们已经完成了对ijkplayer使用JNI的分析。附上签名说明。
Signature在JNI,签名主要用于操作Java类中的方法。签名一般由两部分组成:方法参数;方法返回值。
方法参数包含在“()”中,返回值在括号外!方法参数个数较多时会依次以“;”隔开。当参数或者返回值是基本数据类型时,必须用其在JNI中的描述符表示。下表就是Java基本数据类型对应的JNI中的描述符。 方法参数或者返回值为java中的对象时,必须以“L”加上其路径,不过路径必须以“/”分开,自定义的对象也使用本规则,不在包中时直接“L”加上类名称。当参数或者返回值为数组时,前面必须加上“[”。看看下面的签名。能否一一转换成相应的方法?
([LStudent;)[LStudent;([I[Ljava/lang/String;[LStudent;)Ljava/lang/Object;([LStudent;[LStudent;)[LStudent;([Ljava/util/Iterator;)[Ljava/util/Enumeration;([Ljava/lang/Object;)[Ljava/lang/Object;([Ljava/lang/String;)[Ljava/lang/String;(LStudent;)LStudent;小结本文介绍了ijkplayer如何使用JNI,主要包括以下内容:
Java 如何调用 C/C++ 接口。C/C++ 如何调用 Java 方法。C/C++ 如何设置/获取 Java 字段的值。链接:https://www.jianshu.com/p/aa6efea4ef35
1.《ijkplayer 「音视频直播技术」看ijkplayer如何使用JNI》援引自互联网,旨在传递更多网络信息知识,仅代表作者本人观点,与本网站无关,侵删请联系页脚下方联系方式。
2.《ijkplayer 「音视频直播技术」看ijkplayer如何使用JNI》仅供读者参考,本网站未对该内容进行证实,对其原创性、真实性、完整性、及时性不作任何保证。
3.文章转载时请保留本站内容来源地址,https://www.lu-xu.com/yule/762236.html