Ijklayer是目前最火的手機(jī)玩家。它同時支持Android和iOS。是來自著名b站的開源播放器庫。它在GitHub上有15.2K的啟動。
之所以這么流行,主要是代碼太漂亮了。把它當(dāng)藝術(shù)品看,我覺得不過分,沒看過它代碼的同學(xué)可以了解一下。
Ijkplayer做了很多優(yōu)化來提高性能,其中一個關(guān)鍵點就是使用了JNI。邊緣廣播最關(guān)鍵的部分都是用C實現(xiàn)的..
今天,我們來看看jikplayer是如何使用JNI的。
導(dǎo)入動態(tài)庫當(dāng)ijkplayer創(chuàng)建一個IJKMediaPlayer對象時,它將被轉(zhuǎn)移到其構(gòu)造函數(shù)中的loadLibrariesOnce方法。代碼如下:
loadLibrariesOnce方法中的libLoader是由ijkplayer定義的IjkLibLoader類對象。這個對象的loadLibrary方法最終將調(diào)用System.loadLibrary函數(shù)來完成共享庫的加載。
在上述操作之后,ijkffmpeg、ijdsdk和ijkplayer被加載到JavaVM中。
在Android系統(tǒng)下,每一個進(jìn)程只能有一個JavaVM。第一步是看如何通過ijkplayer中的Java代碼調(diào)至C/C++接口。
在Java層定義本地方法如果想通過Java代碼調(diào)用C/C++代碼,需要讓Java程序知道哪些C/C++接口可以使用。這有點像C/C++里經(jīng)常說的符號表(名字和地址的對應(yīng)表)。怎么才能做到這一點?方法很簡單,就是在Java類方法前面加上關(guān)鍵字“native”。讓我們看看IJKPlayer提供的本地方法:
這是不是很簡單的一步?
當(dāng)然,你不能只在這一步調(diào)用C/C++接口,因為你還沒有告訴JavaVM你的C/C++接口在哪里。讓我們開始第二步。
注冊C/C++方法在Java層定義本地方法只是工作的一半。當(dāng)Java代碼實際調(diào)用“本機(jī)”方法時,JavaVM虛擬機(jī)會在其符號表中搜索Java程序想要調(diào)用的任何函數(shù)。如果此時不可用,JavaVM將報告一個錯誤。所以現(xiàn)在需要把C/C++提供的接口注冊到JavaVM中。
首先,建立一個函數(shù)對應(yīng)表。該表中的每一項都包括三個元素,即外部調(diào)用的接口名稱、簽名和真實的內(nèi)部實現(xiàn)函數(shù)。
signature 后面有專門的講解。代碼如下:
看看這里的外部調(diào)用函數(shù)名和Java層上面定義的方法名是不是一樣的?只有一件事,他們才能建立相應(yīng)的關(guān)系。
然后,將上表中的方法注冊到JavaVM中。代碼如下:
上面的代碼看起來是不是有點混亂?尤其是宏定義IJK_FIND_JAVA_CLASS?其實沒關(guān)系,只要我們知道上面代碼的核心是通過findcast找到定義局部方法的java類,然后通過RegisterNatives函數(shù)把C/C++接口注冊到JavaVM中,和findcast找到的類綁定。
在哪兒注冊最好以上,我們知道如何注冊C/C++,那么在哪里注冊呢?答案在JNI函數(shù)中。在加載動態(tài)鏈接庫時,JavaVM會主動調(diào)用JNI_(JavaVM * jvm,void * reserved)(如果實現(xiàn)了JNI_函數(shù)),所以這里注冊是最好的地方??纯磇jkplayer的實現(xiàn):
先在JNI_函數(shù)中獲取JNIEnv,然后找到ijkmediplayer類,最后注冊C/C++方法,將注冊的方法與ijkmediplayer類關(guān)聯(lián)。
當(dāng)然,有了JNI_,就一定有JNI_OnUnload功能。卸載共享庫時調(diào)用,這里可以釋放一些資源。
通過以上操作,我們可以從Java調(diào)用C++代碼。你有快速嘗試的沖動嗎?不用擔(dān)心,現(xiàn)在只介紹如何從Java調(diào)用C/C++的方法。那么如何從C/C++調(diào)優(yōu)Java代碼呢?
C/C++調(diào)用Java方法在ijkplayer中,它會用c來調(diào)用android下的MediaCodec類中的方法。讓我們以此為例,看看它是如何從c調(diào)用java方法的。
首先,通過FindClass獲取要處理的類的jclass對象。然后獲取對象的全局引用,刪除局部引用。
這些方法的調(diào)用都要做異常判斷,如果出現(xiàn)異常所有的結(jié)果都是無效的值。獲得jclass后,您可以獲得
最后,打電話
現(xiàn)在C/C++也可以調(diào)用Java方法。_
最后,我們來看看C/C++如何訪問java字段,這就更簡單了。
C/C++訪問Java字段有了C/C++訪問Java的基礎(chǔ),訪問Java字段就容易多了。它也是先獲取jclass,然后通過jclass獲取jfieldID,最后獲取/設(shè)置Java字段。我們不會談?wù)摣@取jclass,但會重點關(guān)注獲取jfieldID和Get/Set。
上面的代碼通過GetFieldID方法得到了我們想要的jfieldID。下一步是看如何獲取/設(shè)置。
很簡單,JNI的電話
至此,我們已經(jīng)完成了對ijkplayer使用JNI的分析。附上簽名說明。
Signature在JNI,簽名主要用于操作Java類中的方法。簽名一般由兩部分組成:方法參數(shù);方法返回值。
方法參數(shù)包含在“()”中,返回值在括號外!方法參數(shù)個數(shù)較多時會依次以“;”隔開。當(dāng)參數(shù)或者返回值是基本數(shù)據(jù)類型時,必須用其在JNI中的描述符表示。下表就是Java基本數(shù)據(jù)類型對應(yīng)的JNI中的描述符。看看下面的簽名。能否一一轉(zhuǎn)換成相應(yīng)的方法?
([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;小結(jié)本文介紹了ijkplayer如何使用JNI,主要包括以下內(nèi)容:
Java 如何調(diào)用 C/C++ 接口。C/C++ 如何調(diào)用 Java 方法。C/C++ 如何設(shè)置/獲取 Java 字段的值。鏈接:https://www.jianshu.com/p/aa6efea4ef35
1.《ijk 「音視頻直播技術(shù)」看ijkplayer如何使用JNI》援引自互聯(lián)網(wǎng),旨在傳遞更多網(wǎng)絡(luò)信息知識,僅代表作者本人觀點,與本網(wǎng)站無關(guān),侵刪請聯(lián)系頁腳下方聯(lián)系方式。
2.《ijk 「音視頻直播技術(shù)」看ijkplayer如何使用JNI》僅供讀者參考,本網(wǎng)站未對該內(nèi)容進(jìn)行證實,對其原創(chuàng)性、真實性、完整性、及時性不作任何保證。
3.文章轉(zhuǎn)載時請保留本站內(nèi)容來源地址,http://f99ss.com/keji/762198.html