ijkplayer 源码分析(1):初始化流程

article/2025/8/24 14:22:45

一、ijkplayer 初始化流程

在这里插入图片描述

本文是基于 A4ijkplayer 项目进行 ijkplayer 源码分析,该项目是将 ijkplayer 改成基于 CMake 编译,可导入 Android Studio 编译运行,方便代码查找、函数跳转、单步调试、调用栈跟踪等。

初始化完成的主要工作是创建播放器对象:IjkMediaPlayer 。的其提供了两种形式的构造函数,区别在于是否传参 IjkLibLoader。默认不传,即使用默认的 System.loadLibrary(libName),两种构造函数最终都是调用 initPlayer() 函数初始化播放器。该函数内做了四件事:

  • 加载 native 动态库:loadLibrariesOnce()
    加载动态库,动态注册 JNI 函数,以及其他一些初始化操作
  • 初始化 native 资源:initNativeOnce()
    ijkplayer 源码中在该方法中并没有做什么操作
  • 创建事件处理的 EventHandler
    创建 java 层的 handler ,用于接收和处理 native 层回调上来的消息事件
  • 设置 native 资源:native_setup()
    创建 native IjkMediaPlayer 实例,创建消息队列,指定 msg_loop,创建视频渲染对象 SDL_Vout,创建平台相关的 IJKFF_Pipeline(包含视频解码和音频输出)等
public IjkMediaPlayer() {this(sLocalLibLoader);
}public IjkMediaPlayer(IjkLibLoader libLoader) {initPlayer(libLoader);
}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(new WeakReference<IjkMediaPlayer>(this));
}

1、loadLibrariesOnce()

该函数是静态方法,整个进程的生命周期内只调用一次,用于加载所需要依赖的 natvie 动态库。ijkplayer 源码是加载 ijkffmpeg、ijksdl、ijkplayer 这个三个动态库,我为了方便调试和跟进 ijkplayer 源码,将其改成 CMake 方式编译,在 CMakeList 中将 ijksdl 和 ijkplayer 的源码编译到了同一个动态库 a4ijkplayer 中,所以调用如下:

    private static volatile boolean mIsLibLoaded = false;public static void loadLibrariesOnce(IjkLibLoader libLoader) {synchronized (IjkMediaPlayer.class) {if (!mIsLibLoaded) {if (libLoader == null)libLoader = sLocalLibLoader;libLoader.loadLibrary("ijkffmpeg");libLoader.loadLibrary("a4ijkplayer");
//                libLoader.loadLibrary("ijksdl");
//                libLoader.loadLibrary("ijkplayer");mIsLibLoaded = true;}}}

loadLibrary 加载动态库时,会调用每个库 JNI 的 JNI_OnLoad() 方法,卸载时会调用 JNI_UnLoad()。

1.1 调用 libLoader.loadLibrary(“ijksdl”)

在加载 libijksdl.so 动态库时,会调用 ijkmedia/ijksdl/android/ijksdl_android_jni.c 文件中 JNI_OnLoad() 方法。
注:我在 A4ijkplayer项目中将 ijksdl 和 ijkplayer 的源码编译到了同一个动态库 a4ijkplayer 中,不会调用 libLoader.loadLibrary(“ijksdl”) 因而不会调用 ijksdl_android_jni.c 中的 JNI_OnLoad() 方法。为解决该问题,将其改名为 SDL_JNI_OnLoad(),然后在 ijkplayer_jni.c 文件的 JNI_OnLoad() 方法调用改名后的 SDL_JNI_OnLoad() 从而保证 SDL 库的原有 JNI_OnLoad() 中的相关方法能被调用到,相关修改见:这个提交

JNIEXPORT jint JNICALL SDL_JNI_OnLoad(JavaVM *vm, void *reserved)
{int retval;JNIEnv* env = NULL;g_jvm = vm;if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) {return -1;}retval = J4A_LoadAll__catchAll(env);JNI_CHECK_RET(retval == 0, env, NULL, NULL, -1);return JNI_VERSION_1_4;
}

1.2 调用 libLoader.loadLibrary(“a4ijkplayer”)

Ijkplayer 原本代码时调用 libLoader.loadLibrary(“ijkplayer”) , A4ijkplayer 项目中是加载合二为一的 liba4ijkplayer.so ,接着会调用 ijkmedia/ijkplayer/android/ijkplayer_jni.c 文件中 JNI_OnLoad() 方法,如下:

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);// 因为把 sdl 和 ijkplayer 和成一个 so 了,不会调用 sdl 原本的 JNI_OnLoad,所以需在这里主动调用jint result = SDL_JNI_OnLoad(vm, reserved);if (result < 0) {return result;}pthread_mutex_init(&g_clazz.mutex, NULL );// FindClass returns LocalReferenceIJK_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);return JNI_VERSION_1_4;
}

这里主要是动态注册 JNI 函数,映射关联 Java 和 jni 相关函数(RegisterNatives),以及其他一些初始化操作。

static JNINativeMethod g_methods[] = {// ...{ "_prepareAsync",          "()V",      (void *) IjkMediaPlayer_prepareAsync },{ "_start",                 "()V",      (void *) IjkMediaPlayer_start },// ...{ "native_init",            "()V",      (void *) IjkMediaPlayer_native_init },{ "native_setup",           "(Ljava/lang/Object;)V", (void *) IjkMediaPlayer_native_setup },{ "native_finalize",        "()V",      (void *) IjkMediaPlayer_native_finalize },// ...
};

2、initNativeOnce()

该方法也是静态方法,调用 native_init() 方法。

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

最终调用到底层 ijkmedia/ijkplayer/android/ijkplayer_jni.c 文件中的 IjkMediaPlayer_native_init() 方法。
ijkplayer 源码中在该方法中并没有做什么操作,如果需要修改源码,需要做一下全局初始化,可以放在该方法中执行。

// static JNINativeMethod g_methods[] = {...} 数组中
{ "native_init",            "()V",      (void *) IjkMediaPlayer_native_init },
static void
IjkMediaPlayer_native_init(JNIEnv *env)
{MPTRACE("%s\n", __func__);
}

3、创建 EventHandler

创建 java 层的 handler ,用于接收 native 层回调上来的消息,如:资源已准备好、播放完成、seek 完成、错误回调等。其消息处理默认是在 IjkMediaPlayer 构造函数的调用线程,如果没获取到当前线程的 looper,则消息处理在主线程。

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;
}

底层在通知事件时,会回调到 java 层的 postEventFromNative() 函数,然后通过 EventHandler 发送消息到处理线程,避免阻塞底层执行。如下(IjkMediaPlayer.java 中):

@CalledByNative
private static void postEventFromNative(Object weakThiz, int what,int arg1, int arg2, Object obj) {// ...if (mp.mEventHandler != null) {Message m = mp.mEventHandler.obtainMessage(what, arg1, arg2, obj);mp.mEventHandler.sendMessage(m);}
}

然后在 EventHandler 的 handleMessage() 中处理事件,如下:


private static class EventHandler extends Handler {// ...@Overridepublic void handleMessage(Message msg) {// ...switch (msg.what) {case MEDIA_PREPARED:player.notifyOnPrepared();return;case MEDIA_PLAYBACK_COMPLETE:player.stayAwake(false);player.notifyOnCompletion();return;// ...}
}

再根据业务层设置的监听器,回调出去,如下:(AbstractMediaPlayer.java 中)

protected final void notifyOnPrepared() {if (mOnPreparedListener != null)mOnPreparedListener.onPrepared(this);
}protected final void notifyOnCompletion() {if (mOnCompletionListener != null)mOnCompletionListener.onCompletion(this);
}

4、native_setup()

最终调用到底层 ijkmedia/ijkplayer/android/ijkplayer_jni.c 文件中的 IjkMediaPlayer_native_setup() 方法。

// static JNINativeMethod g_methods[] = {...} 数组中
{ "native_setup",           "(Ljava/lang/Object;)V", (void *) IjkMediaPlayer_native_setup },
static void
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);
}

4.1 ijkmp_android_create()

可以通过我的 A4ijkplayer 项目在 Android Studio 中跳转查看,该方法在 ijkmedia/ijkplayer/android/ijkplayer_android.c 文件中。

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;
}

如上,ijkmp_android_create() 一共做了四件事:

  • ijkmp_create() :创建 IjkMediaPlayer 结构体实例
  • SDL_VoutAndroid_CreateForAndroidSurface():创建视频图像渲染对象 SDL_Vout
  • ffpipeline_create_from_android():创建平台相关的 IJKFF_Pipeline,包含视频解码和音频输出
  • ffpipeline_set_vout():将管道和视频输出关联

4.1.1 ijkmp_create()

该函数创建一个 native 层的 IjkMediaPlayer 结构体实例,其结构定义在: ijkmedia/ijkplayer/ijkplayer_internal.h 中。

IjkMediaPlayer *ijkmp_create(int (*msg_loop)(void*))
{IjkMediaPlayer *mp = (IjkMediaPlayer *) mallocz(sizeof(IjkMediaPlayer));// .....mp->ffplayer = ffp_create();// .....mp->msg_loop = msg_loop;// .....return mp;
}

并通过 ffp_create() 创建 FFplayer 并指定消息事件处理函数 msg_loop。如下: message_loop() 将 native 线程绑定到 Java 线程(SDL_JNI_SetupThreadEnv 中),用于获取 JNIEnv 对象,以便可以从底层调用 Java 层方法。

其内部调用了message_loop_n() 方法,而 message_loop_n() 则是循环调用 ijkmp_get_msg() 来获取当前的事件,并通过 post_event() 方法将事件传递到 Java 层。

ijkmp_get_msg() 从消息队列中获取消息事件,队列为空没有事件时会阻塞,返回 -1 表示队列已退出。
post_event() 会通过 JNI 反向调用到 Java 层 IjkMediaPlayer 对象的 postEventFromNative() 方法,最终调用到 EventHandler 的handleMessage() 方法。

static int message_loop(void *arg)
{// ...JNIEnv *env = NULL;if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {return -1;}IjkMediaPlayer *mp = (IjkMediaPlayer*) arg;message_loop_n(env, mp);// ...return 0;
}
static void message_loop_n(JNIEnv *env, IjkMediaPlayer *mp)
{jobject weak_thiz = (jobject) ijkmp_get_weak_thiz(mp);while (1) {AVMessage msg;int retval = ijkmp_get_msg(mp, &msg, 1);if (retval < 0)break;switch (msg.what) {// ...case FFP_MSG_ERROR:post_event(env, weak_thiz, MEDIA_ERROR, MEDIA_ERROR_IJK_PLAYER, msg.arg1);break;case FFP_MSG_PREPARED:post_event(env, weak_thiz, MEDIA_PREPARED, 0, 0);break;// ...}}
}
inline static void post_event(JNIEnv *env, jobject weak_this, int what, int arg1, int arg2)
{J4AC_IjkMediaPlayer__postEventFromNative(env, weak_this, what, arg1, arg2, NULL);
}

4.1.2 SDL_VoutAndroid_CreateForAndroidSurface()

该函数用于创建 Android 平台视频图像渲染对象 SDL_Vout,如下:

SDL_Vout *SDL_VoutAndroid_CreateForAndroidSurface()
{return SDL_VoutAndroid_CreateForANativeWindow();
}
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;
}

这里只是创建 SDL_Vout 结构体,及相关的内存和函数指针,GL 和 Surface 相关的操作在后续流程调用这里赋值的函数指针或赋值这里 SDL_Vout 的成员变量。如上面函数将 opaque->native_window 置空,native_window 真正赋值是在Java 层调用 setSurface 设置要显示的窗口时最后调用到 SDL_VoutAndroid_SetNativeWindow_l() 将上层的 Surface 和 opaque->native_window 关联。

func_create_overlay() 函数如下,这里只是将该函数指针赋值给 vout->create_overlay,真正调用是在渲染的时候调。在 ff_ffplay.c 中通过 SDL_Vout_CreateOverlay() 函数调用 vout->create_overlay 从而调到 func_create_overlay() 函数。

static SDL_VoutOverlay *func_create_overlay(int width, int height, int frame_format, SDL_Vout *vout)
{SDL_LockMutex(vout->mutex);SDL_VoutOverlay *overlay = func_create_overlay_l(width, height, frame_format, vout);SDL_UnlockMutex(vout->mutex);return overlay;
}
static SDL_VoutOverlay *func_create_overlay_l(int width, int height, int frame_format, SDL_Vout *vout)
{switch (frame_format) {case IJK_AV_PIX_FMT__ANDROID_MEDIACODEC:// 硬解码return SDL_VoutAMediaCodec_CreateOverlay(width, height, vout);default:// 软解码return SDL_VoutFFmpeg_CreateOverlay(width, height, frame_format, vout);}
}

func_display_overlay() 函数如下,这里只是将该函数指针赋值给 vout->display_overlay,真正调用是在 ff_ffplay.c
video_image_display2() 通过 SDL_VoutDisplayYUVOverlay() 函数调用 vout->display_overlay 从而调到 func_display_overlay() 函数。

4.1.3 ffpipeline_create_from_android()

该函数用于创建平台相关的 IJKFF_Pipeline,包含视频解码和音频输出,这里只是给 pipeline 设置函数指针,如下:

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_open_video_decoder :用于创建视频解码器的函数,在后续流程调用该函数,根据参数创建硬解码还是软解码。 无论硬解码还是软解码返回的都是 IJKFF_Pipenode,说其是解码器的抽象。

static IJKFF_Pipenode *func_open_video_decoder(IJKFF_Pipeline *pipeline, FFPlayer *ffp)
{IJKFF_Pipeline_Opaque *opaque = pipeline->opaque;IJKFF_Pipenode        *node = NULL;if (ffp->mediacodec_all_videos || ffp->mediacodec_avc || ffp->mediacodec_hevc || ffp->mediacodec_mpeg2)// 视频硬解码node = ffpipenode_create_video_decoder_from_android_mediacodec(ffp, pipeline, opaque->weak_vout);if (!node) {// 视频软解码node = ffpipenode_create_video_decoder_from_ffplay(ffp);}return node;
}

真正调用初始化视频解码器是在 prepareAsync() 阶段,在开启视频解码线程之前,如下:

static int stream_component_open(FFPlayer *ffp, int stream_index)
{//...case AVMEDIA_TYPE_VIDEO:// 初始化视频解码器decoder_init(&is->viddec, avctx, &is->videoq, is->continue_read_thread);ffp->node_vdec = ffpipeline_open_video_decoder(ffp->pipeline, ffp);// 开始视频解码线程if ((ret = decoder_start(&is->viddec, video_thread, ffp, "ff_video_dec")) < 0)goto out;//...
}
IJKFF_Pipenode* ffpipeline_open_video_decoder(IJKFF_Pipeline *pipeline, FFPlayer *ffp)
{return pipeline->func_open_video_decoder(pipeline, ffp);
}

func_open_audio_output :用于创建音频输出的函数,在后续流程调用该函数,根据参数创建 AudioTrack 或者 OpenSL 用来播放音频。

static SDL_Aout *func_open_audio_output(IJKFF_Pipeline *pipeline, FFPlayer *ffp)
{SDL_Aout *aout = NULL;if (ffp->opensles) {// 创建 OpenSLESaout = SDL_AoutAndroid_CreateForOpenSLES();} else {// 创建 AudioTrackaout = SDL_AoutAndroid_CreateForAudioTrack();}if (aout)SDL_AoutSetStereoVolume(aout, pipeline->opaque->left_volume, pipeline->opaque->right_volume);return aout;
}

func_init_video_decoder :用于初始化视频解码器的函数,只有硬解码才有效。

static IJKFF_Pipenode *func_init_video_decoder(IJKFF_Pipeline *pipeline, FFPlayer *ffp)
{IJKFF_Pipeline_Opaque *opaque = pipeline->opaque;IJKFF_Pipenode        *node = NULL;if (ffp->mediacodec_all_videos || ffp->mediacodec_avc || ffp->mediacodec_hevc || ffp->mediacodec_mpeg2)node = ffpipenode_init_decoder_from_android_mediacodec(ffp, pipeline, opaque->weak_vout);return node;
}

func_config_video_decoder :用于创建配置视频解码器的函数,只有硬解码才有效。

static int func_config_video_decoder(IJKFF_Pipeline *pipeline, FFPlayer *ffp)
{IJKFF_Pipeline_Opaque *opaque = pipeline->opaque;int                       ret = NULL;if (ffp->node_vdec) {ret = ffpipenode_config_from_android_mediacodec(ffp, pipeline, opaque->weak_vout, ffp->node_vdec);}return ret;
}

4.1.4 ffpipeline_set_vout()

该函数用于将管道和视频输出关联,如下:

void ffpipeline_set_vout(IJKFF_Pipeline* pipeline, SDL_Vout *vout)
{if (!check_ffpipeline(pipeline, __func__))return;IJKFF_Pipeline_Opaque *opaque = pipeline->opaque;opaque->weak_vout = vout;
}

4.2 jni_set_media_player()

将 native 层的 IjkMediaPlayer 对象保存到 Java 层,即将 native 层的 IjkMediaPlayer 指针保存到 Java 层 IjkMediaPlayer 的 mNativeMediaPlayer 变量。

static IjkMediaPlayer *jni_set_media_player(JNIEnv* env, jobject thiz, IjkMediaPlayer *mp)
{// ...IjkMediaPlayer *old = (IjkMediaPlayer*) (intptr_t) J4AC_IjkMediaPlayer__mNativeMediaPlayer__get__catchAll(env, thiz);if (mp) {ijkmp_inc_ref(mp);}J4AC_IjkMediaPlayer__mNativeMediaPlayer__set__catchAll(env, thiz, (intptr_t) mp);// ...return old;
}
public final class IjkMediaPlayer extends AbstractMediaPlayer {@AccessedByNativeprivate long mNativeMediaPlayer;
}

4.3 ijkmp_set_weak_thiz()

将 Java 层 IjkMediaPlayer 对象的弱引用保存到 native 层 IjkMediaPlayer 中(mp->weak_thiz),如下:

void *ijkmp_set_weak_thiz(IjkMediaPlayer *mp, void *weak_thiz)
{void *prev_weak_thiz = mp->weak_thiz;mp->weak_thiz = weak_thiz;return prev_weak_thiz;
}
private void initPlayer(IjkLibLoader libLoader) {// ...native_setup(new WeakReference<IjkMediaPlayer>(this));
}

4.4 ijkmp_set_inject_opaque()

void *ijkmp_set_inject_opaque(IjkMediaPlayer *mp, void *opaque)
{void *prev_weak_thiz = ffp_set_inject_opaque(mp->ffplayer, opaque);return prev_weak_thiz;
}
void *ffp_set_inject_opaque(FFPlayer *ffp, void *opaque)
{if (!ffp)return NULL;void *prev_weak_thiz = ffp->inject_opaque;ffp->inject_opaque = opaque;av_application_closep(&ffp->app_ctx);av_application_open(&ffp->app_ctx, ffp);ffp_set_option_int(ffp, FFP_OPT_CATEGORY_FORMAT, "ijkapplication", (int64_t)(intptr_t)ffp->app_ctx);ffp->app_ctx->func_on_app_event = app_func_event;return prev_weak_thiz;
}

4.5 ijkmp_set_ijkio_inject_opaque()

创建 io manager,用于管理 io 相关的操作和事件,比如缓存大小等。

void *ijkmp_set_ijkio_inject_opaque(IjkMediaPlayer *mp, void *opaque)
{void *prev_weak_thiz = ffp_set_ijkio_inject_opaque(mp->ffplayer, opaque);return prev_weak_thiz;
}
void *ffp_set_ijkio_inject_opaque(FFPlayer *ffp, void *opaque)
{if (!ffp)return NULL;void *prev_weak_thiz = ffp->ijkio_inject_opaque;ffp->ijkio_inject_opaque = opaque;ijkio_manager_destroyp(&ffp->ijkio_manager_ctx);ijkio_manager_create(&ffp->ijkio_manager_ctx, ffp);ijkio_manager_set_callback(ffp->ijkio_manager_ctx, ijkio_app_func_event);ffp_set_option_int(ffp, FFP_OPT_CATEGORY_FORMAT, "ijkiomanager", (int64_t)(intptr_t)ffp->ijkio_manager_ctx);return prev_weak_thiz;
}

4.6 ijkmp_android_set_mediacodec_select_callback()

设置选择硬解码时触发的回调。

void ijkmp_android_set_mediacodec_select_callback(IjkMediaPlayer *mp, bool (*callback)(void *opaque, ijkmp_mediacodecinfo_context *mcc), void *opaque)
{if (mp && mp->ffplayer && mp->ffplayer->pipeline) {ffpipeline_set_mediacodec_select_callback(mp->ffplayer->pipeline, callback, opaque);}// ...
}
void ffpipeline_set_mediacodec_select_callback(IJKFF_Pipeline* pipeline, bool (*callback)(void *opaque, ijkmp_mediacodecinfo_context *mcc), void *opaque)
{// ...pipeline->opaque->mediacodec_select_callback        = callback;pipeline->opaque->mediacodec_select_callback_opaque = opaque;
}

Github : A4ijkplayer

参考链接:
https://www.jianshu.com/p/daf0a61cc1e0
https://anacz.blog.csdn.net/article/details/98893919


http://chatgpt.dhexx.cn/article/Aac3Z01Z.shtml

相关文章

ijkplayer框架深入剖析

随着互联网技术的飞速发展&#xff0c;移动端播放视频的需求如日中天&#xff0c;由此也催生了一批开源/闭源的播放器&#xff0c;但是无论这个播放器功能是否强大、兼容性是否优秀&#xff0c;它的基本模块通常都是由以下部分组成&#xff1a;事务处理、数据的接收和解复用、音…

android编译ijkplayer,android studio 3.0 集成ijkplayer

一、ijkplayer编译过程略&#xff0c;有兴趣的朋友可以再研究&#xff0c;以下以编译好的版本讲解。 将ijkplayer相关的so及aar文件复制到app下的libs目录&#xff0c;为支持多版本的手机使用&#xff0c;将所有的so文件都复制过去。 文件下载地址&#xff1a;https://download…

开源播放器ijkplayer的使用

编译 快速入门&#xff1a; ijkplayer是Bilibili发布的轻量级 Android/iOS 开源视频播放器。核心代码主要是用C写的&#xff0c;主要由ffmpeg(解码)openssl(https)播放器相关组成。编译可裁剪&#xff0c;支持直播、点播(在线播放)、硬件加速解码、弹幕等&#xff0c;完整版支…

ijkplayer笔记

一、初始化 - (id)initWithContentURLString:(NSString *)aUrlStringwithOptions:(IJKFFOptions *)options {if (aUrlString nil)return nil;self [super init];if (self) {ijkmp_global_init();ijkmp_global_set_inject_callback(ijkff_inject_callback);[IJKFFMoviePlayer…

Ijkplayer编译

记录一下编译ijkplayer过程 一、环境 1.1、VMware ubuntu 1.2、安装git、vim sudo apt install git sudo apt install vim二、配置编译环境 2.1、配置AndroidSDK环境 2.1.1、下载AndroidSDK wget http://dl.google.com/android/android-sdk_r24.2-linux.tgz国内下载地址…

ijkplayer播放器剖析(一)让ijkplayer播起来

一、引言&#xff1a; ijkplayer是一款对FFmpeg封装非常好的第三方开源播放器&#xff0c;遗憾的是&#xff0c;ijkplayer2.0似乎不开源&#xff0c;并且1.0版本更新也基本停止了&#xff0c;很多公司都会采用ijkplayer作为其播放应用的内核&#xff0c;这款集合软硬件编解码功…

13_android编译ijkplayer

13_android编译ijkplayer 一.编译环境 macOS Big Sur 11.4NDK r10eHomeBrewgit 二.编译前准备 配置ANDROID_SDK和ANDROID_NDK环境变量 安装git&#xff0c;make&#xff0c; yasm brew install git brew install make brew install yasm三.使用git获取ijkplayer最新源码 g…

ijkplayer项目

ijkplayer项目 环境配置 NDK全称&#xff1a;Native Development Kit。 1、NDK是一系列工具的集合。NDK提供了一系列的工具&#xff0c;帮助开发者快速开发C&#xff08;或C&#xff09;的动态库&#xff0c;并能自动将so和java应用一起打包成apk。这些工具对开发者的帮助是巨…

ijkplayer android 内存,IjkPlayer

ijkplayer是b站开源的超级好用的视频播放器&#xff0c;小编这里为大家送上。相信大家都早有耳闻。ijkplayer Android和ios都可用&#xff0c;还支持多种视频的硬解码。人生苦短&#xff0c;不如快点试一试。需要的朋友快来西西下载吧&#xff01; 应用简介 ijkplayer是Bilibil…

android集成 ijkplayer Ijkplayer集成使用方案 + demo

首先想使用ijkplayer的话&#xff0c;肯定得先编译啦&#xff0c;但是我之前已经编译好了&#xff0c;时间是2018年3月份左右&#xff0c;版本也是当时最新的0.8.8&#xff0c;所以大可放心使用 其实拉到项目中还是很简单的。也就是把要适配的.so库拉到项目中&#xff0c;再把需…

ijkplayer 源码分析(上)

本文基于0.8.8版本的 ijkplayer &#xff0c;对其源码进行剖析&#xff0c;涉及到不同平台下的封装接口或处理方式时&#xff0c;均以 Android 为例。 ijkplayer 是一款比较出众的开源 Android/IOS 跨平台播放器&#xff0c;基于 ffplay&#xff0c;API 易于集成&#xff0c;可…

ijkplayer播放器剖析(五)视频同步与渲染机制分析

ijkplayer播放器剖析系列文章&#xff1a; kplayer播放器剖析&#xff08;一&#xff09;从应用层分析至Jni层的流程分析 ijkplayer播放器剖析&#xff08;二&#xff09;消息机制分析 ijkplayer播放器剖析&#xff08;三&#xff09;音频解码与音频输出机制分析 ijkplay…

ijkplayer播放器详解使用教程

1.认识ijkplayer 最近公司准备开发一款视频播放及直播的应用&#xff0c;找了许多开源的框架&#xff0c;大部分都是基于ffmpeg开发的。最开始准备用Vitamio框架开发的&#xff0c;相关的文章也比较丰富&#xff0c;结果对于非个人移动应用均需购买Vitamio使用授权。不过B站开…

ijkplayer播放器架构从原型到升级

ijkplayer是一款跨平台的播放器&#xff0c;支持Android与iOS端&#xff0c;核心部分基于ffmpeg&#xff0c;支持Android的mediacodec硬解与iOS的videotoolbox硬解&#xff0c;视频图像采用OpenGL进行渲染。许多主流播放器都使用ijkplayer作为播放方案。接下来我们从核心播放流…

游戏手柄改typec接口

前言 几年前买的杂牌游戏手柄坏了好久&#xff0c;连接十分不稳定&#xff0c;稍微动一下线就会断连&#xff0c;我推断是线的质量不好&#xff0c;理论上将把线换掉应该就好了。一不做二不休&#xff0c;我想直接改成typec接口&#xff0c;手柄与数据线分离&#xff0c;这样就…

nl80211_iftype接口类型详解

NL80211_IFTYPE_UNSPECIFIED 上层协议未指定硬件接口类型&#xff0c;由驱动指定 NL80211_IFTYPE_ADHOC independent BSS member&#xff0c;各个无线主机之间对等交换数据 NL80211_IFTYPE_STATION managed BSS member NL80211_IFTYPE_AP 接入点&#xff0c;通常一端通过有…

android接口和type c对比,USB Type-C究竟比3.5mm音频接口好在哪里?

随着苹果宣布将在iPhone7/7 Plus上取消传统的3.5mm音频接口,不少动作快的手机厂商已经即使跟进了,目前乐视所有新机和摩托罗拉Moto Z均使用USB Type-C接口代替3.5mm音频接口,这样做究竟有什么好处呢? 基础知识 首先我们需要知道,3.5mm接口所传输的是立体声模拟音频,这也就…

TYPE-C接口的定义诠释以及功能参数挖掘

现在的安卓手机大多都采用了Type-C接口&#xff0c;如华为、荣耀、小米、三星、魅族等。对于这个接口&#xff0c;大家不再陌生&#xff0c;但大多数人对它的认识还停留在 “支持正反插”、“用来充电” 的基础层面。今天就来深入挖掘一下TYPE-C发展七年至今&#xff0c;为何能…

Type-C接口原理图,附引脚说明

维基链接&#xff1a;https://zh.wikipedia.org/wiki/USB_Type-C 针名描述针名描述A1GND接地B12GND接地A2SSTXp1SuperSpeed差分信号#1&#xff0c;TX&#xff0c;正B11SSRXp1SuperSpeed差分信号#1&#xff0c;RX&#xff0c;正A3SSTXn1SuperSpeed差分信号#1&#xff0c;TX&…

typec接口知识

typec接口定义(24脚) typec母头 typec公头(一对D,D-,只有一个CC脚&#xff0c;另一个CC脚变成了VCONN) D/D-&#xff1a;当USB3接口不可用的时候&#xff0c;这些引脚为USB2信号提供信号通道。 Vbus/GND&#xff1a;这些引脚能够为上行数据接口提供100W的供电能力&#xff0c;…