整章目录:Android------- IjkPlayer 源码学习目录
本篇主要介绍Ijkplayer 在native 自定义的消息处理机制,其原理于Android的handler相识。下图红色圈起部分:
native层的消息处理机制本命为message_loop,会在ijkplayer_jni->IjkMediaPlayer_native_setup中被设置到IjkMediaPlayer结构体中的msg_loop变量中。
如果不清楚 IjkMediaPlayer_native_setup的调用过程,请看Android ----- ijkplayer源码阅读Java层(二)
message_loop:
message_loop_n:
注意这里有一个死循环,不停的去队列中取消息。
这里预留一个空间A: post_event方法
ijkmp_get_msg:获取一个消息
这里第二个死循环
msg_queue_get:
/**
*
* @param q 消息队列
* @param msg 存放放回的消息
* @param block 如果消息队列为空,是否等待。 1为等待,0为不等待
* @return >0 表示获得消息成功,否则失败。
*/
/* return < 0 if aborted, 0 if no msg and > 0 if msg. */
inline static int msg_queue_get(MessageQueue *q, AVMessage *msg, int block)
{
AVMessage *msg1;
int ret;
// 获得操作锁,防止异步
SDL_LockMutex(q->mutex);
for (;;) {
// 是否退出了,返回 -1
if (q->abort_request) {
ret = -1;
break;
}
// 获得链表头节点,放入msg1
msg1 = q->first_msg;
// 如果存在
if (msg1) {
// 将链表头指向下一节点
q->first_msg = msg1->next;
if (!q->first_msg)
q->last_msg = NULL;
// 链表中的节点数减1
q->nb_messages--;
// 将取出节点的内容存储到返回指针指向的地址中
*msg = *msg1;
// 取出节点已经使用完毕,清除其内容
msg1->obj = NULL;
#ifdef FFP_MERGE
av_free(msg1);
#else
msg1->next = q->recycle_msg;
// 将节点回收,下次使用。
q->recycle_msg = msg1;
#endif
// 返回1
ret = 1;
break;
} else if (!block) {
// 不等待,直接返回0
ret = 0;
break;
} else {
// 等待
SDL_CondWait(q->cond, q->mutex);
}
}
// 释放锁
SDL_UnlockMutex(q->mutex);
return ret;
}
都加了注释,理解应该没啥问题。当拿到了一个消息后,会到前面的预留空间A-----调用post_event()将消息传回到Java层
定义了别名
void J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__postEventFromNative(JNIEnv *env, jobject weakThiz, jint what, jint arg1, jint arg2, jobject obj)
{
(*env)->CallStaticVoidMethod(env, class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.id, class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.method_postEventFromNative, weakThiz, what, arg1, arg2, obj);
}
class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.id:调用的Java 类
class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.method_postEventFromNative: 调用的Java 类中的方法
上述操作即是调用IjkMediaPlayer.java 类中的postEventFromNative方法
然后回到Java层,将消息发送给mEventHandler 处理: