initPlayer初始化过程(一)

目录

简要

流程图

代码分析

 1)so库加载及初始化

 2)创建Looper线程

3)so相关操作setup

 

 

简要

本文主要介绍ijkplayer的初始过程

先看LOG

D/IJKMEDIA: IjkMediaPlayer_native_init
D/IJKMEDIA: IjkMediaPlayer_native_setup
I/IJKMEDIA: av_version_info: ff3.4--ijk0.8.7--20180103--001
D/IJKMEDIA: ffpipeline_create_from_android()
D/IJKMEDIA: ijkmp_set_inject_opaque(0x2736)
D/IJKMEDIA: ijkmp_set_inject_opaque()=void
D/IJKMEDIA: ijkmp_set_ijkio_inject_opaque(0x2736)
D/IJKMEDIA: ijkmp_set_ijkio_inject_opaque()=void
D/IJKMEDIA: ijkmp_android_set_mediacodec_select_callback()
D/IJKMEDIA: IjkMediaPlayer_setVideoSurface
D/IJKMEDIA: ijkmp_set_android_surface(surface=0xbb890bf0)
D/IJKMEDIA: ffpipeline_set_surface()
D/IJKMEDIA: ijkmp_set_android_surface(surface=0xbb890bf0)=void

从Log可以看到,初始化过程主要做了

       So库的初始化

       创建视频解码器

       设置缓冲区队列

       解码器选择回调

       设置Surface

流程图

initPlayer初始化过程(一)_第1张图片

代码分析

下面通过代码进行分析

IjkMediaPlayer.java

声明IjkMediaPlayer对象,会调用initPlayer,

ijkMediaPlayer = new IjkMediaPlayer();
    public IjkMediaPlayer(IjkLibLoader libLoader) {
        initPlayer(libLoader);
    }
其中IjkLibLoader为一个lib库封装的加载接口 
private void initPlayer(IjkLibLoader libLoader) {
        loadLibrariesOnce(libLoader);
        initNativeOnce();

        Looper looper;
        if ((looper = Looper.myLooper()) != null) {
            mEventHandler = new EventHandler(this, looper);
        } else if ((looper = Looper.getMainLooper()) != null) {
            mEventHandler = new EventHandler(this, looper);
        } else {
            mEventHandler = null;
        }

        /*
         * Native setup requires a weak reference to our object. It's easier to
         * create it here than in C++.
         */
        native_setup(new WeakReference(this));
    }
initPlayer主要分三大部分:so库加载及初始化,创建Looper线程,so库setup,下面分步介绍

 1)so库加载及初始化

loadLibrariesOnce会加载播放器所有需要的so库
    public static void loadLibrariesOnce(IjkLibLoader libLoader) {
        synchronized (IjkMediaPlayer.class) {
            if (!mIsLibLoaded) {
                if (libLoader == null)
                    libLoader = sLocalLibLoader;

                libLoader.loadLibrary("ijkffmpeg");
                libLoader.loadLibrary("ijkplayer");
                mIsLibLoaded = true;
            }
        }
    }

 initNativeOnce初始化so相关,实则啥也没干

    private static void initNativeOnce() {
        synchronized (IjkMediaPlayer.class) {
            if (!mIsNativeInitialized) {
                native_init();
                mIsNativeInitialized = true;
            }
        }
    }

通过Jni调用ijkplayer_jni.c

{ "native_init",           "(Ljava/lang/Object;)V", (void *) IjkMediaPlayer_native_init},

 IjkMediaPlayer_native_init其实啥也没干,就打印了Log

IjkMediaPlayer_native_init(JNIEnv *env)
{
    MPTRACE("%s\n", __func__);
}

 回来,看看JNI_OnLoad都干了什么:

initPlayer初始化过程(一)_第2张图片

这些都是给java提供相关的操作接口,都是在这里定义

JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved)
{
    JNIEnv* env = NULL;

    g_jvm = vm;
    if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) {
        return -1;
    }
    assert(env != NULL);

    pthread_mutex_init(&g_clazz.mutex, NULL );

    // FindClass returns LocalReference
    IJK_FIND_JAVA_CLASS(env, g_clazz.clazz, JNI_CLASS_IJKPLAYER);
    (*env)->RegisterNatives(env, g_clazz.clazz, g_methods, NELEM(g_methods) );

    ijkmp_global_init();
    ijkmp_global_set_inject_callback(inject_callback);

    FFmpegApi_global_init(env);

    SDL_JNI_OnLoad(vm,reserved);

    return JNI_VERSION_1_4;
}
JNI_OnLoad主要做了FFMepg的相关初始化ijkmp_global_init,API初始化FFmpegApi_global_init,及android系统SDL显示相关的初始化SDL_JNI_OnLoad
void ffp_global_init()
{
    if (g_ffmpeg_global_inited)
        return;

    ALOGD("ijkmediaplayer version : %s", ijkmp_version());
    /* register all codecs, demux and protocols */
    avcodec_register_all();
#if CONFIG_AVDEVICE
    avdevice_register_all();
#endif
#if CONFIG_AVFILTER
    avfilter_register_all();
#endif
    av_register_all();

    ijkav_register_all();

    avformat_network_init();

    av_lockmgr_register(lockmgr);
    av_log_set_callback(ffp_log_callback_brief);

    av_init_packet(&flush_pkt);
    flush_pkt.data = (uint8_t *)&flush_pkt;

    g_ffmpeg_global_inited = true;
}

 2)创建Looper线程

        if ((looper = Looper.myLooper()) != null) {
            mEventHandler = new EventHandler(this, looper);
        } else if ((looper = Looper.getMainLooper()) != null) {
            mEventHandler = new EventHandler(this, looper);
        } else {
            mEventHandler = null;
        }

创建Looper线程,这部分不做太多解释 

3)so相关操作setup

native_setup(new WeakReference(this));
new WeakReference(this) 弱引用变量this传入的上下文

通过Jni调用ijkplayer_jni.c

{ "native_setup",           "(Ljava/lang/Object;)V", (void *) IjkMediaPlayer_native_setup },

进入IjkMediaPlayer_native_setup,主要实现了android的surface和解码器的创建,及设置播放器相关上下文和解码器选择回调

IjkMediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
{
    MPTRACE("%s\n", __func__);
    IjkMediaPlayer *mp = ijkmp_android_create(message_loop);
    JNI_CHECK_GOTO(mp, env, "java/lang/OutOfMemoryError", "mpjni: native_setup: ijkmp_create() failed", LABEL_RETURN);

    jni_set_media_player(env, thiz, mp);
    ijkmp_set_weak_thiz(mp, (*env)->NewGlobalRef(env, weak_this));
    ijkmp_set_inject_opaque(mp, ijkmp_get_weak_thiz(mp));
    ijkmp_set_ijkio_inject_opaque(mp, ijkmp_get_weak_thiz(mp));
    ijkmp_android_set_mediacodec_select_callback(mp, mediacodec_select_callback, ijkmp_get_weak_thiz(mp));

LABEL_RETURN:
    ijkmp_dec_ref_p(&mp);
}

 其中ijkmp_android_create是ijkplayer_android.c在文件里,是初始化部分的核心,主要工作创建Surface和解码器

IjkMediaPlayer *ijkmp_android_create(int(*msg_loop)(void*))
{
    IjkMediaPlayer *mp = ijkmp_create(msg_loop);
    if (!mp)
        goto fail;
    mp->ffplayer->vout = SDL_VoutAndroid_CreateForAndroidSurface();
    if (!mp->ffplayer->vout)
        goto fail;
    mp->ffplayer->pipeline = ffpipeline_create_from_android(mp->ffplayer);
    if (!mp->ffplayer->pipeline)
        goto fail;

    ffpipeline_set_vout(mp->ffplayer->pipeline, mp->ffplayer->vout);

    return mp;

fail:
    ijkmp_dec_ref_p(&mp);
    return NULL;
}

SDL_VoutAndroid_CreateForAndroidSurface()创建Surface,作为视频输出,播放器显示就是通过Surface来显示的

SDL_Vout *SDL_VoutAndroid_CreateForANativeWindow()
{
    SDL_Vout *vout = SDL_Vout_CreateInternal(sizeof(SDL_Vout_Opaque));
    if (!vout)
        return NULL;

    SDL_Vout_Opaque *opaque = vout->opaque;
    opaque->native_window = NULL;
    if (ISDL_Array__init(&opaque->overlay_manager, 32))
        goto fail;
    if (ISDL_Array__init(&opaque->overlay_pool, 32))
        goto fail;

    opaque->egl = IJK_EGL_create();
    if (!opaque->egl)
        goto fail;

    vout->opaque_class    = &g_nativewindow_class;
    vout->create_overlay  = func_create_overlay;
    vout->free_l          = func_free_l;
    vout->display_overlay = func_display_overlay;

    return vout;
fail:
    func_free_l(vout);
    return NULL;
}

声明了显示相关的接口

而ffpipeline_create_from_android作用是创建视频解码器的相关操作接口

IJKFF_Pipeline *ffpipeline_create_from_android(FFPlayer *ffp)
{
    ALOGD("ffpipeline_create_from_android()\n");
    IJKFF_Pipeline *pipeline = ffpipeline_alloc(&g_pipeline_class, sizeof(IJKFF_Pipeline_Opaque));
    if (!pipeline)
        return pipeline;

    IJKFF_Pipeline_Opaque *opaque = pipeline->opaque;
    opaque->ffp                   = ffp;
    opaque->surface_mutex         = SDL_CreateMutex();
    opaque->left_volume           = 1.0f;
    opaque->right_volume          = 1.0f;
    if (!opaque->surface_mutex) {
        ALOGE("ffpipeline-android:create SDL_CreateMutex failed\n");
        goto fail;
    }

    pipeline->func_destroy              = func_destroy;
    pipeline->func_open_video_decoder   = func_open_video_decoder;
    pipeline->func_open_audio_output    = func_open_audio_output;
    pipeline->func_init_video_decoder   = func_init_video_decoder;
    pipeline->func_config_video_decoder = func_config_video_decoder;

    return pipeline;
fail:
    ffpipeline_free_p(&pipeline);
    return NULL;
}

func_destroy回收,这个不做太多解释

func_open_video_decoder主要职责是打开视频解码器

func_open_audio_output打开音频输出

func_init_video_decoder打开视频解码器

func_config_video_decoder配置视频解码器

这几个接口,后面再进行详细解释

 

你可能感兴趣的:(流媒体,android,c++,ijkplayer)