ijkplayer系列10:流程分析-开始工作

开始工作
开始工作流程如下
在这里插入图片描述

前面几个没啥好看的,我们直接进入ijkmp_start_l():

static int ikjmp_chkst_start_l(int mp_state) {
    MPST_RET_IF_EQ(mp_state, MP_STATE_IDLE);
    MPST_RET_IF_EQ(mp_state, MP_STATE_INITIALIZED);
    MPST_RET_IF_EQ(mp_state, MP_STATE_ASYNC_PREPARING);
    // MPST_RET_IF_EQ(mp_state, MP_STATE_PREPARED);
    // MPST_RET_IF_EQ(mp_state, MP_STATE_STARTED);
    // MPST_RET_IF_EQ(mp_state, MP_STATE_PAUSED);
    // MPST_RET_IF_EQ(mp_state, MP_STATE_COMPLETED);
    MPST_RET_IF_EQ(mp_state, MP_STATE_STOPPED);
    MPST_RET_IF_EQ(mp_state, MP_STATE_ERROR);
    MPST_RET_IF_EQ(mp_state, MP_STATE_END);

    return 0;
}

static int ijkmp_start_l(IjkMediaPlayer *mp) {
    assert(mp);

    MP_RET_IF_FAILED(ikjmp_chkst_start_l(mp->mp_state));

    ffp_remove_msg(mp->ffplayer, FFP_REQ_START);
    ffp_remove_msg(mp->ffplayer, FFP_REQ_PAUSE);
    ffp_notify_msg1(mp->ffplayer, FFP_REQ_START);

    return 0;
}

可以看出,能够切换到STARTED状态的场景还是比较多的,总共有4个,分别为PREPARED、STARTED、PAUSED、COMPLETED。ijkmp_start_l()不会直接将状态变更为STARTED,而是发出一个事件FFP_REQ_START,在收到这个事件后再变更状态。
我们来看下处理事件的代码,代码位于ijkplayer.c的ijkmp_get_msg()方法中:

 /* need to call msg_free_res for freeing the resouce obtained in msg */
int ijkmp_get_msg(IjkMediaPlayer *mp, AVMessage *msg, int block) {
    assert(mp);
    while (1) {
        int continue_wait_next_msg = 0;
        int retval = msg_queue_get(&mp->ffplayer->msg_queue, msg, block);
        if (retval <= 0)
            return retval;

        switch (msg->what) {
        ...
        case FFP_REQ_START:
            MPTRACE("ijkmp_get_msg: FFP_REQ_START\n");
            continue_wait_next_msg = 1;
            pthread_mutex_lock(&mp->mutex);
            if (0 == ikjmp_chkst_start_l(mp->mp_state)) {
                // FIXME: 8 check seekable
                if (mp->restart) {
                    if (mp->restart_from_beginning) {
                        av_log(mp->ffplayer, AV_LOG_DEBUG, "ijkmp_get_msg: FFP_REQ_START: restart from beginning\n");
                        retval = ffp_start_from_l(mp->ffplayer, 0);
                        if (retval == 0)
                            ijkmp_change_state_l(mp, MP_STATE_STARTED);
                    } else {
                        av_log(mp->ffplayer, AV_LOG_DEBUG, "ijkmp_get_msg: FFP_REQ_START: restart from seek pos\n");
                        retval = ffp_start_l(mp->ffplayer);
                        if (retval == 0)
                            ijkmp_change_state_l(mp, MP_STATE_STARTED);
                    }
                    mp->restart = 0;
                    mp->restart_from_beginning = 0;
                } else {
                    av_log(mp->ffplayer, AV_LOG_DEBUG, "ijkmp_get_msg: FFP_REQ_START: start on fly\n");
                    retval = ffp_start_l(mp->ffplayer);
                    if (retval == 0)
                        ijkmp_change_state_l(mp, MP_STATE_STARTED);
                }
            }
            pthread_mutex_unlock(&mp->mutex);
            break;
            ...
        }
    }
}

这里面做了三件事情:

  1. 状态检验,如果当前状态不能变更到STARTED,则忽视这条消息。
  2. 判断是否重启(restart),针对restart做区分处理。由于restart的场景一般适应于点播,所以对于直播来说不用去太关心这部分逻辑,可以认为就是调用ffp_start_l()方法。
  3. 变更状态为STARTED并通知外部。
    接着,我们来看下ffp_start_l(),该方法最终会调用到stream_toggle_pause_l()方法:
/* pause or resume the video */
static void stream_toggle_pause_l(FFPlayer *ffp, int pause_on) {
    VideoState *is = ffp->is;
    if (is->paused && !pause_on) {
        is->frame_timer += av_gettime_relative() / 1000000.0 - is->vidclk.last_updated;

#ifdef FFP_MERGE
        if (is->read_pause_return != AVERROR(ENOSYS)) {
            is->vidclk.paused = 0;
        }
#endif
        set_clock(&is->vidclk, get_clock(&is->vidclk), is->vidclk.serial);
    } else {
    }
    set_clock(&is->extclk, get_clock(&is->extclk), is->extclk.serial);
    is->paused = is->audclk.paused = is->vidclk.paused = is->extclk.paused = pause_on;
    
    SDL_AoutPauseAudio(ffp->aout, pause_on);
} 

不要被这个方法名称欺骗了,这个方法可以暂停工作也可以恢复工作,在这里,我们当然是要恢复工作。方法末尾调用了SDL_AoutPauseAudio()方法来恢复语音工作,这个方法我们不再深入,音频API相关的我会另外开个专题讲解,这里只需要知道它的作用即可。
从以上的分析中,我们知道了start阶段主要做了以下几件事情:

  1. 变更状态为STARTED并通知外部。
  2. 处理一些时间相关的逻辑,时间相关的逻辑我也还没理清,后续会搞个时间专题。
  3. 恢复语音工作。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值