一、引言:
上一篇博客中分析了ijkplayer的整个流程,相信大家对其中的消息队列看的也是云里雾里的,所以这里单独对ijkplayer的消息机制做一个分析。
二、代码分析:
先看下消息机制是怎么创建起来的,创建的发起是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);
...
}
需要注意的是ijkmp_android_create
的入参是一个函数指针:
IjkMediaPlayer *ijkmp_android_create(int(*msg_loop)(void*))
{
IjkMediaPlayer *mp = ijkmp_create(msg_loop);
if (!mp)
goto fail;
...
}
这里传入了函数message_loop
,函数里面的内容后面分析,可以看到,ijkmp_create
的入参也是一个函数指针:
IjkMediaPlayer *ijkmp_create(int (*msg_loop)(void*))
{
IjkMediaPlayer *mp = (IjkMediaPlayer *) mallocz(sizeof(IjkMediaPlayer));
if (!mp)
goto fail;
/* 创建FFmpeg */
mp->ffplayer = ffp_create();
if (!mp->ffplayer)
goto fail;
/* 对mp->msg_loop进行赋值 */
mp->msg_loop = msg_loop;
...
}
这里面的流程我们也比较熟悉了,首先是去底层创建FFmpeg
,之后会将上面传下来的msg_loop
赋值给IjkMediaPlayer
结构体维护的函数指针变量msg_loop
。进入ffp_create
函数看一下跟消息队列相关的内容:
FFPlayer *ffp_create()
{
av_log(NULL, AV_LOG_INFO, "av_version_info: %s\n", av_version_info());
av_log(NULL, AV_LOG_INFO, "ijk_version_info: %s\n", ijk_version_info());
/* 1.申请FFPlayer结构体内存并初始化为0 */
FFPlayer* ffp = (FFPlayer*) av_mallocz(sizeof(FFPlayer));
if (!ffp)
return NULL;
/* 2.初始化ffp的消息队列msg_queue */
msg_queue_init(&ffp->msg_queue);
ffp->af_mutex = SDL_CreateMutex();
ffp->vf_mutex = SDL_CreateMutex();
/* 3.对FFPlayer结构体成员进行reset操作 */
ffp_reset_internal(ffp);
ffp->av_class = &ffp_context_class;
ffp->meta = ijkmeta_create();
av_opt_set_defaults(ffp);
las_stat_init(&ffp->las_player_statistic);
return ffp;
}
进入函数,首先是对FFPlayer
内存的初始化,接下来,会去调用msg_queue_init
对消息队列进行一个初始化,看一下函数实现:
inline static void msg_queue_init(MessageQueue *q)
{
memset