<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          IjkPlayer系列之播放器創(chuàng)建流程

          共 10263字,需瀏覽 21分鐘

           ·

          2022-04-01 21:17

          ?

          ?7c140c186a54f1470b999f0987fa2873.webp今天介紹下 IjkPlayer 的播放器創(chuàng)建流程,本文開(kāi)始將正式開(kāi)始 IjkPlayer 的源碼閱讀之旅,閱讀之前可以先看前面同系列文章:
          主要內(nèi)容如下:
          1. 初始化so

          2. Java層播放器創(chuàng)建

          3. IjkMediaPlayer結(jié)構(gòu)體

          4. Native層播放器創(chuàng)建

          5. 調(diào)用流程圖

          初始化so

          從 IjkPlayer 源碼中VideoActivity查看 IjkPlayer 的初始化,關(guān)鍵代碼如下:
          1//?加載so庫(kù)
          2IjkMediaPlayer.loadLibrariesOnce(null);
          3//?android-ndk-profiler性能分析
          4IjkMediaPlayer.native_profileBegin("libijkplayer.so");
          查看loadLibrariesOnce源碼如下:
           1private?static?volatile?boolean?mIsLibLoaded?=?false;
          2public?static?void?loadLibrariesOnce(IjkLibLoader?libLoader)?{
          3????synchronized?(IjkMediaPlayer.class)?{
          4????????//?保證只加載一次
          5????????if?(!mIsLibLoaded)?{
          6????????????if?(libLoader?==?null)
          7????????????????//?sLocalLibLoader為默認(rèn)的IjkLibLoader
          8????????????????libLoader?=?sLocalLibLoader;
          9????????????libLoader.loadLibrary("ijkffmpeg");
          10????????????libLoader.loadLibrary("ijksdl");
          11????????????libLoader.loadLibrary("ijkplayer");
          12????????????mIsLibLoaded?=?true;
          13????????}
          14????}
          15}
          loadLibrariesOnce 加載相應(yīng)的 so 庫(kù),native_profileBegin 則是 android-ndk-profiler 工具進(jìn)行性能分析的函數(shù),對(duì)應(yīng)的還有native_profileEnd,其定義如下:
          1public?static?native?void?native_profileBegin(String?libName);
          2public?static?native?void?native_profileEnd();
          上述方法分別調(diào)用了函數(shù) monstartupmoncleanup,分別在程序運(yùn)行開(kāi)始和結(jié)束調(diào)用,關(guān)于 android-ndk-profiler 的這里不做過(guò)多介紹。在 IjkPlayer系列之JNI基礎(chǔ)及源碼目錄介紹 這篇文章中介紹了 JNI 的注冊(cè)方式,其中 IjkPlayer 使用的就是其動(dòng)態(tài)注冊(cè)方式,即當(dāng)調(diào)用 System.loadLibrary 加載庫(kù)的時(shí)候會(huì)去查找 JNI_OnLoad 這個(gè)函數(shù),然后在該函數(shù)回調(diào)中進(jìn)行注冊(cè),下面看下 ijkplayer 中的 JNI_OnLoad 實(shí)現(xiàn),如下:
           1JNIEXPORT?jint?JNI_OnLoad(JavaVM?*vm,?void?*reserved)
          2
          {
          3????JNIEnv*?env?=?NULL;
          4????//?保存全局的JavaVM
          5????g_jvm?=?vm;
          6????if?((*vm)->GetEnv(vm,?(void**)?&env,?JNI_VERSION_1_4)?!=?JNI_OK)?{
          7????????return?-1;
          8????}
          9????assert(env?!=?NULL);
          10????//?互斥鎖的初始化
          11????pthread_mutex_init(&g_clazz.mutex,?NULL?);
          12????//?將IjkMediaPlayer轉(zhuǎn)換為一個(gè)全局引用
          13????IJK_FIND_JAVA_CLASS(env,?g_clazz.clazz,?JNI_CLASS_IJKPLAYER);
          14????//?注冊(cè)Native方法與Java方法相對(duì)應(yīng)
          15????(*env)->RegisterNatives(env,?g_clazz.clazz,?g_methods,?NELEM(g_methods)?);
          16????//?初始化:注冊(cè)編解碼器、解復(fù)用器、協(xié)議
          17????ijkmp_global_init();
          18????//?設(shè)置回調(diào),對(duì)應(yīng)Java層的onNativeInvoke回調(diào)函數(shù)
          19????ijkmp_global_set_inject_callback(inject_callback);
          20????//?注冊(cè)av_base64_encode與FFmpegApi_av_base64_encode的對(duì)應(yīng)關(guān)系
          21????FFmpegApi_global_init(env);
          22????return?JNI_VERSION_1_4;
          23}
          其中數(shù)組 g_methods 定義了 Native 函數(shù)與 Java 方法的一一對(duì)應(yīng)關(guān)系,如下:
           1static?JNINativeMethod?g_methods[]?=?{
          2????{
          3????????"_setDataSource",
          4????????"(Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V",
          5????????(void?*)?IjkMediaPlayer_setDataSourceAndHeaders
          6????},
          7????{?"_setDataSourceFd",???????"(I)V",?????(void?*)?IjkMediaPlayer_setDataSourceFd?},
          8????{?"_setDataSource",?????????"(Ltv/danmaku/ijk/media/player/misc/IMediaDataSource;)V",?(void?*)IjkMediaPlayer_setDataSourceCallback?},
          9????{?"_setAndroidIOCallback",??"(Ltv/danmaku/ijk/media/player/misc/IAndroidIO;)V",?(void?*)IjkMediaPlayer_setAndroidIOCallback?},
          10
          11????{?"_setVideoSurface",???????"(Landroid/view/Surface;)V",?(void?*)?IjkMediaPlayer_setVideoSurface?},
          12????{?"_prepareAsync",??????????"()V",??????(void?*)?IjkMediaPlayer_prepareAsync?},
          13????{?"_start",?????????????????"()V",??????(void?*)?IjkMediaPlayer_start?},
          14????{?"_stop",??????????????????"()V",??????(void?*)?IjkMediaPlayer_stop?},
          15????{?"seekTo",?????????????????"(J)V",?????(void?*)?IjkMediaPlayer_seekTo?},
          16????{?"_pause",?????????????????"()V",??????(void?*)?IjkMediaPlayer_pause?},
          17????{?"isPlaying",??????????????"()Z",??????(void?*)?IjkMediaPlayer_isPlaying?},
          18????{?"getCurrentPosition",?????"()J",??????(void?*)?IjkMediaPlayer_getCurrentPosition?},
          19????{?"getDuration",????????????"()J",??????(void?*)?IjkMediaPlayer_getDuration?},
          20????{?"_release",???????????????"()V",??????(void?*)?IjkMediaPlayer_release?},
          21????{?"_reset",?????????????????"()V",??????(void?*)?IjkMediaPlayer_reset?},
          22????{?"setVolume",??????????????"(FF)V",????(void?*)?IjkMediaPlayer_setVolume?},
          23????{?"getAudioSessionId",??????"()I",??????(void?*)?IjkMediaPlayer_getAudioSessionId?},
          24????{?"native_init",????????????"()V",??????(void?*)?IjkMediaPlayer_native_init?},
          25????{?"native_setup",???????????"(Ljava/lang/Object;)V",?(void?*)?IjkMediaPlayer_native_setup?},
          26????{?"native_finalize",????????"()V",??????(void?*)?IjkMediaPlayer_native_finalize?},
          27
          28????{?"_setOption",?????????????"(ILjava/lang/String;Ljava/lang/String;)V",?(void?*)?IjkMediaPlayer_setOption?},
          29????{?"_setOption",?????????????"(ILjava/lang/String;J)V",??????????????????(void?*)?IjkMediaPlayer_setOptionLong?},
          30
          31????{?"_getColorFormatName",????"(I)Ljava/lang/String;",????(void?*)?IjkMediaPlayer_getColorFormatName?},
          32????{?"_getVideoCodecInfo",?????"()Ljava/lang/String;",?????(void?*)?IjkMediaPlayer_getVideoCodecInfo?},
          33????{?"_getAudioCodecInfo",?????"()Ljava/lang/String;",?????(void?*)?IjkMediaPlayer_getAudioCodecInfo?},
          34????{?"_getMediaMeta",??????????"()Landroid/os/Bundle;",????(void?*)?IjkMediaPlayer_getMediaMeta?},
          35????{?"_setLoopCount",??????????"(I)V",?????????????????????(void?*)?IjkMediaPlayer_setLoopCount?},
          36????{?"_getLoopCount",??????????"()I",??????????????????????(void?*)?IjkMediaPlayer_getLoopCount?},
          37????{?"_getPropertyFloat",??????"(IF)F",????????????????????(void?*)?ijkMediaPlayer_getPropertyFloat?},
          38????{?"_setPropertyFloat",??????"(IF)V",????????????????????(void?*)?ijkMediaPlayer_setPropertyFloat?},
          39????{?"_getPropertyLong",???????"(IJ)J",????????????????????(void?*)?ijkMediaPlayer_getPropertyLong?},
          40????{?"_setPropertyLong",???????"(IJ)V",????????????????????(void?*)?ijkMediaPlayer_setPropertyLong?},
          41????{?"_setStreamSelected",?????"(IZ)V",????????????????????(void?*)?ijkMediaPlayer_setStreamSelected?},
          42
          43????{?"native_profileBegin",????"(Ljava/lang/String;)V",????(void?*)?IjkMediaPlayer_native_profileBegin?},
          44????{?"native_profileEnd",??????"()V",??????????????????????(void?*)?IjkMediaPlayer_native_profileEnd?},
          45
          46????{?"native_setLogLevel",?????"(I)V",?????????????????????(void?*)?IjkMediaPlayer_native_setLogLevel?},
          47????{?"_setFrameAtTime",????????"(Ljava/lang/String;JJII)V",?(void?*)?IjkMediaPlayer_setFrameAtTime?},
          48};
          上述代碼主要工作如下:
          • 注冊(cè) Native 方法與 Java 方法之間的對(duì)應(yīng)關(guān)系。

          • 注冊(cè)編解碼器、解復(fù)用器、協(xié)議等。

          • 設(shè)置 onNativeInvoke 回調(diào)供 Native 層調(diào)用,主要關(guān)心其返回值,比如斷網(wǎng)重連等。

          Java層播放器創(chuàng)建

          看下 Java 層 IjkMediaPlayer 的創(chuàng)建
          1IjkMediaPlayer?ijkMediaPlayer?=?new?IjkMediaPlayer();
          查看構(gòu)造方法如下:
           1public?IjkMediaPlayer()?{
          2????//?sLocalLibLoader為默認(rèn)的IjkLibLoader
          3????this(sLocalLibLoader);
          4}
          5
          6public?IjkMediaPlayer(IjkLibLoader?libLoader)?{
          7????initPlayer(libLoader);
          8}
          9
          10private?void?initPlayer(IjkLibLoader?libLoader)?{
          11????//?嘗試加載庫(kù),避免之前從未加載過(guò)so
          12????loadLibrariesOnce(libLoader);
          13????//?對(duì)應(yīng)c層IjkMediaPlayer_native_init方法,暫時(shí)為空實(shí)現(xiàn)
          14????initNativeOnce();
          15
          16????//?用來(lái)處理Iik底層傳遞上來(lái)的消息
          17????Looper?looper;
          18????if?((looper?=?Looper.myLooper())?!=?null)?{
          19????????mEventHandler?=?new?EventHandler(this,?looper);
          20????}?else?if?((looper?=?Looper.getMainLooper())?!=?null)?{
          21????????mEventHandler?=?new?EventHandler(this,?looper);
          22????}?else?{
          23????????mEventHandler?=?null;
          24????}
          25
          26????//?IjkMediaPlayer包裝成弱引用傳遞到native層
          27????native_setup(new?WeakReference(this));
          28}
          可見(jiàn)初始化的時(shí)候加載了 ijkffmpeg、ijksdl、ijkplayer 庫(kù),創(chuàng)建了 mEventHandler 處理 Native 拋上來(lái)的播放事件,比如播放開(kāi)始、播放完成、播放出錯(cuò)等事件,具體由 Native 層調(diào)用 Java 層的函數(shù) postEventFromNative 來(lái)發(fā)送對(duì)應(yīng)的事件,在閱讀 C 層代碼之前,先了解一下 IjkMediaPlayer 結(jié)構(gòu)體。

          IjkMediaPlayer結(jié)構(gòu)體

          IjkPlayer 對(duì)應(yīng) IjkMediaPlayer 結(jié)構(gòu)體,其初始化主要是對(duì)該結(jié)構(gòu)體進(jìn)行初始化,其定義如下:
           1struct?IjkMediaPlayer?{
          2????/*?IjkMediaPlayer創(chuàng)建一次則ref_count計(jì)數(shù)加一次?*/
          3????volatile?int?ref_count;
          4????/*?保護(hù)接口調(diào)用的鎖*/
          5????pthread_mutex_t?mutex;
          6????/* FFPlayer是原ffplayer里的結(jié)構(gòu)體,有被ijk擴(kuò)展?*/
          7????FFPlayer?*ffplayer;
          8????/*?用于ijkPlayer回調(diào)給應(yīng)用層的一個(gè)消息循環(huán)函數(shù)?*/
          9????int?(*msg_loop)(void*);
          10????/*?消息線程?*/
          11????SDL_Thread?*msg_thread;
          12????SDL_Thread?_msg_thread;
          13????/*?播放器狀態(tài)?*/
          14????int?mp_state;
          15????/*?播放地址?*/
          16????char?*data_source;
          17????/*?Java層IjkMediaPlayer對(duì)應(yīng)弱引用對(duì)象?*/
          18????void?*weak_thiz;
          19????/*?是否重新播放?*/
          20????int?restart;
          21????/*?restart是否從頭開(kāi)始?*/
          22????int?restart_from_beginning;
          23????/*?標(biāo)識(shí)用戶是不是seek了進(jìn)度條?*/
          24????int?seek_req;
          25????/*?seek的毫秒值?*/
          26????long?seek_msec;
          27};
          整個(gè)播放流程中涉及到的參數(shù)基本都是 IjkMediaPlayer 結(jié)構(gòu)體中的成員變量,后面 Native 層 IjkPlayer 的創(chuàng)建都是在初始化上述結(jié)構(gòu)體中的成員變量。

          Native層播放器創(chuàng)建

          Native 層播放器的創(chuàng)建主要是結(jié)構(gòu)體 IjkMediaPlayer 的創(chuàng)建及初始化,這里接著上文繼續(xù)查看 native_setup 方法的具體實(shí)現(xiàn)如下:
           1static?void
          2IjkMediaPlayer_native_setup(JNIEnv?*env,?jobject?thiz,?jobject?weak_this)
          3
          {
          4????MPTRACE("%s\n",?__func__);
          5????//?創(chuàng)建C層對(duì)應(yīng)的IjkMediaPlayer
          6????IjkMediaPlayer?*mp?=?ijkmp_android_create(message_loop);
          7????JNI_CHECK_GOTO(mp,?env,?"java/lang/OutOfMemoryError",?"mpjni:?native_setup:?ijkmp_create()?failed",?LABEL_RETURN);
          8????//?Java層mNativeMediaPlayer初始化
          9????jni_set_media_player(env,?thiz,?mp);
          10????//?初始化mp->weak_thiz
          11????ijkmp_set_weak_thiz(mp,?(*env)->NewGlobalRef(env,?weak_this));
          12????//?初始化ffp->inject_opaque等
          13????ijkmp_set_inject_opaque(mp,?ijkmp_get_weak_thiz(mp));
          14????//?初始化ffp->ijkio_inject_opaque等
          15????ijkmp_set_ijkio_inject_opaque(mp,?ijkmp_get_weak_thiz(mp));
          16????//?設(shè)置解碼器選擇回調(diào)
          17????ijkmp_android_set_mediacodec_select_callback(mp,?mediacodec_select_callback,?ijkmp_get_weak_thiz(mp));
          18
          19LABEL_RETURN:
          20????ijkmp_dec_ref_p(&mp);
          21}
          上述代碼主要是開(kāi)始創(chuàng)建 C 層的 IjkMediaPlayer 、其對(duì)應(yīng)結(jié)構(gòu)體部分屬性的初始化及解碼器回調(diào),mediacodec_select_callback 會(huì)通過(guò)調(diào)用 Java 層的函數(shù) onSelectCodec 獲取合適的解碼器信息,可在 IjkMediaCodecInfo 中進(jìn)行解碼器的適配。繼續(xù)查看 ijkmp_android_create 函數(shù)如下:
           1IjkMediaPlayer?*ijkmp_android_create(int(*msg_loop)(void*))
          2
          {
          3????//?填充IjkMediaPlayer結(jié)構(gòu)體
          4????IjkMediaPlayer?*mp?=?ijkmp_create(msg_loop);
          5????if?(!mp)
          6????????goto?fail;
          7????//?初始化SDL_Vout,表示IJK中的顯示上下文
          8????mp->ffplayer->vout?=?SDL_VoutAndroid_CreateForAndroidSurface();
          9????if?(!mp->ffplayer->vout)
          10????????goto?fail;
          11????//?初始化IJKFF_Pipeline,解碼器、音頻輸出
          12????mp->ffplayer->pipeline?=?ffpipeline_create_from_android(mp->ffplayer);
          13????if?(!mp->ffplayer->pipeline)
          14????????goto?fail;
          15????//?綁定SDL_Vout到IJKFF_Pipeline_Opaque
          16????ffpipeline_set_vout(mp->ffplayer->pipeline,?mp->ffplayer->vout);
          17????return?mp;
          18fail:
          19????ijkmp_dec_ref_p(&mp);
          20????return?NULL;
          21}
          其中 ijkmp_create 主要是創(chuàng)建了 FFPlayer,并將 msg_loop 進(jìn)行賦值,msg_loop 事件循環(huán)相關(guān)調(diào)用將在后續(xù)文章中介紹,繼續(xù)看下后面幾個(gè)函數(shù):
          • SDL_VoutAndroid_CreateForAndroidSurface:初始化 IjkPlayer 的 顯示上下文 SDL_Vout。

          • ffpipeline_create_from_android:初始化IJKFF_Pipeline,解碼器、音頻輸出。

          • ffpipeline_set_vout:綁定SDL_VoutIJKFF_Pipeline_Opaque。

          調(diào)用流程圖

          IjkPlayer 創(chuàng)建主要函數(shù)調(diào)用流程如下:daa7722f9982208d0c0028018473173e.webp其他細(xì)節(jié)會(huì)在后續(xù)的文章中介紹,下一篇將介紹 IjkPlayer 中消息循環(huán)機(jī)制。推薦閱讀:?

          ?

          瀏覽 54
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日韩精品免费一区二区三区竹菊 | 欧美日韩性交 | 2014AV天堂网 | 影音先锋成人资源网站 | 99免费视频在线 |